diff --git a/.gitignore b/.gitignore index 677f5ef65..608c27272 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,29 @@ -# Emacs temp files +# Emacs *~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +.\#* -# macOS stuff -.DS_* +# Visual Studio Code +.vscode/ -# waf build system -.waf-1* -.waf3-* -.lock* -build/ +# macOS +.DS_Store +.AppleDouble +.LSOverride +._* + +# Waf build system +/build/ +.waf-*-*/ +.waf3-*-*/ +.lock-waf* # Compiled python code -*.pyc -*.pyo +__pycache__/ +*.py[cod] # Other -VERSION +/VERSION diff --git a/.jenkins b/.jenkins old mode 100755 new mode 100644 index 674d751a2..78e1ca135 --- a/.jenkins +++ b/.jenkins @@ -1,10 +1,27 @@ #!/usr/bin/env bash set -e -DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +nanos() { + # Cannot use date(1) because macOS does not support %N format specifier + python -c 'import time; print(int(time.time() * 1e9))' +} -for file in "$DIR"/.jenkins.d/*; do +for file in .jenkins.d/*; do [[ -f $file && -x $file ]] || continue - echo "Run: $file" + + if [[ -n $TRAVIS ]]; then + label=$(basename "$file" | sed -E 's/[[:digit:]]+-(.*)\..*/\1/') + echo -ne "travis_fold:start:${label}\r" + echo -ne "travis_time:start:${label}\r" + start=$(nanos) + fi + + echo "\$ $file" "$file" + + if [[ -n $TRAVIS ]]; then + finish=$(nanos) + echo -ne "travis_time:end:${label}:start=${start},finish=${finish},duration=$((finish-start)),event=${label}\r" + echo -ne "travis_fold:end:${label}\r" + fi done diff --git a/.jenkins.d/00-deps.sh b/.jenkins.d/00-deps.sh old mode 100755 new mode 100644 index 41b93f05f..ba85553c6 --- a/.jenkins.d/00-deps.sh +++ b/.jenkins.d/00-deps.sh @@ -7,14 +7,47 @@ source "$JDIR"/util.sh set -x if has OSX $NODE_LABELS; then + FORMULAE=(boost pkg-config) + if [[ -n $USE_OPENSSL_1_1 ]]; then + FORMULAE+=(openssl@1.1) + else + FORMULAE+=(openssl) + fi + brew update - brew upgrade - brew install boost pkg-config cryptopp openssl + if [[ -n $TRAVIS ]]; then + # Travis images come with a large number of brew packages + # pre-installed, don't waste time upgrading all of them + for FORMULA in "${FORMULAE[@]}"; do + brew outdated $FORMULA || brew upgrade $FORMULA + done + else + brew upgrade + fi + brew install "${FORMULAE[@]}" brew cleanup fi if has Ubuntu $NODE_LABELS; then sudo apt-get -qq update - sudo apt-get -qq install build-essential pkg-config libboost-all-dev \ - libcrypto++-dev libsqlite3-dev libssl-dev + sudo apt-get -qy install build-essential pkg-config libboost-all-dev \ + libsqlite3-dev libssl-dev + + if [[ $JOB_NAME == *"code-coverage" ]]; then + sudo apt-get -qy install gcovr lcov libgd-perl + fi +fi + +if has CentOS-7 $NODE_LABELS; then + sudo yum -y install yum-utils pkgconfig \ + openssl-devel libtranslit-icu \ + python-devel sqlite-devel \ + devtoolset-7-libasan-devel \ + devtoolset-7-liblsan-devel + sudo yum -y groupinstall 'Development Tools' + + svn checkout https://github.com/cmscaltech/sandie-ndn/trunk/packaging/RPMS/x86_64/boost1_58_0 + pushd boost1_58_0 >/dev/null + sudo rpm -Uv --replacepkgs --replacefiles boost-devel* boost-license* libboost_* + popd >/dev/null fi diff --git a/.jenkins.d/10-build.sh b/.jenkins.d/10-build.sh old mode 100755 new mode 100644 index 9c6cb7c1f..66ec27f02 --- a/.jenkins.d/10-build.sh +++ b/.jenkins.d/10-build.sh @@ -6,45 +6,49 @@ source "$JDIR"/util.sh set -x -sudo rm -Rf /usr/local/include/ndn-cxx -sudo rm -f /usr/local/lib/libndn-cxx* -sudo rm -f /usr/local/lib/pkgconfig/libndn-cxx* +sudo rm -f /usr/local/bin/ndnsec* +sudo rm -fr /usr/local/include/ndn-cxx +sudo rm -f /usr/local/lib{,64}/libndn-cxx* +sudo rm -f /usr/local/lib{,64}/pkgconfig/libndn-cxx.pc + +if [[ $JOB_NAME == *"code-coverage" ]]; then + COVERAGE="--with-coverage" +elif [[ -z $DISABLE_ASAN ]]; then + ASAN="--with-sanitizer=address" +fi +if [[ -n $USE_OPENSSL_1_1 ]] && has OSX $NODE_LABELS; then + OPENSSL="--with-openssl=/usr/local/opt/openssl@1.1" +fi # Cleanup -sudo ./waf -j1 --color=yes distclean +sudo_preserve_env PATH -- ./waf --color=yes distclean if [[ $JOB_NAME != *"code-coverage" && $JOB_NAME != *"limited-build" ]]; then # Configure/build static library in optimized mode with tests - ./waf -j1 --color=yes configure --enable-static --disable-shared --with-tests - ./waf -j1 --color=yes build + ./waf --color=yes configure --enable-static --disable-shared --with-tests $OPENSSL + ./waf --color=yes build -j${WAF_JOBS:-1} # Cleanup - sudo ./waf -j1 --color=yes distclean + sudo_preserve_env PATH -- ./waf --color=yes distclean # Configure/build static and shared library in optimized mode without tests - ./waf -j1 --color=yes configure --enable-static --enable-shared - ./waf -j1 --color=yes build + ./waf --color=yes configure --enable-static --enable-shared $OPENSSL + ./waf --color=yes build -j${WAF_JOBS:-1} # Cleanup - sudo ./waf -j1 --color=yes distclean + sudo_preserve_env PATH -- ./waf --color=yes distclean fi # Configure/build shared library in debug mode with tests/examples and without precompiled headers -if [[ $JOB_NAME == *"code-coverage" ]]; then - COVERAGE="--with-coverage" -elif ! has OSX-10.9 $NODE_LABELS && ! has OSX-10.11 $NODE_LABELS; then - ASAN="--with-sanitizer=address" -fi -./waf -j1 --color=yes configure --disable-static --enable-shared --debug --with-tests --with-examples --without-pch $COVERAGE $ASAN -./waf -j1 --color=yes build +./waf --color=yes configure --disable-static --enable-shared --debug --with-tests \ + --with-examples --without-pch $ASAN $COVERAGE $OPENSSL +./waf --color=yes build -j${WAF_JOBS:-1} # (tests will be run against debug version) # Install -sudo ./waf -j1 --color=yes install +sudo_preserve_env PATH -- ./waf --color=yes install if has Linux $NODE_LABELS; then sudo ldconfig -elif has FreeBSD $NODE_LABELS; then - sudo ldconfig -a fi diff --git a/.jenkins.d/20-tests.sh b/.jenkins.d/20-tests.sh old mode 100755 new mode 100644 index 01bf07038..ec4461b83 --- a/.jenkins.d/20-tests.sh +++ b/.jenkins.d/20-tests.sh @@ -31,7 +31,6 @@ ut_log_args() { } ASAN_OPTIONS="color=always" -ASAN_OPTIONS+=":detect_leaks=false" ASAN_OPTIONS+=":detect_stack_use_after_return=true" ASAN_OPTIONS+=":check_initialization_order=true" ASAN_OPTIONS+=":strict_init_order=true" @@ -41,5 +40,8 @@ ASAN_OPTIONS+=":strict_string_checks=true" ASAN_OPTIONS+=":strip_path_prefix=${PWD}/" export ASAN_OPTIONS +export BOOST_TEST_BUILD_INFO=1 +export BOOST_TEST_COLOR_OUTPUT=1 + # Run unit tests ./build/unit-tests $(ut_log_args) diff --git a/.jenkins.d/30-coverage.sh b/.jenkins.d/30-coverage.sh old mode 100755 new mode 100644 index dbc8025cd..46d3cf054 --- a/.jenkins.d/30-coverage.sh +++ b/.jenkins.d/30-coverage.sh @@ -9,7 +9,28 @@ set -x if [[ $JOB_NAME == *"code-coverage" ]]; then gcovr --object-directory=build \ --output=build/coverage.xml \ - --filter="$PWD/src" \ + --exclude="$PWD/(examples|tests)" \ --root=. \ --xml + + # Generate also a detailed HTML output, but using lcov (better results) + lcov --quiet \ + --capture \ + --directory . \ + --no-external \ + --rc lcov_branch_coverage=1 \ + --output-file build/coverage-with-tests.info + + lcov --quiet \ + --remove build/coverage-with-tests.info "$PWD/tests/*" \ + --rc lcov_branch_coverage=1 \ + --output-file build/coverage.info + + genhtml --branch-coverage \ + --demangle-cpp \ + --frames \ + --legend \ + --output-directory build/coverage \ + --title "ndn-cxx unit tests" \ + build/coverage.info fi diff --git a/.jenkins.d/40-standalone-header-compilation.sh b/.jenkins.d/40-standalone-header-compilation.sh old mode 100755 new mode 100644 index 0095b3f71..cb600eefd --- a/.jenkins.d/40-standalone-header-compilation.sh +++ b/.jenkins.d/40-standalone-header-compilation.sh @@ -6,37 +6,29 @@ # (similar to running all test cases), instead of failing at the first error. CXX=${CXX:-g++} +STD=-std=c++14 +CXXFLAGS="-O2 -Wall -Wno-unused-const-variable -Wno-unused-local-typedef $(pkg-config --cflags libndn-cxx)" +INCLUDEDIR="$(pkg-config --variable=includedir libndn-cxx)"/ndn-cxx -STD= -if $CXX -xc++ /dev/null -o /dev/null -c -std=c++11 &>/dev/null; then - STD=-std=c++11 -elif $CXX -xc++ /dev/null -o /dev/null -c -std=c++0x &>/dev/null; then - STD=-std=c++0x -fi - -STDLIB= -if $CXX -xc++ /dev/null -o /dev/null -c $STD -stdlib=libc++ &>/dev/null; then - STDLIB=-stdlib=libc++ -fi - -echo 'Compiler flags:' $CXX $STD $STDLIB +echo "Using: $CXX $STD $CXXFLAGS" -INCLUDEDIR=/usr/local/include/ndn-cxx NCHECKED=0 NERRORS=0 while IFS= read -r -d '' H; do - echo 'Verifying standalone header compilation for' $H - $CXX -xc++ "$INCLUDEDIR/$H" -o /dev/null -c $STD $STDLIB $(pkg-config --cflags libndn-cxx) + echo "Verifying standalone header compilation for ${H#${INCLUDEDIR}/}" + "$CXX" -xc++ $STD $CXXFLAGS -c -o /dev/null "$H" [[ $? -eq 0 ]] || ((NERRORS++)) ((NCHECKED++)) -done < <(cd "$INCLUDEDIR" && find * -name '*.hpp' -type f -print0 2>/dev/null) +done < <(find "$INCLUDEDIR" -name '*.hpp' -type f -print0 2>/dev/null) if [[ $NCHECKED -eq 0 ]]; then echo 'No header found. Is ndn-cxx installed?' exit 1 +else + echo "$NCHECKED headers checked." fi if [[ $NERRORS -gt 0 ]]; then - echo $NERRORS 'headers cannot compile on its own' + echo "$NERRORS headers could not be compiled." exit 1 fi diff --git a/.jenkins.d/README.md b/.jenkins.d/README.md index b1bd93aa9..7c78349f5 100644 --- a/.jenkins.d/README.md +++ b/.jenkins.d/README.md @@ -13,13 +13,13 @@ Environment Variables Used in Build Scripts * `[OS_TYPE]`: `Linux` * `[DISTRO_TYPE]`: `Ubuntu` - * `[DISTRO_VERSION]`: `Ubuntu-14.04`, `Ubuntu-16.04` + * `[DISTRO_VERSION]`: `Ubuntu-16.04`, `Ubuntu-18.04` - Possible values for OS X / macOS: + Possible values for macOS: * `[OS_TYPE]`: `OSX` * `[DISTRO_TYPE]`: `OSX` (can be absent) - * `[DISTRO_VERSION]`: `OSX-10.10`, `OSX-10.11`, `OSX-10.12` + * `[DISTRO_VERSION]`: `OSX-10.12`, `OSX-10.13`, `OSX-10.14` - `JOB_NAME`: optional variable to define type of the job. Depending on the defined job type, the build scripts can perform different tasks. @@ -27,5 +27,7 @@ Environment Variables Used in Build Scripts Possible values: * empty: default build process - * `code-coverage` (Linux OS is assumed): debug build with tests and code coverage analysis + * `code-coverage` (Ubuntu Linux is assumed): debug build with tests and code coverage analysis * `limited-build`: only a single debug build with tests + +- `WAF_JOBS`: number of parallel build jobs used by waf, defaults to 1. diff --git a/.jenkins.d/util.sh b/.jenkins.d/util.sh index a89bc2739..8ddc4baf6 100644 --- a/.jenkins.d/util.sh +++ b/.jenkins.d/util.sh @@ -16,3 +16,22 @@ has() { set ${saved_xtrace} return ${ret} } + +sudo_preserve_env() { + local saved_xtrace + [[ $- == *x* ]] && saved_xtrace=-x || saved_xtrace=+x + set +x + + local vars=() + while [[ $# -gt 0 ]]; do + local arg=$1 + shift + case ${arg} in + --) break ;; + *) vars+=("${arg}=${!arg}") ;; + esac + done + + set ${saved_xtrace} + sudo env "${vars[@]}" "$@" +} diff --git a/.mailmap b/.mailmap new file mode 100644 index 000000000..967715ed4 --- /dev/null +++ b/.mailmap @@ -0,0 +1,8 @@ + + + + +Teng Liang + +Hila Ben Abraham +Laqin Fan diff --git a/.travis.yml b/.travis.yml index 49058ccdf..570bb0ece 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,28 +1,112 @@ -sudo: required -language: generic +language: cpp +dist: bionic env: global: - JOB_NAME=limited-build + - WAF_JOBS=2 + matrix: include: + # Linux/gcc + # https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test/+packages - os: linux - dist: trusty - env: - - CXX=g++ - - NODE_LABELS="Linux Ubuntu Ubuntu-14.04" - - os: linux - dist: trusty - env: - - CXX=clang++ - - NODE_LABELS="Linux Ubuntu Ubuntu-14.04" - - os: osx - osx_image: xcode7.3 - env: - - CXX=clang++ - - NODE_LABELS="OSX OSX-10.11" -notifications: - email: - on_success: always - on_failure: always + env: COMPILER=g++-5 + - os: linux + env: COMPILER=g++-6 + - os: linux + env: COMPILER=g++-7 + - os: linux + env: COMPILER=g++-8 + # disable AddressSanitizer with gcc 9 due to + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90570 + - os: linux + env: COMPILER=g++-9 DISABLE_ASAN=yes + + # Linux/clang + # https://apt.llvm.org/ + - os: linux + env: COMPILER=clang++-3.9 + - os: linux + env: COMPILER=clang++-4.0 + - os: linux + env: COMPILER=clang++-5.0 + - os: linux + env: COMPILER=clang++-6.0 + # disable AddressSanitizer with clang 7 and 8 + # due to https://bugs.llvm.org/show_bug.cgi?id=40808 + - os: linux + env: COMPILER=clang++-7 DISABLE_ASAN=yes + - os: linux + env: COMPILER=clang++-8 DISABLE_ASAN=yes + - os: linux + env: COMPILER=clang++-9 + - os: linux + env: COMPILER=clang++-10 + + # macOS/clang + # https://docs.travis-ci.com/user/reference/osx/#macos-version + - os: osx + osx_image: xcode9.2 + env: OSX_VERSION=10.12 + - os: osx + osx_image: xcode9.4 + env: OSX_VERSION=10.13 + - os: osx + osx_image: xcode10.1 + env: OSX_VERSION=10.13 + - os: osx + osx_image: xcode10.1 + env: OSX_VERSION=10.13 USE_OPENSSL_1_1=yes + - os: osx + osx_image: xcode10.3 + env: OSX_VERSION=10.14 + - os: osx + osx_image: xcode10.3 + env: OSX_VERSION=10.14 USE_OPENSSL_1_1=yes + - os: osx + osx_image: xcode11 + env: OSX_VERSION=10.14 + - os: osx + osx_image: xcode11 + env: OSX_VERSION=10.14 USE_OPENSSL_1_1=yes + + allow_failures: + - env: COMPILER=clang++-10 + + fast_finish: true + +before_install: | + case ${COMPILER} in + g++-[567]|clang++-[3456].*) + ;; + g++-*) + travis_retry sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test + travis_retry sudo apt-get -qq update + ;; + clang++-*) + LLVM_REPO=${COMPILER/clang++/llvm-toolchain-${TRAVIS_DIST}} + travis_retry wget -nv -O - "https://apt.llvm.org/llvm-snapshot.gpg.key" | sudo apt-key add - + travis_retry sudo add-apt-repository -y "deb http://apt.llvm.org/${TRAVIS_DIST}/ ${LLVM_REPO%-10} main" + travis_retry sudo apt-get -qq update + ;; + esac + +install: + - if [[ -n ${COMPILER} ]]; then travis_retry sudo apt-get -qy install "${COMPILER/clang++/clang}"; fi + +before_script: + - if [[ ${TRAVIS_OS_NAME} == linux ]]; then export NODE_LABELS="Linux Ubuntu Ubuntu-18.04"; fi + - if [[ ${TRAVIS_OS_NAME} == osx ]]; then export NODE_LABELS="OSX OSX-${OSX_VERSION}"; fi + # do not waste time upgrading useless packages + - if [[ ${TRAVIS_OS_NAME} == osx ]]; then brew pin cgal gdal numpy postgis sfcgal || true; fi + - if [[ ${OSX_VERSION} == 10.12 ]]; then brew update; fi + # workaround for https://github.com/Homebrew/homebrew-core/issues/26358 + - if [[ ${OSX_VERSION} == 10.12 ]]; then brew outdated python || brew upgrade python; fi + # workaround for https://github.com/travis-ci/travis-ci/issues/6688 + - if [[ ${OSX_VERSION} == 10.12 ]]; then /usr/bin/yes | pip2 uninstall numpy || true; fi + - if [[ -n ${COMPILER} ]]; then export CXX=${COMPILER}; fi + - ${CXX:-c++} --version + - python --version + script: - ./.jenkins diff --git a/.waf-tools/boost.py b/.waf-tools/boost.py index 9b9395ea0..4b2ede536 100644 --- a/.waf-tools/boost.py +++ b/.waf-tools/boost.py @@ -54,9 +54,9 @@ def build(bld): from waflib.Configure import conf from waflib.TaskGen import feature, after_method -BOOST_LIBS = ['/usr/lib/x86_64-linux-gnu', '/usr/lib/i386-linux-gnu', - '/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib'] +BOOST_LIBS = ['/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib'] BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include'] + BOOST_VERSION_FILE = 'boost/version.hpp' BOOST_VERSION_CODE = ''' #include @@ -91,13 +91,18 @@ def build(bld): BOOST_LOG_CODE = ''' #include +int main() { BOOST_LOG_TRIVIAL(info) << "boost_log is working"; } +''' + +BOOST_LOG_SETUP_CODE = ''' +#include #include #include int main() { using namespace boost::log; add_common_attributes(); add_console_log(std::clog, keywords::format = "%Message%"); - BOOST_LOG_TRIVIAL(debug) << "log is working" << std::endl; + BOOST_LOG_TRIVIAL(info) << "boost_log_setup is working"; } ''' @@ -146,7 +151,7 @@ def options(opt): opt.add_option('--boost-abi', type='string', default='', dest='boost_abi', help='''select libraries with tags (gd for debug, static is automatically added), see doc Boost, Getting Started, chapter 6.1''') - opt.add_option('--boost-linkage_autodetect', action="store_true", dest='boost_linkage_autodetect', + opt.add_option('--boost-linkage_autodetect', action='store_true', dest='boost_linkage_autodetect', help="auto-detect boost linkage options (don't get used to it / might break other stuff)") opt.add_option('--boost-toolset', type='string', default='', dest='boost_toolset', @@ -176,7 +181,7 @@ def boost_get_version(self, d): try: txt = node.read() except EnvironmentError: - Logs.error("Could not read the file %r" % node.abspath()) + Logs.error('Could not read the file %r' % node.abspath()) else: re_but1 = re.compile('^#define\\s+BOOST_LIB_VERSION\\s+"(.+)"', re.M) m1 = re_but1.search(txt) @@ -184,7 +189,7 @@ def boost_get_version(self, d): m2 = re_but2.search(txt) if m1 and m2: return (m1.group(1), m2.group(1)) - return self.check_cxx(fragment=BOOST_VERSION_CODE, includes=[d], execute=True, define_ret=True).split(":") + return self.check_cxx(fragment=BOOST_VERSION_CODE, includes=[d], execute=True, define_ret=True).split(':') @conf def boost_get_includes(self, *k, **kw): @@ -195,10 +200,10 @@ def boost_get_includes(self, *k, **kw): if self.__boost_get_version_file(d): return d if includes: - self.end_msg('headers not found in %s' % includes) + self.end_msg('headers not found in %s' % includes, 'YELLOW') self.fatal('The configuration failed') else: - self.end_msg('headers not found, please provide a --boost-includes argument (see help)') + self.end_msg('headers not found, please provide a --boost-includes argument (see help)', 'YELLOW') self.fatal('The configuration failed') @@ -241,10 +246,10 @@ def __boost_get_libs_path(self, *k, **kw): break if not path: if libs: - self.end_msg('libs not found in %s' % libs) + self.end_msg('libs not found in %s' % libs, 'YELLOW') self.fatal('The configuration failed') else: - self.end_msg('libs not found, please provide a --boost-libs argument (see help)') + self.end_msg('libs not found, please provide a --boost-libs argument (see help)', 'YELLOW') self.fatal('The configuration failed') self.to_log('Found the boost path in %r with the libraries:' % path) @@ -314,7 +319,7 @@ def match_libs(lib_names, is_static): libs.append(format_lib_name(file.name)) break else: - self.end_msg('lib %s not found in %s' % (lib, path.abspath())) + self.end_msg('lib %s not found in %s' % (lib, path.abspath()), 'YELLOW') self.fatal('The configuration failed') return libs @@ -355,7 +360,7 @@ def _check_pthread_flag(self, *k, **kw): # ... -mt is also the pthreads flag for HP/aCC # -lpthread: GNU Linux, etc. # --thread-safe: KAI C++ - if Utils.unversioned_sys_platform() == "sunos": + if Utils.unversioned_sys_platform() == 'sunos': # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ @@ -363,23 +368,22 @@ def _check_pthread_flag(self, *k, **kw): # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: - boost_pthread_flags = ["-pthreads", "-lpthread", "-mt", "-pthread"] + boost_pthread_flags = ['-pthreads', '-lpthread', '-mt', '-pthread'] else: - boost_pthread_flags = ["", "-lpthreads", "-Kthread", "-kthread", "-llthread", "-pthread", - "-pthreads", "-mthreads", "-lpthread", "--thread-safe", "-mt"] + boost_pthread_flags = ['', '-lpthreads', '-Kthread', '-kthread', '-llthread', '-pthread', + '-pthreads', '-mthreads', '-lpthread', '--thread-safe', '-mt'] for boost_pthread_flag in boost_pthread_flags: try: self.env.stash() self.env['CXXFLAGS_%s' % var] += [boost_pthread_flag] self.env['LINKFLAGS_%s' % var] += [boost_pthread_flag] - self.check_cxx(code=PTHREAD_CODE, msg=None, use=var, execute=False) - + self.check_cxx(code=PTHREAD_CODE, msg=None, use=var, execute=False, quiet=True) self.end_msg(boost_pthread_flag) return except self.errors.ConfigurationError: self.env.revert() - self.end_msg('None') + self.end_msg('none') @conf def check_boost(self, *k, **kw): @@ -404,16 +408,24 @@ def check_boost(self, *k, **kw): var = kw.get('uselib_store', 'BOOST') - self.start_msg('Checking boost includes') - self.env['INCLUDES_%s' % var] = inc = self.boost_get_includes(**params) - versions = self.boost_get_version(inc) - self.env.BOOST_VERSION = versions[0] - self.env.BOOST_VERSION_NUMBER = int(versions[1]) - self.end_msg("%d.%d.%d" % (int(versions[1]) / 100000, - int(versions[1]) / 100 % 1000, - int(versions[1]) % 100)) - if Logs.verbose: - Logs.pprint('CYAN', ' path : %s' % self.env['INCLUDES_%s' % var]) + if not self.env.DONE_FIND_BOOST_COMMON: + self.find_program('dpkg-architecture', var='DPKG_ARCHITECTURE', mandatory=False) + if self.env.DPKG_ARCHITECTURE: + deb_host_multiarch = self.cmd_and_log([self.env.DPKG_ARCHITECTURE[0], '-qDEB_HOST_MULTIARCH']) + BOOST_LIBS.insert(0, '/usr/lib/%s' % deb_host_multiarch.strip()) + + self.start_msg('Checking boost includes') + self.env['INCLUDES_%s' % var] = inc = self.boost_get_includes(**params) + versions = self.boost_get_version(inc) + self.env.BOOST_VERSION = versions[0] + self.env.BOOST_VERSION_NUMBER = int(versions[1]) + self.end_msg('%d.%d.%d' % (int(versions[1]) / 100000, + int(versions[1]) / 100 % 1000, + int(versions[1]) % 100)) + if Logs.verbose: + Logs.pprint('CYAN', ' path : %s' % self.env['INCLUDES_%s' % var]) + + self.env.DONE_FIND_BOOST_COMMON = True if not params['lib'] and not params['stlib']: return @@ -425,7 +437,7 @@ def check_boost(self, *k, **kw): self.env['STLIBPATH_%s' % var] = [path] self.env['LIB_%s' % var] = libs self.env['STLIB_%s' % var] = stlibs - self.end_msg('ok') + self.end_msg(' '.join(libs + stlibs)) if Logs.verbose: Logs.pprint('CYAN', ' path : %s' % path) Logs.pprint('CYAN', ' shared libs : %s' % libs) @@ -446,15 +458,18 @@ def try_link(): self.check_cxx(fragment=BOOST_ERROR_CODE, use=var, execute=False) if has_lib('thread'): self.check_cxx(fragment=BOOST_THREAD_CODE, use=var, execute=False) - if has_lib('log'): + if has_lib('log') or has_lib('log_setup'): if not has_lib('thread'): self.env['DEFINES_%s' % var] += ['BOOST_LOG_NO_THREADS'] - if has_shlib('log'): + if has_shlib('log') or has_shlib('log_setup'): self.env['DEFINES_%s' % var] += ['BOOST_LOG_DYN_LINK'] - self.check_cxx(fragment=BOOST_LOG_CODE, use=var, execute=False) + if has_lib('log_setup'): + self.check_cxx(fragment=BOOST_LOG_SETUP_CODE, use=var, execute=False) + else: + self.check_cxx(fragment=BOOST_LOG_CODE, use=var, execute=False) if params.get('linkage_autodetect', False): - self.start_msg("Attempting to detect boost linkage flags") + self.start_msg('Attempting to detect boost linkage flags') toolset = self.boost_get_toolset(kw.get('toolset', '')) if toolset in ('vc',): # disable auto-linking feature, causing error LNK1181 @@ -476,10 +491,10 @@ def try_link(): # we attempt to play with some known-to-work CXXFLAGS combinations for cxxflags in (['/MD', '/EHsc'], []): self.env.stash() - self.env["CXXFLAGS_%s" % var] += cxxflags + self.env['CXXFLAGS_%s' % var] += cxxflags try: try_link() - self.end_msg("ok: winning cxxflags combination: %s" % (self.env["CXXFLAGS_%s" % var])) + self.end_msg('ok: winning cxxflags combination: %s' % (self.env['CXXFLAGS_%s' % var])) exc = None break except Errors.ConfigurationError as e: @@ -487,17 +502,17 @@ def try_link(): exc = e if exc is not None: - self.end_msg("Could not auto-detect boost linking flags combination, you may report it to boost.py author", ex=exc) + self.end_msg('Could not auto-detect boost linking flags combination, you may report it to boost.py author', ex=exc) self.fatal('The configuration failed') else: - self.end_msg("Boost linkage flags auto-detection not implemented (needed ?) for this toolchain") + self.end_msg('Boost linkage flags auto-detection not implemented (needed ?) for this toolchain') self.fatal('The configuration failed') else: self.start_msg('Checking for boost linkage') try: try_link() except Errors.ConfigurationError as e: - self.end_msg("Could not link against boost libraries using supplied options") + self.end_msg('Could not link against boost libraries using supplied options', 'YELLOW') self.fatal('The configuration failed') self.end_msg('ok') diff --git a/.waf-tools/compiler-features.py b/.waf-tools/compiler-features.py index 502596ca1..1602f1683 100644 --- a/.waf-tools/compiler-features.py +++ b/.waf-tools/compiler-features.py @@ -23,31 +23,8 @@ @conf def check_std_to_string(self): if self.check_cxx(msg='Checking for std::to_string', - fragment=STD_TO_STRING, - features='cxx', mandatory=False): + fragment=STD_TO_STRING, mandatory=False): self.define('HAVE_STD_TO_STRING', 1) -VECTOR_INSERT_ERASE_CONST_ITERATOR = ''' -#include -int -main() -{ - std::vector v; - std::vector::const_iterator it = v.cbegin(); - - v.insert(it, 2); - it = v.cend() - 1; - v.erase(it); -} -''' - -@conf -def check_vector_const_iterators(self): - if self.check_cxx(msg='Checking for std::vector::insert with const_iterator', - fragment=VECTOR_INSERT_ERASE_CONST_ITERATOR, - features='cxx', mandatory=False): - self.define('HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR', 1) - def configure(conf): conf.check_std_to_string() - conf.check_vector_const_iterators() diff --git a/.waf-tools/coverage.py b/.waf-tools/coverage.py index ce928838a..cc5816500 100644 --- a/.waf-tools/coverage.py +++ b/.waf-tools/coverage.py @@ -1,15 +1,15 @@ # -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -from waflib import TaskGen, Logs +from waflib import TaskGen def options(opt): - opt.add_option('--with-coverage', action='store_true', default=False, dest='with_coverage', - help='''Set compiler flags for gcc to enable code coverage information''') + opt.add_option('--with-coverage', action='store_true', default=False, + help='Add compiler flags to enable code coverage information') def configure(conf): if conf.options.with_coverage: if not conf.options.debug: - conf.fatal("Code coverage flags require debug mode compilation (add --debug)") + conf.fatal('Code coverage flags require debug mode compilation (add --debug)') conf.check_cxx(cxxflags=['-fprofile-arcs', '-ftest-coverage', '-fPIC'], linkflags=['-fprofile-arcs'], uselib_store='GCOV', mandatory=True) diff --git a/.waf-tools/cryptopp.py b/.waf-tools/cryptopp.py deleted file mode 100644 index 1632ab61f..000000000 --- a/.waf-tools/cryptopp.py +++ /dev/null @@ -1,122 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 - -''' - -When using this tool, the wscript will look like: - - def options(opt): - opt.load('compiler_cxx cryptopp') - - def configure(conf): - conf.load('compiler_cxx cryptopp') - conf.check_cryptopp() - - def build(bld): - bld(source='main.cpp', target='app', use='CRYPTOPP') - -Options are generated, in order to specify the location of cryptopp includes/libraries. - - -''' -import sys -import re -from waflib import Utils,Logs,Errors -from waflib.Configure import conf -CRYPTOPP_DIR = ['/usr', '/usr/local', '/opt/local', '/sw'] -CRYPTOPP_VERSION_FILE = 'config.h' - -CRYPTOPP_CHECK_FRAGMENT = ''' -#include "../../src/security/v1/cryptopp.hpp" -#include - -int -main() -{ - using namespace CryptoPP; - - std::string buffer = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; - SHA256 hash; - StringSource(buffer, true, new HashFilter(hash, new FileSink(std::cout))); - StringSource(reinterpret_cast(buffer.c_str()), buffer.size(), - true, new HashFilter(hash, new FileSink(std::cout))); -} -''' - -def options(opt): - opt.add_option('--with-cryptopp', type='string', default=None, dest='cryptopp_dir', - help='''Path to where CryptoPP is installed, e.g., /usr/local''') - -@conf -def __cryptopp_get_version_file(self, dir): - try: - return self.root.find_dir(dir).find_node('%s/%s' % ('include/cryptopp', - CRYPTOPP_VERSION_FILE)) - except: - return None - -@conf -def __cryptopp_find_root_and_version_file(self, *k, **kw): - root = k and k[0] or kw.get('path', self.options.cryptopp_dir) - - file = self.__cryptopp_get_version_file(root) - if root and file: - return (root, file) - for dir in CRYPTOPP_DIR: - file = self.__cryptopp_get_version_file(dir) - if file: - return (dir, file) - - if root: - self.fatal('CryptoPP not found in %s' % root) - else: - self.fatal('CryptoPP not found, please provide a --with-cryptopp=PATH argument (see help)') - -@conf -def check_cryptopp(self, *k, **kw): - if not self.env['CXX']: - self.fatal('Load a c++ compiler first, e.g., conf.load("compiler_cxx")') - - var = kw.get('uselib_store', 'CRYPTOPP') - mandatory = kw.get('mandatory', True) - - use = kw.get('use', 'PTHREAD') - - self.start_msg('Checking Crypto++ lib') - (root, file) = self.__cryptopp_find_root_and_version_file(*k, **kw) - - try: - txt = file.read() - re_version = re.compile('^#define\\s+CRYPTOPP_VERSION\\s+([0-9]+)', re.M) - match = re_version.search(txt) - - if match: - self.env.CRYPTOPP_VERSION = match.group(1) - v = int(self.env.CRYPTOPP_VERSION) - (major, minor, patch) = (int(v / 100), int(v % 100 / 10), int(v % 10)) - self.end_msg("%d.%d.%d" % (major, minor, patch)) - else: - self.fatal('CryptoPP files are present, but are not recognizable') - except: - self.fatal('CryptoPP not found or is not usable') - - isLibWorking = False - for defines in [[], ['CRYPTOPP_DISABLE_ASM']]: - try: - self.check_cxx(msg='Checking if CryptoPP library works', - fragment=CRYPTOPP_CHECK_FRAGMENT, - lib='cryptopp', - includes="%s/include" % root, - libpath="%s/lib" % root, - mandatory=True, - use=use, - defines=defines, - uselib_store=var) - isLibWorking = True - break - except: - # try another flags - pass - - if mandatory and not isLibWorking: - self.fatal('CryptoPP is present, but is not usable') diff --git a/.waf-tools/default-compiler-flags.py b/.waf-tools/default-compiler-flags.py index 2999e8f85..9e045c3fb 100644 --- a/.waf-tools/default-compiler-flags.py +++ b/.waf-tools/default-compiler-flags.py @@ -1,44 +1,67 @@ # -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -from waflib import Logs, Configure, Utils +from waflib import Configure, Logs, Utils def options(opt): - opt.add_option('--debug', '--with-debug', action='store_true', default=False, dest='debug', - help='''Compile in debugging mode without optimizations (-O0 or -Og)''') + opt.add_option('--debug', '--with-debug', action='store_true', default=False, + help='Compile in debugging mode with minimal optimizations (-O0 or -Og)') def configure(conf): - cxx = conf.env['CXX_NAME'] # CXX_NAME represents generic name of the compiler + conf.start_msg('Checking C++ compiler version') + + cxx = conf.env.CXX_NAME # generic name of the compiler + ccver = tuple(int(i) for i in conf.env.CC_VERSION) + ccverstr = '.'.join(conf.env.CC_VERSION) + errmsg = '' + warnmsg = '' if cxx == 'gcc': - flags = GccFlags() + if ccver < (5, 3, 0): + errmsg = ('The version of gcc you are using is too old.\n' + 'The minimum supported gcc version is 5.3.0.') + conf.flags = GccFlags() elif cxx == 'clang': - flags = ClangFlags() + if ccver < (3, 6, 0): + errmsg = ('The version of clang you are using is too old.\n' + 'The minimum supported clang version is 3.6.0.') + conf.flags = ClangFlags() + else: + warnmsg = 'Note: %s compiler is unsupported' % cxx + conf.flags = CompilerFlags() + + if errmsg: + conf.end_msg(ccverstr, color='RED') + conf.fatal(errmsg) + elif warnmsg: + conf.end_msg(ccverstr, color='YELLOW') + Logs.warn(warnmsg) else: - flags = CompilerFlags() - Logs.warn('The code has not yet been tested with %s compiler' % cxx) + conf.end_msg(ccverstr) - areCustomCxxflagsPresent = (len(conf.env.CXXFLAGS) > 0) + conf.areCustomCxxflagsPresent = (len(conf.env.CXXFLAGS) > 0) - # General flags are always applied (e.g., selecting C++11 mode) - generalFlags = flags.getGeneralFlags(conf) + # General flags are always applied (e.g., selecting C++ language standard) + generalFlags = conf.flags.getGeneralFlags(conf) conf.add_supported_cxxflags(generalFlags['CXXFLAGS']) conf.add_supported_linkflags(generalFlags['LINKFLAGS']) conf.env.DEFINES += generalFlags['DEFINES'] +@Configure.conf +def check_compiler_flags(conf): # Debug or optimized CXXFLAGS and LINKFLAGS are applied only if the # corresponding environment variables are not set. # DEFINES are always applied. if conf.options.debug: - extraFlags = flags.getDebugFlags(conf) - if areCustomCxxflagsPresent: + extraFlags = conf.flags.getDebugFlags(conf) + if conf.areCustomCxxflagsPresent: missingFlags = [x for x in extraFlags['CXXFLAGS'] if x not in conf.env.CXXFLAGS] - if len(missingFlags) > 0: - Logs.warn("Selected debug mode, but CXXFLAGS is set to a custom value '%s'" - % " ".join(conf.env.CXXFLAGS)) - Logs.warn("Default flags '%s' are not activated" % " ".join(missingFlags)) + if missingFlags: + Logs.warn('Selected debug mode, but CXXFLAGS is set to a custom value "%s"' + % ' '.join(conf.env.CXXFLAGS)) + Logs.warn('Default flags "%s" will not be used' % ' '.join(missingFlags)) else: - extraFlags = flags.getOptimizedFlags(conf) + extraFlags = conf.flags.getOptimizedFlags(conf) - if not areCustomCxxflagsPresent: + if not conf.areCustomCxxflagsPresent: conf.add_supported_cxxflags(extraFlags['CXXFLAGS']) conf.add_supported_linkflags(extraFlags['LINKFLAGS']) @@ -55,9 +78,10 @@ def add_supported_cxxflags(self, cxxflags): self.start_msg('Checking supported CXXFLAGS') supportedFlags = [] - for flag in cxxflags: - if self.check_cxx(cxxflags=['-Werror', flag], mandatory=False): - supportedFlags += [flag] + for flags in cxxflags: + flags = Utils.to_list(flags) + if self.check_cxx(cxxflags=['-Werror'] + flags, mandatory=False): + supportedFlags += flags self.end_msg(' '.join(supportedFlags)) self.env.prepend_value('CXXFLAGS', supportedFlags) @@ -73,15 +97,19 @@ def add_supported_linkflags(self, linkflags): self.start_msg('Checking supported LINKFLAGS') supportedFlags = [] - for flag in linkflags: - if self.check_cxx(linkflags=['-Werror', flag], mandatory=False): - supportedFlags += [flag] + for flags in linkflags: + flags = Utils.to_list(flags) + if self.check_cxx(linkflags=['-Werror'] + flags, mandatory=False): + supportedFlags += flags self.end_msg(' '.join(supportedFlags)) self.env.prepend_value('LINKFLAGS', supportedFlags) class CompilerFlags(object): + def getCompilerVersion(self, conf): + return tuple(int(i) for i in conf.env.CC_VERSION) + def getGeneralFlags(self, conf): """Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are always needed""" return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': []} @@ -98,18 +126,30 @@ class GccBasicFlags(CompilerFlags): """ This class defines basic flags that work for both gcc and clang compilers """ + def getGeneralFlags(self, conf): + flags = super(GccBasicFlags, self).getGeneralFlags(conf) + flags['CXXFLAGS'] += ['-std=c++14'] + if Utils.unversioned_sys_platform() == 'linux': + flags['LINKFLAGS'] += ['-fuse-ld=gold'] + elif Utils.unversioned_sys_platform() == 'freebsd': + flags['LINKFLAGS'] += ['-fuse-ld=lld'] + return flags + def getDebugFlags(self, conf): flags = super(GccBasicFlags, self).getDebugFlags(conf) flags['CXXFLAGS'] += ['-O0', + '-Og', # gcc >= 4.8, clang >= 4.0 '-g3', '-pedantic', '-Wall', '-Wextra', '-Werror', - '-Wno-unused-parameter', - '-Wno-error=maybe-uninitialized', # Bug #1615 + '-Wnon-virtual-dtor', '-Wno-error=deprecated-declarations', # Bug #3795 + '-Wno-error=maybe-uninitialized', # Bug #1615 + '-Wno-unused-parameter', ] + flags['LINKFLAGS'] += ['-Wl,-O1'] return flags def getOptimizedFlags(self, conf): @@ -119,63 +159,58 @@ def getOptimizedFlags(self, conf): '-pedantic', '-Wall', '-Wextra', + '-Wnon-virtual-dtor', '-Wno-unused-parameter', ] + flags['LINKFLAGS'] += ['-Wl,-O1'] return flags class GccFlags(GccBasicFlags): - def getGeneralFlags(self, conf): - flags = super(GccFlags, self).getGeneralFlags(conf) - version = tuple(int(i) for i in conf.env['CC_VERSION']) - if version < (4, 8, 2): - conf.fatal('The version of gcc you are using (%s) is too old.\n' % - '.'.join(conf.env['CC_VERSION']) + - 'The minimum supported gcc version is 4.8.2.') - else: - flags['CXXFLAGS'] += ['-std=c++11'] - return flags - 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 - ] + flags['CXXFLAGS'] += ['-fdiagnostics-color'] 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 + flags['CXXFLAGS'] += ['-fdiagnostics-color'] return flags class ClangFlags(GccBasicFlags): def getGeneralFlags(self, conf): flags = super(ClangFlags, self).getGeneralFlags(conf) - flags['CXXFLAGS'] += ['-std=c++11'] - if Utils.unversioned_sys_platform() == 'darwin': - flags['CXXFLAGS'] += ['-stdlib=libc++'] - flags['LINKFLAGS'] += ['-stdlib=libc++'] + if Utils.unversioned_sys_platform() == 'darwin' and self.getCompilerVersion(conf) >= (9, 0, 0): + # Bug #4296 + flags['CXXFLAGS'] += [['-isystem', '/usr/local/include'], # for Homebrew + ['-isystem', '/opt/local/include']] # for MacPorts + if Utils.unversioned_sys_platform() == 'freebsd': + flags['CXXFLAGS'] += [['-isystem', '/usr/local/include']] # Bug #4790 return flags def getDebugFlags(self, conf): flags = super(ClangFlags, self).getDebugFlags(conf) flags['CXXFLAGS'] += ['-fcolor-diagnostics', + '-Wextra-semi', + '-Wundefined-func-template', '-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 - '-Wno-error=infinite-recursion', # Bug #3358 ] + version = self.getCompilerVersion(conf) + if version < (3, 9, 0) or (Utils.unversioned_sys_platform() == 'darwin' and version < (8, 1, 0)): + flags['CXXFLAGS'] += ['-Wno-unknown-pragmas'] + if version < (6, 0, 0): + flags['CXXFLAGS'] += ['-Wno-missing-braces'] # Bug #4721 return flags def getOptimizedFlags(self, conf): flags = super(ClangFlags, self).getOptimizedFlags(conf) flags['CXXFLAGS'] += ['-fcolor-diagnostics', + '-Wextra-semi', + '-Wundefined-func-template', '-Wno-unused-local-typedef', # Bugs #2657 and #3209 ] + version = self.getCompilerVersion(conf) + if version < (3, 9, 0) or (Utils.unversioned_sys_platform() == 'darwin' and version < (8, 1, 0)): + flags['CXXFLAGS'] += ['-Wno-unknown-pragmas'] + if version < (6, 0, 0): + flags['CXXFLAGS'] += ['-Wno-missing-braces'] # Bug #4721 return flags diff --git a/.waf-tools/openssl.py b/.waf-tools/openssl.py index de0f9dc59..b35795f5c 100644 --- a/.waf-tools/openssl.py +++ b/.waf-tools/openssl.py @@ -19,23 +19,20 @@ def build(bld): ''' import re -from waflib import Utils, Logs +from waflib import Utils from waflib.Configure import conf -OPENSSL_VERSION_FILE = 'opensslv.h' OPENSSL_DIR_OSX = ['/usr/local', '/opt/local', '/usr/local/opt/openssl'] OPENSSL_DIR = ['/usr', '/usr/local', '/opt/local', '/sw'] def options(opt): opt.add_option('--with-openssl', type='string', default=None, dest='openssl_dir', - help='''Path to where OpenSSL is installed, e.g., /usr/local''') - + help='directory where OpenSSL is installed, e.g., /usr/local') @conf def __openssl_get_version_file(self, dir): try: - return self.root.find_dir(dir).find_node('%s/%s' % ('include/openssl', - OPENSSL_VERSION_FILE)) + return self.root.find_dir(dir).find_node('include/openssl/opensslv.h') except: return None @@ -47,8 +44,8 @@ def __openssl_find_root_and_version_file(self, *k, **kw): if root and file: return (root, file) - openssl_dir = []; - if Utils.unversioned_sys_platform() == "darwin": + openssl_dir = [] + if Utils.unversioned_sys_platform() == 'darwin': openssl_dir = OPENSSL_DIR_OSX else: openssl_dir = OPENSSL_DIR @@ -66,10 +63,7 @@ def __openssl_find_root_and_version_file(self, *k, **kw): @conf def check_openssl(self, *k, **kw): - atleast_version = kw.get('atleast_version', 0) - var = kw.get('uselib_store', 'OPENSSL') - - self.start_msg('Checking for OpenSSL lib') + self.start_msg('Checking for OpenSSL version') (root, file) = self.__openssl_find_root_and_version_file(*k, **kw) try: @@ -88,18 +82,21 @@ def check_openssl(self, *k, **kw): except: self.fatal('OpenSSL version file is not found or is not usable') + atleast_version = kw.get('atleast_version', 0) if int(version, 16) < atleast_version: - self.fatal("The version of OpenSSL is too old\n" + - "Please upgrade your distribution or install newer version of OpenSSL library") - - kwargs = {} + self.fatal('The version of OpenSSL is too old\n' + 'Please upgrade your distribution or manually install a newer version of OpenSSL') + + if 'msg' not in kw: + kw['msg'] = 'Checking if OpenSSL library works' + if 'lib' not in kw: + kw['lib'] = ['ssl', 'crypto'] + if 'uselib_store' not in kw: + kw['uselib_store'] = 'OPENSSL' + if 'define_name' not in kw: + kw['define_name'] = 'HAVE_%s' % kw['uselib_store'] if root: - kwargs['includes'] = "%s/include" % root - kwargs['libpath'] = "%s/lib" % root - - libcrypto = self.check_cxx(lib=['ssl', 'crypto'], - msg='Checking if OpenSSL library works', - define_name='HAVE_%s' % var, - uselib_store=var, - mandatory=True, - **kwargs) + kw['includes'] = '%s/include' % root + kw['libpath'] = '%s/lib' % root + + self.check_cxx(**kw) diff --git a/.waf-tools/osx-frameworks.py b/.waf-tools/osx-frameworks.py new file mode 100644 index 000000000..76cd3df77 --- /dev/null +++ b/.waf-tools/osx-frameworks.py @@ -0,0 +1,42 @@ +#! /usr/bin/env python +# encoding: utf-8 + +from waflib import Logs, Utils, TaskGen +from waflib.Configure import conf + +@conf +def check_osx_framework_cxx(conf, fw_name, **kw): + conf.check_cxx(framework_name=fw_name, + uselib_store='OSX_' + fw_name.upper(), + fragment='#include <{0}/{0}.h>\nint main() {{}}'.format(fw_name), + **kw) + +@conf +def check_osx_framework_mm(conf, fw_name, **kw): + conf.check_cxx(framework_name=fw_name, + uselib_store='OSX_' + fw_name.upper(), + fragment='#import <{0}/{0}.h>\nint main() {{}}'.format(fw_name), + compile_filename='test.mm', + **kw) + +@conf +def check_osx_frameworks(conf, *k, **kw): + if Utils.unversioned_sys_platform() == 'darwin': + try: + conf.check_osx_framework_cxx('CoreFoundation', mandatory=True) + conf.check_osx_framework_cxx('Security', use='OSX_COREFOUNDATION', mandatory=True) + conf.check_osx_framework_cxx('SystemConfiguration', use='OSX_COREFOUNDATION', mandatory=True) + + conf.check_osx_framework_mm('Foundation', mandatory=True) + conf.check_osx_framework_mm('CoreWLAN', use='OSX_FOUNDATION', mandatory=True) + + conf.define('HAVE_OSX_FRAMEWORKS', 1) + conf.env['HAVE_OSX_FRAMEWORKS'] = True + except: + Logs.warn('Building on macOS, but one or more required frameworks are not functional.') + Logs.warn('Note that the frameworks are known to work only with the Apple clang compiler.') + +@TaskGen.extension('.mm') +def m_hook(self, node): + '''Alias .mm files to be compiled the same as .cpp files, clang will do the right thing.''' + return self.create_compiled_task('cxx', node) diff --git a/.waf-tools/osx-security.py b/.waf-tools/osx-security.py deleted file mode 100644 index f7f273e68..000000000 --- a/.waf-tools/osx-security.py +++ /dev/null @@ -1,32 +0,0 @@ -#! /usr/bin/env python -# encoding: utf-8 - -from waflib import Logs, Utils -from waflib.Configure import conf - -OSX_SECURITY_CODE=''' -#include -#include -#include -#include -#include -int main() {} -''' - -@conf -def check_osx_security(conf, *k, **kw): - if Utils.unversioned_sys_platform() == "darwin": - try: - conf.check_cxx(framework_name='CoreFoundation', uselib_store='OSX_COREFOUNDATION', - mandatory=True) - conf.check_cxx(framework_name='CoreServices', uselib_store='OSX_CORESERVICES', - mandatory=True) - conf.check_cxx(framework_name='Security', uselib_store='OSX_SECURITY', - define_name='HAVE_SECURITY', use="OSX_COREFOUNDATION", - fragment=OSX_SECURITY_CODE, mandatory=True) - - conf.define('HAVE_OSX_SECURITY', 1) - conf.env['HAVE_OSX_SECURITY'] = True - except: - Logs.warn("Compiling on OSX, but CoreFoundation, CoreServices, or Security framework is not functional.") - Logs.warn("The frameworks are known to work only with Apple-specific compilers: llvm-gcc-4.2 or clang") diff --git a/.waf-tools/pch.py b/.waf-tools/pch.py index 57582ad28..103e75283 100644 --- a/.waf-tools/pch.py +++ b/.waf-tools/pch.py @@ -52,7 +52,7 @@ def build(bld): """ import os -from waflib import Task, TaskGen, Logs, Utils +from waflib import Task, TaskGen, Utils from waflib.Tools import c_preproc, cxx @@ -67,11 +67,6 @@ def options(opt): def configure(conf): if (conf.options.with_pch and conf.env['COMPILER_CXX'] in PCH_COMPILER_OPTIONS.keys()): - if Utils.unversioned_sys_platform() == "darwin" and conf.env['CXX_NAME'] == 'clang': - version = tuple(int(i) for i in conf.env['CC_VERSION']) - if version < (6, 1, 0): - # Issue #2804 - return conf.env.WITH_PCH = True flags = PCH_COMPILER_OPTIONS[conf.env['COMPILER_CXX']] conf.env.CXXPCH_F = flags[0] @@ -134,7 +129,7 @@ def add_pch(self): x.env.append_value('CXXFLAGS', self.env['CXXPCH_F'] + [pch.target]) class gchx(Task.Task): - run_str = '${CXX} ${ARCH_ST:ARCH} ${CXXFLAGS} ${CPPFLAGS} ${CXXPCH_FLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXXPCH_F:SRC} ${CXX_SRC_F}${SRC[0].abspath()} ${CXX_TGT_F}${TGT[0].abspath()}' + run_str = '${CXX} ${ARCH_ST:ARCH} ${CXXFLAGS} ${CXXPCH_FLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXXPCH_F:SRC} ${CXX_SRC_F}${SRC[0].abspath()} ${CXX_TGT_F}${TGT[0].abspath()} ${CPPFLAGS}' scan = c_preproc.scan color = 'BLUE' ext_out=['.h'] diff --git a/.waf-tools/sphinx_build.py b/.waf-tools/sphinx_build.py index e61da6e65..b44a54f4e 100644 --- a/.waf-tools/sphinx_build.py +++ b/.waf-tools/sphinx_build.py @@ -44,28 +44,28 @@ def apply_sphinx(self): task.inputs.append(conf) confdir = conf.parent.abspath() - buildername = getattr(self, "builder", "html") - srcdir = getattr(self, "srcdir", confdir) - outdir = self.path.find_or_declare(getattr(self, "outdir", buildername)).get_bld() - doctreedir = getattr(self, "doctreedir", os.path.join(outdir.abspath(), ".doctrees")) + buildername = getattr(self, 'builder', 'html') + srcdir = getattr(self, 'srcdir', confdir) + outdir = self.path.find_or_declare(getattr(self, 'outdir', buildername)).get_bld() + doctreedir = getattr(self, 'doctreedir', os.path.join(outdir.abspath(), '.doctrees')) task.env['BUILDERNAME'] = buildername task.env['SRCDIR'] = srcdir task.env['DOCTREEDIR'] = doctreedir task.env['OUTDIR'] = outdir.abspath() - task.env['VERSION'] = "version=%s" % self.VERSION - task.env['RELEASE'] = "release=%s" % self.VERSION + task.env['VERSION'] = 'version=%s' % self.version + task.env['RELEASE'] = 'release=%s' % getattr(self, 'release', self.version) import imp confData = imp.load_source('sphinx_conf', conf.abspath()) - if buildername == "man": + if buildername == 'man': for i in confData.man_pages: target = outdir.find_or_declare('%s.%d' % (i[1], i[4])) task.outputs.append(target) if self.install_path: - self.bld.install_files("%s/man%d/" % (self.install_path, i[4]), target) + self.bld.install_files('%s/man%d/' % (self.install_path, i[4]), target) else: task.outputs.append(outdir) diff --git a/.waf-tools/sqlite3.py b/.waf-tools/sqlite3.py index 3d4e46ed0..4f2c01690 100644 --- a/.waf-tools/sqlite3.py +++ b/.waf-tools/sqlite3.py @@ -1,16 +1,15 @@ #! /usr/bin/env python # encoding: utf-8 -from waflib import Options, Logs from waflib.Configure import conf def options(opt): - opt.add_option('--with-sqlite3', type='string', default=None, - dest='with_sqlite3', help='''Path to SQLite3, e.g., /usr/local''') + opt.add_option('--with-sqlite3', type='string', default=None, dest='sqlite3_dir', + help='directory where SQLite3 is installed, e.g., /usr/local') @conf def check_sqlite3(self, *k, **kw): - root = k and k[0] or kw.get('path', None) or Options.options.with_sqlite3 + root = k and k[0] or kw.get('path', self.options.sqlite3_dir) mandatory = kw.get('mandatory', True) var = kw.get('uselib_store', 'SQLITE3') @@ -20,8 +19,8 @@ def check_sqlite3(self, *k, **kw): define_name='HAVE_%s' % var, uselib_store=var, mandatory=mandatory, - includes="%s/include" % root, - libpath="%s/lib" % root) + includes='%s/include' % root, + libpath='%s/lib' % root) else: try: self.check_cfg(package='sqlite3', diff --git a/.waf-tools/type_traits.py b/.waf-tools/type_traits.py deleted file mode 100644 index efc4e3d0f..000000000 --- a/.waf-tools/type_traits.py +++ /dev/null @@ -1,15 +0,0 @@ -# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- - -def checkForTypeProperty(conf, prop, tparams): - if conf.check_cxx(msg=('Checking for std::%s' % prop), - fragment=('#include \nstatic_assert(std::%s<%s>::value, "");' % - (prop, tparams)), - features='cxx', mandatory=False): - define = 'HAVE_' + prop.upper() - conf.define(define, 1) - conf.env[define] = True - -def configure(conf): - checkForTypeProperty(conf, 'is_default_constructible', 'int') - checkForTypeProperty(conf, 'is_nothrow_move_constructible', 'int') - checkForTypeProperty(conf, 'is_nothrow_move_assignable', 'int') diff --git a/AUTHORS.md b/AUTHORS.md index 48457ef14..38fc19c35 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -39,4 +39,5 @@ in the library: * Marcin Juszkiewicz * Susmit Shannigrahi * José Quevedo -* Zhiyi Zhang +* Zhiyi Zhang +* Chavoosh Ghasemi diff --git a/COPYING.md b/COPYING.md index 173a714db..7b140e494 100644 --- a/COPYING.md +++ b/COPYING.md @@ -1,20 +1,23 @@ -ndn-cxx LICENSE -====================== +ndn-cxx is licensed under the terms of the GNU Lesser General Public License, +version 3 or later. -ndn-cxx library is licensed under conditions of GNU Lesser General Public License. +ndn-cxx relies on third-party software, licensed under the following licenses: -The library relies on third-party software and library, licensed under the following -licenses: +- The Boost libraries are licensed under the + [Boost Software License 1.0](https://www.boost.org/users/license.html) -- Boost libraries licensed under conditions of - [Boost Software License 1.0](http://www.boost.org/users/license.html) +- any-lite by Martin Moene is licensed under the + [Boost Software License 1.0](https://github.com/martinmoene/any-lite/blob/master/LICENSE.txt) -- CryptoPP library is licensed under conditions of - [Boost Software License 1.0](http://www.boost.org/users/license.html) +- optional-lite by Martin Moene is licensed under the + [Boost Software License 1.0](https://github.com/martinmoene/optional-lite/blob/master/LICENSE.txt) -- SQLite is in [public domain](http://www.sqlite.org/copyright.html) +- variant-lite by Martin Moene is licensed under the + [Boost Software License 1.0](https://github.com/martinmoene/variant-lite/blob/master/LICENSE.txt) -- waf build system is licensed under conditions of +- SQLite is in the [public domain](https://www.sqlite.org/copyright.html) + +- The waf build system is licensed under the terms of the [BSD license](https://github.com/named-data/ndn-cxx/blob/master/waf) @@ -23,68 +26,67 @@ compatible license. These library fall into category of "System Libraries" under license definitions and are used in accordance with GPL license exception for "System Libraries": -- OpenSSL is licensed under an [Apache-style licence](http://www.openssl.org/source/license.html) +- OpenSSL is licensed under an + [Apache-style license](https://www.openssl.org/source/license.html) -- (OS X platform only) OS X Security Framework is licensed under -[Apple Public Source License](http://www.opensource.apple.com/license/apsl/) +- (macOS platform only) The macOS Security Framework is licensed under the + [Apple Public Source License](https://opensource.apple.com/apsl) The LGPL and GPL licenses are provided below in this file. For more information -about these licenses, see http://www.gnu.org/licenses/ - +about these licenses, see https://www.gnu.org/licenses/ ----------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- -GNU LESSER GENERAL PUBLIC LICENSE -================================= +### GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 -Copyright © 2007 Free Software Foundation, Inc. <> +Copyright (C) 2007 Free Software Foundation, Inc. + -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. +This version of the GNU Lesser General Public License incorporates the +terms and conditions of version 3 of the GNU General Public License, +supplemented by the additional permissions listed below. -This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. +#### 0. Additional Definitions. -### 0. Additional Definitions. +As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the +GNU General Public License. -As used herein, “this License” refers to version 3 of the GNU Lesser -General Public License, and the “GNU GPL” refers to version 3 of the GNU -General Public License. +"The Library" refers to a covered work governed by this License, other +than an Application or a Combined Work as defined below. -“The Library” refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - -An “Application” is any work that makes use of an interface provided +An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. -A “Combined Work” is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the “Linked -Version”. +A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". -The “Minimal Corresponding Source” for a Combined Work means the +The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. -The “Corresponding Application Code” for a Combined Work means the +The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. -### 1. Exception to Section 3 of the GNU GPL. +#### 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. -### 2. Conveying Modified Versions. +#### 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application @@ -92,107 +94,101 @@ that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: -* a) under this License, provided that you make a good faith effort to -ensure that, in the event an Application does not supply the -function or data, the facility still operates, and performs -whatever part of its purpose remains meaningful, or - -* b) under the GNU GPL, with none of the additional permissions of -this License applicable to that copy. +- a) under this License, provided that you make a good faith effort + to ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or +- b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. -### 3. Object Code Incorporating Material from Library Header Files. +#### 3. Object Code Incorporating Material from Library Header Files. -The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object +The object code form of an Application may incorporate material from a +header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: -* a) Give prominent notice with each copy of the object code that the -Library is used in it and that the Library and its use are -covered by this License. -* b) Accompany the object code with a copy of the GNU GPL and this license -document. - -### 4. Combined Works. - -You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - -* a) Give prominent notice with each copy of the Combined Work that -the Library is used in it and that the Library and its use are -covered by this License. - -* b) Accompany the Combined Work with a copy of the GNU GPL and this license -document. - -* c) For a Combined Work that displays copyright notices during -execution, include the copyright notice for the Library among -these notices, as well as a reference directing the user to the -copies of the GNU GPL and this license document. - -* d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this -License, and the Corresponding Application Code in a form -suitable for, and under terms that permit, the user to -recombine or relink the Application with a modified version of -the Linked Version to produce a modified Combined Work, in the -manner specified by section 6 of the GNU GPL for conveying -Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the -Library. A suitable mechanism is one that (a) uses at run time -a copy of the Library already present on the user's computer -system, and (b) will operate properly with a modified version -of the Library that is interface-compatible with the Linked -Version. - -* e) Provide Installation Information, but only if you would otherwise -be required to provide such information under section 6 of the -GNU GPL, and only to the extent that such information is -necessary to install and execute a modified version of the -Combined Work produced by recombining or relinking the -Application with a modified version of the Linked Version. (If -you use option 4d0, the Installation Information must accompany -the Minimal Corresponding Source and Corresponding Application -Code. If you use option 4d1, you must provide the Installation -Information in the manner specified by section 6 of the GNU GPL -for conveying Corresponding Source.) - -### 5. Combined Libraries. - -You may place library facilities that are a work based on the -Library side by side in a single library together with other library +- a) Give prominent notice with each copy of the object code that + the Library is used in it and that the Library and its use are + covered by this License. +- b) Accompany the object code with a copy of the GNU GPL and this + license document. + +#### 4. Combined Works. + +You may convey a Combined Work under terms of your choice that, taken +together, effectively do not restrict modification of the portions of +the Library contained in the Combined Work and reverse engineering for +debugging such modifications, if you also do each of the following: + +- a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. +- b) Accompany the Combined Work with a copy of the GNU GPL and this + license document. +- c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. +- d) Do one of the following: + - 0) Convey the Minimal Corresponding Source under the terms of + this License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + - 1) Use a suitable shared library mechanism for linking with + the Library. A suitable mechanism is one that (a) uses at run + time a copy of the Library already present on the user's + computer system, and (b) will operate properly with a modified + version of the Library that is interface-compatible with the + Linked Version. +- e) Provide Installation Information, but only if you would + otherwise be required to provide such information under section 6 + of the GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the Application + with a modified version of the Linked Version. (If you use option + 4d0, the Installation Information must accompany the Minimal + Corresponding Source and Corresponding Application Code. If you + use option 4d1, you must provide the Installation Information in + the manner specified by section 6 of the GNU GPL for conveying + Corresponding Source.) + +#### 5. Combined Libraries. + +You may place library facilities that are a work based on the Library +side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: -* a) Accompany the combined library with a copy of the same work based -on the Library, uncombined with any other library facilities, -conveyed under the terms of this License. -* b) Give prominent notice with the combined library that part of it -is a work based on the Library, and explaining where to find the -accompanying uncombined form of the same work. +- a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities, conveyed under the terms of this License. +- b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. -### 6. Revised Versions of the GNU Lesser General Public License. +#### 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. -Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License “or any later version” -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. +Each version is given a distinguishing version number. If the Library +as you received it specifies that a certain numbered version of the +GNU Lesser General Public License "or any later version" applies to +it, you have the option of following the terms and conditions either +of that published version or of any later version published by the +Free Software Foundation. If the Library as you received it does not +specify a version number of the GNU Lesser General Public License, you +may choose any version of the GNU Lesser General Public License ever +published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall @@ -200,204 +196,210 @@ apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. -GNU GENERAL PUBLIC LICENSE -========================== +-------------------------------------------------------------------------------- + +### GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 -> Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. +Copyright (C) 2007 Free Software Foundation, Inc. + + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. -# Preamble +### Preamble - The GNU General Public License is a free, copyleft license for +The GNU General Public License is a free, copyleft license for software and other kinds of works. - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you +The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom +to share and change all versions of a program--to make sure it remains +free software for all its users. We, the Free Software Foundation, use +the GNU General Public License for most of our software; it applies +also to any other work released this way by its authors. You can apply +it to your programs, too. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. +To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you +have certain responsibilities if you distribute copies of the +software, or if you modify it: responsibilities to respect the freedom +of others. - For example, if you distribute copies of such a program, whether +For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they know their rights. - Developers that use the GNU GPL protect your rights with two steps: +Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and +For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. +Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the +manufacturer can do so. This is fundamentally incompatible with the +aim of protecting users' freedom to change the software. The +systematic pattern of such abuse occurs in the area of products for +individuals to use, which is precisely where it is most unacceptable. +Therefore, we have designed this version of the GPL to prohibit the +practice for those products. If such problems arise substantially in +other domains, we stand ready to extend this provision to those +domains in future versions of the GPL, as needed to protect the +freedom of users. + +Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. +software on general-purpose computers, but in those that do, we wish +to avoid the special danger that patents applied to a free program +could make it effectively proprietary. To prevent this, the GPL +assures that patents cannot be used to render the program non-free. - The precise terms and conditions for copying, distribution and +The precise terms and conditions for copying, distribution and modification follow. -# TERMS AND CONDITIONS +### TERMS AND CONDITIONS -## 0. Definitions. +#### 0. Definitions. - _"This License"_ refers to version 3 of the GNU General Public License. +"This License" refers to version 3 of the GNU General Public License. - _"Copyright"_ also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. +"Copyright" also means copyright-like laws that apply to other kinds +of works, such as semiconductor masks. - _"The Program"_ refers to any copyrightable work licensed under this -License. Each licensee is addressed as _"you"_. _"Licensees"_ and +"The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. - To _"modify"_ a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a _"modified version"_ of the -earlier work or a work _"based on"_ the earlier work. +To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of +an exact copy. The resulting work is called a "modified version" of +the earlier work or a work "based on" the earlier work. - A _"covered work"_ means either the unmodified Program or a work based +A "covered work" means either the unmodified Program or a work based on the Program. - To _"propagate"_ a work means to do anything with it that, without +To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, +computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. - To _"convey"_ a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. +To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user +through a computer network, with no transfer of a copy, is not +conveying. - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible +An interactive user interface displays "Appropriate Legal Notices" to +the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If +work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. -## 1. Source Code. +#### 1. Source Code. - The _"source code"_ for a work means the preferred form of the work -for making modifications to it. _"Object code"_ means any non-source -form of a work. +The "source code" for a work means the preferred form of the work for +making modifications to it. "Object code" means any non-source form of +a work. - A _"Standard Interface"_ means an interface that either is an official +A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. - The _"System Libraries"_ of an executable work include anything, other +The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A +implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. - The _"Corresponding Source"_ for a work in object code form means all +The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's +control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source +which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. +The Corresponding Source need not include anything that users can +regenerate automatically from other parts of the Corresponding Source. - The Corresponding Source for a work in source code form is that -same work. +The Corresponding Source for a work in source code form is that same +work. -## 2. Basic Permissions. +#### 2. Basic Permissions. - All rights granted under this License are granted for the term of +All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your +content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. +You may make, run and propagate covered works that you do not convey, +without conditions so long as your license otherwise remains in force. +You may convey covered works to others for the sole purpose of having +them make modifications exclusively for you, or provide you with +facilities for running those works, provided that you comply with the +terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for +you must do so exclusively on your behalf, under your direction and +control, on terms that prohibit them from making any copies of your +copyrighted material outside their relationship with you. - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. +Conveying under any other circumstances is permitted solely under the +conditions stated below. Sublicensing is not allowed; section 10 makes +it unnecessary. -## 3. Protecting Users' Legal Rights From Anti-Circumvention Law. +#### 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - No covered work shall be deemed part of an effective technological +No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. +When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such +circumvention is effected by exercising rights under this License with +respect to the covered work, and you disclaim any intention to limit +operation or modification of the work as a means of enforcing, against +the work's users, your or third parties' legal rights to forbid +circumvention of technological measures. -## 4. Conveying Verbatim Copies. +#### 4. Conveying Verbatim Copies. - You may convey verbatim copies of the Program's source code as you +You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any @@ -405,59 +407,56 @@ non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. - You may charge any price or no price for each copy that you convey, +You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. -## 5. Conveying Modified Source Versions. +#### 5. Conveying Modified Source Versions. - You may convey a work based on the Program, or the modifications to +You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: +terms of section 4, provided that you also meet all of these +conditions: - a) The work must carry prominent notices stating that you modified +- a) The work must carry prominent notices stating that you modified it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This +- b) The work must carry prominent notices stating that it is + released under this License and any conditions added under + section 7. This requirement modifies the requirement in section 4 + to "keep intact all notices". +- c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no + regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display +- d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. - A compilation of a covered work with other separate and independent +A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work +beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. -## 6. Conveying Non-Source Forms. +#### 6. Conveying Non-Source Forms. - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: +You may convey a covered work in object code form under the terms of +sections 4 and 5, provided that you also convey the machine-readable +Corresponding Source under the terms of this License, in one of these +ways: - a) Convey the object code in, or embodied in, a physical product +- a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product +- b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product @@ -466,196 +465,190 @@ in one of these ways: product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This + conveying of source, or (2) access to copy the Corresponding + Source from a network server at no charge. +- c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. - - d) Convey the object code by offering access from a designated +- d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the + Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. +- e) Convey the object code using peer-to-peer transmission, + provided you inform other peers where the object code and + Corresponding Source of the work are being offered to the general + public at no charge under subsection 6d. - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded +A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. - A _"User Product"_ is either (1) a _"consumer product"_, which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - _"Installation Information"_ for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or +A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, +family, or household purposes, or (2) anything designed or sold for +incorporation into a dwelling. In determining whether a product is a +consumer product, doubtful cases shall be resolved in favor of +coverage. For a particular product received by a particular user, +"normally used" refers to a typical or common use of that class of +product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected +to use, the product. A product is a consumer product regardless of +whether the product has substantial commercial, industrial or +non-consumer uses, unless such uses represent the only significant +mode of use of the product. + +"Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to +install and execute modified versions of a covered work in that User +Product from a modified version of its Corresponding Source. The +information must suffice to ensure that the continued functioning of +the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply +by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. +The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or +updates for a work that has been modified or installed by the +recipient, or for the User Product in which it has been modified or +installed. Access to a network may be denied when the modification +itself materially and adversely affects the operation of the network +or violates the rules and protocols for communication across the +network. - Corresponding Source conveyed, and Installation Information provided, +Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. -## 7. Additional Terms. +#### 7. Additional Terms. - _"Additional permissions"_ are terms that supplement the terms of this +"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions +that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. - When you convey a copy of a covered work, you may at your option +When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: +Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders +of that material) supplement the terms of this License with terms: - a) Disclaiming warranty or limiting liability differently from the +- a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or +- b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in +- c) Prohibiting misrepresentation of the origin of that material, + or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some +- d) Limiting the use for publicity purposes of names of licensors + or authors of the material; or +- e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you +- f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions + of it) with contractual assumptions of liability to the recipient, + for any liability that these contractual assumptions directly + impose on those licensors and authors. + +All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains +restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. - If you add terms to a covered work in accord with this section, you +If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. +Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; the +above requirements apply either way. -## 8. Termination. +#### 8. Termination. - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or +You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. +However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally +terminates your license, and (b) permanently, if the copyright holder +fails to notify you of the violation by some reasonable means prior to +60 days after the cessation. - Moreover, your license from a particular copyright holder is +Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. - Termination of your rights under this section does not terminate the +Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently +this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. -## 9. Acceptance Not Required for Having Copies. +#### 9. Acceptance Not Required for Having Copies. - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work +You are not required to accept this License in order to receive or run +a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, +to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. -## 10. Automatic Licensing of Downstream Recipients. +#### 10. Automatic Licensing of Downstream Recipients. - Each time you convey a covered work, the recipient automatically +Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible +propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. - An _"entity transaction"_ is a transaction transferring control of an +An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered +organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could @@ -663,43 +656,43 @@ give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may +You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. -## 11. Patents. +#### 11. Patents. - A _"contributor"_ is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The +A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". - A contributor's _"essential patent claims"_ are all patent claims -owned or controlled by the contributor, whether already acquired or +A contributor's "essential patent claims" are all patent claims owned +or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For +consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. - Each contributor grants you a non-exclusive, worldwide, royalty-free +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. - In the following three paragraphs, a "patent license" is any express +In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a +sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. - If you convey a covered work, knowingly relying on a patent license, +If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, @@ -707,13 +700,13 @@ then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have +license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. - If, pursuant to or in connection with a single transaction or +If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify @@ -721,159 +714,162 @@ or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting +A patent license is "discriminatory" if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on +the non-exercise of one or more of the rights that are specifically +granted under this License. You may not convey a covered work if you +are a party to an arrangement with a third party that is in the +business of distributing software, under which you make payment to the +third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties +who would receive the covered work from you, a discriminatory patent +license (a) in connection with copies of the covered work conveyed by +you (or copies made from those copies), or (b) primarily for and in +connection with specific products or compilations that contain the +covered work, unless you entered into that arrangement, or that patent +license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. -## 12. No Surrender of Others' Freedom. +#### 12. No Surrender of Others' Freedom. - If conditions are imposed on you (whether by court order, agreement or +If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - -## 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under +this License and any other pertinent obligations, then as a +consequence you may not convey it at all. For example, if you agree to +terms that obligate you to collect a royalty for further conveying +from those to whom you convey the Program, the only way you could +satisfy both those terms and this License would be to refrain entirely +from conveying the Program. + +#### 13. Use with the GNU Affero General Public License. + +Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this +combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. -## 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any +#### 14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions +of the GNU General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in +detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies that a certain numbered version of the GNU General Public +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that numbered version or +of any later version published by the Free Software Foundation. If the +Program does not specify a version number of the GNU General Public +License, you may choose any version ever published by the Free +Software Foundation. + +If the Program specifies that a proxy can decide which future versions +of the GNU General Public License can be used, that proxy's public +statement of acceptance of a version permanently authorizes you to +choose that version for the Program. + +Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. -## 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -## 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - -## 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided +#### 15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + +#### 16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR +CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT +NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR +LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM +TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER +PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +#### 17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. -# END OF TERMS AND CONDITIONS --------------------------------------------------------------------------- - +END OF TERMS AND CONDITIONS -# How to Apply These Terms to Your New Programs +### How to Apply These Terms to Your New Programs - If you develop a new program, and you want it to be of the greatest +If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. +free software which everyone can redistribute and change under these +terms. - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. +To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively state +the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. - - Copyright (C) + + Copyright (C) - This program 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. + This program 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. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU General Public License + along with this program. If not, see . -Also add information on how to contact you by electronic and paper mail. +Also add information on how to contact you by electronic and paper +mail. - If the program does terminal interaction, make it output a short +If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type 'show c' for details. - - The hypothetical commands _'show w'_ and _'show c'_ should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands \`show w' and \`show c' should show the +appropriate parts of the General Public License. Of course, your +program's commands might be different; for a GUI interface, you would +use an "about box". + +You should also get your employer (if you work as a programmer) or +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. For more information on this, and how to apply and follow +the GNU GPL, see . + +The GNU General Public License does not permit incorporating your +program into proprietary programs. If your program is a subroutine +library, you may consider it more useful to permit linking proprietary +applications with the library. If this is what you want to do, use the +GNU Lesser General Public License instead of this License. But first, +please read . diff --git a/README-dev.md b/README-dev.md index 6d6d572f6..ad9447cc2 100644 --- a/README-dev.md +++ b/README-dev.md @@ -1,22 +1,24 @@ Notes for ndn-cxx developers ============================ +If you are new to the NDN community of software generally, read the +[Contributor's Guide](https://github.com/named-data/NFD/blob/master/CONTRIBUTING.md). + Code style ---------- -ndn-cxx code is subject to [ndn-cxx code style](http://named-data.net/doc/ndn-cxx/current/code-style.html). +ndn-cxx code is subject to [ndn-cxx code style](https://named-data.net/doc/ndn-cxx/current/code-style.html). Licensing --------- -Contributions to the library must be licensed under LGPL 3.0 or compatible license. If -you are choosing LGPL 3.0, please use the following license boilerplate in all `.hpp` and +Contributions to the library must be licensed under the LGPL v3 or compatible license. If +you are choosing LGPL v3, please use the following license boilerplate in all `.hpp` and `.cpp` files: - /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ - /** - * Copyright (c) [Year(s)] [Copyright Holder]. + /* + * Copyright (c) [Year(s)] [Copyright Holder(s)]. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -43,29 +45,29 @@ you are choosing LGPL 3.0, please use the following license boilerplate in all ` If you are affiliated to an NSF-supported NDN project institution, please use the [NDN Team License Boilerplate](https://redmine.named-data.net/projects/ndn-cxx/wiki/NDN_Team_License_Boilerplate_(ndn-cxx)). -Running unit-tests +Running unit tests ------------------ -To run unit tests, ndn-cxx needs to be configured, build with unit test support, and installed +To run the unit tests, ndn-cxx needs to be built with unit test support and installed into the configured location. For example: - ./waf configure --with-tests + ./waf configure --with-tests # --debug is also strongly recommended while developing ./waf sudo ./waf install -**Note**: On Linux platform you also need to run `sudo ldconfig` to reconfigure dynamic loader -run-time bindings. On FreeBSD, use `sudo ldconfig -a` instead. +**Note**: On Linux you also need to run `sudo ldconfig` to reconfigure dynamic loader +run-time bindings. -The simplest way to run tests, is just to run the compiled binary without any parameters: +The simplest way to run the tests is to launch the compiled binary without any parameters: ./build/unit-tests -[Boost.Test framework](http://www.boost.org/doc/libs/1_54_0/libs/test/doc/html/index.html) +[Boost.Test framework](https://www.boost.org/doc/libs/1_58_0/libs/test/doc/html/index.html) is very flexible and allows a number of run-time customization of what tests should be run. For example, it is possible to choose to run only a specific test suite, only a specific test case within a suite, or specific test cases within specific test suites: - # Run only Face test suite tests (tests/unit-tests/face.t.cpp) + # Run only Face test suite tests (tests/unit/face.t.cpp) ./build/unit-tests -t TestFace # Run only test case ExpressInterestData from the same test suite @@ -76,8 +78,8 @@ test case within a suite, or specific test cases within specific test suites: By default, Boost.Test framework will produce verbose output only when a test case fails. If it is desired to see verbose output (result of each test assertion), add `-l all` -option to `./build/unit-tests` command. To see test progress, you can use `-l test_suite` -or `-p` to show progress bar: +option to `./build/unit-tests` command. To see test progress, you can use `-l test_suite`, +or `-p` to show a progress bar: # Show report all log messages including the passed test notification ./build/unit-tests -l all @@ -93,7 +95,7 @@ or `-p` to show progress bar: There are many more command line options available, information about which can be obtained either from the command line using `--help` switch, or online on -[Boost.Test library](http://www.boost.org/doc/libs/1_54_0/libs/test/doc/html/index.html) +[Boost.Test library](https://www.boost.org/doc/libs/1_58_0/libs/test/doc/html/index.html) website. **Warning:** If you have customized parameters for NDN platform using `client.conf` in diff --git a/README.md b/README.md index bf2017944..f661518fc 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,40 @@ -ndn-cxx: NDN C++ library with eXperimental eXtensions -===================================================== +# ndn-cxx: NDN C++ library with eXperimental eXtensions +![Language](https://img.shields.io/badge/C%2B%2B-14-blue.svg) [![Build Status](https://travis-ci.org/named-data/ndn-cxx.svg?branch=master)](https://travis-ci.org/named-data/ndn-cxx) +![Latest Version](https://img.shields.io/github/tag/named-data/ndn-cxx.svg?color=darkkhaki&label=latest%20version) -ndn-cxx is a C++ library, implementing Named Data Networking (NDN) primitives that can be -used to implement various NDN applications. The library is currently being used as part of -the following projects: +**ndn-cxx** is a C++14 library implementing Named Data Networking (NDN) primitives +that can be used to write various NDN applications. The library is currently being +used by the following projects: * [NFD - NDN Forwarding Daemon](https://github.com/named-data/NFD) * [NLSR - Named-data Link-State Routing protocol](https://github.com/named-data/NLSR) +* [ndn-tools - Essential NDN command-line tools](https://github.com/named-data/ndn-tools) * [repo-ng - Next generation of NDN repository](https://github.com/named-data/repo-ng) -* [ChronoChat - Multi-user NDN chat application](https://github.com/named-data/ChronoChat) -* [ChronoSync - Sync library for multiuser realtime applications for NDN](https://github.com/named-data/ChronoSync) -* [ndn-tools - NDN Essential Tools](https://github.com/named-data/ndn-tools) -* [ndn-traffic-generator - Traffic Generator For NDN](https://github.com/named-data/ndn-traffic-generator) +* [ChronoSync - Sync library for multiuser realtime applications](https://github.com/named-data/ChronoSync) +* [PSync - Partial and full synchronization library](https://github.com/named-data/PSync) +* [ndn-traffic-generator - Traffic generator for NDN](https://github.com/named-data/ndn-traffic-generator) +* [NAC - Name-based Access Control](https://github.com/named-data/name-based-access-control) +* [NDNS - Domain Name Service for NDN](https://github.com/named-data/ndns) -See the file [`docs/INSTALL.rst`](https://github.com/named-data/ndn-cxx/blob/master/docs/INSTALL.rst) -for build and install instructions. +## Documentation -Please submit any bugs or issues to the ndn-cxx issue tracker: -https://redmine.named-data.net/projects/ndn-cxx/issues +See [`docs/INSTALL.rst`](docs/INSTALL.rst) for compilation and installation instructions. -## More documentation +Extensive documentation is available on the library's [homepage](https://named-data.net/doc/ndn-cxx/). -Extensive documentation of the library is available on the library's homepage: -http://www.named-data.net/doc/ndn-cxx/ +## Reporting bugs + +Please submit any bugs or feature requests to the +[ndn-cxx issue tracker](https://redmine.named-data.net/projects/ndn-cxx/issues). + +## Contributing + +You're encouraged to contribute to ndn-cxx! Check out the +[Contributor's Guide](https://github.com/named-data/NFD/blob/master/CONTRIBUTING.md) to get started. ## License -ndn-cxx is an open source project licensed under LGPL 3.0 license. For more information about -the license, refer to [`COPYING.md`](https://github.com/named-data/ndn-cxx/blob/master/COPYING.md). +ndn-cxx is an open source project licensed under the LGPL version 3. +See [`COPYING.md`](COPYING.md) for more information. diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst deleted file mode 120000 index ab3c7525d..000000000 --- a/RELEASE_NOTES.rst +++ /dev/null @@ -1 +0,0 @@ -docs/release-notes-latest.rst \ No newline at end of file diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst new file mode 100644 index 000000000..2b137c9ab --- /dev/null +++ b/RELEASE_NOTES.rst @@ -0,0 +1,79 @@ +ndn-cxx version 0.7.0 +--------------------- + +Release date: January 13, 2020 + +**Breaking Change** + +This release features support of only `NDN packet format version 0.3 +`__ (:issue:`4527`, :issue:`4567`, +:issue:`4709`, :issue:`4913`). The library encodes and interprets Interest and Data +packets only in 0.3 format; support for version 0.2 has been completely removed. In +addition, the URI representation of Interest packets has also been changed following the +packet format updates. + +New features +^^^^^^^^^^^^ + +- HMAC signing support (:issue:`3075`) + +- Support for ``ParametersSha256DigestComponent`` in ``Name`` and ``Interest`` classes + (:issue:`4658`) + +- Encoding/decoding of ``HopLimit`` field in Interest (:issue:`4806`) + +- PIT token (:issue:`4532`). + + PIT token is a hop-by-hop header field that identifies an Interest-Data exchange. The + downstream node can assign an opaque token to an outgoing Interest, and the upstream node + is expected to return the same token on the Data or Nack in reply to that Interest. This + would allow the downstream node to accelerate its processing, especially in PIT lookup. + +- ``io::loadBuffer`` and ``io::saveBuffer`` helper functions + +Improvements and bug fixes +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Various improvements in the Linux implementation of ``NetworkMonitor`` class + +- Rework of ``RttEstimator`` class: + + * split into two classes: ``RttEstimator`` and ``RttEstimatorWithStats`` (:issue:`4887`) + * add a getter for the smoothed RTT value (:issue:`4892`) + * switch to use ``time::nanoseconds`` (:issue:`4887`) + +- Make use of attributes in logging facilities and generalize logger backend support + (:issue:`4969`, :issue:`3782`) + +- Silently accept an empty validation policy instead of throwing an exception (:issue:`5049`) + +- Introduce alternative URI syntax for component types used in naming conventions, with + ability to choose between canonical and alternate format (:issue:`4777`) + +- Don't force the generation of an Interest nonce during decoding (:issue:`4685`) + +- Various documentation improvements + +Removals +^^^^^^^^ + +- ``ndn::util::Scheduler`` (use ``ndn::Scheduler`` or ``ndn::scheduler::Scheduler``) and + ``ndn::EventId`` (use ``ndn::scheduler::EventId``) (:issue:`4883`) + +- Unused ``KeyClass`` and ``AclType`` enums + +- Unused ``v2::PublicKey`` alias of ``transform::PublicKey`` + +- ``HmacFilter`` class, use SignerFilter and VerifierFilter instead + +- Ill-defined equality operators for ``Interest``, ``MetaInfo``, ``Signature`` (:issue:`4569`) + +- Implicit conversion from the ``xyzHandle`` types to ``const xyzId*`` (where ``xyz`` is + ``PendingInterest``, ``RegisteredPrefixId``, and ``InterestFilterId``) + +- Deprecated ``KeyLocator::Type`` enum + +- Private header files of concrete PIB, TPM, and KeyHandle implementations are no longer + installed (:issue:`4782`) + +- Renamed ``util/backports-ostream-joiner.hpp`` to ``util/ostream-joiner.hpp`` diff --git a/client.conf.sample b/client.conf.sample index abed4ffbf..9eae16e71 100644 --- a/client.conf.sample +++ b/client.conf.sample @@ -1,25 +1,24 @@ ; "transport" specifies Face's default transport connection. -; The value is a unix or tcp4 scheme Face URI. +; The value can be a "unix:" or "tcp4:" Face URI. ; ; For example: -; ; unix:///var/run/nfd.sock ; tcp://192.0.2.1 ; tcp4://example.com:6363 - +; transport=unix:///var/run/nfd.sock ; "pib" determines which Public Info Base (PIB) should used by default in applications. -; If "pib" is not specified, the default PIB will be used. -; Note that default PIB could be different on different system. +; If "pib" is not specified, a platform-dependent default will be used. ; If "pib" is specified, it may have a value of: ; pib-sqlite3 -; pib=pib-sqlite3 +; +;pib=pib-sqlite3 ; "tpm" determines which Trusted Platform Module (TPM) should used by default in applications. -; If "tpm" is not specified, the default TPM will be used. -; Note that default TPM could be different on different system. +; If "tpm" is not specified, a platform-dependent default will be used. ; If "tpm" is specified, it may have a value of: -; tpm-osxkeychain (default in OS X) -; tpm-file (default in operating systems other than OS X) -; tpm=tpm-file \ No newline at end of file +; tpm-osxkeychain (default on macOS) +; tpm-file (default in operating systems other than macOS) +; +;tpm=tpm-file diff --git a/docs/INSTALL.rst b/docs/INSTALL.rst index 99f02df8d..4156a5ef8 100644 --- a/docs/INSTALL.rst +++ b/docs/INSTALL.rst @@ -9,21 +9,22 @@ Supported platforms ndn-cxx uses continuous integration and has been tested on the following platforms: -- Ubuntu 14.04 (64-bit and 32-bit) -- Ubuntu 16.04 (64-bit and 32-bit) -- OS X 10.9 -- OS X 10.10 -- OS X 10.11 -- macOS 10.12 +- Ubuntu 16.04 (amd64, armhf, i386) +- Ubuntu 18.04 (amd64) +- Ubuntu 19.10 (amd64) +- macOS 10.13 +- macOS 10.14 +- macOS 10.15 +- CentOS 7 (with gcc 7 and boost 1.58.0) ndn-cxx is known to work on the following platforms, although they are not officially supported: -- Fedora >= 20 -- CentOS >= 6.2 +- Debian >= 9 +- Fedora >= 24 - Gentoo Linux -- FreeBSD >= 10.0 -- Raspbian >= 3.12 +- Raspbian >= 2017-08-16 +- FreeBSD 11.2 Prerequisites ------------- @@ -31,50 +32,48 @@ Prerequisites Required: ~~~~~~~~~ -- ``python`` >= 2.6 -- ``libsqlite3`` -- ``libcrypto++`` -- OpenSSL >= 1.0.1 +- GCC >= 5.3, or clang >= 3.6 +- ``python2`` >= 2.7, or ``python3`` >= 3.4 +- Boost libraries >= 1.58 - ``pkg-config`` -- Boost libraries >= 1.54 -- OSX Security framework (on OSX/macOS platform only) +- SQLite 3.x +- OpenSSL >= 1.0.2 +- Apple Security framework (on macOS only) Following are the detailed steps for each platform to install the compiler, all necessary development tools and libraries, and ndn-cxx prerequisites. -- OS X / macOS +- macOS - Install Xcode from AppStore or at least Command Line Tools (``xcode-select --install``) + * Install Xcode from the App Store, or at least the Command Line Tools + (``xcode-select --install``) - * When using MacPorts + * If using Homebrew (recommended), enter the following in a terminal:: - In a terminal, enter:: + brew install boost openssl pkg-config - sudo port install pkgconfig boost sqlite3 libcryptopp openssl + .. note:: - * When using Homebrew + If a major OS upgrade is performed after installing the dependencies + with Homebrew, remember to reinstall all packages. - In a terminal, enter:: +- Ubuntu - brew install boost pkg-config cryptopp openssl - - .. note:: + In a terminal, enter:: - If a major OS upgrade is performed after installing dependencies with - MacPorts or Homebrew, remember to reinstall all packages. + sudo apt install build-essential libboost-all-dev libssl-dev libsqlite3-dev pkg-config python-minimal -- Ubuntu +- Fedora In a terminal, enter:: - sudo apt-get install build-essential libcrypto++-dev libsqlite3-dev libboost-all-dev libssl-dev + sudo yum install gcc-g++ sqlite-devel boost-devel openssl-devel -- Fedora +- FreeBSD In a terminal, enter:: - sudo yum install gcc-g++ git - sudo yum install sqlite-devel cryptopp-devel boost-devel openssl-devel + sudo pkg install python pkgconf sqlite3 boost-libs Optional: ~~~~~~~~~ @@ -84,49 +83,48 @@ dependencies need to be installed: - ``doxygen`` - ``graphviz`` -- ``python-sphinx`` and sphinx extensions ``sphinxcontrib-doxylink``, - ``sphinxcontrib-googleanalytics`` +- ``python-sphinx`` +- ``sphinxcontrib-doxylink`` The following lists steps for common platforms to install these prerequisites: -- On OS X / macOS with MacPorts:: +- On macOS with Homebrew and pip:: + + brew install doxygen graphviz + sudo pip install sphinx sphinxcontrib-doxylink + +- On Ubuntu:: - sudo port install doxygen graphviz py27-sphinx sphinx_select - sudo port select sphinx py27-sphinx + sudo apt install doxygen graphviz python3-pip + sudo pip3 install sphinx sphinxcontrib-doxylink - # Install sphinx extensions - sudo port install py27-pip - sudo port select pip pip27 - sudo pip install sphinxcontrib-doxylink sphinxcontrib-googleanalytics +- On Fedora:: -- On Ubuntu:: + sudo yum install doxygen graphviz python-sphinx + sudo pip install sphinxcontrib-doxylink - sudo apt-get install doxygen graphviz python-sphinx python-pip - sudo pip install sphinxcontrib-doxylink sphinxcontrib-googleanalytics +- On FreeBSD:: -- On Fedora:: + sudo pkg install doxygen graphviz py27-sphinx - sudo yum install doxygen graphviz python-sphinx - sudo pip install sphinxcontrib-doxylink sphinxcontrib-googleanalytics .. _build: Build ----- -(These are instructions to build ndn-cxx. To do development of ndn-cxx -code and update the build system, see Development.) +.. note:: + These are instructions for regular builds of ndn-cxx (release mode). + To do development of ndn-cxx code itself, see "Development build" below. -To build in a terminal, change directory to the ndn-cxx root. Enter: - -:: +To build in a terminal, change directory to the ndn-cxx root, then enter:: ./waf configure ./waf sudo ./waf install By default, only the shared version of ndn-cxx library is built. To build the static library, -use ``--enable-static`` option for ``./waf configure`` command. For example:: +use ``--enable-static`` option for ``./waf configure`` command:: ./waf configure --enable-static @@ -138,83 +136,63 @@ enabled. ./waf configure --enable-static --disable-shared +After the shared library is installed, on Linux it is also necessary to run:: -After the shared library is built and installed, some systems require additional actions. - - - on Linux:: - - sudo ldconfig - - - on FreeBSD:: - - sudo ldconfig -m + sudo ldconfig - .. note:: - When library is installed in a non-standard path (in general: not in ``/usr/lib`` or - ``/usr/local/lib``; on some Linux distros including Fedora: not in ``/usr/lib``), - additional actions may be necessary. +.. note:: + When the library is installed in a non-standard path (in general: not in ``/usr/lib`` + or ``/usr/local/lib``; on some Linux distros including Fedora: not in ``/usr/lib``), + additional actions may be necessary. - The installation path should be added to ``/etc/ld.so.conf`` (or in - ``/etc/ld.so.conf.d``) **before** running ``sudo ldconfig``. For example:: + The installation path should be added to ``/etc/ld.so.conf`` (or in + ``/etc/ld.so.conf.d``) **before** running ``sudo ldconfig``. For example:: - echo /usr/local/lib | sudo tee /etc/ld.so.conf.d/ndn-cxx.conf + echo /usr/local/lib | sudo tee /etc/ld.so.conf.d/ndn-cxx.conf - Alternatively, ``LD_LIBRARY_PATH`` environment variable should be set to the location of - the library:: + Alternatively, the ``LD_LIBRARY_PATH`` environment variable can be set to point to + the installation directory of the shared library:: - export LD_LIBRARY_PATH=/usr/local/lib + export LD_LIBRARY_PATH=/usr/local/lib -This builds and installs the following items: +The ``./waf install`` command installs the following files: -- ``/libndn-cxx.a``: static NDN C++ library (if enabled) +- ``/libndn-cxx.a``: static NDN C++ library (if enabled). - ``/libndn-cxx.so``, ``/libndn-cxx.so.`` (on Linux), - ``/libndn-cxx.dylib``, ``/libndn-cxx..dylib`` (on OS X): - shared NDN C++ library (if enabled) + ``/libndn-cxx.dylib``, ``/libndn-cxx..dylib`` (on macOS): + shared NDN C++ library (if enabled). - ``/pkgconfig/libndn-cxx.pc``: pkgconfig file storing all neccessary flags to build against the library. For example, if - pkgconfig or pkgconf package is installed and ``PKG_CONFIG_PATH`` is + pkg-config or pkgconf package is installed and ``PKG_CONFIG_PATH`` is configured properly (or ``/pkgconfig`` is a default path), ``pkgconfig --libs --clflags libndn-cxx`` will return all necessary compile and link flags for the library. -- ``/ndnsec``: tool to manage NDN keys and certificates -- ``/ndnsec-*``: convenience scripts for ``ndnsec`` tools +- ``/ndnsec``: tool to manage NDN keys and certificates. +- ``/ndnsec-*``: convenience aliases for ``ndnsec`` tools. -If configured with tests: ``./waf configure --with-tests``), the above +If configured with tests (``./waf configure --with-tests``), the above commands will also produce: -- ``build/unit-tests``: A unit test binary for the library +- ``build/unit-tests``: a unit test binary for the library. 1.5GB available memory per CPU core is necessary for efficient compilation. On a multi-core machine with less than 1.5GB available memory per CPU core, limit the objects being compiled in parallel with ``./waf -jN`` where N is the amount of available memory divided by 1.5GB (eg. ``./waf -j1`` for 1.5GB memory), -which could usually avoid memory thrashing and result in faster compilation. +which should usually avoid memory thrashing and result in faster compilation. Build with examples ------------------- -By default, examples in ``examples/`` are not build. To enable them, use -``--with-examples`` configure option: - -:: +By default, examples in ``examples/`` are not built. To enable them, use the +``--with-examples`` configure option:: ./waf configure --with-examples ./waf sudo ./waf install + sudo ldconfig # (on Linux only) -:ref:`Additional step `: - - - on Linux:: - - sudo ldconfig - - - on FreeBSD:: - - sudo ldconfig -m - -To run examples: - -:: +To run examples:: # trivial producer app ./build/examples/producer @@ -226,16 +204,14 @@ To run examples: ./build/examples/consumer-with-timer If you want to test out a sample application, just create a ``.cpp`` file in ``examples/`` -folder and it will be compiled on the next run on ``./waf``. For example: - -:: +folder and it will be compiled on the next run on ``./waf``. For example:: cp examples/consumer.cpp examples/my-new-consumer-app.cpp ./waf sudo ./waf install + sudo ldconfig # (on Linux only) ./build/examples/my-new-consumer-app - Debug symbols ~~~~~~~~~~~~~ @@ -243,31 +219,18 @@ The default compiler flags enable debug symbols to be included in binaries (i.e. flag for ``./waf configure`` and ``-g3`` for ``./waf configure --debug``). This potentially allows more meaningful debugging information if your application crashes. -If it is undesirable, default flags can be easily overridden: - -:: +The default build flags can easily be overridden:: CXXFLAGS="-O2" ./waf configure --prefix=/usr --sysconfdir=/etc ./waf sudo ./waf install -:ref:`Additional step `: - - - on Linux:: - - sudo ldconfig - - - on FreeBSD:: - - sudo ldconfig -m Documentation ------------- ndn-cxx tutorials and API documentation can be built using the following -commands: - -:: +commands:: # Full set of documentation (tutorials + API) in build/docs ./waf docs @@ -276,7 +239,7 @@ commands: ./waf sphinx # Only API docs in `build/docs/doxygen` - ./waf doxgyen + ./waf doxygen Manpages are automatically created and installed during the normal build process (e.g., during ``./waf`` and ``./waf install``), if @@ -288,44 +251,31 @@ changed during ``./waf configure`` stage using ``--prefix``, For more details, refer to ``./waf --help``. -Development Build ------------------ -The following is the suggested configure commands for development build. +Development build +----------------- -:: +The following is the suggested configure command for development builds:: ./waf configure --debug --with-tests ./waf sudo ./waf install + sudo ldconfig # (on Linux only) -:ref:`Additional step `: - - - on Linux:: - - sudo ldconfig - - - on FreeBSD:: - - sudo ldconfig -m - -In the development build all compiler optimizations are disabled by -default and all warnings are treated as error. The default behavior can +In the development build most compiler optimizations are disabled by +default and all warnings are treated as errors. The default behavior can be overridden by setting ``CXXFLAGS`` environment variable before -running ``./waf configure``: - -:: +running ``./waf configure``:: CXXFLAGS="-O1 -g3" ./waf configure --debug --with-tests ... -Customize Compiler ------------------- -To choose a custom C++ compiler for building ndn-cxx, set ``CXX`` environment -variable to point to the compiler binary. For example, to build with clang on -Linux, use the following: +Customizing the compiler +------------------------ -:: +To choose a custom C++ compiler for building ndn-cxx, set the ``CXX`` environment +variable to point to the compiler binary. For example, to build with clang on +Linux, use the following:: CXX=clang++ ./waf configure diff --git a/docs/README.rst b/docs/README.rst deleted file mode 100644 index b58f1258b..000000000 --- a/docs/README.rst +++ /dev/null @@ -1,22 +0,0 @@ -ndn-cxx overview -================ - -ndn-cxx is a C++ library, implementing Named Data Networking (NDN) primitives that can be -used to implement various NDN applications. The library is currently being used as part of -the following projects: - -- `NFD - NDN Forwarding Daemon `__ -- `NLSR - Named-data Link-State Routing - protocol `__ -- `repo-ng - Next generation of NDN - repository `__ -- `ChronoChat - Multi-user NDN chat - application `__ -- `ChronoSync - Sync library for multiuser realtime applications for - NDN `__ -- `ndn-tools - NDN Essential Tools `__ -- `ndn-traffic-generator - Traffic Generator For - NDN `__ - -Please submit any bugs or issues to the `ndn-cxx issue tracker -`__. diff --git a/docs/code-style.rst b/docs/code-style.rst index dff6b8641..cc711922d 100644 --- a/docs/code-style.rst +++ b/docs/code-style.rst @@ -52,7 +52,7 @@ extended it to C++. } // namespace example - Note that code inside namespace is **not** indented. Avoid following: + Note that code inside namespace is **not** indented. Avoid the following: .. code-block:: c++ @@ -65,7 +65,7 @@ extended it to C++. // // } // namespace example -1.4. The class declarations should have the following form: +1.4. Class declarations should have the following form: .. code-block:: c++ @@ -73,21 +73,25 @@ extended it to C++. { public: ... ... + protected: ... ... + private: ... ... public: ... ... + protected: ... ... + private: ... ... }; ``public``, ``protected``, ``private`` may be repeated several times without - interleaving (e.g., public, public, public, private, private) if this allows better + interleaving (e.g., public, public, public, private, private) if this improves readability of the code. Nested classes can be defined in appropriate visibility section, either in methods @@ -135,23 +139,6 @@ extended it to C++. statements; } - or (less preferred): - - .. code-block:: c++ - - if (condition) - { - statements; - } - else if (condition) - { - statements; - } - else - { - statements; - } - 1.7. A ``for`` statement should have the following form: .. code-block:: c++ @@ -160,23 +147,14 @@ extended it to C++. statements; } - or (less preferred): - - .. code-block:: c++ - - for (initialization; condition; update) - { - statements; - } - - An empty for statement should have the following form: + An empty ``for`` statement should have the following form: .. code-block:: c++ for (initialization; condition; update) ; - This emphasizes the fact that the for statement is empty and it makes it obvious for + This emphasizes the fact that the ``for`` statement is empty and makes it obvious for the reader that this is intentional. Empty loops should be avoided however. 1.8. A ``while`` statement should have the following form: @@ -187,15 +165,6 @@ extended it to C++. statements; } - or (less preferred): - - .. code-block:: c++ - - while (condition) - { - statements; - } - 1.9. A ``do-while`` statement should have the following form: .. code-block:: c++ @@ -211,7 +180,7 @@ extended it to C++. switch (condition) { case ABC: // 2 space indent statements; // 4 space indent - // Fallthrough + NDN_CXX_FALLTHROUGH; case DEF: statements; @@ -242,7 +211,7 @@ extended it to C++. // Correct style case A1: { statements; - // Fallthrough + NDN_CXX_FALLTHROUGH; } // Incorrect style: braces should cover the entire case block @@ -263,7 +232,7 @@ extended it to C++. switch (condition) { case ABC: // no indent statements; // 2 space indent - // Fallthrough + NDN_CXX_FALLTHROUGH; case DEF: statements; @@ -274,9 +243,11 @@ extended it to C++. break; } - The explicit ``Fallthrough`` comment should be included whenever there is a case - statement without a break statement. Leaving the break out is a common error, and it - must be made clear that it is intentional when it is not there. + The ``NDN_CXX_FALLTHROUGH;`` annotation must be included whenever there is + a case without a break statement. Leaving the break out is a common error, + and it must be made clear that it is intentional when it is not there. + Moreover, modern compilers will warn when a case that falls through is not + explicitly annotated. 1.11. A ``try-catch`` statement should have the following form: @@ -289,19 +260,6 @@ extended it to C++. statements; } - or (less preferred): - - .. code-block:: c++ - - try - { - statements; - } - catch (const Exception& exception) - { - statements; - } - 1.12. The incompleteness of split lines must be made obvious. .. code-block:: c++ @@ -315,9 +273,9 @@ extended it to C++. ... } - Split lines occurs when a statement exceed the 80 column limit given above. It is + Split lines occur when a statement exceeds the column limit given in rule 1.1. It is difficult to give rigid rules for how lines should be split, but the examples above should - give a general hint.In general: + give a general hint. In general: * Break after a comma. * Break after an operator. @@ -325,7 +283,7 @@ extended it to C++. Exceptions: - * The following is the standard practice with operator<<: + * The following is standard practice with ``operator<<``: .. code-block:: c++ @@ -371,7 +329,7 @@ should take the following form: statements; } - If the function has no parameters, ``()`` should be omitted. + If the lambda has no parameters, ``()`` should be omitted. .. code-block:: c++ @@ -379,8 +337,8 @@ should take the following form: statements; } - Capture-all (``[&]`` and ``[=]``) is permitted, but its usage should be minimized. - Only use capture-all when it significantly simplifies code and improves readability. + Either capture-default (``[&]`` or ``[=]``) is permitted, but its usage should be minimized. + Only use a capture-default when it significantly simplifies code and improves readability. .. code-block:: c++ @@ -392,9 +350,9 @@ should take the following form: statements; } - Trailing return type should be omitted. Write them only when compiler cannot deduce - return type automatically, or when it improves readability. - ``()`` is required by C++ standard when trailing return type is written. + Trailing return type should be omitted whenever possible. Add it only when the compiler + cannot deduce the return type automatically, or when it improves readability. + ``()`` is required by the C++ standard when ``mutable`` or a trailing return type is used. .. code-block:: c++ @@ -474,7 +432,6 @@ extension ``.cpp`` my-class.hpp, my-class.cpp - 2.2. Names representing types must be written in English in mixed case starting with upper case. .. code-block:: c++ @@ -502,11 +459,11 @@ to separate words. static const double PI = 3.14; In some cases, it is a better (or is the only way for complex constants in header-only - classes) to implement the value as a method: + classes) to implement the value as a method. .. code-block:: c++ - int + static int // declare constexpr if possible getMaxIterations() { return 25; @@ -541,19 +498,19 @@ written in mixed case starting with lower case. } // namespace analyzer } // namespace model -2.7. Names representing generic template types should be a single uppercase letter +2.7. Names representing generic template types should be a single uppercase letter. .. code-block:: c++ template ... template ... - However, when template parameter represents a certain concept and expected to have a - certain interface, the name should be explicitly spelled out: + However, when a template parameter represents a certain concept and is expected + to have a certain interface, the name should be explicitly spelled out. .. code-block:: c++ - template ... + template ... template ... 2.8. Abbreviations and acronyms must not be uppercase when used as name. @@ -586,7 +543,6 @@ written in mixed case starting with lower case. static std::string s_name; }; - 2.11. Variables with a large scope should have long (explicit) names, variables with a small scope can have short names. @@ -654,16 +610,11 @@ scope can have short names. The notation is taken from mathematics where it is an established convention for indicating a number of objects. - -2.18. The suffix ``No`` should be used for variables representing an entity number. +2.18. The suffix ``Num`` or ``No`` should be used for variables representing an entity number. .. code-block:: c++ - tableNo, employeeNo - - The notation is taken from mathematics where it is an established convention for - indicating an entity number. An elegant alternative is to prefix such variables with - an ``i``: ``iTable``, ``iEmployee``. This effectively makes them named iterators. + tableNum, tableNo, employeeNum, employeeNo 2.19. The prefix ``is``, ``has``, ``need``, or similar should be used for boolean variables and methods. @@ -718,9 +669,9 @@ notation). 2.24. Exceptions can be suffixed with either ``Exception`` (e.g., ``SecurityException``) or ``Error`` (e.g., ``SecurityError``). - The recommended method is to declare exception class ``Exception`` or ``Error`` as an - inner class, from which the exception is thrown. For example, when declaring class - ``Foo`` that can throw errors, one can write the following: + The recommended method is to declare an exception class ``Exception`` or ``Error`` as + a nested type inside the class from which the exception is thrown. For example, when + defining a class ``Foo`` that can throw errors, one can write the following: .. code-block:: c++ @@ -728,12 +679,16 @@ notation). class Foo { + public: class Error : public std::runtime_error { public: - explicit - Error(const std::string& what) - : std::runtime_error(what) + // You can inherit constructors from std::runtime_error like this: + using std::runtime_error::runtime_error; + + // Additional constructors, if desired, can be declared as usual: + Error(const std::string& what, const std::exception& inner) + : std::runtime_error(what + ": " + inner.what()) { } }; @@ -743,7 +698,6 @@ notation). hierarchy, then child classes should should define their own ``Error`` or ``Exception`` classes that are inherited from the parent's Error class. - 2.25. Functions (methods returning something) should be named after what they return and procedures (void methods) after what they do. @@ -759,8 +713,8 @@ not in the primary processing path. 3.2. Header files must contain an include guard. - For example, header file located in ``module/class-name.hpp`` or in - ``src/module/class-name.hpp`` should have header guard in the following form: + For example, a header file named ``module/class-name.hpp`` or + ``src/module/class-name.hpp`` should have a header guard in the following form: .. code-block:: c++ @@ -769,40 +723,43 @@ not in the primary processing path. ... #endif // APP_MODULE_CLASS_NAME_HPP - The name should follow the location of the file inside the source tree and prevents - naming conflicts. Header guard should be prefixed with the application/library name - to avoid conflicts with other packaged and libraries. + The macro name should reflect the path of the header file relative to the root of the + source tree, in order to prevent naming conflicts. The header guard should be prefixed + with the application/library name to avoid conflicts with other packages and libraries. -3.3. Header files which are in the same source distribution should be included in -``"quotes"``, if possible with a path relative to the source file. Header files for -system and other external libraries should be included in ````. +3.3. Include directives for system headers and other external libraries should use +````. Header files in the same source code repository should be included +using ``"quotes"``. .. code-block:: c++ + #include "ndn-cxx/util/random.hpp" + #include #include - #include "util/random.hpp" + All of a project's header files should be included with their path relative to + the project's source directory. The use of UNIX directory shortcuts ``.`` + (the current directory) and ``..`` (the parent directory) is discouraged. -3.4. Include statements should be sorted and grouped. Sorted by their hierarchical position -in the system with low level files included first. Leave an empty line between groups -of include statements. +3.4. Include statements should be grouped. Same-project headers should be included first. +Leave an empty line between groups of include statements. Sort alphabetically within a group. +For example, the include section of ``ndn-cxx/foo/bar.cpp`` may look like this: .. code-block:: c++ + #include "ndn-cxx/impl/pending-interest.hpp" + #include "ndn-cxx/util/random.hpp" + + #include #include #include #include #include - #include "detail/pending-interest.hpp" - #include "util/random.hpp" - - 3.5. Types that are local to one file only can be declared inside that file. - 3.6. Implicit conversion is generally allowed. Implicit conversion between integer and floating point numbers can cause problems and @@ -816,11 +773,10 @@ of include statements. ``const_cast`` instead where appropriate. Use ``static_pointer_cast``, ``dynamic_pointer_cast``, ``const_pointer_cast`` when dealing with ``shared_ptr``. - 3.7. Variables should be initialized where they are declared. This ensures that variables are valid at any time. Sometimes it is impossible to - initialize a variable to a valid value where it is declared: + initialize a variable to a valid value where it is declared. .. code-block:: c++ @@ -830,21 +786,20 @@ of include statements. In these cases it should be left uninitialized rather than initialized to some phony value. -3.8. In most cases, class instance variables should not be declared public. +3.8. In most cases, class data members should not be declared ``public``. - The concepts of information hiding and encapsulation are violated by public variables. Use - private variables and access methods instead. + Public data members violate the concepts of information hiding and encapsulation. + Use private variables and public accessor methods instead. Exceptions to this rule: - * when the class is essentially a dumb data structure with no or minimal behavior - (equivalent to a C struct, also known as PODS). In this case it is appropriate to make - the instance variables public by using struct. + * When the class is essentially a dumb data structure with no or minimal behavior + (equivalent to a C struct, also known as POD type). In this case it is appropriate + to make the instance variables public by using ``struct``. - * when the class is used only inside the compilation unit, e.g., when implementing pImpl + * When the class is used only inside the compilation unit, e.g., when implementing pImpl idiom (aka Bridge pattern) or similar cases. - 3.9. C++ pointers and references should have their reference symbol next to the type rather than to the name. @@ -866,13 +821,13 @@ than to the name. .. code-block:: c++ - isDone = false; // NOT: bool isDone = false; + bool isDone = false; // NOT: bool isDone = false; while (!isDone) { // // other stuff - : // while (!isDone) { - } // : + ... // while (!isDone) { + } // ... // } -3.13. The form while (true) should be used for infinite loops. +3.13. The form ``while (true)`` should be used for infinite loops. .. code-block:: c++ @@ -905,7 +860,7 @@ instead. // } By assigning boolean variables to expressions, the program gets automatic - documentation. The construction will be easier to read, debug and maintain. + documentation. The construction will be easier to read, debug, and maintain. 3.15. The conditional should be put on a separate line. @@ -935,11 +890,11 @@ instead. should be considered declared as named constants instead. If the number does not have an obvious meaning by itself, the readability is enhanced - by introducing a named constant instead. A different approach is to introduce a method + by introducing a named constant instead. A different approach is to introduce a method from which the constant can be accessed. -3.18. Floating point constants should always be written with decimal point, at least one - decimal, and without omitting 0 before decimal point. +3.18. Floating point literals should always be written with a decimal point, at least one +decimal, and without omitting 0 before the decimal point. .. code-block:: c++ @@ -952,9 +907,9 @@ should be considered declared as named constants instead. 3.19. ``goto`` should not be used. -Goto statements violate the idea of structured code. Only in some very few cases (for -instance breaking out of deeply nested structures) should goto be considered, and only if -the alternative structured counterpart is proven to be less readable. + ``goto`` statements violate the idea of structured code. Only in very few cases (for + instance, breaking out of deeply nested structures) should ``goto`` be considered, + and only if the alternative structured counterpart is proven to be less readable. 3.20. ``nullptr`` should be used to represent a null pointer, instead of "0" or "NULL". @@ -1004,7 +959,7 @@ the alternative structured counterpart is proven to be less readable. 3.24. All comments should be written in English. - In an international environment English is the preferred language. + In an international environment, English is the preferred language. 3.25. Use ``//`` for all comments, including multi-line comments. @@ -1021,7 +976,7 @@ the alternative structured counterpart is proven to be less readable. always start with an upper case letter and end with a period. However, method and class documentation comments should use ``/** */`` style for - Doxygen, JavaDoc and JSDoc. + Doxygen, JavaDoc and JSDoc. License boilerplate should use ``/* */`` style. 3.26. Comments should be included relative to their position in the code. @@ -1089,7 +1044,6 @@ the alternative structured counterpart is proven to be less readable. .. code-block:: c++ std::list strings; - for (const auto& str : strings) { statements; // cannot modify `str` } @@ -1097,11 +1051,14 @@ the alternative structured counterpart is proven to be less readable. statements; // can modify `str` } -3.30. Annotate with ``override`` or ``final`` when overriding a virtual method or destructor. +3.30. Use the ``override`` or ``final`` specifier when overriding a virtual +member function or a virtual destructor. + + ``virtual`` MUST NOT be used along with ``final``, so that the compiler + can generate an error when a final function does not override. - ``virtual`` should still be used along with ``override`` and ``final``, - so that a human reader can easily recognize a virtual method - without looking toward the end of the function signature. + ``virtual`` SHOULD NOT be used along with ``override``, for consistency + with ``final``. .. code-block:: c++ @@ -1115,19 +1072,18 @@ the alternative structured counterpart is proven to be less readable. class InputStream : public Stream { public: - virtual void + void open() override; }; class Console : public InputStream { public: - virtual void - open() override; + void + open() final; }; 3.31. The recommended way to throw an exception derived from ``std::exception`` is to use -the ``BOOST_THROW_EXCEPTION`` -`macro `__. -Exceptions thrown using this macro will be augmented with additional diagnostic information, -including file name, line number, and function name from where the exception was thrown. +``NDN_THROW`` or one of the other ``NDN_THROW_*`` macros. +Exceptions thrown using these macros will be augmented with additional diagnostic information, +including the file name, line number, and function name from which the exception was thrown. diff --git a/docs/conf.py b/docs/conf.py index dbcdd3bc1..7e7368021 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,37 +1,53 @@ # -*- coding: utf-8 -*- # -# NFD - Named Data Networking Forwarding Daemon documentation build configuration file, created by -# sphinx-quickstart on Sun Apr 6 19:58:22 2014. +# Configuration file for the Sphinx documentation builder. # -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# http://www.sphinx-doc.org/en/master/config -import sys -import os -import re +# -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('.')) +# +import os +import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = u'ndn-cxx: NDN C++ library with eXperimental eXtensions' +copyright = u'Copyright © 2013-2019 Regents of the University of California.' +author = u'Named Data Networking Project' + +# The short X.Y version +#version = '' + +# The full version, including alpha/beta/rc tags +#release = '' + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +today_fmt = '%Y-%m-%d' + -# -- General configuration ------------------------------------------------ +# -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# +needs_sphinx = '1.1' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ + 'sphinx.ext.extlinks', 'sphinx.ext.todo', - 'redmine_issue', ] def addExtensionIfExists(extension): @@ -39,239 +55,109 @@ def addExtensionIfExists(extension): __import__(extension) extensions.append(extension) except ImportError: - sys.stderr.write("Extension '%s' in not available. " + sys.stderr.write("Extension '%s' not found. " "Some documentation may not build correctly.\n" % extension) - sys.stderr.write("To install, use \n" - " sudo pip install %s\n" % extension.replace('.', '-')) - -addExtensionIfExists('sphinxcontrib.doxylink') - -if os.getenv('GOOGLE_ANALYTICS', None): - addExtensionIfExists('sphinxcontrib.googleanalytics') - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] -# The suffix of source filenames. -source_suffix = '.rst' +if sys.version_info[0] >= 3: + addExtensionIfExists('sphinxcontrib.doxylink') -# The encoding of source files. -#source_encoding = 'utf-8-sig' +# sphinxcontrib.googleanalytics is currently not working with the latest version of Sphinx +# if os.getenv('GOOGLE_ANALYTICS', None): +# addExtensionIfExists('sphinxcontrib.googleanalytics') # The master toctree document. master_doc = 'index' -# General information about the project. -project = u'ndn-cxx: NDN C++ library with eXperimental eXtensions' -copyright = u'Copyright (c) 2013-2015 Regents of the University of California.' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. exclude_patterns = [] -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- +# -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -# html_theme = 'default' +# html_theme = 'named_data_theme' -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - # Add any paths that contain custom themes here, relative to this directory. -html_theme_path = ['./'] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None +html_theme_path = ['.'] # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -html_file_suffix = ".html" - -# Output file base name for HTML help builder. -htmlhelp_basename = 'ndn-cxx-docs' - - -# -- Options for LaTeX output --------------------------------------------- +# -- Options for LaTeX output ------------------------------------------------ latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', -# Additional stuff for the LaTeX preamble. -#'preamble': '', + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - ('index', 'ndn-cxx-docs.tex', u'NDN C++ library with eXperimental eXtensions', - u'Named Data Networking Project', 'manual'), + ('index', 'ndn-cxx-docs.tex', u'NDN C++ library with eXperimental eXtensions', + author, 'manual'), ] -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - -# -- Options for manual page output --------------------------------------- +# -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('manpages/ndnsec', 'ndnsec', u'NDN security tools', None, 1), - ('manpages/ndnsec-cert-dump', 'ndnsec-cert-dump', 'part of NDN security tools', None, 1), - ('manpages/ndnsec-cert-gen', 'ndnsec-cert-gen', 'part of NDN security tools', None, 1), - ('manpages/ndnsec-cert-revoke', 'ndnsec-cert-revoke', 'part of NDN security tools', None, 1), - ('manpages/ndnsec-cert-install', 'ndnsec-cert-instal', 'part of NDN security tools', None, 1), - ('manpages/ndnsec-delete', 'ndnsec-delete', 'part of NDN security tools', None, 1), - ('manpages/ndnsec-export', 'ndnsec-export', 'part of NDN security tools', None, 1), - ('manpages/ndnsec-get-default', 'ndnsec-get-default', 'part of NDN security tools', None, 1), - ('manpages/ndnsec-import', 'ndnsec-import', 'part of NDN security tools', None, 1), - ('manpages/ndnsec-key-gen', 'ndnsec-key-gen', 'part of NDN security tools', None, 1), - ('manpages/ndnsec-list', 'ndnsec-list', 'part of NDN security tools', None, 1), - ('manpages/ndnsec-set-acl', 'ndnsec-set-acl', 'part of NDN security tools', None, 1), - ('manpages/ndnsec-set-default', 'ndnsec-set-default', 'part of NDN security tools', None, 1), - ('manpages/ndnsec-sign-req', 'ndnsec-sign-req', 'part of NDN security tools', None, 1), - ('manpages/ndnsec-unlock-tpm', 'ndnsec-unlock-tpm', 'part of NDN security tools', None, 1), - ('tutorials/security-validator-config', 'ndnsec-validator.conf', - 'NDN trust validator configuration file', None, 5), - ('manpages/ndn-client.conf', 'ndn-client.conf', 'Configuration file for NDN platform', None, 5), + ('manpages/ndnsec', 'ndnsec', 'NDN security toolkit', None, 1), + ('manpages/ndnsec-cert-dump', 'ndnsec-cert-dump', 'export an NDN certificate', None, 1), + ('manpages/ndnsec-cert-gen', 'ndnsec-cert-gen', 'create an NDN certificate for an identity', None, 1), + ('manpages/ndnsec-cert-install', 'ndnsec-cert-install', 'import an NDN certificate from a file', None, 1), + ('manpages/ndnsec-delete', 'ndnsec-delete', 'delete an NDN identity, key, or certificate', None, 1), + ('manpages/ndnsec-export', 'ndnsec-export', 'export an NDN certificate and its private key to a file', None, 1), + ('manpages/ndnsec-get-default', 'ndnsec-get-default', 'show the default NDN identity, key, and certificate for the current user', None, 1), + ('manpages/ndnsec-import', 'ndnsec-import', 'import an NDN certificate and its private key from a file', None, 1), + ('manpages/ndnsec-key-gen', 'ndnsec-key-gen', 'generate an NDN key for an identity', None, 1), + ('manpages/ndnsec-list', 'ndnsec-list', 'list all known NDN identities, keys, and certificates', None, 1), + ('manpages/ndnsec-set-default', 'ndnsec-set-default', 'change the default NDN identity, key, or certificate for the current user', None, 1), + ('manpages/ndnsec-sign-req', 'ndnsec-sign-req', 'generate an NDN certificate signing request', None, 1), + ('manpages/ndnsec-unlock-tpm', 'ndnsec-unlock-tpm', 'unlock the TPM', None, 1), + ('manpages/ndn-client.conf', 'ndn-client.conf', 'configuration file for NDN platform', None, 5), + ('manpages/ndn-log', 'ndn-log', 'ndn-cxx logging', None, 7), ] - # If true, show URL addresses after external links. -man_show_urls = True +#man_show_urls = True -# ---- Custom options -------- +# -- Custom options ---------------------------------------------------------- doxylink = { - 'ndn-cxx' : ('ndn-cxx.tag', 'doxygen/'), + 'ndn-cxx': ('ndn-cxx.tag', 'doxygen/'), +} + +extlinks = { + 'issue': ('https://redmine.named-data.net/issues/%s', 'issue #'), } if os.getenv('GOOGLE_ANALYTICS', None): googleanalytics_id = os.environ['GOOGLE_ANALYTICS'] googleanalytics_enabled = True - -# exclude_patterns = ['RELEASE_NOTES.rst'] - -redmine_project_url = "https://redmine.named-data.net/" diff --git a/docs/doxygen.conf.in b/docs/doxygen.conf.in index d1ab057a1..fd5237b53 100644 --- a/docs/doxygen.conf.in +++ b/docs/doxygen.conf.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.5 +# Doxyfile 1.8.13 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -46,10 +46,10 @@ PROJECT_NUMBER = @VERSION@ PROJECT_BRIEF = -# With the PROJECT_LOGO tag one can specify an logo or icon that is included in -# the documentation. The maximum height of the logo should not exceed 55 pixels -# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo -# to the output directory. +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. PROJECT_LOGO = @@ -60,7 +60,7 @@ PROJECT_LOGO = OUTPUT_DIRECTORY = docs/doxygen -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where @@ -70,27 +70,37 @@ OUTPUT_DIRECTORY = docs/doxygen CREATE_SUBDIRS = YES +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese- -# Traditional, Croatian, Czech, Danish, Dutch, English, Esperanto, Farsi, -# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en, -# Korean, Korean-en, Latvian, Norwegian, Macedonian, Persian, Polish, -# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, -# Turkish, Ukrainian and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the @@ -125,12 +135,12 @@ ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = YES -# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. -FULL_PATH_NAMES = NO +FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand @@ -142,7 +152,7 @@ FULL_PATH_NAMES = NO # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = src/ +STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -151,7 +161,7 @@ STRIP_FROM_PATH = src/ # specify the list of include paths that are normally passed to the compiler # using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = .. # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't @@ -175,7 +185,7 @@ JAVADOC_AUTOBRIEF = YES # requiring an explicit \brief command for a brief description.) # The default value is: NO. -QT_AUTOBRIEF = NO +QT_AUTOBRIEF = YES # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as @@ -195,9 +205,9 @@ MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a -# new page for each member. If set to NO, the documentation of a member will be -# part of the file/class/namespace that contains it. +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO @@ -232,7 +242,7 @@ TCL_SUBST = # members will be omitted, etc. # The default value is: NO. -OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored @@ -259,11 +269,14 @@ OPTIMIZE_OUTPUT_VHDL = NO # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. # -# Note For files without extension you can use no_extension as a placeholder. +# Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. @@ -280,10 +293,19 @@ EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +# TOC_INCLUDE_HEADINGS = 0 + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by by putting a % sign in front of the word -# or globally by setting AUTOLINK_SUPPORT to NO. +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES @@ -323,13 +345,20 @@ SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first +# tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = YES + # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent @@ -388,7 +417,7 @@ LOOKUP_CACHE_SIZE = 0 # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. @@ -398,35 +427,35 @@ LOOKUP_CACHE_SIZE = 0 EXTRACT_ALL = YES -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO -# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = YES -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. -EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_CLASSES = NO -# This flag is only useful for Objective-C code. When set to YES local methods, +# This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO only methods in the interface are +# included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. @@ -451,21 +480,21 @@ HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set -# to NO these classes will be included in the various overviews. This option has -# no effect if EXTRACT_ALL is enabled. +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO these declarations will be +# (class|struct|union) declarations. If set to NO, these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO these +# documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. @@ -479,7 +508,7 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES upper-case letters are also +# names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. @@ -488,18 +517,32 @@ INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES the +# their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. @@ -514,17 +557,18 @@ INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. +# name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. # The default value is: NO. -SORT_BRIEF_DOCS = NO +SORT_BRIEF_DOCS = YES # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and @@ -536,7 +580,7 @@ SORT_BRIEF_DOCS = NO # detailed member documentation. # The default value is: NO. -SORT_MEMBERS_CTORS_1ST = NO +SORT_MEMBERS_CTORS_1ST = YES # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will @@ -565,27 +609,25 @@ SORT_BY_SCOPE_NAME = NO STRICT_PROTO_MATCHING = NO -# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the -# todo list. This list is created by putting \todo commands in the -# documentation. +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES -# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the -# test list. This list is created by putting \test commands in the -# documentation. +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES -# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES -# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. @@ -610,8 +652,8 @@ ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES the list -# will mention the files that were used to generate the documentation. +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = NO @@ -659,8 +701,7 @@ LAYOUT_FILE = # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. Do not use file names with spaces, bibtex cannot handle them. See -# also \cite for info how to create references. +# search path. See also \cite for info how to create references. CITE_BIB_FILES = @@ -676,7 +717,7 @@ CITE_BIB_FILES = QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. @@ -684,7 +725,7 @@ QUIET = YES WARNINGS = YES -# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. @@ -701,12 +742,18 @@ WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO doxygen will only warn about wrong or incomplete parameter -# documentation, but not about the absence of documentation. +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = YES +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated @@ -730,10 +777,10 @@ WARN_LOGFILE = # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with -# spaces. +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = src/ +INPUT = ndn-cxx # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -746,12 +793,17 @@ INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank the -# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, -# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, -# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, -# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, -# *.qsf, *.as and *.js. +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. FILE_PATTERNS = @@ -784,7 +836,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = */ndn-cxx/impl/* */ndn-cxx/*/impl/* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -837,6 +889,10 @@ IMAGE_PATH = # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. INPUT_FILTER = @@ -846,11 +902,15 @@ INPUT_FILTER = # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER ) will also be used to filter the input files that are used for +# INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. @@ -910,7 +970,7 @@ REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. @@ -957,6 +1017,25 @@ USE_HTAGS = NO VERBATIM_HEADERS = YES +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse-libclang=ON option for CMake. +# The default value is: NO. + +# CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +# CLANG_OPTIONS = + #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- @@ -987,7 +1066,7 @@ IGNORE_PREFIX = # Configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES @@ -1049,13 +1128,15 @@ HTML_FOOTER = @HTML_FOOTER@ HTML_STYLESHEET = ../docs/named_data_theme/static/named_data_doxygen.css -# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- -# defined cascading style sheet that is included after the standard style sheets +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. -# Doxygen will copy the style sheet file to the output directory. For an example -# see the documentation. +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = @@ -1074,7 +1155,7 @@ HTML_EXTRA_FILES = ../docs/named_data_theme/static/doxygen.css \ ../docs/named_data_theme/static/bar-top.png # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the stylesheet and background images according to +# will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 @@ -1105,8 +1186,9 @@ HTML_COLORSTYLE_GAMMA = 91 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: YES. +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES @@ -1117,7 +1199,7 @@ HTML_TIMESTAMP = YES # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_DYNAMIC_SECTIONS = NO +HTML_DYNAMIC_SECTIONS = YES # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand @@ -1202,28 +1284,29 @@ GENERATE_HTMLHELP = NO CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = -# The GENERATE_CHI flag controls if a separate .chi index file is generated ( -# YES) or that it should be included in the master .chm file ( NO). +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = -# The BINARY_TOC flag controls whether a binary table of contents is generated ( -# YES) or a normal table of contents ( NO) in the .chm file. +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1336,7 +1419,7 @@ DISABLE_INDEX = NO # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has @@ -1355,7 +1438,7 @@ GENERATE_TREEVIEW = YES # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. -ENUM_VALUES_PER_LINE = 4 +ENUM_VALUES_PER_LINE = 1 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. @@ -1364,7 +1447,7 @@ ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1393,7 +1476,7 @@ FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering -# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. @@ -1463,11 +1546,11 @@ SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using Javascript. There -# are two flavours of web server based searching depending on the -# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for -# searching and an index file used by the script. When EXTERNAL_SEARCH is -# enabled the indexing and searching needs to be provided by external tools. See -# the section "External Indexing and Searching" for details. +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. # The default value is: NO. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1479,7 +1562,7 @@ SERVER_BASED_SEARCH = NO # external search engine pointed to by the SEARCHENGINE_URL option to obtain the # search results. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library # Xapian (see: http://xapian.org/). # @@ -1492,7 +1575,7 @@ EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will return the search results when EXTERNAL_SEARCH is enabled. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library # Xapian (see: http://xapian.org/). See the section "External Indexing and # Searching" for details. @@ -1530,7 +1613,7 @@ EXTRA_SEARCH_MAPPINGS = # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output. +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. # The default value is: YES. GENERATE_LATEX = NO @@ -1561,7 +1644,7 @@ LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex -# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1579,9 +1662,12 @@ COMPACT_LATEX = NO PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names -# that should be included in the LaTeX output. To get the times font for -# instance you can specify -# EXTRA_PACKAGES=times +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1595,23 +1681,36 @@ EXTRA_PACKAGES = # # Note: Only use a user-defined header if you know what you are doing! The # following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will -# replace them by respectively the title of the page, the current date and time, -# only the current date, the version number of doxygen, the project name (see -# PROJECT_NAME), or the project number (see PROJECT_NUMBER). +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the # generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. # # Note: Only use a user-defined footer if you know what you are doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the LATEX_OUTPUT output # directory. Note that the files will be copied as-is; there are no commands or @@ -1629,8 +1728,8 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES -# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES to get a +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a # higher quality PDF documentation. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1671,11 +1770,19 @@ LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- -# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The # RTF output is optimized for Word 97 and may not look too pretty with other RTF # readers/editors. # The default value is: NO. @@ -1690,7 +1797,7 @@ GENERATE_RTF = NO RTF_OUTPUT = rtf -# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1727,11 +1834,21 @@ RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO + #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- -# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for # classes and files. # The default value is: NO. @@ -1755,6 +1872,13 @@ MAN_OUTPUT = man MAN_EXTENSION = .3 +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + # If the MAN_LINKS tag is set to YES and doxygen generates man output, then it # will generate one additional man file for each entity documented in the real # man page(s). These additional files only source the real man page, but without @@ -1768,7 +1892,7 @@ MAN_LINKS = NO # Configuration options related to the XML output #--------------------------------------------------------------------------- -# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that # captures the structure of the code including all documentation. # The default value is: NO. @@ -1782,7 +1906,7 @@ GENERATE_XML = NO XML_OUTPUT = xml -# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program # listings (including syntax highlighting and cross-referencing information) to # the XML output. Note that enabling this will significantly increase the size # of the XML output. @@ -1795,7 +1919,7 @@ XML_PROGRAMLISTING = YES # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- -# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files # that can be used to generate PDF. # The default value is: NO. @@ -1809,14 +1933,23 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- -# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen -# Definitions (see http://autogen.sf.net) file that captures the structure of -# the code including all documentation. Note that this feature is still -# experimental and incomplete at the moment. +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sf.net) file that captures the +# structure of the code including all documentation. Note that this feature is +# still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO @@ -1825,7 +1958,7 @@ GENERATE_AUTOGEN_DEF = NO # Configuration options related to the Perl module output #--------------------------------------------------------------------------- -# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module # file that captures the structure of the code including all documentation. # # Note that this feature is still experimental and incomplete at the moment. @@ -1833,7 +1966,7 @@ GENERATE_AUTOGEN_DEF = NO GENERATE_PERLMOD = NO -# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI # output from the Perl module output. # The default value is: NO. @@ -1841,9 +1974,9 @@ GENERATE_PERLMOD = NO PERLMOD_LATEX = NO -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely # formatted so it can be parsed by a human reader. This is useful if you want to -# understand what is going on. On the other hand, if this tag is set to NO the +# understand what is going on. On the other hand, if this tag is set to NO, the # size of the Perl module output will be much smaller and Perl will parse it # just the same. # The default value is: YES. @@ -1863,14 +1996,14 @@ PERLMOD_MAKEVAR_PREFIX = # Configuration options related to the preprocessor #--------------------------------------------------------------------------- -# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all # C-preprocessor directives found in the sources and include files. # The default value is: YES. ENABLE_PREPROCESSING = YES -# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names -# in the source code. If set to NO only conditional compilation will be +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be # performed. Macro expansion can be done in a controlled way by setting # EXPAND_ONLY_PREDEF to YES. # The default value is: NO. @@ -1886,7 +2019,7 @@ MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = NO -# If the SEARCH_INCLUDES tag is set to YES the includes files in the +# If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. @@ -1898,7 +2031,7 @@ SEARCH_INCLUDES = YES # preprocessor. # This tag requires that the tag SEARCH_INCLUDES is set to YES. -INCLUDE_PATH = +INCLUDE_PATH = .. # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the @@ -1917,15 +2050,18 @@ INCLUDE_FILE_PATTERNS = # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. PREDEFINED = DOXYGEN \ - NFD_LOG_INIT \ - BOOST_CONCEPT_ASSERT \ - PUBLIC_WITH_TESTS_ELSE_PROTECTED=protected \ - PUBLIC_WITH_TESTS_ELSE_PRIVATE=private \ - PROTECTED_WITH_TESTS_ELSE_PRIVATE=private \ - VIRTUAL_WITH_TESTS \ - NDN_CXX_KEYCHAIN_REGISTER_PIB \ - NDN_CXX_KEYCHAIN_REGISTER_TPM \ - DEPRECATED(x)=x + BOOST_CONCEPT_ASSERT(x)= \ + BOOST_CONCEPT_REQUIRES(x)= \ + NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(x)= \ + NDN_LOG_INIT(x)= \ + NDN_LOG_MEMBER_DECL()= \ + NDN_LOG_MEMBER_DECL_SPECIALIZED(x)= \ + NDN_LOG_MEMBER_INIT(x,y)= \ + NDN_LOG_MEMBER_INIT_SPECIALIZED(x,y)= \ + NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED=protected \ + NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE=private \ + NDN_CXX_PROTECTED_WITH_TESTS_ELSE_PRIVATE=private \ + NDN_CXX_VIRTUAL_WITH_TESTS= # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The @@ -1937,9 +2073,9 @@ PREDEFINED = DOXYGEN \ EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will -# remove all refrences to function-like macros that are alone on a line, have an -# all uppercase name, and do not end with a semicolon. Such function macros are -# typically used for boiler-plate code, and will confuse the parser if not +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not # removed. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. @@ -1959,7 +2095,7 @@ SKIP_FUNCTION_MACROS = YES # where loc1 and loc2 can be relative or absolute paths or URLs. See the # section "Linking to external documentation" for more information about the use # of tag files. -# Note: Each tag file must have an unique name (where the name does NOT include +# Note: Each tag file must have a unique name (where the name does NOT include # the path). If a tag file is not located in the directory in which doxygen is # run, you must also specify the path to the tagfile here. @@ -1971,20 +2107,21 @@ TAGFILES = GENERATE_TAGFILE = ndn-cxx.tag -# If the ALLEXTERNALS tag is set to YES all external class will be listed in the -# class index. If set to NO only the inherited external classes will be listed. +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. # The default value is: NO. ALLEXTERNALS = NO -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in -# the modules index. If set to NO, only the current project's groups will be +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. EXTERNAL_GROUPS = YES -# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in # the related pages index. If set to NO, only the current project's pages will # be listed. # The default value is: YES. @@ -2001,7 +2138,7 @@ PERL_PATH = /usr/bin/perl # Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram # (in HTML and LaTeX) for classes with base or super classes. Setting the tag to # NO turns the diagrams off. Note that this option also works with HAVE_DOT # disabled, but it is recommended to install and use dot, since it yields more @@ -2019,7 +2156,14 @@ CLASS_DIAGRAMS = YES MSCGEN_PATH = -# If set to YES, the inheritance and collaboration graphs will hide inheritance +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2030,7 +2174,7 @@ HIDE_UNDOC_RELATIONS = YES # http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO -# The default value is: NO. +# The default value is: YES. HAVE_DOT = YES @@ -2044,7 +2188,7 @@ HAVE_DOT = YES DOT_NUM_THREADS = 0 -# When you want a differently looking font n the dot files that doxygen +# When you want a differently looking font in the dot files that doxygen # generates you can specify the font name using DOT_FONTNAME. You need to make # sure dot is able to find the font, which can be done by putting it in a # standard location or by setting the DOTFONTPATH environment variable or by @@ -2092,7 +2236,7 @@ COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. # The default value is: NO. @@ -2144,7 +2288,8 @@ INCLUDED_BY_GRAPH = YES # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2155,7 +2300,8 @@ CALL_GRAPH = NO # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2178,11 +2324,17 @@ GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). -# Possible values are: png, jpg, gif and svg. +# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd, +# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo, +# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2219,6 +2371,30 @@ DOTFILE_DIRS = MSCFILE_DIRS = +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +# PLANTUML_CFG_FILE = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes # larger than this value, doxygen will truncate the graph, which is visualized @@ -2255,14 +2431,14 @@ MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = YES -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support # this, this feature is disabled by default. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_MULTI_TARGETS = NO +DOT_MULTI_TARGETS = YES # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated @@ -2272,7 +2448,7 @@ DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot # files that are used to generate the various graphs. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. diff --git a/docs/examples.rst b/docs/examples.rst index 8689e4fd7..729a6c5f2 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -52,7 +52,7 @@ The following example demonstrates how to use :ndn-cxx:`Scheduler` to schedule a events for execution at specific points of time. The library internally uses `boost::asio::io_service -`_ to +`_ to implement fully asynchronous NDN operations (i.e., sending and receiving Interests and Data). In addition to network-related operations, ``boost::asio::io_service`` can be used to execute any arbitrary callback within the processing thread (run either explicitly via diff --git a/docs/index.rst b/docs/index.rst index f73ad84e8..dc3682b08 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,11 +1,22 @@ ndn-cxx: NDN C++ library with eXperimental eXtensions ===================================================== -ndn-cxx is a C++ library, implementing Named Data Networking (NDN) primitives that can be -used to implement various NDN applications. - -Please submit any bugs or issues to the `ndn-cxx issue tracker -`__. +**ndn-cxx** is a C++14 library implementing Named Data Networking (NDN) primitives +that can be used to write various NDN applications. The library is currently being +used by the following projects: + +* `NFD - NDN Forwarding Daemon `_ +* `NLSR - Named-data Link-State Routing protocol `_ +* `ndn-tools - Essential NDN command-line tools `_ +* `repo-ng - Next generation of NDN repository `_ +* `ChronoSync - Sync library for multiuser realtime applications `_ +* `PSync - Partial and full synchronization library `_ +* `ndn-traffic-generator - Traffic generator for NDN `_ +* `NAC - Name-based Access Control `_ +* `NDNS - Domain Name Service for NDN `_ + +Please submit any bugs or feature requests to the `ndn-cxx issue tracker +`_. ndn-cxx Documentation --------------------- @@ -14,7 +25,6 @@ ndn-cxx Documentation :hidden: :maxdepth: 3 - README INSTALL examples tutorials @@ -29,15 +39,14 @@ ndn-cxx Documentation RELEASE_NOTES releases -- :doc:`README` - - :doc:`INSTALL` - :doc:`examples` - :doc:`tutorials` - + :doc:`tutorials/security-library` + + `NDN Software Contributor's Guide `_ (guide for newcomers to the NDN community of software generally) + + :doc:`tutorials/utils-ndn-regex` + :doc:`tutorials/security-validator-config` @@ -46,6 +55,7 @@ ndn-cxx Documentation + :doc:`specs/signed-interest` + :doc:`specs/certificate-format` + :doc:`specs/safe-bag` + + :doc:`specs/validation-error-code` - :doc:`manpages` @@ -62,5 +72,5 @@ ndn-cxx Documentation License ------- -ndn-cxx is an open source project licensed under LGPL 3.0 license. For more information about +ndn-cxx is an open source project licensed under the LGPL version 3. For more information about the license, refer to `COPYING.md `_. diff --git a/docs/manpages.rst b/docs/manpages.rst index 450d20d68..c88228ebe 100644 --- a/docs/manpages.rst +++ b/docs/manpages.rst @@ -3,25 +3,18 @@ Manpages .. toctree:: ndn-client.conf + ndn-cxx logging manpages/ndnsec ndnsec-list ndnsec-get-default ndnsec-set-default ndnsec-key-gen - ndnsec-dsk-gen ndnsec-sign-req ndnsec-cert-gen - ndnsec-cert-revoke ndnsec-cert-install ndnsec-cert-dump ndnsec-delete ndnsec-export ndnsec-import ndnsec-unlock-tpm - ndnsec-set-acl :maxdepth: 1 - -.. - manpages/ndnsec-op-tool - manpages/ndnsec-set-acl - manpages/ndnsec-sig-verify diff --git a/docs/manpages/ndn-client.conf.rst b/docs/manpages/ndn-client.conf.rst index ab8d828d2..62f42ca2c 100644 --- a/docs/manpages/ndn-client.conf.rst +++ b/docs/manpages/ndn-client.conf.rst @@ -5,8 +5,9 @@ System configuration of NDN platform is specified in ``client.conf``. The configuration file ``client.conf`` is looked up in several directories in the following order: -- ``$HOME/.ndn/``: user-specific settings -- ``@SYSCONFDIR@/ndn/`` (``/usr/local/etc/ndn``, ``/opt/local/etc/ndn``, or other, depending how the library is configured): system-wide settings +- ``$HOME/.ndn``: user-specific settings +- ``@SYSCONFDIR@/ndn`` (``/usr/local/etc/ndn``, ``/opt/local/etc/ndn``, or other, depending how the + library is configured): system-wide settings - ``/etc/ndn``: default system-wide settings Here is an example of ``client.conf`` for current ndn-cxx package: @@ -18,13 +19,14 @@ NFD --- transport - FaceUri for default connection toward local NDN forwarder. Only ``unix`` and ``tcp4`` FaceUri + FaceUri for default connection toward local NDN forwarder. Only ``unix`` and ``tcp4`` FaceUris can be specified here. By default, ``unix:///var/run/nfd.sock`` is used. - ..note:: - This value can be overriden using `NDN_CLIENT_TRANSPORT` environment variable. + .. note:: + This value can be overridden using the ``NDN_CLIENT_TRANSPORT`` environment variable. + Key Management -------------- @@ -48,17 +50,17 @@ pib pib=pib-sqlite3 - Changing PIB scheme without changing location is **not** allowed. If such change is - necessary, the whole backend storage must be destroyed. For example, when default location - is used:: + Changing PIB scheme without changing location is **not** allowed. If a change like this is + necessary, the whole backend storage must be destroyed. For example, when the default location is + used:: rm -rf ~/.ndn/ndnsec-* - It's not recommended to share the same directory between machines, e.g. via NFS. + It is not recommended to share the same directory between machines, e.g. via NFS. Simultaneous access from multiple machines may cause errors. - ..note:: - This value can be overriden using `NDN_CLIENT_PIB` environment variable. + .. note:: + This value can be overridden using the ``NDN_CLIENT_PIB`` environment variable. tpm Trusted Platform Module (TPM) where the private keys are stored. The format for this setting @@ -68,15 +70,15 @@ tpm Possible values for ``[scheme]``: - * ``tpm-osx-keychain`` (default on OS X platform): secure storage of private keys in OS X + * ``tpm-osx-keychain`` (default on macOS): secure storage of private keys in the macOS Keychain with OS-provided access restrictions. ``[location]`` parameter is ignored. - May not work for daemon applications, as user interaction may be required to access OS X - Keychain. + May not work for daemon applications, as user interaction may be required to access the + macOS Keychain. - * ``tpm-file`` (default on all other platforms): file-based storage of private keys + * ``tpm-file`` (default on all other platforms): file-based storage of private keys. Possible values for ``[location]``: @@ -89,11 +91,11 @@ tpm tpm=tpm-file - **Change of ``tpm`` setting is only possible together with ``pib`` setting. Otherwise, an - error will be generated during PIB/TPM access** + **Changing the ``tpm`` setting is only possible together with ``pib`` setting. Otherwise, + an error will be generated during PIB/TPM access.** - It's not recommended to share the same directory between machines, e.g. via NFS. + It is not recommended to share the same directory between machines, e.g. via NFS. Simultaneous access from multiple machines may cause errors. - ..note:: - This value can be overriden using `NDN_CLIENT_TPM` environment variable. + .. note:: + This value can be overridden using the ``NDN_CLIENT_TPM`` environment variable. diff --git a/docs/manpages/ndn-log.rst b/docs/manpages/ndn-log.rst new file mode 100644 index 000000000..b8fc3b279 --- /dev/null +++ b/docs/manpages/ndn-log.rst @@ -0,0 +1,83 @@ +ndn-log +======= + +The ndn-cxx logging facility exposes the internal state of NDN libraries and +applications so the user can investigate internal interactions, such as interest +dispatch inside ndn::Face, Data and Interest validation in the security framework, +sync and recovery Interest processing inside ChronoSync, etc. During runtime, the +user is able to specify the types of messages he or she would like to receive from +a set of logging modules pre-configured by library and application developers. + +Environment Variable +-------------------- + +One way to control ndn-cxx logging facility is through the environment variable +``NDN_LOG``. Using this variable, one can set the log levels for the available logging +modules. Logging modules within different libraries and applications usually have +distinguishing prefixes (``ndn.``, ``sync.``, etc.), which can be specified when +setting the environment variable. Wildcards can be used to enable logging for all +modules (just ``*``) or all modules under a selected prefix (e.g., ``ndn.*``). + +ndn-cxx logging facility provides a mechanism to manage the type of log messages +that are written by classifying log messages by severity levels. Listed below +are the available log levels. + +**Log Levels:** + +:: + + TRACE + DEBUG + INFO + WARN + ERROR + FATAL + +A message's severity level will determine whether the log is written. For instance, +if an application sets its log severity level to DEBUG, all messages marked with +DEBUG, or any of those below that level, are written. FATAL level logs are always +written. + +Setting NDN_LOG requires the following syntax with as many prefixes and +corresponding loglevels as the user desires: + + export NDN_LOG="=:=" + +**Examples:** + +:: + + export NDN_LOG="ndn.*=DEBUG" + export NDN_LOG="ndn.UnixTransport=INFO" + export NDN_LOG="sync.Logic=ERROR" + export NDN_LOG="*=DEBUG:ndn.UnixTransport=INFO:sync.Logic=ERROR" + +**Note:** + +Shorter (general) prefixes should be placed before longer (specific) prefixes. +Otherwise, the specific prefix's loglevel will be overwritten. For example, +`export NDN_LOG="ndn.UnixTransport=TRACE:ndn.*=ERROR:*=INFO"` sets all modules +to INFO; it should be written as +`export NDN_LOG="*=INFO:ndn.*=ERROR:ndn.UnixTransport=TRACE"` for the desired effect. + +**Note:** + +Setting the environment variable with sudo requires the application to be run +in the same command. + +:: + + Correct: + + sudo env NDN_LOG=logLevel ./ndn-application + + sudo -s + export NDN_LOG=logLevel + ./ndn-application + + Incorrect: + + sudo export NDN_LOG=logLevel + sudo ./ndn-application + + NDN_LOG=logLevel sudo ./ndn-application diff --git a/docs/manpages/ndnsec-cert-dump.rst b/docs/manpages/ndnsec-cert-dump.rst index 9daf52cf5..04e01075c 100644 --- a/docs/manpages/ndnsec-cert-dump.rst +++ b/docs/manpages/ndnsec-cert-dump.rst @@ -1,56 +1,54 @@ ndnsec-cert-dump ================ -``ndnsec-cert-dump`` is a tool to dump a certificate from **Public Info Base** or file and output -it to standard output. - -Usage ------ - -:: +Synopsis +-------- - $ ndnsec-cert-dump [-h] [-p] [-ikf] name +**ndnsec-cert-dump** [**-h**] [**-p**] [**-r** [**-H** *host*] [**-P** *port*]] +[**-i**\|\ **-k**\|\ **-f**] *name* Description ----------- -``ndnsec-cert-dump`` can read a certificate from **Public Info Base (PIB)** or a file and output -the certificate to standard output. +:program:`ndnsec-cert-dump` reads a certificate from the **Public Info Base (PIB)** +or from a file, and prints it on the standard output. -By default, ``name`` is interpreted as a certificate name. +By default, *name* is interpreted as a certificate name. Options ------- -``-i`` - Interpret ``name`` as an identity name. If specified, the certificate to dump is the default - certificate of the identity. +.. option:: -i, --identity -``-k`` - Interpret ``name`` as a key name. If specified, the certificate to dump is the default certificate - of the key. + Interpret *name* as an identity name. If specified, the certificate to dump + is the default certificate of the identity. -``-f`` - Interpret ``name`` as a path to a file containing the certificate. If ``name`` is ``-``, - certificate will be read from standard input. +.. option:: -k, --key -``-p`` - Print out the certificate to a human-readable format. + Interpret *name* as a key name. If specified, the certificate to dump is the + default certificate of the key. -Examples --------- +.. option:: -f, --file + + Interpret *name* as a path to a file containing the certificate. If *name* + is "-", the certificate will be read from the standard input. + +.. option:: -p, --pretty + + Print the certificate in a human-readable format. + +Example +------- -Dump a certificate from PIB to standard output: -:: +Dump a certificate from PIB to standard output:: - $ ndnsec-cert-dump /ndn/test/KEY/david/ksk-1396913058196/ID-CERT/%00%00%01E%3E%9D%A0%DE + $ ndnsec-cert-dump /ndn/test/david/KEY/ksk-1396913058196/ID-CERT/%00%00%01E%3E%9D%A0%DE -Dump a certificate to a human-readable format: -:: +Dump a certificate in human-readable format:: - $ ndnsec-cert-dump -p /ndn/test/KEY/david/ksk-1396913058196/ID-CERT/%00%00%01E%3E%9D%A0%DE + $ ndnsec-cert-dump -p /ndn/test/david/KEY/ksk-1396913058196/ID-CERT/%00%00%01E%3E%9D%A0%DE Certificate name: - /ndn/test/KEY/david/ksk-1396913058196/ID-CERT/%00%00%01E%3E%9D%A0%DE + /ndn/test/david/KEY/ksk-1396913058196/ID-CERT/%00%00%01E%3E%9D%A0%DE Validity: NotBefore: 20140401T000000 NotAfter: 20150331T235959 diff --git a/docs/manpages/ndnsec-cert-gen.rst b/docs/manpages/ndnsec-cert-gen.rst index 923c936f5..3b6617f4a 100644 --- a/docs/manpages/ndnsec-cert-gen.rst +++ b/docs/manpages/ndnsec-cert-gen.rst @@ -1,66 +1,64 @@ ndnsec-cert-gen =============== -``ndnsec-cert-gen`` is a tool to issue an identity certificate. - -Usage ------ - -:: +Synopsis +-------- - $ ndnsec-cert-gen [-h] [-S timestamp] [-E timestamp] [-N name] [-I info] [-s sign-id] [-p cert-prefix] request +**ndnsec-cert-gen** [**-h**] [**-S** *timestamp*] [**-E** *timestamp*] +[**-I** *info*]... [**-s** *signer*] [**-i** *issuer*] *file* Description ----------- -``ndnsec-cert-gen`` takes signing request as input and issues an identity certificate for the key in -the signing request. The signing request can be created during ``ndnsec-keygen`` and can be -re-generated with ``ndnsec-sign-req``. - -By default, the default key/certificate will be used to sign the issued certificate. +:program:`ndnsec-cert-gen` takes a signing request as input and issues an +identity certificate for the key in the signing request. The signing request +can be created with :program:`ndnsec-key-gen` and can be re-generated with +:program:`ndnsec-sign-req`. -``request`` could be a path to a file that contains the signing request. If ``request`` is ``-``, -then signing request will be read from standard input. +By default, the default key is used to sign the issued certificate. -The generated certificate will be written to standard output in base64 encoding. +*file* is the name of a file that contains the signing request. If *file* is +"-", the signing request is read from the standard input. +The generated certificate is written to the standard output in base64 encoding. Options ------- -``-S timestamp`` - Timestamp when the certificate becomes valid. The default value is now. +.. option:: -S , --not-before -``-E timestamp`` - Timestamp when the certificate expires. The default value is one year from now. + Date and time when the certificate becomes valid, in "YYYYMMDDhhmmss" format. + The default value is now. -``-N name`` - Name of the certificate owner. +.. option:: -E , --not-after -``-I info`` - Other information about the certificate owner. ``subject-info`` is a list of pairs of OID and - corresponding value. For example, "2.5.4.10 'Some Organization' 2.5.4.3 'http://home.page/'". + Date and time when the certificate expires, in "YYYYMMDDhhmmss" format. + The default value is 365 days after the **--not-before** timestamp. -``-s sign-id`` - Signing identity. The default key/certificate of ``sign-id`` will be used to sign the requested - certificate. If this option is not specified, the system default identity will be used. +.. option:: -I , --info -``-p cert-prefix`` - The certificate prefix, which is the part of certificate name before ``KEY`` component. + Other information to be included in the issued certificate. For example:: - By default, the certificate prefix will be inferred from the certificate name according - to the relation between the signing identity and the subject identity. If the signing - identity is a prefix of the subject identity, ``KEY`` will be inserted after the - signingIdentity, otherwise ``KEY`` is inserted after subject identity (i.e., before - ``ksk-....``). + -I "affiliation Some Organization" -I "homepage http://home.page/" -Examples --------- +.. option:: -s , --sign-id + + Signing identity. The default key/certificate of *signer* will be used to + sign the requested certificate. If this option is not specified, the system + default identity will be used. + +.. option:: -i , --issuer-id + + Issuer's ID to be included in the issued certificate name. The default + value is "NA". + +Example +------- :: $ ndnsec-cert-gen -S 20140401000000 -E 20150331235959 -N "David" - -I "2.5.4.10 'Some Organization'" -s /ndn/test sign_request.cert + -I "2.5.4.10 'Some Organization'" -s /ndn/test request.cert Bv0C9wc9CANuZG4IBHRlc3QIA0tFWQgFZGF2aWQIEWtzay0xMzk2OTEzMDU4MTk2 CAdJRC1DRVJUCAgAAAFFPp2g3hQDGAECFf0BdjCCAXIwIhgPMjAxNDA0MDEwMDAw MDBaGA8yMDE1MDMzMTIzNTk1OVowKDAMBgNVBCkTBURhdmlkMBgGA1UEChMRU29t diff --git a/docs/manpages/ndnsec-cert-install.rst b/docs/manpages/ndnsec-cert-install.rst index 1ca1ddb34..dae8ee770 100644 --- a/docs/manpages/ndnsec-cert-install.rst +++ b/docs/manpages/ndnsec-cert-install.rst @@ -1,56 +1,50 @@ ndnsec-cert-install =================== -``ndnsec-cert-install`` is a tool to install a certificate into **Public Information Base (PIB)**. - -Usage ------ - -:: +Synopsis +-------- - $ ndnsec-cert-install [-h] [-IKN] cert-source +**ndnsec-cert-install** [**-h**] [**-I**\|\ **-K**\|\ **-N**] *file* Description ----------- -``ndnsec-cert-install`` can insert a certificate into PIB. By default, the installed certificate -will be set as the default certificate of its corresponding identity and the identity is set as -the system default identity. +:program:`ndnsec-cert-install` allows importing a certificate into the +**Public Information Base (PIB)**. By default, the installed certificate +will be set as the default certificate for the corresponding identity and +the identity will be set as the user's default identity. -``cert-source`` could be a filesystem path or an HTTP URL of a file containing to certificate to -install or . If ``cert-file`` is ``-``, the certificate will be read from standard input. +*file* can be a filesystem path or an HTTP URL of a file containing the certificate +to install. If *file* is "-", the certificate will be read from the standard input. Options ------- -``-I`` - Set the certificate as the default certificate of its corresponding identity, but do not change - the system default identity. +.. option:: -I, --identity-default -``-K`` - Set the certificate as the default certificate of its corresponding key, but do not change the - corresponding identity's default key and the system default identity. + Set the certificate as the default certificate for the corresponding identity, + but do not change the user's default identity. -``-N`` - Install the certificate but do not change any default settings. +.. option:: -K, --key-default -Examples --------- + Set the certificate as the default certificate for the corresponding key, but + do not change the identity's default key or the user's default identity. -Install a certificate and set it as the system default certificate: +.. option:: -N, --no-default -:: + Install the certificate but do not change any default settings. - $ ndnsec-cert-install cert_file.cert +Example +------- + +Install a certificate and set it as the default certificate:: -Install a certificate with HTTP URL and set it as the system default certificate: + $ ndnsec-cert-install cert_file.cert -:: +Install a certificate via HTTP and set it as the default certificate:: $ ndnsec-install-cert "http://ndncert.domain.com/cert/get/my-certificate.ndncert" -Install a certificate but do not change any default settings: - -:: +Install a certificate but do not change any default settings:: $ ndnsec-cert-install -N cert_file.cert diff --git a/docs/manpages/ndnsec-cert-revoke.rst b/docs/manpages/ndnsec-cert-revoke.rst deleted file mode 100644 index 5136fe11c..000000000 --- a/docs/manpages/ndnsec-cert-revoke.rst +++ /dev/null @@ -1,36 +0,0 @@ -ndnsec-cert-revoke -================== - -``ndnsec-cert-revoke`` is a tool to generate a certificate revocation data. - -Usage ------ - -:: - - $ ndnsec-cert-revoke [-h] request - -Description ------------ - -This command takes an identity ertificate as input. -The tool will check whether user is the issuer of the certificate (by checking whether user has the key pointed by the KeyLocator of the certificate). -If so, the tool will generate an empty packet named by the certificate name appended with "REVOKED" as a revocation data. -If user is not the issuer of the certificate, the command will return error. - -This tool generates a revocation Data. -It does not actually revoke a certificate. -How to publish and use the revocation Data is not finalized yet. - -Options -------- - -``request`` - request is file name of the certificate to revoke (``-`` for standard input) - -Examples --------- - -:: - - $ ndnsec-cert-revoke some-cert-to-revoke.ndncert diff --git a/docs/manpages/ndnsec-delete.rst b/docs/manpages/ndnsec-delete.rst index 3c808af08..141aa0c81 100644 --- a/docs/manpages/ndnsec-delete.rst +++ b/docs/manpages/ndnsec-delete.rst @@ -1,32 +1,32 @@ ndnsec-delete ============= -``ndnsec-delete`` is a tool to delete security data from both **Public Info Base** and -**Trusted Platform Module**. - -Usage ------ - -:: +Synopsis +-------- - ndnsec-delete [-h] [-kc] name +**ndnsec-delete** [**-h**] [**-k**\|\ **-c**] *name* Description ----------- -By default, ``ndnsec-delete`` interpret ``name`` as an identity name. If an identity is deleted, -all the keys and certificates belonging to the identity will be deleted as well. If a key is -deleted, all the certificate belonging to the key will be deleted as well. +:program:`ndnsec-delete` allows to delete security data from both the +**Public Info Base (PIB)** and the **Trusted Platform Module (TPM)**. +By default, :program:`ndnsec-delete` will interpret *name* as an identity name. +If an identity is deleted, all keys and certificates belonging to that identity +will be deleted as well. If a key is deleted, all certificates associated with +that key will be deleted as well. Options ------- -``-k`` - Interpret ``name`` as a key name and delete the key and its related data. +.. option:: -k, --delete-key + + Interpret *name* as a key name and delete the key and its associated data. -``-c`` - Interpret ``name`` as a certificate name and delete the certificate. +.. option:: -c, --delete-cert + + Interpret *name* as a certificate name and delete the certificate. Exit Status ----------- @@ -35,11 +35,9 @@ Normally, the exit status is 0 if the requested entity is deleted successfully. If the entity to be deleted does not exist, the exit status is 1. For other errors, the exit status is 2. -Examples --------- - -Delete all data related to an identity: +Example +------- -:: +Delete all data related to an identity:: $ ndnsec-delete /ndn/test/david diff --git a/docs/manpages/ndnsec-dsk-gen.rst b/docs/manpages/ndnsec-dsk-gen.rst deleted file mode 100644 index 1b876691a..000000000 --- a/docs/manpages/ndnsec-dsk-gen.rst +++ /dev/null @@ -1,43 +0,0 @@ -ndnsec-dsk-gen -============== - -``ndnsec-dsk-gen`` is tool to generate a pair of Data-Signing-Key (DSK) for the specified ``identity`` -and sign the generated key using the corresponding Key-Signing-Key (KSK). -The generated DSK will be set as the default key of the identity. - -Usage ------ - -:: - - $ ndnsec-dsk-gen [-h] [-t keyType] identity - -Description ------------ - -``ndnsec-dsk-gen`` creates a pair of Data-Signing-Key (DSK) for the specified ``identity`` -and sign the generated key using the corresponding Key-Signing-Key (KSK). -The tool will first check the default KSK of the identity, and then generate a DSK -and sign the DSK using the KSK. -The information encoded in the DSK certificate is set the same as the KSK certificate. -In the end, the DSK is set as the default key of the identity. - -Options -------- - -``-t keyType`` - Specify the key type, ``r`` (default) for RSA and ``e`` for ECDSA. - -Examples --------- - -:: - - $ ndnsec-dsk-gen /ndn/test - OK: dsk certificate with name [/ndn/test/KEY/dsk-1417501749768/ID-CERT/%FD%00%00%01J%09%B02%8B] has been successfully installed - $ ndnsec-list -c - * /ndn/test - +->* /ndn/test/dsk-1417501749768 - +->* /ndn/test/KEY/dsk-1417501749768/ID-CERT/%FD%00%00%01J%09%B02%8B - +-> /ndn/test/ksk-1417475325879 - +->* /ndn/test/KEY/ksk-1417475325879/ID-CERT/%FD%00%00%01J%09%AE.Y diff --git a/docs/manpages/ndnsec-export.rst b/docs/manpages/ndnsec-export.rst index 839e38155..4d7e27706 100644 --- a/docs/manpages/ndnsec-export.rst +++ b/docs/manpages/ndnsec-export.rst @@ -1,44 +1,39 @@ ndnsec-export ============= -``ndnsec-export`` is a tool to export an identity's security data - -Usage ------ - -:: +Synopsis +-------- - $ ndnsec-export [-h] [-o output] [-p] identity +**ndnsec-export** [**-h**] [**-o** *file*] [**-P** *passphrase*] *identity* Description ----------- -``ndnsec-export`` can export public data of the ``identity`` including default key/certificate. -``ndnsec-export`` can also export sensitive data (such as private key), but the sensitive data will -be encrypted. The exported identity can be imported again using ``ndnsec-import``. - -By default, the command will write exported data to standard output. +:program:`ndnsec-export` exports the default certificate of *identity* and its +private key to a file. It will ask for a passphrase to encrypt the private key. +The resulting file can be imported again using :program:`ndnsec-import`. Options ------- -``-o output`` - Output the exported data to a file pointed by ``output``. +.. option:: -o , --output -``-p`` - Export private key of the identity. A password will be asked for data encryption. + Write to the specified output file instead of the standard output. -Examples --------- +.. option:: -P , --password -Export an identity's security data including private key and store the security data in a file: + Passphrase to use for the export. If empty or not specified, the user is + interactively asked to type the passphrase on the terminal. Note that + specifying the passphrase via this option is insecure, as it can potentially + end up in the shell's history, be visible in :command:`ps` output, and so on. -:: +Example +------- - $ ndnsec-export -o id.info -p /ndn/test/alice +Export an identity's default certificate and private key into a file:: -Export an identity's security data without private key and write it to standard output: + $ ndnsec-export -o alice.ndnkey /ndn/test/alice -:: +Export an identity's default certificate and private key to the standard output:: $ ndnsec-export /ndn/test/alice diff --git a/docs/manpages/ndnsec-get-default.rst b/docs/manpages/ndnsec-get-default.rst index 48889c8d0..0a27dee72 100644 --- a/docs/manpages/ndnsec-get-default.rst +++ b/docs/manpages/ndnsec-get-default.rst @@ -1,61 +1,56 @@ ndnsec-get-default ================== -``ndnsec-get-default`` is a tool to display the default setting of a particular entity. - -Usage ------ - -:: +Synopsis +-------- - $ ndnsec-get-default [-h] [-kc] [-i identity|-K key] [-q] +**ndnsec-get-default** [**-h**] [**-k**\|\ **-c**] [**-i** *identity*\|\ **-K** *key*] [**-q**] Description ----------- -Given a particular entity, ``ndnsec-get-default`` can display its default setting as specified in -options. If ``identity`` is specified, the given entity becomes the identity. If ``key`` is -specified, the given identity becomes the key. If no entity is specified, the command will take the -system default identity as the given entity. +Given a particular entity, :program:`ndnsec-get-default` shows its default settings +according to the command-line options. By default, if neither **-i** nor **-K** is +given, the command displays the default identity or the default key/certificate of +the default identity. Options ------- -``-k`` - Display the given entity's default key name. +.. option:: -k, --default-key -``-c`` - Display the given entity's default certificate name. + Display the chosen entity's default key name. -``-i identity`` - Display default setting of the ``identity`` +.. option:: -c, --default-cert -``-K key`` - Display default setting of the ``key``. + Display the chosen entity's default certificate name. -``-q`` - Disable trailling new line character. +.. option:: -i , --identity -Examples --------- + Display default settings of *identity*. + +.. option:: -K , --key + + Display default settings of *key*. -Display an identity's default key name. +.. option:: -q, --quiet -:: + Disable printing the trailing newline character. + +Example +------- + +Display an identity's default key name:: $ ndnsec-get-default -k -i /ndn/test/alice /ndn/test/alice/ksk-1394129695025 -Display an identity's default certificate name. - -:: +Display an identity's default certificate name:: $ ndnsec-get-default -c -i /ndn/test/alice /ndn/test/KEY/alice/ksk-1394129695025/ID-CERT/%FD%01D%98%9A%F2%3F -Display a key's default certificate name. - -:: +Display a key's default certificate name:: $ ndnsec-get-default -c -K /ndn/test/alice/ksk-1394129695025 /ndn/test/KEY/alice/ksk-1394129695025/ID-CERT/%FD%01D%98%9A%F2%3F diff --git a/docs/manpages/ndnsec-import.rst b/docs/manpages/ndnsec-import.rst index 5b61f597d..7c25a6aeb 100644 --- a/docs/manpages/ndnsec-import.rst +++ b/docs/manpages/ndnsec-import.rst @@ -1,33 +1,33 @@ ndnsec-import ============= -``ndnsec-import`` is a tool to import an identity's security data that is prepared by -``ndnsec-export``. - -Usage ------ - -:: +Synopsis +-------- - $ ndnsec-import [-h] [-p] input +**ndnsec-import** [**-h**] [**-P** *passphrase*] *file* Description ----------- -``ndnsec-import`` read data from ``input``. It will ask for password if the input contains private -key. If ``input`` is ``-``, security data will be read from standard input. +:program:`ndnsec-import` imports a certificate and its private key from a file +created by :program:`ndnsec-export`. It will ask for the passphrase used to +encrypt the private key. + +If *file* is "-", read from the standard input. Options ------- -``-p`` - Indicates the imported data containing private key. A password will be asked for data encryption. +.. option:: -P , --password -Examples --------- + Passphrase to use for the export. If empty or not specified, the user is + interactively asked to type the passphrase on the terminal. Note that + specifying the passphrase via this option is insecure, as it can potentially + end up in the shell's history, be visible in :command:`ps` output, and so on. -Import an identity's security data including private key: +Example +------- -:: +Import a certificate and private key from a file:: - $ ndnsec-import -p input_file + $ ndnsec-import alice.ndnkey diff --git a/docs/manpages/ndnsec-key-gen.rst b/docs/manpages/ndnsec-key-gen.rst index d34012858..0d68b8637 100644 --- a/docs/manpages/ndnsec-key-gen.rst +++ b/docs/manpages/ndnsec-key-gen.rst @@ -1,38 +1,42 @@ ndnsec-key-gen ============== -``ndnsec-key-gen`` is tool to generate a pair of key. - -Usage ------ - -:: +Synopsis +-------- - $ ndnsec-key-gen [-h] [-n] [-d] [-t keyType] identity +**ndnsec-key-gen** [**-h**] [**-n**] [**-t** *type*] [**-k** *keyidtype*] *identity* Description ----------- -``ndnsec-key-gen`` creates a key pair for the specified ``identity`` and sets the key as the -identity's default key. ``ndnsec-key-gen`` will also create a signing request for the generated key. -The signing request will be written to standard output in base64 encoding. +:program:`ndnsec-key-gen` generates a key pair for the specified *identity* and +sets the generated public key as the identity's default key. +:program:`ndnsec-key-gen` will also create a signing request for the generated key. +The signing request will be written to the standard output in base64 encoding. -By default, it will also set the identity as the system default identity. +By default, it will also set the identity as the user's default identity. Options ------- -``-n`` - Do not set the identity as the system default identity. +.. option:: -n, --not-default -``-d`` - Generate Data-Signing-Key (DSK) instead of the default Key-Signing-Key (KSK). + Do not set the identity as the user's default identity. -``-t keyType`` - Specify the key type. ``r`` (default) for RSA key. ``e`` for ECDSA key. + Note that if no other identity/key/certificate exists, then the identity + will become the default regardless of this option. -Examples --------- +.. option:: -t , --type + + Type of key to generate. "r" for RSA (default), "e" for ECDSA. + +.. option:: -k , --keyid-type + + Type of KeyId for the generated key. "r" for 64-bit random number (default), + "h" for SHA256 of the public key. + +Example +------- :: diff --git a/docs/manpages/ndnsec-list.rst b/docs/manpages/ndnsec-list.rst index bc4a31648..e0fde91f0 100644 --- a/docs/manpages/ndnsec-list.rst +++ b/docs/manpages/ndnsec-list.rst @@ -1,24 +1,20 @@ ndnsec-list =========== -``ndnsec-list`` is a tool to display entities stored in **Public Information Base (PIB)**, such as -identities, keys, and certificates. - -Usage ------ - -:: +Synopsis +-------- - $ ndnsec-list [-h] [-KkCc] +**ndnsec-list** [**-h**] [**-k**\|\ **-c**] Description ----------- -``ndnsec-list`` lists names of all the entities according to the granularity specified in options -(The default granularity is identity). The default entities will be marked with ``*`` in front of -their names. For example: +:program:`ndnsec-list` prints the names of all the entities stored in the +**Public Information Base (PIB)**, such as identities, keys, and certificates, +up to the given granularity level. By default, only the identity names are +shown. The default entities will be marked with a "*" in front of their names. -:: +For example:: $ ndnsec list * /ndn/edu/ucla/cs/yingdi @@ -26,24 +22,23 @@ their names. For example: /ndn/test/bob /ndn/test/alice - Options ------- -``-K, -k`` - Display key names for each identity. The key name with ``*`` in front is the default key name of - the corresponding identity. +.. option:: -k, --key -``-C, -c`` - Display certificate names for each key. The certificate name with ``*`` in front is the default - certificate name of the corresponding key. + Display key names for each identity. The key name with a "*" in front is + the default key name of the corresponding identity. -Examples --------- +.. option:: -c, --cert + + Display certificate names for each key. The certificate name with a "*" + in front is the default certificate name of the corresponding key. -Display all the key names in PIB. +Example +------- -:: +Display all the key names in PIB:: $ ndnsec-list -k * /ndn/edu/ucla/cs/yingdi @@ -59,9 +54,7 @@ Display all the key names in PIB. /ndn/test/alice +->* /ndn/test/alice/ksk-1394129695025 -Display all the certificate names in PIB. - -:: +Display all the certificate names in PIB:: $ ndnsec-list -c * /ndn/edu/ucla/cs/yingdi diff --git a/docs/manpages/ndnsec-set-acl.rst b/docs/manpages/ndnsec-set-acl.rst deleted file mode 100644 index 23eb1a370..000000000 --- a/docs/manpages/ndnsec-set-acl.rst +++ /dev/null @@ -1,26 +0,0 @@ -ndnsec-set-acl -============== - -``ndnsec-set-acl`` is a tool to add an application into access control list of an private key. - -Usage ------ - -:: - - $ ndnsec-set-acl [-h] keyName appPath - -Description ------------ - -``ndnsec-set-acl`` will add the application pointed by ``appPath`` into the ACL of a key with name -``keyName``. - -Examples --------- - -Add an application into a key's ACL: - -:: - - $ ndnsec-set-acl /ndn/test/alice/ksk-1394129695025 /test/app/path diff --git a/docs/manpages/ndnsec-set-default.rst b/docs/manpages/ndnsec-set-default.rst index da0c5b58a..05c66777f 100644 --- a/docs/manpages/ndnsec-set-default.rst +++ b/docs/manpages/ndnsec-set-default.rst @@ -1,49 +1,43 @@ ndnsec-set-default ================== -``ndnsec-set-default`` is a tool to change the default security settings. - -Usage ------ - -:: +Synopsis +-------- - $ ndnsec-set-default [-h] [-k|c] name +**ndnsec-set-default** [**-h**] [**-k**\|\ **-c**] *name* Description ----------- -By default, ``ndnsec-set-default`` takes ``name`` as an identity name and sets the identity as the -system default identity. +:program:`ndnsec-set-default` allows changing the default security settings. + +Without any options, *name*, which must be an identity name, is set as the +default identity for the current user. Options ------- -``-k`` - Set default key. ``name`` should be a key name, ``ndnsec-set-default`` can infer the corresponding - identity and set the key as the identity's default key. +.. option:: -k, --default-key -``-c`` - Set default certificate. ``name`` should be a certificate name, ``ndnsec-set-default`` can - infer the corresponding key name and set the certificate as the key's default certificate. + Set *name*, which must be a key name, as the default key for the + corresponding identity. -Examples --------- +.. option:: -c, --default-cert -Set a key's default certificate: + Set *name*, which must be a certificate name, as the default certificate + for the corresponding key. -:: +Example +------- - $ ndnsec-set-default -c /ndn/test/KEY/alice/ksk-1394129695025/ID-CERT/%FD%01D%98%9A%F2%3F +Set a key's default certificate:: -Set an identity's default key: + $ ndnsec-set-default -c /ndn/test/KEY/alice/ksk-1394129695025/ID-CERT/%FD%01D%98%9A%F2%3F -:: +Set an identity's default key:: $ ndnsec-set-default -k /ndn/test/alice/ksk-1394129695025 -Set system default identity: - -:: +Set the user's default identity:: $ ndnsec-set-default /ndn/test/alice diff --git a/docs/manpages/ndnsec-sign-req.rst b/docs/manpages/ndnsec-sign-req.rst index 67d11f42d..d17ff3cc7 100644 --- a/docs/manpages/ndnsec-sign-req.rst +++ b/docs/manpages/ndnsec-sign-req.rst @@ -1,37 +1,35 @@ ndnsec-sign-req =============== -``ndnsec-sign-req`` is a tool to generate a signing request for a particular key. - -Usage ------ - -:: +Synopsis +-------- - $ ndnsec-sign-req [-h] [-k] name +**ndnsec-sign-req** [**-h**] [**-k**] *name* Description ----------- -The signing request of a key is actually a self-signed certificate. Given key's information, -``ndnsec-sign-req`` looks up the key in PIB. If such a key exists, a self-signed certificate of the -key, or its signing request, will be outputed to **stdout** with base64 encoding. +:program:`ndnsec-sign-req` generates a signing request for a key. + +The signing request of a key is actually a self-signed certificate. Given the +key's information, :program:`ndnsec-sign-req` looks up the key in the PIB. +If such a key exists, a self-signed certificate for the key, i.e. its signing +request, is written to the standard output in base64 encoding. -By default, ``name`` is interpreted as an identity name. ``ndnsec-sign-req`` will generate a -signing request for the identity's default key. +By default, *name* is interpreted as an identity name, and the signing request +will be generated for that identity's default key. Options ------- -``-k`` - Interpret ``name`` as a key name. +.. option:: -k, --key -Examples --------- + Interpret *name* as a key name, instead of an identity name. -Create a signing request for an identity's default key. +Example +------- -:: +Create a signing request for an identity's default key:: $ ndnsec-sign-req /ndn/test/david Bv0DAAc9CANuZG4IBHRlc3QIBWRhdmlkCANLRVkIEWtzay0xMzk2OTk4Mzg5MjU3 @@ -52,10 +50,7 @@ Create a signing request for an identity's default key. 0wHjvDS1cuIH2j6XveoUYapRjZXaEZqB/YoBwRqEYq2KVn/ol5knLM6FIISXXjxn cIh62A== - -Create a signing request for a particular key. - -:: +Create a signing request for a particular key:: $ ndnsec-sign-req -k /ndn/test/david/ksk-1396913058196 Bv0DAAc9CANuZG4IBHRlc3QIBWRhdmlkCANLRVkIEWtzay0xMzk2OTEzMDU4MTk2 diff --git a/docs/manpages/ndnsec-unlock-tpm.rst b/docs/manpages/ndnsec-unlock-tpm.rst index 7672f00db..f5a8d9281 100644 --- a/docs/manpages/ndnsec-unlock-tpm.rst +++ b/docs/manpages/ndnsec-unlock-tpm.rst @@ -1,17 +1,13 @@ ndnsec-unlock-tpm ================= -``ndnsec-unlock-tpm`` is a tool to (temporarily) unlock the **Trusted Platform Module (TPM)** that -manages private keys. +Synopsis +-------- -Usage ------ - -:: - - $ ndnsec-unlock-tpm [-h] +ndnsec-unlock-tpm [**-h**] Description ----------- -``ndnsec-unlock-tpm`` will ask for password to unlock the TPM. +:program:`ndnsec-unlock-tpm` can be used to (temporarily) unlock the +**Trusted Platform Module (TPM)** that manages private keys. diff --git a/docs/manpages/ndnsec.rst b/docs/manpages/ndnsec.rst index 8641d0192..1eb0ed8e3 100644 --- a/docs/manpages/ndnsec.rst +++ b/docs/manpages/ndnsec.rst @@ -1,89 +1,71 @@ ndnsec ====== -``ndnsec`` is a command-line toolkit to perform various NDN security management -operation. +:program:`ndnsec` is a command-line toolkit to perform various NDN security +management operations. -Usage ------ +Synopsis +-------- -:: +**ndnsec** *command* [*argument*]... - $ ndnsec [] - -or alternatively - -:: - - $ ndnsec-command [] +**ndnsec-**\ *command* [*argument*]... Description ----------- -The NDN security data are stored and managed in two places: **Public Information Base** and -**Trusted Platform Module**. ``ndnsec`` toolkit provides a command-line interface of managing and -using the NDN security data. +The NDN security data are stored in two places: **Public Information Base** +(PIB) and **Trusted Platform Module** (TPM). The :program:`ndnsec` toolkit +provides a command-line interface for managing and using the NDN security data. -ndnsec commands ---------------- +Commands +-------- -ndnsec-list_ - Display information in PublicInfo. +list_ + List all known identities/keys/certificates. -ndnsec-get-default_ - Get default setting info. +get-default_ + Show the default identity/key/certificate. -ndnsec-set-default_ - Configure default setting. +set-default_ + Change the default identity/key/certificate. -ndnsec-key-gen_ - Generate a Key-Signing-Key for an identity. +delete_ + Delete an identity/key/certificate. -ndnsec-dsk-gen_ - Generate a Data-Signing-Key (DSK) for an identity and sign the DSK using the corresponding KSK. +key-gen_ + Generate a key for an identity. -ndnsec-sign-req_ +sign-req_ Generate a certificate signing request. -ndnsec-cert-gen_ - Generate an identity certificate. - -ndnsec-cert-dump_ - Dump a certificate from PublicInfo. - -ndnsec-cert-install_ - Install a certificate into PublicInfo. - -ndnsec-delete_ - Delete identity/key/certificate. +cert-gen_ + Create a certificate for an identity. -ndnsec-export_ - Export an identity package. +cert-dump_ + Export a certificate. -ndnsec-import_ - Import an identity package. +cert-install_ + Import a certificate from a file. -ndnsec-set-acl_ - Configure ACL of a private key. +export_ + Export an identity as a SafeBag. -ndnsec-unlock-tpm_ - Unlock Tpm. +import_ + Import an identity from a SafeBag. -ndnsec-op-tool_ - Operator tool. +unlock-tpm_ + Unlock the TPM. -.. _ndnsec-list: ndnsec-list.html -.. _ndnsec-get-default: ndnsec-get-default.html -.. _ndnsec-set-default: ndnsec-set-default.html -.. _ndnsec-key-gen: ndnsec-key-gen.html -.. _ndnsec-dsk-gen: ndnsec-dsk-gen.html -.. _ndnsec-sign-req: ndnsec-sign-req.html -.. _ndnsec-cert-gen: ndnsec-cert-gen.html -.. _ndnsec-cert-dump: ndnsec-cert-dump.html -.. _ndnsec-cert-install: ndnsec-cert-install.html -.. _ndnsec-delete: ndnsec-delete.html -.. _ndnsec-export: ndnsec-export.html -.. _ndnsec-import: ndnsec-import.html -.. _ndnsec-set-acl: ndnsec-set-acl.html -.. _ndnsec-unlock-tpm: ndnsec-unlock-tpm.html -.. _ndnsec-op-tool: ndnsec-op-tool.html +.. _list: ndnsec-list.html +.. _get-default: ndnsec-get-default.html +.. _set-default: ndnsec-set-default.html +.. _delete: ndnsec-delete.html +.. _key-gen: ndnsec-key-gen.html +.. _sign-req: ndnsec-sign-req.html +.. _cert-gen: ndnsec-cert-gen.html +.. _cert-dump: ndnsec-cert-dump.html +.. _cert-install: ndnsec-cert-install.html +.. _export: ndnsec-export.html +.. _import: ndnsec-import.html +.. _unlock-tpm: ndnsec-unlock-tpm.html diff --git a/docs/redmine_issue.py b/docs/redmine_issue.py deleted file mode 100644 index 0df2b1ff8..000000000 --- a/docs/redmine_issue.py +++ /dev/null @@ -1,70 +0,0 @@ -# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -# Based on http://doughellmann.com/2010/05/09/defining-custom-roles-in-sphinx.html - -"""Integration of Sphinx with Redmine. -""" - -from docutils import nodes, utils -from docutils.parsers.rst.roles import set_classes - -def redmine_role(name, rawtext, text, lineno, inliner, options={}, content=[]): - """Link to a Redmine issue. - - Returns 2 part tuple containing list of nodes to insert into the - document and a list of system messages. Both are allowed to be - empty. - - :param name: The role name used in the document. - :param rawtext: The entire markup snippet, with role. - :param text: The text marked with the role. - :param lineno: The line number where rawtext appears in the input. - :param inliner: The inliner instance that called us. - :param options: Directive options for customization. - :param content: The directive content for customization. - """ - try: - issue_num = int(text) - if issue_num <= 0: - raise ValueError - except ValueError: - msg = inliner.reporter.error( - 'Redmine issue number must be a number greater than or equal to 1; ' - '"%s" is invalid.' % text, line=lineno) - prb = inliner.problematic(rawtext, rawtext, msg) - return [prb], [msg] - app = inliner.document.settings.env.app - node = make_link_node(rawtext, app, 'issues', str(issue_num), options) - return [node], [] - -def make_link_node(rawtext, app, type, slug, options): - """Create a link to a Redmine resource. - - :param rawtext: Text being replaced with link node. - :param app: Sphinx application context - :param type: Link type (issue, changeset, etc.) - :param slug: ID of the thing to link to - :param options: Options dictionary passed to role func. - """ - # - try: - base = app.config.redmine_project_url - if not base: - raise AttributeError - except AttributeError: - raise ValueError('redmine_project_url configuration value is not set') - # - slash = '/' if base[-1] != '/' else '' - ref = base + slash + type + '/' + slug + '/' - set_classes(options) - node = nodes.reference(rawtext, 'Issue #' + utils.unescape(slug), refuri=ref, - **options) - return node - -def setup(app): - """Install the plugin. - - :param app: Sphinx application context. - """ - app.add_role('issue', redmine_role) - app.add_config_value('redmine_project_url', None, 'env') - return diff --git a/docs/release-notes-latest.rst b/docs/release-notes-latest.rst deleted file mode 120000 index c25095c41..000000000 --- a/docs/release-notes-latest.rst +++ /dev/null @@ -1 +0,0 @@ -release-notes/release-notes-0.5.0.rst \ No newline at end of file diff --git a/docs/release-notes-latest.rst b/docs/release-notes-latest.rst new file mode 100644 index 000000000..2b137c9ab --- /dev/null +++ b/docs/release-notes-latest.rst @@ -0,0 +1,79 @@ +ndn-cxx version 0.7.0 +--------------------- + +Release date: January 13, 2020 + +**Breaking Change** + +This release features support of only `NDN packet format version 0.3 +`__ (:issue:`4527`, :issue:`4567`, +:issue:`4709`, :issue:`4913`). The library encodes and interprets Interest and Data +packets only in 0.3 format; support for version 0.2 has been completely removed. In +addition, the URI representation of Interest packets has also been changed following the +packet format updates. + +New features +^^^^^^^^^^^^ + +- HMAC signing support (:issue:`3075`) + +- Support for ``ParametersSha256DigestComponent`` in ``Name`` and ``Interest`` classes + (:issue:`4658`) + +- Encoding/decoding of ``HopLimit`` field in Interest (:issue:`4806`) + +- PIT token (:issue:`4532`). + + PIT token is a hop-by-hop header field that identifies an Interest-Data exchange. The + downstream node can assign an opaque token to an outgoing Interest, and the upstream node + is expected to return the same token on the Data or Nack in reply to that Interest. This + would allow the downstream node to accelerate its processing, especially in PIT lookup. + +- ``io::loadBuffer`` and ``io::saveBuffer`` helper functions + +Improvements and bug fixes +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Various improvements in the Linux implementation of ``NetworkMonitor`` class + +- Rework of ``RttEstimator`` class: + + * split into two classes: ``RttEstimator`` and ``RttEstimatorWithStats`` (:issue:`4887`) + * add a getter for the smoothed RTT value (:issue:`4892`) + * switch to use ``time::nanoseconds`` (:issue:`4887`) + +- Make use of attributes in logging facilities and generalize logger backend support + (:issue:`4969`, :issue:`3782`) + +- Silently accept an empty validation policy instead of throwing an exception (:issue:`5049`) + +- Introduce alternative URI syntax for component types used in naming conventions, with + ability to choose between canonical and alternate format (:issue:`4777`) + +- Don't force the generation of an Interest nonce during decoding (:issue:`4685`) + +- Various documentation improvements + +Removals +^^^^^^^^ + +- ``ndn::util::Scheduler`` (use ``ndn::Scheduler`` or ``ndn::scheduler::Scheduler``) and + ``ndn::EventId`` (use ``ndn::scheduler::EventId``) (:issue:`4883`) + +- Unused ``KeyClass`` and ``AclType`` enums + +- Unused ``v2::PublicKey`` alias of ``transform::PublicKey`` + +- ``HmacFilter`` class, use SignerFilter and VerifierFilter instead + +- Ill-defined equality operators for ``Interest``, ``MetaInfo``, ``Signature`` (:issue:`4569`) + +- Implicit conversion from the ``xyzHandle`` types to ``const xyzId*`` (where ``xyz`` is + ``PendingInterest``, ``RegisteredPrefixId``, and ``InterestFilterId``) + +- Deprecated ``KeyLocator::Type`` enum + +- Private header files of concrete PIB, TPM, and KeyHandle implementations are no longer + installed (:issue:`4782`) + +- Renamed ``util/backports-ostream-joiner.hpp`` to ``util/ostream-joiner.hpp`` diff --git a/docs/release-notes/release-notes-0.1.0.rst b/docs/release-notes/release-notes-0.1.0.rst index 168f5bc11..a8cf1bc9d 100644 --- a/docs/release-notes/release-notes-0.1.0.rst +++ b/docs/release-notes/release-notes-0.1.0.rst @@ -49,11 +49,11 @@ The current features include: `_ - Full support for `NFD management protocols - `_ to NFD status + `_ to NFD status information, create and manage NFD Faces, receive NFD Face status change notifications, update StrategyChoice for namespaces, and manage routes in RIB - Support for `LocalControlHeader - `_ to implement + `_ to implement special NDN applications that need low-level control of NDN packet forwarding - **Security support** diff --git a/docs/release-notes/release-notes-0.2.0.rst b/docs/release-notes/release-notes-0.2.0.rst index 718a39bc0..0a8c10f85 100644 --- a/docs/release-notes/release-notes-0.2.0.rst +++ b/docs/release-notes/release-notes-0.2.0.rst @@ -32,8 +32,7 @@ New features: The new option also allow periodic reloading trust anchors, allowing dynamic trust models. - + Added support for multiple signature types to :ndn-cxx:`PublicKey`, - :ndn-cxx:`SecPublicInfo` abstractions + + Added support for multiple signature types to ``PublicKey``, ``SecPublicInfo`` abstractions + New :ndn-cxx:`SignatureSha256WithEcdsa` signature type @@ -64,7 +63,7 @@ New features: + Introduce :ndn-cxx:`Scheduler::cancelAllEvents` to cancel all previously scheduled events (:issue:`1757`) - + Introduce :ndn-cxx:`util::EventEmitter`, :ndn-cxx:`util::NotificationSubscriber`, + + Introduce ``util::EventEmitter``, :ndn-cxx:`util::NotificationSubscriber`, :ndn-cxx:`util::NotificationStream`, and :ndn-cxx:`nfd::FaceMonitor` utility classes + Introduce :ndn-cxx:`util::SegmentFetcher` helper class to fetch multi-segmented data @@ -123,12 +122,11 @@ Updates and bug fixes: Sub-classes of :ndn-cxx:`Validator` class can use the following hooks to fine-tune the validation process: - * :ndn-cxx:`Validator::preCertificateValidation ` to - process received certificate before validation. - * :ndn-cxx:`Validator::onTimeout ` to process interest timeout - * :ndn-cxx:`Validator::afterCheckPolicy ` to process validation requests. + * ``preCertificateValidation`` to process received certificate before validation. + * ``onTimeout`` to process interest timeout + * ``afterCheckPolicy`` to process validation requests. - + Fix memory issues in :ndn-cxx:`SecPublicInfoSqlite3` + + Fix memory issues in ``SecPublicInfoSqlite3`` - **Miscellaneous tools** @@ -156,7 +154,7 @@ Deprecated: - ``name::Component::toEscapedString`` method, use :ndn-cxx:`name::Component::toUri` instead. -- ``SecPublicInfo::addPublicKey`` method, use :ndn-cxx:`SecPublicInfo::addKey` instead. +- ``SecPublicInfo::addPublicKey`` method, use ``SecPublicInfo::addKey`` instead. - ``Tlv::ConentType`` constant (typo), use ``Tlv::ContentType`` instead. diff --git a/docs/release-notes/release-notes-0.3.1.rst b/docs/release-notes/release-notes-0.3.1.rst index 982d8bd9d..7f8a9f012 100644 --- a/docs/release-notes/release-notes-0.3.1.rst +++ b/docs/release-notes/release-notes-0.3.1.rst @@ -13,9 +13,9 @@ New features: - Add isConnected() in :ndn-cxx:`signal::Connection` and :ndn-cxx:`signal::ScopedConnection` (:issue:`2308`) - - Extend :ndn-cxx:`DummyClientFace` to process :ndn-cxx:`LocalControlHeader` (:issue:`2510`) + - Extend :ndn-cxx:`DummyClientFace` to process ``LocalControlHeader`` (:issue:`2510`) - - Add CachingPolicy to :ndn-cxx:`LocalControlHeader` (:issue:`2183`) + - Add CachingPolicy to ``LocalControlHeader`` (:issue:`2183`) Updates and bug fixes: ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/release-notes/release-notes-0.3.3.rst b/docs/release-notes/release-notes-0.3.3.rst index 65aca003b..d7aeecf55 100644 --- a/docs/release-notes/release-notes-0.3.3.rst +++ b/docs/release-notes/release-notes-0.3.3.rst @@ -117,7 +117,7 @@ Removed: Upcoming features (partially finished in development branches): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- NDNLPv2 (http://redmine.named-data.net/projects/nfd/wiki/NDNLPv2, :issue:`2520`, +- NDNLPv2 (https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2, :issue:`2520`, :issue:`2879`, :issue:`2763`, :issue:`2883`, :issue:`2841`, :issue:`2866`) - New NDN certificate format (:issue:`2861`, :issue:`2868`) diff --git a/docs/release-notes/release-notes-0.5.1.rst b/docs/release-notes/release-notes-0.5.1.rst new file mode 100644 index 000000000..cdb555a66 --- /dev/null +++ b/docs/release-notes/release-notes-0.5.1.rst @@ -0,0 +1,104 @@ +ndn-cxx version 0.5.1 +--------------------- + +Release date: January 25, 2017 + +.. note:: + This is the last release of the library that supports NDN Certificate format version 1 and + the existing implementations of validators. The upcoming 0.6.0 release will include + multiple breaking changes of the security framework. + +Changes since version 0.5.0: + +New features: +^^^^^^^^^^^^^ + +- Add version 2 of the security framework (introduced in ``security::v2`` namespace) + + * :ref:`NDN Certificate Format Version 2.0 ` + (:issue:`3103`) + * New Public Information Base (PIB) and Trusted Program Module (TPM) framework to manage + public/private keys and NDN Certificate version 2.0 (:issue:`2948`, :issue:`3202`) + * New KeyChain implementation (:issue:`2926`) + * New Validator implementation (:issue:`3289`, :issue:`1872`) + * New security-supporting utilities: trust anchor container and certificate cache + * Creation of `Command Interests + `__ delegated to + :ndn-cxx:`CommandInterestSigner` class, while the new KeyChain only :ref:`signs Interests + ` (:issue:`3912`) + +- Enable validator to fetch certificates directly from the signed/command interest sender + (:issue:`3921`) + +- Add UP and DOWN kinds to :ndn-cxx:`FaceEventNotification` (issue:`3794`) + +- Add support for NIC-associated permanent faces in FaceUri (:issue:`3522`) + +- Add support for CongestionMark and Ack NDNLPv2 fields (:issue:`3797`, :issue:`3931`) + +- Add StrategyChoice equality operators and formatted output (:issue:`3903`) + +Improvements and bug fixes +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Ensure that NACK callback is called for matching Interests, regardless of their nonce + (:issue:`3908`) + +- Optimize :ndn-cxx:`name::Component::compare` implementation (:issue:`3807`) + +- Fix memory leak in ndn-cxx:`Regex` (:issue:`3673`) + +- Correct NDNLPv2 rules for whether an unknown field can be ignored (:issue:`3884`) + +- Ensure that port numbers in FaceUri are 16 bits wide + +- Correct ValidityPeriod::isValid check (:issue:`2868`) + +- Fix encoding of type-specific TLV (:issue:`3914`) + +- Rename previously incorrectly named EcdsaKeyParams to EcKeyParams (:issue:`3135`) + +- Various documentation improvements, including ndn-cxx code style updates (:issue:`3795`, :issue:`3857`) + +Deprecated +^^^^^^^^^^ + +- Old security framework. All old security framework classes are moved to + ``ndn::security::v1`` namespace in this release and will be removed in the next release. + + * ``v1::KeyChain``, use :ndn-cxx:`v2::KeyChain` instead + + * ``v1::Validator`` interface and all implementations of this interface (``ValidatorRegex``, + ``ValidatorConfig``, ``ValidatorNull``). Use :ndn-cxx:`v2::Validator` and the + corresponding implementations of :ndn-cxx:`ValidationPolicy` interfaces (will be introduced + before 0.6.0 release). + + * ``v1::SecPublicInfo`` and its implementation (``SecPublicInfoSqlite``), ``SecTpm`` and its + implementations (``SecTpmFile``, ``SecTpmOsx``). These classes are internal implementation + and not intended to be used without ``v1::KeyChain``. :ndn-cxx:`v2::KeyChain` internally + uses the newly introduced :ndn-cxx:`Pib` and :ndn-cxx:`Tpm` interfaces with their + corresponding implementations. + + * ``v1::Certificate``, ``v1::IdentityCertificate``, ``v1::CertificateExtension``, + ``v1::CertificateSubjectDescription``, use :ndn-cxx:`v2::Certificate` and + :ndn-cxx:`AdditionalDescription` + + * ``v1::SecuredBag``, use ``v2::SafeBag`` instead + +- Constant ``io::BASE_64``, use ``io::BASE64`` instead (:issue:`3741`) + +- Headers ``management/nfd-*``, use ``mgmt/nfd/*`` instead (:issue:`3760`) + +- ``ndn::crypto::sha256`` in favor of ``ndn::crypto::computeSha256Digest`` + +- ``security/cryptopp.hpp`` header. Use ``security/v1/cryptopp.hpp`` when needed, avoid direct + include as CryptoPP dependency will be removed from future versions of the library. + +- ``security/identity-certificate.hpp`` header. Use ``security/v1/identity-certificate.hpp`` instead. + +- ``ndn::PublicKey``, ``ndn::Certificate``, ``ndn::IdentityCertificate``, + ``ndn::CertificateExtension``, ``ndn::CertificateSubjectDescription``. When necessary, use + ``security::v1::PublicKey``, ``security::v1::Certificate``, ``security::v1::IdentityCertificate``, + ``security::v1::CertificateExtension``, ``security::v1::CertificateSubjectDescription`` instead. + The next release will feature :ref:`a new version of NDN Certificate format + `. diff --git a/docs/release-notes/release-notes-0.6.0.rst b/docs/release-notes/release-notes-0.6.0.rst new file mode 100644 index 000000000..f774775de --- /dev/null +++ b/docs/release-notes/release-notes-0.6.0.rst @@ -0,0 +1,153 @@ +ndn-cxx version 0.6.0 +--------------------- + +Release date: October 16, 2017 + +Changes since version 0.5.1: + +New features: +^^^^^^^^^^^^^ + +- **breaking change** Security framework version 2 (:issue:`3098`, :issue:`3920`, + :issue:`3644`, :issue:`4085`, :issue:`4323`, :issue:`4339`) + + The released version of the library only supports the new version of the security (v2 + certificate format) and features a number of updates of KeyChain and Validator + interfaces. At the same time, management APIs for :ndn-cxx:`ValidatorConfig` remained + intact; transition to the new framework would require only adjusting + :ndn-cxx:`Validator::validate` calls and updating configuration files to follow the new + naming conventions of :ref:`NDN Certificate Format Version 2.0`. + +- Integration of fetching certificates using Certificate Bundle as part of specialized + ``CertificateFetcher`` (:issue:`3891`) + +- ``ForwardingHint``, ``Delegation``, and ``DelegationList``; refactoring of Interest encoding + to include ``ForwardingHint`` instead of ``LinkObject``, following the latest NDN + specification updates (:issue:`4054`, :issue:`4055`) + +- Fine-grained signals on interface/address changes in NetworkMonitor + for all supported platforms (:issue:`3353`, :issue:`4025`, :issue:`3817`, :issue:`4024`) + +- Addition of ``TxSequence`` field and ``Ack``, the first repeatable field in + NDNLPv2 (:issue:`3931`) + +- Optional ``LocalUri`` as part of ``ControlParameters`` and adjusting face creation command + and responses to handle the new optional field (:issue:`4014`, :issue:`4015`, :issue:`3956`) + +- ``LpReliability`` flag in Face management data structures (:issue:`4003`) + +- Backported implementation of C++17 classes ``ostream_joiner`` and ``optional`` + (:issue:`3962`, :issue:`3753`) + +Improvements and bug fixes +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Removed dependency on CryptoPP library. All cryptographic operations are now realized using + OpenSSL library routines and/or with the help of ``security::transform`` framework + (:issue:`3006`, :issue:`3946`, :issue:`3924`, :issue:`3886`). + +- Improved APIs for NFD management data structures, including equality comparators, formatted + output, etc. (:issue:`3932`, :issue:`3903`, :issue:`3864`) + +- FaceUri now accepts link-local IPv6 addresses (:issue:`1428`) + +- Rename variables in ``FaceStatus`` and ``ForwarderStatus`` ('datas' => 'data') + (:issue:`3955`) + +- Improve logging framework and its uses + + * Add API to enumerate Logger modules (:issue:`4013`) + + * Advanced filtering of the logging modules (:issue:`3918`) + + * Add logging capabilities to ``Face``, ``UnixTransport``, ``TcpTransport``, and the new + security framework (:issue:`3563`) + + To enable logging, set environment variable ``NDN_LOG`` to enable specific, subset, or all + logging module at appropriate levels. Examples: + + :: + + export NDN_LOG=*=ALL + export NDN_LOG=ndn.*=ALL + export NDN_LOG=ndn.security=DEBUG:ndn.TcpTransport=ALL + +- Ensure that ``Face`` sends ``Nack`` only after every ``InterestCallback`` has responded + (:issue:`4228`) + +- Fix potential overflow in ``time::toIsoString`` (:issue:`3915`) + +- Fix potentially misaligned memory accesses (:issue:`4172`, :issue:`4097`, :issue:`4175`, + :issue:`4190`, :issue:`4191`) + +- Fix potential memory access error in ``Face/PendingInterest`` (:issue:`4228`) + +- Improvements and streamlining of the ``security::transform`` framework + +- Source/header reorganization (:issue:`3940`) + + * Move network-related files to ``src/net`` + + .. note:: + Namespace changes + + * ndn::util::FaceUri is now ndn::FaceUri + * ndn::util::ethernet is now ndn::ethernet + * ndn::util::NetworkMonitor and related classes are now in ndn::net + + * Move signal-related files into ``src/util/signal/`` directory, except for + the main include ``signal.hpp`` + + * Move InMemoryStorage to ``src/ims`` + + * Rename ``digest.hpp`` to ``sha256.hpp`` to match the ``Sha256`` class declared within + +Removed +^^^^^^^ + +- Old security framework. + + * ``v1::KeyChain``, use :ndn-cxx:`v2::KeyChain` instead + + * ``v1::Validator`` interface and ``ValidatorRegex`` implementation of this + interface. ``ValidatorConfig``, ``ValidatorNull`` implementation refactored to be based on + the new validation framework. + + * ``v1::SecPublicInfo`` and its implementation (``SecPublicInfoSqlite``), ``SecTpm`` and its + implementations (``SecTpmFile``, ``SecTpmOsx``). These classes are internal implementation + and not intended to be used without ``v1::KeyChain``. :ndn-cxx:`v2::KeyChain` internally + uses the newly introduced :ndn-cxx:`Pib` and :ndn-cxx:`Tpm` interfaces with their + corresponding implementations. + + * ``v1::Certificate``, ``v1::IdentityCertificate``, ``v1::CertificateExtension``, + ``v1::CertificateSubjectDescription``, use :ndn-cxx:`v2::Certificate` and + :ndn-cxx:`AdditionalDescription` + + * ``v1::SecuredBag``, use ``v2::SafeBag`` instead + +- Constant ``io::BASE_64``, use ``io::BASE64`` instead (:issue:`3741`) + +- Headers ``management/nfd-*``, use ``mgmt/nfd/*`` instead (:issue:`3760`) + +- ``security/cryptopp.hpp`` header + +- ``security/identity-certificate.hpp`` header + +- ``ndn::PublicKey``, ``ndn::Certificate``, ``ndn::IdentityCertificate``, + ``ndn::CertificateExtension``, ``ndn::CertificateSubjectDescription``. + +- ``Link`` and ``SelectedDelegation`` fields in ``Interest``, replaced by + ``ForwardingHint`` following the latest version of NDN specification (:issue:`4055`) + +- ``LocalControlHeader`` constants (:issue:`3755`) + +- ``NInDatas`` and ``NOutDatas`` (:issue:`3955`) + +- Overload of ``Block::Block`` that parses a ``Block`` from a ``void*`` buffer + +- Duplicate ``buf()`` and ``get()`` methods from ``Buffer`` class in favor of ``data()`` + +- ``util/crypto.hpp``, ``crypto::sha256()``, and ``crypto::computeSha256Digest()`` in favor of + ``Sha256::computeDigest()`` + +- Previously deprecated functions (:issue:`4055`) diff --git a/docs/release-notes/release-notes-0.6.1.rst b/docs/release-notes/release-notes-0.6.1.rst new file mode 100644 index 000000000..277091567 --- /dev/null +++ b/docs/release-notes/release-notes-0.6.1.rst @@ -0,0 +1,69 @@ +ndn-cxx version 0.6.1 +--------------------- + +Release date: February 19, 2018 + +New features: +^^^^^^^^^^^^^ + +- (potentially breaking change) :ndn-cxx:`expressInterest` now by default loopbacks Interests to + producer callbacks on the same :ndn-cxx:`Face`. When undesired, use + ``InterestFilter::allowLoopback(false)`` (:issue:`3979`) + +- New signal in :ndn-cxx:`SegmentFetcher` to notify retrieval of Data segments + (:issue:`4438`) + +- Initial support for the Content Store management protocol + (:issue:`4050`) + +- Literal operators for ``time::duration`` types, such as ``1_s``, ``42_ms``, ``30_days`` + (:issue:`4468`) + +- Support for BLAKE2 hash function (requires OpenSSL >= 1.1.0) + +- A ``escape()`` helper function complementing the existing ``unescape()`` (:issue:`4484`) + +Improvements and bug fixes +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- ``ndnsec key-gen`` command line now allows customization of key ID (:issue:`4294`) + +- Fixed encoding of ``'~'`` and ``'+'`` in :ndn-cxx:`Component::toUri()` + (:issue:`4484`) + +- Fixed handling of large dates when converting to/from string + (:issue:`4478`, :issue:`3915`) + +- Fixed error handling in :ndn-cxx:`KeyChain::importSafeBag()` + (:issue:`4359`) + +- Fixed parsing of IPv6 addresses with scope-id + (:issue:`4474`) + +- :ndn-cxx:`io::load()` now handles empty files properly + (:issue:`4434`) + +- Switched to using `boost::asio::basic_waitable_timer` + (:issue:`4431`) + +- Allow linking multiple :ndn-cxx:`DummyClientFace` instances together to emulate a broadcast medium + (:issue:`3913`) + +- Fixed build when ``std::to_string`` is not available + (:issue:`4393`) + +- Avoid undefined behavior when casting to :ndn-cxx:`tlv::SignatureTypeValue` + (:issue:`4370`) + +- Fixed compilation with Boost 1.66.0 + (:issue:`4422`) + +- Various documentation updates + (:issue:`3918`, :issue: `4184`, :issue: `4275`) + +Removed +^^^^^^^ + +- Removed obsolete TLV-TYPE constants + (:issue:`4055`, :issue:`3098`, :issue: `3755`) + diff --git a/docs/release-notes/release-notes-0.6.2.rst b/docs/release-notes/release-notes-0.6.2.rst new file mode 100644 index 000000000..3c48aeb31 --- /dev/null +++ b/docs/release-notes/release-notes-0.6.2.rst @@ -0,0 +1,53 @@ +ndn-cxx version 0.6.2 +--------------------- + +Release date: May 4, 2018 + +New features: +^^^^^^^^^^^^^ + +- Initial support for [NDN packet format version + 0.3](https://named-data.net/doc/NDN-packet-spec/0.3/) (:issue:`4527`) + + * Recognize typed name components, allow typed name component in ``FinalBlockId`` + (:issue:`4526`) + + * Recognize Interest in Packet Format v0.3 (:issue:`4527`) + + In this release, ``Interest::wireDecode`` accepts both v0.2 and v0.3 formats, but + ``Interest::wireEncode`` only encodes into v0.2 format. A future release of the + library will switch the encoding to v0.3 format. + + * Recognize Data in Packet Format v0.3 (:issue:`4568`) + + In this release, ``Data::wireDecode`` accepts both v0.2 and v0.3 formats, but + ``Data::wireEncode`` only encodes into v0.2 format. A future release of the library + will switch the encoding to v0.3 format. + +- Library support for cs/erase command of NFD Management (:issue:`4318`) + +- A convenience function to print out ``Block`` structures (:issue:`2225`) + +Improvements and bug fixes +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Change encoding of NDNLPv2 sequence number from nonNegativeInteger to fixed-width + integer (8 bytes in network order) (:issue:`4403`) + +- Fix compilation with Boost 1.67 (:issue:`4584`) + +- Upgrade build environment to latest version of ``waf`` and other improvements + +- Logging system improvements (:issue:`4552`) + +Deprecated +~~~~~~~~~~ + +- Selectors (:issue:`4527`) + + NDN Packet Format v0.3 replaces Selectors with ``CanBePrefix`` and ``MustBeFresh`` elements. + This commit deprecates getter/setter for Selectors in Interest class. Getter/setter for + CanBePrefix and MustBeFresh are mapped to the closest v0.2 semantics and encoded as + selectors. + +- ``Data::get/setFinalBlockId()`` in favor of ``Data::get/setFinalBlock()`` diff --git a/docs/release-notes/release-notes-0.6.3.rst b/docs/release-notes/release-notes-0.6.3.rst new file mode 100644 index 000000000..863e24694 --- /dev/null +++ b/docs/release-notes/release-notes-0.6.3.rst @@ -0,0 +1,88 @@ +ndn-cxx version 0.6.3 +--------------------- + +Release date: September 18, 2018 + +The build requirements have been upgraded to gcc >= 5.3 or clang >= 3.6, boost >= 1.58, +openssl >= 1.0.2. This effectively drops support for all versions of Ubuntu older than 16.04 +that use distribution-provided compilers and packages. + +The compilation now uses the C++14 standard. + +New features: +^^^^^^^^^^^^^ + +- More support for `NDN packet format version + 0.3 `__ (:issue:`4527`) + + - Allow applications to declare a default ``CanBePrefix`` setting (:issue:`4581`) + + - Accommodate typed name components in ``Name::getSuccessor`` (:issue:`4570`) + + - Support Parameters element (:issue:`4658`) + + - Recognize alternative type representations in URI syntax (:issue:`4690`) + + - Introduce ``ParametersSha256DigestComponent`` (:issue:`4658`, :issue:`4570`) + +- Prefix announcement object (:issue:`4650`) + +- MTU element in ``ControlParameters`` and ``FaceStatus`` (:issue:`4005`) + +- Enable congestion control features in ``SegmentFetcher`` (:issue:`4364`) + +- ``_block`` literal operator (:issue:`4722`) + +- Add official support for CentOS 7 (:issue:`4610`) + +Improvements and bug fixes +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Fix a segfault in ``Face::satisfyPendingInterests`` when ``Face::put`` is + called in DataCallback (:issue:`4596`) + +- Allow specifying passphrase for ndnsec import/export on the command line (:issue:`4633`) + +- Fix bug preventing customization of KeyChain's TPM on macOS (:issue:`4297`) + +- Fix bug with handling Sha256-signed Command Interests (:issue:`4635`) + +- Eliminate selector usage in ``SegmentFetcher`` (:issue:`4555`) + +- Improvements in ``netlink`` message processing + +- Gracefully handle ``NetworkMonitor`` backend initialization failure (:issue:`4668`) + +- Add support 224-bit and 521-bit NIST elliptic curves, add support for SHA-3 (with + openssl >= 1.1.1-pre1), and forbid RSA keys shorter than 2048 bits in security helpers + +- Improve and simplify code with modern C++ features + +- Properly declare move constructors + +- Improve error handling + +- Improve test cases + +- Correct and improve documentation + +Deprecated +~~~~~~~~~~ + +- ``SegmentFetcher::fetch()`` static functions in favor of ``start()`` (:issue:`4464`) + +- ``ndn::ip::address{,V6}FromString`` as Boost.Asio >= 1.58 has proper implementation of + ``addressFromString`` + +- Selectors (:issue:`4527`) + + NDN Packet Format v0.3 replaces Selectors with ``CanBePrefix`` and ``MustBeFresh`` elements. + ``CanBePrefix`` and ``MustBeFresh`` are currently mapped to the closest v0.2 semantics and + encoded as selectors. + +- ``Data::get/setFinalBlockId()`` in favor of ``Data::get/setFinalBlock()`` + +Removed +~~~~~~~ + +- Dependency on Boost.Regex in favor of ``std::regex`` diff --git a/docs/release-notes/release-notes-0.6.5.rst b/docs/release-notes/release-notes-0.6.5.rst new file mode 100644 index 000000000..a9e6ac728 --- /dev/null +++ b/docs/release-notes/release-notes-0.6.5.rst @@ -0,0 +1,78 @@ +ndn-cxx version 0.6.5 +--------------------- + +Release date: February 4, 2019 + +New features: +^^^^^^^^^^^^^ + +- More support for `NDN packet format version + 0.3 `__ (:issue:`4527`) + + * Stop using ``ChildSelector`` in ``NotificationSubscriber`` (:issue:`4664`) + + * Stop using ``ChildSelector`` in ``CertificateBundleFetcher`` (:issue:`4665`) + +- Support floating point numbers in TLV-VALUE (:issue:`4612`) + +- Scoped prefix registration, scoped Interest filter, and scoped pending Interest + (:issue:`3919`, :issue:`4316`) + +- Counters for satisfied and unsatisfied Interests in ``ForwarderStatus`` + (:issue:`4720`) + +- ``random::getRandomNumberEngine()`` in the public API + +- ``MetadataObject`` class to encode/decode RDR-style metadata (:issue:`4707`) + +- ``SegmentFetcher::stop()`` (:issue:`4692`) + +Improvements and bug fixes +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Use openssl-based routines for the PKCS#8 decoding/decryption when exporting key from macOS + Keychain (:issue:`4450`) + +- Switch to AES-256 for private key encryption in PKCS #8 export + +- Add exponential backoff in ``CertificateFetcherFromNetwork`` (:issue:`4718`, :issue:`4712`) + +- Throw exception when loading an orphaned ``ValidationPolicyConfig`` (API violation) + (:issue:`4758`) + +- Forbid unrecognized TLVs before ``Name`` (:issue:`4667`) + +- Prevent memory pool size from becoming zero in ``InMemoryStorage`` (:issue:`4769`) + +- Clean up fetchers when destructing ``nfd::Controller`` (:issue:`4775`) + +- Fix ``SegmentFetcher`` undefined behavior caused by uncanceled pending interest + (:issue:`4770`) + +- Seed the PRNG with more entropy (:issue:`4808`) + +- Stop accepting NonNegativeInteger as sequence number in NDNLP (:issue:`4598`) + +- Backport C++17 ``std::any`` and ``std::variant`` as ``ndn::any`` and ``ndn::variant`` + +- Reimplement ``scheduler::EventId`` with ``CancelHandle`` (:issue:`4698`) + +Deprecated +~~~~~~~~~~ + +- ``ndn-cxx/util/scheduler-scoped-event-id.hpp`` header as it is now sufficient to use + ``ndn-cxx/util/scheduler.hpp`` header (:issue:`4698`) + +- Implicit conversion from nullptr to ``scheduler::EventId`` (:issue:`4698`) + +Removed +~~~~~~~ + +- ``ndn::ip::address{,V6}FromString`` + +- ``SegmentFetcher::fetch`` (:issue:`4464`) + +- ``{get,set}FinalBlockId()`` + +- Headers that were already considered internal implementation details have been explicitly + moved to a ``detail/`` subdir to more clearly separate private and public headers diff --git a/docs/release-notes/release-notes-0.6.6.rst b/docs/release-notes/release-notes-0.6.6.rst new file mode 100644 index 000000000..a69cd8b7f --- /dev/null +++ b/docs/release-notes/release-notes-0.6.6.rst @@ -0,0 +1,60 @@ +ndn-cxx version 0.6.6 +--------------------- + +Release date: April 27, 2019 + +Note that this is the last release that encodes to `NDN packet format version 0.2.1 +`__. A future release will continue to +decode v0.2.1 format, but will encode to `v0.3 format +`__. + +New features: +^^^^^^^^^^^^^ + +- More support for `NDN packet format version + 0.3 `__ (:issue:`4527`) + + * Support new naming conventions to encode/decode segment numbers, byte offsets, versions, + timestamps, and sequence numbers based on typed name components (:issue:`4777`) + + * Stop using ``ChildSelector`` in ``CertificateBundleFetcher`` (:issue:`4665`) + +- ``NDN_THROW`` macro to throw exceptions including file position and runtime context of the + throw statement (:issue:`4834`) + +- Ensure that a ``Block`` with TLV-TYPE zero is treated as invalid (:issue:`4726`, :issue:`4895`) + +Improvements and bug fixes +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Avoid directly using memory address as ``PendingInterestId`` to prevent potential false + removal of an entry (:issue:`2865`) + +- Follow up packet specification changes to rename the ``Parameters`` element to + ``ApplicationParameters`` and to change its number to be a non-critical element type + (:issue:`4658`, :issue:`4780`) + +- Add option to disable infrastructure interest in ``CertificateFetcherDirectFetch`` (:issue:`4879`) + +- Fix compilation against recent versions of Boost libraries and issues with Xcode 10.2 and + older versions of Boost libraries (:issue:`4890`, :issue:`4923`, :issue:`4860`) + +- Improve the "CanBePrefix unset" warning (:issue:`4581`) + +- Improve documentation + +Deprecated +~~~~~~~~~~ + +- ``PendingInterestId``, ``RegisteredPrefixId``, and ``InterestFilterId`` types in favor of + ``PendingInterestHandle``, ``RegisteredPrefixHandle``, and ``InterestFilterHandle`` + (:issue:`4316`, :issue:`3919`) + +- ``Block::empty`` in favor of ``Block::isValid`` (with inverted semantics) + +- ``Scheduler::scheduleEvent`` and ``Scheduler::cancelEvent`` in favor of ``Scheduler::schedule`` + and ``EventId::cancel`` (or use ``ScopedEventId`` to automatically cancel the event when + the object goes out of scope) (:issue:`4883`) + +- ``ndn::util::Scheduler`` (use ``ndn::Scheduler`` or ``ndn::scheduler::Scheduler``) and + ``ndn::EventId`` (use ``ndn::scheduler::EventId``) (:issue:`4883`) diff --git a/docs/release-notes/release-notes-0.7.0.rst b/docs/release-notes/release-notes-0.7.0.rst new file mode 100644 index 000000000..2b137c9ab --- /dev/null +++ b/docs/release-notes/release-notes-0.7.0.rst @@ -0,0 +1,79 @@ +ndn-cxx version 0.7.0 +--------------------- + +Release date: January 13, 2020 + +**Breaking Change** + +This release features support of only `NDN packet format version 0.3 +`__ (:issue:`4527`, :issue:`4567`, +:issue:`4709`, :issue:`4913`). The library encodes and interprets Interest and Data +packets only in 0.3 format; support for version 0.2 has been completely removed. In +addition, the URI representation of Interest packets has also been changed following the +packet format updates. + +New features +^^^^^^^^^^^^ + +- HMAC signing support (:issue:`3075`) + +- Support for ``ParametersSha256DigestComponent`` in ``Name`` and ``Interest`` classes + (:issue:`4658`) + +- Encoding/decoding of ``HopLimit`` field in Interest (:issue:`4806`) + +- PIT token (:issue:`4532`). + + PIT token is a hop-by-hop header field that identifies an Interest-Data exchange. The + downstream node can assign an opaque token to an outgoing Interest, and the upstream node + is expected to return the same token on the Data or Nack in reply to that Interest. This + would allow the downstream node to accelerate its processing, especially in PIT lookup. + +- ``io::loadBuffer`` and ``io::saveBuffer`` helper functions + +Improvements and bug fixes +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Various improvements in the Linux implementation of ``NetworkMonitor`` class + +- Rework of ``RttEstimator`` class: + + * split into two classes: ``RttEstimator`` and ``RttEstimatorWithStats`` (:issue:`4887`) + * add a getter for the smoothed RTT value (:issue:`4892`) + * switch to use ``time::nanoseconds`` (:issue:`4887`) + +- Make use of attributes in logging facilities and generalize logger backend support + (:issue:`4969`, :issue:`3782`) + +- Silently accept an empty validation policy instead of throwing an exception (:issue:`5049`) + +- Introduce alternative URI syntax for component types used in naming conventions, with + ability to choose between canonical and alternate format (:issue:`4777`) + +- Don't force the generation of an Interest nonce during decoding (:issue:`4685`) + +- Various documentation improvements + +Removals +^^^^^^^^ + +- ``ndn::util::Scheduler`` (use ``ndn::Scheduler`` or ``ndn::scheduler::Scheduler``) and + ``ndn::EventId`` (use ``ndn::scheduler::EventId``) (:issue:`4883`) + +- Unused ``KeyClass`` and ``AclType`` enums + +- Unused ``v2::PublicKey`` alias of ``transform::PublicKey`` + +- ``HmacFilter`` class, use SignerFilter and VerifierFilter instead + +- Ill-defined equality operators for ``Interest``, ``MetaInfo``, ``Signature`` (:issue:`4569`) + +- Implicit conversion from the ``xyzHandle`` types to ``const xyzId*`` (where ``xyz`` is + ``PendingInterest``, ``RegisteredPrefixId``, and ``InterestFilterId``) + +- Deprecated ``KeyLocator::Type`` enum + +- Private header files of concrete PIB, TPM, and KeyHandle implementations are no longer + installed (:issue:`4782`) + +- Renamed ``util/backports-ostream-joiner.hpp`` to ``util/ostream-joiner.hpp`` diff --git a/docs/releases.rst b/docs/releases.rst index bee955701..b80eaa2b5 100644 --- a/docs/releases.rst +++ b/docs/releases.rst @@ -1,10 +1,18 @@ -ndn-cxx Versions -++++++++++++++++ +All ndn-cxx Releases +++++++++++++++++++++ .. toctree:: :hidden: :maxdepth: 1 + release-notes/release-notes-0.7.0 + release-notes/release-notes-0.6.6 + release-notes/release-notes-0.6.5 + release-notes/release-notes-0.6.3 + release-notes/release-notes-0.6.2 + release-notes/release-notes-0.6.1 + release-notes/release-notes-0.6.0 + release-notes/release-notes-0.5.1 release-notes/release-notes-0.5.0 release-notes/release-notes-0.4.1 release-notes/release-notes-0.4.0 @@ -16,59 +24,109 @@ ndn-cxx Versions release-notes/release-notes-0.2.0 release-notes/release-notes-0.1.0 +* **ndn-cxx version 0.7.0** + (:doc:`Release Notes `, `Documentation `__) + + `src (git) `__, + `src (tarball) `__ (`checksum `__) + +* **ndn-cxx version 0.6.6** + (:doc:`Release Notes `, `Documentation `__) + + `src (git) `__, + `src (tarball) `__ (`checksum `__) + +* **ndn-cxx version 0.6.5** + (:doc:`Release Notes `, `Documentation `__) + + `src (git) `__, + `src (tarball) `__ (`checksum `__) + +* **ndn-cxx version 0.6.4 was skipped** + +* **ndn-cxx version 0.6.3** + (:doc:`Release Notes `, `Documentation `__) + + `src (git) `__, + `src (tarball) `__ (`checksum `__) + +* **ndn-cxx version 0.6.2** + (:doc:`Release Notes `, `Documentation `__) + + `src (git) `__, + `src (tarball) `__ (`checksum `__) + +* **ndn-cxx version 0.6.1** + (:doc:`Release Notes `, `Documentation `__) + + `src (git) `__, + `src (tarball) `__ (`checksum `__) + +* **ndn-cxx version 0.6.0** + (:doc:`Release Notes `, `Documentation `__) + + `src (git) `__, + `src (tarball) `__ (`checksum `__) + +* **ndn-cxx version 0.5.1** + (:doc:`Release Notes `, `Documentation `__) + + `src (git) `__, + `src (tarball) `__ (`checksum `__) + * **ndn-cxx version 0.5.0** - (:doc:`Release Notes `, `Documentation `__) + (:doc:`Release Notes `, `Documentation `__) `src (git) `__, - `src (tarball) `__ (`checksum `__) + `src (tarball) `__ (`checksum `__) * **ndn-cxx version 0.4.1** - (:doc:`Release Notes `, `Documentation `__) + (:doc:`Release Notes `, `Documentation `__) `src (git) `__, - `src (tarball) `__ (`checksum `__) + `src (tarball) `__ (`checksum `__) * **ndn-cxx version 0.4.0** - (:doc:`Release Notes `, `Documentation `__) + (:doc:`Release Notes `, `Documentation `__) `src (git) `__, - `src (tarball) `__ (`checksum `__) + `src (tarball) `__ (`checksum `__) * **ndn-cxx version 0.3.4** - (:doc:`Release Notes `, `Documentation `__) + (:doc:`Release Notes `, `Documentation `__) `src (git) `__, - `src (tarball) `__ (`checksum `__) + `src (tarball) `__ (`checksum `__) * **ndn-cxx version 0.3.3** - (:doc:`Release Notes `, `Documentation `__) + (:doc:`Release Notes `, `Documentation `__) `src (git) `__, - `src (tarball) `__ (`checksum `__) + `src (tarball) `__ (`checksum `__) * **ndn-cxx version 0.3.2** - (:doc:`Release Notes `, `Documentation `__) + (:doc:`Release Notes `, `Documentation `__) `src (git) `__, - `src (tarball) `__ (`checksum `__) + `src (tarball) `__ (`checksum `__) * **ndn-cxx version 0.3.1** - (:doc:`Release Notes `, `Documentation `__) + (:doc:`Release Notes `, `Documentation `__) `src (git) `__, - `src (tarball) `__ (`checksum `__) + `src (tarball) `__ (`checksum `__) * **ndn-cxx version 0.3.0** - (:doc:`Release Notes `, `Documentation `__) + (:doc:`Release Notes `, `Documentation `__) `src (git) `__, - `src (tarball) `__ (`checksum `__) + `src (tarball) `__ (`checksum `__) * **ndn-cxx version 0.2.0** - (:doc:`Release Notes `, `Documentation `__) + (:doc:`Release Notes `, `Documentation `__) `src (git) `__, - `src (tarball) `__ (`checksum `__) + `src (tarball) `__ (`checksum `__) - ndn-cxx version 0.2.0-rc1 `src (git) `__ @@ -77,10 +135,10 @@ ndn-cxx Versions `src (git) `__ * **ndn-cxx version 0.1.0** - (:doc:`Release Notes `, `Documentation `__) + (:doc:`Release Notes `, `Documentation `__) `src (git) `__, - `src (tarball) `__ (`checksum `__) + `src (tarball) `__ (`checksum `__) - ndn-cxx version 0.1.0-rc1 `src (git) `__ diff --git a/docs/specs.rst b/docs/specs.rst index ca5810b74..65803db1e 100644 --- a/docs/specs.rst +++ b/docs/specs.rst @@ -7,3 +7,4 @@ Specifications specs/signed-interest specs/certificate-format specs/safe-bag + specs/validation-error-code diff --git a/docs/specs/certificate-format.rst b/docs/specs/certificate-format.rst index 5873a1080..f1ec42425 100644 --- a/docs/specs/certificate-format.rst +++ b/docs/specs/certificate-format.rst @@ -1,3 +1,5 @@ +.. _NDN Certificate Format Version 2.0: + NDN Certificate Format Version 2.0 ================================== @@ -11,7 +13,7 @@ the specification of a data packet is not sufficient to be the specification of a common certificate format, as it requires additional components. For example, a certificate may follow a specific naming convention and may need to include validity period, revocation information, etc. This specification defines -naming and components of the NDN certificates and is complementary to NDN packet +naming and structure of the NDN certificates and is complementary to NDN packet specification. :: @@ -24,6 +26,9 @@ specification. |+------------------------+| || ContentType: KEY(2) || |+------------------------+| + |+------------------------+| + || FreshnessPeriod: >~ 1h || + |+------------------------+| +--------------------------+ | Content | |+------------------------+| @@ -42,6 +47,20 @@ specification. +--------------------------+ + CertificateV2 = DATA-TYPE TLV-LENGTH + Name ; //KEY/[KeyId]/[IssuerId]/[Version] + MetaInfo ; ContentType = KEY, FreshnessPeriod required + Content ; X509PublicKey + CertificateV2SignatureInfo + SignatureValue + + CertificateV2SignatureInfo = SIGNATURE-INFO-TYPE TLV-LENGTH + SignatureType + KeyLocator + ValidityPeriod + *CertificateV2Extension + + Name ---- @@ -49,24 +68,29 @@ The name of a certificate consists of five parts as shown below: :: - //[KeyId]/KEY/[IssuerId]/[Version] - -A certificate name starts with the subject to which a public key is bound. The -second part is a single name component, called KeyId, which should uniquely -identify the key under the subject namespace. The value of KeyId is up to -the owner of the subject namespace (e.g., 8-byte random number, SHA-256 digest -of the public key, timestamp, or numerical identifier). A special name -component ``KEY`` is appended after KeyId, which indicates that the data is a -certificate. After ``KEY``, there is an IssuerId name component that -distinguishes different issuers for the same key. How to specify the IssuerId -is up to the issuer and key owner. The last component is version number. + //KEY/[KeyId]/[IssuerId]/[Version] + +A certificate name starts with the subject to which a public key is bound. The following parts +include the keyword ``KEY`` component, KeyId, IssuerId, and version components. + +``KeyId`` is an opaque name component to identify an instance of the public key for the +certificate namespace. The value of `Key ID` is controlled by the namespace owner and can be +an 8-byte random number, SHA-256 digest of the public key, timestamp, or a simple numerical +identifier. + +``Issuer Id`` is an opaque name component to identify issuer of the certificate. The value is +controlled by the certificate issuer and, similar to KeyId, can be an 8-byte random number, +SHA-256 digest of the issuer's public key, or a simple numerical identifier. + + For example, :: - /edu/ucla/cs/yingdi/%03%CD...%F1/KEY/%9F%D3...%B7/%FD%d2...%8E - \_________________/\___________/ \___________/\___________/ - Subject Name Key ID Issuer Id Version + /edu/ucla/cs/yingdi/KEY/%03%CD...%F1/%9F%D3...%B7/%FD%d2...%8E + \_________________/ \___________/ \___________/\___________/ + Certificate Namespace Key Id Issuer Id Version + (Identity) MetaInfo @@ -86,39 +110,25 @@ By default, the content of a certificate is the public key encoded in SignatureInfo ------------- -Besides, ``SignatureType`` and ``KeyLocator``, the ``SignatureInfo`` field of a -certificate include more optional fields. - -:: - - SignatureInfo ::= SIGNATURE-INFO-TYPE TLV-LENGTH - SignatureType - KeyLocator - ValidityPeriod? - ... (SignatureInfo Extension TLVs) - -One optional field is ``ValidityPeriod``, which contains two sub TLV fields: -``NotBefore`` and ``NotAfter``, which are two UTC timestamps in ISO 8601 compact -format (``yyyymmddTHHMMSS``, e.g., "20020131T235959"). NotBefore indicates -when the certificate takes effect while NotAfter indicates when the certificate -expires. +The SignatureInfo block of a certificate is required to include the ``ValidityPeriod`` field. +``ValidityPeriod`` includes two sub TLV fields: ``NotBefore`` and ``NotAfter``, which carry two +UTC timestamps in ISO 8601 compact format (``yyyymmddTHHMMSS``, e.g., "20020131T235959"). +``NotBefore`` indicates when the certificate takes effect while ``NotAfter`` indicates when the +certificate expires. .. note:: - Using ISO style string is the convention of specifying validity period of - certificate, which has been adopted by many certificate systems, such as - X.509, PGP, and DNSSEC. + Using ISO style string is the convention of specifying the validity period of certificate, + which has been adopted by many certificate systems, such as X.509, PGP, and DNSSEC. :: - ValidityPeriod ::= VALIDITY-PERIOD-TYPE TLV-LENGTH - NotBefore - NotAfter + ValidityPeriod = VALIDITY-PERIOD-TYPE TLV-LENGTH + NotBefore + NotAfter - NotBefore ::= NOT-BEFORE-TYPE TLV-LENGTH - BYTE{15} + NotBefore = NOT-BEFORE-TYPE TLV-LENGTH 8DIGIT "T" 6DIGIT - NotAfter ::= NOT-AFTER-TYPE TLV-LENGTH - BYTE{15} + NotAfter = NOT-AFTER-TYPE TLV-LENGTH 8DIGIT "T" 6DIGIT For each TLV, the TLV-TYPE codes are assigned as below: @@ -133,17 +143,13 @@ For each TLV, the TLV-TYPE codes are assigned as below: | NotAfter | 255 | 0xFF | +---------------------------------------------+-------------------+----------------+ -.. note:: - TLV-TYPE code that falls into [253, 65536) is encoded in - `3-byte `__ - Extensions ~~~~~~~~~~ A certificate may optionally carry some extensions in SignatureInfo. An extension -could be either critical or non-critical depends on the TLV-TYPE code convention. An -critical extension implies that if a validator cannot recognize or cannot parse the -extension, the validator must reject the certificate. An non-critical extension +could be either critical or non-critical depends on the TLV-TYPE code convention. A +critical extension implies that if a validator cannot recognize or parse the +extension, the validator must reject the certificate. A non-critical extension implies that if a validator cannot recognize or cannot parse the extension, the validator may ignore the extension. @@ -151,43 +157,20 @@ The TLV-TYPE code range [256, 512) is reserved for extensions. The last bit of TLV-TYPE code indicates whether the extension is critical or not: ``1`` for critical while ``0`` for non-critical. If an extension could be either critical or non-critical, the extension should be allocated with two TLV-TYPE codes which only -differ at the last bit. For example, TLV-TYPE codes 256 and 257 are allocated to the -``StatusChecking`` extension, 256 for critical StatusChecking while 257 for -non-critical StatusChecking. - +differ at the last bit. -Proposed Extensions -------------------- +Extensions +---------- -We list the proposed extensions here: +We list currently defined extensions: +---------------------------------------------+-------------------+----------------+ -| TLV-TYPE | Assigned code | Assigned code | +| TLV-TYPE | Assigned number | Assigned number| | | (decimal) | (hexadecimal) | +=============================================+===================+================+ -| StatusChecking (Non-critical) | 256 | 0x0100 | -+---------------------------------------------+-------------------+----------------+ -| StatusChecking (Critical) | 257 | 0x0101 | -+---------------------------------------------+-------------------+----------------+ -| AdditionalDescription (Non-critical) | 258 | 0x0102 | -+---------------------------------------------+-------------------+----------------+ -| MultipleSignature (Critical) | 259 | 0x0103 | +| AdditionalDescription (non-critical) | 258 | 0x0102 | +---------------------------------------------+-------------------+----------------+ -.. note:: - TLV-TYPE code that falls into [253, 65536) is encoded in - `3-byte `__ - -Status Checking -~~~~~~~~~~~~~~~ - -TBD - -Multiple Signature -~~~~~~~~~~~~~~~~~~ - -TBD - AdditionalDescription ~~~~~~~~~~~~~~~~~~~~~ @@ -199,21 +182,21 @@ key-value pair to provide additional description about the certificate. :: - AdditionalDescription ::= ADDITIONAL-DESCRIPTION-TYPE TLV-LENGTH - DescriptionEntry+ + CertificateV2Extension = AdditionalDescription + + AdditionalDescription = ADDITIONAL-DESCRIPTION-TYPE TLV-LENGTH + 1*DescriptionEntry - DescriptionEntry ::= DESCRIPTION-ENTRY-TYPE TLV-LENGTH - DescriptionKey - DescriptionValue + DescriptionEntry = DESCRIPTION-ENTRY-TYPE TLV-LENGTH + DescriptionKey + DescriptionValue - DescriptionKey ::= DESCRIPTION-KEY-TYPE TLV-LENGTH - BYTE+ + DescriptionKey = DESCRIPTION-KEY-TYPE TLV-LENGTH 1*OCTET - DescriptionValue ::= DESCRIPTION-VALUE-TYPE TLV-LENGTH - BYTE+ + DescriptionValue = DESCRIPTION-VALUE-TYPE TLV-LENGTH 1*OCTET +---------------------------------------------+-------------------+----------------+ -| TLV-TYPE | Assigned code | Assigned code | +| TLV-TYPE | Assigned number | Assigned number| | | (decimal) | (hexadecimal) | +=============================================+===================+================+ | DescriptionEntry | 512 | 0x0200 | diff --git a/docs/specs/safe-bag.rst b/docs/specs/safe-bag.rst index 2542f8dbf..fcb62118a 100644 --- a/docs/specs/safe-bag.rst +++ b/docs/specs/safe-bag.rst @@ -11,14 +11,17 @@ The format of **SafeBag** is defined as: :: - SafeBag ::= SAFE-BAG-TYPE TLV-LENGTH - Certificate ; a data packet following certificate format spec - EncryptedKeyBag ; private key encrypted in PKCS#8 format + SafeBag = SAFE-BAG-TYPE TLV-LENGTH + CertificateV2 ; a data packet following certificate format spec + EncryptedKeyBag + + EncryptedKeyBag = ENCRYPTED-KEY-BAG-TYPE TLV-LENGTH + *OCTET ; private key encrypted in PKCS#8 format All TLV-TYPE codes are application specific: +---------------------------------------------+-------------------+----------------+ -| TLV-TYPE | Assigned code | Assigned code | +| TLV-TYPE | Assigned number | Assigned number| | | (decimal) | (hexadecimal) | +=============================================+===================+================+ | SafeBag | 128 | 0x80 | diff --git a/docs/specs/signed-interest.rst b/docs/specs/signed-interest.rst index 093797ad8..2319e5aa6 100644 --- a/docs/specs/signed-interest.rst +++ b/docs/specs/signed-interest.rst @@ -1,3 +1,5 @@ +.. _Signed Interest: + Signed Interest =============== diff --git a/docs/specs/validation-error-code.rst b/docs/specs/validation-error-code.rst new file mode 100644 index 000000000..4610cd455 --- /dev/null +++ b/docs/specs/validation-error-code.rst @@ -0,0 +1,33 @@ +Validation Error Code +===================== + +The following table defines a list of known codes and their description, which can be returned from the :ndn-cxx:`v2::Validator` interface. +Other error codes can be returned by validator implementations outside ndn-cxx codebase. + ++------------+--------------------------+-----------------------------------------------------+ +| Error code | Short ID | Description | ++============+==========================+=====================================================+ +| 0 | NO_ERROR | No error | ++------------+--------------------------+-----------------------------------------------------+ +| 1 | INVALID_SIGNATURE | Invalid signature | ++------------+--------------------------+-----------------------------------------------------+ +| 2 | NO_SIGNATURE | Missing signature | ++------------+--------------------------+-----------------------------------------------------+ +| 3 | CANNOT_RETRIEVE_CERT | Cannot retrieve certificate | ++------------+--------------------------+-----------------------------------------------------+ +| 4 | EXPIRED_CERT | Certificate expired | ++------------+--------------------------+-----------------------------------------------------+ +| 5 | LOOP_DETECTED | Loop detected in certification chain | ++------------+--------------------------+-----------------------------------------------------+ +| 6 | MALFORMED_CERT | Malformed certificate | ++------------+--------------------------+-----------------------------------------------------+ +| 7 | EXCEEDED_DEPTH_LIMIT | Exceeded validation depth limit | ++------------+--------------------------+-----------------------------------------------------+ +| 8 | INVALID_KEY_LOCATOR | Key locator violates validation policy | ++------------+--------------------------+-----------------------------------------------------+ +| .. | ... | ... | ++------------+--------------------------+-----------------------------------------------------+ +| 255 | IMPLEMENTATION_ERROR | Internal implementation error | ++------------+--------------------------+-----------------------------------------------------+ + +Specialized validator implementations can use error codes >= 256 to indicate a specialized error. diff --git a/docs/tutorials.rst b/docs/tutorials.rst index c3c1ca143..0edb3c274 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -4,6 +4,5 @@ Tutorials .. toctree:: :maxdepth: 2 - tutorials/security-library tutorials/utils-ndn-regex tutorials/security-validator-config diff --git a/docs/tutorials/security-library.rst b/docs/tutorials/security-library.rst deleted file mode 100644 index 8ee8d40c8..000000000 --- a/docs/tutorials/security-library.rst +++ /dev/null @@ -1,359 +0,0 @@ -Security Library Tutorial -========================= - -.. contents:: - -Identity, Key and Certificates ------------------------------- - -All keys, certificates and their corresponding identities are managed by :ndn-cxx:`KeyChain`. - -An real world **identity** can be expressed by a namespace. (e.g., -``/ndn/edu/ucla/alice``, or ``/ndn/edu/ucla/BoelterHall/4805``). - -**Keys** belonging to an identity are named under the identity's namespace, with a unique -**KeyId**:: - - //[KeyId] - -For now, only two types of KeyId are specified: ``ksk-[timestamp]`` and -``dsk-[timestamp]``. The first type of KeyId is used to denote Key-Signing-Key (KSK) -which is supposed to have a long lifetime. The second type of KeyId is used to denote -Data-Signing-Key (DSK) which is supposed to have a short lifetime. Both types of KeyId -use timestamps (number of milliseconds since unix epoch) to provide relative uniqueness of -key names. Replacing timestamp with key hash can bring stronger uniqueness but on the -cost of longer name. Therefore, key hash is not used for now. For example, -``/ndn/edu/ucla/alice/ksk-1234567890`` or -``/ndn/edu/ucla/BoelterHall/4805/dsk-1357924680``. - -An identity may have more than one keys associated with it. For example, one may have a -KSK to sign other keys and a DSK to sign data packets, or one may periodically replace its -expired DSK/KSK with a new key. - -The private part of a key ("private key"), is stored in a :ndn-cxx:`Trusted Platform -Module (TPM) `. The public part ("public key"), is managed in a -:ndn-cxx:`Public-key Information Base (PIB) `. The most important -information managed by PIB is **certificates** of public keys. A certificate binds a -public key to its key name or the corresponding identity. The signer (or issuer) of a -certificate vouches for the binding through its own signature. With different signers -vouching for the binding, a public key may have more than one certificates. - -The certificate name follows the naming convention of `NDNS (NDN Domain Name Service) `_. The -public key name will be broken into two parts: - -- The first part ("authoritative namespace") will be put before a name component ``KEY`` - which serves as an application tag -- The second part ("label") will be put between ``KEY`` and ``ID-CERT`` which serves as an - indicator of certificate. - -A version number of the certificate is appended after ``ID-CERT``. For example, -``/ndn/edu/ucla/KEY/alice/ksk-1234567890/ID-CERT/%FD%01`` or -``/ndn/edu/ucla/BoelterHall/4805/KEY/dsk-1357924680/ID-CERT/%FD%44``. - -The :ndn-cxx:`NDN certificate ` is just an ordinary `NDN-TLV Data -packet `_, with the content part in DER -encoding that resembles X.509 certificate: - -.. code-block:: cpp - - // NDN-TLV Encoding - Certificate ::= DATA-TLV TLV-LENGTH - Name - MetaInfo (= CertificateMetaInfo) - Content (= CertificateContent) - Signature - - CertificateMetaInfo ::= META-INFO-TYPE TLV-LENGTH - ContentType (= KEY) - FreshnessPeriod (= ?) - - - CertificateContent ::= CONTENT-TYPE TLV-LENGTH - CertificateDerPayload - - - // DER Encoding - CertificateDerPayload ::= SEQUENCE { - validity Validity, - subject Name, - subjectPubKeyInfo SubjectPublicKeyInfo, - extension Extensions OPTIONAL } - - Validity ::= SEQUENCE { - notBefore Time, - notAfter Time } - - Time ::= CHOICE { - GeneralizedTime } - - Name ::= CHOICE { - RDNSequence } - - RDNSequence ::= SEQUENCE OF RelativeDistinguishedName - - RelativeDistinguishedName ::= - SET OF AttributeTypeAndValue - - SubjectPublicKeyInfo ::= SEQUENCE { - algorithm AlgorithmIdentifier - keybits BIT STRING } - - Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension - -See `RFC 3280 `_ for more details about DER field -definitions. - -Signing -------- - -Key Management -%%%%%%%%%%%%%% - -Create Identity/Keys/Certificate -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The simplest way to initialize an identity and its key and certificate is to call -:ndn-cxx:`KeyChain::createIdentity` - -.. code-block:: cpp - - KeyChain keyChain; - Name defaultCertName = keyChain.createIdentity(identity); - -This method guarantees that the default key and certificate of the supplied identity -always exist in the KeyChain. This method checks if the supplied identity has already had -a default key and a default certificate and returns the default certificate name if -exists. If the default certificate is missing, KeyChain will automatically create a -self-signed certificate of the default key. If the default key is missing, KeyChain will -automatically create a new key and set it as the default key and create a self-signed -certificate as well. - -Create Keys Manually -~~~~~~~~~~~~~~~~~~~~ - -One can call :ndn-cxx:`KeyChain::generateRsaKeyPair` to generate an RSA key pair or -:ndn-cxx:`KeyChain::generateEcdsaKeyPair` to generate an ECDSA key. Note that generated -key pair is not set as the default key of the identity, so you need to set it manually by -calling :ndn-cxx:`KeyChain::setDefaultKeyNameForIdentity`. There is also a helper method -:ndn-cxx:`KeyChain::generateRsaKeyPairAsDefault`, which combines the two steps into one. - -.. code-block:: cpp - - KeyChain keyChain; - Name alice("/ndn/test/alice"); - - Name aliceKeyName = keyChain.generateRsaKeyPair(alice); - keyChain.setDefaultKeyNameForIdentity(aliceKeyName); - - // Now the key with the name aliceKeyName2 becomes alice's default key - Name aliceKeyName2 = keyChain.generateRsaKeyPairAsDefault(alice); - -Create Identity Certificate Manually -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you have created a key pair, you can generate a self-signed certificate for the key by -calling :ndn-cxx:`KeyChain::selfSign`. - -.. code-block:: cpp - - KeyChain keyChain; - Name aliceKeyName("/ndn/test/alice/ksk-1394129695025"); - - shared_ptr aliceCert = keyChain.selfSign(aliceKeyName); - -You can sign a public key using a different key: - -.. code-block:: cpp - - KeyChain keyChain; - - shared_ptr certificate = - keyChain.prepareUnsignedIdentityCertificate(publicKeyName, publicKey, - signingIdentity, - notBefore, notAfter, - subjectDescription, prefix - - keyChain.signByIdentity(*certificate, signingIdentity); - -Signing Data -%%%%%%%%%%%% - -Although the security library does not have the intelligence to automatically determine -the signing key for each data packet, it still provides a mechanism, called **Default -Signing Settings**, to facilitate signing process. - -The basic signing process in the security library would be like this: create :ndn-cxx:`KeyChain` -instance and supply the data packet and signing certificate name to :ndn-cxx:`KeyChain::sign` -method. - -.. code-block:: cpp - - KeyChain keyChain; - keyChain.sign(dataPacket, signingCertificateName); - -The :ndn-cxx:`KeyChain` instance will - -- construct ``SignatureInfo`` using the signing certificate name; -- look up the corresponding private key in :ndn-cxx:`TPM `; -- sign the data packet if the private key exists. - -The basic process, however, requires application developers to supply the exact -certificate name. Such a process has two shortages: first, it might be difficult to -remember the certificate name; second, application developers have to be aware of -certificate update and key roll-over. Therefore, the security library provides another -signing process in which application developers only need to supply the signing identity: - -.. code-block:: cpp - - KeyChain keyChain; - keyChain.signByIdentity(dataPacket, signingIdentity); - -The :ndn-cxx:`KeyChain` instance will - -- determine the default key of the signing identity; -- determine the default certificate of the key; -- construct ``SignatureInfo`` using the default certificate name; -- look up the corresponding private key in :ndn-cxx:`TPM `; -- sign the data packet if the private key exists. - -The process above requires that each identity has a default key and that each key has a -default certificate. All these default settings is managed in :ndn-cxx:`PIB -`, one can get/set these default settings through :ndn-cxx:`KeyChain` -directly: - -.. code-block:: cpp - - KeyChain keyChain; - Name defaultKeyName = keyChain.getDefaultKeyNameForIdentity(identity); - Name defaultCertName = keyChain.getDefaultCertificateNameForKey(keyName); - - keyChain.setDefaultKeyNameForIdentity(keyName); - keyChain.setDefaultCertificateNameForKey(certificateName); - -There is even a default identity which will be used when no identity information is -supplied in signing method: - -.. code-block:: cpp - - KeyChain keyChain; - keyChain.sign(dataPacket); - -And default identity can be got/set through :ndn-cxx:`KeyChain` as well: - -.. code-block:: cpp - - KeyChain keyChain; - Name defaultIdentity = keyChain.getDefaultIdentity(); - keyChain.setDefaultIdentity(identity); - - -Signing Interests -%%%%%%%%%%%%%%%%% - -The process of signing Interests according to the :doc:`Signed Interest specification -<../specs/signed-interest>` is exactly the same as the process of signing Data packets: - -.. code-block:: cpp - - KeyChain keyChain; - - keyChain.sign(interest, signingCertName); - keyChain.signByIdentity(interest, signingIdentity); - keyChain.sign(interest); - -Validation ----------- - -Interest and Data validation is done through a **Validator**. :ndn-cxx:`Validator` is a virtual -class, two pure virtual methods must be implemented in order to construct a working -validator: - -.. code-block:: cpp - - class Validator - { - ... - protected: - virtual void - checkPolicy(const Data& data, - int nSteps, - const OnDataValidated& onValidated, - const OnDataValidationFailed& onValidationFailed, - std::vector >& nextSteps) = 0; - - virtual void - checkPolicy(const Interest& interest, - int nSteps, - const OnInterestValidated& onValidated, - const OnInterestValidationFailed& onValidationFailed, - std::vector >& nextSteps) = 0; - ... - }; - -What should be implemented in these two methods is to check: - -- whether the packet and signer comply with trust policies; -- whether their signature can be verified. - -If the packet can be validated, the ``onValidated`` callback should be invoked, otherwise -the ``onValidationFailed`` callback should be invoked. If more information (e.g., other -certificates) is needed, express the request for missing information in one or more -``ValidationRequest`` and push them into ``nextSteps``. - -.. code-block:: cpp - - class ValidationRequest - { - public: - Interest m_interest; // The Interest for the requested data/certificate. - OnDataValidated m_onValidated; // Callback when the retrieved certificate is authenticated. - OnDataValidationFailed m_onDataValidated; // Callback when the retrieved certificate cannot be authenticated. - int m_nRetries; // The number of retries when the interest times out. - int m_nStep; // The number of validation steps that have been performed. - }; - -Besides the two ``Validator::checkPolicy`` methods, the ``Validator`` also provides three -hooks to control packet validation in a finer granularity. - -.. code-block:: cpp - - class Validator - { - ... - protected: - virtual shared_ptr - preCertificateValidation(const Data& data); - - virtual void - onTimeout(const Interest& interest, - int nRemainingRetries, - const OnFailure& onFailure, - const shared_ptr& validationRequest); - - virtual void - afterCheckPolicy(const std::vector >& nextSteps, - const OnFailure& onFailure); - ... - }; - -``Validator::preCertificateValidation`` is triggered before validating requested -certificate. The Data supplied matches the interest in the ``ValidationRequest``. It may -be certificate or a data encapsulating certificate. This hook returns a data (actually -certificate) that is will be passed as Data into ``Validator::validate``; - -``Validator::onTimeout`` is triggered when interest for certificate times out. The logic -to handle the timeout can be implemented in this hook. One could invoke onFailure or -re-express the interest. - -``Validator::afterCheckPolicy`` is invoked after ``Validator::checkPolicy`` is done. One -can implement the logic of how to process the set of ValidationRequests according to its -trust model. - -Configuration-based Validator -%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -In most cases, the trust model of applications are simple. However, it is not trivial to -implement the two ``Validator::checkPolicy`` methods. Therefore, we provide a more -developer-friendly configuration-based validator, ``ValidatorConfig``. With -``ValidatorConfig``, one can express the trust model using a policy language in a -configuration file. See :doc:`security-validator-config` for more details. diff --git a/docs/tutorials/security-validator-config.rst b/docs/tutorials/security-validator-config.rst index 9df002002..fcd49dc0d 100644 --- a/docs/tutorials/security-validator-config.rst +++ b/docs/tutorials/security-validator-config.rst @@ -9,7 +9,7 @@ write a configuration file. The configuration file consists of **rules** and **trust-anchors** that will be used in validation. **Rules** tell the validator how to validate a packet, while **trust-anchors** tell the validator which certificates are valid immediately. Here is an example of -configuration file containing two rules. +configuration file containing two rules and a trust anchor. :: @@ -30,7 +30,7 @@ configuration file containing two rules. key-locator { type name - name /ndn/edu/ucla/KEY/yingdi/ksk-1234/ID-CERT + name /ndn/edu/ucla/yingdi/KEY/1234 relation equal } } @@ -61,64 +61,73 @@ A rule can be broken into two parts: - The second part is to check whether further validation process is necessary. -When receiving a packet, the validator will apply rules in the configuration file -one-by-one against the packet, until finding a rule that the packet qualifies for. And the -second part of the matched rule will be used to check the validity of the packet. If the -packet cannot qualify for any rules, it is treated as an invalid packet. Once a packet has -been matched by a rule, the rest rules will not be applied against the packet. Therefore, -you should always put the most specific rule to the top, otherwise it will become useless. +When a packet is presented for validation, the validator will check the rules one-by-one +in the configuration file using **for** and **filter** conditions against the packet, +until finding a rule for which the packet qualifies. After that, the **checker** +conditions of the matched rule will be used to check the validity of the packet. If the +packet does not match any rules, it is treated as an invalid packet. Once a packet has +been matched by a rule, the remaining rules are not applied to the packet (i.e., the +matched rule "captures" the packet). Therefore, you should always put the most specific +rule first. In the example configuration, the first rule indicates that all the data packets under the -name prefix ``/localhost/example`` must be signed by a key whose certificate name is -``/ndn/edu/ucla/KEY/yingdi/ksk-1234/ID-CERT``. If a packet does not have a name under prefix -``/localhost/example``, validator will skip the first rule and apply the second rule. The -second rule indicates that any data packets must be validated along a hierarchy. And a -certificate stored in a file "testbed-trust-anchor.cert" is valid. +name prefix ``/localhost/example`` must be signed by a certificate whose name (the key +part) is ``/ndn/edu/ucla/yingdi/KEY/1234``. If a packet does not have a name under +prefix ``/localhost/example``, the validator will skip the first rule and apply the second +rule. The second rule indicates that all other data packets must be validated using the +hierarchical policy (data name should be prefix or equal to the identity part of the +certificate name). The example configuration defines that all certificate chains must be +rooted in the certificate defined in the file "testbed-trust-anchor.cert". Rules in general ---------------- -A rule has four types of properties: **id**, **for**, **filter**, and **checker**. +A rule has four properties: **id**, **for**, **filter**, and **checker**. -The property **id** uniquely identifies the rule in the configuration file. As long as +The **id** property uniquely identifies the rule in the configuration file. As long as being unique, any name can be given to a rule, e.g., "Simple Rule", "Testbed Validation Rule". A rule must have one and only one **id** property. -A rule is either used to validate an interest packet or a data packet. This information -is specified in the property **for**. Only two value can be specified: **data** and -**interest**. A rule must have one and only one **for** property. +A rule is either used to validate a data packet or an interest packet. This information +is specified in the **for** property, which can be either **data** or **interest**. A +rule must have exactly one **for** property. -The property **filter** further constrains the packets that can be checked by the -rule. Filter property is not required in a rule, in this case, the rule will capture all -the packets passed to it. A rule may contain more than one filters, in this case, a packet -can be checked by a rule only if the packet satisfies all the filters. +The **filter** property further constrains the packets that can be checked by the +rule. The filter property is not required in a rule; if omitted, the rule will capture all +packets passed to it. A rule may contain multiple filters, in this case, a packet +is captured by the rule only if all filters are satisfied. .. note:: **ATTENTION: A packet that satisfies all the filters may not be valid**. -The property **checker** defines the conditions that a matched packet must fulfill to be +The **checker** property defines the conditions that a matched packet must fulfill to be treated as a valid packet. A rule must have at least one **checker** property. A packet is treated as valid if it can pass at least one of the checkers and as invalid when it cannot pass any checkers. -**filter** and **checker** have their own properties. Next, we will introduce them -separately. - Filter Property --------------- -Filter has its own **type** property. Although a rule may contain more than one filters, -there is at most one filter of each type. So far, only one type of filter is defined: -**name**. In other word, only one filter can be specified in a rule for now. +Filter has a **type** property and type-specific properties. Although a rule can contain +more than one filters, there can be at most one filter of each type. + +Currently, only the packet name filter is defined. Name Filter ~~~~~~~~~~~ -There are two ways to express the conditions on name. The first way is to specify a -relationship between the packet name and a particular name. In this case, two more -properties are required: **name** and **relation**. A packet can fulfill the condition if -the **name** has a **relation\* to the packet name. Three types of **\ relation\*\* has -been defined: **equal**, **is-prefix-of**, **is-strict-prefix-of**. For example, a filter +There are two ways to express the conditions on packet name: + +- relationship between the packet name and the specified name +- :doc:`NDN regular expression ` match. + +Name and Relation +^^^^^^^^^^^^^^^^^ + +In the first case, two more properties are required: **name** and **relation**. A packet +can fulfill the condition if the **name** has a **relation** to the packet's name. Three +types of **relation** has been defined: **equal**, **is-prefix-of**, +**is-strict-prefix-of**. For example, the filter :: @@ -129,8 +138,9 @@ been defined: **equal**, **is-prefix-of**, **is-strict-prefix-of**. For example, relation equal } -shall only capture a packet with the exact name ``/localhost/example``. -And a filter +will capture only a packet with the exact name ``/localhost/example``. + +The filter :: @@ -141,8 +151,8 @@ And a filter relation is-prefix-of } -shall capture a packet with name ``/localhost/example`` or ``/localhost/example/data``, but -cannot catch a packet with name ``/localhost/another_example``. And a filter +will capture a packet with name ``/localhost/example`` or ``/localhost/example/data``, but +will not capture a packet with name ``/localhost/another_example``. And the filter :: @@ -153,42 +163,46 @@ cannot catch a packet with name ``/localhost/another_example``. And a filter relation is-strict-prefix-of } -shall capture a packet with name ``/localhost/example/data``, but cannot catch a packet +will capture a packet with name ``/localhost/example/data``, but will not capture a packet with name ``/localhost/example``. +NDN Regular Expression Match +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + The second way is to specify an :doc:`utils-ndn-regex` that can match the packet. In this -case, only one property **regex** is required. For example, a filter +case, only one property **regex** is required. For example, the filter :: filter { type name - regex ^[^]*<>*$ + regex ^<>*<><><>$ } -shall capture all the identity certificates. +will capture all certificates. Checker Property ---------------- Passing all the filters in a rule only indicates that a packet can be checked using the -rule, and it does not necessarily implies that the packet is valid. The validity of a +rule, and it does not necessarily imply that the packet is valid. The validity of a packet is determined by the property **checker**, which defines the conditions that a valid packet must fulfill. -Same as **filter**, **checker** has a property **type**. We have defined three types of -checkers: **customized**, and **hierarchical**, and **fixed-signer**. As suggested by its -name, **customized** checker allows you to customize the conditions according to specific -requirements. **hierarchical** checker and **fixed-signer** checker are pre-defined -shortcuts, which specify specific trust models separately. +Same as **filter**, **checker** has a property **type**. We have defined two types of +checkers: + +- **customized** is a checker that allows customization of the conditions according to specific + requirements; + +- **hierarchical** is a checker with pre-defined hierarchical trust model. Customized Checker ~~~~~~~~~~~~~~~~~~ -So far, we only allow three customized properties in a customized -checker: **sig-type**, **key-locator**. All of them are related to the -``SignatureInfo`` of a packet. +The customized checker requires two properties: **sig-type**, **key-locator**. Both must +appear exactly once and are related to the ``SignatureInfo`` of a packet. :: @@ -202,18 +216,16 @@ checker: **sig-type**, **key-locator**. All of them are related to the } } -The property **sig-type** specifies the acceptable signature type. Right now three -signature types have been defined: **rsa-sha256** and **ecdsa-sha256** (which are strong -signature types) and **sha256** (which is a weak signature type). If sig-type is sha256, -then **key-locator** will be ignored. Validator will simply calculate the digest of a -packet and compare it with the one in ``SignatureValue``. If sig-type is rsa-sha256 or -ecdsa-sha256, you have to further customize the checker with **key-locator**. +The property **sig-type** specifies the acceptable signature type and can be +**rsa-sha256**, **ecdsa-sha256** (strong signature types), or **sha256** (weak signature +type). If sig-type is sha256, **key-locator** is ignored, and the validator will simply +calculate the digest of a packet and compare it with the one in ``SignatureValue``. If +sig-type is rsa-sha256 or ecdsa-sha256, you have to further customize the checker with +**key-locator**. -The property **key-locator** which specifies the conditions on ``KeyLocator``. If the +The property **key-locator** specifies the conditions on ``KeyLocator``. If the **key-locator** property is specified, it requires the existence of the ``KeyLocator`` -field in ``SignatureInfo``. Although there are more than one types of ``KeyLocator`` -defined in the `Packet Format `__, -**key-locator** property only supports one type: **name**: +field in ``SignatureInfo``. **key-locator** property only supports one type: **name**: :: @@ -223,9 +235,9 @@ defined in the `Packet Format ... } -Such a key-locator property specifies the conditions on the certificate name of the -signing key. Since the conditions are about name, they can be specified in the same way as -the name filter. For example, a checker could be: +This key-locator property specifies the conditions on the certificate name of the signing +key. Since the conditions are about name, they can be specified in the same way as the +name filter. For example, a checker can be: :: @@ -236,23 +248,23 @@ the name filter. For example, a checker could be: key-locator { type name - name /ndn/edu/ucla/KEY/yingdi/ksk-1234/ID-CERT + name /ndn/edu/ucla/yingdi/KEY/1234 relation equal } } -This checker property requires that the packet must have a ``rsa-sha256`` signature generated -by a key whose certificate name is ``/ndn/edu/ucla/KEY/yingdi/ksk-1234/ID-CERT``. +This checker property requires that the packet must have a ``rsa-sha256`` signature that +can be verified with ``/ndn/edu/ucla/yingdi/KEY/1234`` key. Besides the two ways to express conditions on the ``KeyLocator`` name (name and regex), you can further constrain the ``KeyLocator`` name using the information extracted from the packet name. This third type of condition is expressed via a property **hyper-relation**. The **hyper-relation** property consists of three parts: -- an NDN regular expression that can extract information from packet name -- an NDN regular expression that can extract information from ``KeyLocator`` name -- relation from the part extracted from ``KeyLocator`` name to the one extracted from the - packet name +- an NDN regular expression that extracts information from the packet name +- an NDN regular expression that extracts information from the ``KeyLocator`` name +- relation from the part extracted from the ``KeyLocator`` name to the one extracted from + the packet name For example, a checker: @@ -267,8 +279,8 @@ For example, a checker: type name hyper-relation { - k-regex ^([^]*)(<>*)$ - k-expand \\1\\2 + k-regex ^(<>*)<>$ + k-expand \\1 h-relation is-prefix-of p-regex ^(<>*)$ p-expand \\1 @@ -277,30 +289,8 @@ For example, a checker: } } -requires the packet name must be under the corresponding namespace of the ``KeyLocator`` -name. - -In some cases, you can even customize checker with another property For example: - -:: - - checker - { - type customized - sig-type rsa-sha256 - key-locator - { - type name - hyper-relation - { - k-regex ^([^]*)(<>*)$ - k-expand \\1\\2 - h-relation is-prefix-of - p-regex ^(<>*)$ - p-expand \\1 - } - } - } +requires the packet name must be under the corresponding namespace (identity part) of the +``KeyLocator`` name. Hierarchical Checker ~~~~~~~~~~~~~~~~~~~~ @@ -329,8 +319,8 @@ is equivalent to a customized checker: type name hyper-relation { - k-regex ^([^]*)(<>*)$ - k-expand \\1\\2 + k-regex ^(<>*)<>$ + k-expand \\1 h-relation is-prefix-of p-regex ^(<>*)$ p-expand \\1 @@ -338,42 +328,14 @@ is equivalent to a customized checker: } } -Fixed-Signer Checker -~~~~~~~~~~~~~~~~~~~~ - -In some cases, you only accept packets signed with pre-trusted certificates, -i.e. "one-step validation". Such a trust model can be expressed with **fixed-signer** -checker. And you only need to specify the trusted certificate via property **signer**. The -definition of **signer** is the same as **trust-anchor**. For example: - -:: - - checker - { - type fixed-signer - sig-type rsa-sha256 - signer - { - type file - file-name "trusted-signer.cert" - } - signer - { - type base64 - base64-string "Bv0DGwdG...amHFvHIMDw==" - } - } - .. _validator-conf-trust-anchors: Trust Anchors ------------- -Although **trust-anchor** is always not required in the configuration file (for example, -if fixed-signer checker is used), it is very common to have a few trust-anchors in the -configuration file, otherwise most packets cannot be validated. A configuration file may -contain more than one trust anchors, but the order of trust anchors does not matter. The -structure of trust-anchor is same as the **signer** in fixed-signer checker, for example: +**trust-anchor** is a necessary option in order to properly validate packets. A +configuration file may contain more than one trust anchors and the order of trust anchors +does not matter. The structure of trust-anchor is as follows: :: @@ -389,7 +351,7 @@ structure of trust-anchor is same as the **signer** in fixed-signer checker, for } You may also specify a trust-anchor directory. All certificates under this directory are -taken as trust anchors. For example, if all trust anchors are put into +taken as static trust anchors. For example, if all trust anchors are put into ``/usr/local/etc/ndn/keys``. :: @@ -397,7 +359,7 @@ taken as trust anchors. For example, if all trust anchors are put into trust-anchor { type dir - file-name /usr/local/etc/ndn/keys + dir /usr/local/etc/ndn/keys } If certificates under the directory might be changed during runtime, you can set a refresh @@ -408,11 +370,11 @@ period, such as trust-anchor { type dir - file-name /usr/local/etc/ndn/keys + dir /usr/local/etc/ndn/keys refresh 1h ; refresh certificates every hour, other units include m (for minutes) and s (for seconds) } -There is another special trust anchor **any**. As long as such a trust-anchor is defined +There is also a special trust anchor **any**. As long as such a trust-anchor is defined in config file, packet validation will be turned off. .. note:: @@ -458,31 +420,31 @@ example: | | | | | Identity example: ``/ndn`` | | | | -| | Certificate name example: ``/ndn/KEY/ksk-1/ID-CERT/%01`` | +| | Certificate name example: ``/ndn/KEY/1/%00/%01`` | +------------+-------------------------------------------------------------------------------------+ | site | ``//`` | | | | | | Identity example: ``/ndn/edu/ucla`` | | | | -| | Certificate name example: ``/ndn/edu/ucla/KEY/ksk-2/ID-CERT/%01`` | +| | Certificate name example: ``/ndn/edu/ucla/KEY/2/%00/%01`` | +------------+-------------------------------------------------------------------------------------+ | operator | ``///%C1.O.N./`` | | | | | | Identity example: ``/ndn/edu/ucla/%C1.O.N./op1`` | | | | -| | Certificate name example: ``/ndn/edu/ucla/%C1.O.N./op1/KEY/ksk-3/ID-CERT/%01`` | +| | Certificate name example: ``/ndn/edu/ucla/%C1.O.N./op1/KEY/3/%00/%01`` | +------------+-------------------------------------------------------------------------------------+ | router | ``///%C1.O.R./`` | | | | | | Identity example: ``/ndn/edu/ucla/%C1.O.R./rt1`` | | | | -| | Certificate name example: ``/ndn/edu/ucla/%C1.O.R./rt1/KEY/ksk-4/ID-CERT/%01`` | +| | Certificate name example: ``/ndn/edu/ucla/%C1.O.R./rt1/KEY/4/%00/%01`` | +------------+-------------------------------------------------------------------------------------+ | NLSR | ``///%C1.O.R.//NLSR`` | | | | | | Identity example: ``/ndn/edu/ucla/%C1.O.R./rt1/NLSR`` | | | | -| | Certificate name example: ``/ndn/edu/ucla/%C1.O.R./rt1/NLSR/KEY/ksk-5/ID-CERT/%01`` | +| | Certificate name example: ``/ndn/edu/ucla/%C1.O.R./rt1/NLSR/KEY/5/%00/%01`` | +------------+-------------------------------------------------------------------------------------+ Assume that a typical NLSR data name is @@ -507,7 +469,7 @@ And here is the configuration file: filter { type name - regex ^[^]* + regex ^<>*<><>$ } checker { @@ -518,10 +480,10 @@ And here is the configuration file: type name hyper-relation { - k-regex ^([^]*)$ + k-regex ^(<>*)<>$ k-expand \\1 h-relation equal - p-regex ^([^]*)<>$ + p-regex ^(<>*)<><>$ p-expand \\1 } } @@ -534,7 +496,7 @@ And here is the configuration file: filter { type name - regex ^[^<%C1.O.R.>]*<%C1.O.R.><><>$ + regex ^<>*<%C1.O.R.><><><><>$ } checker { @@ -545,10 +507,10 @@ And here is the configuration file: type name hyper-relation { - k-regex ^([^<%C1.O.N.>]*)<%C1.O.N.><>$ + k-regex ^(<>*)<%C1.O.N.><><>$ k-expand \\1 h-relation equal - p-regex ^([^<%C1.O.R.>]*)<%C1.O.R.><><>$ + p-regex ^(<>*)<%C1.O.R.><><><><>$ p-expand \\1 } } @@ -561,7 +523,7 @@ And here is the configuration file: filter { type name - regex ^[^]*<>$ + regex ^<>*<><><>$ } checker { @@ -584,43 +546,63 @@ written as: :: - rule - { - id "NRD Prefix Registration Command Rule" - for interest - filter - { - type name - regex ^[] - } - checker - { - type customized - sig-type rsa-sha256 - key-locator - { - type name - regex ^[^]*<>*$ - } - } - } - rule - { - id "Testbed Hierarchy Rule" - for data - filter - { - type name - regex ^[^]*<>*<>$ - } - checker - { - type hierarchical - sig-type rsa-sha256 - } - } - trust-anchor - { - type file - file-name "testbed-trust-anchor.cert" - } + rule + { + id "RIB Prefix Registration Command Rule" + for interest ; rule for Interests (to validate CommandInterests) + filter + { + type name ; condition on interest name (w/o signature) + regex ^[][]<><><>$ ; prefix before + ; SigInfo & SigValue + } + checker + { + type customized + sig-type rsa-sha256 ; interest must have a rsa-sha256 signature + key-locator + { + type name ; key locator must be the certificate name of the + ; signing key + regex ^<>*<><><>$ + } + } + checker + { + type customized + sig-type ecdsa-sha256 ; interest must have a ecdsa-sha256 signature + key-locator + { + type name ; key locator must be the certificate name of the + ; signing key + regex ^<>*<><><>$ + } + } + } + rule + { + id "NDN Testbed Hierarchy Rule" + for data ; rule for Data (to validate NDN certificates) + filter + { + type name ; condition on data name + regex ^<>*<><><>$ + } + checker + { + type hierarchical ; the certificate name of the signing key and + ; the data name must follow the hierarchical model + sig-type rsa-sha256 ; data must have a rsa-sha256 signature + } + checker + { + type hierarchical ; the certificate name of the signing key and + ; the data name must follow the hierarchical model + sig-type ecdsa-sha256 ; data must have a ecdsa-sha256 signature + } + } + trust-anchor + { + type file + file-name keys/ndn-testbed-root.ndncert.base64 + } diff --git a/docs/tutorials/utils-ndn-regex.rst b/docs/tutorials/utils-ndn-regex.rst index 88934b610..af107c0c5 100644 --- a/docs/tutorials/utils-ndn-regex.rst +++ b/docs/tutorials/utils-ndn-regex.rst @@ -1,23 +1,20 @@ NDN Regular Expression ====================== -NDN regular expression matching is done at two levels: one at the name -level and one at the name component level. - -We use ``<`` and ``>`` to enclose a name component matcher which -specifies the pattern of a name component. The component pattern is -expressed using the `Perl Regular Expression -Syntax `__. -For example, ```` can match the 1st, 3rd, and 4th components of -``/ac/dc/abc/abbc``, but it cannot match the 2nd component. A special -case is that ``<>`` is a wildcard matcher that can match **ANY** -component. - -Note that a component match can match only one name component. In order -to match a name, you need to specify the pattern of a name based on the -name component matchers. For example, ```` can match the -name ``/ndn/edu/ucla``. In order to describe a more complicated name -pattern, we borrow some syntaxes from the standard regular expressions. +NDN regular expression is a kind of regular expression that can match NDN names. Matching is +performed at two levels: the name level and the name component level. + +A name component matcher, enclosed in ``<`` and ``>``, specifies the pattern of a name component. The +component pattern is expressed with the `Perl Regular Expression Syntax +`__. +For example, ```` matches the 1st, 3rd, and 4th components of ``/ac/dc/abc/abbc``, but does +not match the 2nd component. A special case is that ``<>`` denotes a wildcard matcher that can match +**ANY** name component. + +A component matcher can match only one name component. To match a name, you need to compose an NDN +regular expression with zero or more name component matchers. For example, ```` +matches the name ``/ndn/edu/ucla``. To describe a more complicated name pattern, we borrow some +syntaxes from the standard regular expressions. NDN Regex Syntax ---------------- @@ -25,79 +22,70 @@ NDN Regex Syntax Anchors ~~~~~~~ -A ``'^'`` character shall match the start of a name. For example, -``^`` shall match any names starting with a component ``ndn``, and -it will exclude a name like ``/local/broadcast``. - -A ``'$'`` character shall match the end of a name. For example, -``^$`` shall match only one name: ``/ndn/edu``. +The ``^`` character matches the start of a name. For example, ``^`` matches any name starting +with the component ``ndn``, but does not match a name like ``/local/broadcast``. -Repeats -~~~~~~~ +The ``$`` character matches the end of a name. For example, ``^$`` matches only one +name: ``/ndn/edu``. -A component matcher can be followed by a repeat syntax to indicate how -many times the preceding component can be matched. +Repetition +~~~~~~~~~~ -Syntax ``*`` for zero or more times. For example, -``^<>*`` shall match ``/ndn/KEY/ID-CERT/``, or -``/ndn/KEY/edu/ID-CERT``, or ``/ndn/KEY/edu/ksk-12345/ID-CERT`` and so -on. +A component matcher can be followed by a repeat quantifier to indicate how many times the preceding +component may appear. -Syntax ``+`` for one or more times. For example, -``^<>+`` shall match ``/ndn/KEY/edu/ID-CERT``, or -``/ndn/KEY/edu/ksk-12345/ID-CERT`` and so on, but it cannot match -``/ndn/KEY/ID-CERT/``. +The ``*`` quantifier denotes "zero or more times". For example, ``^*$`` matches ``/A/C``, +``/A/B/C``, ``/A/B/B/C``, and so on. -Syntax ``?`` for zero or one times. For example, -``^<>?`` shall match ``/ndn/KEY/ID-CERT/``, or -``/ndn/KEY/edu/ID-CERT``, but it cannot match -``/ndn/KEY/edu/ksk-12345/ID-CERT``. +The ``+`` quantifier denotes "one or more times". For example, ``^+$`` matches ``/A/B/C``, +``/A/B/B/C``, and so on, but does not match ``/A/C``. -Repetition can also be bounded: +The ``?`` quantifier denotes "zero or one time". For example, ``^?`` matches ``/A/C`` and +``/A/B/C``, but does not match ``/A/B/B/C``. -``{n}`` for exactly ``n`` times. ``{n,}`` for at least ``n`` times. -``{,n}`` for at most ``n`` times. And ``{n, m}`` for ``n`` to ``m`` -times. +A bounded quantifier specifies a minimum and maximum number of permitted matches: ``{n}`` denotes +"exactly ``n`` times"; ``{n,}`` denotes "at least ``n`` times"; ``{,n}`` denotes "at most ``n`` +times"; ``{n, m}`` denotes "between ``n`` and ``m`` times (inclusive)". For example, +``^{2, 4}$`` matches ``/A/B/B/C`` and ``/A/B/B/B/B/C``. -Note that the repeat matching is **greedy**, that is it will consume as -many matched components as possible. We do not support non-greedy repeat -matching and possessive repeat matching for now. +Note that the quantifiers are **greedy**, which means it will consume as many matched components as +possible. NDN regular expressions currently do not support non-greedy repeat matching and possessive +repeat matching. For example, for the name ``/A/B/C/C/C``, ``^+$`` will match the entire +name instead of only ``/A/B/C``. Sets ~~~~ -Name component set is a bracket-expression starting with ``'['`` and -ending with ``']'``, it defines a set of name components, and matches -any single name component that is a member of that set. +A name component set, denoted by a bracket expression starting with ``[`` and ending with ``]``, +defines a set of name components. It matches any single name component that is a member of that set. -Unlike the standard regular expression, NDN regular expression only -supports **Single Components Set**, that is, you have to list all the -set members one by one between the bracket. For example, -``^[]`` shall match any names starting with either a -component ``ndn"`` or ``localhost``. +Unlike standard regular expressions, NDN regular expression only supports **Single Components Set**, +that is, you have to list all the set members one by one between the brackets. For example, +``^[]`` matches any names starting with either ``ndn"`` or ``localhost`` component. -When a name component set starts with a ``'^'``, the set becomes a -**Negation Set**, that is, it matches the complement of the name -components it contains. For example, ``^[^]`` shall match any names -that does not start with a component ``ndn``. +When a name component set starts with a ``'^'``, the set becomes a **Negation Set**. It matches the +complement of the contained name components. For example, ``^[^]`` matches any non-empty name +that does not start with ``ndn`` component. Some other types of sets, such as Range Set, will be supported later. -Note that component set can be repeated as well. +Note that component sets may be repeated in the same way as component matchers. Sub-pattern and Back Reference ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A section beginning ``(`` and ending ``)`` acts as a marked sub-pattern. -Whatever matched the sub-pattern is split out in a separate field by the -matching algorithms. For example ``^([^])(<>*)`` shall -match a data name of NDN DNS NS record, and the first sub-pattern -captures the zone name while the second sub-pattern captures the -relative record name. - -Marked sub-patterns can be referred to by a back-reference ``\n``. The -same example above shall match a name -``/ndn/edu/ucla/DNS/irl/NS/123456``, and a back reference ``\1\2`` shall -extract ``/ndn/edu/ucla/irl`` out of the name. - -Note that marked sub-patterns can be also repeated. +A section beginning ``(`` and ending ``)`` acts as a marked sub-pattern. Whatever matched the +sub-pattern is split out in a separate field by the matching algorithm. For example +``^(<>{2})(<>)`` matches the name ``/A/C/D/B/E``, and the first sub-pattern captures ``C/D``. + +Marked sub-patterns can be referred to by a back-reference ``\N``, which references one or more +capturing groups. In the example above, a back reference ``\1\2`` extracts ``/C/D/E`` out of the +name. + +Marked sub-patterns can also be repeated. The regex engine does not permanently substitute +back-references in a regular expression, but will use the last match saved into the back-reference. +If a new match is found by capturing parentheses, the previous match is overwritten. For example, +both ``^([]+)$`` and ``^([])+$`` match ``/C/A/B``. However, the former regex +stores ``C/A/B`` as the first back-reference, while the latter one stores ``B``. That is because the +``+`` quantifier in the latter NDN regular expression causes the marked sub-pattern to be matched +three times, and ``B`` is the last saved match. diff --git a/examples/consumer-with-timer.cpp b/examples/consumer-with-timer.cpp index 8c82cf6a7..b3b35eedb 100644 --- a/examples/consumer-with-timer.cpp +++ b/examples/consumer-with-timer.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -21,18 +21,18 @@ * @author Alexander Afanasyev */ -// correct way to include ndn-cxx headers -// #include -// #include -#include "face.hpp" -#include "util/scheduler.hpp" +#include +#include + +#include +#include // Enclosing code in ndn simplifies coding (can also use `using namespace ndn`) namespace ndn { -// Additional nested namespace could be used to prevent/limit name contentions +// Additional nested namespaces should be used to prevent/limit name conflicts namespace examples { -class ConsumerWithTimer : noncopyable +class ConsumerWithTimer { public: ConsumerWithTimer() @@ -44,20 +44,22 @@ class ConsumerWithTimer : noncopyable void run() { - Interest interest(Name("/example/testApp/randomData")); - interest.setInterestLifetime(time::seconds(1)); + Name interestName("/example/testApp/randomData"); + interestName.appendVersion(); + + Interest interest(interestName); + interest.setCanBePrefix(false); interest.setMustBeFresh(true); + interest.setInterestLifetime(2_s); + std::cout << "Sending Interest " << interest << std::endl; m_face.expressInterest(interest, bind(&ConsumerWithTimer::onData, this, _1, _2), bind(&ConsumerWithTimer::onNack, this, _1, _2), bind(&ConsumerWithTimer::onTimeout, this, _1)); - std::cout << "Sending " << interest << std::endl; - // Schedule a new event - m_scheduler.scheduleEvent(time::seconds(2), - bind(&ConsumerWithTimer::delayedInterest, this)); + m_scheduler.schedule(3_s, [this] { delayedInterest(); }); // m_ioService.run() will block until all events finished or m_ioService.stop() is called m_ioService.run(); @@ -69,22 +71,22 @@ class ConsumerWithTimer : noncopyable private: void - onData(const Interest& interest, const Data& data) + onData(const Interest&, const Data& data) const { - std::cout << data << std::endl; + std::cout << "Received Data " << data << std::endl; } void - onNack(const Interest& interest, const lp::Nack& nack) + onNack(const Interest& interest, const lp::Nack& nack) const { - std::cout << "received Nack with reason " << nack.getReason() - << " for interest " << interest << std::endl; + std::cout << "Received Nack with reason " << nack.getReason() + << " for " << interest << std::endl; } void - onTimeout(const Interest& interest) + onTimeout(const Interest& interest) const { - std::cout << "Timeout " << interest << std::endl; + std::cout << "Timeout for " << interest << std::endl; } void @@ -92,39 +94,41 @@ class ConsumerWithTimer : noncopyable { std::cout << "One more Interest, delayed by the scheduler" << std::endl; - Interest interest(Name("/example/testApp/randomData")); - interest.setInterestLifetime(time::milliseconds(1000)); + Name interestName("/example/testApp/randomData"); + interestName.appendVersion(); + + Interest interest(interestName); + interest.setCanBePrefix(false); interest.setMustBeFresh(true); + interest.setInterestLifetime(2_s); + std::cout << "Sending Interest " << interest << std::endl; m_face.expressInterest(interest, bind(&ConsumerWithTimer::onData, this, _1, _2), bind(&ConsumerWithTimer::onNack, this, _1, _2), bind(&ConsumerWithTimer::onTimeout, this, _1)); - - std::cout << "Sending " << interest << std::endl; } private: - // Explicitly create io_service object, which can be shared between Face and Scheduler + // Explicitly create io_service object, which will be shared between Face and Scheduler boost::asio::io_service m_ioService; Face m_face; Scheduler m_scheduler; }; - - } // namespace examples } // namespace ndn int main(int argc, char** argv) { - ndn::examples::ConsumerWithTimer consumer; try { + ndn::examples::ConsumerWithTimer consumer; consumer.run(); + return 0; } catch (const std::exception& e) { std::cerr << "ERROR: " << e.what() << std::endl; + return 1; } - return 0; } diff --git a/examples/consumer.cpp b/examples/consumer.cpp index 0e0ff43b7..ef6cd7683 100644 --- a/examples/consumer.cpp +++ b/examples/consumer.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -21,54 +21,56 @@ * @author Alexander Afanasyev */ -// correct way to include ndn-cxx headers -// #include -#include "face.hpp" +#include + +#include // Enclosing code in ndn simplifies coding (can also use `using namespace ndn`) namespace ndn { -// Additional nested namespace could be used to prevent/limit name contentions +// Additional nested namespaces should be used to prevent/limit name conflicts namespace examples { -class Consumer : noncopyable +class Consumer { public: void run() { - Interest interest(Name("/example/testApp/randomData")); - interest.setInterestLifetime(time::milliseconds(1000)); + Name interestName("/example/testApp/randomData"); + interestName.appendVersion(); + + Interest interest(interestName); + interest.setCanBePrefix(false); interest.setMustBeFresh(true); + interest.setInterestLifetime(6_s); // The default is 4 seconds + std::cout << "Sending Interest " << interest << std::endl; m_face.expressInterest(interest, bind(&Consumer::onData, this, _1, _2), bind(&Consumer::onNack, this, _1, _2), bind(&Consumer::onTimeout, this, _1)); - std::cout << "Sending " << interest << std::endl; - - // processEvents will block until the requested data received or timeout occurs + // processEvents will block until the requested data is received or a timeout occurs m_face.processEvents(); } private: void - onData(const Interest& interest, const Data& data) + onData(const Interest&, const Data& data) const { - std::cout << data << std::endl; + std::cout << "Received Data " << data << std::endl; } void - onNack(const Interest& interest, const lp::Nack& nack) + onNack(const Interest&, const lp::Nack& nack) const { - std::cout << "received Nack with reason " << nack.getReason() - << " for interest " << interest << std::endl; + std::cout << "Received Nack with reason " << nack.getReason() << std::endl; } void - onTimeout(const Interest& interest) + onTimeout(const Interest& interest) const { - std::cout << "Timeout " << interest << std::endl; + std::cout << "Timeout for " << interest << std::endl; } private: @@ -81,12 +83,13 @@ class Consumer : noncopyable int main(int argc, char** argv) { - ndn::examples::Consumer consumer; try { + ndn::examples::Consumer consumer; consumer.run(); + return 0; } catch (const std::exception& e) { std::cerr << "ERROR: " << e.what() << std::endl; + return 1; } - return 0; } diff --git a/examples/producer.cpp b/examples/producer.cpp index 81df7df98..516e1c0a1 100644 --- a/examples/producer.cpp +++ b/examples/producer.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -21,19 +21,18 @@ * @author Alexander Afanasyev */ -// correct way to include ndn-cxx headers -// #include -// #include +#include +#include +#include -#include "face.hpp" -#include "security/key-chain.hpp" +#include // Enclosing code in ndn simplifies coding (can also use `using namespace ndn`) namespace ndn { -// Additional nested namespace could be used to prevent/limit name contentions +// Additional nested namespaces should be used to prevent/limit name conflicts namespace examples { -class Producer : noncopyable +class Producer { public: void @@ -41,48 +40,41 @@ class Producer : noncopyable { m_face.setInterestFilter("/example/testApp", bind(&Producer::onInterest, this, _1, _2), - RegisterPrefixSuccessCallback(), + nullptr, // RegisterPrefixSuccessCallback is optional bind(&Producer::onRegisterFailed, this, _1, _2)); m_face.processEvents(); } private: void - onInterest(const InterestFilter& filter, const Interest& interest) + onInterest(const InterestFilter&, const Interest& interest) { - std::cout << "<< I: " << interest << std::endl; + std::cout << ">> I: " << interest << std::endl; - // Create new name, based on Interest's name - Name dataName(interest.getName()); - dataName - .append("testApp") // add "testApp" component to Interest name - .appendVersion(); // add "version" component (current UNIX timestamp in milliseconds) - - static const std::string content = "HELLO KITTY"; + static const std::string content("Hello, world!"); // Create Data packet - shared_ptr data = make_shared(); - data->setName(dataName); - data->setFreshnessPeriod(time::seconds(10)); - data->setContent(reinterpret_cast(content.c_str()), content.size()); + auto data = make_shared(interest.getName()); + data->setFreshnessPeriod(10_s); + data->setContent(reinterpret_cast(content.data()), content.size()); // Sign Data packet with default identity m_keyChain.sign(*data); - // m_keyChain.sign(data, ); - // m_keyChain.sign(data, ); + // m_keyChain.sign(*data, signingByIdentity()); + // m_keyChain.sign(*data, signingByKey()); + // m_keyChain.sign(*data, signingByCertificate()); + // m_keyChain.sign(*data, signingWithSha256()); // Return Data packet to the requester - std::cout << ">> D: " << *data << std::endl; + std::cout << "<< D: " << *data << std::endl; m_face.put(*data); } - void onRegisterFailed(const Name& prefix, const std::string& reason) { - std::cerr << "ERROR: Failed to register prefix \"" - << prefix << "\" in local hub's daemon (" << reason << ")" - << std::endl; + std::cerr << "ERROR: Failed to register prefix '" << prefix + << "' with the local forwarder (" << reason << ")" << std::endl; m_face.shutdown(); } @@ -97,12 +89,13 @@ class Producer : noncopyable int main(int argc, char** argv) { - ndn::examples::Producer producer; try { + ndn::examples::Producer producer; producer.run(); + return 0; } catch (const std::exception& e) { std::cerr << "ERROR: " << e.what() << std::endl; + return 1; } - return 0; } diff --git a/examples/wscript b/examples/wscript index 52de33fcc..107303358 100644 --- a/examples/wscript +++ b/examples/wscript @@ -3,22 +3,21 @@ top = '..' def build(bld): - # List all .cpp files (whole example should be in one .cpp) - for i in bld.path.ant_glob(['*.cpp']): - name = str(i)[:-len(".cpp")] - bld(features=['cxx', 'cxxprogram'], - target=name, - source=[i] + bld.path.ant_glob(['%s/**/*.cpp' % name]), - use='ndn-cxx', - install_path=None - ) + # List all .cpp files (whole example in one .cpp) + for ex in bld.path.ant_glob('*.cpp'): + name = ex.change_ext('').path_from(bld.path.get_bld()) + bld.program(name='example-%s' % name, + target=name, + source=[ex], + use='ndn-cxx', + install_path=None) - # List all directories files (example can has multiple .cpp in the directory) - for name in bld.path.ant_glob(['*'], dir=True, src=False): - bld(features=['cxx', 'cxxprogram'], - target="%s/%s" % (name, name), - source=bld.path.ant_glob(['%s/**/*.cpp' % name]), - use='ndn-cxx', - install_path=None, - includes='%s' % name, - ) + # List all directories (example can have multiple .cpp in the directory) + for subdir in bld.path.ant_glob('*', dir=True, src=False): + name = subdir.path_from(bld.path) + bld.program(name='example-%s' % name, + target=name, + source=subdir.ant_glob('**/*.cpp'), + use='ndn-cxx', + includes=name, + install_path=None) diff --git a/ndn-cxx/data.cpp b/ndn-cxx/data.cpp new file mode 100644 index 000000000..1ba5f4f00 --- /dev/null +++ b/ndn-cxx/data.cpp @@ -0,0 +1,334 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/util/sha256.hpp" + +namespace ndn { + +BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); +BOOST_CONCEPT_ASSERT((WireEncodable)); +BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); +BOOST_CONCEPT_ASSERT((WireDecodable)); +static_assert(std::is_base_of::value, + "Data::Error must inherit from tlv::Error"); + +Data::Data(const Name& name) + : m_name(name) + , m_content(tlv::Content) +{ +} + +Data::Data(const Block& wire) +{ + wireDecode(wire); +} + +template +size_t +Data::wireEncode(EncodingImpl& encoder, bool wantUnsignedPortionOnly) const +{ + // Data ::= DATA-TLV TLV-LENGTH + // Name + // MetaInfo? + // Content? + // SignatureInfo + // SignatureValue + + size_t totalLength = 0; + + // SignatureValue + if (!wantUnsignedPortionOnly) { + if (!m_signature) { + NDN_THROW(Error("Requested wire format, but Data has not been signed")); + } + totalLength += encoder.prependBlock(m_signature.getValue()); + } + + // SignatureInfo + totalLength += encoder.prependBlock(m_signature.getInfo()); + + // Content + totalLength += encoder.prependBlock(getContent()); + + // MetaInfo + totalLength += getMetaInfo().wireEncode(encoder); + + // Name + totalLength += getName().wireEncode(encoder); + + if (!wantUnsignedPortionOnly) { + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::Data); + } + return totalLength; +} + +template size_t +Data::wireEncode(EncodingBuffer&, bool) const; + +template size_t +Data::wireEncode(EncodingEstimator&, bool) const; + +const Block& +Data::wireEncode(EncodingBuffer& encoder, const Block& signatureValue) const +{ + size_t totalLength = encoder.size(); + totalLength += encoder.appendBlock(signatureValue); + + encoder.prependVarNumber(totalLength); + encoder.prependVarNumber(tlv::Data); + + const_cast(this)->wireDecode(encoder.block()); + return m_wire; +} + +const Block& +Data::wireEncode() const +{ + if (m_wire.hasWire()) + return m_wire; + + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer); + + const_cast(this)->wireDecode(buffer.block()); + return m_wire; +} + +void +Data::wireDecode(const Block& wire) +{ + // Data ::= DATA-TLV TLV-LENGTH + // Name + // MetaInfo? + // Content? + // SignatureInfo + // SignatureValue + + m_wire = wire; + m_wire.parse(); + + auto element = m_wire.elements_begin(); + if (element == m_wire.elements_end() || element->type() != tlv::Name) { + NDN_THROW(Error("Name element is missing or out of order")); + } + m_name.wireDecode(*element); + int lastElement = 1; // last recognized element index, in spec order + + m_metaInfo = MetaInfo(); + m_content = Block(tlv::Content); + m_signature = Signature(); + m_fullName.clear(); + + for (++element; element != m_wire.elements_end(); ++element) { + switch (element->type()) { + case tlv::MetaInfo: { + if (lastElement >= 2) { + NDN_THROW(Error("MetaInfo element is out of order")); + } + m_metaInfo.wireDecode(*element); + lastElement = 2; + break; + } + case tlv::Content: { + if (lastElement >= 3) { + NDN_THROW(Error("Content element is out of order")); + } + m_content = *element; + lastElement = 3; + break; + } + case tlv::SignatureInfo: { + if (lastElement >= 4) { + NDN_THROW(Error("SignatureInfo element is out of order")); + } + m_signature.setInfo(*element); + lastElement = 4; + break; + } + case tlv::SignatureValue: { + if (lastElement >= 5) { + NDN_THROW(Error("SignatureValue element is out of order")); + } + m_signature.setValue(*element); + lastElement = 5; + break; + } + default: { + if (tlv::isCriticalType(element->type())) { + NDN_THROW(Error("unrecognized element of critical type " + to_string(element->type()))); + } + break; + } + } + } + + if (!m_signature) { + NDN_THROW(Error("SignatureInfo element is missing")); + } +} + +const Name& +Data::getFullName() const +{ + if (m_fullName.empty()) { + if (!m_wire.hasWire()) { + NDN_THROW(Error("Cannot compute full name because Data has no wire encoding (not signed)")); + } + m_fullName = m_name; + m_fullName.appendImplicitSha256Digest(util::Sha256::computeDigest(m_wire.wire(), m_wire.size())); + } + + return m_fullName; +} + +void +Data::resetWire() +{ + m_wire.reset(); + m_fullName.clear(); +} + +Data& +Data::setName(const Name& name) +{ + resetWire(); + m_name = name; + return *this; +} + +Data& +Data::setMetaInfo(const MetaInfo& metaInfo) +{ + resetWire(); + m_metaInfo = metaInfo; + return *this; +} + +const Block& +Data::getContent() const +{ + if (!m_content.hasWire()) { + const_cast(m_content).encode(); + } + return m_content; +} + +Data& +Data::setContent(const Block& block) +{ + resetWire(); + + if (block.type() == tlv::Content) { + m_content = block; + } + else { + m_content = Block(tlv::Content, block); + } + + return *this; +} + +Data& +Data::setContent(const uint8_t* value, size_t valueSize) +{ + resetWire(); + m_content = makeBinaryBlock(tlv::Content, value, valueSize); + return *this; +} + +Data& +Data::setContent(ConstBufferPtr value) +{ + resetWire(); + m_content = Block(tlv::Content, std::move(value)); + return *this; +} + +Data& +Data::setSignature(const Signature& signature) +{ + resetWire(); + m_signature = signature; + return *this; +} + +Data& +Data::setSignatureValue(const Block& value) +{ + resetWire(); + m_signature.setValue(value); + return *this; +} + +Data& +Data::setContentType(uint32_t type) +{ + resetWire(); + m_metaInfo.setType(type); + return *this; +} + +Data& +Data::setFreshnessPeriod(time::milliseconds freshnessPeriod) +{ + resetWire(); + m_metaInfo.setFreshnessPeriod(freshnessPeriod); + return *this; +} + +Data& +Data::setFinalBlock(optional finalBlockId) +{ + resetWire(); + m_metaInfo.setFinalBlock(std::move(finalBlockId)); + return *this; +} + +bool +operator==(const Data& lhs, const Data& rhs) +{ + return lhs.getName() == rhs.getName() && + lhs.getMetaInfo().wireEncode() == rhs.getMetaInfo().wireEncode() && + lhs.getContent() == rhs.getContent() && + lhs.getSignature().getSignatureInfo() == rhs.getSignature().getSignatureInfo() && + lhs.getSignature().getValue() == rhs.getSignature().getValue(); +} + +std::ostream& +operator<<(std::ostream& os, const Data& data) +{ + os << "Name: " << data.getName() << "\n"; + os << "MetaInfo: " << data.getMetaInfo() << "\n"; + os << "Content: (size: " << data.getContent().value_size() << ")\n"; + os << "Signature: (type: " << data.getSignature().getType() + << ", value_length: "<< data.getSignature().getValue().value_size() << ")"; + os << std::endl; + + return os; +} + +} // namespace ndn diff --git a/ndn-cxx/data.hpp b/ndn-cxx/data.hpp new file mode 100644 index 000000000..d15b8506e --- /dev/null +++ b/ndn-cxx/data.hpp @@ -0,0 +1,269 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_DATA_HPP +#define NDN_DATA_HPP + +#include "ndn-cxx/meta-info.hpp" +#include "ndn-cxx/name.hpp" +#include "ndn-cxx/signature.hpp" +#include "ndn-cxx/detail/packet-base.hpp" +#include "ndn-cxx/encoding/block.hpp" + +namespace ndn { + +/** @brief Represents a Data packet. + */ +class Data : public PacketBase, public std::enable_shared_from_this +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + /** @brief Construct an unsigned Data packet with given @p name and empty Content. + * @warning In certain contexts that use `Data::shared_from_this()`, Data must be created + * using `make_shared`. Otherwise, `shared_from_this()` will trigger undefined behavior. + */ + explicit + Data(const Name& name = Name()); + + /** @brief Construct a Data packet by decoding from @p wire. + * @param wire @c tlv::Data element as defined in NDN Packet Format v0.2 or v0.3. + * It may be signed or unsigned. + * @warning In certain contexts that use `Data::shared_from_this()`, Data must be created + * using `make_shared`. Otherwise, `shared_from_this()` will trigger undefined behavior. + */ + explicit + Data(const Block& wire); + + /** @brief Prepend wire encoding to @p encoder in NDN Packet Format v0.2. + * @param encoder EncodingEstimator or EncodingBuffer instance + * @param wantUnsignedPortionOnly If true, only prepends Name, MetaInfo, Content, and + * SignatureInfo to @p encoder, but omit SignatureValue and outmost Type-Length of Data + * element. This is intended to be used with wireEncode(encoder, signatureValue). + * @throw Error SignatureBits are not provided and wantUnsignedPortionOnly is false. + */ + template + size_t + wireEncode(EncodingImpl& encoder, bool wantUnsignedPortionOnly = false) const; + + /** @brief Finalize Data packet encoding with the specified SignatureValue + * @param encoder EncodingBuffer containing Name, MetaInfo, Content, and SignatureInfo, but + * without SignatureValue or outmost Type-Length of Data element + * @param signatureValue SignatureValue element + * + * This method is intended to be used in concert with Data::wireEncode(encoder, true) + * @code + * Data data; + * ... + * EncodingBuffer encoder; + * data.wireEncode(encoder, true); + * ... + * Block signatureValue = (encoder.buf(), encoder.size()); + * data.wireEncode(encoder, signatureValue) + * @endcode + */ + const Block& + wireEncode(EncodingBuffer& encoder, const Block& signatureValue) const; + + /** @brief Encode to a @c Block. + * @pre Data is signed. + * + * Normally, this function encodes to NDN Packet Format v0.2. However, if this instance has + * cached wire encoding (\c hasWire() is true), the cached encoding is returned and it might + * be in v0.3 format. + */ + const Block& + wireEncode() const; + + /** @brief Decode from @p wire in NDN Packet Format v0.2 or v0.3. + */ + void + wireDecode(const Block& wire); + + /** @brief Check if this instance has cached wire encoding. + */ + bool + hasWire() const + { + return m_wire.hasWire(); + } + + /** @brief Get full name including implicit digest + * @pre hasWire() == true; i.e. wireEncode() must have been called + * @throw Error Data has no wire encoding + */ + const Name& + getFullName() const; + +public: // Data fields + /** @brief Get name + */ + const Name& + getName() const + { + return m_name; + } + + /** @brief Set name + * @return a reference to this Data, to allow chaining + */ + Data& + setName(const Name& name); + + /** @brief Get MetaInfo + */ + const MetaInfo& + getMetaInfo() const + { + return m_metaInfo; + } + + /** @brief Set MetaInfo + * @return a reference to this Data, to allow chaining + */ + Data& + setMetaInfo(const MetaInfo& metaInfo); + + /** @brief Get Content + * + * The Content value is accessible through value()/value_size() or value_begin()/value_end() + * methods of the Block class. + */ + const Block& + getContent() const; + + /** @brief Set Content from a block + * + * If block's TLV-TYPE is Content, it will be used directly as Data's Content element. + * If block's TLV-TYPE is not Content, it will be nested into a Content element. + * + * @return a reference to this Data, to allow chaining + */ + Data& + setContent(const Block& block); + + /** @brief Copy Content value from raw buffer + * @param value pointer to the first octet of the value + * @param valueSize size of the raw buffer + * @return a reference to this Data, to allow chaining + */ + Data& + setContent(const uint8_t* value, size_t valueSize); + + /** @brief Set Content from wire buffer + * @param value Content value, which does not need to be a TLV element + * @return a reference to this Data, to allow chaining + */ + Data& + setContent(ConstBufferPtr value); + + /** @brief Get Signature + */ + const Signature& + getSignature() const + { + return m_signature; + } + + /** @brief Set Signature + * @return a reference to this Data, to allow chaining + */ + Data& + setSignature(const Signature& signature); + + /** @brief Set SignatureValue + * @return a reference to this Data, to allow chaining + */ + Data& + setSignatureValue(const Block& value); + +public: // MetaInfo fields + uint32_t + getContentType() const + { + return m_metaInfo.getType(); + } + + Data& + setContentType(uint32_t type); + + time::milliseconds + getFreshnessPeriod() const + { + return m_metaInfo.getFreshnessPeriod(); + } + + Data& + setFreshnessPeriod(time::milliseconds freshnessPeriod); + + const optional& + getFinalBlock() const + { + return m_metaInfo.getFinalBlock(); + } + + Data& + setFinalBlock(optional finalBlockId); + +protected: + /** @brief Clear wire encoding and cached FullName + * @note This does not clear the SignatureValue. + */ + void + resetWire(); + +private: + Name m_name; + MetaInfo m_metaInfo; + Block m_content; + Signature m_signature; + + mutable Block m_wire; + mutable Name m_fullName; ///< cached FullName computed from m_wire +}; + +#ifndef DOXYGEN +extern template size_t +Data::wireEncode(EncodingBuffer&, bool) const; + +extern template size_t +Data::wireEncode(EncodingEstimator&, bool) const; +#endif + +std::ostream& +operator<<(std::ostream& os, const Data& data); + +bool +operator==(const Data& lhs, const Data& rhs); + +inline bool +operator!=(const Data& lhs, const Data& rhs) +{ + return !(lhs == rhs); +} + +} // namespace ndn + +#endif // NDN_DATA_HPP diff --git a/ndn-cxx/delegation-list.cpp b/ndn-cxx/delegation-list.cpp new file mode 100644 index 000000000..a05112422 --- /dev/null +++ b/ndn-cxx/delegation-list.cpp @@ -0,0 +1,231 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/delegation-list.hpp" +#include "ndn-cxx/util/ostream-joiner.hpp" + +namespace ndn { + +BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); +BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); +BOOST_CONCEPT_ASSERT((WireDecodable)); + +DelegationList::DelegationList() + : m_isSorted(true) +{ +} + +DelegationList::DelegationList(std::initializer_list dels) + : m_isSorted(true) +{ + for (const Delegation& del : dels) { + this->insert(del, INS_REPLACE); + } +} + +DelegationList::DelegationList(const Block& block, bool wantSort) +{ + this->wireDecode(block, wantSort); +} + +bool +DelegationList::isValidTlvType(uint32_t type) +{ + switch (type) { + case tlv::Content: + case tlv::ForwardingHint: + return true; + default: + return false; + } +} + +template +size_t +DelegationList::wireEncode(EncodingImpl& encoder, uint32_t type) const +{ + if (!isValidTlvType(type)) { + NDN_THROW(std::invalid_argument("Unexpected TLV-TYPE " + to_string(type) + + " while encoding DelegationList")); + } + + if (this->size() == 0) { + NDN_THROW(Error("Empty DelegationList")); + } + + // LinkContent ::= (type) TLV-LENGTH + // Delegation+ + + // Delegation ::= LINK-DELEGATION-TYPE TLV-LENGTH + // Preference + // Name + + // Preference ::= LINK-PREFERENCE-TYPE TLV-LENGTH + // nonNegativeInteger + + size_t totalLen = 0; + for (auto i = m_dels.rbegin(); i != m_dels.rend(); ++i) { + size_t delLen = 0; + delLen += i->name.wireEncode(encoder); + delLen += prependNonNegativeIntegerBlock(encoder, tlv::LinkPreference, i->preference); + delLen += encoder.prependVarNumber(delLen); + delLen += encoder.prependVarNumber(tlv::LinkDelegation); + totalLen += delLen; + } + totalLen += encoder.prependVarNumber(totalLen); + totalLen += encoder.prependVarNumber(type); + return totalLen; +} + +template size_t +DelegationList::wireEncode(EncodingBuffer&, uint32_t) const; + +template size_t +DelegationList::wireEncode(EncodingEstimator&, uint32_t) const; + +void +DelegationList::wireDecode(const Block& block, bool wantSort) +{ + if (!isValidTlvType(block.type())) { + NDN_THROW(Error("Unexpected TLV-TYPE " + to_string(block.type()) + " while decoding DelegationList")); + } + + m_isSorted = wantSort; + m_dels.clear(); + + block.parse(); + for (const auto& del : block.elements()) { + if (del.type() != tlv::LinkDelegation) { + NDN_THROW(Error("Unexpected TLV-TYPE " + to_string(del.type()) + " while decoding Delegation")); + } + del.parse(); + + auto val = del.elements_begin(); + if (val == del.elements_end() || val->type() != tlv::LinkPreference) { + NDN_THROW(Error("Missing Preference field in Delegation")); + } + uint64_t preference = 0; + try { + preference = readNonNegativeInteger(*val); + } + catch (const tlv::Error&) { + NDN_THROW_NESTED(Error("Invalid Preference field in Delegation")); + } + + ++val; + if (val == del.elements_end() || val->type() != tlv::Name) { + NDN_THROW(Error("Missing Name field in Delegation")); + } + Name name; + try { + name.wireDecode(*val); + } + catch (const tlv::Error&) { + NDN_THROW_NESTED(Error("Invalid Name field in Delegation")); + } + + this->insertImpl(preference, name); + } + + if (this->size() == 0) { + NDN_THROW(Error("Empty DelegationList")); + } +} + +void +DelegationList::sort() +{ + if (m_isSorted) { + return; + } + + std::vector dels; + dels.swap(m_dels); + + m_isSorted = true; + for (const Delegation& del : dels) { + this->insertImpl(del.preference, del.name); + } +} + +bool +DelegationList::insert(uint64_t preference, const Name& name, + InsertConflictResolution onConflict) +{ + switch (onConflict) { + case INS_REPLACE: + this->eraseImpl(nullopt, name); + this->insertImpl(preference, name); + return true; + case INS_APPEND: + this->insertImpl(preference, name); + return true; + case INS_SKIP: + if (!std::any_of(m_dels.begin(), m_dels.end(), + [name] (const Delegation& del) { return del.name == name; })) { + this->insertImpl(preference, name); + return true; + } + return false; + } + + NDN_THROW(std::invalid_argument("Unknown InsertConflictResolution")); +} + +void +DelegationList::insertImpl(uint64_t preference, const Name& name) +{ + if (!m_isSorted) { + m_dels.push_back({preference, name}); + return; + } + + Delegation del{preference, name}; + auto pos = std::upper_bound(m_dels.begin(), m_dels.end(), del); + m_dels.insert(pos, del); +} + +size_t +DelegationList::eraseImpl(optional preference, const Name& name) +{ + size_t nErased = 0; + for (auto i = m_dels.begin(); i != m_dels.end();) { + if ((!preference || i->preference == *preference) && + i->name == name) { + ++nErased; + i = m_dels.erase(i); + } + else { + ++i; + } + } + return nErased; +} + +std::ostream& +operator<<(std::ostream& os, const DelegationList& dl) +{ + os << '['; + std::copy(dl.begin(), dl.end(), make_ostream_joiner(os, ',')); + return os << ']'; +} + +} // namespace ndn diff --git a/ndn-cxx/delegation-list.hpp b/ndn-cxx/delegation-list.hpp new file mode 100644 index 000000000..057042641 --- /dev/null +++ b/ndn-cxx/delegation-list.hpp @@ -0,0 +1,264 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_DELEGATION_LIST_HPP +#define NDN_DELEGATION_LIST_HPP + +#include "ndn-cxx/delegation.hpp" + +#include + +namespace ndn { + +/** \brief represents a list of Delegations + * \sa https://named-data.net/doc/ndn-tlv/link.html + * + * Delegations are stored in an std::vector, under the assumption that there is usually only a + * small number of Delegations, so that copying is acceptable when they are modified. + */ +class DelegationList +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + /** \brief construct an empty DelegationList + */ + DelegationList(); + + /** \brief construct a sorted DelegationList with specified delegations + * + * This is equivalent to inserting each delegation into an empty DelegationList with INS_REPLACE + * conflict resolution. + */ + DelegationList(std::initializer_list dels); + + /** \brief decode a DelegationList + * \sa wireDecode + */ + explicit + DelegationList(const Block& block, bool wantSort = true); + + /** \brief encode into wire format + * \param encoder either an EncodingBuffer or an EncodingEstimator + * \param type TLV-TYPE number, either Content (for \p Link) or ForwardingHint + * \throw std::invalid_argument \p type is invalid + * \throw Error there is no Delegation + */ + template + size_t + wireEncode(EncodingImpl& encoder, uint32_t type = tlv::ForwardingHint) const; + + /** \brief decode a DelegationList + * \param block either a Content block (from \p Link) or a ForwardingHint block + * \param wantSort if true, delegations are sorted + * \throw Error the block cannot be parsed as a list of Delegations + */ + void + wireDecode(const Block& block, bool wantSort = true); + + bool + isSorted() const noexcept + { + return m_isSorted; + } + + using const_iterator = std::vector::const_iterator; + + const_iterator + begin() const noexcept + { + return m_dels.begin(); + } + + const_iterator + end() const noexcept + { + return m_dels.end(); + } + + NDN_CXX_NODISCARD bool + empty() const noexcept + { + return m_dels.empty(); + } + + size_t + size() const noexcept + { + return m_dels.size(); + } + + /** \brief get the i-th delegation + * \pre i < size() + */ + const Delegation& + operator[](size_t i) const + { + BOOST_ASSERT(i < size()); + return m_dels[i]; + } + + /** \brief get the i-th delegation + * \throw std::out_of_range i >= size() + */ + const Delegation& + at(size_t i) const + { + return m_dels.at(i); + } + +public: // modifiers + /** \brief sort the delegation list + * \post isSorted() == true + * \post Delegations are sorted in increasing preference order. + * + * A DelegationList can be constructed as sorted or unsorted. In most cases, it is recommended + * to use a sorted DelegationList. An unsorted DelegationList is useful for extracting the i-th + * delegation from a received ForwardingHint or Link object. + * + * This method turns an unsorted DelegationList into a sorted DelegationList. + * If access to unsorted DelegationList is not needed, it is more efficient to sort the + * DelegationList in wireDecode. + */ + void + sort(); + + /** \brief what to do when inserting a duplicate name + */ + enum InsertConflictResolution { + /** \brief existing delegation(s) with the same name are replaced with the new delegation + */ + INS_REPLACE, + + /** \brief multiple delegations with the same name are kept in the DelegationList + * \note This is NOT RECOMMENDED by Link specification. + */ + INS_APPEND, + + /** \brief new delegation is not inserted if an existing delegation has the same name + */ + INS_SKIP + }; + + /** \brief insert Delegation + * \return whether inserted + */ + bool + insert(uint64_t preference, const Name& name, + InsertConflictResolution onConflict = INS_REPLACE); + + /** \brief insert Delegation + * \return whether inserted + */ + bool + insert(const Delegation& del, InsertConflictResolution onConflict = INS_REPLACE) + { + return this->insert(del.preference, del.name, onConflict); + } + + /** \brief delete Delegation(s) with specified preference and name + * \return count of erased Delegation(s) + */ + size_t + erase(uint64_t preference, const Name& name) + { + return this->eraseImpl(preference, name); + } + + /** \brief delete Delegation(s) with matching preference and name + * \return count of erased Delegation(s) + */ + size_t + erase(const Delegation& del) + { + return this->eraseImpl(del.preference, del.name); + } + + /** \brief erase Delegation(s) with specified name + * \return count of erased Delegation(s) + */ + size_t + erase(const Name& name) + { + return this->eraseImpl(nullopt, name); + } + +private: + static bool + isValidTlvType(uint32_t type); + + void + insertImpl(uint64_t preference, const Name& name); + + size_t + eraseImpl(optional preference, const Name& name); + +private: // non-member operators + // NOTE: the following "hidden friend" operators are available via + // argument-dependent lookup only and must be defined inline. + + /** \brief Compare whether two DelegationLists are equal. + * \note Order matters! If two DelegationLists contain the same Delegations but at least one is + * unsorted, they may compare unequal if the Delegations appear in different order. + */ + friend bool + operator==(const DelegationList& lhs, const DelegationList& rhs) + { + return lhs.m_dels == rhs.m_dels; + } + + friend bool + operator!=(const DelegationList& lhs, const DelegationList& rhs) + { + return lhs.m_dels != rhs.m_dels; + } + +private: + bool m_isSorted; + + /** \brief delegation container; its contents are sorted when \p m_isSorted is true + * \note This container is a member field rather than a base class, in order to ensure contents + * are sorted when \p m_isSorted is true. + * \note A vector is chosen instead of a std::set, so that the container can be unsorted when + * \p m_isSorted is false. This container is expected to have less than seven items, and + * therefore the overhead of moving items during insertion and deletion is small. + */ + std::vector m_dels; +}; + +#ifndef DOXYGEN +extern template size_t +DelegationList::wireEncode(EncodingBuffer&, uint32_t) const; + +extern template size_t +DelegationList::wireEncode(EncodingEstimator&, uint32_t) const; +#endif + +std::ostream& +operator<<(std::ostream& os, const DelegationList& dl); + +} // namespace ndn + +#endif // NDN_DELEGATION_LIST_HPP diff --git a/ndn-cxx/delegation.hpp b/ndn-cxx/delegation.hpp new file mode 100644 index 000000000..84c8e7be5 --- /dev/null +++ b/ndn-cxx/delegation.hpp @@ -0,0 +1,89 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_DELEGATION_HPP +#define NDN_DELEGATION_HPP + +#include "ndn-cxx/name.hpp" + +namespace ndn { + +/** \brief Represents a Delegation. + * \sa https://named-data.net/doc/NDN-packet-spec/current/link.html + */ +class Delegation +{ +private: // non-member operators + // NOTE: the following "hidden friend" operators are available via + // argument-dependent lookup only and must be defined inline. + + friend bool + operator==(const Delegation& lhs, const Delegation& rhs) + { + return !(lhs != rhs); + } + + friend bool + operator!=(const Delegation& lhs, const Delegation& rhs) + { + return lhs.preference != rhs.preference || + lhs.name != rhs.name; + } + + friend bool + operator<(const Delegation& lhs, const Delegation& rhs) + { + return std::tie(lhs.preference, lhs.name) < + std::tie(rhs.preference, rhs.name); + } + + friend bool + operator<=(const Delegation& lhs, const Delegation& rhs) + { + return !(rhs < lhs); + } + + friend bool + operator>(const Delegation& lhs, const Delegation& rhs) + { + return rhs < lhs; + } + + friend bool + operator>=(const Delegation& lhs, const Delegation& rhs) + { + return !(lhs < rhs); + } + + friend std::ostream& + operator<<(std::ostream& os, const Delegation& d) + { + return os << d.name << '(' << d.preference << ')'; + } + +public: + uint64_t preference; + Name name; +}; + +} // namespace ndn + +#endif // NDN_DELEGATION_HPP diff --git a/ndn-cxx/detail/README.md b/ndn-cxx/detail/README.md new file mode 100644 index 000000000..a5ffca79a --- /dev/null +++ b/ndn-cxx/detail/README.md @@ -0,0 +1,6 @@ +# Implementation Detail + +This folder contains implementation detail of ndn-cxx library. +Declarations contained in these files are not considered public API and they can change without notice. + +Headers in this folder are installed to the target system. diff --git a/ndn-cxx/detail/asio-fwd.hpp b/ndn-cxx/detail/asio-fwd.hpp new file mode 100644 index 000000000..4d632c2ea --- /dev/null +++ b/ndn-cxx/detail/asio-fwd.hpp @@ -0,0 +1,34 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_DETAIL_ASIO_FWD_HPP +#define NDN_DETAIL_ASIO_FWD_HPP + +namespace ndn { + +class DummyIoService +{ +public: +}; + +} // namespace ndn + +#endif // NDN_DETAIL_ASIO_FWD_HPP diff --git a/ndn-cxx/detail/cancel-handle.cpp b/ndn-cxx/detail/cancel-handle.cpp new file mode 100644 index 000000000..4ce807c03 --- /dev/null +++ b/ndn-cxx/detail/cancel-handle.cpp @@ -0,0 +1,37 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/detail/cancel-handle.hpp" + +namespace ndn { +namespace detail { + +void +CancelHandle::cancel() const +{ + if (m_cancel != nullptr) { + m_cancel(); + m_cancel = nullptr; + } +} + +} // namespace detail +} // namespace ndn diff --git a/ndn-cxx/detail/cancel-handle.hpp b/ndn-cxx/detail/cancel-handle.hpp new file mode 100644 index 000000000..64159938e --- /dev/null +++ b/ndn-cxx/detail/cancel-handle.hpp @@ -0,0 +1,139 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_DETAIL_CANCEL_HANDLE_HPP +#define NDN_DETAIL_CANCEL_HANDLE_HPP + +#include "ndn-cxx/detail/common.hpp" + +namespace ndn { +namespace detail { + +/** \brief Handle to cancel an operation. + */ +class CancelHandle +{ +public: + CancelHandle() noexcept; + + explicit + CancelHandle(std::function cancel) noexcept + : m_cancel(std::move(cancel)) + { + } + + /** \brief Cancel the operation. + */ + void + cancel() const; + +private: + mutable std::function m_cancel; +}; + +inline +CancelHandle::CancelHandle() noexcept = default; + +/** \brief Cancels an operation automatically upon destruction. + */ +template +class ScopedCancelHandle +{ + static_assert(std::is_convertible::value, + "HandleT must publicly derive from CancelHandle"); + +public: + ScopedCancelHandle() noexcept; + + /** \brief Implicit constructor from HandleT. + */ + ScopedCancelHandle(HandleT hdl) noexcept + : m_hdl(std::move(hdl)) + { + } + + /** \brief Copy construction is disallowed. + */ + ScopedCancelHandle(const ScopedCancelHandle&) = delete; + + /** \brief Move constructor. + */ + ScopedCancelHandle(ScopedCancelHandle&& other) noexcept + : m_hdl(other.release()) + { + } + + /** \brief Copy assignment is disallowed. + */ + ScopedCancelHandle& + operator=(const ScopedCancelHandle&) = delete; + + /** \brief Move assignment operator. + */ + ScopedCancelHandle& + operator=(ScopedCancelHandle&& other) + { + m_hdl.cancel(); + m_hdl = other.release(); + return *this; + } + + /** \brief Cancel the operation. + */ + ~ScopedCancelHandle() + { + m_hdl.cancel(); + } + + /** \brief Cancel the operation. + */ + void + cancel() + { + release().cancel(); + } + + /** \brief Release the operation so that it won't be cancelled when this ScopedCancelHandle is + * destructed. + */ + HandleT + release() noexcept + { + return std::exchange(m_hdl, HandleT{}); + } + + explicit + operator bool() const noexcept + { + return !!m_hdl; + } + +private: + HandleT m_hdl; +}; + +template +ScopedCancelHandle::ScopedCancelHandle() noexcept = default; + +} // namespace detail +} // namespace ndn + +#endif // NDN_DETAIL_CANCEL_HANDLE_HPP diff --git a/ndn-cxx/detail/cf-releaser-osx.hpp b/ndn-cxx/detail/cf-releaser-osx.hpp new file mode 100644 index 000000000..fff58ab59 --- /dev/null +++ b/ndn-cxx/detail/cf-releaser-osx.hpp @@ -0,0 +1,151 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_DETAIL_CF_RELEASER_OSX_HPP +#define NDN_DETAIL_CF_RELEASER_OSX_HPP + +#include "ndn-cxx/detail/common.hpp" + +#ifndef NDN_CXX_HAVE_OSX_FRAMEWORKS +#error "This file should not be included ..." +#endif + +#include + +namespace ndn { +namespace detail { + +/** + * @brief Helper class to wrap CoreFoundation object pointers + * + * The class is similar in spirit to shared_ptr, but uses CoreFoundation + * mechanisms to retain/release object. + * + * Original implementation by Christopher Hunt and it was borrowed from + * http://www.cocoabuilder.com/archive/cocoa/130776-auto-cfrelease-and.html + * + * @note The filename cf-releaser-osx.hpp is an intentional violation of code-style rule 2.1. + * Having '-osx' suffix is necessary to prevent installation on non-macOS platforms. + */ +template +class CFReleaser +{ +public: // Construction/destruction + CFReleaser() + : m_typeRef(nullptr) + { + } + + CFReleaser(const T& typeRef) + : m_typeRef(typeRef) + { + } + + CFReleaser(const CFReleaser& inReleaser) + : m_typeRef(nullptr) + { + retain(inReleaser.m_typeRef); + } + + CFReleaser& + operator=(const T& typeRef) + { + if (typeRef != m_typeRef) { + release(); + m_typeRef = typeRef; + } + return *this; + } + + CFReleaser& + operator=(const CFReleaser& inReleaser) + { + retain(inReleaser.m_typeRef); + return *this; + } + + ~CFReleaser() + { + release(); + } + +public: // Access + const T& + get() const + { + return m_typeRef; + } + + T& + get() + { + return m_typeRef; + } + +public: // Miscellaneous + void + retain(const T& typeRef) + { + if (typeRef != nullptr) { + CFRetain(typeRef); + } + release(); + m_typeRef = typeRef; + } + + void + retain() + { + T typeRef = m_typeRef; + m_typeRef = nullptr; + retain(typeRef); + } + + void + release() + { + if (m_typeRef != nullptr) { + CFRelease(m_typeRef); + m_typeRef = nullptr; + } + } + +private: // Comparison with nullptr + friend bool + operator==(const CFReleaser& lhs, std::nullptr_t) + { + return lhs.m_typeRef == nullptr; + } + + friend bool + operator!=(const CFReleaser& lhs, std::nullptr_t) + { + return lhs.m_typeRef != nullptr; + } + +private: + T m_typeRef; +}; + +} // namespace detail +} // namespace ndn + +#endif // NDN_DETAIL_CF_RELEASER_OSX_HPP diff --git a/ndn-cxx/detail/cf-string-osx.cpp b/ndn-cxx/detail/cf-string-osx.cpp new file mode 100644 index 000000000..5cceb33a1 --- /dev/null +++ b/ndn-cxx/detail/cf-string-osx.cpp @@ -0,0 +1,71 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/detail/cf-string-osx.hpp" + +namespace ndn { +namespace detail { +namespace cfstring { + +CFReleaser +fromBuffer(const uint8_t* buf, size_t buflen) +{ + CFStringRef cfStr = CFStringCreateWithBytes(kCFAllocatorDefault, buf, buflen, kCFStringEncodingUTF8, false); + if (cfStr == nullptr) { + NDN_THROW(std::runtime_error("Failed to create CFString from buffer")); + } + return cfStr; +} + +CFReleaser +fromStdString(const std::string& str) +{ + CFStringRef cfStr = CFStringCreateWithCString(kCFAllocatorDefault, str.data(), kCFStringEncodingUTF8); + if (cfStr == nullptr) { + NDN_THROW(std::runtime_error("Failed to create CFString from std::string")); + } + return cfStr; +} + +std::string +toStdString(CFStringRef cfStr) +{ + const char* cStr = CFStringGetCStringPtr(cfStr, kCFStringEncodingUTF8); + if (cStr != nullptr) { + // fast path + return cStr; + } + + // reserve space for the string + null terminator + std::string str(CFStringGetLength(cfStr) + 1, '\0'); + // copy the CFString into the std::string buffer + if (!CFStringGetCString(cfStr, &str.front(), str.size(), kCFStringEncodingUTF8)) { + NDN_THROW(std::runtime_error("CFString to std::string conversion failed")); + } + // drop the null terminator, std::string doesn't need it + str.pop_back(); + + return str; +} + +} // namespace cfstring +} // namespace detail +} // namespace ndn diff --git a/ndn-cxx/detail/cf-string-osx.hpp b/ndn-cxx/detail/cf-string-osx.hpp new file mode 100644 index 000000000..ddd79aa2d --- /dev/null +++ b/ndn-cxx/detail/cf-string-osx.hpp @@ -0,0 +1,68 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_DETAIL_CF_STRING_OSX_HPP +#define NDN_DETAIL_CF_STRING_OSX_HPP + +#include "ndn-cxx/detail/common.hpp" + +#ifndef NDN_CXX_HAVE_OSX_FRAMEWORKS +#error "This file should not be included ..." +#endif + +#include "ndn-cxx/detail/cf-releaser-osx.hpp" + +/** + * @file + * + * This file contains utilities to deal with Apple Core Foundation's CFString and related types. + */ + +namespace ndn { +namespace detail { +namespace cfstring { + +/** + * @brief Create a CFString by copying bytes from a raw buffer + * @throw std::runtime_error creation failed + */ +CFReleaser +fromBuffer(const uint8_t* buf, size_t buflen); + +/** + * @brief Create a CFString by copying characters from a std::string + * @throw std::runtime_error creation failed + */ +CFReleaser +fromStdString(const std::string& str); + +/** + * @brief Convert a CFString to a std::string + * @throw std::runtime_error conversion failed + */ +std::string +toStdString(CFStringRef cfStr); + +} // namespace cfstring +} // namespace detail +} // namespace ndn + +#endif // NDN_DETAIL_CF_STRING_OSX_HPP diff --git a/ndn-cxx/detail/common.hpp b/ndn-cxx/detail/common.hpp new file mode 100644 index 000000000..e80af5731 --- /dev/null +++ b/ndn-cxx/detail/common.hpp @@ -0,0 +1,124 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +/** \file + * \brief Common includes and macros used throughout the library. + * \warning This file is an implementation detail of the ndn-cxx library. + * Aliases imported in this file MUST NOT be used outside of ndn-cxx. + */ + +#ifndef NDN_DETAIL_COMMON_HPP +#define NDN_DETAIL_COMMON_HPP + +#include "ndn-cxx/detail/config.hpp" + +// require C++14 +#if __cplusplus < 201402L +#error "ndn-cxx applications must be compiled using the C++14 standard (-std=c++14)" +#endif + +// ndn-cxx specific macros declared in this and other headers must have NDN_CXX_ prefix +// to avoid conflicts with other projects that include ndn-cxx headers. +#ifdef NDN_CXX_HAVE_TESTS +#define NDN_CXX_VIRTUAL_WITH_TESTS virtual +#define NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED public +#define NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE public +#define NDN_CXX_PROTECTED_WITH_TESTS_ELSE_PRIVATE protected +#else +#define NDN_CXX_VIRTUAL_WITH_TESTS +#define NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED protected +#define NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE private +#define NDN_CXX_PROTECTED_WITH_TESTS_ELSE_PRIVATE private +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ndn { + +using std::shared_ptr; +using std::unique_ptr; +using std::weak_ptr; +using std::make_shared; +using std::make_unique; + +using std::static_pointer_cast; +using std::dynamic_pointer_cast; +using std::const_pointer_cast; + +using std::function; +using std::bind; +using std::ref; +using std::cref; + +using namespace std::string_literals; + +} // namespace ndn + +using namespace std::placeholders; + +/// \cond +// Bug 2109 workaround +#define BOOST_BIND_NO_PLACEHOLDERS +#include +namespace boost { +#define NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(N) \ + template<> \ + struct is_placeholder> \ + { \ + enum _vt { \ + value = N \ + }; \ + }; +NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(1) +NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(2) +NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(3) +NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(4) +NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(5) +NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(6) +NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(7) +NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(8) +NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(9) +#undef NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER +} // namespace boost +/// \endcond + +#include +#include +#include + +namespace ndn { +using boost::noncopyable; +} // namespace ndn + +#include "ndn-cxx/util/backports.hpp" +#include "ndn-cxx/util/exception.hpp" + +#endif // NDN_DETAIL_COMMON_HPP diff --git a/ndn-cxx/detail/packet-base.cpp b/ndn-cxx/detail/packet-base.cpp new file mode 100644 index 000000000..8ba73626c --- /dev/null +++ b/ndn-cxx/detail/packet-base.cpp @@ -0,0 +1,52 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/detail/packet-base.hpp" +#include "ndn-cxx/lp/tags.hpp" + +namespace ndn { + +uint64_t +PacketBase::getCongestionMark() const +{ + auto mark = this->getTag(); + + if (mark == nullptr) { + return 0; + } + else { + return *mark; + } +} + +void +PacketBase::setCongestionMark(uint64_t mark) +{ + if (mark != 0) { + auto tag = make_shared(mark); + this->setTag(std::move(tag)); + } + else { + this->removeTag(); + } +} + +} // namespace ndn diff --git a/ndn-cxx/detail/packet-base.hpp b/ndn-cxx/detail/packet-base.hpp new file mode 100644 index 000000000..8903fd798 --- /dev/null +++ b/ndn-cxx/detail/packet-base.hpp @@ -0,0 +1,47 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_DETAIL_PACKET_BASE_HPP +#define NDN_DETAIL_PACKET_BASE_HPP + +#include "ndn-cxx/detail/tag-host.hpp" + +namespace ndn { + +/** \brief base class to allow simple management of packet tags + */ +class PacketBase : public TagHost +{ +public: + /** \brief get the value of the CongestionMark tag + */ + uint64_t + getCongestionMark() const; + + /** \brief set the CongestionMark tag to the specified value + */ + void + setCongestionMark(uint64_t mark); +}; + +} // namespace ndn + +#endif // NDN_DETAIL_PACKET_BASE_HPP diff --git a/src/tag-host.hpp b/ndn-cxx/detail/tag-host.hpp similarity index 86% rename from src/tag-host.hpp rename to ndn-cxx/detail/tag-host.hpp index 0d1d39d30..8fecc639f 100644 --- a/src/tag-host.hpp +++ b/ndn-cxx/detail/tag-host.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,11 +19,11 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#ifndef NDN_TAG_HOST_HPP -#define NDN_TAG_HOST_HPP +#ifndef NDN_DETAIL_TAG_HOST_HPP +#define NDN_DETAIL_TAG_HOST_HPP -#include "common.hpp" -#include "tag.hpp" +#include "ndn-cxx/detail/common.hpp" +#include "ndn-cxx/tag.hpp" #include @@ -58,12 +58,11 @@ class TagHost removeTag() const; private: - mutable std::map> m_tags; + mutable std::map> m_tags; }; - template -inline shared_ptr +shared_ptr TagHost::getTag() const { static_assert(std::is_base_of::value, "T must inherit from Tag"); @@ -76,21 +75,21 @@ TagHost::getTag() const } template -inline void +void TagHost::setTag(shared_ptr tag) const { static_assert(std::is_base_of::value, "T must inherit from Tag"); if (tag == nullptr) { m_tags.erase(T::getTypeId()); - return; } - - m_tags[T::getTypeId()] = tag; + else { + m_tags[T::getTypeId()] = std::move(tag); + } } template -inline void +void TagHost::removeTag() const { setTag(nullptr); @@ -98,4 +97,4 @@ TagHost::removeTag() const } // namespace ndn -#endif // NDN_TAG_HOST_HPP +#endif // NDN_DETAIL_TAG_HOST_HPP diff --git a/ndn-cxx/encoding/block-helpers.cpp b/ndn-cxx/encoding/block-helpers.cpp new file mode 100644 index 000000000..dd6e08f66 --- /dev/null +++ b/ndn-cxx/encoding/block-helpers.cpp @@ -0,0 +1,199 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/encoding/block-helpers.hpp" + +#include + +namespace ndn { +namespace encoding { + +namespace endian = boost::endian; + +// ---- non-negative integer ---- + +template +size_t +prependNonNegativeIntegerBlock(EncodingImpl& encoder, uint32_t type, uint64_t value) +{ + size_t valueLength = encoder.prependNonNegativeInteger(value); + size_t totalLength = valueLength; + totalLength += encoder.prependVarNumber(valueLength); + totalLength += encoder.prependVarNumber(type); + + return totalLength; +} + +template size_t +prependNonNegativeIntegerBlock(EncodingImpl&, uint32_t, uint64_t); + +template size_t +prependNonNegativeIntegerBlock(EncodingImpl&, uint32_t, uint64_t); + +Block +makeNonNegativeIntegerBlock(uint32_t type, uint64_t value) +{ + EncodingEstimator estimator; + size_t totalLength = prependNonNegativeIntegerBlock(estimator, type, value); + + EncodingBuffer encoder(totalLength, 0); + prependNonNegativeIntegerBlock(encoder, type, value); + + return encoder.block(); +} + +uint64_t +readNonNegativeInteger(const Block& block) +{ + auto begin = block.value_begin(); + return tlv::readNonNegativeInteger(block.value_size(), begin, block.value_end()); +} + +// ---- empty ---- + +template +size_t +prependEmptyBlock(EncodingImpl& encoder, uint32_t type) +{ + size_t totalLength = encoder.prependVarNumber(0); + totalLength += encoder.prependVarNumber(type); + + return totalLength; +} + +template size_t +prependEmptyBlock(EncodingImpl&, uint32_t); + +template size_t +prependEmptyBlock(EncodingImpl&, uint32_t); + +Block +makeEmptyBlock(uint32_t type) +{ + EncodingEstimator estimator; + size_t totalLength = prependEmptyBlock(estimator, type); + + EncodingBuffer encoder(totalLength, 0); + prependEmptyBlock(encoder, type); + + return encoder.block(); +} + +// ---- string ---- + +template +size_t +prependStringBlock(EncodingImpl& encoder, uint32_t type, const std::string& value) +{ + return encoder.prependByteArrayBlock(type, reinterpret_cast(value.data()), value.size()); +} + +template size_t +prependStringBlock(EncodingImpl&, uint32_t, const std::string&); + +template size_t +prependStringBlock(EncodingImpl&, uint32_t, const std::string&); + +Block +makeStringBlock(uint32_t type, const std::string& value) +{ + return makeBinaryBlock(type, value.data(), value.size()); +} + +std::string +readString(const Block& block) +{ + return std::string(reinterpret_cast(block.value()), block.value_size()); +} + +// ---- double ---- + +static_assert(std::numeric_limits::is_iec559, "This code requires IEEE-754 doubles"); + +template +size_t +prependDoubleBlock(EncodingImpl& encoder, uint32_t type, double value) +{ + uint64_t temp = 0; + std::memcpy(&temp, &value, 8); + endian::native_to_big_inplace(temp); + return encoder.prependByteArrayBlock(type, reinterpret_cast(&temp), 8); +} + +template size_t +prependDoubleBlock(EncodingImpl&, uint32_t, double); + +template size_t +prependDoubleBlock(EncodingImpl&, uint32_t, double); + +Block +makeDoubleBlock(uint32_t type, double value) +{ + EncodingEstimator estimator; + size_t totalLength = prependDoubleBlock(estimator, type, value); + + EncodingBuffer encoder(totalLength, 0); + prependDoubleBlock(encoder, type, value); + + return encoder.block(); +} + +double +readDouble(const Block& block) +{ + if (block.value_size() != 8) { + NDN_THROW(tlv::Error("Invalid length for double (must be 8)")); + } + +#if BOOST_VERSION >= 107100 + return endian::endian_load(block.value()); +#else + uint64_t temp = 0; + std::memcpy(&temp, block.value(), 8); + endian::big_to_native_inplace(temp); + double d = 0; + std::memcpy(&d, &temp, 8); + return d; +#endif +} + +// ---- binary ---- + +Block +makeBinaryBlock(uint32_t type, const uint8_t* value, size_t length) +{ + EncodingEstimator estimator; + size_t totalLength = estimator.prependByteArrayBlock(type, value, length); + + EncodingBuffer encoder(totalLength, 0); + encoder.prependByteArrayBlock(type, value, length); + + return encoder.block(); +} + +Block +makeBinaryBlock(uint32_t type, const char* value, size_t length) +{ + return makeBinaryBlock(type, reinterpret_cast(value), length); +} + +} // namespace encoding +} // namespace ndn diff --git a/ndn-cxx/encoding/block-helpers.hpp b/ndn-cxx/encoding/block-helpers.hpp new file mode 100644 index 000000000..fd2918630 --- /dev/null +++ b/ndn-cxx/encoding/block-helpers.hpp @@ -0,0 +1,327 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_ENCODING_BLOCK_HELPERS_HPP +#define NDN_ENCODING_BLOCK_HELPERS_HPP + +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/util/concepts.hpp" + +namespace ndn { +namespace encoding { + +/** @brief Prepend a TLV element containing a non-negative integer. + * @param encoder an EncodingBuffer or EncodingEstimator + * @param type TLV-TYPE number + * @param value non-negative integer value + * @sa makeNonNegativeIntegerBlock, readNonNegativeInteger + */ +template +size_t +prependNonNegativeIntegerBlock(EncodingImpl& encoder, uint32_t type, uint64_t value); + +extern template size_t +prependNonNegativeIntegerBlock(EncodingImpl&, uint32_t, uint64_t); + +extern template size_t +prependNonNegativeIntegerBlock(EncodingImpl&, uint32_t, uint64_t); + +/** @brief Create a TLV block containing a non-negative integer. + * @param type TLV-TYPE number + * @param value non-negative integer value + * @sa prependNonNegativeIntegerBlock, readNonNegativeInteger + */ +Block +makeNonNegativeIntegerBlock(uint32_t type, uint64_t value); + +/** @brief Read a non-negative integer from a TLV element. + * @param block the TLV element + * @throw tlv::Error block does not contain a non-negative integer + * @sa prependNonNegativeIntegerBlock, makeNonNegativeIntegerBlock + */ +uint64_t +readNonNegativeInteger(const Block& block); + +/** @brief Read a non-negative integer from a TLV element and cast to the specified type. + * @tparam R result type, must be an integral type + * @param block the TLV element + * @throw tlv::Error block does not contain a valid non-negative integer or the number cannot be + * represented in R + */ +template +std::enable_if_t::value, R> +readNonNegativeIntegerAs(const Block& block) +{ + uint64_t value = readNonNegativeInteger(block); + if (value > std::numeric_limits::max()) { + NDN_THROW(tlv::Error("Value in TLV element of type " + to_string(block.type()) + " is too large")); + } + return static_cast(value); +} + +/** @brief Read a non-negative integer from a TLV element and cast to the specified type. + * @tparam R result type, must be an enumeration type + * @param block the TLV element + * @throw tlv::Error block does not contain a valid non-negative integer or the number cannot be + * represented in R + * @warning If R is an unscoped enum type, it must have a fixed underlying type. Otherwise, this + * function may trigger unspecified behavior. + */ +template +std::enable_if_t::value, R> +readNonNegativeIntegerAs(const Block& block) +{ + return static_cast(readNonNegativeIntegerAs>(block)); +} + +/** @brief Prepend an empty TLV element. + * @param encoder an EncodingBuffer or EncodingEstimator + * @param type TLV-TYPE number + * @details The TLV element has zero-length TLV-VALUE. + * @sa makeEmptyBlock + */ +template +size_t +prependEmptyBlock(EncodingImpl& encoder, uint32_t type); + +extern template size_t +prependEmptyBlock(EncodingImpl&, uint32_t); + +extern template size_t +prependEmptyBlock(EncodingImpl&, uint32_t); + +/** @brief Create an empty TLV block. + * @param type TLV-TYPE number + * @return A TLV block with zero-length TLV-VALUE + * @sa prependEmptyBlock + */ +Block +makeEmptyBlock(uint32_t type); + +/** @brief Prepend a TLV element containing a string. + * @param encoder an EncodingBuffer or EncodingEstimator + * @param type TLV-TYPE number + * @param value string value, may contain NUL octets + * @sa makeStringBlock, readString + */ +template +size_t +prependStringBlock(EncodingImpl& encoder, uint32_t type, const std::string& value); + +extern template size_t +prependStringBlock(EncodingImpl&, uint32_t, const std::string&); + +extern template size_t +prependStringBlock(EncodingImpl&, uint32_t, const std::string&); + +/** @brief Create a TLV block containing a string. + * @param type TLV-TYPE number + * @param value string value, may contain NUL octets + * @sa prependStringBlock, readString + */ +Block +makeStringBlock(uint32_t type, const std::string& value); + +/** @brief Read TLV-VALUE of a TLV element as a string. + * @param block the TLV element + * @return a string, may contain NUL octets + * @sa prependStringBlock, makeStringBlock + */ +std::string +readString(const Block& block); + +/** @brief Prepend a TLV element containing an IEEE 754 double-precision floating-point number. + * @param encoder an EncodingBuffer or EncodingEstimator + * @param type TLV-TYPE number + * @param value a floating point number value + * @sa makeDoubleBlock, readDouble + */ +template +size_t +prependDoubleBlock(EncodingImpl& encoder, uint32_t type, double value); + +extern template size_t +prependDoubleBlock(EncodingImpl&, uint32_t, double); + +extern template size_t +prependDoubleBlock(EncodingImpl&, uint32_t, double); + +/** @brief Create a TLV element containing an IEEE 754 double-precision floating-point number. + * @param type TLV-TYPE number + * @param value floating point number value + * @sa prependDoubleBlock, readDouble + */ +Block +makeDoubleBlock(uint32_t type, double value); + +/** @brief Read TLV-VALUE of a TLV element as an IEEE 754 double-precision floating-point number. + * @param block the TLV element + * @return a floating point number value + * @sa prependDoubleBlock, makeDoubleBlock + */ +double +readDouble(const Block& block); + +/** @brief Create a TLV block copying TLV-VALUE from raw buffer. + * @param type TLV-TYPE number + * @param value raw buffer as TLV-VALUE + * @param length length of value buffer + * @sa Encoder::prependByteArrayBlock + */ +Block +makeBinaryBlock(uint32_t type, const uint8_t* value, size_t length); + +/** @brief Create a TLV block copying TLV-VALUE from raw buffer. + * @param type TLV-TYPE number + * @param value raw buffer as TLV-VALUE + * @param length length of value buffer + * @sa Encoder::prependByteArrayBlock + */ +Block +makeBinaryBlock(uint32_t type, const char* value, size_t length); + +namespace detail { + +/** @brief Create a binary block copying from RandomAccessIterator. + */ +template +class BinaryBlockFast +{ +public: + BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator)); + + static Block + makeBlock(uint32_t type, Iterator first, Iterator last) + { + EncodingEstimator estimator; + size_t valueLength = last - first; + size_t totalLength = valueLength; + totalLength += estimator.prependVarNumber(valueLength); + totalLength += estimator.prependVarNumber(type); + + EncodingBuffer encoder(totalLength, 0); + encoder.prependRange(first, last); + encoder.prependVarNumber(valueLength); + encoder.prependVarNumber(type); + + return encoder.block(); + } +}; + +/** @brief Create a binary block copying from generic InputIterator. + */ +template +class BinaryBlockSlow +{ +public: + BOOST_CONCEPT_ASSERT((boost::InputIterator)); + + static Block + makeBlock(uint32_t type, Iterator first, Iterator last) + { + // reserve 4 bytes in front (common for 1(type)-3(length) encoding + // Actual size will be adjusted as necessary by the encoder + EncodingBuffer encoder(4, 4); + size_t valueLength = encoder.appendRange(first, last); + encoder.prependVarNumber(valueLength); + encoder.prependVarNumber(type); + + return encoder.block(); + } +}; + +} // namespace detail + +/** @brief Create a TLV block copying TLV-VALUE from iterators. + * @tparam Iterator an InputIterator dereferencable to an 1-octet type; faster implementation is + * available for RandomAccessIterator + * @param type TLV-TYPE number + * @param first begin iterator + * @param last past-the-end iterator + */ +template +Block +makeBinaryBlock(uint32_t type, Iterator first, Iterator last) +{ + using BinaryBlockHelper = std::conditional_t< + std::is_base_of::iterator_category>::value, + detail::BinaryBlockFast, + detail::BinaryBlockSlow>; + + return BinaryBlockHelper::makeBlock(type, first, last); +} + +/** @brief Prepend a TLV element containing a nested TLV element. + * @tparam U type that satisfies WireEncodableWithEncodingBuffer concept + * @param encoder an EncodingBuffer or EncodingEstimator + * @param type TLV-TYPE number for outer TLV element + * @param value an object to be encoded as inner TLV element + * @sa makeNestedBlock + */ +template +size_t +prependNestedBlock(EncodingImpl& encoder, uint32_t type, const U& value) +{ + BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); + + size_t valueLength = value.wireEncode(encoder); + size_t totalLength = valueLength; + totalLength += encoder.prependVarNumber(valueLength); + totalLength += encoder.prependVarNumber(type); + + return totalLength; +} + +/** @brief Create a TLV block containing a nested TLV element. + * @tparam U type that satisfies WireEncodableWithEncodingBuffer concept + * @param type TLV-TYPE number for outer TLV element + * @param value an object to be encoded as inner TLV element + * @sa prependNestedBlock + */ +template +Block +makeNestedBlock(uint32_t type, const U& value) +{ + EncodingEstimator estimator; + size_t totalLength = prependNestedBlock(estimator, type, value); + + EncodingBuffer encoder(totalLength, 0); + prependNestedBlock(encoder, type, value); + + return encoder.block(); +} + +} // namespace encoding + +using encoding::makeNonNegativeIntegerBlock; +using encoding::readNonNegativeInteger; +using encoding::readNonNegativeIntegerAs; +using encoding::makeEmptyBlock; +using encoding::makeStringBlock; +using encoding::readString; +using encoding::makeBinaryBlock; +using encoding::makeNestedBlock; + +} // namespace ndn + +#endif // NDN_ENCODING_BLOCK_HELPERS_HPP diff --git a/ndn-cxx/encoding/block.cpp b/ndn-cxx/encoding/block.cpp new file mode 100644 index 000000000..4f6d8c88d --- /dev/null +++ b/ndn-cxx/encoding/block.cpp @@ -0,0 +1,537 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Alexander Afanasyev + */ + +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/encoding/tlv.hpp" +#include "ndn-cxx/security/transform.hpp" +#include "ndn-cxx/util/ostream-joiner.hpp" +#include "ndn-cxx/util/string-helper.hpp" + +#include +#include +#include + +namespace ndn { + +BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); + +const size_t MAX_SIZE_OF_BLOCK_FROM_STREAM = MAX_NDN_PACKET_SIZE; + +// ---- constructor, creation, assignment ---- + +Block::Block() = default; + +Block::Block(const Block&) = default; + +Block& +Block::operator=(const Block&) = default; + +Block::Block(const EncodingBuffer& buffer) + : Block(buffer.getBuffer(), buffer.begin(), buffer.end(), true) +{ +} + +Block::Block(const ConstBufferPtr& buffer) + : Block(buffer, buffer->begin(), buffer->end(), true) +{ +} + +Block::Block(ConstBufferPtr buffer, Buffer::const_iterator begin, Buffer::const_iterator end, + bool verifyLength) + : m_buffer(std::move(buffer)) + , m_begin(begin) + , m_end(end) + , m_valueBegin(m_begin) + , m_valueEnd(m_end) + , m_size(m_end - m_begin) +{ + if (m_buffer->size() == 0) { + NDN_THROW(std::invalid_argument("Buffer is empty")); + } + + const uint8_t* bufferBegin = &m_buffer->front(); + const uint8_t* bufferEnd = bufferBegin + m_buffer->size(); + if (&*begin < bufferBegin || &*begin > bufferEnd || + &*end < bufferBegin || &*end > bufferEnd) { + NDN_THROW(std::invalid_argument("Begin/end iterators point outside the buffer")); + } + + m_type = tlv::readType(m_valueBegin, m_valueEnd); + uint64_t length = tlv::readVarNumber(m_valueBegin, m_valueEnd); + // m_valueBegin now points to TLV-VALUE + + if (verifyLength && length != static_cast(m_valueEnd - m_valueBegin)) { + NDN_THROW(Error("TLV-LENGTH does not match buffer size")); + } +} + +Block::Block(const Block& block, Buffer::const_iterator begin, Buffer::const_iterator end, + bool verifyLength) + : Block(block.m_buffer, begin, end, verifyLength) +{ +} + +Block::Block(ConstBufferPtr buffer, uint32_t type, + Buffer::const_iterator begin, Buffer::const_iterator end, + Buffer::const_iterator valueBegin, Buffer::const_iterator valueEnd) + : m_buffer(std::move(buffer)) + , m_begin(begin) + , m_end(end) + , m_valueBegin(valueBegin) + , m_valueEnd(valueEnd) + , m_type(type) + , m_size(m_end - m_begin) +{ +} + +Block::Block(const uint8_t* buf, size_t bufSize) +{ + const uint8_t* pos = buf; + const uint8_t* const end = buf + bufSize; + + m_type = tlv::readType(pos, end); + uint64_t length = tlv::readVarNumber(pos, end); + // pos now points to TLV-VALUE + + BOOST_ASSERT(pos <= end); + if (length > static_cast(end - pos)) { + NDN_THROW(Error("Not enough bytes in the buffer to fully parse TLV")); + } + + BOOST_ASSERT(pos > buf); + uint64_t typeLengthSize = static_cast(pos - buf); + m_size = typeLengthSize + length; + + m_buffer = make_shared(buf, m_size); + m_begin = m_buffer->begin(); + m_end = m_valueEnd = m_buffer->end(); + m_valueBegin = m_begin + typeLengthSize; +} + +Block::Block(uint32_t type) + : m_type(type) + , m_size(tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(0)) +{ +} + +Block::Block(uint32_t type, ConstBufferPtr value) + : m_buffer(std::move(value)) + , m_begin(m_buffer->end()) + , m_end(m_buffer->end()) + , m_valueBegin(m_buffer->begin()) + , m_valueEnd(m_buffer->end()) + , m_type(type) +{ + m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size(); +} + +Block::Block(uint32_t type, const Block& value) + : m_buffer(value.m_buffer) + , m_begin(m_buffer->end()) + , m_end(m_buffer->end()) + , m_valueBegin(value.begin()) + , m_valueEnd(value.end()) + , m_type(type) +{ + m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size(); +} + +Block +Block::fromStream(std::istream& is) +{ + std::istream_iterator begin(is >> std::noskipws); + std::istream_iterator end; + + uint32_t type = tlv::readType(begin, end); + uint64_t length = tlv::readVarNumber(begin, end); + if (begin != end) { + is.putback(*begin); + } + + size_t tlSize = tlv::sizeOfVarNumber(type) + tlv::sizeOfVarNumber(length); + if (tlSize + length > MAX_SIZE_OF_BLOCK_FROM_STREAM) { + NDN_THROW(Error("TLV-LENGTH from stream exceeds limit")); + } + + EncodingBuffer eb(tlSize + length, length); + uint8_t* valueBuf = eb.buf(); + is.read(reinterpret_cast(valueBuf), length); + if (length != static_cast(is.gcount())) { + NDN_THROW(Error("Not enough bytes from stream to fully parse TLV")); + } + + eb.prependVarNumber(length); + eb.prependVarNumber(type); + + // TLV-VALUE is directly written into eb.buf(), eb.end() is not incremented, but eb.getBuffer() + // has the correct layout. + return Block(eb.getBuffer()); +} + +std::tuple +Block::fromBuffer(ConstBufferPtr buffer, size_t offset) +{ + auto begin = buffer->begin() + offset; + auto pos = begin; + + uint32_t type = 0; + bool isOk = tlv::readType(pos, buffer->end(), type); + if (!isOk) { + return std::make_tuple(false, Block()); + } + + uint64_t length = 0; + isOk = tlv::readVarNumber(pos, buffer->end(), length); + if (!isOk) { + return std::make_tuple(false, Block()); + } + // pos now points to TLV-VALUE + + if (length > static_cast(buffer->end() - pos)) { + return std::make_tuple(false, Block()); + } + + return std::make_tuple(true, Block(std::move(buffer), type, begin, pos + length, pos, pos + length)); +} + +std::tuple +Block::fromBuffer(const uint8_t* buf, size_t bufSize) +{ + const uint8_t* pos = buf; + const uint8_t* const end = buf + bufSize; + + uint32_t type = 0; + bool isOk = tlv::readType(pos, end, type); + if (!isOk) { + return std::make_tuple(false, Block()); + } + uint64_t length = 0; + isOk = tlv::readVarNumber(pos, end, length); + if (!isOk) { + return std::make_tuple(false, Block()); + } + // pos now points to TLV-VALUE + + if (length > static_cast(end - pos)) { + return std::make_tuple(false, Block()); + } + + size_t typeLengthSize = pos - buf; + auto b = make_shared(buf, pos + length); + return std::make_tuple(true, Block(b, type, b->begin(), b->end(), + b->begin() + typeLengthSize, b->end())); +} + +// ---- wire format ---- + +void +Block::reset() noexcept +{ + *this = {}; +} + +void +Block::resetWire() noexcept +{ + m_buffer.reset(); // discard underlying buffer by resetting shared_ptr + m_begin = m_end = m_valueBegin = m_valueEnd = {}; +} + +Buffer::const_iterator +Block::begin() const +{ + if (!hasWire()) + NDN_THROW(Error("Underlying wire buffer is empty")); + + return m_begin; +} + +Buffer::const_iterator +Block::end() const +{ + if (!hasWire()) + NDN_THROW(Error("Underlying wire buffer is empty")); + + return m_end; +} + +const uint8_t* +Block::wire() const +{ + if (!hasWire()) + NDN_THROW(Error("Underlying wire buffer is empty")); + + return &*m_begin; +} + +size_t +Block::size() const +{ + if (!isValid()) { + NDN_THROW(Error("Cannot determine size of invalid block")); + } + + return m_size; +} + +// ---- value ---- + +const uint8_t* +Block::value() const noexcept +{ + return hasValue() ? &*m_valueBegin : nullptr; +} + +size_t +Block::value_size() const noexcept +{ + return hasValue() ? static_cast(m_valueEnd - m_valueBegin) : 0; +} + +Block +Block::blockFromValue() const +{ + if (!hasValue()) + NDN_THROW(Error("Block has no TLV-VALUE")); + + return Block(*this, m_valueBegin, m_valueEnd, true); +} + +// ---- sub elements ---- + +void +Block::parse() const +{ + if (!m_elements.empty() || value_size() == 0) + return; + + Buffer::const_iterator begin = value_begin(); + Buffer::const_iterator end = value_end(); + + while (begin != end) { + Buffer::const_iterator pos = begin; + + uint32_t type = tlv::readType(pos, end); + uint64_t length = tlv::readVarNumber(pos, end); + if (length > static_cast(end - pos)) { + m_elements.clear(); + NDN_THROW(Error("TLV-LENGTH of sub-element of type " + to_string(type) + + " exceeds TLV-VALUE boundary of parent block")); + } + // pos now points to TLV-VALUE of sub element + + Buffer::const_iterator subEnd = pos + length; + m_elements.emplace_back(m_buffer, type, begin, subEnd, pos, subEnd); + + begin = subEnd; + } +} + +void +Block::encode() +{ + if (hasWire()) + return; + + EncodingEstimator estimator; + size_t estimatedSize = encode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + encode(buffer); +} + +size_t +Block::encode(EncodingEstimator& estimator) const +{ + if (hasValue()) { + return m_size; + } + + size_t len = encodeValue(estimator); + len += estimator.prependVarNumber(len); + len += estimator.prependVarNumber(m_type); + return len; +} + +size_t +Block::encodeValue(EncodingEstimator& estimator) const +{ + size_t len = 0; + for (const Block& element : m_elements | boost::adaptors::reversed) { + len += element.encode(estimator); + } + return len; +} + +size_t +Block::encode(EncodingBuffer& encoder) +{ + size_t len = 0; + m_end = encoder.begin(); + if (hasValue()) { + len += encoder.prependRange(m_valueBegin, m_valueEnd); + } + else { + for (Block& element : m_elements | boost::adaptors::reversed) { + len += element.encode(encoder); + } + } + m_valueEnd = m_end; + m_valueBegin = encoder.begin(); + + len += encoder.prependVarNumber(len); + len += encoder.prependVarNumber(m_type); + m_begin = encoder.begin(); + + m_buffer = encoder.getBuffer(); + m_size = len; + return len; +} + +const Block& +Block::get(uint32_t type) const +{ + auto it = this->find(type); + if (it != m_elements.end()) { + return *it; + } + + NDN_THROW(Error("No sub-element of type " + to_string(type) + + " found in block of type " + to_string(m_type))); +} + +Block::element_const_iterator +Block::find(uint32_t type) const +{ + return std::find_if(m_elements.begin(), m_elements.end(), + [type] (const Block& subBlock) { return subBlock.type() == type; }); +} + +void +Block::remove(uint32_t type) +{ + resetWire(); + + auto it = std::remove_if(m_elements.begin(), m_elements.end(), + [type] (const Block& subBlock) { return subBlock.type() == type; }); + m_elements.erase(it, m_elements.end()); +} + +Block::element_iterator +Block::erase(Block::element_const_iterator position) +{ + resetWire(); + return m_elements.erase(position); +} + +Block::element_iterator +Block::erase(Block::element_const_iterator first, Block::element_const_iterator last) +{ + resetWire(); + return m_elements.erase(first, last); +} + +void +Block::push_back(const Block& element) +{ + resetWire(); + m_elements.push_back(element); +} + +Block::element_iterator +Block::insert(Block::element_const_iterator pos, const Block& element) +{ + resetWire(); + return m_elements.insert(pos, element); +} + +// ---- misc ---- + +Block::operator boost::asio::const_buffer() const +{ + return boost::asio::const_buffer(wire(), size()); +} + +bool +operator==(const Block& lhs, const Block& rhs) +{ + return lhs.type() == rhs.type() && + lhs.value_size() == rhs.value_size() && + (lhs.value_size() == 0 || + std::memcmp(lhs.value(), rhs.value(), lhs.value_size()) == 0); +} + +std::ostream& +operator<<(std::ostream& os, const Block& block) +{ + auto oldFmt = os.flags(std::ios_base::dec); + + if (!block.isValid()) { + os << "[invalid]"; + } + else if (!block.m_elements.empty()) { + EncodingEstimator estimator; + size_t tlvLength = block.encodeValue(estimator); + os << block.type() << '[' << tlvLength << "]={"; + std::copy(block.elements_begin(), block.elements_end(), make_ostream_joiner(os, ',')); + os << '}'; + } + else if (block.value_size() > 0) { + os << block.type() << '[' << block.value_size() << "]="; + printHex(os, block.value(), block.value_size(), true); + } + else { + os << block.type() << "[empty]"; + } + + os.flags(oldFmt); + return os; +} + +Block +operator "" _block(const char* input, std::size_t len) +{ + namespace t = security::transform; + t::StepSource ss; + OBufferStream os; + ss >> t::hexDecode() >> t::streamSink(os); + + for (const char* end = input + len; input != end; ++input) { + if (std::strchr("0123456789ABCDEF", *input) != nullptr) { + ss.write(reinterpret_cast(input), 1); + } + } + + try { + ss.end(); + } + catch (const t::Error&) { + NDN_THROW(std::invalid_argument("Input has odd number of hexadecimal digits")); + } + + return Block(os.buf()); +} + +} // namespace ndn diff --git a/ndn-cxx/encoding/block.hpp b/ndn-cxx/encoding/block.hpp new file mode 100644 index 000000000..51f9f4d6d --- /dev/null +++ b/ndn-cxx/encoding/block.hpp @@ -0,0 +1,521 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Alexander Afanasyev + */ + +#ifndef NDN_ENCODING_BLOCK_HPP +#define NDN_ENCODING_BLOCK_HPP + +#include "ndn-cxx/encoding/buffer.hpp" +#include "ndn-cxx/encoding/encoding-buffer-fwd.hpp" +#include "ndn-cxx/encoding/tlv.hpp" + +namespace boost { +namespace asio { +class const_buffer; +} // namespace asio +} // namespace boost + +namespace ndn { + +/** @brief Represents a TLV element of NDN packet format + * @sa https://named-data.net/doc/NDN-packet-spec/current/ + */ +class Block +{ +public: + using element_container = std::vector; + using element_iterator = element_container::iterator; + using element_const_iterator = element_container::const_iterator; + + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + +public: // construction, assignment + /** @brief Create an invalid Block + * @post `isValid() == false` + */ + Block(); + + /** @brief Copy constructor + */ + Block(const Block&); + + /** @brief Copy assignment operator + */ + Block& + operator=(const Block&); + + /** @brief Move constructor + */ + Block(Block&&) noexcept; + + /** @brief Move assignment operator + */ + Block& + operator=(Block&&) noexcept; + + /** @brief Parse Block from an EncodingBuffer + * @param buffer an EncodingBuffer containing one TLV element + * @throw tlv::Error Type-Length parsing fails, or TLV-LENGTH does not match size of TLV-VALUE + */ + explicit + Block(const EncodingBuffer& buffer); + + /** @brief Parse Block from a wire Buffer + * @param buffer a Buffer containing one TLV element + * @note This constructor takes shared ownership of @p buffer. + * @throw tlv::Error Type-Length parsing fails, or TLV-LENGTH does not match size of TLV-VALUE + */ + explicit + Block(const ConstBufferPtr& buffer); + + /** @brief Parse Block within boundaries of a wire Buffer + * @param buffer a Buffer containing a TLV element at [@p begin,@p end) + * @param begin begin position of the TLV element within @p buffer + * @param end end position of the TLV element within @p buffer + * @param verifyLength if true, check TLV-LENGTH equals size of TLV-VALUE + * @throw std::invalid_argument @p buffer is empty, or [@p begin,@p end) range is not within @p buffer + * @throw tlv::Error Type-Length parsing fails, or TLV-LENGTH does not match size of TLV-VALUE + * @note This overload automatically detects TLV-TYPE and position of TLV-VALUE. + */ + Block(ConstBufferPtr buffer, Buffer::const_iterator begin, Buffer::const_iterator end, + bool verifyLength = true); + + /** @brief Parse Block within boundaries of an existing Block, reusing underlying wire Buffer + * @param block a Block whose buffer contains a TLV element at [@p begin,@p end) + * @param begin begin position of the TLV element within @p block + * @param end end position of the TLV element within @p block + * @param verifyLength if true, check TLV-LENGTH equals size of TLV-VALUE + * @throw std::invalid_argument [@p begin,@p end) range is not within @p block + * @throw tlv::Error Type-Length parsing fails, or TLV-LENGTH does not match size of TLV-VALUE + */ + Block(const Block& block, Buffer::const_iterator begin, Buffer::const_iterator end, + bool verifyLength = true); + + /** @brief Create a Block from a wire Buffer without parsing + * @param buffer a Buffer containing a TLV element at [@p begin,@p end) + * @param type TLV-TYPE + * @param begin begin position of the TLV element within @p buffer + * @param end end position of the TLV element within @p buffer + * @param valueBegin begin position of TLV-VALUE within @p buffer + * @param valueEnd end position of TLV-VALUE within @p buffer + */ + Block(ConstBufferPtr buffer, uint32_t type, + Buffer::const_iterator begin, Buffer::const_iterator end, + Buffer::const_iterator valueBegin, Buffer::const_iterator valueEnd); + + /** @brief Parse Block from a raw buffer + * @param buf pointer to the first octet of a TLV element + * @param bufSize size of the raw buffer; may be greater than the actual size of the TLV element + * @throw tlv::Error Type-Length parsing fails, or size of TLV-VALUE exceeds @p bufSize + * @note This overload copies the TLV element octets into an internal wire buffer. + */ + Block(const uint8_t* buf, size_t bufSize); + + /** @brief Create a zero-length Block with the specified TLV-TYPE + * @param type TLV-TYPE + */ + explicit + Block(uint32_t type); + + /** @brief Create a Block with the specified TLV-TYPE and TLV-VALUE + * @param type TLV-TYPE + * @param value a Buffer containing the TLV-VALUE, must not be nullptr + */ + Block(uint32_t type, ConstBufferPtr value); + + /** @brief Create a Block with the specified TLV-TYPE and TLV-VALUE + * @param type TLV-TYPE + * @param value a Block to be nested as TLV-VALUE, must be valid + */ + Block(uint32_t type, const Block& value); + + /** @brief Parse Block from an input stream + * @throw tlv::Error TLV-LENGTH is zero or exceeds upper bound + * @warning If decoding fails, bytes are still consumed from the input stream. + */ + static Block + fromStream(std::istream& is); + + /** @brief Try to parse Block from a wire buffer + * @param buffer a Buffer containing a TLV element at offset @p offset + * @param offset begin position of the TLV element within @p buffer + * @note This function does not throw upon decoding failure. + * @return `true` and the parsed Block if parsing succeeds; otherwise `false` and an invalid Block + */ + NDN_CXX_NODISCARD static std::tuple + fromBuffer(ConstBufferPtr buffer, size_t offset); + + /** @brief Try to parse Block from a raw buffer + * @param buf pointer to the first octet of a TLV element + * @param bufSize size of the raw buffer; may be greater than the actual size of the TLV element + * @note This function does not throw upon decoding failure. + * @note This overload copies the TLV element octets into an internal wire buffer. + * @return `true` and the parsed Block if parsing succeeds; otherwise `false` and an invalid Block + */ + NDN_CXX_NODISCARD static std::tuple + fromBuffer(const uint8_t* buf, size_t bufSize); + +public: // wire format + /** @brief Check if the Block is valid + * + * A Block is valid unless it has an invalid TLV-TYPE or is default-constructed. + * In particular, a Block with zero-length TLV-VALUE *is* valid. + */ + bool + isValid() const noexcept + { + return m_type != tlv::Invalid; + } + + /** @brief Check if the Block is empty + * + * A Block is considered empty *iff* it is not valid, i.e., isValid() returns false. + * + * @warning Note that an empty Block is *not* the same as a valid but zero-length Block. + * @deprecated Use Block::isValid() + */ + NDN_CXX_NODISCARD bool + empty() const noexcept + { + return !isValid(); + } + + /** @brief Reset the Block to a default-constructed state + * + * Equivalent to `*this = Block()`. + * + * @post `isValid() == false` + * @sa resetWire() + */ + void + reset() noexcept; + + /** @brief Reset wire buffer but keep TLV-TYPE and sub-elements (if any) + * @post `hasWire() == false` + * @post `hasValue() == false` + * @sa reset() + */ + void + resetWire() noexcept; + + /** @brief Check if the Block contains a fully encoded wire representation + * + * A Block has a fully encoded wire if the underlying buffer exists and contains the full + * Type-Length-Value instead of just the TLV-VALUE field. + */ + bool + hasWire() const noexcept + { + return m_buffer != nullptr && m_begin != m_end; + } + + /** @brief Get begin iterator of encoded wire + * @pre `hasWire() == true` + */ + Buffer::const_iterator + begin() const; + + /** @brief Get end iterator of encoded wire + * @pre `hasWire() == true` + */ + Buffer::const_iterator + end() const; + + /** @brief Return a raw pointer to the beginning of the encoded wire + * @pre `hasWire() == true` + * @sa value() + */ + const uint8_t* + wire() const; + + /** @brief Return the size of the encoded wire, i.e. of the whole TLV + * @pre `isValid() == true` + * @sa value_size() + */ + size_t + size() const; + + /** @brief Get underlying buffer + */ + ConstBufferPtr + getBuffer() const + { + return m_buffer; + } + +public: // type and value + /** @brief Return the TLV-TYPE of the Block + * @note This will return tlv::Invalid if isValid() is false. + */ + uint32_t + type() const + { + return m_type; + } + + /** @brief Check if the Block has a non-empty TLV-VALUE + * + * This property reflects whether the underlying buffer contains a TLV-VALUE. If this is false, + * TLV-VALUE has zero-length. If this is true, TLV-VALUE may be zero-length. + * + * @sa value_size() + */ + bool + hasValue() const noexcept + { + return m_buffer != nullptr; + } + + /** @brief Get begin iterator of TLV-VALUE + * @pre `hasValue() == true` + */ + Buffer::const_iterator + value_begin() const + { + return m_valueBegin; + } + + /** @brief Get end iterator of TLV-VALUE + * @pre `hasValue() == true` + */ + Buffer::const_iterator + value_end() const + { + return m_valueEnd; + } + + /** @brief Return a raw pointer to the beginning of TLV-VALUE + * @sa wire() + */ + const uint8_t* + value() const noexcept; + + /** @brief Return the size of TLV-VALUE, aka TLV-LENGTH + * @sa size() + */ + size_t + value_size() const noexcept; + + Block + blockFromValue() const; + +public: // sub-elements + /** @brief Parse TLV-VALUE into sub-elements + * @post elements() reflects sub-elements found in TLV-VALUE + * @throw tlv::Error TLV-VALUE is not a sequence of TLV elements + * @note This method does not perform recursive parsing. + * @note This method has no effect if elements() is already populated. + * @note This method is not really const, but it does not modify any data. + */ + void + parse() const; + + /** @brief Encode sub-elements into TLV-VALUE + * @post TLV-VALUE contains sub-elements from elements() + */ + void + encode(); + + /** @brief Return the first sub-element of the specified TLV-TYPE + * @pre parse() has been executed + * @throw tlv::Error a sub-element of the specified type does not exist + */ + const Block& + get(uint32_t type) const; + + /** @brief Find the first sub-element of the specified TLV-TYPE + * @pre parse() has been executed + * @return iterator in elements() to the found sub-element, or elements_end() if no such + * sub-element exists in elements() + */ + element_const_iterator + find(uint32_t type) const; + + /** @brief Remove all sub-elements of the specified TLV-TYPE + * @pre parse() has been executed + * @post `find(type) == elements_end()` + */ + void + remove(uint32_t type); + + /** @brief Erase a sub-element + */ + element_iterator + erase(element_const_iterator position); + + /** @brief Erase a range of sub-elements + */ + element_iterator + erase(element_const_iterator first, element_const_iterator last); + + /** @brief Append a sub-element + */ + void + push_back(const Block& element); + + /** @brief Insert a sub-element + * @param pos position of the new sub-element + * @param element new sub-element to insert + * @return iterator in elements() to the new sub-element + */ + element_iterator + insert(element_const_iterator pos, const Block& element); + + /** @brief Get container of sub-elements + * @pre parse() has been executed + */ + const element_container& + elements() const + { + return m_elements; + } + + /** @brief Equivalent to elements().begin() + */ + element_const_iterator + elements_begin() const + { + return m_elements.begin(); + } + + /** @brief Equivalent to elements().end() + */ + element_const_iterator + elements_end() const + { + return m_elements.end(); + } + + /** @brief Equivalent to elements().size() + */ + size_t + elements_size() const + { + return m_elements.size(); + } + +public: // misc + /** @brief Implicit conversion to `boost::asio::const_buffer` + */ + operator boost::asio::const_buffer() const; + +private: + /** @brief Estimate Block size as if sub-elements are encoded into TLV-VALUE + */ + size_t + encode(EncodingEstimator& estimator) const; + + /** @brief Estimate TLV-LENGTH as if sub-elements are encoded into TLV-VALUE + */ + size_t + encodeValue(EncodingEstimator& estimator) const; + + /** @brief Encode sub-elements into TLV-VALUE and prepend Block to encoder + * @post TLV-VALUE contains sub-elements from elements() + * @post internal buffer and iterators point to Encoder's buffer + */ + size_t + encode(EncodingBuffer& encoder); + +protected: + /** @brief Underlying buffer storing TLV-VALUE and possibly TLV-TYPE and TLV-LENGTH fields + * + * If m_buffer is nullptr, this is an invalid or zero-length Block with TLV-TYPE given in m_type. + * Otherwise, + * - [m_valueBegin, m_valueEnd) point to the TLV-VALUE inside m_buffer. + * - If m_begin != m_end, [m_begin, m_end) point to Type-Length-Value of this Block in m_buffer. + * Otherwise, m_buffer does not contain TLV-TYPE and TLV-LENGTH fields. + */ + shared_ptr m_buffer; + Buffer::const_iterator m_begin; ///< @sa m_buffer + Buffer::const_iterator m_end; ///< @sa m_buffer + + Buffer::const_iterator m_valueBegin; ///< @sa m_buffer + Buffer::const_iterator m_valueEnd; ///< @sa m_buffer + + uint32_t m_type = tlv::Invalid; ///< TLV-TYPE + + /** @brief Total size including Type-Length-Value + * + * This field is meaningful only if isValid() is true. + */ + size_t m_size = 0; + + /** @brief Contains the sub-elements + * + * This field is valid only if parse() has been executed. + */ + mutable element_container m_elements; + + /** @brief Print @p block to @p os. + * + * Default-constructed Block is printed as: `[invalid]`. + * Zero-length Block is printed as: `TT[empty]`, where TT is TLV-TYPE in decimal. + * Non-zero-length Block on which parse() has not been called is printed as: `TT[LL]=VVVV`, + * where LL is TLV-LENGTH in decimal, and VVVV is TLV-VALUE in hexadecimal. + * Block on which parse() has been called is printed as: `TT[LL]={SUB,SUB}`, + * where each SUB is a sub-element printed using this format. + */ + friend std::ostream& + operator<<(std::ostream& os, const Block& block); +}; + +inline +Block::Block(Block&&) noexcept = default; + +inline Block& +Block::operator=(Block&&) noexcept = default; + +/** @brief Compare whether two Blocks have same TLV-TYPE, TLV-LENGTH, and TLV-VALUE + */ +bool +operator==(const Block& lhs, const Block& rhs); + +inline bool +operator!=(const Block& lhs, const Block& rhs) +{ + return !(lhs == rhs); +} + +/** @brief Construct a Block from hexadecimal @p input. + * @param input a string containing hexadecimal bytes and comments. + * 0-9 and upper-case A-F are input; all other characters are comments. + * @param len length of @p input. + * @throw std::invalid_argument input is empty or has an odd number of hexadecimal digits. + * @throw tlv::Error @p input cannot be parsed into a valid Block. + * + * Example + * @code + * Block nameBlock = "0706 080141 080142"_block; + * Block nackBlock = "FD032005 reason(no-route)=FD03210196"_block; + * @endcode + */ +Block +operator "" _block(const char* input, std::size_t len); + +} // namespace ndn + +#endif // NDN_ENCODING_BLOCK_HPP diff --git a/src/encoding/buffer-stream.cpp b/ndn-cxx/encoding/buffer-stream.cpp similarity index 93% rename from src/encoding/buffer-stream.cpp rename to ndn-cxx/encoding/buffer-stream.cpp index ec501e6a5..bf363c54f 100644 --- a/src/encoding/buffer-stream.cpp +++ b/ndn-cxx/encoding/buffer-stream.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,7 +19,7 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "buffer-stream.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" namespace ndn { namespace detail { diff --git a/src/encoding/buffer-stream.hpp b/ndn-cxx/encoding/buffer-stream.hpp similarity index 95% rename from src/encoding/buffer-stream.hpp rename to ndn-cxx/encoding/buffer-stream.hpp index e7dc60f89..bd865c0c3 100644 --- a/src/encoding/buffer-stream.hpp +++ b/ndn-cxx/encoding/buffer-stream.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -24,7 +24,7 @@ #ifndef NDN_ENCODING_BUFFER_STREAM_HPP #define NDN_ENCODING_BUFFER_STREAM_HPP -#include "buffer.hpp" +#include "ndn-cxx/encoding/buffer.hpp" #include #include diff --git a/ndn-cxx/encoding/buffer.hpp b/ndn-cxx/encoding/buffer.hpp new file mode 100644 index 000000000..8f4d3dbce --- /dev/null +++ b/ndn-cxx/encoding/buffer.hpp @@ -0,0 +1,130 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Alexander Afanasyev + */ + +#ifndef NDN_ENCODING_BUFFER_HPP +#define NDN_ENCODING_BUFFER_HPP + +#include "ndn-cxx/detail/common.hpp" + +#include + +namespace ndn { + +/** + * @brief General-purpose automatically managed/resized buffer + * + * In most respect, the Buffer class is equivalent to a `std::vector`, and it in fact + * uses the latter as a base class. In addition to that, it provides the get() helper method + * that automatically casts the returned pointer to the requested type. + */ +class Buffer : public std::vector +{ +public: + /** @brief Creates an empty Buffer + */ + Buffer() = default; + + /** @brief Copy constructor + */ + Buffer(const Buffer&); + + /** @brief Copy assignment operator + */ + Buffer& + operator=(const Buffer&); + + /** @brief Move constructor + */ + Buffer(Buffer&&) noexcept; + + /** @brief Move assignment operator + */ + Buffer& + operator=(Buffer&&) noexcept; + + /** @brief Creates a Buffer with pre-allocated size + * @param size size of the Buffer to be allocated + */ + explicit + Buffer(size_t size) + : std::vector(size, 0) + { + } + + /** @brief Creates a Buffer by copying contents from a raw buffer + * @param buf const pointer to buffer to copy + * @param length length of the buffer to copy + */ + Buffer(const void* buf, size_t length) + : std::vector(reinterpret_cast(buf), + reinterpret_cast(buf) + length) + { + } + + /** @brief Creates a Buffer by copying the elements of the range [first, last) + * @param first an input iterator to the first element to copy + * @param last an input iterator to the element immediately following the last element to copy + */ + template + Buffer(InputIt first, InputIt last) + : std::vector(first, last) + { + } + + /** @return pointer to the first byte of the buffer, cast to the requested type T + */ + template + T* + get() noexcept + { + return reinterpret_cast(data()); + } + + /** @return const pointer to the first byte of the buffer, cast to the requested type T + */ + template + const T* + get() const noexcept + { + return reinterpret_cast(data()); + } +}; + +inline +Buffer::Buffer(const Buffer&) = default; + +inline Buffer& +Buffer::operator=(const Buffer&) = default; + +inline +Buffer::Buffer(Buffer&&) noexcept = default; + +inline Buffer& +Buffer::operator=(Buffer&&) noexcept = default; + +using BufferPtr = shared_ptr; +using ConstBufferPtr = shared_ptr; + +} // namespace ndn + +#endif // NDN_ENCODING_BUFFER_HPP diff --git a/src/encoding/encoder.cpp b/ndn-cxx/encoding/encoder.cpp similarity index 81% rename from src/encoding/encoder.cpp rename to ndn-cxx/encoding/encoder.cpp index 12b5ea1b1..2323c2649 100644 --- a/src/encoding/encoder.cpp +++ b/ndn-cxx/encoding/encoder.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,18 +19,21 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "encoder.hpp" +#include "ndn-cxx/encoding/encoder.hpp" + +#include namespace ndn { namespace encoding { -Encoder::Encoder(size_t totalReserve/* = MAX_NDN_PACKET_SIZE*/, size_t reserveFromBack/* = 400*/) - : m_buffer(new Buffer(totalReserve)) +namespace endian = boost::endian; + +Encoder::Encoder(size_t totalReserve, size_t reserveFromBack) + : m_buffer(make_shared(totalReserve)) { m_begin = m_end = m_buffer->end() - (reserveFromBack < totalReserve ? reserveFromBack : 0); } - Encoder::Encoder(const Block& block) : m_buffer(const_pointer_cast(block.getBuffer())) , m_begin(m_buffer->begin() + (block.begin() - m_buffer->begin())) @@ -38,30 +41,24 @@ Encoder::Encoder(const Block& block) { } -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - void Encoder::reserveBack(size_t size) { - if ((m_end + size) > m_buffer->end()) + if (m_end + size > m_buffer->end()) reserve(m_buffer->size() * 2 + size, false); } void Encoder::reserveFront(size_t size) { - if ((m_buffer->begin() + size) > m_begin) + if (m_buffer->begin() + size > m_begin) reserve(m_buffer->size() * 2 + size, true); } - Block -Encoder::block(bool verifyLength/* = true*/) const +Encoder::block(bool verifyLength) const { - return Block(m_buffer, - m_begin, m_end, - verifyLength); + return Block(m_buffer, m_begin, m_end, verifyLength); } void @@ -97,9 +94,6 @@ Encoder::reserve(size_t size, bool addInFront) } } -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - size_t Encoder::prependByte(uint8_t value) { @@ -120,7 +114,6 @@ Encoder::appendByte(uint8_t value) return 1; } - size_t Encoder::prependByteArray(const uint8_t* array, size_t length) { @@ -141,7 +134,6 @@ Encoder::appendByteArray(const uint8_t* array, size_t length) return length; } - size_t Encoder::prependVarNumber(uint64_t varNumber) { @@ -150,19 +142,19 @@ Encoder::prependVarNumber(uint64_t varNumber) return 1; } else if (varNumber <= std::numeric_limits::max()) { - uint16_t value = htobe16(static_cast(varNumber)); + uint16_t value = endian::native_to_big(static_cast(varNumber)); prependByteArray(reinterpret_cast(&value), 2); prependByte(253); return 3; } else if (varNumber <= std::numeric_limits::max()) { - uint32_t value = htobe32(static_cast(varNumber)); + uint32_t value = endian::native_to_big(static_cast(varNumber)); prependByteArray(reinterpret_cast(&value), 4); prependByte(254); return 5; } else { - uint64_t value = htobe64(varNumber); + uint64_t value = endian::native_to_big(varNumber); prependByteArray(reinterpret_cast(&value), 8); prependByte(255); return 9; @@ -178,25 +170,24 @@ Encoder::appendVarNumber(uint64_t varNumber) } else if (varNumber <= std::numeric_limits::max()) { appendByte(253); - uint16_t value = htobe16(static_cast(varNumber)); + uint16_t value = endian::native_to_big(static_cast(varNumber)); appendByteArray(reinterpret_cast(&value), 2); return 3; } else if (varNumber <= std::numeric_limits::max()) { appendByte(254); - uint32_t value = htobe32(static_cast(varNumber)); + uint32_t value = endian::native_to_big(static_cast(varNumber)); appendByteArray(reinterpret_cast(&value), 4); return 5; } else { appendByte(255); - uint64_t value = htobe64(varNumber); + uint64_t value = endian::native_to_big(varNumber); appendByteArray(reinterpret_cast(&value), 8); return 9; } } - size_t Encoder::prependNonNegativeInteger(uint64_t varNumber) { @@ -204,15 +195,15 @@ Encoder::prependNonNegativeInteger(uint64_t varNumber) return prependByte(static_cast(varNumber)); } else if (varNumber <= std::numeric_limits::max()) { - uint16_t value = htobe16(static_cast(varNumber)); + uint16_t value = endian::native_to_big(static_cast(varNumber)); return prependByteArray(reinterpret_cast(&value), 2); } else if (varNumber <= std::numeric_limits::max()) { - uint32_t value = htobe32(static_cast(varNumber)); + uint32_t value = endian::native_to_big(static_cast(varNumber)); return prependByteArray(reinterpret_cast(&value), 4); } else { - uint64_t value = htobe64(varNumber); + uint64_t value = endian::native_to_big(varNumber); return prependByteArray(reinterpret_cast(&value), 8); } } @@ -224,15 +215,15 @@ Encoder::appendNonNegativeInteger(uint64_t varNumber) return appendByte(static_cast(varNumber)); } else if (varNumber <= std::numeric_limits::max()) { - uint16_t value = htobe16(static_cast(varNumber)); + uint16_t value = endian::native_to_big(static_cast(varNumber)); return appendByteArray(reinterpret_cast(&value), 2); } else if (varNumber <= std::numeric_limits::max()) { - uint32_t value = htobe32(static_cast(varNumber)); + uint32_t value = endian::native_to_big(static_cast(varNumber)); return appendByteArray(reinterpret_cast(&value), 4); } else { - uint64_t value = htobe64(varNumber); + uint64_t value = endian::native_to_big(varNumber); return appendByteArray(reinterpret_cast(&value), 8); } } diff --git a/src/encoding/encoder.hpp b/ndn-cxx/encoding/encoder.hpp similarity index 89% rename from src/encoding/encoder.hpp rename to ndn-cxx/encoding/encoder.hpp index 28b2fa121..773d87a2a 100644 --- a/src/encoding/encoder.hpp +++ b/ndn-cxx/encoding/encoder.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,8 +22,7 @@ #ifndef NDN_ENCODING_ENCODER_HPP #define NDN_ENCODING_ENCODER_HPP -#include "../common.hpp" -#include "block.hpp" +#include "ndn-cxx/encoding/block.hpp" namespace ndn { namespace encoding { @@ -33,22 +32,9 @@ namespace encoding { * Interface of this class (mostly) matches interface of Estimator class * @sa Estimator */ -class Encoder +class Encoder : noncopyable { public: // common interface between Encoder and Estimator - /** - * @brief Create instance of the encoder with the specified reserved sizes - * @param totalReserve initial buffer size to reserve - * @param reserveFromBack number of bytes to reserve for append* operations - */ - explicit - Encoder(size_t totalReserve = MAX_NDN_PACKET_SIZE, size_t reserveFromBack = 400); - - Encoder(const Encoder&) = delete; - - Encoder& - operator=(const Encoder&) = delete; - /** * @brief Prepend a byte */ @@ -140,9 +126,17 @@ class Encoder appendBlock(const Block& block); public: // unique interface to the Encoder - typedef Buffer::value_type value_type; - typedef Buffer::iterator iterator; - typedef Buffer::const_iterator const_iterator; + using value_type = Buffer::value_type; + using iterator = Buffer::iterator; + using const_iterator = Buffer::const_iterator; + + /** + * @brief Create instance of the encoder with the specified reserved sizes + * @param totalReserve initial buffer size to reserve + * @param reserveFromBack number of bytes to reserve for append* operations + */ + explicit + Encoder(size_t totalReserve = MAX_NDN_PACKET_SIZE, size_t reserveFromBack = 400); /** * @brief Create EncodingBlock from existing block @@ -189,16 +183,15 @@ class Encoder * @brief Get size of the underlying buffer */ size_t - capacity() const; + capacity() const noexcept; /** * @brief Get underlying buffer */ shared_ptr - getBuffer(); + getBuffer() const noexcept; public: // accessors - /** * @brief Get an iterator pointing to the first byte of the encoded buffer */ @@ -217,6 +210,9 @@ class Encoder const_iterator begin() const; + /** + * @brief Get an iterator pointing to the past-the-end byte of the encoded buffer + */ const_iterator end() const; @@ -233,10 +229,10 @@ class Encoder buf() const; /** - * @brief Get size of the encoded buffer + * @brief Get the size of the encoded buffer */ size_t - size() const; + size() const noexcept; /** * @brief Create Block from the underlying buffer @@ -257,21 +253,20 @@ class Encoder iterator m_end; }; - inline size_t -Encoder::size() const +Encoder::size() const noexcept { return m_end - m_begin; } inline shared_ptr -Encoder::getBuffer() +Encoder::getBuffer() const noexcept { return m_buffer; } inline size_t -Encoder::capacity() const +Encoder::capacity() const noexcept { return m_buffer->size(); } @@ -313,9 +308,12 @@ Encoder::buf() const } template -inline size_t +size_t Encoder::prependRange(Iterator first, Iterator last) { + using ValueType = typename std::iterator_traits::value_type; + static_assert(sizeof(ValueType) == 1 && !std::is_same::value, ""); + size_t length = std::distance(first, last); reserveFront(length); @@ -324,11 +322,13 @@ Encoder::prependRange(Iterator first, Iterator last) return length; } - template -inline size_t +size_t Encoder::appendRange(Iterator first, Iterator last) { + using ValueType = typename std::iterator_traits::value_type; + static_assert(sizeof(ValueType) == 1 && !std::is_same::value, ""); + size_t length = std::distance(first, last); reserveBack(length); @@ -337,7 +337,6 @@ Encoder::appendRange(Iterator first, Iterator last) return length; } - } // namespace encoding } // namespace ndn diff --git a/ndn-cxx/encoding/encoding-buffer-fwd.hpp b/ndn-cxx/encoding/encoding-buffer-fwd.hpp new file mode 100644 index 000000000..1222a5bd4 --- /dev/null +++ b/ndn-cxx/encoding/encoding-buffer-fwd.hpp @@ -0,0 +1,61 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_ENCODING_ENCODING_BUFFER_FWD_HPP +#define NDN_ENCODING_ENCODING_BUFFER_FWD_HPP + +#include "ndn-cxx/detail/common.hpp" + +namespace ndn { +namespace encoding { + +enum Tag { + EncoderTag = true, ///< Tag for EncodingImpl to indicate that Encoder is requested + EstimatorTag = false ///< Tag for EncodingImpl to indicate that Estimator is requested +}; + +template +class EncodingImpl; + +using EncodingBuffer = EncodingImpl; +using EncodingEstimator = EncodingImpl; + +} // namespace encoding + +using encoding::EncodingImpl; +using encoding::EncodingBuffer; +using encoding::EncodingEstimator; + +} // namespace ndn + +#define NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(ClassName) \ + extern template size_t \ + ClassName::wireEncode<::ndn::encoding::EncoderTag>(::ndn::EncodingBuffer&) const; \ + extern template size_t \ + ClassName::wireEncode<::ndn::encoding::EstimatorTag>(::ndn::EncodingEstimator&) const \ + +#define NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(ClassName) \ + template size_t \ + ClassName::wireEncode<::ndn::encoding::EncoderTag>(::ndn::EncodingBuffer&) const; \ + template size_t \ + ClassName::wireEncode<::ndn::encoding::EstimatorTag>(::ndn::EncodingEstimator&) const \ + +#endif // NDN_ENCODING_ENCODING_BUFFER_FWD_HPP diff --git a/src/encoding/encoding-buffer.hpp b/ndn-cxx/encoding/encoding-buffer.hpp similarity index 77% rename from src/encoding/encoding-buffer.hpp rename to ndn-cxx/encoding/encoding-buffer.hpp index 4f364fe1f..60b334bce 100644 --- a/src/encoding/encoding-buffer.hpp +++ b/ndn-cxx/encoding/encoding-buffer.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,19 +22,18 @@ #ifndef NDN_ENCODING_ENCODING_BUFFER_HPP #define NDN_ENCODING_ENCODING_BUFFER_HPP -#include "../common.hpp" -#include "encoding-buffer-fwd.hpp" -#include "encoder.hpp" -#include "estimator.hpp" +#include "ndn-cxx/encoding/encoding-buffer-fwd.hpp" +#include "ndn-cxx/encoding/encoder.hpp" +#include "ndn-cxx/encoding/estimator.hpp" namespace ndn { namespace encoding { /** - * @brief EncodingImpl specialization for real TLV encoding + * @brief EncodingImpl specialization for actual TLV encoding */ template<> -class EncodingImpl : public encoding::Encoder +class EncodingImpl : public Encoder { public: explicit @@ -51,15 +50,14 @@ class EncodingImpl : public encoding::Encoder }; /** - * @brief EncodingImpl specialization TLV size estimation + * @brief EncodingImpl specialization for TLV size estimation */ template<> -class EncodingImpl : public encoding::Estimator +class EncodingImpl : public Estimator { public: explicit EncodingImpl(size_t totalReserve = 0, size_t totalFromBack = 0) - : Estimator(totalReserve, totalFromBack) { } }; diff --git a/ndn-cxx/encoding/estimator.cpp b/ndn-cxx/encoding/estimator.cpp new file mode 100644 index 000000000..bd1fc9aee --- /dev/null +++ b/ndn-cxx/encoding/estimator.cpp @@ -0,0 +1,107 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/encoding/estimator.hpp" + +namespace ndn { +namespace encoding { + +size_t +Estimator::prependVarNumber(uint64_t varNumber) const noexcept +{ + if (varNumber < 253) { + return 1; + } + else if (varNumber <= std::numeric_limits::max()) { + return 3; + } + else if (varNumber <= std::numeric_limits::max()) { + return 5; + } + else { + return 9; + } +} + +size_t +Estimator::appendVarNumber(uint64_t varNumber) const noexcept +{ + return prependVarNumber(varNumber); +} + +size_t +Estimator::prependNonNegativeInteger(uint64_t varNumber) const noexcept +{ + if (varNumber <= std::numeric_limits::max()) { + return 1; + } + else if (varNumber <= std::numeric_limits::max()) { + return 2; + } + else if (varNumber <= std::numeric_limits::max()) { + return 4; + } + else { + return 8; + } +} + +size_t +Estimator::appendNonNegativeInteger(uint64_t varNumber) const noexcept +{ + return prependNonNegativeInteger(varNumber); +} + +size_t +Estimator::prependByteArrayBlock(uint32_t type, const uint8_t* array, size_t arraySize) const noexcept +{ + size_t totalLength = arraySize; + totalLength += prependVarNumber(arraySize); + totalLength += prependVarNumber(type); + + return totalLength; +} + +size_t +Estimator::appendByteArrayBlock(uint32_t type, const uint8_t* array, size_t arraySize) const noexcept +{ + return prependByteArrayBlock(type, array, arraySize); +} + +size_t +Estimator::prependBlock(const Block& block) const +{ + if (block.hasWire()) { + return block.size(); + } + else { + return prependByteArrayBlock(block.type(), block.value(), block.value_size()); + } +} + +size_t +Estimator::appendBlock(const Block& block) const +{ + return prependBlock(block); +} + +} // namespace encoding +} // namespace ndn diff --git a/ndn-cxx/encoding/estimator.hpp b/ndn-cxx/encoding/estimator.hpp new file mode 100644 index 000000000..c564cb09d --- /dev/null +++ b/ndn-cxx/encoding/estimator.hpp @@ -0,0 +1,150 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_ENCODING_ESTIMATOR_HPP +#define NDN_ENCODING_ESTIMATOR_HPP + +#include "ndn-cxx/encoding/block.hpp" + +namespace ndn { +namespace encoding { + +/** + * @brief Helper class to estimate size of TLV encoding + * Interface of this class (mostly) matches interface of Encoder class + * @sa Encoder + */ +class Estimator : noncopyable +{ +public: // common interface between Encoder and Estimator + /** + * @brief Prepend a byte + */ + constexpr size_t + prependByte(uint8_t) const noexcept + { + return 1; + } + + /** + * @brief Append a byte + */ + constexpr size_t + appendByte(uint8_t) const noexcept + { + return 1; + } + + /** + * @brief Prepend a byte array @p array of length @p length + */ + constexpr size_t + prependByteArray(const uint8_t*, size_t length) const noexcept + { + return length; + } + + /** + * @brief Append a byte array @p array of length @p length + */ + constexpr size_t + appendByteArray(const uint8_t*, size_t length) const noexcept + { + return length; + } + + /** + * @brief Prepend range of bytes from the range [@p first, @p last) + */ + template + size_t + prependRange(Iterator first, Iterator last) const noexcept + { + return std::distance(first, last); + } + + /** + * @brief Append range of bytes from the range [@p first, @p last) + */ + template + size_t + appendRange(Iterator first, Iterator last) const noexcept + { + return std::distance(first, last); + } + + /** + * @brief Prepend VarNumber @p varNumber of NDN TLV encoding + * @sa http://named-data.net/doc/ndn-tlv/ + */ + size_t + prependVarNumber(uint64_t varNumber) const noexcept; + + /** + * @brief Prepend VarNumber @p varNumber of NDN TLV encoding + * @sa http://named-data.net/doc/ndn-tlv/ + */ + size_t + appendVarNumber(uint64_t varNumber) const noexcept; + + /** + * @brief Prepend non-negative integer @p integer of NDN TLV encoding + * @sa http://named-data.net/doc/ndn-tlv/ + */ + size_t + prependNonNegativeInteger(uint64_t integer) const noexcept; + + /** + * @brief Append non-negative integer @p integer of NDN TLV encoding + * @sa http://named-data.net/doc/ndn-tlv/ + */ + size_t + appendNonNegativeInteger(uint64_t integer) const noexcept; + + /** + * @brief Prepend TLV block of type @p type and value from buffer @p array of size @p arraySize + */ + size_t + prependByteArrayBlock(uint32_t type, const uint8_t* array, size_t arraySize) const noexcept; + + /** + * @brief Append TLV block of type @p type and value from buffer @p array of size @p arraySize + */ + size_t + appendByteArrayBlock(uint32_t type, const uint8_t* array, size_t arraySize) const noexcept; + + /** + * @brief Prepend TLV block @p block + */ + size_t + prependBlock(const Block& block) const; + + /** + * @brief Append TLV block @p block + */ + size_t + appendBlock(const Block& block) const; +}; + +} // namespace encoding +} // namespace ndn + +#endif // NDN_ENCODING_ESTIMATOR_HPP diff --git a/ndn-cxx/encoding/nfd-constants.cpp b/ndn-cxx/encoding/nfd-constants.cpp new file mode 100644 index 000000000..95473514c --- /dev/null +++ b/ndn-cxx/encoding/nfd-constants.cpp @@ -0,0 +1,204 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/encoding/nfd-constants.hpp" +#include "ndn-cxx/util/ostream-joiner.hpp" +#include "ndn-cxx/util/string-helper.hpp" + +#include +#include +#include +#include +#include + +namespace ndn { +namespace nfd { + +std::ostream& +operator<<(std::ostream& os, FaceScope faceScope) +{ + switch (faceScope) { + case FACE_SCOPE_NONE: + return os << "none"; + case FACE_SCOPE_NON_LOCAL: + return os << "non-local"; + case FACE_SCOPE_LOCAL: + return os << "local"; + } + return os << static_cast(faceScope); +} + +std::ostream& +operator<<(std::ostream& os, FacePersistency facePersistency) +{ + switch (facePersistency) { + case FACE_PERSISTENCY_NONE: + return os << "none"; + case FACE_PERSISTENCY_PERSISTENT: + return os << "persistent"; + case FACE_PERSISTENCY_ON_DEMAND: + return os << "on-demand"; + case FACE_PERSISTENCY_PERMANENT: + return os << "permanent"; + } + return os << static_cast(facePersistency); +} + +std::ostream& +operator<<(std::ostream& os, LinkType linkType) +{ + switch (linkType) { + case LINK_TYPE_NONE: + return os << "none"; + case LINK_TYPE_POINT_TO_POINT: + return os << "point-to-point"; + case LINK_TYPE_MULTI_ACCESS: + return os << "multi-access"; + case LINK_TYPE_AD_HOC: + return os << "adhoc"; + } + return os << static_cast(linkType); +} + +std::ostream& +operator<<(std::ostream& os, FaceEventKind faceEventKind) +{ + switch (faceEventKind) { + case FACE_EVENT_NONE: + return os << "none"; + case FACE_EVENT_CREATED: + return os << "created"; + case FACE_EVENT_DESTROYED: + return os << "destroyed"; + case FACE_EVENT_UP: + return os << "up"; + case FACE_EVENT_DOWN: + return os << "down"; + } + return os << static_cast(faceEventKind); +} + +std::istream& +operator>>(std::istream& is, RouteOrigin& routeOrigin) +{ + using boost::algorithm::iequals; + + std::string s; + is >> s; + + if (iequals(s, "none")) + routeOrigin = ROUTE_ORIGIN_NONE; + else if (iequals(s, "app")) + routeOrigin = ROUTE_ORIGIN_APP; + else if (iequals(s, "autoreg")) + routeOrigin = ROUTE_ORIGIN_AUTOREG; + else if (iequals(s, "client")) + routeOrigin = ROUTE_ORIGIN_CLIENT; + else if (iequals(s, "autoconf")) + routeOrigin = ROUTE_ORIGIN_AUTOCONF; + else if (iequals(s, "nlsr")) + routeOrigin = ROUTE_ORIGIN_NLSR; + else if (iequals(s, "prefixann")) + routeOrigin = ROUTE_ORIGIN_PREFIXANN; + else if (iequals(s, "static")) + routeOrigin = ROUTE_ORIGIN_STATIC; + else { + // To reject negative numbers, we parse as a wider signed type, and compare with the range. + static_assert(std::numeric_limits>::max() <= + std::numeric_limits::max(), ""); + + int v = -1; + try { + v = boost::lexical_cast(s); + } + catch (const boost::bad_lexical_cast&) { + } + + if (v >= std::numeric_limits>::min() && + v <= std::numeric_limits>::max()) { + routeOrigin = static_cast(v); + } + else { + routeOrigin = ROUTE_ORIGIN_NONE; + is.setstate(std::ios::failbit); + } + } + + return is; +} + +std::ostream& +operator<<(std::ostream& os, RouteOrigin routeOrigin) +{ + switch (routeOrigin) { + case ROUTE_ORIGIN_NONE: + return os << "none"; + case ROUTE_ORIGIN_APP: + return os << "app"; + case ROUTE_ORIGIN_AUTOREG: + return os << "autoreg"; + case ROUTE_ORIGIN_CLIENT: + return os << "client"; + case ROUTE_ORIGIN_AUTOCONF: + return os << "autoconf"; + case ROUTE_ORIGIN_NLSR: + return os << "nlsr"; + case ROUTE_ORIGIN_PREFIXANN: + return os << "prefixann"; + case ROUTE_ORIGIN_STATIC: + return os << "static"; + } + return os << static_cast(routeOrigin); +} + +std::ostream& +operator<<(std::ostream& os, RouteFlags routeFlags) +{ + if (routeFlags == ROUTE_FLAGS_NONE) { + return os << "none"; + } + + static const std::map knownBits = { + {ROUTE_FLAG_CHILD_INHERIT, "child-inherit"}, + {ROUTE_FLAG_CAPTURE, "capture"} + }; + + auto join = make_ostream_joiner(os, '|'); + for (const auto& pair : knownBits) { + RouteFlags bit = ROUTE_FLAGS_NONE; + std::string token; + std::tie(bit, token) = pair; + + if ((routeFlags & bit) != 0) { + join = token; + routeFlags = static_cast(routeFlags & ~bit); + } + } + + if (routeFlags != ROUTE_FLAGS_NONE) { + join = AsHex{routeFlags}; + } + + return os; +} + +} // namespace nfd +} // namespace ndn diff --git a/ndn-cxx/encoding/nfd-constants.hpp b/ndn-cxx/encoding/nfd-constants.hpp new file mode 100644 index 000000000..3929ce5ce --- /dev/null +++ b/ndn-cxx/encoding/nfd-constants.hpp @@ -0,0 +1,135 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_ENCODING_NFD_CONSTANTS_HPP +#define NDN_ENCODING_NFD_CONSTANTS_HPP + +#include "ndn-cxx/detail/common.hpp" + +namespace ndn { +namespace nfd { + +const uint64_t INVALID_FACE_ID = 0; + +/** \ingroup management + */ +enum FaceScope : uint8_t { + FACE_SCOPE_NONE = std::numeric_limits::max(), + FACE_SCOPE_NON_LOCAL = 0, ///< face is non-local + FACE_SCOPE_LOCAL = 1, ///< face is local +}; + +std::ostream& +operator<<(std::ostream& os, FaceScope faceScope); + +/** \ingroup management + */ +enum FacePersistency : uint8_t { + FACE_PERSISTENCY_NONE = std::numeric_limits::max(), + FACE_PERSISTENCY_PERSISTENT = 0, ///< face is persistent + FACE_PERSISTENCY_ON_DEMAND = 1, ///< face is on-demand + FACE_PERSISTENCY_PERMANENT = 2, ///< face is permanent +}; + +std::ostream& +operator<<(std::ostream& os, FacePersistency facePersistency); + +/** \ingroup management + */ +enum LinkType : uint8_t { + LINK_TYPE_NONE = std::numeric_limits::max(), + LINK_TYPE_POINT_TO_POINT = 0, ///< link is point-to-point + LINK_TYPE_MULTI_ACCESS = 1, ///< link is multi-access + LINK_TYPE_AD_HOC = 2, ///< link is ad hoc +}; + +std::ostream& +operator<<(std::ostream& os, LinkType linkType); + +/** \ingroup management + */ +enum FaceFlagBit { + BIT_LOCAL_FIELDS_ENABLED = 0, ///< whether local fields are enabled on a face + BIT_LP_RELIABILITY_ENABLED = 1, ///< whether the link reliability feature is enabled on a face + BIT_CONGESTION_MARKING_ENABLED = 2, ///< whether congestion detection and marking is enabled on a face +}; + +/** \ingroup management + */ +enum FaceEventKind : uint8_t { + FACE_EVENT_NONE = 0, + FACE_EVENT_CREATED = 1, ///< face was created + FACE_EVENT_DESTROYED = 2, ///< face was destroyed + FACE_EVENT_UP = 3, ///< face went UP (from DOWN state) + FACE_EVENT_DOWN = 4, ///< face went DOWN (from UP state) +}; + +std::ostream& +operator<<(std::ostream& os, FaceEventKind faceEventKind); + +/** \ingroup management + * \brief CS enablement flags + * \sa https://redmine.named-data.net/projects/nfd/wiki/CsMgmt#Update-config + */ +enum CsFlagBit { + BIT_CS_ENABLE_ADMIT = 0, ///< enables the CS to admit new Data + BIT_CS_ENABLE_SERVE = 1, ///< enables the CS to satisfy Interests using cached Data +}; + +/** \ingroup management + */ +enum RouteOrigin : uint16_t { + ROUTE_ORIGIN_NONE = std::numeric_limits::max(), + ROUTE_ORIGIN_APP = 0, + ROUTE_ORIGIN_AUTOREG = 64, + ROUTE_ORIGIN_CLIENT = 65, + ROUTE_ORIGIN_AUTOCONF = 66, + ROUTE_ORIGIN_NLSR = 128, + ROUTE_ORIGIN_PREFIXANN = 129, + ROUTE_ORIGIN_STATIC = 255, +}; + +/** \brief extract RouteOrigin from stream + * \post if the first token in \p contains a valid RouteOrigin as string or numeric value, it is + * extracted into \p routeOrigin ; otherwise, \p routeOrigin is set to \p ROUTE_ORIGIN_NONE , + * and failbit is set on \p is + */ +std::istream& +operator>>(std::istream& is, RouteOrigin& routeOrigin); + +std::ostream& +operator<<(std::ostream& os, RouteOrigin routeOrigin); + +/** \ingroup management + */ +enum RouteFlags : uint64_t { + ROUTE_FLAGS_NONE = 0, + ROUTE_FLAG_CHILD_INHERIT = 1, + ROUTE_FLAG_CAPTURE = 2, +}; + +std::ostream& +operator<<(std::ostream& os, RouteFlags routeFlags); + +} // namespace nfd +} // namespace ndn + +#endif // NDN_ENCODING_NFD_CONSTANTS_HPP diff --git a/ndn-cxx/encoding/tlv-nfd.hpp b/ndn-cxx/encoding/tlv-nfd.hpp new file mode 100644 index 000000000..1c30ab497 --- /dev/null +++ b/ndn-cxx/encoding/tlv-nfd.hpp @@ -0,0 +1,110 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_ENCODING_TLV_NFD_HPP +#define NDN_ENCODING_TLV_NFD_HPP + +#include "ndn-cxx/encoding/tlv.hpp" +#include "ndn-cxx/encoding/nfd-constants.hpp" + +namespace ndn { +namespace tlv { +namespace nfd { + +// NFD Management protocol +enum { + // ControlParameters + ControlParameters = 104, + FaceId = 105, + Uri = 114, + Origin = 111, + Cost = 106, + Capacity = 131, + Count = 132, + Flags = 108, + Mask = 112, + Strategy = 107, + ExpirationPeriod = 109, + + // ControlResponse + ControlResponse = 101, + StatusCode = 102, + StatusText = 103, + + // ForwarderStatus + NfdVersion = 128, + StartTimestamp = 129, + CurrentTimestamp = 130, + NNameTreeEntries = 131, + NFibEntries = 132, + NPitEntries = 133, + NMeasurementsEntries = 134, + NCsEntries = 135, + + // Face Management + FaceStatus = 128, + LocalUri = 129, + ChannelStatus = 130, + UriScheme = 131, + FaceScope = 132, + FacePersistency = 133, + LinkType = 134, + BaseCongestionMarkingInterval = 135, + DefaultCongestionThreshold = 136, + Mtu = 137, + FaceQueryFilter = 150, + FaceEventNotification = 192, + FaceEventKind = 193, + + // ForwarderStatus and FaceStatus counters + NInInterests = 144, + NInData = 145, + NInNacks = 151, + NOutInterests = 146, + NOutData = 147, + NOutNacks = 152, + NInBytes = 148, + NOutBytes = 149, + NSatisfiedInterests = 153, + NUnsatisfiedInterests = 154, + + // Content Store Management + CsInfo = 128, + NHits = 129, + NMisses = 130, + + // FIB Management + FibEntry = 128, + NextHopRecord = 129, + + // Strategy Choice Management + StrategyChoice = 128, + + // RIB Management + RibEntry = 128, + Route = 129 +}; + +} // namespace nfd +} // namespace tlv +} // namespace ndn + +#endif // NDN_ENCODING_TLV_NFD_HPP diff --git a/src/encoding/tlv-security.hpp b/ndn-cxx/encoding/tlv-security.hpp similarity index 87% rename from src/encoding/tlv-security.hpp rename to ndn-cxx/encoding/tlv-security.hpp index ac8f24800..8b70a3e87 100644 --- a/src/encoding/tlv-security.hpp +++ b/ndn-cxx/encoding/tlv-security.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,18 +22,12 @@ #ifndef NDN_ENCODING_TLV_SECURITY_HPP #define NDN_ENCODING_TLV_SECURITY_HPP -#include "tlv.hpp" +#include "ndn-cxx/encoding/tlv.hpp" namespace ndn { namespace tlv { namespace security { -enum { - IdentityPackage = 128, - KeyPackage = 129, - CertificatePackage = 130 -}; - enum { SafeBag = 128, EncryptedKeyBag = 129 diff --git a/ndn-cxx/encoding/tlv.cpp b/ndn-cxx/encoding/tlv.cpp new file mode 100644 index 000000000..a9feab7e3 --- /dev/null +++ b/ndn-cxx/encoding/tlv.cpp @@ -0,0 +1,81 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/encoding/tlv.hpp" + +namespace ndn { +namespace tlv { + +Error::Error(const char* expectedType, uint32_t actualType) + : Error("Expecting "s + expectedType + " element, but TLV has type " + to_string(actualType)) +{ +} + +std::ostream& +operator<<(std::ostream& os, SignatureTypeValue st) +{ + switch (st) { + case DigestSha256: + return os << "DigestSha256"; + case SignatureSha256WithRsa: + return os << "SignatureSha256WithRsa"; + case SignatureSha256WithEcdsa: + return os << "SignatureSha256WithEcdsa"; + case SignatureHmacWithSha256: + return os << "SignatureHmacWithSha256"; + } + return os << "Unknown(" << static_cast(st) << ')'; +} + +std::ostream& +operator<<(std::ostream& os, ContentTypeValue ct) +{ + switch (ct) { + case ContentType_Blob: + return os << "Blob"; + case ContentType_Link: + return os << "Link"; + case ContentType_Key: + return os << "Key"; + case ContentType_Nack: + return os << "Nack"; + case ContentType_Manifest: + return os << "Manifest"; + case ContentType_PrefixAnn: + return os << "PrefixAnn"; + case ContentType_Flic: + return os << "FLIC"; + } + + if (ct >= 6 && ct <= 1023) { + os << "Reserved("; + } + else if (ct >= 9000 && ct <= 9999) { + os << "Experimental("; + } + else { + os << "Unknown("; + } + return os << static_cast(ct) << ')'; +} + +} // namespace tlv +} // namespace ndn diff --git a/ndn-cxx/encoding/tlv.hpp b/ndn-cxx/encoding/tlv.hpp new file mode 100644 index 000000000..a3b697952 --- /dev/null +++ b/ndn-cxx/encoding/tlv.hpp @@ -0,0 +1,536 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_ENCODING_TLV_HPP +#define NDN_ENCODING_TLV_HPP + +#include "ndn-cxx/detail/common.hpp" + +#include +#include +#include +#include +#include + +#include + +namespace ndn { + +/** @brief practical limit of network layer packet size + * + * If a packet is longer than this size, library and application MAY drop it. + */ +const size_t MAX_NDN_PACKET_SIZE = 8800; + +/** + * @brief Namespace defining NDN Packet Format related constants and procedures + */ +namespace tlv { + +/** @brief represents an error in TLV encoding or decoding + * + * Element::Error SHOULD inherit from this Error class. + */ +class Error : public std::runtime_error +{ +public: + using std::runtime_error::runtime_error; + + Error(const char* expectedType, uint32_t actualType); +}; + +/** @brief TLV-TYPE numbers defined in NDN Packet Format v0.3 + * @sa https://named-data.net/doc/NDN-packet-spec/current/types.html + */ +enum : uint32_t { + Invalid = 0, + Interest = 5, + Data = 6, + Name = 7, + GenericNameComponent = 8, + ImplicitSha256DigestComponent = 1, + ParametersSha256DigestComponent = 2, + CanBePrefix = 33, + MustBeFresh = 18, + ForwardingHint = 30, + Nonce = 10, + InterestLifetime = 12, + HopLimit = 34, + ApplicationParameters = 36, + MetaInfo = 20, + Content = 21, + SignatureInfo = 22, + SignatureValue = 23, + ContentType = 24, + FreshnessPeriod = 25, + FinalBlockId = 26, + SignatureType = 27, + KeyLocator = 28, + KeyDigest = 29, + LinkDelegation = 31, + LinkPreference = 30, + + NameComponentMin = 1, + NameComponentMax = 65535, + + AppPrivateBlock1 = 128, + AppPrivateBlock2 = 32767 +}; + +/** @brief TLV-TYPE numbers defined in NDN Packet Format v0.2 but not in v0.3 + * @sa https://named-data.net/doc/NDN-packet-spec/0.2.1/types.html + */ +enum : uint32_t { + Selectors = 9, + MinSuffixComponents = 13, + MaxSuffixComponents = 14, + PublisherPublicKeyLocator = 15, + Exclude = 16, + ChildSelector = 17, + Any = 19, +}; + +[[deprecated("use GenericNameComponent")]] +constexpr int NameComponent = GenericNameComponent; + +/** @brief TLV-TYPE numbers for typed name components. + * @sa https://redmine.named-data.net/projects/ndn-tlv/wiki/NameComponentType + */ +enum : uint32_t { + KeywordNameComponent = 32, + SegmentNameComponent = 33, + ByteOffsetNameComponent = 34, + VersionNameComponent = 35, + TimestampNameComponent = 36, + SequenceNumNameComponent = 37, +}; + +/** @brief SignatureType values + * @sa https://named-data.net/doc/NDN-packet-spec/current/signature.html + */ +enum SignatureTypeValue : uint16_t { + DigestSha256 = 0, + SignatureSha256WithRsa = 1, + SignatureSha256WithEcdsa = 3, + SignatureHmacWithSha256 = 4, +}; + +std::ostream& +operator<<(std::ostream& os, SignatureTypeValue st); + +/** @brief TLV-TYPE numbers for SignatureInfo features + * @sa docs/specs/certificate-format.rst + */ +enum { + ValidityPeriod = 253, + NotBefore = 254, + NotAfter = 255, + + AdditionalDescription = 258, + DescriptionEntry = 512, + DescriptionKey = 513, + DescriptionValue = 514 +}; + +/** @brief ContentType values + * @sa https://redmine.named-data.net/projects/ndn-tlv/wiki/ContentType + */ +enum ContentTypeValue : uint32_t { + ContentType_Blob = 0, ///< payload + ContentType_Link = 1, ///< another name that identifies the actual data content + ContentType_Key = 2, ///< public key, certificate + ContentType_Nack = 3, ///< application-level nack + ContentType_Manifest = 4, + ContentType_PrefixAnn = 5, ///< prefix announcement + ContentType_Flic = 1024, ///< File-Like ICN Collection +}; + +std::ostream& +operator<<(std::ostream& os, ContentTypeValue ct); + +/** + * @brief Determine whether a TLV-TYPE is "critical" for evolvability purpose. + * @sa https://named-data.net/doc/NDN-packet-spec/0.3/tlv.html#considerations-for-evolvability-of-tlv-based-encoding + */ +constexpr bool +isCriticalType(uint32_t type) +{ + return type <= 31 || (type & 0x01); +} + +/** + * @brief Read VAR-NUMBER in NDN-TLV encoding. + * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type + * + * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after + * the read VAR-NUMBER + * @param [in] end End of the buffer + * @param [out] number Read VAR-NUMBER + * + * @return true if number was successfully read from input, false otherwise + */ +template +NDN_CXX_NODISCARD bool +readVarNumber(Iterator& begin, Iterator end, uint64_t& number) noexcept; + +/** + * @brief Read TLV-TYPE. + * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type + * + * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after + * the read TLV-TYPE + * @param [in] end End of the buffer + * @param [out] type Read TLV-TYPE + * + * @return true if TLV-TYPE was successfully read from input, false otherwise + * @note This function is largely equivalent to readVarNumber(), except that it returns false if + * the TLV-TYPE is zero or larger than 2^32-1 (maximum allowed by the packet format). + */ +template +NDN_CXX_NODISCARD bool +readType(Iterator& begin, Iterator end, uint32_t& type) noexcept; + +/** + * @brief Read VAR-NUMBER in NDN-TLV encoding. + * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type + * + * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after + * the read VAR-NUMBER + * @param [in] end End of the buffer + * + * @throw tlv::Error VAR-NUMBER cannot be read + */ +template +uint64_t +readVarNumber(Iterator& begin, Iterator end); + +/** + * @brief Read TLV-TYPE. + * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type + * + * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after + * the read TLV-TYPE + * @param [in] end End of the buffer + * + * @throw tlv::Error TLV-TYPE cannot be read + * @note This function is largely equivalent to readVarNumber(), except that it throws if + * the TLV-TYPE is zero or larger than 2^32-1 (maximum allowed by the packet format). + */ +template +uint32_t +readType(Iterator& begin, Iterator end); + +/** + * @brief Get the number of bytes necessary to hold the value of @p number encoded as VAR-NUMBER. + */ +constexpr size_t +sizeOfVarNumber(uint64_t number) noexcept; + +/** + * @brief Write VAR-NUMBER to the specified stream. + * @return length of written VAR-NUMBER + */ +size_t +writeVarNumber(std::ostream& os, uint64_t number); + +/** + * @brief Read nonNegativeInteger in NDN-TLV encoding. + * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type + * + * @param [in] size size of the nonNegativeInteger + * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after + * the read nonNegativeInteger + * @param [in] end End of the buffer + * + * @throw tlv::Error number cannot be read + * @note How many bytes to read is directly controlled by \p size, which can be either 1, 2, 4, or 8. + * If \p size differs from `std::distance(begin, end)`, tlv::Error exception will be thrown. + */ +template +uint64_t +readNonNegativeInteger(size_t size, Iterator& begin, Iterator end); + +/** + * @brief Get the number of bytes necessary to hold the value of @p integer encoded as nonNegativeInteger. + */ +constexpr size_t +sizeOfNonNegativeInteger(uint64_t integer) noexcept; + +/** + * @brief Write nonNegativeInteger to the specified stream. + * @return length of written nonNegativeInteger + */ +size_t +writeNonNegativeInteger(std::ostream& os, uint64_t integer); + +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// + +// Inline definitions + +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// + +namespace detail { + +/** @brief Function object to read a number from InputIterator + */ +template +class ReadNumberSlow +{ +public: + constexpr bool + operator()(size_t size, Iterator& begin, Iterator end, uint64_t& number) const noexcept + { + number = 0; + size_t count = 0; + for (; begin != end && count < size; ++begin, ++count) { + number = (number << 8) | *begin; + } + return count == size; + } +}; + +/** @brief Function object to read a number from ContiguousIterator + */ +template +class ReadNumberFast +{ +public: + constexpr bool + operator()(size_t size, Iterator& begin, Iterator end, uint64_t& number) const noexcept + { + if (begin + size > end) { + return false; + } + + switch (size) { + case 1: { + number = *begin; + ++begin; + return true; + } + case 2: { + uint16_t value = 0; + std::memcpy(&value, &*begin, 2); + begin += 2; + number = boost::endian::big_to_native(value); + return true; + } + case 4: { + uint32_t value = 0; + std::memcpy(&value, &*begin, 4); + begin += 4; + number = boost::endian::big_to_native(value); + return true; + } + case 8: { + uint64_t value = 0; + std::memcpy(&value, &*begin, 8); + begin += 8; + number = boost::endian::big_to_native(value); + return true; + } + default: { + NDN_CXX_UNREACHABLE; + } + } + } +}; + +/** @brief Determine whether to select ReadNumber implementation for ContiguousIterator + * + * This is not a full ContiguousIterator detection implementation. It returns true for the most + * common ContiguousIterator types used with TLV decoding function templates. + */ +template, + typename ValueType = typename std::iterator_traits::value_type> +constexpr bool +shouldSelectContiguousReadNumber() +{ + return (std::is_convertible::value || + std::is_convertible::const_iterator>::value || + std::is_convertible::const_iterator>::value) && + sizeof(ValueType) == 1 && + !std::is_same::value; +} + +template +class ReadNumber : public std::conditional_t(), + ReadNumberFast, ReadNumberSlow> +{ +}; + +} // namespace detail + +template +bool +readVarNumber(Iterator& begin, Iterator end, uint64_t& number) noexcept +{ + if (begin == end) + return false; + + uint8_t firstOctet = *begin; + ++begin; + if (firstOctet < 253) { + number = firstOctet; + return true; + } + + size_t size = firstOctet == 253 ? 2 : + firstOctet == 254 ? 4 : 8; + return detail::ReadNumber()(size, begin, end, number); +} + +template +bool +readType(Iterator& begin, Iterator end, uint32_t& type) noexcept +{ + uint64_t number = 0; + bool isOk = readVarNumber(begin, end, number); + if (!isOk || number == Invalid || number > std::numeric_limits::max()) { + return false; + } + + type = static_cast(number); + return true; +} + +template +uint64_t +readVarNumber(Iterator& begin, Iterator end) +{ + if (begin == end) { + NDN_THROW(Error("Empty buffer during TLV parsing")); + } + + uint64_t value = 0; + bool isOk = readVarNumber(begin, end, value); + if (!isOk) { + NDN_THROW(Error("Insufficient data during TLV parsing")); + } + + return value; +} + +template +uint32_t +readType(Iterator& begin, Iterator end) +{ + uint64_t type = readVarNumber(begin, end); + if (type == Invalid || type > std::numeric_limits::max()) { + NDN_THROW(Error("Illegal TLV-TYPE " + to_string(type))); + } + + return static_cast(type); +} + +constexpr size_t +sizeOfVarNumber(uint64_t number) noexcept +{ + return number < 253 ? 1 : + number <= std::numeric_limits::max() ? 3 : + number <= std::numeric_limits::max() ? 5 : 9; +} + +inline size_t +writeVarNumber(std::ostream& os, uint64_t number) +{ + if (number < 253) { + os.put(static_cast(number)); + return 1; + } + else if (number <= std::numeric_limits::max()) { + os.put(static_cast(253)); + uint16_t value = boost::endian::native_to_big(static_cast(number)); + os.write(reinterpret_cast(&value), 2); + return 3; + } + else if (number <= std::numeric_limits::max()) { + os.put(static_cast(254)); + uint32_t value = boost::endian::native_to_big(static_cast(number)); + os.write(reinterpret_cast(&value), 4); + return 5; + } + else { + os.put(static_cast(255)); + uint64_t value = boost::endian::native_to_big(number); + os.write(reinterpret_cast(&value), 8); + return 9; + } +} + +template +uint64_t +readNonNegativeInteger(size_t size, Iterator& begin, Iterator end) +{ + if (size != 1 && size != 2 && size != 4 && size != 8) { + NDN_THROW(Error("Invalid length " + to_string(size) + " for nonNegativeInteger")); + } + + uint64_t number = 0; + bool isOk = detail::ReadNumber()(size, begin, end, number); + if (!isOk) { + NDN_THROW(Error("Insufficient data during nonNegativeInteger parsing")); + } + + return number; +} + +constexpr size_t +sizeOfNonNegativeInteger(uint64_t integer) noexcept +{ + return integer <= std::numeric_limits::max() ? 1 : + integer <= std::numeric_limits::max() ? 2 : + integer <= std::numeric_limits::max() ? 4 : 8; +} + +inline size_t +writeNonNegativeInteger(std::ostream& os, uint64_t integer) +{ + if (integer <= std::numeric_limits::max()) { + os.put(static_cast(integer)); + return 1; + } + else if (integer <= std::numeric_limits::max()) { + uint16_t value = boost::endian::native_to_big(static_cast(integer)); + os.write(reinterpret_cast(&value), 2); + return 2; + } + else if (integer <= std::numeric_limits::max()) { + uint32_t value = boost::endian::native_to_big(static_cast(integer)); + os.write(reinterpret_cast(&value), 4); + return 4; + } + else { + uint64_t value = boost::endian::native_to_big(integer); + os.write(reinterpret_cast(&value), 8); + return 8; + } +} + +} // namespace tlv +} // namespace ndn + +#endif // NDN_ENCODING_TLV_HPP diff --git a/ndn-cxx/face.cpp b/ndn-cxx/face.cpp new file mode 100644 index 000000000..97af0da80 --- /dev/null +++ b/ndn-cxx/face.cpp @@ -0,0 +1,344 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/face.hpp" +#include "ndn-cxx/encoding/tlv.hpp" +#include "ndn-cxx/impl/face-impl.hpp" +#include "ndn-cxx/net/face-uri.hpp" +#include "ndn-cxx/security/signing-helpers.hpp" +#include "ndn-cxx/util/time.hpp" + +#include "ns3/node-list.h" +#include "ns3/ndnSIM/helper/ndn-stack-helper.hpp" +#include "ns3/ndnSIM/NFD/daemon/face/generic-link-service.hpp" +#include "ns3/ndnSIM/NFD/daemon/face/internal-transport.hpp" + +// NDN_LOG_INIT(ndn.Face) is declared in face-impl.hpp + +// A callback scheduled through io.post and io.dispatch may be invoked after the face is destructed. +// To prevent this situation, use these macros to capture Face::m_impl as weak_ptr and skip callback +// execution if the face has been destructed. +#define IO_CAPTURE_WEAK_IMPL(OP) \ + { \ + weak_ptr implWeak(m_impl); \ + m_impl->m_scheduler.schedule(time::seconds(0), [=] { \ + auto impl = implWeak.lock(); \ + if (impl != nullptr) { +#define IO_CAPTURE_WEAK_IMPL_END \ + } \ + }); \ + } + +namespace ndn { + +Face::OversizedPacketError::OversizedPacketError(char pktType, const Name& name, size_t wireSize) + : Error((pktType == 'I' ? "Interest " : pktType == 'D' ? "Data " : "Nack ") + + name.toUri() + " encodes into " + to_string(wireSize) + " octets, " + "exceeding the implementation limit of " + to_string(MAX_NDN_PACKET_SIZE) + " octets") + , pktType(pktType) + , name(name) + , wireSize(wireSize) +{ +} + +Face::Face(DummyIoService& ioService) +{ + construct(nullptr, ns3::ndn::StackHelper::getKeyChain()); +} + +Face::Face(shared_ptr transport) +{ + construct(transport, ns3::ndn::StackHelper::getKeyChain()); +} + +Face::Face(shared_ptr transport, KeyChain& keyChain) +{ + construct(std::move(transport), keyChain); +} + +shared_ptr +Face::makeDefaultTransport() +{ + ns3::Ptr node = ns3::NodeList::GetNode(ns3::Simulator::GetContext()); + NS_ASSERT_MSG(node->GetObject() != 0, + "NDN stack should be installed on the node " << node); + + auto uri = ::nfd::FaceUri("ndnFace://" + boost::lexical_cast(node->GetId())); + + ::nfd::face::GenericLinkService::Options serviceOpts; + serviceOpts.allowLocalFields = true; + + auto nfdFace = make_shared<::nfd::Face>(make_unique<::nfd::face::GenericLinkService>(serviceOpts), + make_unique<::nfd::face::InternalForwarderTransport>(uri, uri)); + auto forwarderTransport = static_cast<::nfd::face::InternalForwarderTransport*>(nfdFace->getTransport()); + + auto clientTransport = make_shared<::nfd::face::InternalClientTransport>(); + clientTransport->connectToForwarder(forwarderTransport); + + node->GetObject()->addFace(nfdFace);; + + return clientTransport; +} + +void +Face::construct(shared_ptr transport, KeyChain& keyChain) +{ + BOOST_ASSERT(m_impl == nullptr); + m_impl = make_shared(*this, keyChain); + + if (transport == nullptr) { + transport = makeDefaultTransport(); + BOOST_ASSERT(transport != nullptr); + } + m_transport = std::move(transport); + + IO_CAPTURE_WEAK_IMPL(post) { + impl->ensureConnected(false); + } IO_CAPTURE_WEAK_IMPL_END +} + +Face::~Face() = default; + +PendingInterestHandle +Face::expressInterest(const Interest& interest, + const DataCallback& afterSatisfied, + const NackCallback& afterNacked, + const TimeoutCallback& afterTimeout) +{ + auto id = m_impl->m_pendingInterestTable.allocateId(); + + auto interest2 = make_shared(interest); + interest2->getNonce(); + + IO_CAPTURE_WEAK_IMPL(post) { + impl->asyncExpressInterest(id, interest2, afterSatisfied, afterNacked, afterTimeout); + } IO_CAPTURE_WEAK_IMPL_END + + return PendingInterestHandle(*this, reinterpret_cast(id)); +} + +void +Face::cancelPendingInterest(const PendingInterestId* pendingInterestId) +{ + IO_CAPTURE_WEAK_IMPL(post) { + impl->asyncRemovePendingInterest(reinterpret_cast(pendingInterestId)); + } IO_CAPTURE_WEAK_IMPL_END +} + +void +Face::removeAllPendingInterests() +{ + IO_CAPTURE_WEAK_IMPL(post) { + impl->asyncRemoveAllPendingInterests(); + } IO_CAPTURE_WEAK_IMPL_END +} + +size_t +Face::getNPendingInterests() const +{ + return m_impl->m_pendingInterestTable.size(); +} + +void +Face::put(Data data) +{ + IO_CAPTURE_WEAK_IMPL(post) { + impl->asyncPutData(data); + } IO_CAPTURE_WEAK_IMPL_END +} + +void +Face::put(lp::Nack nack) +{ + IO_CAPTURE_WEAK_IMPL(post) { + impl->asyncPutNack(nack); + } IO_CAPTURE_WEAK_IMPL_END +} + +RegisteredPrefixHandle +Face::setInterestFilter(const InterestFilter& filter, const InterestCallback& onInterest, + const RegisterPrefixFailureCallback& onFailure, + const security::SigningInfo& signingInfo, uint64_t flags) +{ + return setInterestFilter(filter, onInterest, nullptr, onFailure, signingInfo, flags); +} + +RegisteredPrefixHandle +Face::setInterestFilter(const InterestFilter& filter, const InterestCallback& onInterest, + const RegisterPrefixSuccessCallback& onSuccess, + const RegisterPrefixFailureCallback& onFailure, + const security::SigningInfo& signingInfo, uint64_t flags) +{ + nfd::CommandOptions options; + options.setSigningInfo(signingInfo); + + auto id = m_impl->registerPrefix(filter.getPrefix(), onSuccess, onFailure, flags, options, + filter, onInterest); + return RegisteredPrefixHandle(*this, reinterpret_cast(id)); +} + +InterestFilterHandle +Face::setInterestFilter(const InterestFilter& filter, const InterestCallback& onInterest) +{ + auto id = m_impl->m_interestFilterTable.allocateId(); + + IO_CAPTURE_WEAK_IMPL(post) { + impl->asyncSetInterestFilter(id, filter, onInterest); + } IO_CAPTURE_WEAK_IMPL_END + + return InterestFilterHandle(*this, reinterpret_cast(id)); +} + +void +Face::clearInterestFilter(const InterestFilterId* interestFilterId) +{ + IO_CAPTURE_WEAK_IMPL(post) { + impl->asyncUnsetInterestFilter(reinterpret_cast(interestFilterId)); + } IO_CAPTURE_WEAK_IMPL_END +} + +RegisteredPrefixHandle +Face::registerPrefix(const Name& prefix, + const RegisterPrefixSuccessCallback& onSuccess, + const RegisterPrefixFailureCallback& onFailure, + const security::SigningInfo& signingInfo, + uint64_t flags) +{ + nfd::CommandOptions options; + options.setSigningInfo(signingInfo); + + auto id = m_impl->registerPrefix(prefix, onSuccess, onFailure, flags, options, nullopt, nullptr); + return RegisteredPrefixHandle(*this, reinterpret_cast(id)); +} + +void +Face::unregisterPrefixImpl(const RegisteredPrefixId* registeredPrefixId, + const UnregisterPrefixSuccessCallback& onSuccess, + const UnregisterPrefixFailureCallback& onFailure) +{ + IO_CAPTURE_WEAK_IMPL(post) { + impl->asyncUnregisterPrefix(reinterpret_cast(registeredPrefixId), + onSuccess, onFailure); + } IO_CAPTURE_WEAK_IMPL_END +} + +void +Face::doProcessEvents(time::milliseconds timeout, bool keepThread) +{ +} + +void +Face::shutdown() +{ + IO_CAPTURE_WEAK_IMPL(post) { + impl->shutdown(); + if (m_transport->isConnected()) + m_transport->close(); + } IO_CAPTURE_WEAK_IMPL_END +} + +/** + * @brief extract local fields from NDNLPv2 packet and tag onto a network layer packet + */ +template +static void +extractLpLocalFields(NetPkt& netPacket, const lp::Packet& lpPacket) +{ + addTagFromField(netPacket, lpPacket); + addTagFromField(netPacket, lpPacket); + + if (lpPacket.has()) { + netPacket.setTag(make_shared(lpPacket.get() + 1)); + } +} + +void +Face::onReceiveElement(const Block& blockFromDaemon) +{ + lp::Packet lpPacket(blockFromDaemon); // bare Interest/Data is a valid lp::Packet, + // no need to distinguish + + Buffer::const_iterator begin, end; + std::tie(begin, end) = lpPacket.get(); + Block netPacket(&*begin, std::distance(begin, end)); + switch (netPacket.type()) { + case tlv::Interest: { + auto interest = make_shared(netPacket); + if (lpPacket.has()) { + auto nack = make_shared(std::move(*interest)); + nack->setHeader(lpPacket.get()); + extractLpLocalFields(*nack, lpPacket); + NDN_LOG_DEBUG(">N " << nack->getInterest() << '~' << nack->getHeader().getReason()); + m_impl->nackPendingInterests(*nack); + } + else { + extractLpLocalFields(*interest, lpPacket); + NDN_LOG_DEBUG(">I " << *interest); + m_impl->processIncomingInterest(std::move(interest)); + } + break; + } + case tlv::Data: { + auto data = make_shared(netPacket); + extractLpLocalFields(*data, lpPacket); + NDN_LOG_DEBUG(">D " << data->getName()); + m_impl->satisfyPendingInterests(*data); + break; + } + } +} + +PendingInterestHandle::PendingInterestHandle(Face& face, const PendingInterestId* id) + : CancelHandle([&face, id] { face.cancelPendingInterest(id); }) +{ +} + +RegisteredPrefixHandle::RegisteredPrefixHandle(Face& face, const RegisteredPrefixId* id) + : CancelHandle([&face, id] { face.unregisterPrefixImpl(id, nullptr, nullptr); }) + , m_face(&face) + , m_id(id) +{ + // The lambda passed to CancelHandle constructor cannot call this->unregister, + // because base class destructor cannot access the member fields of this subclass. +} + +void +RegisteredPrefixHandle::unregister(const UnregisterPrefixSuccessCallback& onSuccess, + const UnregisterPrefixFailureCallback& onFailure) +{ + if (m_id == nullptr) { + if (onFailure != nullptr) { + onFailure("RegisteredPrefixHandle is empty"); + } + return; + } + + m_face->unregisterPrefixImpl(m_id, onSuccess, onFailure); + m_face = nullptr; + m_id = nullptr; +} + +InterestFilterHandle::InterestFilterHandle(Face& face, const InterestFilterId* id) + : CancelHandle([&face, id] { face.clearInterestFilter(id); }) +{ +} + +} // namespace ndn diff --git a/ndn-cxx/face.hpp b/ndn-cxx/face.hpp new file mode 100644 index 000000000..5dd9ff0e9 --- /dev/null +++ b/ndn-cxx/face.hpp @@ -0,0 +1,598 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_FACE_HPP +#define NDN_FACE_HPP + +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/interest-filter.hpp" +#include "ndn-cxx/detail/asio-fwd.hpp" +#include "ndn-cxx/detail/cancel-handle.hpp" +#include "ndn-cxx/encoding/nfd-constants.hpp" +#include "ndn-cxx/lp/nack.hpp" +#include "ndn-cxx/security/key-chain.hpp" +#include "ndn-cxx/security/signing-info.hpp" + +namespace ndn { + +class Transport; + +class PendingInterestId; +class PendingInterestHandle; +class RegisteredPrefixId; +class RegisteredPrefixHandle; +class InterestFilterId; +class InterestFilterHandle; + +/** + * @brief Callback invoked when expressed Interest gets satisfied with a Data packet + */ +typedef function DataCallback; + +/** + * @brief Callback invoked when Nack is sent in response to expressed Interest + */ +typedef function NackCallback; + +/** + * @brief Callback invoked when expressed Interest times out + */ +typedef function TimeoutCallback; + +/** + * @brief Callback invoked when incoming Interest matches the specified InterestFilter + */ +typedef function InterestCallback; + +/** + * @brief Callback invoked when registerPrefix or setInterestFilter command succeeds + */ +typedef function RegisterPrefixSuccessCallback; + +/** + * @brief Callback invoked when registerPrefix or setInterestFilter command fails + */ +typedef function RegisterPrefixFailureCallback; + +/** + * @brief Callback invoked when unregisterPrefix or unsetInterestFilter command succeeds + */ +typedef function UnregisterPrefixSuccessCallback; + +/** + * @brief Callback invoked when unregisterPrefix or unsetInterestFilter command fails + */ +typedef function UnregisterPrefixFailureCallback; + +/** + * @brief Provide a communication channel with local or remote NDN forwarder + */ +class Face : noncopyable +{ +public: + class Error : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + }; + + /** + * @brief Exception thrown when attempting to send a packet over size limit + */ + class OversizedPacketError : public Error + { + public: + /** + * @brief Constructor + * @param pktType packet type, 'I' for Interest, 'D' for Data, 'N' for Nack + * @param name packet name + * @param wireSize wire encoding size + */ + OversizedPacketError(char pktType, const Name& name, size_t wireSize); + + public: + const char pktType; + const Name name; + const size_t wireSize; + }; + +public: // constructors + /** + * @brief Create Face using given transport (or default transport if omitted) + * @param transport the transport for lower layer communication. If nullptr, + * a default transport will be used. The default transport is + * determined from a FaceUri in NDN_CLIENT_TRANSPORT environ, + * a FaceUri in configuration file 'transport' key, or UnixTransport. + * + * @throw ConfigFile::Error @p transport is nullptr, and the configuration file cannot be + * parsed or specifies an unsupported protocol + * @note shared_ptr is passed by value because ownership is shared with this class + */ + explicit + Face(shared_ptr transport = nullptr); + + /** + * @brief Create Face using default transport and given io_service + * + * Usage examples: + * + * @code + * Face face1; + * Face face2(face1.getIoService()); + * + * // Now the following ensures that events on both faces are processed + * face1.processEvents(); + * // or face1.getIoService().run(); + * @endcode + * + * or + * + * @code + * boost::asio::io_service ioService; + * Face face1(ioService); + * Face face2(ioService); + * + * ioService.run(); + * @endcode + * + * @param ioService A reference to boost::io_service object that should control all + * IO operations. + * @throw ConfigFile::Error the configuration file cannot be parsed or specifies an unsupported protocol + */ + explicit + Face(DummyIoService& ioService); + + /** + * @brief Create Face using given transport and KeyChain + * @param transport the transport for lower layer communication. If nullptr, + * a default transport will be used. + * @param keyChain the KeyChain to sign commands + * + * @sa Face(shared_ptr) + * + * @throw ConfigFile::Error @p transport is nullptr, and the configuration file cannot be + * parsed or specifies an unsupported protocol + * @note shared_ptr is passed by value because ownership is shared with this class + */ + Face(shared_ptr transport, KeyChain& keyChain); + + virtual + ~Face(); + +public: // consumer + /** + * @brief Express Interest + * @param interest the Interest; a copy will be made, so that the caller is not + * required to maintain the argument unchanged + * @param afterSatisfied function to be invoked if Data is returned + * @param afterNacked function to be invoked if Network NACK is returned + * @param afterTimeout function to be invoked if neither Data nor Network NACK + * is returned within InterestLifetime + * @throw OversizedPacketError encoded Interest size exceeds MAX_NDN_PACKET_SIZE + * @return A handle for canceling the pending Interest. + */ + PendingInterestHandle + expressInterest(const Interest& interest, + const DataCallback& afterSatisfied, + const NackCallback& afterNacked, + const TimeoutCallback& afterTimeout); + + /** + * @deprecated use PendingInterestHandle::cancel() + */ + [[deprecated]] + void + removePendingInterest(const PendingInterestId* pendingInterestId) + { + cancelPendingInterest(pendingInterestId); + } + + /** + * @brief Cancel all previously expressed Interests + */ + void + removeAllPendingInterests(); + + /** + * @brief Get number of pending Interests + */ + size_t + getNPendingInterests() const; + +public: // producer + /** + * @brief Set InterestFilter to dispatch incoming matching interest to onInterest + * callback and register the filtered prefix with the connected NDN forwarder + * + * This version of setInterestFilter combines setInterestFilter and registerPrefix + * operations and is intended to be used when only one filter for the same prefix needed + * to be set. When multiple names sharing the same prefix should be dispatched to + * different callbacks, use one registerPrefix call, followed (in onSuccess callback) by + * a series of setInterestFilter calls. + * + * @param filter Interest filter (prefix part will be registered with the forwarder) + * @param onInterest A callback to be called when a matching interest is received + * @param onFailure A callback to be called when prefixRegister command fails + * @param signingInfo Signing parameters. When omitted, a default parameters used in the + * signature will be used. + * @param flags Prefix registration flags + * + * @return A handle for unregistering the prefix and unsetting the Interest filter. + */ + RegisteredPrefixHandle + setInterestFilter(const InterestFilter& filter, const InterestCallback& onInterest, + const RegisterPrefixFailureCallback& onFailure, + const security::SigningInfo& signingInfo = security::SigningInfo(), + uint64_t flags = nfd::ROUTE_FLAG_CHILD_INHERIT); + + /** + * @brief Set InterestFilter to dispatch incoming matching interest to onInterest + * callback and register the filtered prefix with the connected NDN forwarder + * + * This version of setInterestFilter combines setInterestFilter and registerPrefix + * operations and is intended to be used when only one filter for the same prefix needed + * to be set. When multiple names sharing the same prefix should be dispatched to + * different callbacks, use one registerPrefix call, followed (in onSuccess callback) by + * a series of setInterestFilter calls. + * + * @param filter Interest filter (prefix part will be registered with the forwarder) + * @param onInterest A callback to be called when a matching interest is received + * @param onSuccess A callback to be called when prefixRegister command succeeds + * @param onFailure A callback to be called when prefixRegister command fails + * @param signingInfo Signing parameters. When omitted, a default parameters used in the + * signature will be used. + * @param flags Prefix registration flags + * + * @return A handle for unregistering the prefix and unsetting the Interest filter. + */ + RegisteredPrefixHandle + setInterestFilter(const InterestFilter& filter, const InterestCallback& onInterest, + const RegisterPrefixSuccessCallback& onSuccess, + const RegisterPrefixFailureCallback& onFailure, + const security::SigningInfo& signingInfo = security::SigningInfo(), + uint64_t flags = nfd::ROUTE_FLAG_CHILD_INHERIT); + + /** + * @brief Set InterestFilter to dispatch incoming matching interest to onInterest callback + * + * @param filter Interest filter + * @param onInterest A callback to be called when a matching interest is received + * + * This method modifies library's FIB only, and does not register the prefix with the + * forwarder. It will always succeed. To register prefix with the forwarder, use + * registerPrefix, or use the setInterestFilter overload taking two callbacks. + * + * @return A handle for unsetting the Interest filter. + */ + InterestFilterHandle + setInterestFilter(const InterestFilter& filter, const InterestCallback& onInterest); + + /** + * @brief Register prefix with the connected NDN forwarder + * + * This method only modifies forwarder's RIB and does not associate any + * onInterest callbacks. Use setInterestFilter method to dispatch incoming Interests to + * the right callbacks. + * + * @param prefix A prefix to register with the connected NDN forwarder + * @param onSuccess A callback to be called when prefixRegister command succeeds + * @param onFailure A callback to be called when prefixRegister command fails + * @param signingInfo Signing parameters. When omitted, a default parameters used in the + * signature will be used. + * @param flags Prefix registration flags + * + * @return A handle for unregistering the prefix. + * @see nfd::RouteFlags + */ + RegisteredPrefixHandle + registerPrefix(const Name& prefix, + const RegisterPrefixSuccessCallback& onSuccess, + const RegisterPrefixFailureCallback& onFailure, + const security::SigningInfo& signingInfo = security::SigningInfo(), + uint64_t flags = nfd::ROUTE_FLAG_CHILD_INHERIT); + + /** + * @deprecated use RegisteredPrefixHandle::unregister() + */ + [[deprecated]] + void + unsetInterestFilter(const RegisteredPrefixId* registeredPrefixId) + { + unregisterPrefixImpl(registeredPrefixId, nullptr, nullptr); + } + + /** + * @deprecated use InterestFilterHandle::cancel() + */ + [[deprecated]] + void + unsetInterestFilter(const InterestFilterId* interestFilterId) + { + clearInterestFilter(interestFilterId); + } + + /** + * @deprecated use RegisteredPrefixHandle::unregister() + */ + [[deprecated]] + void + unregisterPrefix(const RegisteredPrefixId* registeredPrefixId, + const UnregisterPrefixSuccessCallback& onSuccess, + const UnregisterPrefixFailureCallback& onFailure) + { + unregisterPrefixImpl(registeredPrefixId, onSuccess, onFailure); + } + + /** + * @brief Publish data packet + * @param data the Data; a copy will be made, so that the caller is not required to + * maintain the argument unchanged + * + * This method can be called to satisfy incoming Interests, or to add Data packet into the cache + * of the local NDN forwarder if forwarder is configured to accept unsolicited Data. + * + * @throw OversizedPacketError encoded Data size exceeds MAX_NDN_PACKET_SIZE + */ + void + put(Data data); + + /** + * @brief Send a network NACK + * @param nack the Nack; a copy will be made, so that the caller is not required to + * maintain the argument unchanged + * @throw OversizedPacketError encoded Nack size exceeds MAX_NDN_PACKET_SIZE + */ + void + put(lp::Nack nack); + +public: // IO routine + /** + * @brief Process any data to receive or call timeout callbacks. + * + * This call will block forever (default timeout == 0) to process IO on the face. + * To exit cleanly on a producer, unset any Interest filters with unsetInterestFilter() and wait + * for processEvents() to return. To exit after an error, one can call shutdown(). + * In consumer applications, processEvents() will return when all expressed Interests have been + * satisfied, Nacked, or timed out. To terminate earlier, a consumer application should cancel + * all previously expressed and still-pending Interests. + * + * If a positive timeout is specified, then processEvents() will exit after this timeout, provided + * it is not stopped earlier with shutdown() or when all active events finish. processEvents() + * can be called repeatedly, if desired. + * + * If a negative timeout is specified, then processEvents will not block and will process only + * pending events. + * + * @param timeout maximum time to block the thread + * @param keepThread Keep thread in a blocked state (in event processing), even when + * there are no outstanding events (e.g., no Interest/Data is expected). + * If timeout is zero and this parameter is true, the only way to stop + * processEvents() is to call shutdown(). + * + * @note This may throw an exception for reading data or in the callback for processing + * the data. If you call this from an main event loop, you may want to catch and + * log/disregard all exceptions. + * + * @throw OversizedPacketError encoded packet size exceeds MAX_NDN_PACKET_SIZE + */ + void + processEvents(time::milliseconds timeout = time::milliseconds::zero(), + bool keepThread = false) + { + this->doProcessEvents(timeout, keepThread); + } + + /** + * @brief Shutdown face operations + * + * This method cancels all pending operations and closes connection to NDN Forwarder. + * + * Note that this method does not stop the io_service if it is shared between multiple Faces or + * with other IO objects (e.g., Scheduler). + * + * @warning Calling this method could cause outgoing packets to be lost. Producers that shut down + * immediately after sending a Data packet should instead use unsetInterestFilter() to + * shut down cleanly. + */ + void + shutdown(); + + /** + * @return Dereferenced nullptr (cannot use IoService in simulations), preserved for API compatibility + */ + DummyIoService& + getIoService() + { + static DummyIoService io; + return io; + } + +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED: + /** + * @brief Returns the underlying transport. + */ + shared_ptr + getTransport() const + { + return m_transport; + } + +protected: + virtual void + doProcessEvents(time::milliseconds timeout, bool keepThread); + +private: + /** + * @throw ConfigFile::Error on parse error and unsupported protocols + */ + shared_ptr + makeDefaultTransport(); + + /** + * @throw Face::Error on unsupported protocol + * @note shared_ptr is passed by value because ownership is transferred to this function + */ + void + construct(shared_ptr transport, KeyChain& keyChain); + + void + onReceiveElement(const Block& blockFromDaemon); + + void + cancelPendingInterest(const PendingInterestId* pendingInterestId); + + void + clearInterestFilter(const InterestFilterId* interestFilterId); + + void + unregisterPrefixImpl(const RegisteredPrefixId* registeredPrefixId, + const UnregisterPrefixSuccessCallback& onSuccess, + const UnregisterPrefixFailureCallback& onFailure); + +private: + shared_ptr m_transport; + + class Impl; + shared_ptr m_impl; + + friend PendingInterestHandle; + friend RegisteredPrefixHandle; + friend InterestFilterHandle; +}; + +/** \brief A handle of pending Interest. + * + * \code + * PendingInterestHandle hdl = face.expressInterest(interest, satisfyCb, nackCb, timeoutCb); + * hdl.cancel(); // cancel the pending Interest + * \endcode + * + * \warning Canceling a pending Interest after the face has been destructed may trigger undefined + * behavior. + */ +class PendingInterestHandle : public detail::CancelHandle +{ +public: + PendingInterestHandle() noexcept = default; + + PendingInterestHandle(Face& face, const PendingInterestId* id); +}; + +/** \brief A scoped handle of pending Interest. + * + * Upon destruction of this handle, the pending Interest is canceled automatically. + * Most commonly, the application keeps a ScopedPendingInterestHandle as a class member field, + * so that it can cleanup its pending Interest when the class instance is destructed. + * + * \code + * { + * ScopedPendingInterestHandle hdl = face.expressInterest(interest, satisfyCb, nackCb, timeoutCb); + * } // hdl goes out of scope, canceling the pending Interest + * \endcode + * + * \warning Canceling a pending Interest after the face has been destructed may trigger undefined + * behavior. + */ +using ScopedPendingInterestHandle = detail::ScopedCancelHandle; + +/** \brief A handle of registered prefix. + */ +class RegisteredPrefixHandle : public detail::CancelHandle +{ +public: + RegisteredPrefixHandle() noexcept + { + // This could have been '= default', but there's compiler bug in Apple clang 9.0.0, + // see https://stackoverflow.com/a/44693603 + } + + RegisteredPrefixHandle(Face& face, const RegisteredPrefixId* id); + + /** \brief Unregister the prefix. + * \warning Unregistering a prefix after the face has been destructed may trigger undefined + * behavior. + */ + void + unregister(const UnregisterPrefixSuccessCallback& onSuccess = nullptr, + const UnregisterPrefixFailureCallback& onFailure = nullptr); + +private: + Face* m_face = nullptr; + const RegisteredPrefixId* m_id = nullptr; +}; + +/** \brief A scoped handle of registered prefix. + * + * Upon destruction of this handle, the prefix is unregistered automatically. + * Most commonly, the application keeps a ScopedRegisteredPrefixHandle as a class member field, + * so that it can cleanup its prefix registration when the class instance is destructed. + * The application will not be notified whether the unregistration was successful. + * + * \code + * { + * ScopedRegisteredPrefixHandle hdl = face.registerPrefix(prefix, onSuccess, onFailure); + * } // hdl goes out of scope, unregistering the prefix + * \endcode + * + * \warning Unregistering a prefix after the face has been destructed may trigger undefined + * behavior. + */ +using ScopedRegisteredPrefixHandle = detail::ScopedCancelHandle; + +/** \brief A handle of registered Interest filter. + * + * \code + * InterestFilterHandle hdl = face.setInterestFilter(prefix, onInterest); + * hdl.cancel(); // unset the Interest filter + * \endcode + * + * \warning Unsetting an Interest filter after the face has been destructed may trigger + * undefined behavior. + */ +class InterestFilterHandle : public detail::CancelHandle +{ +public: + InterestFilterHandle() noexcept = default; + + InterestFilterHandle(Face& face, const InterestFilterId* id); +}; + +/** \brief A scoped handle of registered Interest filter. + * + * Upon destruction of this handle, the Interest filter is unset automatically. + * Most commonly, the application keeps a ScopedInterestFilterHandle as a class member field, + * so that it can cleanup its Interest filter when the class instance is destructed. + * + * \code + * { + * ScopedInterestFilterHandle hdl = face.setInterestFilter(prefix, onInterest); + * } // hdl goes out of scope, unsetting the Interest filter + * \endcode + * + * \warning Unsetting an Interest filter after the face has been destructed may trigger + * undefined behavior. + */ +using ScopedInterestFilterHandle = detail::ScopedCancelHandle; + +} // namespace ndn + +#endif // NDN_FACE_HPP diff --git a/ndn-cxx/impl/README.md b/ndn-cxx/impl/README.md new file mode 100644 index 000000000..3886c84e5 --- /dev/null +++ b/ndn-cxx/impl/README.md @@ -0,0 +1,6 @@ +# Implementation Detail + +This folder contains implementation detail of ndn-cxx library. +Declarations contained in these files are not considered public API and they can change without notice. + +Headers in this folder are not installed to the target system. diff --git a/src/common-pch.hpp b/ndn-cxx/impl/common-pch.hpp similarity index 76% rename from src/common-pch.hpp rename to ndn-cxx/impl/common-pch.hpp index ad4bbff5e..7f1ab5ae2 100644 --- a/src/common-pch.hpp +++ b/ndn-cxx/impl/common-pch.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,13 +19,13 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#ifndef NDN_COMMON_PCH_HPP -#define NDN_COMMON_PCH_HPP +#ifndef NDN_IMPL_COMMON_PCH_HPP +#define NDN_IMPL_COMMON_PCH_HPP // If the compiler supports precompiled headers, this header should be compiled // and included before anything else -#include "common.hpp" +#include "ndn-cxx/detail/common.hpp" // STL headers to precompile #include @@ -40,17 +40,12 @@ // Boost headers to precompile #include #include -#include #include #include #include #include -#include -#include -#include -#include +#include +#include +#include -// Other useful headers to precompile -#include "security/v1/cryptopp.hpp" - -#endif // NDN_COMMON_PCH_HPP +#endif // NDN_IMPL_COMMON_PCH_HPP diff --git a/ndn-cxx/impl/face-impl.hpp b/ndn-cxx/impl/face-impl.hpp new file mode 100644 index 000000000..0e1c2aad3 --- /dev/null +++ b/ndn-cxx/impl/face-impl.hpp @@ -0,0 +1,398 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_IMPL_FACE_IMPL_HPP +#define NDN_IMPL_FACE_IMPL_HPP + +#include "ndn-cxx/face.hpp" +#include "ndn-cxx/impl/lp-field-tag.hpp" +#include "ndn-cxx/impl/pending-interest.hpp" +#include "ndn-cxx/impl/registered-prefix.hpp" +#include "ndn-cxx/lp/packet.hpp" +#include "ndn-cxx/lp/tags.hpp" +#include "ndn-cxx/mgmt/nfd/command-options.hpp" +#include "ndn-cxx/mgmt/nfd/controller.hpp" +#include "ndn-cxx/transport/transport.hpp" +// #include "ndn-cxx/transport/tcp-transport.hpp" +// #include "ndn-cxx/transport/unix-transport.hpp" +#include "ndn-cxx/util/config-file.hpp" +#include "ndn-cxx/util/logger.hpp" +#include "ndn-cxx/util/scheduler.hpp" +#include "ndn-cxx/util/signal.hpp" + +NDN_LOG_INIT(ndn.Face); +// INFO level: prefix registration, etc. +// +// DEBUG level: packet logging. +// Each log entry starts with a direction symbol ('<' denotes an outgoing packet, '>' denotes an +// incoming packet) and a packet type symbol ('I' denotes an Interest, 'D' denotes a Data, 'N' +// denotes a Nack). Interest is printed in its URI string representation, Data is printed as name +// only, Nack is printed as the Interest followed by the Nack reason separated by a '~' symbol. A +// log line about an incoming packet may be followed by zero or more lines about Interest matching +// InterestFilter, Data satisfying Interest, or Nack rejecting Interest, which are also written at +// DEBUG level. +// +// TRACE level: more detailed unstructured messages. + +namespace ndn { + +/** @brief implementation detail of Face + */ +class Face::Impl : noncopyable +{ +public: + using PendingInterestTable = RecordContainer; + using InterestFilterTable = RecordContainer; + using RegisteredPrefixTable = RecordContainer; + + Impl(Face& face, KeyChain& keyChain) + : m_face(face) + , m_scheduler(m_face.getIoService()) + , m_nfdController(m_face, keyChain) + { + auto postOnEmptyPitOrNoRegisteredPrefixes = [this] { + m_scheduler.schedule(time::seconds(0), bind(&Impl::onEmptyPitOrNoRegisteredPrefixes, this)); + // without this extra "post", transport can get paused (-async_read) and then resumed + // (+async_read) from within onInterest/onData callback. After onInterest/onData + // finishes, there is another +async_read with the same memory block. A few of such + // async_read duplications can cause various effects and result in segfault. + }; + + m_pendingInterestTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes); + m_registeredPrefixTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes); + } + +public: // consumer + void + asyncExpressInterest(RecordId id, shared_ptr interest, + const DataCallback& afterSatisfied, + const NackCallback& afterNacked, + const TimeoutCallback& afterTimeout) + { + NDN_LOG_DEBUG("ensureConnected(true); + + const Interest& interest2 = *interest; + auto& entry = m_pendingInterestTable.put(id, std::move(interest), afterSatisfied, afterNacked, + afterTimeout, ref(m_scheduler)); + + lp::Packet lpPacket; + addFieldFromTag(lpPacket, interest2); + addFieldFromTag(lpPacket, interest2); + + entry.recordForwarding(); + m_face.m_transport->send(finishEncoding(std::move(lpPacket), interest2.wireEncode(), + 'I', interest2.getName())); + dispatchInterest(entry, interest2); + } + + void + asyncRemovePendingInterest(RecordId id) + { + m_pendingInterestTable.erase(id); + } + + void + asyncRemoveAllPendingInterests() + { + m_pendingInterestTable.clear(); + } + + /** @return whether the Data should be sent to the forwarder, if it does not come from the forwarder + */ + bool + satisfyPendingInterests(const Data& data) + { + bool hasAppMatch = false, hasForwarderMatch = false; + m_pendingInterestTable.removeIf([&] (PendingInterest& entry) { + if (!entry.getInterest()->matchesData(data)) { + return false; + } + NDN_LOG_DEBUG(" satisfying " << *entry.getInterest() << " from " << entry.getOrigin()); + + if (entry.getOrigin() == PendingInterestOrigin::APP) { + hasAppMatch = true; + entry.invokeDataCallback(data); + } + else { + hasForwarderMatch = true; + } + + return true; + }); + + // if Data matches no pending Interest record, it is sent to the forwarder as unsolicited Data + return hasForwarderMatch || !hasAppMatch; + } + + /** @return a Nack to be sent to the forwarder, or nullopt if no Nack should be sent + */ + optional + nackPendingInterests(const lp::Nack& nack) + { + optional outNack; + m_pendingInterestTable.removeIf([&] (PendingInterest& entry) { + if (!nack.getInterest().matchesInterest(*entry.getInterest())) { + return false; + } + NDN_LOG_DEBUG(" nacking " << *entry.getInterest() << " from " << entry.getOrigin()); + + optional outNack1 = entry.recordNack(nack); + if (!outNack1) { + return false; + } + + if (entry.getOrigin() == PendingInterestOrigin::APP) { + entry.invokeNackCallback(*outNack1); + } + else { + outNack = outNack1; + } + return true; + }); + + // send "least severe" Nack from any PendingInterest record originated from forwarder, because + // it is unimportant to consider Nack reason for the unlikely case when forwarder sends multiple + // Interests to an app in a short while + return outNack; + } + +public: // producer + void + asyncSetInterestFilter(RecordId id, const InterestFilter& filter, + const InterestCallback& onInterest) + { + NDN_LOG_INFO("setting InterestFilter: " << filter); + m_interestFilterTable.put(id, filter, onInterest); + } + + void + asyncUnsetInterestFilter(RecordId id) + { + const InterestFilterRecord* record = m_interestFilterTable.get(id); + if (record != nullptr) { + NDN_LOG_INFO("unsetting InterestFilter: " << record->getFilter()); + m_interestFilterTable.erase(id); + } + } + + void + processIncomingInterest(shared_ptr interest) + { + const Interest& interest2 = *interest; + auto& entry = m_pendingInterestTable.insert(std::move(interest), ref(m_scheduler)); + dispatchInterest(entry, interest2); + } + + void + dispatchInterest(PendingInterest& entry, const Interest& interest) + { + m_interestFilterTable.forEach([&] (const InterestFilterRecord& filter) { + if (!filter.doesMatch(entry)) { + return; + } + NDN_LOG_DEBUG(" matches " << filter.getFilter()); + entry.recordForwarding(); + filter.invokeInterestCallback(interest); + }); + } + + void + asyncPutData(const Data& data) + { + NDN_LOG_DEBUG("ensureConnected(true); + + lp::Packet lpPacket; + addFieldFromTag(lpPacket, data); + addFieldFromTag(lpPacket, data); + + m_face.m_transport->send(finishEncoding(std::move(lpPacket), data.wireEncode(), + 'D', data.getName())); + } + + void + asyncPutNack(const lp::Nack& nack) + { + NDN_LOG_DEBUG(" outNack = nackPendingInterests(nack); + if (!outNack) { + return; + } + + this->ensureConnected(true); + + lp::Packet lpPacket; + lpPacket.add(outNack->getHeader()); + addFieldFromTag(lpPacket, *outNack); + + const Interest& interest = outNack->getInterest(); + m_face.m_transport->send(finishEncoding(std::move(lpPacket), interest.wireEncode(), + 'N', interest.getName())); + } + +public: // prefix registration + RecordId + registerPrefix(const Name& prefix, + const RegisterPrefixSuccessCallback& onSuccess, + const RegisterPrefixFailureCallback& onFailure, + uint64_t flags, const nfd::CommandOptions& options, + const optional& filter, const InterestCallback& onInterest) + { + NDN_LOG_INFO("registering prefix: " << prefix); + auto id = m_registeredPrefixTable.allocateId(); + + m_nfdController.start( + nfd::ControlParameters().setName(prefix).setFlags(flags), + [=] (const nfd::ControlParameters&) { + NDN_LOG_INFO("registered prefix: " << prefix); + + RecordId filterId = 0; + if (filter) { + NDN_LOG_INFO("setting InterestFilter: " << *filter); + InterestFilterRecord& filterRecord = m_interestFilterTable.insert(*filter, onInterest); + filterId = filterRecord.getId(); + } + + m_registeredPrefixTable.put(id, prefix, options, filterId); + + if (onSuccess != nullptr) { + onSuccess(prefix); + } + }, + [=] (const nfd::ControlResponse& resp) { + NDN_LOG_INFO("register prefix failed: " << prefix); + onFailure(prefix, resp.getText()); + }, + options); + + return id; + } + + void + asyncUnregisterPrefix(RecordId id, + const UnregisterPrefixSuccessCallback& onSuccess, + const UnregisterPrefixFailureCallback& onFailure) + { + const RegisteredPrefix* record = m_registeredPrefixTable.get(id); + if (record == nullptr) { + if (onFailure != nullptr) { + onFailure("Unrecognized RegisteredPrefixHandle"); + } + return; + } + + if (record->getFilterId() != 0) { + asyncUnsetInterestFilter(record->getFilterId()); + } + + NDN_LOG_INFO("unregistering prefix: " << record->getPrefix()); + + m_nfdController.start( + nfd::ControlParameters().setName(record->getPrefix()), + [=] (const nfd::ControlParameters&) { + NDN_LOG_INFO("unregistered prefix: " << record->getPrefix()); + m_registeredPrefixTable.erase(id); + + if (onSuccess != nullptr) { + onSuccess(); + } + }, + [=] (const nfd::ControlResponse& resp) { + NDN_LOG_INFO("unregister prefix failed: " << record->getPrefix()); + onFailure(resp.getText()); + }, + record->getCommandOptions()); + } + +public: // IO routine + void + ensureConnected(bool wantResume) + { + if (!m_face.m_transport->isConnected()) { + m_face.m_transport->connect([this] (const Block& wire) { m_face.onReceiveElement(wire); }); + } + + if (wantResume && !m_face.m_transport->isReceiving()) { + m_face.m_transport->resume(); + } + } + + void + onEmptyPitOrNoRegisteredPrefixes() + { + if (m_pendingInterestTable.empty() && m_registeredPrefixTable.empty()) { + m_face.m_transport->pause(); + } + } + + void + shutdown() + { + m_pendingInterestTable.clear(); + m_registeredPrefixTable.clear(); + } + +private: + /** @brief Finish packet encoding + * @param lpPacket NDNLP packet without FragmentField + * @param wire wire encoding of Interest or Data + * @param pktType packet type, 'I' for Interest, 'D' for Data, 'N' for Nack + * @param name packet name + * @return wire encoding of either NDNLP or bare network packet + * @throw Face::OversizedPacketError wire encoding exceeds limit + */ + Block + finishEncoding(lp::Packet&& lpPacket, Block wire, char pktType, const Name& name) + { + if (!lpPacket.empty()) { + lpPacket.add(std::make_pair(wire.begin(), wire.end())); + wire = lpPacket.wireEncode(); + } + + if (wire.size() > MAX_NDN_PACKET_SIZE) { + NDN_THROW(Face::OversizedPacketError(pktType, name, wire.size())); + } + + return wire; + } + +private: + Face& m_face; + Scheduler m_scheduler; + scheduler::ScopedEventId m_processEventsTimeoutEvent; + nfd::Controller m_nfdController; + + PendingInterestTable m_pendingInterestTable; + InterestFilterTable m_interestFilterTable; + RegisteredPrefixTable m_registeredPrefixTable; + + friend class Face; +}; + +} // namespace ndn + +#endif // NDN_IMPL_FACE_IMPL_HPP diff --git a/ndn-cxx/impl/interest-filter-record.hpp b/ndn-cxx/impl/interest-filter-record.hpp new file mode 100644 index 000000000..e3c7ea647 --- /dev/null +++ b/ndn-cxx/impl/interest-filter-record.hpp @@ -0,0 +1,91 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_IMPL_INTEREST_FILTER_RECORD_HPP +#define NDN_IMPL_INTEREST_FILTER_RECORD_HPP + +#include "ndn-cxx/impl/pending-interest.hpp" + +namespace ndn { + +/** + * @brief Opaque type to identify an InterestFilterRecord + */ +class InterestFilterId; + +static_assert(sizeof(const InterestFilterId*) == sizeof(RecordId), ""); + +/** + * @brief associates an InterestFilter with Interest callback + */ +class InterestFilterRecord : public RecordBase +{ +public: + /** + * @brief Construct an Interest filter record + * + * @param filter an InterestFilter that represents what Interest should invoke the callback + * @param interestCallback invoked when matching Interest is received + */ + InterestFilterRecord(const InterestFilter& filter, + const InterestCallback& interestCallback) + : m_filter(filter) + , m_interestCallback(interestCallback) + { + } + + const InterestFilter& + getFilter() const + { + return m_filter; + } + + /** + * @brief Check if Interest name matches the filter + * @param name Interest Name + */ + bool + doesMatch(const PendingInterest& entry) const + { + return (entry.getOrigin() == PendingInterestOrigin::FORWARDER || m_filter.allowsLoopback()) && + m_filter.doesMatch(entry.getInterest()->getName()); + } + + /** + * @brief invokes the InterestCallback + * @note This method does nothing if the Interest callback is empty + */ + void + invokeInterestCallback(const Interest& interest) const + { + if (m_interestCallback != nullptr) { + m_interestCallback(m_filter, interest); + } + } + +private: + InterestFilter m_filter; + InterestCallback m_interestCallback; +}; + +} // namespace ndn + +#endif // NDN_IMPL_INTEREST_FILTER_RECORD_HPP diff --git a/ndn-cxx/impl/lp-field-tag.hpp b/ndn-cxx/impl/lp-field-tag.hpp new file mode 100644 index 000000000..b30e51aed --- /dev/null +++ b/ndn-cxx/impl/lp-field-tag.hpp @@ -0,0 +1,51 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_IMPL_LP_FIELD_TAG_HPP +#define NDN_IMPL_LP_FIELD_TAG_HPP + +#include "ndn-cxx/lp/packet.hpp" +#include "ndn-cxx/lp/tags.hpp" + +namespace ndn { + +template +void +addFieldFromTag(lp::Packet& lpPacket, const Packet& packet) +{ + shared_ptr tag = static_cast(packet).getTag(); + if (tag != nullptr) { + lpPacket.add(*tag); + } +} + +template +void +addTagFromField(Packet& packet, const lp::Packet& lpPacket) +{ + if (lpPacket.has()) { + packet.setTag(make_shared(lpPacket.get())); + } +} + +} // namespace ndn + +#endif // NDN_IMPL_LP_FIELD_TAG_HPP diff --git a/ndn-cxx/impl/name-component-types.hpp b/ndn-cxx/impl/name-component-types.hpp new file mode 100644 index 000000000..760495fad --- /dev/null +++ b/ndn-cxx/impl/name-component-types.hpp @@ -0,0 +1,418 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_IMPL_NAME_COMPONENT_TYPES_HPP +#define NDN_IMPL_NAME_COMPONENT_TYPES_HPP + +#include "ndn-cxx/name-component.hpp" +#include "ndn-cxx/util/sha256.hpp" +#include "ndn-cxx/util/string-helper.hpp" + +#include +#include + +namespace ndn { +namespace name { +namespace detail { + +/** \brief Declare rules for a NameComponent type. + */ +class ComponentType : noncopyable +{ +public: + using Error = Component::Error; + + virtual + ~ComponentType() = default; + + /** \brief Throw Component::Error if \p comp is invalid. + */ + virtual void + check(const Component& comp) const + { + } + + /** \brief Calculate the successor of \p comp. + * + * If \p comp is the maximum possible value of this component type, return true to indicate + * that the successor should have a greater TLV-TYPE. + */ + virtual std::pair + getSuccessor(const Component& comp) const + { + return {false, getSuccessorImpl(comp).second}; + } + + /** \brief Return the minimum allowable TLV-VALUE of this component type. + */ + virtual const std::vector& + getMinValue() const + { + static std::vector value; + return value; + } + + /** \brief Return the prefix of the alternate URI representation. + * + * NDN URI specification allows a name component type to declare an alternate URI representation + * in the form of `=`, in addition to the plain `=` + * syntax. + * + * \return the `` portion of the alternate URI representation. + * \retval nullptr this component does not have an alternate URI representation. + */ + virtual const char* + getAltUriPrefix() const + { + return nullptr; + } + + /** \brief Parse component from alternate URI representation. + * \param input the `` portion of the alternate URI representation. + * \throw Component::Error + * \pre getAltUriPrefix() != nullptr + */ + virtual Component + parseAltUriValue(const std::string&) const + { + NDN_CXX_UNREACHABLE; + } + + /** \brief Write URI representation of \p comp to \p os. + * + * This base class implementation encodes the component in the plain + * `=` syntax. + */ + virtual void + writeUri(std::ostream& os, const Component& comp) const + { + os << comp.type() << '='; + writeUriEscapedValue(os, comp); + } + +protected: + /** \brief Calculate the successor of \p comp, extending TLV-LENGTH if value overflows. + * \return whether TLV-LENGTH was extended, and the successor + */ + std::pair + getSuccessorImpl(const Component& comp) const + { + EncodingBuffer encoder(comp.size() + 9, 9); + // leave room for additional byte when TLV-VALUE overflows, and for TLV-LENGTH size increase + + bool isOverflow = true; + size_t i = comp.value_size(); + for (; isOverflow && i > 0; i--) { + uint8_t newValue = static_cast((comp.value()[i - 1] + 1) & 0xFF); + encoder.prependByte(newValue); + isOverflow = (newValue == 0); + } + encoder.prependByteArray(comp.value(), i); + + if (isOverflow) { + // new name component has to be extended + encoder.appendByte(0); + } + + encoder.prependVarNumber(encoder.size()); + encoder.prependVarNumber(comp.type()); + return {isOverflow, encoder.block()}; + } + + /** \brief Write TLV-VALUE as `` of NDN URI syntax. + */ + void + writeUriEscapedValue(std::ostream& os, const Component& comp) const + { + bool isAllPeriods = std::all_of(comp.value_begin(), comp.value_end(), + [] (uint8_t x) { return x == '.'; }); + if (isAllPeriods) { + os << "..."; + } + escape(os, reinterpret_cast(comp.value()), comp.value_size()); + } +}; + +/** \brief Rules for GenericNameComponent. + * + * GenericNameComponent has an alternate URI representation that omits the `` prefix. + * This must be special-cased in the caller, and is not handled by this class. + */ +class GenericNameComponentType final : public ComponentType +{ +public: + void + writeUri(std::ostream& os, const Component& comp) const final + { + writeUriEscapedValue(os, comp); + } +}; + +/** \brief Rules for a component type holding a SHA256 digest value, written as + * a hex string in URI representation. + */ +class Sha256ComponentType final : public ComponentType +{ +public: + Sha256ComponentType(uint32_t type, const std::string& typeName, const std::string& uriPrefix) + : m_type(type) + , m_typeName(typeName) + , m_uriPrefix(uriPrefix) + { + } + + bool + match(const Component& comp) const + { + return comp.type() == m_type && comp.value_size() == util::Sha256::DIGEST_SIZE; + } + + void + check(const Component& comp) const final + { + BOOST_ASSERT(comp.type() == m_type); + if (comp.value_size() != util::Sha256::DIGEST_SIZE) { + NDN_THROW(Error(m_typeName + " TLV-LENGTH must be " + to_string(util::Sha256::DIGEST_SIZE))); + } + } + + Component + create(ConstBufferPtr value) const + { + return Component(Block(m_type, std::move(value))); + } + + Component + create(const uint8_t* value, size_t valueSize) const + { + return Component(makeBinaryBlock(m_type, value, valueSize)); + } + + std::pair + getSuccessor(const Component& comp) const final + { + bool isExtended = false; + Block successor; + std::tie(isExtended, successor) = getSuccessorImpl(comp); + if (isExtended) { + return {true, comp}; + } + return {false, Component(successor)}; + } + + const std::vector& + getMinValue() const final + { + static std::vector value(util::Sha256::DIGEST_SIZE); + return value; + } + + const char* + getAltUriPrefix() const final + { + return m_uriPrefix.data(); + } + + Component + parseAltUriValue(const std::string& input) const final + { + shared_ptr value; + try { + value = fromHex(input); + } + catch (const StringHelperError&) { + NDN_THROW(Error("Cannot convert to " + m_typeName + " (invalid hex encoding)")); + } + return Component(m_type, std::move(value)); + } + + void + writeUri(std::ostream& os, const Component& comp) const final + { + os << m_uriPrefix << '='; + printHex(os, comp.value(), comp.value_size(), false); + } + +private: + const uint32_t m_type; + const std::string m_typeName; + const std::string m_uriPrefix; +}; + +inline const Sha256ComponentType& +getComponentType1() +{ + static const Sha256ComponentType ct1(tlv::ImplicitSha256DigestComponent, + "ImplicitSha256DigestComponent", "sha256digest"); + return ct1; +} + +inline const Sha256ComponentType& +getComponentType2() +{ + static const Sha256ComponentType ct2(tlv::ParametersSha256DigestComponent, + "ParametersSha256DigestComponent", "params-sha256"); + return ct2; +} + +/** \brief Rules for a component type holding a nonNegativeInteger value, written as + * a decimal number in URI representation. + */ +class DecimalComponentType final : public ComponentType +{ +public: + DecimalComponentType(uint32_t type, const std::string& typeName, const std::string& uriPrefix) + : m_type(type) + , m_typeName(typeName) + , m_uriPrefix(uriPrefix) + { + } + + // NOTE: + // We do not override check() and ensure that the component value is a well-formed + // nonNegativeInteger, because the application may be using the same typed component + // with different syntax and semantics. + + const char* + getAltUriPrefix() const final + { + return m_uriPrefix.data(); + } + + Component + parseAltUriValue(const std::string& input) const final + { + uint64_t n = 0; + try { + n = std::stoull(input); + } + catch (const std::invalid_argument&) { + NDN_THROW(Error("Cannot convert to " + m_typeName + " (invalid format)")); + } + catch (const std::out_of_range&) { + NDN_THROW(Error("Cannot convert to " + m_typeName + " (out of range)")); + } + if (to_string(n) != input) { + NDN_THROW(Error("Cannot convert to " + m_typeName + " (invalid format)")); + } + return Component::fromNumber(n, m_type); + } + + void + writeUri(std::ostream& os, const Component& comp) const final + { + if (comp.isNumber()) { + os << m_uriPrefix << '=' << comp.toNumber(); + } + else { + ComponentType::writeUri(os, comp); + } + } + +private: + const uint32_t m_type; + const std::string m_typeName; + const std::string m_uriPrefix; +}; + +/** \brief Rules regarding NameComponent types. + */ +class ComponentTypeTable : noncopyable +{ +public: + ComponentTypeTable(); + + /** \brief Retrieve ComponentType by TLV-TYPE. + */ + const ComponentType& + get(uint32_t type) const + { + if (type >= m_table.size() || m_table[type] == nullptr) { + return m_baseType; + } + return *m_table[type]; + } + + /** \brief Retrieve ComponentType by alternate URI prefix. + */ + const ComponentType* + findByUriPrefix(const std::string& prefix) const + { + auto it = m_uriPrefixes.find(prefix); + if (it == m_uriPrefixes.end()) { + return nullptr; + } + return it->second; + } + +private: + void + set(uint32_t type, const ComponentType& ct) + { + m_table.at(type) = &ct; + if (ct.getAltUriPrefix() != nullptr) { + m_uriPrefixes[ct.getAltUriPrefix()] = &ct; + } + } + +private: + const ComponentType m_baseType; + std::array m_table; + std::unordered_map m_uriPrefixes; +}; + +inline +ComponentTypeTable::ComponentTypeTable() +{ + m_table.fill(nullptr); + + set(tlv::ImplicitSha256DigestComponent, getComponentType1()); + set(tlv::ParametersSha256DigestComponent, getComponentType2()); + + static const GenericNameComponentType ct8; + set(tlv::GenericNameComponent, ct8); + + static const DecimalComponentType ct33(tlv::SegmentNameComponent, "SegmentNameComponent", "seg"); + set(tlv::SegmentNameComponent, ct33); + static const DecimalComponentType ct34(tlv::ByteOffsetNameComponent, "ByteOffsetNameComponent", "off"); + set(tlv::ByteOffsetNameComponent, ct34); + static const DecimalComponentType ct35(tlv::VersionNameComponent, "VersionNameComponent", "v"); + set(tlv::VersionNameComponent, ct35); + static const DecimalComponentType ct36(tlv::TimestampNameComponent, "TimestampNameComponent", "t"); + set(tlv::TimestampNameComponent, ct36); + static const DecimalComponentType ct37(tlv::SequenceNumNameComponent, "SequenceNumNameComponent", "seq"); + set(tlv::SequenceNumNameComponent, ct37); +} + +/** \brief Get the global ComponentTypeTable. + */ +inline const ComponentTypeTable& +getComponentTypeTable() +{ + static ComponentTypeTable ctt; + return ctt; +} + +} // namespace detail +} // namespace name +} // namespace ndn + +#endif // NDN_IMPL_NAME_COMPONENT_TYPES_HPP diff --git a/ndn-cxx/impl/pending-interest.hpp b/ndn-cxx/impl/pending-interest.hpp new file mode 100644 index 000000000..a7660564f --- /dev/null +++ b/ndn-cxx/impl/pending-interest.hpp @@ -0,0 +1,198 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_IMPL_PENDING_INTEREST_HPP +#define NDN_IMPL_PENDING_INTEREST_HPP + +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/face.hpp" +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/impl/record-container.hpp" +#include "ndn-cxx/lp/nack.hpp" +#include "ndn-cxx/util/scheduler.hpp" + +namespace ndn { + +/** + * @brief Opaque type to identify a PendingInterest + */ +class PendingInterestId; + +static_assert(sizeof(const PendingInterestId*) == sizeof(RecordId), ""); + +/** + * @brief Indicates where a pending Interest came from + */ +enum class PendingInterestOrigin +{ + APP, ///< Interest was received from this app via Face::expressInterest API + FORWARDER ///< Interest was received from the forwarder via Transport +}; + +std::ostream& +operator<<(std::ostream& os, PendingInterestOrigin origin) +{ + switch (origin) { + case PendingInterestOrigin::APP: + return os << "app"; + case PendingInterestOrigin::FORWARDER: + return os << "forwarder"; + } + NDN_CXX_UNREACHABLE; +} + +/** + * @brief Stores a pending Interest and associated callbacks + */ +class PendingInterest : public RecordBase +{ +public: + /** + * @brief Construct a pending Interest record for an Interest from Face::expressInterest + * + * The timeout is set based on the current time and InterestLifetime. + * This class will invoke the timeout callback unless the record is deleted before timeout. + */ + PendingInterest(shared_ptr interest, const DataCallback& dataCallback, + const NackCallback& nackCallback, const TimeoutCallback& timeoutCallback, + Scheduler& scheduler) + : m_interest(std::move(interest)) + , m_origin(PendingInterestOrigin::APP) + , m_dataCallback(dataCallback) + , m_nackCallback(nackCallback) + , m_timeoutCallback(timeoutCallback) + , m_nNotNacked(0) + { + scheduleTimeoutEvent(scheduler); + } + + /** + * @brief Construct a pending Interest record for an Interest from NFD + */ + PendingInterest(shared_ptr interest, Scheduler& scheduler) + : m_interest(std::move(interest)) + , m_origin(PendingInterestOrigin::FORWARDER) + , m_nNotNacked(0) + { + scheduleTimeoutEvent(scheduler); + } + + shared_ptr + getInterest() const + { + return m_interest; + } + + PendingInterestOrigin + getOrigin() const + { + return m_origin; + } + + /** + * @brief Record that the Interest has been forwarded to one destination + * + * A "destination" could be either a local InterestFilter or the forwarder. + */ + void + recordForwarding() + { + ++m_nNotNacked; + } + + /** + * @brief Record an incoming Nack against a forwarded Interest + * @return least severe Nack if all destinations where the Interest was forwarded have Nacked; + * otherwise, nullopt + */ + optional + recordNack(const lp::Nack& nack) + { + --m_nNotNacked; + BOOST_ASSERT(m_nNotNacked >= 0); + + if (!m_leastSevereNack || lp::isLessSevere(nack.getReason(), m_leastSevereNack->getReason())) { + m_leastSevereNack = nack; + } + + return m_nNotNacked > 0 ? nullopt : m_leastSevereNack; + } + + /** + * @brief Invoke the Data callback + * @note This method does nothing if the Data callback is empty + */ + void + invokeDataCallback(const Data& data) + { + if (m_dataCallback != nullptr) { + m_dataCallback(*m_interest, data); + } + } + + /** + * @brief Invoke the Nack callback + * @note This method does nothing if the Nack callback is empty + */ + void + invokeNackCallback(const lp::Nack& nack) + { + if (m_nackCallback != nullptr) { + m_nackCallback(*m_interest, nack); + } + } + +private: + void + scheduleTimeoutEvent(Scheduler& scheduler) + { + m_timeoutEvent = scheduler.schedule(m_interest->getInterestLifetime(), + [=] { this->invokeTimeoutCallback(); }); + } + + /** + * @brief Invoke the timeout callback (if non-empty) and the deleter + */ + void + invokeTimeoutCallback() + { + if (m_timeoutCallback) { + m_timeoutCallback(*m_interest); + } + + deleteSelf(); + } + +private: + shared_ptr m_interest; + PendingInterestOrigin m_origin; + DataCallback m_dataCallback; + NackCallback m_nackCallback; + TimeoutCallback m_timeoutCallback; + scheduler::ScopedEventId m_timeoutEvent; + int m_nNotNacked; ///< number of Interest destinations that have not Nacked + optional m_leastSevereNack; + std::function m_deleter; +}; + +} // namespace ndn + +#endif // NDN_IMPL_PENDING_INTEREST_HPP diff --git a/ndn-cxx/impl/record-container.hpp b/ndn-cxx/impl/record-container.hpp new file mode 100644 index 000000000..94b2f5e0d --- /dev/null +++ b/ndn-cxx/impl/record-container.hpp @@ -0,0 +1,199 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_IMPL_RECORD_CONTAINER_HPP +#define NDN_IMPL_RECORD_CONTAINER_HPP + +#include "ndn-cxx/detail/common.hpp" +#include "ndn-cxx/util/signal.hpp" + +#include + +namespace ndn { + +using RecordId = uintptr_t; + +template +class RecordContainer; + +/** \brief Template of PendingInterest, RegisteredPrefix, and InterestFilterRecord. + * \tparam T concrete type + */ +template +class RecordBase : noncopyable +{ +public: + RecordId + getId() const + { + BOOST_ASSERT(m_id != 0); + return m_id; + } + +protected: + ~RecordBase() = default; + + /** \brief Delete this record from the container. + */ + void + deleteSelf() + { + BOOST_ASSERT(m_container != nullptr); + m_container->erase(m_id); + } + +private: + RecordContainer* m_container = nullptr; + RecordId m_id = 0; + friend RecordContainer; +}; + +/** \brief Container of PendingInterest, RegisteredPrefix, or InterestFilterRecord. + * \tparam T record type + */ +template +class RecordContainer +{ +public: + using Record = T; + using Container = std::map; + + /** \brief Retrieve record by ID. + */ + Record* + get(RecordId id) + { + auto i = m_container.find(id); + if (i == m_container.end()) { + return nullptr; + } + return &i->second; + } + + /** \brief Insert a record with given ID. + */ + template + Record& + put(RecordId id, TArgs&&... args) + { + BOOST_ASSERT(id != 0); + auto it = m_container.emplace(std::piecewise_construct, std::forward_as_tuple(id), + std::forward_as_tuple(std::forward(args)...)); + BOOST_ASSERT(it.second); + + Record& record = it.first->second; + record.m_container = this; + record.m_id = id; + return record; + } + + RecordId + allocateId() + { + return ++m_lastId; + } + + /** \brief Insert a record with newly assigned ID. + */ + template + Record& + insert(TArgs&&... args) + { + return put(allocateId(), std::forward(args)...); + } + + void + erase(RecordId id) + { + m_container.erase(id); + if (empty()) { + this->onEmpty(); + } + } + + void + clear() + { + m_container.clear(); + this->onEmpty(); + } + + /** \brief Visit all records with the option to erase. + * \tparam Visitor function of type 'bool f(Record& record)' + * \param f visitor function, return true to erase record + */ + template + void + removeIf(const Visitor& f) + { + for (auto i = m_container.begin(); i != m_container.end(); ) { + bool wantErase = f(i->second); + if (wantErase) { + i = m_container.erase(i); + } + else { + ++i; + } + } + if (empty()) { + this->onEmpty(); + } + } + + /** \brief Visit all records. + * \tparam Visitor function of type 'void f(Record& record)' + * \param f visitor function + */ + template + void + forEach(const Visitor& f) + { + removeIf([&f] (Record& record) { + f(record); + return false; + }); + } + + NDN_CXX_NODISCARD bool + empty() const noexcept + { + return m_container.empty(); + } + + size_t + size() const noexcept + { + return m_container.size(); + } + +public: + /** \brief Signals when container becomes empty + */ + util::Signal> onEmpty; + +private: + Container m_container; + std::atomic m_lastId{0}; +}; + +} // namespace ndn + +#endif // NDN_IMPL_RECORD_CONTAINER_HPP diff --git a/ndn-cxx/impl/registered-prefix.hpp b/ndn-cxx/impl/registered-prefix.hpp new file mode 100644 index 000000000..423aec1c4 --- /dev/null +++ b/ndn-cxx/impl/registered-prefix.hpp @@ -0,0 +1,78 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_IMPL_REGISTERED_PREFIX_HPP +#define NDN_IMPL_REGISTERED_PREFIX_HPP + +#include "ndn-cxx/impl/interest-filter-record.hpp" +#include "ndn-cxx/mgmt/nfd/command-options.hpp" +#include "ndn-cxx/mgmt/nfd/control-parameters.hpp" + +namespace ndn { + +/** + * @brief Opaque type to identify a RegisteredPrefix + */ +class RegisteredPrefixId; + +static_assert(sizeof(const RegisteredPrefixId*) == sizeof(RecordId), ""); + +/** + * @brief stores information about a prefix registered in NDN forwarder + */ +class RegisteredPrefix : public RecordBase +{ +public: + RegisteredPrefix(const Name& prefix, const nfd::CommandOptions& options, + RecordId filterId = 0) + : m_prefix(prefix) + , m_options(options) + , m_filterId(filterId) + { + } + + const Name& + getPrefix() const + { + return m_prefix; + } + + const nfd::CommandOptions& + getCommandOptions() const + { + return m_options; + } + + RecordId + getFilterId() const + { + return m_filterId; + } + +private: + Name m_prefix; + nfd::CommandOptions m_options; + RecordId m_filterId; +}; + +} // namespace ndn + +#endif // NDN_IMPL_REGISTERED_PREFIX_HPP diff --git a/src/util/in-memory-storage-entry.cpp b/ndn-cxx/ims/in-memory-storage-entry.cpp similarity index 76% rename from src/util/in-memory-storage-entry.cpp rename to ndn-cxx/ims/in-memory-storage-entry.cpp index c0f5e5975..5720bc9a6 100644 --- a/src/util/in-memory-storage-entry.cpp +++ b/ndn-cxx/ims/in-memory-storage-entry.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,10 +19,9 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "in-memory-storage-entry.hpp" +#include "ndn-cxx/ims/in-memory-storage-entry.hpp" namespace ndn { -namespace util { InMemoryStorageEntry::InMemoryStorageEntry() : m_isFresh(true) @@ -33,7 +32,7 @@ void InMemoryStorageEntry::release() { m_dataPacket.reset(); - m_markStaleEventId.reset(); + m_markStaleEventId.cancel(); } void @@ -44,16 +43,9 @@ InMemoryStorageEntry::setData(const Data& data) } void -InMemoryStorageEntry::setMarkStaleEventId(unique_ptr&& markStaleEventId) +InMemoryStorageEntry::scheduleMarkStale(Scheduler& sched, time::nanoseconds after) { - m_markStaleEventId = std::move(markStaleEventId); + m_markStaleEventId = sched.schedule(after, [this] { m_isFresh = false; }); } -void -InMemoryStorageEntry::markStale() -{ - m_isFresh = false; -} - -} // namespace util } // namespace ndn diff --git a/src/util/in-memory-storage-entry.hpp b/ndn-cxx/ims/in-memory-storage-entry.hpp similarity index 75% rename from src/util/in-memory-storage-entry.hpp rename to ndn-cxx/ims/in-memory-storage-entry.hpp index 6e77b3dee..b25770919 100644 --- a/src/util/in-memory-storage-entry.hpp +++ b/ndn-cxx/ims/in-memory-storage-entry.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,23 +19,20 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#ifndef NDN_UTIL_IN_MEMORY_STORAGE_ENTRY_HPP -#define NDN_UTIL_IN_MEMORY_STORAGE_ENTRY_HPP +#ifndef NDN_IMS_IN_MEMORY_STORAGE_ENTRY_HPP +#define NDN_IMS_IN_MEMORY_STORAGE_ENTRY_HPP -#include "../common.hpp" -#include "../interest.hpp" -#include "../data.hpp" -#include "scheduler-scoped-event-id.hpp" +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/util/scheduler.hpp" namespace ndn { -namespace util { - /** @brief Represents an in-memory storage entry +/** @brief Represents an in-memory storage entry */ class InMemoryStorageEntry : noncopyable { public: - /** @brief Create an entry */ InMemoryStorageEntry(); @@ -62,7 +59,6 @@ class InMemoryStorageEntry : noncopyable return m_dataPacket->getFullName(); } - /** @brief Returns the Data packet stored in the in-memory storage entry */ const Data& @@ -71,7 +67,6 @@ class InMemoryStorageEntry : noncopyable return *m_dataPacket; } - /** @brief Changes the content of in-memory storage entry * * This method also allows data to satisfy Interest with MustBeFresh @@ -79,15 +74,10 @@ class InMemoryStorageEntry : noncopyable void setData(const Data& data); - /** @brief Set eventId for the markStale event. - */ - void - setMarkStaleEventId(unique_ptr&& eventId); - - /** @brief Disable the data from satisfying interest with MustBeFresh + /** @brief Schedule an event to mark this entry as non-fresh. */ void - markStale(); + scheduleMarkStale(Scheduler& sched, time::nanoseconds after); /** @brief Check if the data can satisfy an interest with MustBeFresh */ @@ -101,10 +91,9 @@ class InMemoryStorageEntry : noncopyable shared_ptr m_dataPacket; bool m_isFresh; - unique_ptr m_markStaleEventId; + scheduler::ScopedEventId m_markStaleEventId; }; -} // namespace util } // namespace ndn -#endif // NDN_UTIL_IN_MEMORY_STORAGE_ENTRY_HPP +#endif // NDN_IMS_IN_MEMORY_STORAGE_ENTRY_HPP diff --git a/src/util/in-memory-storage-fifo.cpp b/ndn-cxx/ims/in-memory-storage-fifo.cpp similarity index 88% rename from src/util/in-memory-storage-fifo.cpp rename to ndn-cxx/ims/in-memory-storage-fifo.cpp index 0899024de..fcbd35d69 100644 --- a/src/util/in-memory-storage-fifo.cpp +++ b/ndn-cxx/ims/in-memory-storage-fifo.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,17 +19,16 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "in-memory-storage-fifo.hpp" +#include "ndn-cxx/ims/in-memory-storage-fifo.hpp" namespace ndn { -namespace util { InMemoryStorageFifo::InMemoryStorageFifo(size_t limit) : InMemoryStorage(limit) { } -InMemoryStorageFifo::InMemoryStorageFifo(boost::asio::io_service& ioService, size_t limit) +InMemoryStorageFifo::InMemoryStorageFifo(DummyIoService& ioService, size_t limit) : InMemoryStorage(ioService, limit) { } @@ -62,5 +61,4 @@ InMemoryStorageFifo::beforeErase(InMemoryStorageEntry* entry) m_cleanupIndex.get().erase(it); } -} // namespace util } // namespace ndn diff --git a/src/util/in-memory-storage-fifo.hpp b/ndn-cxx/ims/in-memory-storage-fifo.hpp similarity index 79% rename from src/util/in-memory-storage-fifo.hpp rename to ndn-cxx/ims/in-memory-storage-fifo.hpp index 371028497..e196829e2 100644 --- a/src/util/in-memory-storage-fifo.hpp +++ b/ndn-cxx/ims/in-memory-storage-fifo.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,50 +19,48 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#ifndef NDN_UTIL_IN_MEMORY_STORAGE_FIFO_HPP -#define NDN_UTIL_IN_MEMORY_STORAGE_FIFO_HPP +#ifndef NDN_IMS_IN_MEMORY_STORAGE_FIFO_HPP +#define NDN_IMS_IN_MEMORY_STORAGE_FIFO_HPP -#include "in-memory-storage.hpp" +#include "ndn-cxx/ims/in-memory-storage.hpp" #include -#include #include +#include namespace ndn { -namespace util { -/** @brief Provides in-memory storage employing FIFO replacement policy, which is first in first - * out. +/** @brief Provides in-memory storage employing First-In-First-Out (FIFO) replacement policy. */ class InMemoryStorageFifo : public InMemoryStorage { public: explicit - InMemoryStorageFifo(size_t limit = 10); + InMemoryStorageFifo(size_t limit = 16); explicit - InMemoryStorageFifo(boost::asio::io_service& ioService, size_t limit = 10); + InMemoryStorageFifo(DummyIoService& ioService, size_t limit = 16); NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED: /** @brief Removes one Data packet from in-memory storage based on FIFO * @return{ whether the Data was removed } */ - virtual bool + bool evictItem() override; /** @brief Update the entry after a entry is successfully inserted, add it to the cleanupIndex */ - virtual void + void afterInsert(InMemoryStorageEntry* entry) override; /** @brief Update the entry or other data structures before a entry is successfully erased, * erase it from the cleanupIndex */ - virtual void + void beforeErase(InMemoryStorageEntry* entry) override; private: - //multi_index_container to implement FIFO + // multi_index_container to implement FIFO class byArrival; class byEntity; @@ -87,7 +85,6 @@ class InMemoryStorageFifo : public InMemoryStorage CleanupIndex m_cleanupIndex; }; -} // namespace util } // namespace ndn -#endif // NDN_UTIL_IN_MEMORY_STORAGE_FIFO_HPP +#endif // NDN_IMS_IN_MEMORY_STORAGE_FIFO_HPP diff --git a/src/util/in-memory-storage-lfu.cpp b/ndn-cxx/ims/in-memory-storage-lfu.cpp similarity index 90% rename from src/util/in-memory-storage-lfu.cpp rename to ndn-cxx/ims/in-memory-storage-lfu.cpp index 0c08f1c0a..b2de51ee3 100644 --- a/src/util/in-memory-storage-lfu.cpp +++ b/ndn-cxx/ims/in-memory-storage-lfu.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,17 +19,16 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "in-memory-storage-lfu.hpp" +#include "ndn-cxx/ims/in-memory-storage-lfu.hpp" namespace ndn { -namespace util { InMemoryStorageLfu::InMemoryStorageLfu(size_t limit) : InMemoryStorage(limit) { } -InMemoryStorageLfu::InMemoryStorageLfu(boost::asio::io_service& ioService, size_t limit) +InMemoryStorageLfu::InMemoryStorageLfu(DummyIoService& ioService, size_t limit) : InMemoryStorage(ioService, limit) { } @@ -72,5 +71,4 @@ InMemoryStorageLfu::afterAccess(InMemoryStorageEntry* entry) m_cleanupIndex.get().modify(it, &incrementFrequency); } -} // namespace util } // namespace ndn diff --git a/src/util/in-memory-storage-lfu.hpp b/ndn-cxx/ims/in-memory-storage-lfu.hpp similarity index 87% rename from src/util/in-memory-storage-lfu.hpp rename to ndn-cxx/ims/in-memory-storage-lfu.hpp index d866a29c8..2b579fff6 100644 --- a/src/util/in-memory-storage-lfu.hpp +++ b/ndn-cxx/ims/in-memory-storage-lfu.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,19 +19,18 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#ifndef NDN_UTIL_IN_MEMORY_STORAGE_LFU_HPP -#define NDN_UTIL_IN_MEMORY_STORAGE_LFU_HPP +#ifndef NDN_IMS_IN_MEMORY_STORAGE_LFU_HPP +#define NDN_IMS_IN_MEMORY_STORAGE_LFU_HPP -#include "in-memory-storage.hpp" +#include "ndn-cxx/ims/in-memory-storage.hpp" -#include #include -#include #include #include +#include +#include namespace ndn { -namespace util { /** @brief Provides an in-memory storage with Least Frequently Used (LFU) replacement policy. * @note The frequency right now is usage count. @@ -41,34 +40,34 @@ class InMemoryStorageLfu : public InMemoryStorage { public: explicit - InMemoryStorageLfu(size_t limit = 10); + InMemoryStorageLfu(size_t limit = 16); explicit - InMemoryStorageLfu(boost::asio::io_service& ioService, size_t limit = 10); + InMemoryStorageLfu(DummyIoService& ioService, size_t limit = 16); NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED: /** @brief Removes one Data packet from in-memory storage based on LFU, i.e. evict the least * frequently accessed Data packet * @return{ whether the Data was removed } */ - virtual bool + bool evictItem() override; /** @brief Update the entry when the entry is returned by the find() function, * increment the frequency according to LFU */ - virtual void + void afterAccess(InMemoryStorageEntry* entry) override; /** @brief Update the entry after a entry is successfully inserted, add it to the cleanupIndex */ - virtual void + void afterInsert(InMemoryStorageEntry* entry) override; /** @brief Update the entry or other data structures before a entry is successfully erased, * erase it from the cleanupIndex */ - virtual void + void beforeErase(InMemoryStorageEntry* entry) override; private: @@ -88,7 +87,7 @@ class InMemoryStorageLfu : public InMemoryStorage } private: - //multi_index_container to implement LFU + // multi_index_container to implement LFU class byFrequency; class byEntity; @@ -115,7 +114,6 @@ class InMemoryStorageLfu : public InMemoryStorage CleanupIndex m_cleanupIndex; }; -} // namespace util } // namespace ndn -#endif // NDN_UTIL_IN_MEMORY_STORAGE_LFU_HPP +#endif // NDN_IMS_IN_MEMORY_STORAGE_LFU_HPP diff --git a/src/util/in-memory-storage-lru.cpp b/ndn-cxx/ims/in-memory-storage-lru.cpp similarity index 90% rename from src/util/in-memory-storage-lru.cpp rename to ndn-cxx/ims/in-memory-storage-lru.cpp index 01c8b123d..33a986fcc 100644 --- a/src/util/in-memory-storage-lru.cpp +++ b/ndn-cxx/ims/in-memory-storage-lru.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,17 +19,16 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "in-memory-storage-lru.hpp" +#include "ndn-cxx/ims/in-memory-storage-lru.hpp" namespace ndn { -namespace util { InMemoryStorageLru::InMemoryStorageLru(size_t limit) : InMemoryStorage(limit) { } -InMemoryStorageLru::InMemoryStorageLru(boost::asio::io_service& ioService, +InMemoryStorageLru::InMemoryStorageLru(DummyIoService& ioService, size_t limit) : InMemoryStorage(ioService, limit) { @@ -71,5 +70,4 @@ InMemoryStorageLru::afterAccess(InMemoryStorageEntry* entry) afterInsert(entry); } -} // namespace util } // namespace ndn diff --git a/src/util/in-memory-storage-lru.hpp b/ndn-cxx/ims/in-memory-storage-lru.hpp similarity index 80% rename from src/util/in-memory-storage-lru.hpp rename to ndn-cxx/ims/in-memory-storage-lru.hpp index 478739890..9326b6f62 100644 --- a/src/util/in-memory-storage-lru.hpp +++ b/ndn-cxx/ims/in-memory-storage-lru.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,58 +19,56 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#ifndef NDN_UTIL_IN_MEMORY_STORAGE_LRU_HPP -#define NDN_UTIL_IN_MEMORY_STORAGE_LRU_HPP +#ifndef NDN_IMS_IN_MEMORY_STORAGE_LRU_HPP +#define NDN_IMS_IN_MEMORY_STORAGE_LRU_HPP -#include "in-memory-storage.hpp" +#include "ndn-cxx/ims/in-memory-storage.hpp" -#include #include -#include #include #include +#include +#include namespace ndn { -namespace util { -/** @brief Provides in-memory storage employing LRU replacement policy, of which the least - * recently used entry will be evict first. +/** @brief Provides in-memory storage employing Least Recently Used (LRU) replacement policy. */ class InMemoryStorageLru : public InMemoryStorage { public: explicit - InMemoryStorageLru(size_t limit = 10); + InMemoryStorageLru(size_t limit = 16); - InMemoryStorageLru(boost::asio::io_service& ioService, size_t limit = 10); + InMemoryStorageLru(DummyIoService& ioService, size_t limit = 16); NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED: /** @brief Removes one Data packet from in-memory storage based on LRU, i.e. evict the least * recently accessed Data packet * @return{ whether the Data was removed } */ - virtual bool + bool evictItem() override; /** @brief Update the entry when the entry is returned by the find() function, * update the last used time according to LRU */ - virtual void + void afterAccess(InMemoryStorageEntry* entry) override; /** @brief Update the entry after a entry is successfully inserted, add it to the cleanupIndex */ - virtual void + void afterInsert(InMemoryStorageEntry* entry) override; /** @brief Update the entry or other data structures before a entry is successfully erased, * erase it from the cleanupIndex */ - virtual void + void beforeErase(InMemoryStorageEntry* entry) override; private: - //multi_index_container to implement LRU + // multi_index_container to implement LRU class byUsedTime; class byEntity; @@ -95,7 +93,6 @@ class InMemoryStorageLru : public InMemoryStorage CleanupIndex m_cleanupIndex; }; -} // namespace util } // namespace ndn -#endif // NDN_UTIL_IN_MEMORY_STORAGE_LRU_HPP +#endif // NDN_IMS_IN_MEMORY_STORAGE_LRU_HPP diff --git a/src/util/in-memory-storage-persistent.cpp b/ndn-cxx/ims/in-memory-storage-persistent.cpp similarity index 83% rename from src/util/in-memory-storage-persistent.cpp rename to ndn-cxx/ims/in-memory-storage-persistent.cpp index 954e9c16f..1c345ea48 100644 --- a/src/util/in-memory-storage-persistent.cpp +++ b/ndn-cxx/ims/in-memory-storage-persistent.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,17 +19,16 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "in-memory-storage-persistent.hpp" +#include "ndn-cxx/ims/in-memory-storage-persistent.hpp" namespace ndn { -namespace util { InMemoryStoragePersistent::InMemoryStoragePersistent() : InMemoryStorage() { } -InMemoryStoragePersistent::InMemoryStoragePersistent(boost::asio::io_service& ioService) +InMemoryStoragePersistent::InMemoryStoragePersistent(DummyIoService& ioService) : InMemoryStorage(ioService) { } @@ -40,5 +39,4 @@ InMemoryStoragePersistent::evictItem() return false; } -} // namespace util } // namespace ndn diff --git a/src/util/in-memory-storage-persistent.hpp b/ndn-cxx/ims/in-memory-storage-persistent.hpp similarity index 75% rename from src/util/in-memory-storage-persistent.hpp rename to ndn-cxx/ims/in-memory-storage-persistent.hpp index 3265f5297..331bdcfa3 100644 --- a/src/util/in-memory-storage-persistent.hpp +++ b/ndn-cxx/ims/in-memory-storage-persistent.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,16 +19,15 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#ifndef NDN_UTIL_IN_MEMORY_STORAGE_PERSISTENT_HPP -#define NDN_UTIL_IN_MEMORY_STORAGE_PERSISTENT_HPP +#ifndef NDN_IMS_IN_MEMORY_STORAGE_PERSISTENT_HPP +#define NDN_IMS_IN_MEMORY_STORAGE_PERSISTENT_HPP -#include "in-memory-storage.hpp" +#include "ndn-cxx/ims/in-memory-storage.hpp" namespace ndn { -namespace util { /** @brief Provides application cache with persistent storage, of which no replacement policy will - * be employed. Entries will only be deleted by explicitly application control. + * be employed. Entries will only be deleted by explicit application control. */ class InMemoryStoragePersistent : public InMemoryStorage { @@ -36,7 +35,7 @@ class InMemoryStoragePersistent : public InMemoryStorage InMemoryStoragePersistent(); explicit - InMemoryStoragePersistent(boost::asio::io_service& ioService); + InMemoryStoragePersistent(DummyIoService& ioService); NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED: /** @brief Do nothing. @@ -45,11 +44,10 @@ class InMemoryStoragePersistent : public InMemoryStorage * * @return false */ - virtual bool + bool evictItem() override; }; -} // namespace util } // namespace ndn -#endif // NDN_UTIL_IN_MEMORY_STORAGE_PERSISTENT_HPP +#endif // NDN_IMS_IN_MEMORY_STORAGE_PERSISTENT_HPP diff --git a/ndn-cxx/ims/in-memory-storage.cpp b/ndn-cxx/ims/in-memory-storage.cpp new file mode 100644 index 000000000..b1a27938e --- /dev/null +++ b/ndn-cxx/ims/in-memory-storage.cpp @@ -0,0 +1,392 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/ims/in-memory-storage.hpp" +#include "ndn-cxx/ims/in-memory-storage-entry.hpp" + +namespace ndn { + +const time::milliseconds InMemoryStorage::INFINITE_WINDOW(-1); +const time::milliseconds InMemoryStorage::ZERO_WINDOW(0); + +InMemoryStorage::const_iterator::const_iterator(const Data* ptr, const Cache* cache, + Cache::index::type::iterator it) + : m_ptr(ptr) + , m_cache(cache) + , m_it(it) +{ +} + +InMemoryStorage::const_iterator& +InMemoryStorage::const_iterator::operator++() +{ + m_it++; + if (m_it != m_cache->get().end()) { + m_ptr = &((*m_it)->getData()); + } + else { + m_ptr = nullptr; + } + + return *this; +} + +InMemoryStorage::const_iterator +InMemoryStorage::const_iterator::operator++(int) +{ + InMemoryStorage::const_iterator i(*this); + this->operator++(); + return i; +} + +InMemoryStorage::const_iterator::reference +InMemoryStorage::const_iterator::operator*() +{ + return *m_ptr; +} + +InMemoryStorage::const_iterator::pointer +InMemoryStorage::const_iterator::operator->() +{ + return m_ptr; +} + +bool +InMemoryStorage::const_iterator::operator==(const const_iterator& rhs) +{ + return m_it == rhs.m_it; +} + +bool +InMemoryStorage::const_iterator::operator!=(const const_iterator& rhs) +{ + return m_it != rhs.m_it; +} + +InMemoryStorage::InMemoryStorage(size_t limit) + : m_limit(limit) + , m_nPackets(0) +{ + init(); +} + +InMemoryStorage::InMemoryStorage(DummyIoService& ioService, size_t limit) + : m_limit(limit) + , m_nPackets(0) +{ + m_scheduler = make_unique(ioService); + init(); +} + +void +InMemoryStorage::init() +{ + // TODO consider a more suitable initial value + m_capacity = m_initCapacity; + + if (m_limit != std::numeric_limits::max() && m_capacity > m_limit) { + m_capacity = m_limit; + } + + for (size_t i = 0; i < m_capacity; i++) { + m_freeEntries.push(new InMemoryStorageEntry()); + } +} + +InMemoryStorage::~InMemoryStorage() +{ + // evict all items from cache + auto it = m_cache.begin(); + while (it != m_cache.end()) { + it = freeEntry(it); + } + + BOOST_ASSERT(m_freeEntries.size() == m_capacity); + + while (!m_freeEntries.empty()) { + delete m_freeEntries.top(); + m_freeEntries.pop(); + } +} + +void +InMemoryStorage::setCapacity(size_t capacity) +{ + size_t oldCapacity = m_capacity; + m_capacity = std::max(capacity, m_initCapacity); + + if (size() > m_capacity) { + ssize_t nAllowedFailures = size() - m_capacity; + while (size() > m_capacity) { + if (!evictItem() && --nAllowedFailures < 0) { + NDN_THROW(Error()); + } + } + } + + if (m_capacity >= oldCapacity) { + for (size_t i = oldCapacity; i < m_capacity; i++) { + m_freeEntries.push(new InMemoryStorageEntry()); + } + } + else { + for (size_t i = oldCapacity; i > m_capacity; i--) { + delete m_freeEntries.top(); + m_freeEntries.pop(); + } + } + + BOOST_ASSERT(size() + m_freeEntries.size() == m_capacity); +} + +void +InMemoryStorage::insert(const Data& data, const time::milliseconds& mustBeFreshProcessingWindow) +{ + // check if identical Data/Name already exists + auto it = m_cache.get().find(data.getFullName()); + if (it != m_cache.get().end()) + return; + + //if full, double the capacity + bool doesReachLimit = (getLimit() == getCapacity()); + if (isFull() && !doesReachLimit) { + // note: This is incorrect if 2*capacity overflows, but memory should run out before that + size_t newCapacity = std::min(2 * getCapacity(), getLimit()); + setCapacity(newCapacity); + } + + //if full and reach limitation of the capacity, employ replacement policy + if (isFull() && doesReachLimit) { + evictItem(); + } + + //insert to cache + BOOST_ASSERT(m_freeEntries.size() > 0); + // take entry for the memory pool + InMemoryStorageEntry* entry = m_freeEntries.top(); + m_freeEntries.pop(); + m_nPackets++; + entry->setData(data); + if (m_scheduler != nullptr && mustBeFreshProcessingWindow > ZERO_WINDOW) { + entry->scheduleMarkStale(*m_scheduler, mustBeFreshProcessingWindow); + } + m_cache.insert(entry); + + //let derived class do something with the entry + afterInsert(entry); +} + +shared_ptr +InMemoryStorage::find(const Name& name) +{ + auto it = m_cache.get().lower_bound(name); + + // if not found, return null + if (it == m_cache.get().end()) { + return nullptr; + } + + // if the given name is not the prefix of the lower_bound, return null + if (!name.isPrefixOf((*it)->getFullName())) { + return nullptr; + } + + afterAccess(*it); + return ((*it)->getData()).shared_from_this(); +} + +shared_ptr +InMemoryStorage::find(const Interest& interest) +{ + // if the interest contains implicit digest, it is possible to directly locate a packet. + auto it = m_cache.get().find(interest.getName()); + + // if a packet is located by its full name, it must be the packet to return. + if (it != m_cache.get().end()) { + return ((*it)->getData()).shared_from_this(); + } + + // if the packet is not discovered by last step, either the packet is not in the storage or + // the interest doesn't contains implicit digest. + it = m_cache.get().lower_bound(interest.getName()); + + if (it == m_cache.get().end()) { + return nullptr; + } + + // to locate the element that has a just smaller name than the interest's + if (it != m_cache.get().begin()) { + it--; + } + + InMemoryStorageEntry* ret = selectChild(interest, it); + if (ret == nullptr) { + return nullptr; + } + + // let derived class do something with the entry + afterAccess(ret); + return ret->getData().shared_from_this(); +} + +InMemoryStorage::Cache::index::type::iterator +InMemoryStorage::findNextFresh(Cache::index::type::iterator it) const +{ + for (; it != m_cache.get().end(); it++) { + if ((*it)->isFresh()) + return it; + } + + return it; +} + +InMemoryStorageEntry* +InMemoryStorage::selectChild(const Interest& interest, + Cache::index::type::iterator startingPoint) const +{ + BOOST_ASSERT(startingPoint != m_cache.get().end()); + + if (startingPoint != m_cache.get().begin()) { + BOOST_ASSERT((*startingPoint)->getFullName() < interest.getName()); + } + + // filter out non-fresh data + if (interest.getMustBeFresh()) { + startingPoint = findNextFresh(startingPoint); + } + + if (startingPoint == m_cache.get().end()) { + return nullptr; + } + + if (interest.matchesData((*startingPoint)->getData())) { + return *startingPoint; + } + + // iterate to the right + auto rightmostCandidate = startingPoint; + while (true) { + ++rightmostCandidate; + // filter out non-fresh data + if (interest.getMustBeFresh()) { + rightmostCandidate = findNextFresh(rightmostCandidate); + } + + bool isInPrefix = false; + if (rightmostCandidate != m_cache.get().end()) { + isInPrefix = interest.getName().isPrefixOf((*rightmostCandidate)->getFullName()); + } + if (isInPrefix) { + if (interest.matchesData((*rightmostCandidate)->getData())) { + return *rightmostCandidate; + } + } + else { + break; + } + } + + return nullptr; +} + +InMemoryStorage::Cache::iterator +InMemoryStorage::freeEntry(Cache::iterator it) +{ + // push the *empty* entry into mem pool + (*it)->release(); + m_freeEntries.push(*it); + m_nPackets--; + return m_cache.erase(it); +} + +void +InMemoryStorage::erase(const Name& prefix, const bool isPrefix) +{ + if (isPrefix) { + auto it = m_cache.get().lower_bound(prefix); + while (it != m_cache.get().end() && prefix.isPrefixOf((*it)->getName())) { + // let derived class do something with the entry + beforeErase(*it); + it = freeEntry(it); + } + } + else { + auto it = m_cache.get().find(prefix); + if (it == m_cache.get().end()) + return; + + // let derived class do something with the entry + beforeErase(*it); + freeEntry(it); + } + + if (m_freeEntries.size() > (2 * size())) + setCapacity(getCapacity() / 2); +} + +void +InMemoryStorage::eraseImpl(const Name& name) +{ + auto it = m_cache.get().find(name); + if (it == m_cache.get().end()) + return; + + freeEntry(it); +} + +InMemoryStorage::const_iterator +InMemoryStorage::begin() const +{ + auto it = m_cache.get().begin(); + return const_iterator(&((*it)->getData()), &m_cache, it); +} + +InMemoryStorage::const_iterator +InMemoryStorage::end() const +{ + auto it = m_cache.get().end(); + return const_iterator(nullptr, &m_cache, it); +} + +void +InMemoryStorage::afterInsert(InMemoryStorageEntry* entry) +{ +} + +void +InMemoryStorage::beforeErase(InMemoryStorageEntry* entry) +{ +} + +void +InMemoryStorage::afterAccess(InMemoryStorageEntry* entry) +{ +} + +void +InMemoryStorage::printCache(std::ostream& os) const +{ + // start from the upper layer towards bottom + for (const auto& elem : m_cache.get()) + os << elem->getFullName() << std::endl; +} + +} // namespace ndn diff --git a/src/util/in-memory-storage.hpp b/ndn-cxx/ims/in-memory-storage.hpp similarity index 88% rename from src/util/in-memory-storage.hpp rename to ndn-cxx/ims/in-memory-storage.hpp index bdc39626d..e3211837f 100644 --- a/src/util/in-memory-storage.hpp +++ b/ndn-cxx/ims/in-memory-storage.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,34 +19,30 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#ifndef NDN_UTIL_IN_MEMORY_STORAGE_HPP -#define NDN_UTIL_IN_MEMORY_STORAGE_HPP +#ifndef NDN_IMS_IN_MEMORY_STORAGE_HPP +#define NDN_IMS_IN_MEMORY_STORAGE_HPP -#include "../common.hpp" -#include "../interest.hpp" -#include "../data.hpp" -#include "scheduler.hpp" -#include "in-memory-storage-entry.hpp" +#include "ndn-cxx/ims/in-memory-storage-entry.hpp" +#include "ndn-cxx/util/scheduler.hpp" + +#include +#include -#include #include -#include -#include #include #include - -#include -#include +#include +#include +#include namespace ndn { -namespace util { /** @brief Represents in-memory storage */ class InMemoryStorage : noncopyable { public: - //multi_index_container to implement storage + // multi_index_container to implement storage class byFullName; typedef boost::multi_index_container< @@ -68,9 +64,15 @@ class InMemoryStorage : noncopyable * * @note Don't try to instantiate this class directly, use InMemoryStorage::begin() instead. */ - class const_iterator : public std::iterator + class const_iterator { public: + using iterator_category = std::input_iterator_tag; + using value_type = const Data; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + const_iterator(const Data* ptr, const Cache* cache, Cache::index::type::iterator it); @@ -80,10 +82,10 @@ class InMemoryStorage : noncopyable const_iterator operator++(int); - const Data& + reference operator*(); - const Data* + pointer operator->(); bool @@ -104,7 +106,8 @@ class InMemoryStorage : noncopyable class Error : public std::runtime_error { public: - Error() : std::runtime_error("Cannot reduce the capacity of the in-memory storage!") + Error() + : std::runtime_error("Cannot reduce the capacity of the in-memory storage!") { } }; @@ -119,7 +122,7 @@ class InMemoryStorage : noncopyable * The InMemoryStorage created through this method will handle MustBeFresh in interest processing */ explicit - InMemoryStorage(boost::asio::io_service& ioService, + InMemoryStorage(DummyIoService& ioService, size_t limit = std::numeric_limits::max()); /** @note Please make sure to implement it to free m_freeEntries and evict @@ -130,7 +133,7 @@ class InMemoryStorage : noncopyable /** @brief Inserts a Data packet * - * @param data the packet to insert + * @param data the packet to insert, must be signed and have wire encoding * @param mustBeFreshProcessingWindow Beyond this time period after the data is inserted, the * data can only be used to answer interest without MustBeFresh selector. * @@ -176,8 +179,8 @@ class InMemoryStorage : noncopyable * entry completely matched with the prefix according to canonical ordering. * For this case, user should substitute the prefix with full name. * - * @note Please do not use this function directly in any derived class to erase - * entry in the cache, use eraseHelper instead. + * @warning Please do not use this function directly in any derived class to erase + * an entry from the cache, use eraseImpl() instead. * @note It will invoke beforeErase(shared_ptr). */ void @@ -238,10 +241,10 @@ class InMemoryStorage : noncopyable /** @brief Removes one Data packet from in-memory storage based on * derived class implemented replacement policy + * @return whether a Data packet was removed * - * Please do not use this function directly in any derived class to erase - * entry in the cache, use eraseHelper instead. - * @return{ whether the Data was removed } + * @warning Please do not use this function directly in any derived class to erase + * an entry from the cache, use eraseImpl() instead. */ virtual bool evictItem() = 0; @@ -330,6 +333,8 @@ class InMemoryStorage : noncopyable Cache m_cache; /// user defined maximum capacity of the in-memory storage in packets size_t m_limit; + /// initial capacity, used as minimum capacity + const size_t m_initCapacity = 16; /// current capacity of the in-memory storage in packets size_t m_capacity; /// current number of packets in in-memory storage @@ -337,10 +342,9 @@ class InMemoryStorage : noncopyable /// memory pool std::stack m_freeEntries; /// scheduler - unique_ptr m_scheduler; + unique_ptr m_scheduler; }; -} // namespace util } // namespace ndn -#endif // NDN_UTIL_IN_MEMORY_STORAGE_HPP +#endif // NDN_IMS_IN_MEMORY_STORAGE_HPP diff --git a/src/interest-filter.cpp b/ndn-cxx/interest-filter.cpp similarity index 85% rename from src/interest-filter.cpp rename to ndn-cxx/interest-filter.cpp index 36e08f161..173c4ddd5 100644 --- a/src/interest-filter.cpp +++ b/ndn-cxx/interest-filter.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,8 +19,8 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "interest-filter.hpp" -#include "util/regex/regex-pattern-list-matcher.hpp" +#include "ndn-cxx/interest-filter.hpp" +#include "ndn-cxx/util/regex/regex-pattern-list-matcher.hpp" namespace ndn { @@ -48,8 +48,8 @@ InterestFilter::InterestFilter(const Name& prefix, const std::string& regexFilte InterestFilter::operator const Name&() const { if (hasRegexFilter()) { - BOOST_THROW_EXCEPTION(Error("Please update InterestCallback to accept const InterestFilter&" - " (non-trivial InterestFilter is being used)")); + NDN_THROW(Error("Please update InterestCallback to accept `const InterestFilter&'" + " (non-trivial InterestFilter is being used)")); } return m_prefix; } diff --git a/src/interest-filter.hpp b/ndn-cxx/interest-filter.hpp similarity index 83% rename from src/interest-filter.hpp rename to ndn-cxx/interest-filter.hpp index d6241a147..74b7229c3 100644 --- a/src/interest-filter.hpp +++ b/ndn-cxx/interest-filter.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,7 +22,7 @@ #ifndef NDN_INTEREST_FILTER_HPP #define NDN_INTEREST_FILTER_HPP -#include "name.hpp" +#include "ndn-cxx/name.hpp" namespace ndn { @@ -38,11 +38,7 @@ class InterestFilter class Error : public std::runtime_error { public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } + using std::runtime_error::runtime_error; }; /** @@ -125,9 +121,30 @@ class InterestFilter return *m_regexFilter; } + /** \brief Get whether Interest loopback is allowed + */ + NDN_CXX_NODISCARD bool + allowsLoopback() const + { + return m_allowsLoopback; + } + + /** \brief Set whether Interest loopback is allowed + * \param wantLoopback if true, this InterestFilter may receive Interests that are expressed + * locally on the same \p ndn::Face ; if false, this InterestFilter can only + * receive Interests received from the forwarder. The default is true. + */ + InterestFilter& + allowLoopback(bool wantLoopback) + { + m_allowsLoopback = wantLoopback; + return *this; + } + private: Name m_prefix; shared_ptr m_regexFilter; + bool m_allowsLoopback = true; }; std::ostream& diff --git a/ndn-cxx/interest.cpp b/ndn-cxx/interest.cpp new file mode 100644 index 000000000..00a3249c9 --- /dev/null +++ b/ndn-cxx/interest.cpp @@ -0,0 +1,629 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/transform/digest-filter.hpp" +#include "ndn-cxx/security/transform/step-source.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" +#include "ndn-cxx/util/random.hpp" + +#ifdef NDN_CXX_HAVE_STACKTRACE +#include +#endif + +#include +#include +#include + +namespace ndn { + +BOOST_CONCEPT_ASSERT((WireEncodable)); +BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); +BOOST_CONCEPT_ASSERT((WireDecodable)); +static_assert(std::is_base_of::value, + "Interest::Error must inherit from tlv::Error"); + +#ifdef NDN_CXX_HAVE_TESTS +bool Interest::s_errorIfCanBePrefixUnset = true; +#endif // NDN_CXX_HAVE_TESTS +boost::logic::tribool Interest::s_defaultCanBePrefix = boost::logic::indeterminate; +bool Interest::s_autoCheckParametersDigest = true; + +Interest::Interest(const Name& name, time::milliseconds lifetime) +{ + setName(name); + setInterestLifetime(lifetime); + + if (!boost::logic::indeterminate(s_defaultCanBePrefix)) { + setCanBePrefix(bool(s_defaultCanBePrefix)); + } +} + +Interest::Interest(const Block& wire) +{ + wireDecode(wire); +} + +// ---- encode and decode ---- + +static void +warnOnceCanBePrefixUnset() +{ + static bool didWarn = false; + if (!didWarn) { + didWarn = true; + std::cerr << "WARNING: Interest.CanBePrefix will be set to false in the near future. " + << "Please declare a preferred setting via Interest::setDefaultCanBePrefix.\n"; +#ifdef NDN_CXX_HAVE_STACKTRACE + if (std::getenv("NDN_CXX_VERBOSE_CANBEPREFIX_UNSET_WARNING") != nullptr) { + std::cerr << boost::stacktrace::stacktrace(2, 64); + } +#endif + } +} + +template +size_t +Interest::wireEncode(EncodingImpl& encoder) const +{ + if (!m_isCanBePrefixSet) { + warnOnceCanBePrefixUnset(); +#ifdef NDN_CXX_HAVE_TESTS + if (s_errorIfCanBePrefixUnset) { + NDN_THROW(std::logic_error("Interest.CanBePrefix is unset")); + } +#endif // NDN_CXX_HAVE_TESTS + } + + // Encode as NDN Packet Format v0.3 + // Interest = INTEREST-TYPE TLV-LENGTH + // Name + // [CanBePrefix] + // [MustBeFresh] + // [ForwardingHint] + // [Nonce] + // [InterestLifetime] + // [HopLimit] + // [ApplicationParameters [InterestSignature]] + // (elements are encoded in reverse order) + + // sanity check of ApplicationParameters and ParametersSha256DigestComponent + ssize_t digestIndex = findParametersDigestComponent(getName()); + BOOST_ASSERT(digestIndex != -2); // guaranteed by the checks in setName() and wireDecode() + if (digestIndex == -1) { + if (hasApplicationParameters()) + NDN_THROW(Error("Interest with parameters must have a ParametersSha256DigestComponent")); + } + else if (!hasApplicationParameters()) { + NDN_THROW(Error("Interest without parameters must not have a ParametersSha256DigestComponent")); + } + + size_t totalLength = 0; + + // ApplicationParameters and following elements (in reverse order) + std::for_each(m_parameters.rbegin(), m_parameters.rend(), [&] (const Block& b) { + totalLength += encoder.prependBlock(b); + }); + + // HopLimit + if (getHopLimit()) { + uint8_t hopLimit = *getHopLimit(); + totalLength += encoder.prependByteArrayBlock(tlv::HopLimit, &hopLimit, sizeof(hopLimit)); + } + + // InterestLifetime + if (getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::InterestLifetime, + static_cast(getInterestLifetime().count())); + } + + // Nonce + uint32_t nonce = getNonce(); // if nonce was unset, this generates a fresh nonce + totalLength += encoder.prependByteArrayBlock(tlv::Nonce, reinterpret_cast(&nonce), sizeof(nonce)); + + // ForwardingHint + if (!getForwardingHint().empty()) { + totalLength += getForwardingHint().wireEncode(encoder); + } + + // MustBeFresh + if (getMustBeFresh()) { + totalLength += prependEmptyBlock(encoder, tlv::MustBeFresh); + } + + // CanBePrefix + if (getCanBePrefix()) { + totalLength += prependEmptyBlock(encoder, tlv::CanBePrefix); + } + + // Name + totalLength += getName().wireEncode(encoder); + + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::Interest); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Interest); + +const Block& +Interest::wireEncode() const +{ + if (m_wire.hasWire()) + return m_wire; + + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer encoder(estimatedSize, 0); + wireEncode(encoder); + + const_cast(this)->wireDecode(encoder.block()); + return m_wire; +} + +void +Interest::wireDecode(const Block& wire) +{ + if (wire.type() != tlv::Interest) { + NDN_THROW(Error("Interest", wire.type())); + } + m_wire = wire; + m_wire.parse(); + + // Interest = INTEREST-TYPE TLV-LENGTH + // Name + // [CanBePrefix] + // [MustBeFresh] + // [ForwardingHint] + // [Nonce] + // [InterestLifetime] + // [HopLimit] + // [ApplicationParameters [InterestSignature]] + + auto element = m_wire.elements_begin(); + if (element == m_wire.elements_end() || element->type() != tlv::Name) { + NDN_THROW(Error("Name element is missing or out of order")); + } + // decode into a temporary object until we determine that the name is valid, in order + // to maintain class invariants and thus provide a basic form of exception safety + Name tempName(*element); + if (tempName.empty()) { + NDN_THROW(Error("Name has zero name components")); + } + ssize_t digestIndex = findParametersDigestComponent(tempName); + if (digestIndex == -2) { + NDN_THROW(Error("Name has more than one ParametersSha256DigestComponent")); + } + m_name = std::move(tempName); + + m_isCanBePrefixSet = true; // don't trigger warning from decoded packet + m_canBePrefix = m_mustBeFresh = false; + m_forwardingHint = {}; + m_nonce.reset(); + m_interestLifetime = DEFAULT_INTEREST_LIFETIME; + m_hopLimit.reset(); + m_parameters.clear(); + + int lastElement = 1; // last recognized element index, in spec order + for (++element; element != m_wire.elements_end(); ++element) { + switch (element->type()) { + case tlv::CanBePrefix: { + if (lastElement >= 2) { + NDN_THROW(Error("CanBePrefix element is out of order")); + } + if (element->value_size() != 0) { + NDN_THROW(Error("CanBePrefix element has non-zero TLV-LENGTH")); + } + m_canBePrefix = true; + lastElement = 2; + break; + } + case tlv::MustBeFresh: { + if (lastElement >= 3) { + NDN_THROW(Error("MustBeFresh element is out of order")); + } + if (element->value_size() != 0) { + NDN_THROW(Error("MustBeFresh element has non-zero TLV-LENGTH")); + } + m_mustBeFresh = true; + lastElement = 3; + break; + } + case tlv::ForwardingHint: { + if (lastElement >= 4) { + NDN_THROW(Error("ForwardingHint element is out of order")); + } + m_forwardingHint.wireDecode(*element); + lastElement = 4; + break; + } + case tlv::Nonce: { + if (lastElement >= 5) { + NDN_THROW(Error("Nonce element is out of order")); + } + uint32_t nonce = 0; + if (element->value_size() != sizeof(nonce)) { + NDN_THROW(Error("Nonce element is malformed")); + } + std::memcpy(&nonce, element->value(), sizeof(nonce)); + m_nonce = nonce; + lastElement = 5; + break; + } + case tlv::InterestLifetime: { + if (lastElement >= 6) { + NDN_THROW(Error("InterestLifetime element is out of order")); + } + m_interestLifetime = time::milliseconds(readNonNegativeInteger(*element)); + lastElement = 6; + break; + } + case tlv::HopLimit: { + if (lastElement >= 7) { + break; // HopLimit is non-critical, ignore out-of-order appearance + } + if (element->value_size() != 1) { + NDN_THROW(Error("HopLimit element is malformed")); + } + m_hopLimit = *element->value(); + lastElement = 7; + break; + } + case tlv::ApplicationParameters: { + if (lastElement >= 8) { + break; // ApplicationParameters is non-critical, ignore out-of-order appearance + } + BOOST_ASSERT(!hasApplicationParameters()); + m_parameters.push_back(*element); + lastElement = 8; + break; + } + default: { // unrecognized element + // if the TLV-TYPE is critical, abort decoding + if (tlv::isCriticalType(element->type())) { + NDN_THROW(Error("Unrecognized element of critical type " + to_string(element->type()))); + } + // if we already encountered ApplicationParameters, store this element as parameter + if (hasApplicationParameters()) { + m_parameters.push_back(*element); + } + // otherwise, ignore it + break; + } + } + } + + if (s_autoCheckParametersDigest && !isParametersDigestValid()) { + NDN_THROW(Error("ParametersSha256DigestComponent does not match the SHA-256 of Interest parameters")); + } +} + +std::string +Interest::toUri() const +{ + std::ostringstream os; + os << *this; + return os.str(); +} + +// ---- matching ---- + +bool +Interest::matchesData(const Data& data) const +{ + size_t interestNameLength = m_name.size(); + const Name& dataName = data.getName(); + size_t fullNameLength = dataName.size() + 1; + + // check Name and CanBePrefix + if (interestNameLength == fullNameLength) { + if (m_name.get(-1).isImplicitSha256Digest()) { + if (m_name != data.getFullName()) { + return false; + } + } + else { + // Interest Name is same length as Data full Name, but last component isn't digest + // so there's no possibility of matching + return false; + } + } + else if (getCanBePrefix() ? !m_name.isPrefixOf(dataName) : (m_name != dataName)) { + return false; + } + + // check MustBeFresh + if (getMustBeFresh() && data.getFreshnessPeriod() <= 0_ms) { + return false; + } + + return true; +} + +bool +Interest::matchesInterest(const Interest& other) const +{ + return getName() == other.getName() && + getCanBePrefix() == other.getCanBePrefix() && + getMustBeFresh() == other.getMustBeFresh(); +} + +// ---- field accessors and modifiers ---- + +Interest& +Interest::setName(const Name& name) +{ + ssize_t digestIndex = findParametersDigestComponent(name); + if (digestIndex == -2) { + NDN_THROW(std::invalid_argument("Name cannot have more than one ParametersSha256DigestComponent")); + } + if (name != m_name) { + m_name = name; + if (hasApplicationParameters()) { + addOrReplaceParametersDigestComponent(); + } + m_wire.reset(); + } + return *this; +} + +Interest& +Interest::setForwardingHint(const DelegationList& value) +{ + m_forwardingHint = value; + m_wire.reset(); + return *this; +} + +uint32_t +Interest::getNonce() const +{ + if (!hasNonce()) { + m_nonce = random::generateWord32(); + m_wire.reset(); + } + return *m_nonce; +} + +Interest& +Interest::setNonce(uint32_t nonce) +{ + if (nonce != m_nonce) { + m_nonce = nonce; + m_wire.reset(); + } + return *this; +} + +void +Interest::refreshNonce() +{ + if (!hasNonce()) + return; + + uint32_t oldNonce = *m_nonce; + while (m_nonce == oldNonce) + m_nonce = random::generateWord32(); + + m_wire.reset(); +} + +Interest& +Interest::setInterestLifetime(time::milliseconds lifetime) +{ + if (lifetime < 0_ms) { + NDN_THROW(std::invalid_argument("InterestLifetime must be >= 0")); + } + if (lifetime != m_interestLifetime) { + m_interestLifetime = lifetime; + m_wire.reset(); + } + return *this; +} + +Interest& +Interest::setHopLimit(optional hopLimit) +{ + if (hopLimit != m_hopLimit) { + m_hopLimit = hopLimit; + m_wire.reset(); + } + return *this; +} + +void +Interest::setApplicationParametersInternal(Block parameters) +{ + parameters.encode(); // ensure we have wire encoding needed by computeParametersDigest() + if (m_parameters.empty()) { + m_parameters.push_back(std::move(parameters)); + } + else { + BOOST_ASSERT(m_parameters[0].type() == tlv::ApplicationParameters); + m_parameters[0] = std::move(parameters); + } +} + +Interest& +Interest::setApplicationParameters(const Block& parameters) +{ + if (!parameters.isValid()) { + setApplicationParametersInternal(Block(tlv::ApplicationParameters)); + } + else if (parameters.type() == tlv::ApplicationParameters) { + setApplicationParametersInternal(parameters); + } + else { + setApplicationParametersInternal(Block(tlv::ApplicationParameters, parameters)); + } + addOrReplaceParametersDigestComponent(); + m_wire.reset(); + return *this; +} + +Interest& +Interest::setApplicationParameters(const uint8_t* value, size_t length) +{ + if (value == nullptr && length != 0) { + NDN_THROW(std::invalid_argument("ApplicationParameters buffer cannot be nullptr")); + } + setApplicationParametersInternal(makeBinaryBlock(tlv::ApplicationParameters, value, length)); + addOrReplaceParametersDigestComponent(); + m_wire.reset(); + return *this; +} + +Interest& +Interest::setApplicationParameters(ConstBufferPtr value) +{ + if (value == nullptr) { + NDN_THROW(std::invalid_argument("ApplicationParameters buffer cannot be nullptr")); + } + setApplicationParametersInternal(Block(tlv::ApplicationParameters, std::move(value))); + addOrReplaceParametersDigestComponent(); + m_wire.reset(); + return *this; +} + +Interest& +Interest::unsetApplicationParameters() +{ + m_parameters.clear(); + ssize_t digestIndex = findParametersDigestComponent(getName()); + if (digestIndex >= 0) { + m_name.erase(digestIndex); + } + m_wire.reset(); + return *this; +} + +// ---- ParametersSha256DigestComponent support ---- + +bool +Interest::isParametersDigestValid() const +{ + ssize_t digestIndex = findParametersDigestComponent(getName()); + if (digestIndex == -1) { + return !hasApplicationParameters(); + } + // cannot be -2 because of the checks in setName() and wireDecode() + BOOST_ASSERT(digestIndex >= 0); + + if (!hasApplicationParameters()) { + return false; + } + + const auto& digestComponent = getName()[digestIndex]; + auto digest = computeParametersDigest(); + + return std::equal(digestComponent.value_begin(), digestComponent.value_end(), + digest->begin(), digest->end()); +} + +shared_ptr +Interest::computeParametersDigest() const +{ + using namespace security::transform; + + StepSource in; + OBufferStream out; + in >> digestFilter(DigestAlgorithm::SHA256) >> streamSink(out); + + std::for_each(m_parameters.begin(), m_parameters.end(), [&] (const Block& b) { + in.write(b.wire(), b.size()); + }); + in.end(); + + return out.buf(); +} + +void +Interest::addOrReplaceParametersDigestComponent() +{ + BOOST_ASSERT(hasApplicationParameters()); + + ssize_t digestIndex = findParametersDigestComponent(getName()); + auto digestComponent = name::Component::fromParametersSha256Digest(computeParametersDigest()); + + if (digestIndex == -1) { + // no existing digest components, append one + m_name.append(std::move(digestComponent)); + } + else { + // cannot be -2 because of the checks in setName() and wireDecode() + BOOST_ASSERT(digestIndex >= 0); + // replace the existing digest component + m_name.set(digestIndex, std::move(digestComponent)); + } +} + +ssize_t +Interest::findParametersDigestComponent(const Name& name) +{ + ssize_t pos = -1; + for (ssize_t i = 0; i < static_cast(name.size()); i++) { + if (name[i].isParametersSha256Digest()) { + if (pos != -1) + return -2; + pos = i; + } + } + return pos; +} + +// ---- operators ---- + +std::ostream& +operator<<(std::ostream& os, const Interest& interest) +{ + os << interest.getName(); + + char delim = '?'; + auto printOne = [&] (const auto&... args) { + os << delim; + delim = '&'; + using expand = int[]; + (void)expand{(os << args, 0)...}; // use a fold expression when we switch to C++17 + }; + + if (interest.getCanBePrefix()) { + printOne("CanBePrefix"); + } + if (interest.getMustBeFresh()) { + printOne("MustBeFresh"); + } + if (interest.hasNonce()) { + printOne("Nonce=", interest.getNonce()); + } + if (interest.getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) { + printOne("Lifetime=", interest.getInterestLifetime().count()); + } + if (interest.getHopLimit()) { + printOne("HopLimit=", static_cast(*interest.getHopLimit())); + } + + return os; +} + +} // namespace ndn diff --git a/ndn-cxx/interest.hpp b/ndn-cxx/interest.hpp new file mode 100644 index 000000000..c386ce816 --- /dev/null +++ b/ndn-cxx/interest.hpp @@ -0,0 +1,420 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_INTEREST_HPP +#define NDN_INTEREST_HPP + +#include "ndn-cxx/delegation-list.hpp" +#include "ndn-cxx/name.hpp" +#include "ndn-cxx/detail/packet-base.hpp" +#include "ndn-cxx/util/time.hpp" + +#include + +namespace ndn { + +class Data; + +/** @var const unspecified_duration_type DEFAULT_INTEREST_LIFETIME; + * @brief default value for InterestLifetime + */ +const time::milliseconds DEFAULT_INTEREST_LIFETIME = 4_s; + +/** @brief Represents an Interest packet. + */ +class Interest : public PacketBase, public std::enable_shared_from_this +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + /** @brief Construct an Interest with given @p name and @p lifetime. + * + * @throw std::invalid_argument @p name is invalid or @p lifetime is negative + * @warning In certain contexts that use `Interest::shared_from_this()`, Interest must be created + * using `make_shared`. Otherwise, `shared_from_this()` will trigger undefined behavior. + */ + explicit + Interest(const Name& name = Name(), time::milliseconds lifetime = DEFAULT_INTEREST_LIFETIME); + + /** @brief Construct an Interest by decoding from @p wire. + * + * @warning In certain contexts that use `Interest::shared_from_this()`, Interest must be created + * using `make_shared`. Otherwise, `shared_from_this()` will trigger undefined behavior. + */ + explicit + Interest(const Block& wire); + + /** @brief Prepend wire encoding to @p encoder according to NDN Packet Format v0.3. + */ + template + size_t + wireEncode(EncodingImpl& encoder) const; + + /** @brief Encode into a Block according to NDN Packet Format v0.3. + */ + const Block& + wireEncode() const; + + /** @brief Decode from @p wire according to NDN Packet Format v0.3. + */ + void + wireDecode(const Block& wire); + + /** @brief Check if this instance has cached wire encoding. + */ + bool + hasWire() const + { + return m_wire.hasWire(); + } + + /** @brief Return a URI-like string that represents the Interest. + * + * The string always starts with `getName().toUri()`. After the name, if any of the + * Interest's CanBePrefix, MustBeFresh, Nonce, InterestLifetime, or HopLimit fields + * are present, their textual representation is appended as a query string. + * Example: "/test/name?MustBeFresh&Nonce=123456" + */ + std::string + toUri() const; + +public: // matching + /** @brief Check if Interest can be satisfied by @p data. + * + * This method considers Name, CanBePrefix, and MustBeFresh. However, MustBeFresh processing + * is limited to rejecting Data with zero/omitted FreshnessPeriod. + */ + bool + matchesData(const Data& data) const; + + /** @brief Check if this Interest matches @p other + * + * Two Interests match if both have the same Name, CanBePrefix, and MustBeFresh. + */ + bool + matchesInterest(const Interest& other) const; + +public: // element access + const Name& + getName() const noexcept + { + return m_name; + } + + /** @brief Set the Interest's name. + * @throw std::invalid_argument @p name is invalid + */ + Interest& + setName(const Name& name); + + /** @brief Declare the default CanBePrefix setting of the application. + * + * As part of transitioning to NDN Packet Format v0.3, the default setting for CanBePrefix + * will be changed from "true" to "false". Application developers are advised to review all + * Interests expressed by their application and decide what CanBePrefix setting is appropriate + * for each Interest, to avoid breaking changes when the transition occurs. Application may + * either set CanBePrefix on a per-Interest basis, or declare a default CanBePrefix setting for + * all Interests expressed by the application using this function. If an application neither + * declares a default nor sets CanBePrefix on every Interest, Interest::wireEncode will print a + * one-time warning message. + * + * @note This function should not be used in libraries or in ndn-cxx unit tests. + * @sa https://redmine.named-data.net/projects/nfd/wiki/Packet03Transition + */ + static void + setDefaultCanBePrefix(bool canBePrefix) + { + s_defaultCanBePrefix = canBePrefix; + } + + /** @brief Check whether the CanBePrefix element is present. + */ + bool + getCanBePrefix() const noexcept + { + return m_canBePrefix; + } + + /** @brief Add or remove CanBePrefix element. + * @param canBePrefix whether CanBePrefix element should be present. + */ + Interest& + setCanBePrefix(bool canBePrefix) + { + m_canBePrefix = canBePrefix; + m_wire.reset(); + m_isCanBePrefixSet = true; + return *this; + } + + /** @brief Check whether the MustBeFresh element is present. + */ + bool + getMustBeFresh() const noexcept + { + return m_mustBeFresh; + } + + /** @brief Add or remove MustBeFresh element. + * @param mustBeFresh whether MustBeFresh element should be present. + */ + Interest& + setMustBeFresh(bool mustBeFresh) + { + m_mustBeFresh = mustBeFresh; + m_wire.reset(); + return *this; + } + + const DelegationList& + getForwardingHint() const noexcept + { + return m_forwardingHint; + } + + Interest& + setForwardingHint(const DelegationList& value); + + /** @brief Modify ForwardingHint in-place. + * @tparam Modifier a unary function that accepts DelegationList& + * + * This is equivalent to, but more efficient (avoids copying) than: + * @code + * auto fh = interest.getForwardingHint(); + * modifier(fh); + * interest.setForwardingHint(fh); + * @endcode + */ + template + Interest& + modifyForwardingHint(const Modifier& modifier) + { + modifier(m_forwardingHint); + m_wire.reset(); + return *this; + } + + /** @brief Check if the Nonce element is present. + */ + bool + hasNonce() const noexcept + { + return m_nonce.has_value(); + } + + /** @brief Get nonce value. + * + * If nonce was not present, it is added and assigned a random value. + */ + uint32_t + getNonce() const; + + /** @brief Set nonce value. + */ + Interest& + setNonce(uint32_t nonce); + + /** @brief Change nonce value. + * + * If the Nonce element is present, the new nonce value will differ from the old value. + * If the Nonce element is not present, this method does nothing. + */ + void + refreshNonce(); + + time::milliseconds + getInterestLifetime() const noexcept + { + return m_interestLifetime; + } + + /** @brief Set the Interest's lifetime. + * @throw std::invalid_argument @p lifetime is negative + */ + Interest& + setInterestLifetime(time::milliseconds lifetime); + + optional + getHopLimit() const noexcept + { + return m_hopLimit; + } + + /** @brief Set the Interest's hop limit. + * + * Use `setHopLimit(nullopt)` to remove any hop limit from the Interest. + */ + Interest& + setHopLimit(optional hopLimit); + + bool + hasApplicationParameters() const noexcept + { + return !m_parameters.empty(); + } + + Block + getApplicationParameters() const + { + if (m_parameters.empty()) + return {}; + else + return m_parameters.front(); + } + + /** @brief Set ApplicationParameters from a Block. + * @return a reference to this Interest + * + * If the block is default-constructed, this will set a zero-length ApplicationParameters + * element. Else, if the block's TLV-TYPE is ApplicationParameters, it will be used directly + * as this Interest's ApplicationParameters element. Else, the block will be nested into an + * ApplicationParameters element. + * + * This function will also recompute the value of the ParametersSha256DigestComponent in the + * Interest's name. If the name does not contain a ParametersSha256DigestComponent, one will + * be appended to it. + */ + Interest& + setApplicationParameters(const Block& parameters); + + /** @brief Set ApplicationParameters by copying from a raw buffer. + * @param value points to a buffer from which the TLV-VALUE of the parameters will be copied; + * may be nullptr if @p length is zero + * @param length size of the buffer + * @return a reference to this Interest + * + * This function will also recompute the value of the ParametersSha256DigestComponent in the + * Interest's name. If the name does not contain a ParametersSha256DigestComponent, one will + * be appended to it. + */ + Interest& + setApplicationParameters(const uint8_t* value, size_t length); + + /** @brief Set ApplicationParameters from a shared buffer. + * @param value buffer containing the TLV-VALUE of the parameters; must not be nullptr + * @return a reference to this Interest + * + * This function will also recompute the value of the ParametersSha256DigestComponent in the + * Interest's name. If the name does not contain a ParametersSha256DigestComponent, one will + * be appended to it. + */ + Interest& + setApplicationParameters(ConstBufferPtr value); + + /** @brief Remove the ApplicationParameters element from this Interest. + * @post hasApplicationParameters() == false + * + * This function will also remove any ParametersSha256DigestComponents from the Interest's name. + */ + Interest& + unsetApplicationParameters(); + +public: // ParametersSha256DigestComponent support + static bool + getAutoCheckParametersDigest() + { + return s_autoCheckParametersDigest; + } + + static void + setAutoCheckParametersDigest(bool b) + { + s_autoCheckParametersDigest = b; + } + + /** @brief Check if the ParametersSha256DigestComponent in the name is valid. + * + * Returns true if there is a single ParametersSha256DigestComponent in the name and the digest + * value is correct, or if there is no ParametersSha256DigestComponent in the name and the + * Interest does not contain any parameters. + * Returns false otherwise. + */ + bool + isParametersDigestValid() const; + +private: + void + setApplicationParametersInternal(Block parameters); + + NDN_CXX_NODISCARD shared_ptr + computeParametersDigest() const; + + /** @brief Append a ParametersSha256DigestComponent to the Interest's name + * or update the digest value in the existing component. + * + * @pre The name is assumed to be valid, i.e., it must not contain more than one + * ParametersSha256DigestComponent. + * @pre hasApplicationParameters() == true + */ + void + addOrReplaceParametersDigestComponent(); + + /** @brief Return the index of the ParametersSha256DigestComponent in @p name. + * + * @retval pos The name contains exactly one ParametersSha256DigestComponent at index `pos`. + * @retval -1 The name contains zero ParametersSha256DigestComponents. + * @retval -2 The name contains more than one ParametersSha256DigestComponents. + */ + static ssize_t + findParametersDigestComponent(const Name& name); + +#ifdef NDN_CXX_HAVE_TESTS +public: + /// If true, not setting CanBePrefix results in an error in wireEncode(). + static bool s_errorIfCanBePrefixUnset; +#endif // NDN_CXX_HAVE_TESTS + +private: + static boost::logic::tribool s_defaultCanBePrefix; + static bool s_autoCheckParametersDigest; + + Name m_name; + DelegationList m_forwardingHint; + mutable optional m_nonce; + time::milliseconds m_interestLifetime; + optional m_hopLimit; + mutable bool m_isCanBePrefixSet = false; + bool m_canBePrefix = true; + bool m_mustBeFresh = false; + + // Stores the "Interest parameters", i.e., all maybe-unrecognized non-critical TLV + // elements that appear at the end of the Interest, starting from ApplicationParameters. + // If the Interest does not contain any ApplicationParameters TLV, this vector will + // be empty. Conversely, if this vector is not empty, the first element will always + // be an ApplicationParameters block. All blocks in this vector are covered by the + // digest in the ParametersSha256DigestComponent. + std::vector m_parameters; + + mutable Block m_wire; +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(Interest); + +std::ostream& +operator<<(std::ostream& os, const Interest& interest); + +} // namespace ndn + +#endif // NDN_INTEREST_HPP diff --git a/ndn-cxx/key-locator.cpp b/ndn-cxx/key-locator.cpp new file mode 100644 index 000000000..88b7f0390 --- /dev/null +++ b/ndn-cxx/key-locator.cpp @@ -0,0 +1,216 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/key-locator.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/util/overload.hpp" +#include "ndn-cxx/util/string-helper.hpp" + +namespace ndn { + +BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); +BOOST_CONCEPT_ASSERT((WireEncodable)); +BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); +BOOST_CONCEPT_ASSERT((WireDecodable)); +static_assert(std::is_base_of::value, + "KeyLocator::Error must inherit from tlv::Error"); + +const size_t MAX_KEY_DIGEST_OCTETS_TO_SHOW = 5; + +KeyLocator::KeyLocator() = default; + +KeyLocator::KeyLocator(const Block& wire) +{ + wireDecode(wire); +} + +KeyLocator::KeyLocator(const Name& name) + : m_locator(name) +{ +} + +template +size_t +KeyLocator::wireEncode(EncodingImpl& encoder) const +{ + // KeyLocator = KEY-LOCATOR-TYPE TLV-LENGTH (Name / KeyDigest) + // KeyDigest = KEY-DIGEST-TYPE TLV-LENGTH *OCTET + + size_t totalLength = 0; + + auto visitor = overload( + [] (monostate) {}, // nothing to encode, TLV-VALUE is empty + [&] (const Name& name) { totalLength += name.wireEncode(encoder); }, + [&] (const Block& digest) { totalLength += encoder.prependBlock(digest); }, + [] (uint32_t type) { NDN_THROW(Error("Unsupported KeyLocator type " + to_string(type))); }); + visit(visitor, m_locator); + + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::KeyLocator); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(KeyLocator); + +const Block& +KeyLocator::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 +KeyLocator::wireDecode(const Block& wire) +{ + if (wire.type() != tlv::KeyLocator) + NDN_THROW(Error("KeyLocator", wire.type())); + + clear(); + m_wire = wire; + m_wire.parse(); + + auto element = m_wire.elements_begin(); + if (element == m_wire.elements().end()) { + return; + } + + switch (element->type()) { + case tlv::Name: + m_locator.emplace(*element); + break; + case tlv::KeyDigest: + m_locator.emplace(*element); + break; + default: + m_locator = element->type(); + break; + } +} + +uint32_t +KeyLocator::getType() const +{ + switch (m_locator.index()) { + case 0: + return tlv::Invalid; + case 1: + return tlv::Name; + case 2: + return tlv::KeyDigest; + case 3: + return get(m_locator); + default: + NDN_CXX_UNREACHABLE; + } +} + +KeyLocator& +KeyLocator::clear() +{ + m_locator = monostate{}; + m_wire.reset(); + return *this; +} + +const Name& +KeyLocator::getName() const +{ + try { + return get(m_locator); + } + catch (const bad_variant_access&) { + NDN_THROW(Error("KeyLocator does not contain a Name")); + } +} + +KeyLocator& +KeyLocator::setName(const Name& name) +{ + m_locator = name; + m_wire.reset(); + return *this; +} + +const Block& +KeyLocator::getKeyDigest() const +{ + try { + return get(m_locator); + } + catch (const bad_variant_access&) { + NDN_THROW(Error("KeyLocator does not contain a KeyDigest")); + } +} + +KeyLocator& +KeyLocator::setKeyDigest(const Block& keyDigest) +{ + if (keyDigest.type() != tlv::KeyDigest) { + NDN_THROW(std::invalid_argument("Invalid KeyDigest block of type " + to_string(keyDigest.type()))); + } + m_locator = keyDigest; + m_wire.reset(); + return *this; +} + +KeyLocator& +KeyLocator::setKeyDigest(const ConstBufferPtr& keyDigest) +{ + BOOST_ASSERT(keyDigest != nullptr); + m_locator = makeBinaryBlock(tlv::KeyDigest, keyDigest->data(), keyDigest->size()); + m_wire.reset(); + return *this; +} + +std::ostream& +operator<<(std::ostream& os, const KeyLocator& keyLocator) +{ + auto visitor = overload( + [&] (monostate) { + os << "None"; + }, + [&] (const Name& name) { + os << "Name=" << name; + }, + [&] (const Block& digest) { + os << "KeyDigest="; + printHex(os, digest.value(), std::min(digest.value_size(), MAX_KEY_DIGEST_OCTETS_TO_SHOW)); + if (digest.value_size() > MAX_KEY_DIGEST_OCTETS_TO_SHOW) { + os << "..."; + } + }, + [&] (uint32_t type) { + os << "Unknown(" << type << ")"; + }); + visit(visitor, keyLocator.m_locator); + return os; +} + +} // namespace ndn diff --git a/ndn-cxx/key-locator.hpp b/ndn-cxx/key-locator.hpp new file mode 100644 index 000000000..df1213478 --- /dev/null +++ b/ndn-cxx/key-locator.hpp @@ -0,0 +1,173 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_KEY_LOCATOR_HPP +#define NDN_KEY_LOCATOR_HPP + +#include "ndn-cxx/name.hpp" + +namespace ndn { + +class KeyLocator +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + enum +#ifndef DOXYGEN + [[deprecated]] // apparently doxygen can't handle this attribute on enums +#endif + Type { + /// KeyLocator is empty + KeyLocator_None = tlv::Invalid, + /// KeyLocator contains a Name + KeyLocator_Name = tlv::Name, + /// KeyLocator contains a KeyDigest + KeyLocator_KeyDigest = tlv::KeyDigest, + }; + +public: // constructors + /** \brief Construct an empty KeyLocator. + * \post `empty() == true` + */ + KeyLocator(); + + /** \brief Construct from Name. + * \note Implicit conversion is permitted. + * \post `getType() == tlv::Name` + */ + KeyLocator(const Name& name); + + /** \brief Construct from wire encoding. + */ + explicit + KeyLocator(const Block& wire); + +public: // encode and decode + /** \brief Prepend wire encoding to \p encoder. + */ + template + size_t + wireEncode(EncodingImpl& encoder) const; + + const Block& + wireEncode() const; + + /** \brief Decode from wire encoding. + * \throw Error outer TLV type is not KeyLocator + * \note No error is raised for an unrecognized nested TLV, but attempting to reencode will throw. + */ + void + wireDecode(const Block& wire); + +public: // attributes + NDN_CXX_NODISCARD bool + empty() const + { + return holds_alternative(m_locator); + } + + uint32_t + getType() const; + + /** \brief Reset KeyLocator to its default-constructed state. + * \post `empty() == true` + * \post `getType() == tlv::Invalid` + * \return self + */ + KeyLocator& + clear(); + + /** \brief Get nested Name element. + * \throw Error if type is not tlv::Name + */ + const Name& + getName() const; + + /** \brief Set nested Name element. + * \post `getType() == tlv::Name` + * \return self + */ + KeyLocator& + setName(const Name& name); + + /** \brief Get nested KeyDigest element. + * \throw Error if type is not tlv::KeyDigest + */ + const Block& + getKeyDigest() const; + + /** \brief Set nested KeyDigest element (whole TLV). + * \post `getType() == tlv::KeyDigest` + * \throw std::invalid_argument Block type is not tlv::KeyDigest + * \return self + */ + KeyLocator& + setKeyDigest(const Block& keyDigest); + + /** \brief Set nested KeyDigest element value. + * \param keyDigest buffer to use as TLV-VALUE of the nested KeyDigest element. + * \post `getType() == tlv::KeyDigest` + * \return self + */ + KeyLocator& + setKeyDigest(const ConstBufferPtr& keyDigest); + +private: // non-member operators + // NOTE: the following "hidden friend" operators are available via + // argument-dependent lookup only and must be defined inline. + + friend bool + operator==(const KeyLocator& lhs, const KeyLocator& rhs) + { + return lhs.m_locator == rhs.m_locator; + } + + friend bool + operator!=(const KeyLocator& lhs, const KeyLocator& rhs) + { + return lhs.m_locator != rhs.m_locator; + } + +private: + // - monostate represents an empty KeyLocator, without any nested TLVs + // - Name is used when the nested TLV contains a name + // - Block is used when the nested TLV is a KeyDigest + // - in all other (unsupported) cases the nested TLV type is stored as uint32_t + variant m_locator; + + mutable Block m_wire; + + friend std::ostream& operator<<(std::ostream&, const KeyLocator&); +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(KeyLocator); + +std::ostream& +operator<<(std::ostream& os, const KeyLocator& keyLocator); + +} // namespace ndn + +#endif // NDN_KEY_LOCATOR_HPP diff --git a/ndn-cxx/link.cpp b/ndn-cxx/link.cpp new file mode 100644 index 000000000..ab5cb0d7f --- /dev/null +++ b/ndn-cxx/link.cpp @@ -0,0 +1,102 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/link.hpp" + +namespace ndn { + +BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); +BOOST_CONCEPT_ASSERT((WireEncodable)); +BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); +BOOST_CONCEPT_ASSERT((WireDecodable)); +static_assert(std::is_base_of::value, + "Link::Error should inherit from Data::Error"); + +Link::Link() = default; + +Link::Link(const Block& wire, bool wantSort) +{ + this->wireDecode(wire, wantSort); +} + +Link::Link(const Name& name, std::initializer_list dels) + : Data(name) + , m_delList(dels) +{ + encodeContent(); +} + +void +Link::encodeContent() +{ + setContentType(tlv::ContentType_Link); + + if (m_delList.size() > 0) { + EncodingEstimator estimator; + size_t estimatedSize = m_delList.wireEncode(estimator, tlv::Content); + + EncodingBuffer buffer(estimatedSize, 0); + m_delList.wireEncode(buffer, tlv::Content); + + setContent(buffer.block()); + } + else { + setContent(nullptr, 0); + } +} + +void +Link::wireDecode(const Block& wire, bool wantSort) +{ + Data::wireDecode(wire); + + if (getContentType() != tlv::ContentType_Link) { + NDN_THROW(Error("Expecting ContentType Link, got " + to_string(getContentType()))); + } + + m_delList.wireDecode(getContent(), wantSort); +} + +void +Link::setDelegationList(const DelegationList& dels) +{ + m_delList = dels; + encodeContent(); +} + +void +Link::addDelegation(uint32_t preference, const Name& name) +{ + m_delList.insert(preference, name, DelegationList::INS_REPLACE); + encodeContent(); +} + +bool +Link::removeDelegation(const Name& name) +{ + size_t nErased = m_delList.erase(name); + if (nErased > 0) { + encodeContent(); + } + return nErased > 0; +} + +} // namespace ndn diff --git a/ndn-cxx/link.hpp b/ndn-cxx/link.hpp new file mode 100644 index 000000000..bfe47fd71 --- /dev/null +++ b/ndn-cxx/link.hpp @@ -0,0 +1,120 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_LINK_HPP +#define NDN_LINK_HPP + +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/delegation-list.hpp" + +namespace ndn { + +/** @brief represents a Link object + */ +class Link : public Data +{ +public: + class Error : public Data::Error + { + public: + using Data::Error::Error; + }; + + /** @brief Create an empty Link object + * + * Note that in certain contexts that use Link::shared_from_this(), Link must be + * created using `make_shared`: + * + * shared_ptr linkObject = make_shared(); + */ + Link(); + + /** @brief Decode a Link object from a Block + * @param wire a TLV block + * @param wantSort if false, relative order among delegations is preserved + * + * Note that in certain contexts that use Link::shared_from_this(), Link must be + * created using `make_shared`: + * + * shared_ptr linkObject = make_shared(block); + */ + explicit + Link(const Block& wire, bool wantSort = true); + + /** @brief Create a Link object with the given name and delegations + * @param name A reference to the name of the redirected namespace + * @param dels Delegations in payload + * + * Note that in certain contexts that use Link::shared_from_this(), Link must be + * created using `make_shared`: + * + * shared_ptr link = make_shared(name, dels); + */ + explicit + Link(const Name& name, std::initializer_list dels = {}); + + /** @brief Decode from the wire format + * @param wire a TLV block + * @param wantSort if false, relative order among delegations is preserved + */ + void + wireDecode(const Block& wire, bool wantSort = true); + + /** @brief Get the delegations + */ + const DelegationList& + getDelegationList() const + { + return m_delList; + } + + /** @brief Set the delegations + * @note This is more efficient than multiple addDelegation and removeDelegation invocations. + */ + void + setDelegationList(const DelegationList& dels); + + /** @brief Add a delegation in the format of + * @param preference The preference of the delegation to be added + * @param name The name of the delegation to be added + * @note If a delegation with @p name exists, its preference will be updated + */ + void + addDelegation(uint32_t preference, const Name& name); + + /** @brief Remove a delegation whose name is @p name + * @param name The name of the delegation to be removed + * @return true if delegation is removed, otherwise false + */ + bool + removeDelegation(const Name& name); + +private: + void + encodeContent(); + +private: + DelegationList m_delList; +}; + +} // namespace ndn + +#endif // NDN_LINK_HPP diff --git a/ndn-cxx/lp/cache-policy.cpp b/ndn-cxx/lp/cache-policy.cpp new file mode 100644 index 000000000..b4f4d8200 --- /dev/null +++ b/ndn-cxx/lp/cache-policy.cpp @@ -0,0 +1,136 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Eric Newberry + */ + +#include "ndn-cxx/lp/cache-policy.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" + +namespace ndn { +namespace lp { + +std::ostream& +operator<<(std::ostream& os, CachePolicyType policy) +{ + switch (policy) { + case CachePolicyType::NO_CACHE: + return os << "NoCache"; + default: + return os << "None"; + } +} + +CachePolicy::CachePolicy() + : m_policy(CachePolicyType::NONE) +{ +} + +CachePolicy::CachePolicy(const Block& block) +{ + wireDecode(block); +} + +template +size_t +CachePolicy::wireEncode(EncodingImpl& encoder) const +{ + if (m_policy == CachePolicyType::NONE) { + NDN_THROW(Error("CachePolicyType must be set")); + } + + size_t length = 0; + length += prependNonNegativeIntegerBlock(encoder, tlv::CachePolicyType, static_cast(m_policy)); + length += encoder.prependVarNumber(length); + length += encoder.prependVarNumber(tlv::CachePolicy); + return length; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(CachePolicy); + +const Block& +CachePolicy::wireEncode() const +{ + if (m_policy == CachePolicyType::NONE) { + NDN_THROW(Error("CachePolicyType must be set")); + } + + 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 +CachePolicy::wireDecode(const Block& wire) +{ + if (wire.type() != tlv::CachePolicy) { + NDN_THROW(Error("CachePolicy", wire.type())); + } + + m_wire = wire; + m_wire.parse(); + + auto it = m_wire.elements_begin(); + if (it == m_wire.elements_end()) { + NDN_THROW(Error("Empty CachePolicy")); + } + + if (it->type() == tlv::CachePolicyType) { + m_policy = static_cast(readNonNegativeInteger(*it)); + if (this->getPolicy() == CachePolicyType::NONE) { + NDN_THROW(Error("Unknown CachePolicyType")); + } + } + else { + NDN_THROW(Error("CachePolicyType", it->type())); + } +} + +CachePolicyType +CachePolicy::getPolicy() const +{ + switch (m_policy) { + case CachePolicyType::NO_CACHE: + return m_policy; + default: + return CachePolicyType::NONE; + } +} + +CachePolicy& +CachePolicy::setPolicy(CachePolicyType policy) +{ + m_policy = policy; + m_wire.reset(); + return *this; +} + +} // namespace lp +} // namespace ndn diff --git a/src/lp/cache-policy.hpp b/ndn-cxx/lp/cache-policy.hpp similarity index 88% rename from src/lp/cache-policy.hpp rename to ndn-cxx/lp/cache-policy.hpp index 5c5c5d1f0..4307ce165 100644 --- a/src/lp/cache-policy.hpp +++ b/ndn-cxx/lp/cache-policy.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -24,12 +24,8 @@ #ifndef NDN_CXX_LP_CACHE_POLICY_HPP #define NDN_CXX_LP_CACHE_POLICY_HPP -#include "../common.hpp" -#include "../tag.hpp" -#include "../encoding/encoding-buffer.hpp" -#include "../encoding/block-helpers.hpp" - -#include "tlv.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/lp/tlv.hpp" namespace ndn { namespace lp { @@ -54,11 +50,7 @@ class CachePolicy class Error : public ndn::tlv::Error { public: - explicit - Error(const std::string& what) - : ndn::tlv::Error(what) - { - } + using ndn::tlv::Error::Error; }; CachePolicy(); @@ -107,6 +99,8 @@ class CachePolicy mutable Block m_wire; }; +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(CachePolicy); + } // namespace lp } // namespace ndn diff --git a/ndn-cxx/lp/empty-value.hpp b/ndn-cxx/lp/empty-value.hpp new file mode 100644 index 000000000..9485ce2e8 --- /dev/null +++ b/ndn-cxx/lp/empty-value.hpp @@ -0,0 +1,40 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Teng Liang + */ + +#ifndef NDN_CXX_LP_TLV_EMPTY_VALUE_HPP +#define NDN_CXX_LP_TLV_EMPTY_VALUE_HPP + +namespace ndn { +namespace lp { + +/** + * \brief represents a zero-length TLV-VALUE + */ +struct EmptyValue +{ +}; + +} // namespace lp +} // namespace ndn + +#endif // NDN_CXX_LP_TLV_EMPTY_VALUE_HPP \ No newline at end of file diff --git a/ndn-cxx/lp/field-decl.hpp b/ndn-cxx/lp/field-decl.hpp new file mode 100644 index 000000000..627ae1338 --- /dev/null +++ b/ndn-cxx/lp/field-decl.hpp @@ -0,0 +1,217 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_LP_FIELD_DECL_HPP +#define NDN_CXX_LP_FIELD_DECL_HPP + +#include "ndn-cxx/lp/empty-value.hpp" +#include "ndn-cxx/lp/field.hpp" +#include "ndn-cxx/lp/sequence.hpp" +#include "ndn-cxx/lp/tlv.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/util/concepts.hpp" + +#include +#include + +namespace ndn { +namespace lp { + +/** \brief Indicate a uint64_t field shall be decoded and encoded as a non-negative integer. + */ +struct NonNegativeIntegerTag; + +template +struct DecodeHelper +{ + static + BOOST_CONCEPT_REQUIRES(((WireDecodable)), (T)) + decode(const Block& wire) + { + T type; + type.wireDecode(wire); + return type; + } +}; + +template +struct DecodeHelper +{ + static EmptyValue + decode(const Block& wire) + { + if (wire.value_size() != 0) { + NDN_THROW(ndn::tlv::Error("NDNLP field of TLV-TYPE " + to_string(wire.type()) + + " must be empty")); + } + return EmptyValue{}; + } +}; + +template +struct DecodeHelper +{ + static uint64_t + decode(const Block& wire) + { + return readNonNegativeInteger(wire); + } +}; + +template +struct DecodeHelper +{ + static uint64_t + decode(const Block& wire) + { + if (wire.value_size() != sizeof(uint64_t)) { + NDN_THROW(ndn::tlv::Error("NDNLP field of TLV-TYPE " + to_string(wire.type()) + + " must contain a 64-bit integer")); + } + uint64_t n = 0; + std::memcpy(&n, wire.value(), sizeof(n)); + return boost::endian::big_to_native(n); + } +}; + +template +struct DecodeHelper> +{ + static std::pair + decode(const Block& wire) + { + if (wire.value_size() == 0) { + NDN_THROW(ndn::tlv::Error("NDNLP field of TLV-TYPE " + to_string(wire.type()) + + " cannot be empty")); + } + return std::make_pair(wire.value_begin(), wire.value_end()); + } +}; + +template +struct EncodeHelper +{ + static + BOOST_CONCEPT_REQUIRES(((WireEncodableWithEncodingBuffer)), (size_t)) + encode(EncodingImpl& encoder, const T& value) + { + return value.wireEncode(encoder); + } +}; + +template +struct EncodeHelper +{ + static size_t + encode(EncodingImpl& encoder, const EmptyValue value) + { + size_t length = 0; + length += encoder.prependVarNumber(0); + length += encoder.prependVarNumber(TlvType::value); + return length; + } +}; + +template +struct EncodeHelper +{ + static size_t + encode(EncodingImpl& encoder, uint64_t value) + { + return prependNonNegativeIntegerBlock(encoder, TlvType::value, value); + } +}; + +template +struct EncodeHelper +{ + static size_t + encode(EncodingImpl& encoder, uint64_t value) + { + boost::endian::native_to_big_inplace(value); + return encoder.prependByteArrayBlock(TlvType::value, + reinterpret_cast(&value), sizeof(value)); + } +}; + +template +struct EncodeHelper> +{ + static size_t + encode(EncodingImpl& encoder, const std::pair& value) + { + size_t length = 0; + length += encoder.prependRange(value.first, value.second); + length += encoder.prependVarNumber(length); + length += encoder.prependVarNumber(TlvType::value); + return length; + } +}; + +/** \brief Declare a field. + * \tparam LOCATION a tag that indicates where the field is in an LpPacket. + * \tparam VALUE type of field value. + * \tparam TYPE TLV-TYPE number of the field. + * \tparam REPEATABLE whether the field is repeatable. + * \tparam DECODER_TAG selects a specialization of DecodeHelper. + * \tparam ENCODER_TAG selects a specialization of EncodeHelper. + */ +template +class FieldDecl +{ +public: + typedef LOCATION FieldLocation; + typedef VALUE ValueType; + typedef std::integral_constant TlvType; + typedef std::integral_constant IsRepeatable; + + /** \brief Decode a field. + * \param wire an element with top-level TLV-TYPE \c TlvType::value. + * \return value of the field. + * \throw ndn::tlv::Error decode failure. + */ + static ValueType + decode(const Block& wire) + { + if (wire.type() != TlvType::value) { + NDN_THROW(ndn::tlv::Error("Unexpected TLV-TYPE " + to_string(wire.type()))); + } + + return DecodeHelper::decode(wire); + } + + /** \brief Encode a field and prepend to \p encoder. + * \param encoder a buffer encoder or estimator. + * \param value value of the field. + */ + template + static size_t + encode(EncodingImpl& encoder, const ValueType& value) + { + return EncodeHelper::encode(encoder, value); + } +}; + +} // namespace lp +} // namespace ndn + +#endif // NDN_CXX_LP_FIELD_DECL_HPP diff --git a/ndn-cxx/lp/field.hpp b/ndn-cxx/lp/field.hpp new file mode 100644 index 000000000..ea1d4b403 --- /dev/null +++ b/ndn-cxx/lp/field.hpp @@ -0,0 +1,81 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_LP_FIELD_HPP +#define NDN_CXX_LP_FIELD_HPP + +#include "ndn-cxx/detail/common.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/util/concepts.hpp" + +namespace ndn { +namespace lp { + +/** + * \brief indicates where a field may occur + */ +namespace field_location_tags { + +class Base +{ +}; + +/** + * \brief a header field + */ +class Header : public Base +{ +}; + +/** + * \brief the Fragment field + */ +class Fragment : public Base +{ +}; + +} // namespace field_location_tags + +/** + * \brief concept check for fields + */ +template +struct Field +{ + static_assert(std::is_base_of::value, ""); + static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); + NDN_CXX_ASSERT_DEFAULT_CONSTRUCTIBLE(typename X::ValueType); + BOOST_CONCEPT_ASSERT((boost::CopyConstructible)); + BOOST_CONCEPT_USAGE(Field) + { + Block wire; + X j; + typename X::ValueType decoded = j.decode(wire); + EncodingBuffer enc; + j.encode(enc, decoded); + } +}; + +} // namespace lp +} // namespace ndn + +#endif // NDN_CXX_LP_FIELD_HPP diff --git a/ndn-cxx/lp/fields.hpp b/ndn-cxx/lp/fields.hpp new file mode 100644 index 000000000..0d1d783f5 --- /dev/null +++ b/ndn-cxx/lp/fields.hpp @@ -0,0 +1,204 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_LP_FIELDS_HPP +#define NDN_CXX_LP_FIELDS_HPP + +#include "ndn-cxx/lp/field-decl.hpp" + +#include "ndn-cxx/lp/cache-policy.hpp" +#include "ndn-cxx/lp/geo-tag.hpp" +#include "ndn-cxx/lp/nack-header.hpp" +#include "ndn-cxx/lp/prefix-announcement-header.hpp" +#include "ndn-cxx/lp/util-header.hpp" +#include "ndn-cxx/lp/tags.hpp" + +#include + +namespace ndn { +namespace lp { + +typedef FieldDecl SequenceField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl FragIndexField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl FragCountField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl, + tlv::PitToken> PitTokenField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl NackField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl NextHopFaceIdField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl CachePolicyField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl IncomingFaceIdField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl CongestionMarkField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl AckField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl TxSequenceField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl NonDiscoveryField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl PrefixAnnouncementField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl HopCountTagField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl GeoTagField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl GridTagField; +BOOST_CONCEPT_ASSERT((Field)); + + + +/** \brief Declare the Fragment field. + * + * The fragment (i.e. payload) is the bytes between two provided iterators. During encoding, + * these bytes are copied from the Buffer into the LpPacket. + */ +typedef FieldDecl, + tlv::Fragment> FragmentField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl FakeInterestTagField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl ReuseTagField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl UtilTagField; +BOOST_CONCEPT_ASSERT((Field)); + +typedef FieldDecl UtilInterestTagField; +BOOST_CONCEPT_ASSERT((Field)); + + +/** \brief Set of all field declarations. + */ +typedef boost::mpl::set< + FragmentField, + SequenceField, + FragIndexField, + ReuseTagField, + FragCountField, + PitTokenField, + NackField, + NextHopFaceIdField, + IncomingFaceIdField, + CachePolicyField, + CongestionMarkField, + AckField, + TxSequenceField, + NonDiscoveryField, + PrefixAnnouncementField, + HopCountTagField, + FakeInterestTagField, + GridTagField, + GeoTagField + > FieldSet; + +typedef boost::mpl::set< + UtilTagField, + UtilInterestTagField + > FieldSet2; + + +} // namespace lp +} // namespace ndn + +#endif // NDN_CXX_LP_FIELDS_HPP diff --git a/ndn-cxx/lp/geo-tag.cpp b/ndn-cxx/lp/geo-tag.cpp new file mode 100644 index 000000000..4832ada0e --- /dev/null +++ b/ndn-cxx/lp/geo-tag.cpp @@ -0,0 +1,92 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/lp/geo-tag.hpp" +#include "ndn-cxx/lp/tlv.hpp" + +namespace ndn { +namespace lp { + +GeoTag::GeoTag(const Block& block) +{ + wireDecode(block); +} + +template +size_t +GeoTag::wireEncode(EncodingImpl& encoder) const +{ + size_t length = 0; + length += prependDoubleBlock(encoder, tlv::GeoTagPos, std::get<2>(m_pos)); + length += prependDoubleBlock(encoder, tlv::GeoTagPos, std::get<1>(m_pos)); + length += prependDoubleBlock(encoder, tlv::GeoTagPos, std::get<0>(m_pos)); + length += encoder.prependVarNumber(length); + length += encoder.prependVarNumber(tlv::GeoTag); + return length; +} + +template size_t +GeoTag::wireEncode(EncodingImpl& encoder) const; + +template size_t +GeoTag::wireEncode(EncodingImpl& encoder) const; + +const Block& +GeoTag::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 +GeoTag::wireDecode(const Block& wire) +{ + if (wire.type() != tlv::GeoTag) { + NDN_THROW(ndn::tlv::Error("expecting GeoTag block")); + } + + m_wire = wire; + m_wire.parse(); + + if (m_wire.elements().size() < 3 || + m_wire.elements()[0].type() != tlv::GeoTagPos || + m_wire.elements()[1].type() != tlv::GeoTagPos || + m_wire.elements()[2].type() != tlv::GeoTagPos) { + NDN_THROW(ndn::tlv::Error("Unexpected input while decoding GeoTag")); + } + m_pos = {encoding::readDouble(m_wire.elements()[0]), + encoding::readDouble(m_wire.elements()[1]), + encoding::readDouble(m_wire.elements()[2])}; +} + +} // namespace lp +} // namespace ndn diff --git a/ndn-cxx/lp/geo-tag.hpp b/ndn-cxx/lp/geo-tag.hpp new file mode 100644 index 000000000..74c9312dc --- /dev/null +++ b/ndn-cxx/lp/geo-tag.hpp @@ -0,0 +1,102 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_LP_GEO_TAG_HPP +#define NDN_CXX_LP_GEO_TAG_HPP + +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/tag.hpp" + +namespace ndn { +namespace lp { + +/** + * \brief represents a GeoTag header field + */ +class GeoTag : public Tag +{ +public: + static constexpr int + getTypeId() noexcept + { + return 0x60000001; + } + + GeoTag() = default; + + explicit + GeoTag(std::tuple pos) + : m_pos(pos) + { + } + + explicit + GeoTag(const Block& block); + + /** + * \brief prepend GeoTag to encoder + */ + template + size_t + wireEncode(EncodingImpl& encoder) const; + + /** + * \brief encode GeoTag into wire format + */ + const Block& + wireEncode() const; + + /** + * \brief get GeoTag from wire format + */ + void + wireDecode(const Block& wire); + +public: // get & set GeoTag + /** + * \return position x of GeoTag + */ + std::tuple + getPos() const + { + return m_pos; + } + + /** + * \brief set position x + */ + GeoTag* + setPosX(std::tuple pos) + { + m_pos = pos; + return this; + } + +private: + std::tuple m_pos = {0.0, 0.0, 0.0}; + mutable Block m_wire; +}; + +} // namespace lp +} // namespace ndn + +#endif // NDN_CXX_LP_GEOTAG_HPP diff --git a/ndn-cxx/lp/grid-header.cpp b/ndn-cxx/lp/grid-header.cpp new file mode 100644 index 000000000..87157fd45 --- /dev/null +++ b/ndn-cxx/lp/grid-header.cpp @@ -0,0 +1,113 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/lp/grid-header.hpp" +#include "ndn-cxx/lp/tlv.hpp" + +namespace ndn { +namespace lp { + +GridHeader::GridHeader() { + m_grids = make_optional>(); +} + +GridHeader::GridHeader(const Block& block) +{ + m_grids = make_optional>(); + wireDecode(block); +} + +GridHeader::GridHeader(std::vector grids) + : m_grids(std::move(grids)) +{ +} + +template +size_t +GridHeader::wireEncode(EncodingImpl& encoder) const +{ + if (m_grids == nullopt) { + BOOST_THROW_EXCEPTION(Error("GridHeader does not contain any info")); + } + + // std::cout << "Wire encoding" << std::endl; + + size_t length = 0; + std::cout << "vector size: " << m_grids->size() << std::endl; + for (auto it = m_grids->begin(); it != m_grids->end(); it++) { + std::cout << "it->x_start: " << it->x_start << std::endl; + std::cout << "it->x_end: " << it->x_end << std::endl; + std::cout << "it->y_start: " << it->y_start << std::endl; + std::cout << "it->y_end: " << it->y_end << std::endl; + length += prependNonNegativeIntegerBlock(encoder, 90, it->x_start); + length += prependNonNegativeIntegerBlock(encoder, 91, it->x_end); + length += prependNonNegativeIntegerBlock(encoder, 92, it->y_start); + length += prependNonNegativeIntegerBlock(encoder, 93, it->y_end); + } + length += encoder.prependVarNumber(length); + length += encoder.prependVarNumber(tlv::GridTag); + return length; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(GridHeader); + +void +GridHeader::wireDecode(const Block& wire) +{ + if (wire.type() != tlv::GridTag) { + BOOST_THROW_EXCEPTION(Error("Unexpected TLV-TYPE " + to_string(wire.type()))); + } + + std::cout << "Wire decoding" << std::endl; + wire.parse(); + for (auto element = wire.elements_begin(); element != wire.elements_end(); ++element) { + Grid grid; + std::cout << "in wire decoding loop" << std::endl; + //element->parse(); + std::cout << "Element type: " << element->type() << std::endl; + if (element->type() == 93) { + std::cout << "Found type 39" << std::endl; + grid.y_end = encoding::readNonNegativeInteger(*element); + } + ++element; + //element->parse(); + if (element->type() == 92) { + std::cout << "Found type 92" << std::endl; + grid.y_start = encoding::readNonNegativeInteger(*element); + } + ++element; + //element->parse(); + if (element->type() == 91) { + std::cout << "Found type 91" << std::endl; + grid.x_end = encoding::readNonNegativeInteger(*element); + } + ++element; + //element->parse(); + if (element->type() == 90) { + std::cout << "Found type 90" << std::endl; + grid.x_start = encoding::readNonNegativeInteger(*element); + } + m_grids->push_back(grid); + } +} + +} // namespace lp +} // namespace ndn diff --git a/ndn-cxx/lp/grid-header.hpp b/ndn-cxx/lp/grid-header.hpp new file mode 100644 index 000000000..a193eb8ae --- /dev/null +++ b/ndn-cxx/lp/grid-header.hpp @@ -0,0 +1,89 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_LP_GRID_HEADER_HPP +#define NDN_CXX_LP_GRID_HEADER_HPP + +#include "ndn-cxx/lp/tlv.hpp" +#include "ndn-cxx/lp/tags.hpp" + +#include +#include + +namespace ndn { +namespace lp { + +struct Grid { + double x_start; + double x_end; + double y_start; + double y_end; +}; + +/** \brief represents a Util header field in NDNLP + */ +class GridHeader +{ +public: + class Error : public ndn::tlv::Error + { + public: + using ndn::tlv::Error::Error; + }; + GridHeader(); + + explicit + GridHeader(const Block& block); + + /** \brief constructs PrefixAnnouncementHeader using PrefixAnnouncement + * + * \throw Error PrefixAnnouncement does not contain Data. + */ + explicit + GridHeader(std::vector grids); + + /** \brief encodes the prefix announcement header to the wire format + * + * \throw Error this instance does not contain a PrefixAnnouncement. + */ + template + size_t + wireEncode(EncodingImpl& encoder) const; + + void + wireDecode(const Block& wire); + + const optional>& + getGrids() const + { + return m_grids; + } + + optional m_grid; + optional> m_grids; +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(GridHeader); + +} // namespace lp +} // namespace ndn + +#endif // NDN_CXX_LP_PREFIX_ANNOUNCEMENT_HEADER_HPP diff --git a/src/lp/nack-header.cpp b/ndn-cxx/lp/nack-header.cpp similarity index 78% rename from src/lp/nack-header.cpp rename to ndn-cxx/lp/nack-header.cpp index 9f3157c88..f13b8ac62 100644 --- a/src/lp/nack-header.cpp +++ b/ndn-cxx/lp/nack-header.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -21,7 +21,7 @@ * @author Eric Newberry */ -#include "nack-header.hpp" +#include "ndn-cxx/lp/nack-header.hpp" namespace ndn { namespace lp { @@ -31,19 +31,29 @@ operator<<(std::ostream& os, NackReason reason) { switch (reason) { case NackReason::CONGESTION: - os << "Congestion"; - break; + return os << "Congestion"; case NackReason::DUPLICATE: - os << "Duplicate"; - break; + return os << "Duplicate"; case NackReason::NO_ROUTE: - os << "NoRoute"; - break; + return os << "NoRoute"; + case NackReason::OVERLOADED: + return os << "Server overloaded"; default: - os << "None"; - break; + return os << "None"; } - return os; +} + +bool +isLessSevere(lp::NackReason x, lp::NackReason y) +{ + if (x == lp::NackReason::NONE) { + return false; + } + if (y == lp::NackReason::NONE) { + return true; + } + + return to_underlying(x) < to_underlying(y); } NackHeader::NackHeader() @@ -61,18 +71,13 @@ size_t NackHeader::wireEncode(EncodingImpl& encoder) const { size_t length = 0; - length += prependNonNegativeIntegerBlock(encoder, tlv::NackReason, - static_cast(m_reason)); + length += prependNonNegativeIntegerBlock(encoder, tlv::NackReason, static_cast(m_reason)); length += encoder.prependVarNumber(length); length += encoder.prependVarNumber(tlv::Nack); return length; } -template size_t -NackHeader::wireEncode(EncodingImpl& encoder) const; - -template size_t -NackHeader::wireEncode(EncodingImpl& encoder) const; +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(NackHeader); const Block& NackHeader::wireEncode() const @@ -96,7 +101,7 @@ void NackHeader::wireDecode(const Block& wire) { if (wire.type() != tlv::Nack) { - BOOST_THROW_EXCEPTION(ndn::tlv::Error("expecting Nack block")); + NDN_THROW(ndn::tlv::Error("Nack", wire.type())); } m_wire = wire; @@ -110,7 +115,7 @@ NackHeader::wireDecode(const Block& wire) m_reason = static_cast(readNonNegativeInteger(*it)); } else { - BOOST_THROW_EXCEPTION(ndn::tlv::Error("expecting NackReason block")); + NDN_THROW(ndn::tlv::Error("NackReason", it->type())); } } } @@ -122,6 +127,7 @@ NackHeader::getReason() const case NackReason::CONGESTION: case NackReason::DUPLICATE: case NackReason::NO_ROUTE: + case NackReason::OVERLOADED: return m_reason; default: return NackReason::NONE; diff --git a/src/lp/nack-header.hpp b/ndn-cxx/lp/nack-header.hpp similarity index 81% rename from src/lp/nack-header.hpp rename to ndn-cxx/lp/nack-header.hpp index 4544f5438..190cf7be5 100644 --- a/src/lp/nack-header.hpp +++ b/ndn-cxx/lp/nack-header.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -24,11 +24,9 @@ #ifndef NDN_CXX_LP_NACK_HEADER_HPP #define NDN_CXX_LP_NACK_HEADER_HPP -#include "../common.hpp" -#include "../encoding/encoding-buffer.hpp" -#include "../encoding/block-helpers.hpp" - -#include "tlv.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/lp/tlv.hpp" namespace ndn { namespace lp { @@ -40,12 +38,20 @@ enum class NackReason { NONE = 0, CONGESTION = 50, DUPLICATE = 100, - NO_ROUTE = 150 + NO_ROUTE = 150, + OVERLOADED = 200 }; std::ostream& operator<<(std::ostream& os, NackReason reason); +/** \brief compare NackReason for severity + * + * lp::NackReason::NONE is treated as most severe + */ +bool +isLessSevere(lp::NackReason x, lp::NackReason y); + /** * \brief represents a Network NACK header */ @@ -87,7 +93,9 @@ class NackHeader mutable Block m_wire; }; +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(NackHeader); + } // namespace lp } // namespace ndn -#endif // NDN_CXX_LP_NACK_HEADER_HPP \ No newline at end of file +#endif // NDN_CXX_LP_NACK_HEADER_HPP diff --git a/src/lp/nack.cpp b/ndn-cxx/lp/nack.cpp similarity index 86% rename from src/lp/nack.cpp rename to ndn-cxx/lp/nack.cpp index c31a1147b..7e3a57ff9 100644 --- a/src/lp/nack.cpp +++ b/ndn-cxx/lp/nack.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -21,20 +21,22 @@ * @author Eric Newberry */ -#include "nack.hpp" +#include "ndn-cxx/lp/nack.hpp" namespace ndn { namespace lp { +Nack::Nack() = default; + Nack::Nack(const Interest& interest) : m_interest(interest) { } Nack::Nack(Interest&& interest) - : m_interest(interest) + : m_interest(std::move(interest)) { } } // namespace lp -} // namespace ndn \ No newline at end of file +} // namespace ndn diff --git a/src/lp/nack.hpp b/ndn-cxx/lp/nack.hpp similarity index 90% rename from src/lp/nack.hpp rename to ndn-cxx/lp/nack.hpp index 3b23cf6c7..e08307d4f 100644 --- a/src/lp/nack.hpp +++ b/ndn-cxx/lp/nack.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -24,11 +24,9 @@ #ifndef NDN_CXX_LP_NACK_HPP #define NDN_CXX_LP_NACK_HPP -#include "../common.hpp" -#include "../tag-host.hpp" -#include "../interest.hpp" - -#include "nack-header.hpp" +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/detail/packet-base.hpp" +#include "ndn-cxx/lp/nack-header.hpp" namespace ndn { namespace lp { @@ -37,10 +35,10 @@ namespace lp { * * This type binds a NackHeader and an Interest, and is intended for use in network layer. */ -class Nack : public TagHost +class Nack : public PacketBase { public: - Nack() = default; + Nack(); explicit Nack(const Interest& interest); diff --git a/ndn-cxx/lp/packet.cpp b/ndn-cxx/lp/packet.cpp new file mode 100644 index 000000000..9b848929f --- /dev/null +++ b/ndn-cxx/lp/packet.cpp @@ -0,0 +1,182 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/lp/packet.hpp" +#include "ndn-cxx/lp/fields.hpp" + +#include +#include +#include + +namespace ndn { +namespace lp { + +namespace { + +template +int +getLocationSortOrder() noexcept; + +template<> +constexpr int +getLocationSortOrder() noexcept +{ + return 1; +} + +template<> +constexpr int +getLocationSortOrder() noexcept +{ + return 2; +} + +class FieldInfo +{ +public: + constexpr + FieldInfo() noexcept = default; + + explicit + FieldInfo(uint64_t tlv) noexcept; + +public: + uint64_t tlvType = 0; ///< TLV-TYPE of the field; 0 if field does not exist + bool isRecognized = false; ///< is this field known + bool canIgnore = false; ///< can this unknown field be ignored + bool isRepeatable = false; ///< is the field repeatable + int locationSortOrder = getLocationSortOrder(); ///< sort order of field_location_tag +}; + +class ExtractFieldInfo +{ +public: + using result_type = void; + + template + constexpr void + operator()(FieldInfo* info, const T&) const noexcept + { + if (T::TlvType::value != info->tlvType) { + return; + } + info->isRecognized = true; + info->canIgnore = false; + info->isRepeatable = T::IsRepeatable::value; + info->locationSortOrder = getLocationSortOrder(); + } +}; + +FieldInfo::FieldInfo(uint64_t tlv) noexcept + : tlvType(tlv) +{ + boost::mpl::for_each
(boost::bind(ExtractFieldInfo(), this, _1)); + if (!isRecognized) { + canIgnore = tlv::HEADER3_MIN <= tlvType && + tlvType <= tlv::HEADER3_MAX && + (tlvType & 0x03) == 0x00; + } +} + +constexpr bool +compareFieldSortOrder(const FieldInfo& first, const FieldInfo& second) noexcept +{ + return (first.locationSortOrder < second.locationSortOrder) || + (first.locationSortOrder == second.locationSortOrder && first.tlvType < second.tlvType); +} + +} // namespace + +Packet::Packet() + : m_wire(Block(tlv::LpPacket)) +{ +} + +Packet::Packet(const Block& wire) +{ + wireDecode(wire); +} + +Block +Packet::wireEncode() const +{ + // If no header or trailer, return bare network packet + Block::element_container elements = m_wire.elements(); + if (elements.size() == 1 && elements.front().type() == FragmentField::TlvType::value) { + elements.front().parse(); + return elements.front().elements().front(); + } + + m_wire.encode(); + return m_wire; +} + +void +Packet::wireDecode(const Block& wire) +{ + if (wire.type() == ndn::tlv::Interest || wire.type() == ndn::tlv::Data) { + m_wire = Block(tlv::LpPacket); + add(make_pair(wire.begin(), wire.end())); + return; + } + + if (wire.type() != tlv::LpPacket) { + NDN_THROW(Error("LpPacket", wire.type())); + } + + wire.parse(); + + bool isFirst = true; + FieldInfo prev; + for (const Block& element : wire.elements()) { + FieldInfo info(element.type()); + + if (!info.isRecognized && !info.canIgnore) { + NDN_THROW(Error("unrecognized field " + to_string(element.type()) + " cannot be ignored")); + } + + if (!isFirst) { + if (info.tlvType == prev.tlvType && !info.isRepeatable) { + NDN_THROW(Error("non-repeatable field " + to_string(element.type()) + " cannot be repeated")); + } + + else if (info.tlvType != prev.tlvType && !compareFieldSortOrder(prev, info)) { + NDN_THROW(Error("fields are not in correct sort order")); + } + } + + isFirst = false; + prev = info; + } + + m_wire = wire; +} + +bool +Packet::comparePos(uint64_t first, const Block& second) noexcept +{ + FieldInfo firstInfo(first); + FieldInfo secondInfo(second.type()); + return compareFieldSortOrder(firstInfo, secondInfo); +} + +} // namespace lp +} // namespace ndn diff --git a/src/lp/packet.hpp b/ndn-cxx/lp/packet.hpp similarity index 75% rename from src/lp/packet.hpp rename to ndn-cxx/lp/packet.hpp index bc3512220..d3a9766b6 100644 --- a/src/lp/packet.hpp +++ b/ndn-cxx/lp/packet.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,7 +22,7 @@ #ifndef NDN_CXX_LP_PACKET_HPP #define NDN_CXX_LP_PACKET_HPP -#include "fields.hpp" +#include "ndn-cxx/lp/fields.hpp" namespace ndn { namespace lp { @@ -33,11 +33,7 @@ class Packet class Error : public ndn::tlv::Error { public: - explicit - Error(const std::string& what) - : ndn::tlv::Error(what) - { - } + using ndn::tlv::Error::Error; }; Packet(); @@ -45,13 +41,6 @@ class Packet explicit Packet(const Block& wire); - /** - * \brief append packet to encoder - */ - template - size_t - wireEncode(EncodingImpl& encoder) const; - /** * \brief encode packet into wire format */ @@ -65,13 +54,23 @@ class Packet void wireDecode(const Block& wire); + /** + * \retval true packet has no field + * \retval false packet has one or more fields + */ + NDN_CXX_NODISCARD bool + empty() const + { + return m_wire.elements_size() == 0; + } + public: // field access /** * \return true if FIELD occurs one or more times * \details This is equivalent to count() > 0 */ template - bool + NDN_CXX_NODISCARD bool has() const { return count() > 0; @@ -81,14 +80,11 @@ class Packet * \return number of occurrences of FIELD */ template - size_t + NDN_CXX_NODISCARD size_t count() const { - m_wire.parse(); - return std::count_if(m_wire.elements_begin(), m_wire.elements_end(), - [] (const Block& block) { - return block.type() == FIELD::TlvType::value; }); + [] (const Block& block) { return block.type() == FIELD::TlvType::value; }); } /** @@ -99,8 +95,6 @@ class Packet typename FIELD::ValueType get(size_t index = 0) const { - m_wire.parse(); - size_t count = 0; for (const Block& element : m_wire.elements()) { if (element.type() != FIELD::TlvType::value) { @@ -111,20 +105,18 @@ class Packet } } - BOOST_THROW_EXCEPTION(std::out_of_range("Index out of range")); + NDN_THROW(std::out_of_range("lp::Packet::get: index out of range")); } /** * \return values of all occurrences of FIELD */ template - std::vector + NDN_CXX_NODISCARD std::vector list() const { std::vector output; - m_wire.parse(); - for (const Block& element : m_wire.elements()) { if (element.type() != FIELD::TlvType::value) { continue; @@ -149,14 +141,14 @@ class Packet /** * \brief add a FIELD with value - * \throw std::length_error if field already exists and is not repeatable + * \throw std::invalid_argument if field already exists and is not repeatable */ template Packet& add(const typename FIELD::ValueType& value) { if (!FIELD::IsRepeatable::value && has()) { - BOOST_THROW_EXCEPTION(std::length_error("Field cannot be repeated")); + NDN_THROW(std::invalid_argument("lp::Packet::add: field cannot be repeated")); } EncodingEstimator estimator; @@ -165,10 +157,8 @@ class Packet FIELD::encode(buffer, value); Block block = buffer.block(); - Block::element_const_iterator pos = std::lower_bound(m_wire.elements_begin(), - m_wire.elements_end(), - FIELD::TlvType::value, - comparePos); + auto pos = std::upper_bound(m_wire.elements_begin(), m_wire.elements_end(), + FIELD::TlvType::value, comparePos); m_wire.insert(pos, block); return *this; @@ -182,11 +172,8 @@ class Packet Packet& remove(size_t index = 0) { - m_wire.parse(); - size_t count = 0; - for (Block::element_const_iterator it = m_wire.elements_begin(); it != m_wire.elements_end(); - ++it) { + for (auto it = m_wire.elements_begin(); it != m_wire.elements_end(); ++it) { if (it->type() == FIELD::TlvType::value) { if (count == index) { m_wire.erase(it); @@ -196,7 +183,7 @@ class Packet } } - BOOST_THROW_EXCEPTION(std::out_of_range("Index out of range")); + NDN_THROW(std::out_of_range("lp::Packet::remove: index out of range")); } /** @@ -206,14 +193,13 @@ class Packet Packet& clear() { - m_wire.parse(); m_wire.remove(FIELD::TlvType::value); return *this; } private: static bool - comparePos(const Block& first, const uint64_t second); + comparePos(uint64_t first, const Block& second) noexcept; private: mutable Block m_wire; diff --git a/ndn-cxx/lp/pit-token.cpp b/ndn-cxx/lp/pit-token.cpp new file mode 100644 index 000000000..244857903 --- /dev/null +++ b/ndn-cxx/lp/pit-token.cpp @@ -0,0 +1,49 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/lp/pit-token.hpp" +#include "ndn-cxx/encoding/tlv.hpp" +#include "ndn-cxx/util/string-helper.hpp" + +namespace ndn { +namespace lp { + +static constexpr size_t LENGTH_MIN = 1; +static constexpr size_t LENGTH_MAX = 32; + +void +PitToken::validate() const +{ + if (size() < LENGTH_MIN || size() > LENGTH_MAX) { + NDN_THROW(ndn::tlv::Error("PitToken length must be between " + + to_string(LENGTH_MIN) + " and " + to_string(LENGTH_MAX))); + } +} + +std::ostream& +operator<<(std::ostream& os, const PitToken& pitToken) +{ + printHex(os, pitToken, false); + return os; +} + +} // namespace lp +} // namespace ndn diff --git a/ndn-cxx/lp/pit-token.hpp b/ndn-cxx/lp/pit-token.hpp new file mode 100644 index 000000000..fa6159309 --- /dev/null +++ b/ndn-cxx/lp/pit-token.hpp @@ -0,0 +1,73 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_LP_PIT_TOKEN_HPP +#define NDN_CXX_LP_PIT_TOKEN_HPP + +#include "ndn-cxx/encoding/buffer.hpp" +#include "ndn-cxx/tag.hpp" + +namespace ndn { +namespace lp { + +/** \brief represent a PIT token field + * \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2#PIT-Token + */ +class PitToken : public Buffer, public Tag +{ +public: + static constexpr int + getTypeId() noexcept + { + return 98; + } + + /** \brief Construct from header field. + * \throw ndn::tlv::Error element length is out of range. + */ + explicit + PitToken(const std::pair& value) + : Buffer(value.first, value.second) + { + validate(); + } + + /** \brief Convert to header field. + * \throw ndn::tlv::Error element length is out of range. + */ + operator std::pair() const + { + validate(); + return std::make_pair(begin(), end()); + } + +private: + void + validate() const; +}; + +std::ostream& +operator<<(std::ostream& os, const PitToken& pitToken); + +} // namespace lp +} // namespace ndn + +#endif // NDN_CXX_LP_PIT_TOKEN_HPP diff --git a/ndn-cxx/lp/prefix-announcement-header.cpp b/ndn-cxx/lp/prefix-announcement-header.cpp new file mode 100644 index 000000000..8761be1ea --- /dev/null +++ b/ndn-cxx/lp/prefix-announcement-header.cpp @@ -0,0 +1,71 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/lp/prefix-announcement-header.hpp" +#include "ndn-cxx/lp/tlv.hpp" + +namespace ndn { +namespace lp { + +PrefixAnnouncementHeader::PrefixAnnouncementHeader() = default; + +PrefixAnnouncementHeader::PrefixAnnouncementHeader(const Block& block) +{ + wireDecode(block); +} + +PrefixAnnouncementHeader::PrefixAnnouncementHeader(PrefixAnnouncement prefixAnn) + : m_prefixAnn(std::move(prefixAnn)) +{ + if (m_prefixAnn->getData() == nullopt) { + NDN_THROW(Error("PrefixAnnouncement does not contain Data")); + } +} + +template +size_t +PrefixAnnouncementHeader::wireEncode(EncodingImpl& encoder) const +{ + if (m_prefixAnn == nullopt) { + NDN_THROW(Error("PrefixAnnouncementHeader does not contain a PrefixAnnouncement")); + } + + size_t length = 0; + length += m_prefixAnn->getData()->wireEncode(encoder); + length += encoder.prependVarNumber(length); + length += encoder.prependVarNumber(tlv::PrefixAnnouncement); + return length; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(PrefixAnnouncementHeader); + +void +PrefixAnnouncementHeader::wireDecode(const Block& wire) +{ + if (wire.type() != tlv::PrefixAnnouncement) { + NDN_THROW(Error("PrefixAnnouncement", wire.type())); + } + + wire.parse(); + m_prefixAnn.emplace(Data(wire.get(ndn::tlv::Data))); +} +} // namespace lp +} // namespace ndn diff --git a/ndn-cxx/lp/prefix-announcement-header.hpp b/ndn-cxx/lp/prefix-announcement-header.hpp new file mode 100644 index 000000000..89b59a6fe --- /dev/null +++ b/ndn-cxx/lp/prefix-announcement-header.hpp @@ -0,0 +1,79 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_LP_PREFIX_ANNOUNCEMENT_HEADER_HPP +#define NDN_CXX_LP_PREFIX_ANNOUNCEMENT_HEADER_HPP + +#include "ndn-cxx/prefix-announcement.hpp" + +namespace ndn { +namespace lp { + +/** \brief represents a PrefixAnnouncement header field in NDNLP + */ +class PrefixAnnouncementHeader +{ +public: + class Error : public ndn::tlv::Error + { + public: + using ndn::tlv::Error::Error; + }; + + PrefixAnnouncementHeader(); + + explicit + PrefixAnnouncementHeader(const Block& block); + + /** \brief constructs PrefixAnnouncementHeader using PrefixAnnouncement + * + * \throw Error PrefixAnnouncement does not contain Data. + */ + explicit + PrefixAnnouncementHeader(PrefixAnnouncement prefixAnn); + + /** \brief encodes the prefix announcement header to the wire format + * + * \throw Error this instance does not contain a PrefixAnnouncement. + */ + template + size_t + wireEncode(EncodingImpl& encoder) const; + + void + wireDecode(const Block& wire); + + const optional& + getPrefixAnn() const + { + return m_prefixAnn; + } + +private: + optional m_prefixAnn; +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(PrefixAnnouncementHeader); + +} // namespace lp +} // namespace ndn + +#endif // NDN_CXX_LP_PREFIX_ANNOUNCEMENT_HEADER_HPP diff --git a/src/lp/sequence.hpp b/ndn-cxx/lp/sequence.hpp similarity index 92% rename from src/lp/sequence.hpp rename to ndn-cxx/lp/sequence.hpp index ccfa1bcb7..f6b3184b4 100644 --- a/src/lp/sequence.hpp +++ b/ndn-cxx/lp/sequence.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -24,7 +24,7 @@ #ifndef NDN_CXX_LP_SEQUENCE_HPP #define NDN_CXX_LP_SEQUENCE_HPP -#include "../common.hpp" +#include "ndn-cxx/detail/common.hpp" namespace ndn { namespace lp { diff --git a/ndn-cxx/lp/tags.hpp b/ndn-cxx/lp/tags.hpp new file mode 100644 index 000000000..b70b1a9a5 --- /dev/null +++ b/ndn-cxx/lp/tags.hpp @@ -0,0 +1,115 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_LP_TAGS_HPP +#define NDN_CXX_LP_TAGS_HPP + +#include "ndn-cxx/lp/cache-policy.hpp" +#include "ndn-cxx/lp/empty-value.hpp" +#include "ndn-cxx/lp/geo-tag.hpp" +#include "ndn-cxx/lp/prefix-announcement-header.hpp" +#include "ndn-cxx/tag.hpp" +#include "ndn-cxx/lp/util-header.hpp" +#include "ndn-cxx/lp/grid-header.hpp" + +namespace ndn { +namespace lp { + +class UtilHeader; +class GridHeader; + + +/** \class IncomingFaceIdTag + * \brief a packet tag for IncomingFaceId field + * + * This tag can be attached to Interest, Data, Nack. + */ +typedef SimpleTag IncomingFaceIdTag; + +/** \class NextHopFaceIdTag + * \brief a packet tag for NextHopFaceId field + * + * This tag can be attached to Interest. + */ +typedef SimpleTag NextHopFaceIdTag; + +/** \class CachePolicyTag + * \brief a packet tag for CachePolicy field + * + * This tag can be attached to Data. + */ +typedef SimpleTag CachePolicyTag; + +/** \class CongestionMarkTag + * \brief a packet tag for CongestionMark field + * + * This tag can be attached to Interest, Data, Nack. + */ +typedef SimpleTag CongestionMarkTag; + +/** \class NonDiscoveryTag + * \brief a packet tag for NonDiscovery field + * + * This tag can be attached to Interest. + */ +typedef SimpleTag NonDiscoveryTag; + +/** \class PrefixAnnouncementTag + * \brief a packet tag for PrefixAnnouncement field + * + * This tag can be attached to Data. + */ +typedef SimpleTag PrefixAnnouncementTag; + +/** \class HopCountTag + * \brief a packet tag for HopCount field + * + * This tag can be attached to Interest, Data, Nack. + */ +typedef SimpleTag HopCountTag; + +/** \class GeoTag + * \brief a packet tag for GeoTag field + * + * This tag can be attached to Interest, Data, Nack. + */ + +/** \class UtilTag + * Tag for utilization of edge nodes + */ +typedef SimpleTag UtilTag; + +typedef SimpleTag UtilInterestTag; + +typedef SimpleTag GridTag; + +typedef SimpleTag ReuseTag; + +typedef SimpleTag FakeInterestTag; + +typedef SimpleTag HopLimitTag; + +class GeoTag; // 0x60000001, defined directly in geo-tag.hpp + +} // namespace lp +} // namespace ndn + +#endif // NDN_CXX_LP_TAGS_HPP diff --git a/ndn-cxx/lp/tlv.hpp b/ndn-cxx/lp/tlv.hpp new file mode 100644 index 000000000..f8061e43e --- /dev/null +++ b/ndn-cxx/lp/tlv.hpp @@ -0,0 +1,88 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_LP_TLV_HPP +#define NDN_CXX_LP_TLV_HPP + +namespace ndn { +namespace lp { +namespace tlv { + +/** + * \brief TLV-TYPE numbers for NDNLPv2 + */ +enum { + LpPacket = 100, + Fragment = 80, + Sequence = 81, + FragIndex = 82, + FragCount = 83, + HopCountTag = 84, + GeoTag = 85, + GeoTagPos = 85, // inner fields inside GeoTag + PitToken = 98, + Nack = 800, + NackReason = 801, + NextHopFaceId = 816, + IncomingFaceId = 817, + CachePolicy = 820, + CachePolicyType = 821, + CongestionMark = 832, + Ack = 836, + TxSequence = 840, + NonDiscovery = 844, + PrefixAnnouncement = 848, + UtilTag = 849, + UtilInterestTag = 850, + GridTag = 851, + ReuseTag = 852, + FakeInterestTag = 853, + HopLimitTag = 854 + +}; + +enum { + /** + * \brief lower bound of 1-octet header field + */ + HEADER1_MIN = 81, + + /** + * \brief upper bound of 1-octet header field + */ + HEADER1_MAX = 99, + + /** + * \brief lower bound of 3-octet header field + */ + HEADER3_MIN = 800, + + /** + * \brief upper bound of 3-octet header field + */ + HEADER3_MAX = 959 +}; + +} // namespace tlv +} // namespace lp +} // namespace ndn + +#endif // NDN_CXX_LP_TLV_HPP diff --git a/ndn-cxx/lp/util-header.cpp b/ndn-cxx/lp/util-header.cpp new file mode 100644 index 000000000..d1dffe691 --- /dev/null +++ b/ndn-cxx/lp/util-header.cpp @@ -0,0 +1,91 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/lp/util-header.hpp" +#include "ndn-cxx/lp/tlv.hpp" + +namespace ndn { +namespace lp { + +UtilHeader::UtilHeader() { + m_utils = make_optional(); +} + +UtilHeader::UtilHeader(const Block& block) +{ + m_utils = make_optional(); + wireDecode(block); +} + +UtilHeader::UtilHeader(UtilStruct utils) + : m_utils(std::move(utils)) +{ +} + +template +size_t +UtilHeader::wireEncode(EncodingImpl& encoder) const +{ + if (m_utils == nullopt) { + BOOST_THROW_EXCEPTION(Error("UtilHeader does not contain a utilization")); + } + + // std::cout << "Wire encoding" << std::endl; + + size_t length = 0; + for (auto vec_size = 0; vec_size < m_utils->utils.size(); vec_size++) { + //std::cout << "m_utils->delays.size(): " << m_utils->delays.size() << std::endl; + //std::cout << "m_utils->utils.size(): " << m_utils->utils.size() << std::endl; + length += prependNonNegativeIntegerBlock(encoder, 80, m_utils->delays[vec_size]); + length += prependNonNegativeIntegerBlock(encoder, 81, int(m_utils->utils[vec_size])); + } + length += encoder.prependVarNumber(length); + length += encoder.prependVarNumber(tlv::UtilTag); + return length; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(UtilHeader); + +void +UtilHeader::wireDecode(const Block& wire) +{ + if (wire.type() != tlv::UtilTag) { + BOOST_THROW_EXCEPTION(Error("Unexpected TLV-TYPE " + to_string(wire.type()))); + } + //std::cout << "Wire decoding" << std::endl; + wire.parse(); + for (auto element = wire.elements_begin(); element != wire.elements_end(); ++element) { + //std::cout << "in wire decoding loop" << std::endl; + //element->parse(); + //std::cout << "Element type: " << element->type() << std::endl; + if (element->type() == 81) { + // std::cout << "Found type 81" << std::endl; + m_utils->utils.push_back(readNonNegativeInteger(*element)); + } + else if (element->type() == 80) { + // std::cout << "Found type 80" << std::endl; + m_utils->delays.push_back(readNonNegativeInteger(*element)); + } + } +} + +} // namespace lp +} // namespace ndn diff --git a/ndn-cxx/lp/util-header.hpp b/ndn-cxx/lp/util-header.hpp new file mode 100644 index 000000000..fb18793d6 --- /dev/null +++ b/ndn-cxx/lp/util-header.hpp @@ -0,0 +1,86 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_LP_UTIL_HEADER_HPP +#define NDN_CXX_LP_UTIL_HEADER_HPP + +#include "ndn-cxx/lp/tlv.hpp" +#include "ndn-cxx/lp/tags.hpp" + +#include +#include + +namespace ndn { +namespace lp { + +struct UtilStruct { + std::vector utils; + std::vector delays; +}; + +/** \brief represents a Util header field in NDNLP + */ +class UtilHeader +{ +public: + class Error : public ndn::tlv::Error + { + public: + using ndn::tlv::Error::Error; + }; + UtilHeader(); + + explicit + UtilHeader(const Block& block); + + /** \brief constructs PrefixAnnouncementHeader using PrefixAnnouncement + * + * \throw Error PrefixAnnouncement does not contain Data. + */ + explicit + UtilHeader(UtilStruct utils); + + /** \brief encodes the prefix announcement header to the wire format + * + * \throw Error this instance does not contain a PrefixAnnouncement. + */ + template + size_t + wireEncode(EncodingImpl& encoder) const; + + void + wireDecode(const Block& wire); + + const optional& + getUtilStruct() const + { + return m_utils; + } + + optional m_utils; +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(UtilHeader); + +} // namespace lp +} // namespace ndn + +#endif // NDN_CXX_LP_PREFIX_ANNOUNCEMENT_HEADER_HPP diff --git a/ndn-cxx/meta-info.cpp b/ndn-cxx/meta-info.cpp new file mode 100644 index 000000000..4315fc8a0 --- /dev/null +++ b/ndn-cxx/meta-info.cpp @@ -0,0 +1,250 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/meta-info.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" + +namespace ndn { + +BOOST_CONCEPT_ASSERT((WireEncodable)); +BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); +BOOST_CONCEPT_ASSERT((WireDecodable)); +static_assert(std::is_base_of::value, + "MetaInfo::Error must inherit from tlv::Error"); + +MetaInfo::MetaInfo() + : m_type(tlv::ContentType_Blob) + , m_freshnessPeriod(DEFAULT_FRESHNESS_PERIOD) +{ +} + +MetaInfo::MetaInfo(const Block& block) +{ + wireDecode(block); +} + +MetaInfo& +MetaInfo::setType(uint32_t type) +{ + m_wire.reset(); + m_type = type; + return *this; +} + +MetaInfo& +MetaInfo::setFreshnessPeriod(time::milliseconds freshnessPeriod) +{ + if (freshnessPeriod < time::milliseconds::zero()) { + NDN_THROW(std::invalid_argument("FreshnessPeriod must be >= 0")); + } + m_wire.reset(); + m_freshnessPeriod = freshnessPeriod; + return *this; +} + +MetaInfo& +MetaInfo::setFinalBlock(optional finalBlockId) +{ + m_wire.reset(); + m_finalBlockId = std::move(finalBlockId); + return *this; +} + +const std::list& +MetaInfo::getAppMetaInfo() const +{ + return m_appMetaInfo; +} + +MetaInfo& +MetaInfo::setAppMetaInfo(const std::list& info) +{ + for (const auto& block : info) { + if (block.type() < 128 || block.type() > 252) + NDN_THROW(Error("AppMetaInfo block has type outside the application range [128, 252]")); + } + + m_wire.reset(); + m_appMetaInfo = info; + return *this; +} + +MetaInfo& +MetaInfo::addAppMetaInfo(const Block& block) +{ + if (!(128 <= block.type() && block.type() <= 252)) + NDN_THROW(Error("AppMetaInfo block has type outside the application range [128, 252]")); + + m_wire.reset(); + m_appMetaInfo.push_back(block); + return *this; +} + +bool +MetaInfo::removeAppMetaInfo(uint32_t tlvType) +{ + for (auto it = m_appMetaInfo.begin(); it != m_appMetaInfo.end(); ++it) { + if (it->type() == tlvType) { + m_wire.reset(); + m_appMetaInfo.erase(it); + return true; + } + } + return false; +} + +const Block* +MetaInfo::findAppMetaInfo(uint32_t tlvType) const +{ + auto it = std::find_if(m_appMetaInfo.begin(), m_appMetaInfo.end(), + [=] (const Block& b) { return b.type() == tlvType; }); + return it != m_appMetaInfo.end() ? &*it : nullptr; +} + +template +size_t +MetaInfo::wireEncode(EncodingImpl& encoder) const +{ + // MetaInfo ::= META-INFO-TYPE TLV-LENGTH + // ContentType? + // FreshnessPeriod? + // FinalBlockId? + // AppMetaInfo* + + size_t totalLength = 0; + + for (auto it = m_appMetaInfo.rbegin(); it != m_appMetaInfo.rend(); ++it) { + totalLength += encoder.prependBlock(*it); + } + + // FinalBlockId + if (m_finalBlockId) { + totalLength += prependNestedBlock(encoder, tlv::FinalBlockId, *m_finalBlockId); + } + + // FreshnessPeriod + if (m_freshnessPeriod != DEFAULT_FRESHNESS_PERIOD) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::FreshnessPeriod, + static_cast(m_freshnessPeriod.count())); + } + + // ContentType + if (m_type != tlv::ContentType_Blob) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::ContentType, m_type); + } + + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::MetaInfo); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(MetaInfo); + +const Block& +MetaInfo::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 +MetaInfo::wireDecode(const Block& wire) +{ + m_wire = wire; + m_wire.parse(); + + // MetaInfo ::= META-INFO-TYPE TLV-LENGTH + // ContentType? + // FreshnessPeriod? + // FinalBlockId? + // AppMetaInfo* + + auto val = m_wire.elements_begin(); + + // ContentType + if (val != m_wire.elements_end() && val->type() == tlv::ContentType) { + m_type = readNonNegativeIntegerAs(*val); + ++val; + } + else { + m_type = tlv::ContentType_Blob; + } + + // FreshnessPeriod + if (val != m_wire.elements_end() && val->type() == tlv::FreshnessPeriod) { + m_freshnessPeriod = time::milliseconds(readNonNegativeInteger(*val)); + ++val; + } + else { + m_freshnessPeriod = DEFAULT_FRESHNESS_PERIOD; + } + + // FinalBlockId + if (val != m_wire.elements_end() && val->type() == tlv::FinalBlockId) { + m_finalBlockId.emplace(val->blockFromValue()); + ++val; + } + else { + m_finalBlockId = nullopt; + } + + // AppMetaInfo (if any) + for (; val != m_wire.elements().end(); ++val) { + m_appMetaInfo.push_back(*val); + } +} + +std::ostream& +operator<<(std::ostream& os, const MetaInfo& info) +{ + // ContentType + os << "ContentType: " << info.getType(); + + // FreshnessPeriod + if (info.getFreshnessPeriod() > 0_ms) { + os << ", FreshnessPeriod: " << info.getFreshnessPeriod(); + } + + // FinalBlockId + if (info.getFinalBlock()) { + os << ", FinalBlockId: "; + info.getFinalBlock()->toUri(os); + } + + // App-defined MetaInfo items + for (const auto& block : info.getAppMetaInfo()) { + os << ", AppMetaInfoTlvType: " << block.type(); + } + + return os; +} + +} // namespace ndn diff --git a/src/meta-info.hpp b/ndn-cxx/meta-info.hpp similarity index 76% rename from src/meta-info.hpp rename to ndn-cxx/meta-info.hpp index 798acd194..fe3f19c64 100644 --- a/src/meta-info.hpp +++ b/ndn-cxx/meta-info.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,17 +22,19 @@ #ifndef NDN_META_INFO_HPP #define NDN_META_INFO_HPP -#include "common.hpp" -#include "encoding/block.hpp" -#include "encoding/encoding-buffer.hpp" -#include "util/time.hpp" -#include "name-component.hpp" +#include "ndn-cxx/name-component.hpp" +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/util/time.hpp" + #include namespace ndn { +const time::milliseconds DEFAULT_FRESHNESS_PERIOD = time::milliseconds::zero(); + /** - * An MetaInfo holds the meta info which is signed inside the data packet. + * A MetaInfo holds the meta info which is signed inside the data packet. * * The class allows experimentation with application-defined meta information blocks, * which slightly violates NDN-TLV specification. When using the application-defined @@ -59,11 +61,7 @@ class MetaInfo class Error : public tlv::Error { public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } + using tlv::Error::Error; }; MetaInfo(); @@ -85,26 +83,50 @@ class MetaInfo wireDecode(const Block& wire); public: // getter/setter + /** @brief return ContentType + * + * If ContentType element is omitted, returns \c tlv::ContentType_Blob. + */ uint32_t - getType() const; + getType() const + { + return m_type; + } /** @brief set ContentType - * @param type a code defined in tlv::ContentTypeValue + * @param type a number defined in \c tlv::ContentTypeValue */ MetaInfo& setType(uint32_t type); - const time::milliseconds& - getFreshnessPeriod() const; + /** @brief return FreshnessPeriod + * + * If FreshnessPeriod element is omitted, returns \c DEFAULT_FRESHNESS_PERIOD. + */ + time::milliseconds + getFreshnessPeriod() const + { + return m_freshnessPeriod; + } + /** @brief set FreshnessPeriod + * @throw std::invalid_argument specified FreshnessPeriod is negative + */ MetaInfo& - setFreshnessPeriod(const time::milliseconds& freshnessPeriod); + setFreshnessPeriod(time::milliseconds freshnessPeriod); - const name::Component& - getFinalBlockId() const; + /** @brief return FinalBlockId + */ + const optional& + getFinalBlock() const + { + return m_finalBlockId; + } + /** @brief set FinalBlockId + */ MetaInfo& - setFinalBlockId(const name::Component& finalBlockId); + setFinalBlock(optional finalBlockId); public: // app-defined MetaInfo items /** @@ -112,7 +134,7 @@ class MetaInfo * * @note Warning: Experimental API, which may change or disappear in the future * - * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlockId + * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlock * is called before *AppMetaInfo, all app-defined blocks will be lost */ const std::list& @@ -128,7 +150,7 @@ class MetaInfo * * @note Warning: Experimental API, which may change or disappear in the future * - * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlockId + * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlock * is called before *AppMetaInfo, all app-defined blocks will be lost */ MetaInfo& @@ -142,7 +164,7 @@ class MetaInfo * * @note Warning: Experimental API, which may change or disappear in the future * - * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlockId + * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlock * is called before *AppMetaInfo, all app-defined blocks will be lost */ MetaInfo& @@ -155,7 +177,7 @@ class MetaInfo * * @note Warning: Experimental API, which may change or disappear in the future * - * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlockId + * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlock * is called before *AppMetaInfo, all app-defined blocks will be lost */ bool @@ -171,63 +193,26 @@ class MetaInfo * * @note Warning: Experimental API, which may change or disappear in the future * - * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlockId + * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlock * is called before *AppMetaInfo, all app-defined blocks will be lost */ const Block* findAppMetaInfo(uint32_t tlvType) const; -public: // EqualityComparable concept - bool - operator==(const MetaInfo& other) const; - - bool - operator!=(const MetaInfo& other) const; - private: uint32_t m_type; time::milliseconds m_freshnessPeriod; - name::Component m_finalBlockId; + optional m_finalBlockId; std::list m_appMetaInfo; mutable Block m_wire; }; +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(MetaInfo); + std::ostream& operator<<(std::ostream& os, const MetaInfo& info); -///////////////////////////////////////////////////////////////////////// - -inline uint32_t -MetaInfo::getType() const -{ - return m_type; -} - -inline const time::milliseconds& -MetaInfo::getFreshnessPeriod() const -{ - return m_freshnessPeriod; -} - -inline const name::Component& -MetaInfo::getFinalBlockId() const -{ - return m_finalBlockId; -} - -inline bool -MetaInfo::operator==(const MetaInfo& other) const -{ - return wireEncode() == other.wireEncode(); -} - -inline bool -MetaInfo::operator!=(const MetaInfo& other) const -{ - return !(*this == other); -} - } // namespace ndn #endif // NDN_META_INFO_HPP diff --git a/ndn-cxx/metadata-object.cpp b/ndn-cxx/metadata-object.cpp new file mode 100644 index 000000000..43212b673 --- /dev/null +++ b/ndn-cxx/metadata-object.cpp @@ -0,0 +1,92 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * @author Chavoosh Ghasemi + */ + +#include "ndn-cxx/metadata-object.hpp" + +namespace ndn { + +static_assert(std::is_base_of::value, + "MetadataObject::Error must inherit from tlv::Error"); + +const name::Component KEYWORD_METADATA_COMP = "20 08 6D65746164617461"_block; // 32=metadata + +MetadataObject::MetadataObject() = default; + +MetadataObject::MetadataObject(const Data& data) +{ + if (data.getContentType() != tlv::ContentType_Blob) { + NDN_THROW(Error("Expecting ContentType Blob, got " + to_string(data.getContentType()))); + } + + if (!isValidName(data.getName())) { + NDN_THROW(Error("Name " + data.getName().toUri() + " is not a valid MetadataObject name")); + } + + data.getContent().parse(); + // ignore non-Name elements before the first one + m_versionedName.wireDecode(data.getContent().get(tlv::Name)); +} + +Data +MetadataObject::makeData(Name discoveryInterestName, + KeyChain& keyChain, + const ndn::security::SigningInfo& si, + optional version, + time::milliseconds freshnessPeriod) const +{ + if (discoveryInterestName.empty() || discoveryInterestName[-1] != KEYWORD_METADATA_COMP) { + NDN_THROW(Error("Name " + discoveryInterestName.toUri() + + " is not a valid discovery Interest name")); + } + discoveryInterestName.appendVersion(version); + discoveryInterestName.appendSegment(0); + + Data data(discoveryInterestName); + data.setContent(m_versionedName.wireEncode()); + data.setFreshnessPeriod(freshnessPeriod); + keyChain.sign(data, si); + + return data; +} + +MetadataObject& +MetadataObject::setVersionedName(const Name& name) +{ + m_versionedName = name; + return *this; +} + +bool +MetadataObject::isValidName(const Name& name) +{ + return name.size() >= 3 && name[-3] == KEYWORD_METADATA_COMP && + name[-2].isVersion() && name[-1].isSegment(); +} + +Interest +MetadataObject::makeDiscoveryInterest(Name name) +{ + return Interest(name.append(KEYWORD_METADATA_COMP)) + .setCanBePrefix(true) + .setMustBeFresh(true); +} + +} // namespace ndn diff --git a/ndn-cxx/metadata-object.hpp b/ndn-cxx/metadata-object.hpp new file mode 100644 index 000000000..0403d3ed1 --- /dev/null +++ b/ndn-cxx/metadata-object.hpp @@ -0,0 +1,126 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * @author Chavoosh Ghasemi + */ + +#ifndef NDN_METADATA_OBJECT_HPP +#define NDN_METADATA_OBJECT_HPP + +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/security/v2/key-chain.hpp" + +namespace ndn { + +/** + * @brief Class for RDR-style metadata encoding/decoding. + * + * The interest and data packets dealing with metadata (called "discovery interest" + * and "metadata", respectively) follow a specific format. + * @see https://redmine.named-data.net/projects/ndn-tlv/wiki/RDR + * + * Realtime Data Retrieval (RDR) is a protocol for discovering the latest version number + * of a given data collection. There are two names in an RDR metadata object: + * @li the **versioned name** is a prefix of the data collection, and generally + * contains a version component. It appears in the Content element of the metadata object. + * @li the **metadata name** is the name of the metadata object itself, and includes + * a keyword name component `32=metadata`, as well as version and segment components. + */ +class MetadataObject +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + /** + * @brief Create an empty metadata object + */ + MetadataObject(); + + /** + * @brief Construct a metadata object by decoding of the given Data packet + * @throw tlv::Error the Data is not a valid metadata packet + */ + explicit + MetadataObject(const Data& data); + + /** + * @brief Create a Data packet representing this metadata object + * + * @param discoveryInterestName the discovery Interest's name, which must end with + * a keyword name component `32=metadata` + * @param keyChain KeyChain to sign the Data + * @param si signing parameters + * @param version version number of metadata packet; if nullopt, use current Unix + * timestamp (in milliseconds) as the version number + * @param freshnessPeriod freshness period of metadata packet + * + * @throw tlv::Error @p discoveryInterestName is not valid + */ + NDN_CXX_NODISCARD Data + makeData(Name discoveryInterestName, + KeyChain& keyChain, + const ndn::security::SigningInfo& si = KeyChain::getDefaultSigningInfo(), + optional version = nullopt, + time::milliseconds freshnessPeriod = 10_ms) const; + + /** + * @brief Return the versioned name (i.e., the name inside the content) + */ + const Name& + getVersionedName() const + { + return m_versionedName; + } + + /** + * @brief Set the versioned name + * + * Any metadata packet carries a versioned name in its payload where it shows the name + * and the latest version of a data stream. For instance, `/ndn/test/%FD%97%47%1E%6C` is + * a versioned name that shows the latest version of `/ndn/test`. + */ + MetadataObject& + setVersionedName(const Name& name); + +public: // static methods + /** + * @brief Check whether @p name can be a valid metadata name + */ + static bool + isValidName(const Name& name); + + /** + * @brief Generate a discovery interest packet based on @p name + * + * @param name prefix of data collection + */ + NDN_CXX_NODISCARD static Interest + makeDiscoveryInterest(Name name); + +private: + Name m_versionedName; +}; + +} // namespace ndn + +#endif // NDN_METADATA_OBJECT_HPP diff --git a/ndn-cxx/mgmt/control-parameters.hpp b/ndn-cxx/mgmt/control-parameters.hpp new file mode 100644 index 000000000..787c37a90 --- /dev/null +++ b/ndn-cxx/mgmt/control-parameters.hpp @@ -0,0 +1,48 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_MGMT_CONTROL_PARAMETERS_HPP +#define NDN_MGMT_CONTROL_PARAMETERS_HPP + +#include "ndn-cxx/encoding/block.hpp" + +namespace ndn { +namespace mgmt { + +/** \brief base class for a struct that contains ControlCommand parameters + */ +class ControlParameters +{ +public: + virtual + ~ControlParameters() = default; + + virtual void + wireDecode(const Block& wire) = 0; + + virtual Block + wireEncode() const = 0; +}; + +} // namespace mgmt +} // namespace ndn + +#endif // NDN_MGMT_CONTROL_PARAMETERS_HPP diff --git a/src/mgmt/control-response.cpp b/ndn-cxx/mgmt/control-response.cpp similarity index 76% rename from src/mgmt/control-response.cpp rename to ndn-cxx/mgmt/control-response.cpp index a0c74c254..d0abdaf74 100644 --- a/src/mgmt/control-response.cpp +++ b/ndn-cxx/mgmt/control-response.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,9 +19,9 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "control-response.hpp" -#include "../encoding/block-helpers.hpp" -#include "../encoding/tlv-nfd.hpp" +#include "ndn-cxx/mgmt/control-response.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/encoding/tlv-nfd.hpp" namespace ndn { namespace mgmt { @@ -56,8 +56,7 @@ ControlResponse::wireEncode() const m_wire = Block(tlv::nfd::ControlResponse); m_wire.push_back(makeNonNegativeIntegerBlock(tlv::nfd::StatusCode, m_code)); - - m_wire.push_back(makeBinaryBlock(tlv::nfd::StatusText, m_text.c_str(), m_text.size())); + m_wire.push_back(makeStringBlock(tlv::nfd::StatusText, m_text)); if (m_body.hasWire()) { m_wire.push_back(m_body); @@ -74,26 +73,25 @@ ControlResponse::wireDecode(const Block& wire) m_wire.parse(); if (m_wire.type() != tlv::nfd::ControlResponse) - throw Error("Requested decoding of ControlResponse, but Block is of different type"); + NDN_THROW(Error("ControlResponse", m_wire.type())); - Block::element_const_iterator val = m_wire.elements_begin(); + auto val = m_wire.elements_begin(); if (val == m_wire.elements_end() || val->type() != tlv::nfd::StatusCode) { - throw Error("Incorrect ControlResponse format (StatusCode missing or not the first item)"); + NDN_THROW(Error("missing StatusCode sub-element")); } - - m_code = readNonNegativeInteger(*val); + m_code = readNonNegativeIntegerAs(*val); ++val; if (val == m_wire.elements_end() || val->type() != tlv::nfd::StatusText) { - throw Error("Incorrect ControlResponse format (StatusText missing or not the second item)"); + NDN_THROW(Error("missing StatusText sub-element")); } - m_text.assign(reinterpret_cast(val->value()), val->value_size()); + m_text = readString(*val); ++val; if (val != m_wire.elements_end()) m_body = *val; else - m_body = Block(); + m_body = {}; } std::ostream& diff --git a/ndn-cxx/mgmt/control-response.hpp b/ndn-cxx/mgmt/control-response.hpp new file mode 100644 index 000000000..d7c0e7096 --- /dev/null +++ b/ndn-cxx/mgmt/control-response.hpp @@ -0,0 +1,129 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_MGMT_CONTROL_RESPONSE_HPP +#define NDN_MGMT_CONTROL_RESPONSE_HPP + +#include "ndn-cxx/encoding/block.hpp" + +namespace ndn { +namespace mgmt { + +/** \brief ControlCommand response + */ +class ControlResponse +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + ControlResponse(); + + ControlResponse(uint32_t code, const std::string& text); + + explicit + ControlResponse(const Block& block); + + uint32_t + getCode() const; + + ControlResponse& + setCode(uint32_t code); + + const std::string& + getText() const; + + ControlResponse& + setText(const std::string& text); + + const Block& + getBody() const; + + ControlResponse& + setBody(const Block& body); + + const Block& + wireEncode() const; + + void + wireDecode(const Block& block); + +protected: + uint32_t m_code; + std::string m_text; + Block m_body; + + mutable Block m_wire; +}; + +inline uint32_t +ControlResponse::getCode() const +{ + return m_code; +} + +inline ControlResponse& +ControlResponse::setCode(uint32_t code) +{ + m_code = code; + m_wire.reset(); + return *this; +} + +inline const std::string& +ControlResponse::getText() const +{ + return m_text; +} + +inline ControlResponse& +ControlResponse::setText(const std::string& text) +{ + m_text = text; + m_wire.reset(); + return *this; +} + +inline const Block& +ControlResponse::getBody() const +{ + return m_body; +} + +inline ControlResponse& +ControlResponse::setBody(const Block& body) +{ + m_body = body; + m_body.encode(); // will do nothing if already encoded + m_wire.reset(); + return *this; +} + +std::ostream& +operator<<(std::ostream& os, const ControlResponse& response); + +} // namespace mgmt +} // namespace ndn + +#endif // NDN_MGMT_CONTROL_RESPONSE_HPP diff --git a/ndn-cxx/mgmt/dispatcher.cpp b/ndn-cxx/mgmt/dispatcher.cpp new file mode 100644 index 000000000..306c7f3b6 --- /dev/null +++ b/ndn-cxx/mgmt/dispatcher.cpp @@ -0,0 +1,338 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/dispatcher.hpp" +#include "ndn-cxx/lp/tags.hpp" +#include "ndn-cxx/util/logger.hpp" + +NDN_LOG_INIT(ndn.mgmt.Dispatcher); + +namespace ndn { +namespace mgmt { + +const time::milliseconds DEFAULT_FRESHNESS_PERIOD = 1_s; + +Authorization +makeAcceptAllAuthorization() +{ + return [] (const Name& prefix, + const Interest& interest, + const ControlParameters* params, + const AcceptContinuation& accept, + const RejectContinuation& reject) { + accept(""); + }; +} + +Dispatcher::Dispatcher(Face& face, KeyChain& keyChain, + const security::SigningInfo& signingInfo, + size_t imsCapacity) + : m_face(face) + , m_keyChain(keyChain) + , m_signingInfo(signingInfo) + , m_storage(m_face.getIoService(), imsCapacity) +{ +} + +Dispatcher::~Dispatcher() = default; + +void +Dispatcher::addTopPrefix(const Name& prefix, bool wantRegister, + const security::SigningInfo& signingInfo) +{ + bool hasOverlap = std::any_of(m_topLevelPrefixes.begin(), m_topLevelPrefixes.end(), + [&prefix] (const auto& x) { + return x.first.isPrefixOf(prefix) || prefix.isPrefixOf(x.first); + }); + if (hasOverlap) { + NDN_THROW(std::out_of_range("top-level prefix overlaps")); + } + + TopPrefixEntry& topPrefixEntry = m_topLevelPrefixes[prefix]; + + if (wantRegister) { + topPrefixEntry.registeredPrefix = m_face.registerPrefix(prefix, + nullptr, + [] (const Name&, const std::string& reason) { + NDN_THROW(std::runtime_error("prefix registration failed: " + reason)); + }, + signingInfo); + } + + for (const auto& entry : m_handlers) { + Name fullPrefix = Name(prefix).append(entry.first); + auto filterHdl = m_face.setInterestFilter(fullPrefix, bind(entry.second, prefix, _2)); + topPrefixEntry.interestFilters.push_back(filterHdl); + } +} + +void +Dispatcher::removeTopPrefix(const Name& prefix) +{ + m_topLevelPrefixes.erase(prefix); +} + +bool +Dispatcher::isOverlappedWithOthers(const PartialName& relPrefix) const +{ + bool hasOverlapWithHandlers = + std::any_of(m_handlers.begin(), m_handlers.end(), + [&] (const auto& entry) { + return entry.first.isPrefixOf(relPrefix) || relPrefix.isPrefixOf(entry.first); + }); + bool hasOverlapWithStreams = + std::any_of(m_streams.begin(), m_streams.end(), + [&] (const auto& entry) { + return entry.first.isPrefixOf(relPrefix) || relPrefix.isPrefixOf(entry.first); + }); + + return hasOverlapWithHandlers || hasOverlapWithStreams; +} + +void +Dispatcher::afterAuthorizationRejected(RejectReply act, const Interest& interest) +{ + if (act == RejectReply::STATUS403) { + sendControlResponse(ControlResponse(403, "authorization rejected"), interest); + } +} + +void +Dispatcher::queryStorage(const Name& prefix, const Interest& interest, + const InterestHandler& missContinuation) +{ + auto data = m_storage.find(interest); + if (data == nullptr) { + // invoke missContinuation to process this Interest if the query fails. + if (missContinuation) + missContinuation(prefix, interest); + } + else { + // send the fetched data through face if query succeeds. + sendOnFace(*data); + } +} + +void +Dispatcher::sendData(const Name& dataName, const Block& content, const MetaInfo& metaInfo, + SendDestination option, time::milliseconds imsFresh) +{ + auto data = make_shared(dataName); + data->setContent(content).setMetaInfo(metaInfo).setFreshnessPeriod(DEFAULT_FRESHNESS_PERIOD); + + m_keyChain.sign(*data, m_signingInfo); + + if (option == SendDestination::IMS || option == SendDestination::FACE_AND_IMS) { + lp::CachePolicy policy; + policy.setPolicy(lp::CachePolicyType::NO_CACHE); + data->setTag(make_shared(policy)); + m_storage.insert(*data, imsFresh); + } + + if (option == SendDestination::FACE || option == SendDestination::FACE_AND_IMS) { + sendOnFace(*data); + } +} + +void +Dispatcher::sendOnFace(const Data& data) +{ + try { + m_face.put(data); + } + catch (const Face::Error& e) { + NDN_LOG_ERROR("sendOnFace: " << e.what()); + } +} + +void +Dispatcher::processControlCommandInterest(const Name& prefix, + const Name& relPrefix, + const Interest& interest, + const ControlParametersParser& parser, + const Authorization& authorization, + const AuthorizationAcceptedCallback& accepted, + const AuthorizationRejectedCallback& rejected) +{ + // /// + size_t parametersLoc = prefix.size() + relPrefix.size(); + const name::Component& pc = interest.getName().get(parametersLoc); + + shared_ptr parameters; + try { + parameters = parser(pc); + } + catch (const tlv::Error&) { + return; + } + + AcceptContinuation accept = [=] (const auto& req) { accepted(req, prefix, interest, parameters); }; + RejectContinuation reject = [=] (RejectReply reply) { rejected(reply, interest); }; + authorization(prefix, interest, parameters.get(), accept, reject); +} + +void +Dispatcher::processAuthorizedControlCommandInterest(const std::string& requester, + const Name& prefix, + const Interest& interest, + const shared_ptr& parameters, + const ValidateParameters& validateParams, + const ControlCommandHandler& handler) +{ + if (validateParams(*parameters)) { + handler(prefix, interest, *parameters, + [=] (const auto& resp) { this->sendControlResponse(resp, interest); }); + } + else { + sendControlResponse(ControlResponse(400, "failed in validating parameters"), interest); + } +} + +void +Dispatcher::sendControlResponse(const ControlResponse& resp, const Interest& interest, bool isNack) +{ + MetaInfo metaInfo; + if (isNack) { + metaInfo.setType(tlv::ContentType_Nack); + } + + // control response is always sent out through the face + sendData(interest.getName(), resp.wireEncode(), metaInfo, + SendDestination::FACE, DEFAULT_FRESHNESS_PERIOD); +} + +void +Dispatcher::addStatusDataset(const PartialName& relPrefix, + Authorization authorize, + StatusDatasetHandler handle) +{ + if (!m_topLevelPrefixes.empty()) { + NDN_THROW(std::domain_error("one or more top-level prefix has been added")); + } + + if (isOverlappedWithOthers(relPrefix)) { + NDN_THROW(std::out_of_range("status dataset name overlaps")); + } + + AuthorizationAcceptedCallback accepted = + bind(&Dispatcher::processAuthorizedStatusDatasetInterest, this, _1, _2, _3, std::move(handle)); + AuthorizationRejectedCallback rejected = + bind(&Dispatcher::afterAuthorizationRejected, this, _1, _2); + + // follow the general path if storage is a miss + InterestHandler missContinuation = bind(&Dispatcher::processStatusDatasetInterest, this, _1, _2, + std::move(authorize), std::move(accepted), std::move(rejected)); + + m_handlers[relPrefix] = [this, miss = std::move(missContinuation)] (auto&&... args) { + this->queryStorage(std::forward(args)..., miss); + }; +} + +void +Dispatcher::processStatusDatasetInterest(const Name& prefix, + const Interest& interest, + const Authorization& authorization, + const AuthorizationAcceptedCallback& accepted, + const AuthorizationRejectedCallback& rejected) +{ + const Name& interestName = interest.getName(); + bool endsWithVersionOrSegment = interestName.size() >= 1 && + (interestName[-1].isVersion() || interestName[-1].isSegment()); + if (endsWithVersionOrSegment) { + return; + } + + AcceptContinuation accept = [=] (const auto& req) { accepted(req, prefix, interest, nullptr); }; + RejectContinuation reject = [=] (RejectReply reply) { rejected(reply, interest); }; + authorization(prefix, interest, nullptr, accept, reject); +} + +void +Dispatcher::processAuthorizedStatusDatasetInterest(const std::string& requester, + const Name& prefix, + const Interest& interest, + const StatusDatasetHandler& handler) +{ + StatusDatasetContext context(interest, + bind(&Dispatcher::sendStatusDatasetSegment, this, _1, _2, _3, _4), + bind(&Dispatcher::sendControlResponse, this, _1, interest, true)); + handler(prefix, interest, context); +} + +void +Dispatcher::sendStatusDatasetSegment(const Name& dataName, const Block& content, + time::milliseconds imsFresh, bool isFinalBlock) +{ + // the first segment will be sent to both places (the face and the in-memory storage) + // other segments will be inserted to the in-memory storage only + auto destination = SendDestination::IMS; + if (dataName[-1].toSegment() == 0) { + destination = SendDestination::FACE_AND_IMS; + } + + MetaInfo metaInfo; + if (isFinalBlock) { + metaInfo.setFinalBlock(dataName[-1]); + } + + sendData(dataName, content, metaInfo, destination, imsFresh); +} + +PostNotification +Dispatcher::addNotificationStream(const PartialName& relPrefix) +{ + if (!m_topLevelPrefixes.empty()) { + NDN_THROW(std::domain_error("one or more top-level prefix has been added")); + } + + if (isOverlappedWithOthers(relPrefix)) { + NDN_THROW(std::out_of_range("notification stream name overlaps")); + } + + // register a handler for the subscriber of this notification stream + // keep silent if Interest does not match a stored notification + m_handlers[relPrefix] = [this] (auto&&... args) { + this->queryStorage(std::forward(args)..., nullptr); + }; + m_streams[relPrefix] = 0; + + return [=] (const Block& b) { postNotification(b, relPrefix); }; +} + +void +Dispatcher::postNotification(const Block& notification, const PartialName& relPrefix) +{ + if (m_topLevelPrefixes.size() != 1) { + NDN_LOG_WARN("postNotification: no top-level prefix or too many top-level prefixes"); + return; + } + + Name streamName(m_topLevelPrefixes.begin()->first); + streamName.append(relPrefix); + streamName.appendSequenceNumber(m_streams[streamName]++); + + // notification is sent out via the face after inserting into the in-memory storage, + // because a request may be pending in the PIT + sendData(streamName, notification, {}, SendDestination::FACE_AND_IMS, DEFAULT_FRESHNESS_PERIOD); +} + +} // namespace mgmt +} // namespace ndn diff --git a/src/mgmt/dispatcher.hpp b/ndn-cxx/mgmt/dispatcher.hpp similarity index 82% rename from src/mgmt/dispatcher.hpp rename to ndn-cxx/mgmt/dispatcher.hpp index b19aba6c1..308e89a4d 100644 --- a/src/mgmt/dispatcher.hpp +++ b/ndn-cxx/mgmt/dispatcher.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,13 +22,13 @@ #ifndef NDN_MGMT_DISPATCHER_HPP #define NDN_MGMT_DISPATCHER_HPP -#include "../face.hpp" -#include "../security/key-chain.hpp" -#include "../encoding/block.hpp" -#include "../util/in-memory-storage-fifo.hpp" -#include "control-response.hpp" -#include "control-parameters.hpp" -#include "status-dataset-context.hpp" +#include "ndn-cxx/face.hpp" +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/ims/in-memory-storage-fifo.hpp" +#include "ndn-cxx/mgmt/control-response.hpp" +#include "ndn-cxx/mgmt/control-parameters.hpp" +#include "ndn-cxx/mgmt/status-dataset-context.hpp" +#include "ndn-cxx/security/key-chain.hpp" #include @@ -57,7 +57,7 @@ enum class RejectReply { /** \brief a function to be called if authorization is rejected */ -typedef std::function RejectContinuation; +typedef std::function RejectContinuation; /** \brief a function that performs authorization * \param prefix top-level prefix, e.g., "/localhost/nfd"; @@ -76,7 +76,7 @@ typedef std::function Authorization; -/** \return an Authorization that accepts all Interests, with empty string as requester +/** \brief return an Authorization that accepts all Interests, with empty string as requester */ Authorization makeAcceptAllAuthorization(); @@ -105,6 +105,7 @@ typedef std::function ControlCommandHandler; +// ---- STATUS DATASET ---- /** \brief a function to handle a StatusDataset request * \param prefix top-level prefix, e.g., "/localhost/nfd"; @@ -128,16 +129,6 @@ typedef std::function PostNotification; */ class Dispatcher : noncopyable { - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - public: /** \brief constructor * \param face the Face on which the dispatcher operates @@ -145,7 +136,7 @@ class Dispatcher : noncopyable * \param signingInfo signing parameters to sign Data with \p keyChain * \param imsCapacity capacity of the internal InMemoryStorage used by dispatcher */ - Dispatcher(Face& face, security::KeyChain& keyChain, + Dispatcher(Face& face, KeyChain& keyChain, const security::SigningInfo& signingInfo = security::SigningInfo(), size_t imsCapacity = 256); @@ -162,14 +153,14 @@ class Dispatcher : noncopyable * 1. if the new top-level prefix overlaps with an existing top-level prefix * (one top-level prefix is a prefix of another top-level prefix), throw std::domain_error * 2. if wantRegister is true, invoke face.registerPrefix for the top-level prefix; - * the returned RegisteredPrefixId shall be recorded internally, indexed by the top-level + * the returned RegisteredPrefixHandle shall be recorded internally, indexed by the top-level * prefix * 3. foreach relPrefix from ControlCommands and StatusDatasets, * join the top-level prefix with the relPrefix to obtain the full prefix, * and invoke non-registering overload of face.setInterestFilter, * with the InterestHandler set to an appropriate private method to handle incoming Interests * for the ControlCommand or StatusDataset; - * the returned InterestFilterId shall be recorded internally, indexed by the top-level + * the returned InterestFilterHandle shall be recorded internally, indexed by the top-level * prefix */ void @@ -181,10 +172,8 @@ class Dispatcher : noncopyable * * Procedure for removing a top-level prefix: * 1. if the top-level prefix has not been added, abort these steps - * 2. if the top-level prefix has been added with wantRegister, - * invoke face.unregisterPrefix with the RegisteredPrefixId - * 3. foreach InterestFilterId recorded during addTopPrefix, - * invoke face.unsetInterestFilter with the InterestFilterId + * 2. if the top-level prefix has been added with wantRegister, unregister the prefix + * 3. unset each Interest filter recorded during addTopPrefix, */ void removeTopPrefix(const Name& prefix); @@ -194,11 +183,10 @@ class Dispatcher : noncopyable * \tparam CP subclass of ControlParameters used by this command * \param relPrefix a prefix for this command, e.g., "faces/create"; * relPrefixes in ControlCommands, StatusDatasets, NotificationStreams must be - * non-overlapping - * (no relPrefix is a prefix of another relPrefix) - * \param authorization Callback to authorize the incoming commands - * \param validateParams Callback to validate parameters of the incoming commands - * \param handler Callback to handle the commands + * non-overlapping (no relPrefix is a prefix of another relPrefix) + * \param authorize Callback to authorize the incoming commands + * \param validate Callback to validate parameters of the incoming commands + * \param handle Callback to handle the commands * \pre no top-level prefix has been added * \throw std::out_of_range \p relPrefix overlaps with an existing relPrefix * \throw std::domain_error one or more top-level prefix has been added @@ -219,18 +207,17 @@ class Dispatcher : noncopyable template void addControlCommand(const PartialName& relPrefix, - const Authorization& authorization, - const ValidateParameters& validateParams, - const ControlCommandHandler& handler); + Authorization authorize, + ValidateParameters validate, + ControlCommandHandler handle); public: // StatusDataset /** \brief register a StatusDataset or a prefix under which StatusDatasets can be requested * \param relPrefix a prefix for this dataset, e.g., "faces/list"; * relPrefixes in ControlCommands, StatusDatasets, NotificationStreams must be - * non-overlapping - * (no relPrefix is a prefix of another relPrefix) - * \param authorization should set identity to Name() if the dataset is public - * \param handler Callback to process the incoming dataset requests + * non-overlapping (no relPrefix is a prefix of another relPrefix) + * \param authorize should set identity to Name() if the dataset is public + * \param handle Callback to process the incoming dataset requests * \pre no top-level prefix has been added * \throw std::out_of_range \p relPrefix overlaps with an existing relPrefix * \throw std::domain_error one or more top-level prefix has been added @@ -257,15 +244,14 @@ class Dispatcher : noncopyable */ void addStatusDataset(const PartialName& relPrefix, - const Authorization& authorization, - const StatusDatasetHandler& handler); + Authorization authorize, + StatusDatasetHandler handle); public: // NotificationStream /** \brief register a NotificationStream * \param relPrefix a prefix for this notification stream, e.g., "faces/events"; * relPrefixes in ControlCommands, StatusDatasets, NotificationStreams must be - * non-overlapping - * (no relPrefix is a prefix of another relPrefix) + * non-overlapping (no relPrefix is a prefix of another relPrefix) * \return a function into which notifications can be posted * \pre no top-level prefix has been added * \throw std::out_of_range \p relPrefix overlaps with an existing relPrefix @@ -291,27 +277,24 @@ class Dispatcher : noncopyable typedef std::function AuthorizationAcceptedCallback; + const shared_ptr&)> AuthorizationAcceptedCallback; typedef std::function AuthorizationRejectedCallback; /** * @brief the parser of extracting control parameters from name component. - * - * @param component name component that may encode control parameters. + * @param comp name component that may encode control parameters. * @return a shared pointer to the extracted control parameters. * @throw tlv::Error if the NameComponent cannot be parsed as ControlParameters */ - typedef std::function(const name::Component& component)> - ControlParametersParser; + typedef std::function(const name::Component& comp)> ControlParametersParser; bool - isOverlappedWithOthers(const PartialName& relPrefix); + isOverlappedWithOthers(const PartialName& relPrefix) const; /** * @brief process unauthorized request - * * @param act action to reply * @param interest the incoming Interest */ @@ -338,14 +321,14 @@ class Dispatcher : noncopyable }; /** - * @brief send data to the face or in-memory storage + * @brief send data to the face and/or in-memory storage * - * create a data packet with the given @p dataName, @p content, and @p metaInfo, - * set its FreshnessPeriod to DEFAULT_FRESHNESS_PERIOD, and then send it out through the face and/or - * insert it into the in-memory storage as specified in @p option. + * Create a Data packet with the given @p dataName, @p content, and @p metaInfo, + * set its FreshnessPeriod to DEFAULT_FRESHNESS_PERIOD, and then send it out through + * the face and/or insert it into the in-memory storage as specified in @p destination. * - * if it's toward the in-memory storage, set its CachePolicy to NO_CACHE and limit - * its FreshnessPeriod in the storage as @p imsFresh + * If it's toward the in-memory storage, set its CachePolicy to NO_CACHE and limit + * its FreshnessPeriod in the storage to @p imsFresh. * * @param dataName the name of this piece of data * @param content the content of this piece of data @@ -399,7 +382,7 @@ class Dispatcher : noncopyable processAuthorizedControlCommandInterest(const std::string& requester, const Name& prefix, const Interest& interest, - const ControlParameters* parameters, + const shared_ptr& parameters, const ValidateParameters& validate, const ControlCommandHandler& handler); @@ -454,59 +437,56 @@ class Dispatcher : noncopyable private: struct TopPrefixEntry { - Name topPrefix; - bool wantRegister; - const ndn::RegisteredPrefixId* registerPrefixId; - std::vector interestFilters; + ScopedRegisteredPrefixHandle registeredPrefix; + std::vector interestFilters; }; std::unordered_map m_topLevelPrefixes; Face& m_face; - security::KeyChain& m_keyChain; + KeyChain& m_keyChain; security::SigningInfo m_signingInfo; - typedef std::unordered_map HandlerMap; - typedef HandlerMap::iterator HandlerMapIt; - HandlerMap m_handlers; + std::unordered_map m_handlers; // NotificationStream name => next sequence number std::unordered_map m_streams; NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: - util::InMemoryStorageFifo m_storage; + InMemoryStorageFifo m_storage; }; template void Dispatcher::addControlCommand(const PartialName& relPrefix, - const Authorization& authorization, - const ValidateParameters& validateParams, - const ControlCommandHandler& handler) + Authorization authorize, + ValidateParameters validate, + ControlCommandHandler handle) { if (!m_topLevelPrefixes.empty()) { - throw std::domain_error("one or more top-level prefix has been added"); + NDN_THROW(std::domain_error("one or more top-level prefix has been added")); } if (isOverlappedWithOthers(relPrefix)) { - throw std::out_of_range("relPrefix overlaps with another relPrefix"); + NDN_THROW(std::out_of_range("relPrefix overlaps with another relPrefix")); } - ControlParametersParser parser = - [] (const name::Component& component) -> shared_ptr { - return make_shared(component.blockFromValue()); + auto parser = [] (const name::Component& comp) -> shared_ptr { + return make_shared(comp.blockFromValue()); }; AuthorizationAcceptedCallback accepted = bind(&Dispatcher::processAuthorizedControlCommandInterest, this, - _1, _2, _3, _4, validateParams, handler); + _1, _2, _3, _4, std::move(validate), std::move(handle)); AuthorizationRejectedCallback rejected = bind(&Dispatcher::afterAuthorizationRejected, this, _1, _2); m_handlers[relPrefix] = bind(&Dispatcher::processControlCommandInterest, this, - _1, relPrefix, _2, parser, authorization, accepted, rejected); + _1, relPrefix, _2, std::move(parser), std::move(authorize), + std::move(accepted), std::move(rejected)); } } // namespace mgmt } // namespace ndn + #endif // NDN_MGMT_DISPATCHER_HPP diff --git a/ndn-cxx/mgmt/nfd/channel-status.cpp b/ndn-cxx/mgmt/nfd/channel-status.cpp new file mode 100644 index 000000000..32d69a152 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/channel-status.cpp @@ -0,0 +1,109 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/channel-status.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/encoding/tlv-nfd.hpp" +#include "ndn-cxx/util/concepts.hpp" + +namespace ndn { +namespace nfd { + +BOOST_CONCEPT_ASSERT((StatusDatasetItem)); + +ChannelStatus::ChannelStatus() = default; + +ChannelStatus::ChannelStatus(const Block& payload) +{ + this->wireDecode(payload); +} + +template +size_t +ChannelStatus::wireEncode(EncodingImpl& encoder) const +{ + size_t totalLength = 0; + totalLength += prependStringBlock(encoder, tlv::nfd::LocalUri, m_localUri); + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::nfd::ChannelStatus); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(ChannelStatus); + +const Block& +ChannelStatus::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 +ChannelStatus::wireDecode(const Block& block) +{ + if (block.type() != tlv::nfd::ChannelStatus) { + NDN_THROW(Error("ChannelStatus", block.type())); + } + + m_wire = block; + m_wire.parse(); + auto val = m_wire.elements_begin(); + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::LocalUri) { + m_localUri = readString(*val); + ++val; + } + else { + NDN_THROW(Error("Missing required LocalUri field")); + } +} + +ChannelStatus& +ChannelStatus::setLocalUri(const std::string localUri) +{ + m_wire.reset(); + m_localUri = localUri; + return *this; +} + +bool +operator==(const ChannelStatus& a, const ChannelStatus& b) +{ + return a.getLocalUri() == b.getLocalUri(); +} + +std::ostream& +operator<<(std::ostream& os, const ChannelStatus& status) +{ + return os << "Channel(LocalUri: " << status.getLocalUri() << ")"; +} + +} // namespace nfd +} // namespace ndn diff --git a/ndn-cxx/mgmt/nfd/channel-status.hpp b/ndn-cxx/mgmt/nfd/channel-status.hpp new file mode 100644 index 000000000..6b5eb8eb9 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/channel-status.hpp @@ -0,0 +1,92 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_MGMT_NFD_CHANNEL_STATUS_HPP +#define NDN_MGMT_NFD_CHANNEL_STATUS_HPP + +#include "ndn-cxx/encoding/block.hpp" + +namespace ndn { +namespace nfd { + +/** + * \ingroup management + * \brief represents an item in NFD Channel dataset + * \sa https://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Channel-Dataset + */ +class ChannelStatus +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + ChannelStatus(); + + explicit + ChannelStatus(const Block& payload); + + template + size_t + wireEncode(EncodingImpl& encoder) const; + + const Block& + wireEncode() const; + + void + wireDecode(const Block& wire); + +public: // getters & setters + const std::string& + getLocalUri() const + { + return m_localUri; + } + + ChannelStatus& + setLocalUri(const std::string localUri); + +private: + std::string m_localUri; + + mutable Block m_wire; +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(ChannelStatus); + +bool +operator==(const ChannelStatus& a, const ChannelStatus& b); + +inline bool +operator!=(const ChannelStatus& a, const ChannelStatus& b) +{ + return !(a == b); +} + +std::ostream& +operator<<(std::ostream& os, const ChannelStatus& status); + +} // namespace nfd +} // namespace ndn + +#endif // NDN_MGMT_NFD_CHANNEL_STATUS_HPP diff --git a/ndn-cxx/mgmt/nfd/command-options.cpp b/ndn-cxx/mgmt/nfd/command-options.cpp new file mode 100644 index 000000000..beeac1615 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/command-options.cpp @@ -0,0 +1,62 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/command-options.hpp" + +namespace ndn { +namespace nfd { + +const time::milliseconds CommandOptions::DEFAULT_TIMEOUT(10000); +const Name CommandOptions::DEFAULT_PREFIX("ndn:/localhost/nfd"); + +CommandOptions::CommandOptions() + : m_timeout(DEFAULT_TIMEOUT) + , m_prefix(DEFAULT_PREFIX) +{ +} + +CommandOptions& +CommandOptions::setTimeout(const time::milliseconds& timeout) +{ + if (timeout <= time::milliseconds::zero()) { + NDN_THROW(std::out_of_range("Timeout must be positive")); + } + + m_timeout = timeout; + return *this; +} + +CommandOptions& +CommandOptions::setPrefix(const Name& prefix) +{ + m_prefix = prefix; + return *this; +} + +CommandOptions& +CommandOptions::setSigningInfo(const security::SigningInfo& signingInfo) +{ + m_signingInfo = signingInfo; + return *this; +} + +} // namespace nfd +} // namespace ndn diff --git a/ndn-cxx/mgmt/nfd/command-options.hpp b/ndn-cxx/mgmt/nfd/command-options.hpp new file mode 100644 index 000000000..ca02a963c --- /dev/null +++ b/ndn-cxx/mgmt/nfd/command-options.hpp @@ -0,0 +1,106 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_MGMT_NFD_COMMAND_OPTIONS_HPP +#define NDN_MGMT_NFD_COMMAND_OPTIONS_HPP + +#include "ndn-cxx/security/signing-info.hpp" + +namespace ndn { +namespace nfd { + +/** \ingroup management + * \brief contains options for ControlCommand execution + * \note This type is intentionally copyable + */ +class CommandOptions +{ +public: + /** \brief constructs CommandOptions + * \post getTimeout() == DEFAULT_TIMEOUT + * \post getPrefix() == DEFAULT_PREFIX + * \post getSigningInfo().getSignerType() == SIGNER_TYPE_NULL + */ + CommandOptions(); + + /** \return command timeout + */ + const time::milliseconds& + getTimeout() const + { + return m_timeout; + } + + /** \brief sets command timeout + * \param timeout the new command timeout, must be positive + * \throw std::out_of_range if timeout is non-positive + * \return self + */ + CommandOptions& + setTimeout(const time::milliseconds& timeout); + + /** \return command prefix + */ + const Name& + getPrefix() const + { + return m_prefix; + } + + /** \brief sets command prefix + * \return self + */ + CommandOptions& + setPrefix(const Name& prefix); + + /** \return signing parameters + */ + const security::SigningInfo& + getSigningInfo() const + { + return m_signingInfo; + } + + /** \brief sets signing parameters + * \return self + */ + CommandOptions& + setSigningInfo(const security::SigningInfo& signingInfo); + +public: + /** \brief gives the default command timeout: 10000ms + */ + static const time::milliseconds DEFAULT_TIMEOUT; + + /** \brief gives the default command prefix: ndn:/localhost/nfd + */ + static const Name DEFAULT_PREFIX; + +private: + time::milliseconds m_timeout; + Name m_prefix; + security::SigningInfo m_signingInfo; +}; + +} // namespace nfd +} // namespace ndn + +#endif // NDN_MGMT_NFD_COMMAND_OPTIONS_HPP diff --git a/ndn-cxx/mgmt/nfd/control-command.cpp b/ndn-cxx/mgmt/nfd/control-command.cpp new file mode 100644 index 000000000..86ca50053 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/control-command.cpp @@ -0,0 +1,421 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/control-command.hpp" + +namespace ndn { +namespace nfd { + +ControlCommand::ControlCommand(const std::string& module, const std::string& verb) + : m_module(module) + , m_verb(verb) +{ +} + +ControlCommand::~ControlCommand() = default; + +void +ControlCommand::validateRequest(const ControlParameters& parameters) const +{ + m_requestValidator.validate(parameters); +} + +void +ControlCommand::applyDefaultsToRequest(ControlParameters& parameters) const +{ +} + +void +ControlCommand::validateResponse(const ControlParameters& parameters) const +{ + m_responseValidator.validate(parameters); +} + +void +ControlCommand::applyDefaultsToResponse(ControlParameters& parameters) const +{ +} + +Name +ControlCommand::getRequestName(const Name& commandPrefix, + const ControlParameters& parameters) const +{ + this->validateRequest(parameters); + + Name name = commandPrefix; + name.append(m_module).append(m_verb); + name.append(parameters.wireEncode()); + return name; +} + +ControlCommand::FieldValidator::FieldValidator() + : m_required(CONTROL_PARAMETER_UBOUND) + , m_optional(CONTROL_PARAMETER_UBOUND) +{ +} + +void +ControlCommand::FieldValidator::validate(const ControlParameters& parameters) const +{ + const std::vector& presentFields = parameters.getPresentFields(); + + for (size_t i = 0; i < CONTROL_PARAMETER_UBOUND; ++i) { + bool isPresent = presentFields[i]; + if (m_required[i]) { + if (!isPresent) { + NDN_THROW(ArgumentError(CONTROL_PARAMETER_FIELD[i] + " is required but missing")); + } + } + else if (isPresent && !m_optional[i]) { + NDN_THROW(ArgumentError(CONTROL_PARAMETER_FIELD[i] + " is forbidden but present")); + } + } + + if (m_optional[CONTROL_PARAMETER_FLAGS] && m_optional[CONTROL_PARAMETER_MASK]) { + if (parameters.hasFlags() != parameters.hasMask()) { + NDN_THROW(ArgumentError("Flags must be accompanied by Mask")); + } + } +} + +FaceCreateCommand::FaceCreateCommand() + : ControlCommand("faces", "create") +{ + m_requestValidator + .required(CONTROL_PARAMETER_URI) + .optional(CONTROL_PARAMETER_LOCAL_URI) + .optional(CONTROL_PARAMETER_FACE_PERSISTENCY) + .optional(CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL) + .optional(CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD) + .optional(CONTROL_PARAMETER_MTU) + .optional(CONTROL_PARAMETER_FLAGS) + .optional(CONTROL_PARAMETER_MASK); + m_responseValidator + .required(CONTROL_PARAMETER_FACE_ID) + .required(CONTROL_PARAMETER_URI) + .required(CONTROL_PARAMETER_LOCAL_URI) + .required(CONTROL_PARAMETER_FACE_PERSISTENCY) + .optional(CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL) + .optional(CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD) + .optional(CONTROL_PARAMETER_MTU) + .required(CONTROL_PARAMETER_FLAGS); +} + +void +FaceCreateCommand::applyDefaultsToRequest(ControlParameters& parameters) const +{ + if (!parameters.hasFacePersistency()) { + parameters.setFacePersistency(FacePersistency::FACE_PERSISTENCY_PERSISTENT); + } +} + +void +FaceCreateCommand::validateResponse(const ControlParameters& parameters) const +{ + this->ControlCommand::validateResponse(parameters); + + if (parameters.getFaceId() == INVALID_FACE_ID) { + NDN_THROW(ArgumentError("FaceId must be valid")); + } +} + +FaceUpdateCommand::FaceUpdateCommand() + : ControlCommand("faces", "update") +{ + m_requestValidator + .optional(CONTROL_PARAMETER_FACE_ID) + .optional(CONTROL_PARAMETER_FACE_PERSISTENCY) + .optional(CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL) + .optional(CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD) + .optional(CONTROL_PARAMETER_FLAGS) + .optional(CONTROL_PARAMETER_MASK); + m_responseValidator + .required(CONTROL_PARAMETER_FACE_ID) + .required(CONTROL_PARAMETER_FACE_PERSISTENCY) + .optional(CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL) + .optional(CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD) + .required(CONTROL_PARAMETER_FLAGS); +} + +void +FaceUpdateCommand::applyDefaultsToRequest(ControlParameters& parameters) const +{ + if (!parameters.hasFaceId()) { + parameters.setFaceId(0); + } +} + +void +FaceUpdateCommand::validateResponse(const ControlParameters& parameters) const +{ + this->ControlCommand::validateResponse(parameters); + + if (parameters.getFaceId() == INVALID_FACE_ID) { + NDN_THROW(ArgumentError("FaceId must be valid")); + } +} + +FaceDestroyCommand::FaceDestroyCommand() + : ControlCommand("faces", "destroy") +{ + m_requestValidator + .required(CONTROL_PARAMETER_FACE_ID); + m_responseValidator = m_requestValidator; +} + +void +FaceDestroyCommand::validateRequest(const ControlParameters& parameters) const +{ + this->ControlCommand::validateRequest(parameters); + + if (parameters.getFaceId() == INVALID_FACE_ID) { + NDN_THROW(ArgumentError("FaceId must be valid")); + } +} + +void +FaceDestroyCommand::validateResponse(const ControlParameters& parameters) const +{ + this->validateRequest(parameters); +} + +FibAddNextHopCommand::FibAddNextHopCommand() + : ControlCommand("fib", "add-nexthop") +{ + m_requestValidator + .required(CONTROL_PARAMETER_NAME) + .optional(CONTROL_PARAMETER_FACE_ID) + .optional(CONTROL_PARAMETER_COST); + m_responseValidator + .required(CONTROL_PARAMETER_NAME) + .required(CONTROL_PARAMETER_FACE_ID) + .required(CONTROL_PARAMETER_COST); +} + +void +FibAddNextHopCommand::applyDefaultsToRequest(ControlParameters& parameters) const +{ + if (!parameters.hasFaceId()) { + parameters.setFaceId(0); + } + if (!parameters.hasCost()) { + parameters.setCost(0); + } +} + +void +FibAddNextHopCommand::validateResponse(const ControlParameters& parameters) const +{ + this->ControlCommand::validateResponse(parameters); + + if (parameters.getFaceId() == INVALID_FACE_ID) { + NDN_THROW(ArgumentError("FaceId must be valid")); + } +} + +FibRemoveNextHopCommand::FibRemoveNextHopCommand() + : ControlCommand("fib", "remove-nexthop") +{ + m_requestValidator + .required(CONTROL_PARAMETER_NAME) + .optional(CONTROL_PARAMETER_FACE_ID); + m_responseValidator + .required(CONTROL_PARAMETER_NAME) + .required(CONTROL_PARAMETER_FACE_ID); +} + +void +FibRemoveNextHopCommand::applyDefaultsToRequest(ControlParameters& parameters) const +{ + if (!parameters.hasFaceId()) { + parameters.setFaceId(0); + } +} + +void +FibRemoveNextHopCommand::validateResponse(const ControlParameters& parameters) const +{ + this->ControlCommand::validateResponse(parameters); + + if (parameters.getFaceId() == INVALID_FACE_ID) { + NDN_THROW(ArgumentError("FaceId must be valid")); + } +} + +CsConfigCommand::CsConfigCommand() + : ControlCommand("cs", "config") +{ + m_requestValidator + .optional(CONTROL_PARAMETER_CAPACITY) + .optional(CONTROL_PARAMETER_FLAGS) + .optional(CONTROL_PARAMETER_MASK); + m_responseValidator + .required(CONTROL_PARAMETER_CAPACITY) + .required(CONTROL_PARAMETER_FLAGS); +} + +CsEraseCommand::CsEraseCommand() + : ControlCommand("cs", "erase") +{ + m_requestValidator + .required(CONTROL_PARAMETER_NAME) + .optional(CONTROL_PARAMETER_COUNT); + m_responseValidator + .required(CONTROL_PARAMETER_NAME) + .optional(CONTROL_PARAMETER_CAPACITY) + .required(CONTROL_PARAMETER_COUNT); +} + +void +CsEraseCommand::validateRequest(const ControlParameters& parameters) const +{ + this->ControlCommand::validateRequest(parameters); + + if (parameters.hasCount() && parameters.getCount() == 0) { + NDN_THROW(ArgumentError("Count must be positive")); + } +} + +void +CsEraseCommand::validateResponse(const ControlParameters& parameters) const +{ + this->ControlCommand::validateResponse(parameters); + + if (parameters.hasCapacity() && parameters.getCapacity() == 0) { + NDN_THROW(ArgumentError("Capacity must be positive")); + } +} + +StrategyChoiceSetCommand::StrategyChoiceSetCommand() + : ControlCommand("strategy-choice", "set") +{ + m_requestValidator + .required(CONTROL_PARAMETER_NAME) + .required(CONTROL_PARAMETER_STRATEGY); + m_responseValidator = m_requestValidator; +} + +StrategyChoiceUnsetCommand::StrategyChoiceUnsetCommand() + : ControlCommand("strategy-choice", "unset") +{ + m_requestValidator + .required(CONTROL_PARAMETER_NAME); + m_responseValidator = m_requestValidator; +} + +void +StrategyChoiceUnsetCommand::validateRequest(const ControlParameters& parameters) const +{ + this->ControlCommand::validateRequest(parameters); + + if (parameters.getName().size() == 0) { + NDN_THROW(ArgumentError("Name must not be ndn:/")); + } +} + +void +StrategyChoiceUnsetCommand::validateResponse(const ControlParameters& parameters) const +{ + this->validateRequest(parameters); +} + +RibRegisterCommand::RibRegisterCommand() + : ControlCommand("rib", "register") +{ + m_requestValidator + .required(CONTROL_PARAMETER_NAME) + .optional(CONTROL_PARAMETER_FACE_ID) + .optional(CONTROL_PARAMETER_ORIGIN) + .optional(CONTROL_PARAMETER_COST) + .optional(CONTROL_PARAMETER_FLAGS) + .optional(CONTROL_PARAMETER_EXPIRATION_PERIOD); + m_responseValidator + .required(CONTROL_PARAMETER_NAME) + .required(CONTROL_PARAMETER_FACE_ID) + .required(CONTROL_PARAMETER_ORIGIN) + .required(CONTROL_PARAMETER_COST) + .required(CONTROL_PARAMETER_FLAGS) + .optional(CONTROL_PARAMETER_EXPIRATION_PERIOD); +} + +void +RibRegisterCommand::applyDefaultsToRequest(ControlParameters& parameters) const +{ + if (!parameters.hasFaceId()) { + parameters.setFaceId(0); + } + if (!parameters.hasOrigin()) { + parameters.setOrigin(ROUTE_ORIGIN_APP); + } + if (!parameters.hasCost()) { + parameters.setCost(0); + } + if (!parameters.hasFlags()) { + parameters.setFlags(ROUTE_FLAG_CHILD_INHERIT); + } +} + +void +RibRegisterCommand::validateResponse(const ControlParameters& parameters) const +{ + this->ControlCommand::validateResponse(parameters); + + if (parameters.getFaceId() == INVALID_FACE_ID) { + NDN_THROW(ArgumentError("FaceId must be valid")); + } +} + +RibUnregisterCommand::RibUnregisterCommand() + : ControlCommand("rib", "unregister") +{ + m_requestValidator + .required(CONTROL_PARAMETER_NAME) + .optional(CONTROL_PARAMETER_FACE_ID) + .optional(CONTROL_PARAMETER_ORIGIN); + m_responseValidator + .required(CONTROL_PARAMETER_NAME) + .required(CONTROL_PARAMETER_FACE_ID) + .required(CONTROL_PARAMETER_ORIGIN); +} + +void +RibUnregisterCommand::applyDefaultsToRequest(ControlParameters& parameters) const +{ + if (!parameters.hasFaceId()) { + parameters.setFaceId(0); + } + if (!parameters.hasOrigin()) { + parameters.setOrigin(ROUTE_ORIGIN_APP); + } +} + +void +RibUnregisterCommand::validateResponse(const ControlParameters& parameters) const +{ + this->ControlCommand::validateResponse(parameters); + + if (parameters.getFaceId() == INVALID_FACE_ID) { + NDN_THROW(ArgumentError("FaceId must be valid")); + } +} + +} // namespace nfd +} // namespace ndn diff --git a/src/mgmt/nfd/control-command.hpp b/ndn-cxx/mgmt/nfd/control-command.hpp similarity index 75% rename from src/mgmt/nfd/control-command.hpp rename to ndn-cxx/mgmt/nfd/control-command.hpp index 75441567f..054e000c7 100644 --- a/src/mgmt/nfd/control-command.hpp +++ b/ndn-cxx/mgmt/nfd/control-command.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,7 +22,7 @@ #ifndef NDN_MGMT_NFD_CONTROL_COMMAND_HPP #define NDN_MGMT_NFD_CONTROL_COMMAND_HPP -#include "control-parameters.hpp" +#include "ndn-cxx/mgmt/nfd/control-parameters.hpp" namespace ndn { namespace nfd { @@ -30,7 +30,7 @@ namespace nfd { /** * \ingroup management * \brief base class of NFD ControlCommand - * \sa http://redmine.named-data.net/projects/nfd/wiki/ControlCommand + * \sa https://redmine.named-data.net/projects/nfd/wiki/ControlCommand */ class ControlCommand : noncopyable { @@ -137,20 +137,17 @@ class ControlCommand : noncopyable /** * \ingroup management * \brief represents a faces/create command - * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Create-a-face + * \sa https://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Create-a-face */ class FaceCreateCommand : public ControlCommand { public: FaceCreateCommand(); - virtual void + void applyDefaultsToRequest(ControlParameters& parameters) const override; - virtual void - validateRequest(const ControlParameters& parameters) const override; - - virtual void + void validateResponse(const ControlParameters& parameters) const override; }; @@ -158,24 +155,21 @@ class FaceCreateCommand : public ControlCommand /** * \ingroup management * \brief represents a faces/update command - * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Update-a-face + * \sa https://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Update-the-static-properties-of-a-face */ class FaceUpdateCommand : public ControlCommand { public: FaceUpdateCommand(); - virtual void + void applyDefaultsToRequest(ControlParameters& parameters) const override; - virtual void - validateRequest(const ControlParameters& parameters) const override; - /** * \note This can only validate ControlParameters in a success response. * Failure responses should be validated with validateRequest. */ - virtual void + void validateResponse(const ControlParameters& parameters) const override; }; @@ -183,96 +177,83 @@ class FaceUpdateCommand : public ControlCommand /** * \ingroup management * \brief represents a faces/destroy command - * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Destroy-a-face + * \sa https://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Destroy-a-face */ class FaceDestroyCommand : public ControlCommand { public: FaceDestroyCommand(); - virtual void + void validateRequest(const ControlParameters& parameters) const override; - virtual void + void validateResponse(const ControlParameters& parameters) const override; }; /** * \ingroup management - * \brief Base class for faces/[*]-local-control commands + * \brief represents a fib/add-nexthop command + * \sa https://redmine.named-data.net/projects/nfd/wiki/FibMgmt#Add-a-nexthop */ -class FaceLocalControlCommand : public ControlCommand +class FibAddNextHopCommand : public ControlCommand { public: - virtual void - validateRequest(const ControlParameters& parameters) const override; + FibAddNextHopCommand(); - virtual void - validateResponse(const ControlParameters& parameters) const override; + void + applyDefaultsToRequest(ControlParameters& parameters) const override; -protected: - explicit - FaceLocalControlCommand(const std::string& verb); + void + validateResponse(const ControlParameters& parameters) const override; }; /** * \ingroup management - * \brief represents a faces/enable-local-control command - * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Enable-a-LocalControlHeader-feature + * \brief represents a fib/remove-nexthop command + * \sa https://redmine.named-data.net/projects/nfd/wiki/FibMgmt#Remove-a-nexthop */ -class FaceEnableLocalControlCommand : public FaceLocalControlCommand +class FibRemoveNextHopCommand : public ControlCommand { public: - FaceEnableLocalControlCommand(); -}; + FibRemoveNextHopCommand(); + void + applyDefaultsToRequest(ControlParameters& parameters) const override; -/** - * \ingroup management - * \brief represents a faces/disable-local-control command - * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Disable-a-LocalControlHeader-feature - */ -class FaceDisableLocalControlCommand : public FaceLocalControlCommand -{ -public: - FaceDisableLocalControlCommand(); + void + validateResponse(const ControlParameters& parameters) const override; }; /** * \ingroup management - * \brief represents a fib/add-nexthop command - * \sa http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#Add-a-nexthop + * \brief represents a cs/config command + * \sa https://redmine.named-data.net/projects/nfd/wiki/CsMgmt#Update-configuration */ -class FibAddNextHopCommand : public ControlCommand +class CsConfigCommand : public ControlCommand { public: - FibAddNextHopCommand(); - - virtual void - applyDefaultsToRequest(ControlParameters& parameters) const override; - - virtual void - validateResponse(const ControlParameters& parameters) const override; + CsConfigCommand(); }; /** * \ingroup management - * \brief represents a fib/remove-nexthop command - * \sa http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#Remove-a-nexthop + * \brief represents a cs/erase command + * \sa https://redmine.named-data.net/projects/nfd/wiki/CsMgmt#Erase-entries */ -class FibRemoveNextHopCommand : public ControlCommand +class CsEraseCommand : public ControlCommand { public: - FibRemoveNextHopCommand(); + CsEraseCommand(); - virtual void - applyDefaultsToRequest(ControlParameters& parameters) const override; + void + validateRequest(const ControlParameters& parameters) const override; - virtual void + void validateResponse(const ControlParameters& parameters) const override; }; @@ -280,7 +261,7 @@ class FibRemoveNextHopCommand : public ControlCommand /** * \ingroup management * \brief represents a strategy-choice/set command - * \sa http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Set-the-strategy-for-a-namespace + * \sa https://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Set-the-strategy-for-a-namespace */ class StrategyChoiceSetCommand : public ControlCommand { @@ -292,17 +273,17 @@ class StrategyChoiceSetCommand : public ControlCommand /** * \ingroup management * \brief represents a strategy-choice/set command - * \sa http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Unset-the-strategy-for-a-namespace + * \sa https://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Unset-the-strategy-for-a-namespace */ class StrategyChoiceUnsetCommand : public ControlCommand { public: StrategyChoiceUnsetCommand(); - virtual void + void validateRequest(const ControlParameters& parameters) const override; - virtual void + void validateResponse(const ControlParameters& parameters) const override; }; @@ -310,17 +291,17 @@ class StrategyChoiceUnsetCommand : public ControlCommand /** * \ingroup management * \brief represents a rib/register command - * \sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Register-a-route + * \sa https://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Register-a-route */ class RibRegisterCommand : public ControlCommand { public: RibRegisterCommand(); - virtual void + void applyDefaultsToRequest(ControlParameters& parameters) const override; - virtual void + void validateResponse(const ControlParameters& parameters) const override; }; @@ -328,17 +309,17 @@ class RibRegisterCommand : public ControlCommand /** * \ingroup management * \brief represents a rib/unregister command - * \sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Unregister-a-route + * \sa https://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Unregister-a-route */ class RibUnregisterCommand : public ControlCommand { public: RibUnregisterCommand(); - virtual void + void applyDefaultsToRequest(ControlParameters& parameters) const override; - virtual void + void validateResponse(const ControlParameters& parameters) const override; }; diff --git a/ndn-cxx/mgmt/nfd/control-parameters.cpp b/ndn-cxx/mgmt/nfd/control-parameters.cpp new file mode 100644 index 000000000..6c8f0918c --- /dev/null +++ b/ndn-cxx/mgmt/nfd/control-parameters.cpp @@ -0,0 +1,390 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/control-parameters.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/encoding/tlv-nfd.hpp" +#include "ndn-cxx/util/concepts.hpp" +#include "ndn-cxx/util/string-helper.hpp" + +namespace ndn { +namespace nfd { + +//BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); +BOOST_CONCEPT_ASSERT((WireEncodable)); +BOOST_CONCEPT_ASSERT((WireDecodable)); +static_assert(std::is_base_of::value, + "ControlParameters::Error must inherit from tlv::Error"); + +ControlParameters::ControlParameters() + : m_hasFields(CONTROL_PARAMETER_UBOUND) +{ +} + +ControlParameters::ControlParameters(const Block& block) + : m_hasFields(CONTROL_PARAMETER_UBOUND) +{ + wireDecode(block); +} + +template +size_t +ControlParameters::wireEncode(EncodingImpl& encoder) const +{ + size_t totalLength = 0; + + if (this->hasMtu()) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Mtu, m_mtu); + } + if (this->hasDefaultCongestionThreshold()) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::DefaultCongestionThreshold, + m_defaultCongestionThreshold); + } + if (this->hasBaseCongestionMarkingInterval()) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::BaseCongestionMarkingInterval, + m_baseCongestionMarkingInterval.count()); + } + if (this->hasFacePersistency()) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::FacePersistency, m_facePersistency); + } + if (this->hasExpirationPeriod()) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::ExpirationPeriod, + m_expirationPeriod.count()); + } + if (this->hasStrategy()) { + totalLength += prependNestedBlock(encoder, tlv::nfd::Strategy, m_strategy); + } + if (this->hasMask()) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Mask, m_mask); + } + if (this->hasFlags()) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Flags, m_flags); + } + if (this->hasCount()) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Count, m_count); + } + if (this->hasCapacity()) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Capacity, m_capacity); + } + if (this->hasCost()) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Cost, m_cost); + } + if (this->hasOrigin()) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Origin, m_origin); + } + if (this->hasLocalUri()) { + totalLength += prependStringBlock(encoder, tlv::nfd::LocalUri, m_localUri); + } + if (this->hasUri()) { + totalLength += prependStringBlock(encoder, tlv::nfd::Uri, m_uri); + } + if (this->hasFaceId()) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::FaceId, m_faceId); + } + if (this->hasName()) { + totalLength += m_name.wireEncode(encoder); + } + + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::nfd::ControlParameters); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(ControlParameters); + +Block +ControlParameters::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 +ControlParameters::wireDecode(const Block& block) +{ + if (block.type() != tlv::nfd::ControlParameters) { + NDN_THROW(Error("ControlParameters", block.type())); + } + + m_wire = block; + m_wire.parse(); + Block::element_const_iterator val; + + val = m_wire.find(tlv::Name); + m_hasFields[CONTROL_PARAMETER_NAME] = val != m_wire.elements_end(); + if (this->hasName()) { + m_name.wireDecode(*val); + } + + val = m_wire.find(tlv::nfd::FaceId); + m_hasFields[CONTROL_PARAMETER_FACE_ID] = val != m_wire.elements_end(); + if (this->hasFaceId()) { + m_faceId = readNonNegativeInteger(*val); + } + + val = m_wire.find(tlv::nfd::Uri); + m_hasFields[CONTROL_PARAMETER_URI] = val != m_wire.elements_end(); + if (this->hasUri()) { + m_uri = readString(*val); + } + + val = m_wire.find(tlv::nfd::LocalUri); + m_hasFields[CONTROL_PARAMETER_LOCAL_URI] = val != m_wire.elements_end(); + if (this->hasLocalUri()) { + m_localUri = readString(*val); + } + + val = m_wire.find(tlv::nfd::Origin); + m_hasFields[CONTROL_PARAMETER_ORIGIN] = val != m_wire.elements_end(); + if (this->hasOrigin()) { + m_origin = readNonNegativeIntegerAs(*val); + } + + val = m_wire.find(tlv::nfd::Cost); + m_hasFields[CONTROL_PARAMETER_COST] = val != m_wire.elements_end(); + if (this->hasCost()) { + m_cost = readNonNegativeInteger(*val); + } + + val = m_wire.find(tlv::nfd::Capacity); + m_hasFields[CONTROL_PARAMETER_CAPACITY] = val != m_wire.elements_end(); + if (this->hasCapacity()) { + m_capacity = readNonNegativeInteger(*val); + } + + val = m_wire.find(tlv::nfd::Count); + m_hasFields[CONTROL_PARAMETER_COUNT] = val != m_wire.elements_end(); + if (this->hasCount()) { + m_count = readNonNegativeInteger(*val); + } + + val = m_wire.find(tlv::nfd::Flags); + m_hasFields[CONTROL_PARAMETER_FLAGS] = val != m_wire.elements_end(); + if (this->hasFlags()) { + m_flags = readNonNegativeInteger(*val); + } + + val = m_wire.find(tlv::nfd::Mask); + m_hasFields[CONTROL_PARAMETER_MASK] = val != m_wire.elements_end(); + if (this->hasMask()) { + m_mask = readNonNegativeInteger(*val); + } + + val = m_wire.find(tlv::nfd::Strategy); + m_hasFields[CONTROL_PARAMETER_STRATEGY] = val != m_wire.elements_end(); + if (this->hasStrategy()) { + val->parse(); + if (val->elements().empty()) { + NDN_THROW(Error("Expecting Strategy/Name")); + } + else { + m_strategy.wireDecode(*val->elements_begin()); + } + } + + val = m_wire.find(tlv::nfd::ExpirationPeriod); + m_hasFields[CONTROL_PARAMETER_EXPIRATION_PERIOD] = val != m_wire.elements_end(); + if (this->hasExpirationPeriod()) { + m_expirationPeriod = time::milliseconds(readNonNegativeInteger(*val)); + } + + val = m_wire.find(tlv::nfd::FacePersistency); + m_hasFields[CONTROL_PARAMETER_FACE_PERSISTENCY] = val != m_wire.elements_end(); + if (this->hasFacePersistency()) { + m_facePersistency = readNonNegativeIntegerAs(*val); + } + + val = m_wire.find(tlv::nfd::BaseCongestionMarkingInterval); + m_hasFields[CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL] = val != m_wire.elements_end(); + if (this->hasBaseCongestionMarkingInterval()) { + m_baseCongestionMarkingInterval = time::nanoseconds(readNonNegativeInteger(*val)); + } + + val = m_wire.find(tlv::nfd::DefaultCongestionThreshold); + m_hasFields[CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD] = val != m_wire.elements_end(); + if (this->hasDefaultCongestionThreshold()) { + m_defaultCongestionThreshold = readNonNegativeInteger(*val); + } + + val = m_wire.find(tlv::nfd::Mtu); + m_hasFields[CONTROL_PARAMETER_MTU] = val != m_wire.elements_end(); + if (this->hasMtu()) { + m_mtu = readNonNegativeInteger(*val); + } +} + +bool +ControlParameters::hasFlagBit(size_t bit) const +{ + if (bit >= 64) { + NDN_THROW(std::out_of_range("bit must be within range [0, 64)")); + } + + if (!hasMask()) { + return false; + } + + return getMask() & (1 << bit); +} + +bool +ControlParameters::getFlagBit(size_t bit) const +{ + if (bit >= 64) { + NDN_THROW(std::out_of_range("bit must be within range [0, 64)")); + } + + if (!hasFlags()) { + return false; + } + + return getFlags() & (1 << bit); +} + +ControlParameters& +ControlParameters::setFlagBit(size_t bit, bool value, bool wantMask/* = true*/) +{ + if (bit >= 64) { + NDN_THROW(std::out_of_range("bit must be within range [0, 64)")); + } + + uint64_t flags = hasFlags() ? getFlags() : 0; + if (value) { + flags |= (1 << bit); + } + else { + flags &= ~(1 << bit); + } + setFlags(flags); + + if (wantMask) { + uint64_t mask = hasMask() ? getMask() : 0; + mask |= (1 << bit); + setMask(mask); + } + + return *this; +} + +ControlParameters& +ControlParameters::unsetFlagBit(size_t bit) +{ + if (bit >= 64) { + NDN_THROW(std::out_of_range("bit must be within range [0, 64)")); + } + + uint64_t mask = hasMask() ? getMask() : 0; + mask &= ~(1 << bit); + if (mask == 0) { + unsetMask(); + unsetFlags(); + } + else { + setMask(mask); + } + + return *this; +} + +std::ostream& +operator<<(std::ostream& os, const ControlParameters& parameters) +{ + os << "ControlParameters("; + + if (parameters.hasName()) { + os << "Name: " << parameters.getName() << ", "; + } + + if (parameters.hasFaceId()) { + os << "FaceId: " << parameters.getFaceId() << ", "; + } + + if (parameters.hasUri()) { + os << "Uri: " << parameters.getUri() << ", "; + } + + if (parameters.hasLocalUri()) { + os << "LocalUri: " << parameters.getLocalUri() << ", "; + } + + if (parameters.hasOrigin()) { + os << "Origin: " << parameters.getOrigin() << ", "; + } + + if (parameters.hasCost()) { + os << "Cost: " << parameters.getCost() << ", "; + } + + if (parameters.hasCapacity()) { + os << "Capacity: " << parameters.getCapacity() << ", "; + } + + if (parameters.hasCount()) { + os << "Count: " << parameters.getCount() << ", "; + } + + if (parameters.hasFlags()) { + os << "Flags: " << AsHex{parameters.getFlags()} << ", "; + } + + if (parameters.hasMask()) { + os << "Mask: " << AsHex{parameters.getMask()} << ", "; + } + + if (parameters.hasStrategy()) { + os << "Strategy: " << parameters.getStrategy() << ", "; + } + + if (parameters.hasExpirationPeriod()) { + os << "ExpirationPeriod: " << parameters.getExpirationPeriod() << ", "; + } + + if (parameters.hasFacePersistency()) { + os << "FacePersistency: " << parameters.getFacePersistency() << ", "; + } + + if (parameters.hasBaseCongestionMarkingInterval()) { + os << "BaseCongestionMarkingInterval: " << parameters.getBaseCongestionMarkingInterval() << ", "; + } + + if (parameters.hasDefaultCongestionThreshold()) { + os << "DefaultCongestionThreshold: " << parameters.getDefaultCongestionThreshold() << ", "; + } + + if (parameters.hasMtu()) { + os << "Mtu: " << parameters.getMtu() << ", "; + } + + os << ")"; + return os; +} + +} // namespace nfd +} // namespace ndn diff --git a/ndn-cxx/mgmt/nfd/control-parameters.hpp b/ndn-cxx/mgmt/nfd/control-parameters.hpp new file mode 100644 index 000000000..d23cc2794 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/control-parameters.hpp @@ -0,0 +1,668 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_MGMT_NFD_CONTROL_PARAMETERS_HPP +#define NDN_MGMT_NFD_CONTROL_PARAMETERS_HPP + +#include "ndn-cxx/name.hpp" +#include "ndn-cxx/encoding/nfd-constants.hpp" +#include "ndn-cxx/mgmt/control-parameters.hpp" +#include "ndn-cxx/util/time.hpp" + +namespace ndn { +namespace nfd { + +/** + * \ingroup management + */ +enum ControlParameterField { + CONTROL_PARAMETER_NAME, + CONTROL_PARAMETER_FACE_ID, + CONTROL_PARAMETER_URI, + CONTROL_PARAMETER_LOCAL_URI, + CONTROL_PARAMETER_ORIGIN, + CONTROL_PARAMETER_COST, + CONTROL_PARAMETER_CAPACITY, + CONTROL_PARAMETER_COUNT, + CONTROL_PARAMETER_FLAGS, + CONTROL_PARAMETER_MASK, + CONTROL_PARAMETER_STRATEGY, + CONTROL_PARAMETER_EXPIRATION_PERIOD, + CONTROL_PARAMETER_FACE_PERSISTENCY, + CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL, + CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD, + CONTROL_PARAMETER_MTU, + CONTROL_PARAMETER_UBOUND +}; + +const std::string CONTROL_PARAMETER_FIELD[CONTROL_PARAMETER_UBOUND] = { + "Name", + "FaceId", + "Uri", + "LocalUri", + "Origin", + "Cost", + "Capacity", + "Count", + "Flags", + "Mask", + "Strategy", + "ExpirationPeriod", + "FacePersistency", + "BaseCongestionMarkingInterval", + "DefaultCongestionThreshold", + "Mtu" +}; + +/** + * \ingroup management + * \brief represents parameters in a ControlCommand request or response + * \sa https://redmine.named-data.net/projects/nfd/wiki/ControlCommand#ControlParameters + * \details This type is copyable because it's an abstraction of a TLV type. + */ +class ControlParameters : public mgmt::ControlParameters +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + ControlParameters(); + + explicit + ControlParameters(const Block& block); + + template + size_t + wireEncode(EncodingImpl& encoder) const; + + Block + wireEncode() const final; + + void + wireDecode(const Block& wire) final; + +public: // getters & setters + bool + hasName() const + { + return m_hasFields[CONTROL_PARAMETER_NAME]; + } + + const Name& + getName() const + { + BOOST_ASSERT(this->hasName()); + return m_name; + } + + ControlParameters& + setName(const Name& name) + { + m_wire.reset(); + m_name = name; + m_hasFields[CONTROL_PARAMETER_NAME] = true; + return *this; + } + + ControlParameters& + unsetName() + { + m_wire.reset(); + m_hasFields[CONTROL_PARAMETER_NAME] = false; + return *this; + } + + bool + hasFaceId() const + { + return m_hasFields[CONTROL_PARAMETER_FACE_ID]; + } + + uint64_t + getFaceId() const + { + BOOST_ASSERT(this->hasFaceId()); + return m_faceId; + } + + ControlParameters& + setFaceId(uint64_t faceId) + { + m_wire.reset(); + m_faceId = faceId; + m_hasFields[CONTROL_PARAMETER_FACE_ID] = true; + return *this; + } + + ControlParameters& + unsetFaceId() + { + m_wire.reset(); + m_hasFields[CONTROL_PARAMETER_FACE_ID] = false; + return *this; + } + + bool + hasUri() const + { + return m_hasFields[CONTROL_PARAMETER_URI]; + } + + const std::string& + getUri() const + { + BOOST_ASSERT(this->hasUri()); + return m_uri; + } + + ControlParameters& + setUri(const std::string& uri) + { + m_wire.reset(); + m_uri = uri; + m_hasFields[CONTROL_PARAMETER_URI] = true; + return *this; + } + + ControlParameters& + unsetUri() + { + m_wire.reset(); + m_hasFields[CONTROL_PARAMETER_URI] = false; + return *this; + } + + bool + hasLocalUri() const + { + return m_hasFields[CONTROL_PARAMETER_LOCAL_URI]; + } + + const std::string& + getLocalUri() const + { + BOOST_ASSERT(this->hasLocalUri()); + return m_localUri; + } + + ControlParameters& + setLocalUri(const std::string& localUri) + { + m_wire.reset(); + m_localUri = localUri; + m_hasFields[CONTROL_PARAMETER_LOCAL_URI] = true; + return *this; + } + + ControlParameters& + unsetLocalUri() + { + m_wire.reset(); + m_hasFields[CONTROL_PARAMETER_LOCAL_URI] = false; + return *this; + } + + bool + hasOrigin() const + { + return m_hasFields[CONTROL_PARAMETER_ORIGIN]; + } + + RouteOrigin + getOrigin() const + { + BOOST_ASSERT(this->hasOrigin()); + return m_origin; + } + + ControlParameters& + setOrigin(RouteOrigin origin) + { + m_wire.reset(); + m_origin = origin; + m_hasFields[CONTROL_PARAMETER_ORIGIN] = true; + return *this; + } + + ControlParameters& + unsetOrigin() + { + m_wire.reset(); + m_hasFields[CONTROL_PARAMETER_ORIGIN] = false; + return *this; + } + + bool + hasCost() const + { + return m_hasFields[CONTROL_PARAMETER_COST]; + } + + uint64_t + getCost() const + { + BOOST_ASSERT(this->hasCost()); + return m_cost; + } + + ControlParameters& + setCost(uint64_t cost) + { + m_wire.reset(); + m_cost = cost; + m_hasFields[CONTROL_PARAMETER_COST] = true; + return *this; + } + + ControlParameters& + unsetCost() + { + m_wire.reset(); + m_hasFields[CONTROL_PARAMETER_COST] = false; + return *this; + } + + bool + hasCapacity() const + { + return m_hasFields[CONTROL_PARAMETER_CAPACITY]; + } + + uint64_t + getCapacity() const + { + BOOST_ASSERT(this->hasCapacity()); + return m_capacity; + } + + ControlParameters& + setCapacity(uint64_t capacity) + { + m_wire.reset(); + m_capacity = capacity; + m_hasFields[CONTROL_PARAMETER_CAPACITY] = true; + return *this; + } + + ControlParameters& + unsetCapacity() + { + m_wire.reset(); + m_hasFields[CONTROL_PARAMETER_CAPACITY] = false; + return *this; + } + + bool + hasCount() const + { + return m_hasFields[CONTROL_PARAMETER_COUNT]; + } + + uint64_t + getCount() const + { + BOOST_ASSERT(this->hasCount()); + return m_count; + } + + ControlParameters& + setCount(uint64_t count) + { + m_wire.reset(); + m_count = count; + m_hasFields[CONTROL_PARAMETER_COUNT] = true; + return *this; + } + + ControlParameters& + unsetCount() + { + m_wire.reset(); + m_hasFields[CONTROL_PARAMETER_COUNT] = false; + return *this; + } + + bool + hasFlags() const + { + return m_hasFields[CONTROL_PARAMETER_FLAGS]; + } + + uint64_t + getFlags() const + { + BOOST_ASSERT(this->hasFlags()); + return m_flags; + } + + ControlParameters& + setFlags(uint64_t flags) + { + m_wire.reset(); + m_flags = flags; + m_hasFields[CONTROL_PARAMETER_FLAGS] = true; + return *this; + } + + ControlParameters& + unsetFlags() + { + m_wire.reset(); + m_hasFields[CONTROL_PARAMETER_FLAGS] = false; + return *this; + } + + bool + hasMask() const + { + return m_hasFields[CONTROL_PARAMETER_MASK]; + } + + uint64_t + getMask() const + { + BOOST_ASSERT(this->hasMask()); + return m_mask; + } + + ControlParameters& + setMask(uint64_t mask) + { + m_wire.reset(); + m_mask = mask; + m_hasFields[CONTROL_PARAMETER_MASK] = true; + return *this; + } + + ControlParameters& + unsetMask() + { + m_wire.reset(); + m_hasFields[CONTROL_PARAMETER_MASK] = false; + return *this; + } + + bool + hasStrategy() const + { + return m_hasFields[CONTROL_PARAMETER_STRATEGY]; + } + + const Name& + getStrategy() const + { + BOOST_ASSERT(this->hasStrategy()); + return m_strategy; + } + + ControlParameters& + setStrategy(const Name& strategy) + { + m_wire.reset(); + m_strategy = strategy; + m_hasFields[CONTROL_PARAMETER_STRATEGY] = true; + return *this; + } + + ControlParameters& + unsetStrategy() + { + m_wire.reset(); + m_hasFields[CONTROL_PARAMETER_STRATEGY] = false; + return *this; + } + + bool + hasExpirationPeriod() const + { + return m_hasFields[CONTROL_PARAMETER_EXPIRATION_PERIOD]; + } + + const time::milliseconds& + getExpirationPeriod() const + { + BOOST_ASSERT(this->hasExpirationPeriod()); + return m_expirationPeriod; + } + + ControlParameters& + setExpirationPeriod(const time::milliseconds& expirationPeriod) + { + m_wire.reset(); + m_expirationPeriod = expirationPeriod; + m_hasFields[CONTROL_PARAMETER_EXPIRATION_PERIOD] = true; + return *this; + } + + ControlParameters& + unsetExpirationPeriod() + { + m_wire.reset(); + m_hasFields[CONTROL_PARAMETER_EXPIRATION_PERIOD] = false; + return *this; + } + + bool + hasFacePersistency() const + { + return m_hasFields[CONTROL_PARAMETER_FACE_PERSISTENCY]; + } + + FacePersistency + getFacePersistency() const + { + BOOST_ASSERT(this->hasFacePersistency()); + return m_facePersistency; + } + + ControlParameters& + setFacePersistency(FacePersistency persistency) + { + m_wire.reset(); + m_facePersistency = persistency; + m_hasFields[CONTROL_PARAMETER_FACE_PERSISTENCY] = true; + return *this; + } + + ControlParameters& + unsetFacePersistency() + { + m_wire.reset(); + m_hasFields[CONTROL_PARAMETER_FACE_PERSISTENCY] = false; + return *this; + } + + bool + hasBaseCongestionMarkingInterval() const + { + return m_hasFields[CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL]; + } + + time::nanoseconds + getBaseCongestionMarkingInterval() const + { + BOOST_ASSERT(this->hasBaseCongestionMarkingInterval()); + return m_baseCongestionMarkingInterval; + } + + ControlParameters& + setBaseCongestionMarkingInterval(time::nanoseconds interval) + { + m_wire.reset(); + m_baseCongestionMarkingInterval = interval; + m_hasFields[CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL] = true; + return *this; + } + + ControlParameters& + unsetBaseCongestionMarkingInterval() + { + m_wire.reset(); + m_hasFields[CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL] = false; + return *this; + } + + bool + hasDefaultCongestionThreshold() const + { + return m_hasFields[CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD]; + } + + /** \brief get default congestion threshold (measured in bytes) + */ + uint64_t + getDefaultCongestionThreshold() const + { + BOOST_ASSERT(this->hasDefaultCongestionThreshold()); + return m_defaultCongestionThreshold; + } + + /** \brief set default congestion threshold (measured in bytes) + */ + ControlParameters& + setDefaultCongestionThreshold(uint64_t threshold) + { + m_wire.reset(); + m_defaultCongestionThreshold = threshold; + m_hasFields[CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD] = true; + return *this; + } + + ControlParameters& + unsetDefaultCongestionThreshold() + { + m_wire.reset(); + m_hasFields[CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD] = false; + return *this; + } + + bool + hasMtu() const + { + return m_hasFields[CONTROL_PARAMETER_MTU]; + } + + /** \brief get MTU (measured in bytes) + * + * This value is capped at MAX_NDN_PACKET_SIZE, even if the MTU of the face is unlimited. + */ + uint64_t + getMtu() const + { + BOOST_ASSERT(this->hasMtu()); + return m_mtu; + } + + /** \brief set MTU (measured in bytes) + * + * This value is capped at MAX_NDN_PACKET_SIZE, even if the MTU of the face is unlimited. + */ + ControlParameters& + setMtu(uint64_t mtu) + { + m_wire.reset(); + m_mtu = mtu; + m_hasFields[CONTROL_PARAMETER_MTU] = true; + return *this; + } + + ControlParameters& + unsetMtu() + { + m_wire.reset(); + m_hasFields[CONTROL_PARAMETER_MTU] = false; + return *this; + } + + const std::vector& + getPresentFields() const + { + return m_hasFields; + } + +public: // Flags and Mask helpers + /** + * \return whether bit is enabled in Mask + * \param bit bit position within range [0, 64) (least significant bit is 0) + */ + bool + hasFlagBit(size_t bit) const; + + /** + * \return bit at a position in Flags + * \param bit bit position within range [0, 64) (least significant bit is 0) + */ + bool + getFlagBit(size_t bit) const; + + /** + * \brief set a bit in Flags + * \param bit bit position within range [0, 64) (least significant bit is 0) + * \param value new value in Flags + * \param wantMask if true, enable the bit in Mask + */ + ControlParameters& + setFlagBit(size_t bit, bool value, bool wantMask = true); + + /** + * \brief disable a bit in Mask + * \param bit bit position within range [0, 64) (least significant bit is 0) + * \post If all bits are disabled, Flags and Mask fields are deleted. + */ + ControlParameters& + unsetFlagBit(size_t bit); + +private: // fields + std::vector m_hasFields; + + Name m_name; + uint64_t m_faceId; + std::string m_uri; + std::string m_localUri; + RouteOrigin m_origin; + uint64_t m_cost; + uint64_t m_capacity; + uint64_t m_count; + uint64_t m_flags; + uint64_t m_mask; + Name m_strategy; + time::milliseconds m_expirationPeriod; + FacePersistency m_facePersistency; + time::nanoseconds m_baseCongestionMarkingInterval; + uint64_t m_defaultCongestionThreshold; + uint64_t m_mtu; + +private: + mutable Block m_wire; +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(ControlParameters); + +std::ostream& +operator<<(std::ostream& os, const ControlParameters& parameters); + +} // namespace nfd +} // namespace ndn + +#endif // NDN_MGMT_NFD_CONTROL_PARAMETERS_HPP diff --git a/ndn-cxx/mgmt/nfd/control-response.hpp b/ndn-cxx/mgmt/nfd/control-response.hpp new file mode 100644 index 000000000..6b6f5ffaf --- /dev/null +++ b/ndn-cxx/mgmt/nfd/control-response.hpp @@ -0,0 +1,35 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_MGMT_NFD_CONTROL_RESPONSE_HPP +#define NDN_MGMT_NFD_CONTROL_RESPONSE_HPP + +#include "ndn-cxx/mgmt/control-response.hpp" + +namespace ndn { +namespace nfd { + +using ControlResponse = mgmt::ControlResponse; + +} // namespace nfd +} // namespace ndn + +#endif // NDN_MGMT_NFD_CONTROL_RESPONSE_HPP diff --git a/ndn-cxx/mgmt/nfd/controller.cpp b/ndn-cxx/mgmt/nfd/controller.cpp new file mode 100644 index 000000000..b211f3bc7 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/controller.cpp @@ -0,0 +1,195 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/controller.hpp" +#include "ndn-cxx/face.hpp" +#include "ndn-cxx/security/v2/key-chain.hpp" + +#include + +namespace ndn { +namespace nfd { + +using ndn::util::SegmentFetcher; + +const uint32_t Controller::ERROR_TIMEOUT = 10060; // WinSock ESAETIMEDOUT +const uint32_t Controller::ERROR_NACK = 10800; // 10000 + TLV-TYPE of Nack header +const uint32_t Controller::ERROR_VALIDATION = 10021; // 10000 + TLS1_ALERT_DECRYPTION_FAILED +const uint32_t Controller::ERROR_SERVER = 500; +const uint32_t Controller::ERROR_LBOUND = 400; + +Controller::Controller(Face& face, KeyChain& keyChain, security::v2::Validator& validator) + : m_face(face) + , m_keyChain(keyChain) + , m_validator(validator) + , m_signer(keyChain) +{ +} + +Controller::~Controller() +{ + for (const auto& sp : m_fetchers) { + sp->stop(); + } +} + +void +Controller::startCommand(const shared_ptr& command, + const ControlParameters& parameters, + const CommandSucceedCallback& onSuccess, + const CommandFailCallback& onFailure, + const CommandOptions& options) +{ + Name requestName = command->getRequestName(options.getPrefix(), parameters); + Interest interest = m_signer.makeCommandInterest(requestName, options.getSigningInfo()); + interest.setInterestLifetime(options.getTimeout()); + + m_face.expressInterest(interest, + [=] (const Interest&, const Data& data) { + processCommandResponse(data, command, onSuccess, onFailure); + }, + [=] (const Interest&, const lp::Nack&) { + if (onFailure) + onFailure(ControlResponse(Controller::ERROR_NACK, "network Nack received")); + }, + [=] (const Interest&) { + if (onFailure) + onFailure(ControlResponse(Controller::ERROR_TIMEOUT, "request timed out")); + }); +} + +void +Controller::processCommandResponse(const Data& data, + const shared_ptr& command, + const CommandSucceedCallback& onSuccess, + const CommandFailCallback& onFailure) +{ + m_validator.validate(data, + [=] (const Data& data) { + processValidatedCommandResponse(data, command, onSuccess, onFailure); + }, + [=] (const Data&, const auto& error) { + if (onFailure) + onFailure(ControlResponse(ERROR_VALIDATION, boost::lexical_cast(error))); + } + ); +} + +void +Controller::processValidatedCommandResponse(const Data& data, + const shared_ptr& command, + const CommandSucceedCallback& onSuccess, + const CommandFailCallback& onFailure) +{ + ControlResponse response; + try { + response.wireDecode(data.getContent().blockFromValue()); + } + catch (const tlv::Error& e) { + if (onFailure) + onFailure(ControlResponse(ERROR_SERVER, e.what())); + return; + } + + uint32_t code = response.getCode(); + if (code >= ERROR_LBOUND) { + if (onFailure) + onFailure(response); + return; + } + + ControlParameters parameters; + try { + parameters.wireDecode(response.getBody()); + } + catch (const tlv::Error& e) { + if (onFailure) + onFailure(ControlResponse(ERROR_SERVER, e.what())); + return; + } + + try { + command->validateResponse(parameters); + } + catch (const ControlCommand::ArgumentError& e) { + if (onFailure) + onFailure(ControlResponse(ERROR_SERVER, e.what())); + return; + } + + if (onSuccess) + onSuccess(parameters); +} + +void +Controller::fetchDataset(const Name& prefix, + const std::function& processResponse, + const DatasetFailCallback& onFailure, + const CommandOptions& options) +{ + SegmentFetcher::Options fetcherOptions; + fetcherOptions.maxTimeout = options.getTimeout(); + + auto fetcher = SegmentFetcher::start(m_face, Interest(prefix), m_validator, fetcherOptions); + if (processResponse) { + fetcher->onComplete.connect(processResponse); + } + if (onFailure) { + fetcher->onError.connect([=] (uint32_t code, const std::string& msg) { + processDatasetFetchError(onFailure, code, msg); + }); + } + + auto it = m_fetchers.insert(fetcher).first; + fetcher->onComplete.connect([this, it] (ConstBufferPtr) { m_fetchers.erase(it); }); + fetcher->onError.connect([this, it] (uint32_t, const std::string&) { m_fetchers.erase(it); }); +} + +void +Controller::processDatasetFetchError(const DatasetFailCallback& onFailure, + uint32_t code, std::string msg) +{ + BOOST_ASSERT(onFailure); + + switch (static_cast(code)) { + // It's intentional to cast as SegmentFetcher::ErrorCode, and to not have a 'default' clause. + // This forces the switch statement to handle every defined SegmentFetcher::ErrorCode, + // and breaks compilation if it does not. + case SegmentFetcher::ErrorCode::INTEREST_TIMEOUT: + onFailure(ERROR_TIMEOUT, msg); + break; + case SegmentFetcher::ErrorCode::DATA_HAS_NO_SEGMENT: + case SegmentFetcher::ErrorCode::FINALBLOCKID_NOT_SEGMENT: + onFailure(ERROR_SERVER, msg); + break; + case SegmentFetcher::ErrorCode::SEGMENT_VALIDATION_FAIL: + /// \todo When SegmentFetcher exposes validator error code, Controller::ERROR_VALIDATION + /// should be replaced with a range that corresponds to validator error codes. + onFailure(ERROR_VALIDATION, msg); + break; + case SegmentFetcher::ErrorCode::NACK_ERROR: + onFailure(ERROR_NACK, msg); + break; + } +} + +} // namespace nfd +} // namespace ndn diff --git a/ndn-cxx/mgmt/nfd/controller.hpp b/ndn-cxx/mgmt/nfd/controller.hpp new file mode 100644 index 000000000..5059a991c --- /dev/null +++ b/ndn-cxx/mgmt/nfd/controller.hpp @@ -0,0 +1,223 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_MGMT_NFD_CONTROLLER_HPP +#define NDN_MGMT_NFD_CONTROLLER_HPP + +#include "ndn-cxx/mgmt/nfd/control-command.hpp" +#include "ndn-cxx/mgmt/nfd/control-response.hpp" +#include "ndn-cxx/mgmt/nfd/status-dataset.hpp" +#include "ndn-cxx/mgmt/nfd/command-options.hpp" +#include "ndn-cxx/security/command-interest-signer.hpp" +#include "ndn-cxx/security/validator-null.hpp" +#include "ndn-cxx/security/v2/key-chain.hpp" +#include "ndn-cxx/security/v2/validator.hpp" +#include "ndn-cxx/util/segment-fetcher.hpp" + +namespace ndn { + +class Face; + +namespace nfd { + +/** + * \defgroup management Management + * \brief Classes and data structures to manage NDN forwarder + */ + +/** + * \ingroup management + * \brief NFD Management protocol client + * \sa https://redmine.named-data.net/projects/nfd/wiki/Management + */ +class Controller : noncopyable +{ +public: + /** \brief a callback on command success + */ + using CommandSucceedCallback = function; + + /** \brief a callback on command failure + */ + using CommandFailCallback = function; + + /** \brief a callback on dataset retrieval failure + */ + using DatasetFailCallback = function; + + /** \brief construct a Controller that uses face for transport, + * and uses the passed KeyChain to sign commands + */ + Controller(Face& face, KeyChain& keyChain, + security::v2::Validator& validator = security::getAcceptAllValidator()); + + ~Controller(); + + /** \brief start command execution + */ + template + void + start(const ControlParameters& parameters, + const CommandSucceedCallback& onSuccess, + const CommandFailCallback& onFailure, + const CommandOptions& options = CommandOptions()) + { + startCommand(make_shared(), parameters, onSuccess, onFailure, options); + } + + /** \brief start dataset fetching + */ + template + std::enable_if_t::value> + fetch(const std::function& onSuccess, + const DatasetFailCallback& onFailure, + const CommandOptions& options = CommandOptions()) + { + fetchDataset(make_shared(), onSuccess, onFailure, options); + } + + /** \brief start dataset fetching + */ + template + void + fetch(const ParamType& param, + const std::function& onSuccess, + const DatasetFailCallback& onFailure, + const CommandOptions& options = CommandOptions()) + { + fetchDataset(make_shared(param), onSuccess, onFailure, options); + } + +private: + void + startCommand(const shared_ptr& command, + const ControlParameters& parameters, + const CommandSucceedCallback& onSuccess, + const CommandFailCallback& onFailure, + const CommandOptions& options); + + void + processCommandResponse(const Data& data, + const shared_ptr& command, + const CommandSucceedCallback& onSuccess, + const CommandFailCallback& onFailure); + + void + processValidatedCommandResponse(const Data& data, + const shared_ptr& command, + const CommandSucceedCallback& onSuccess, + const CommandFailCallback& onFailure); + + template + void + fetchDataset(shared_ptr dataset, + const std::function& onSuccess, + const DatasetFailCallback& onFailure, + const CommandOptions& options); + + void + fetchDataset(const Name& prefix, + const std::function& processResponse, + const DatasetFailCallback& onFailure, + const CommandOptions& options); + + template + void + processDatasetResponse(shared_ptr dataset, + const std::function& onSuccess, + const DatasetFailCallback& onFailure, + ConstBufferPtr payload); + + void + processDatasetFetchError(const DatasetFailCallback& onFailure, uint32_t code, std::string msg); + +public: + /** \brief error code for timeout + */ + static const uint32_t ERROR_TIMEOUT; + + /** \brief error code for network Nack + */ + static const uint32_t ERROR_NACK; + + /** \brief error code for response validation failure + */ + static const uint32_t ERROR_VALIDATION; + + /** \brief error code for server error + */ + static const uint32_t ERROR_SERVER; + + /** \brief inclusive lower bound of error codes + */ + static const uint32_t ERROR_LBOUND; + +protected: + Face& m_face; + KeyChain& m_keyChain; + security::v2::Validator& m_validator; + security::CommandInterestSigner m_signer; + +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED: + std::set> m_fetchers; +}; + +template +void +Controller::fetchDataset(shared_ptr dataset, + const std::function& onSuccess, + const DatasetFailCallback& onFailure, + const CommandOptions& options) +{ + Name prefix = dataset->getDatasetPrefix(options.getPrefix()); + fetchDataset(prefix, + [=, d = std::move(dataset)] (ConstBufferPtr p) { + processDatasetResponse(std::move(d), onSuccess, onFailure, std::move(p)); + }, + onFailure, options); +} + +template +void +Controller::processDatasetResponse(shared_ptr dataset, + const std::function& onSuccess, + const DatasetFailCallback& onFailure, + ConstBufferPtr payload) +{ + typename Dataset::ResultType result; + + try { + result = dataset->parseResult(std::move(payload)); + } + catch (const tlv::Error& e) { + if (onFailure) + onFailure(ERROR_SERVER, e.what()); + return; + } + + if (onSuccess) + onSuccess(result); +} + +} // namespace nfd +} // namespace ndn + +#endif // NDN_MGMT_NFD_CONTROLLER_HPP diff --git a/ndn-cxx/mgmt/nfd/cs-info.cpp b/ndn-cxx/mgmt/nfd/cs-info.cpp new file mode 100644 index 000000000..36cda7e60 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/cs-info.cpp @@ -0,0 +1,203 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/cs-info.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/encoding/tlv-nfd.hpp" +#include "ndn-cxx/util/concepts.hpp" + +namespace ndn { +namespace nfd { + +BOOST_CONCEPT_ASSERT((StatusDatasetItem)); + +CsInfo::CsInfo() + : m_capacity(0) + , m_nEntries(0) + , m_nHits(0) + , m_nMisses(0) +{ +} + +CsInfo::CsInfo(const Block& block) +{ + this->wireDecode(block); +} + +template +size_t +CsInfo::wireEncode(EncodingImpl& encoder) const +{ + size_t totalLength = 0; + + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NMisses, m_nMisses); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NHits, m_nHits); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NCsEntries, m_nEntries); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Flags, m_flags.to_ullong()); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Capacity, m_capacity); + + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::nfd::CsInfo); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(CsInfo); + +const Block& +CsInfo::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 +CsInfo::wireDecode(const Block& block) +{ + if (block.type() != tlv::nfd::CsInfo) { + NDN_THROW(Error("CsInfo", block.type())); + } + m_wire = block; + m_wire.parse(); + auto val = m_wire.elements_begin(); + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::Capacity) { + m_capacity = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required Capacity field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::Flags) { + m_flags = FlagsBitSet(static_cast(readNonNegativeInteger(*val))); + ++val; + } + else { + NDN_THROW(Error("missing required Flags field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NCsEntries) { + m_nEntries = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NCsEntries field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NHits) { + m_nHits = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NHits field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NMisses) { + m_nMisses = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NMisses field")); + } +} + +CsInfo& +CsInfo::setCapacity(uint64_t capacity) +{ + m_wire.reset(); + m_capacity = capacity; + return *this; +} + +CsInfo& +CsInfo::setEnableAdmit(bool enableAdmit) +{ + m_wire.reset(); + m_flags[BIT_CS_ENABLE_ADMIT] = enableAdmit; + return *this; +} + +CsInfo& +CsInfo::setEnableServe(bool enableServe) +{ + m_wire.reset(); + m_flags[BIT_CS_ENABLE_SERVE] = enableServe; + return *this; +} + +CsInfo& +CsInfo::setNEntries(uint64_t nEntries) +{ + m_wire.reset(); + m_nEntries = nEntries; + return *this; +} + +CsInfo& +CsInfo::setNHits(uint64_t nHits) +{ + m_wire.reset(); + m_nHits = nHits; + return *this; +} + +CsInfo& +CsInfo::setNMisses(uint64_t nMisses) +{ + m_wire.reset(); + m_nMisses = nMisses; + return *this; +} + +bool +operator==(const CsInfo& a, const CsInfo& b) +{ + return a.getCapacity() == b.getCapacity() && + a.getEnableAdmit() == b.getEnableAdmit() && + a.getEnableServe() == b.getEnableServe() && + a.getNEntries() == b.getNEntries() && + a.getNHits() == b.getNHits() && + a.getNMisses() == b.getNMisses(); +} + +std::ostream& +operator<<(std::ostream& os, const CsInfo& csi) +{ + return os << "CsInfo: " + << csi.getNEntries() << " entries, " << csi.getCapacity() << " max, " + << (csi.getEnableAdmit() ? "admit enabled, " : "admit disabled, ") + << (csi.getEnableServe() ? "serve enabled, " : "serve disabled, ") + << csi.getNHits() << (csi.getNHits() == 1 ? " hit, " : " hits, ") + << csi.getNMisses() << (csi.getNMisses() == 1 ? " miss" : " misses"); +} + +} // namespace nfd +} // namespace ndn diff --git a/ndn-cxx/mgmt/nfd/cs-info.hpp b/ndn-cxx/mgmt/nfd/cs-info.hpp new file mode 100644 index 000000000..199eddd8e --- /dev/null +++ b/ndn-cxx/mgmt/nfd/cs-info.hpp @@ -0,0 +1,156 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_MGMT_NFD_CS_INFO_HPP +#define NDN_MGMT_NFD_CS_INFO_HPP + +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/encoding/nfd-constants.hpp" + +#include + +namespace ndn { +namespace nfd { + +/** \ingroup management + * \brief represents the CS Information dataset + * \sa https://redmine.named-data.net/projects/nfd/wiki/CsMgmt#CS-Information-Dataset + */ +class CsInfo +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + CsInfo(); + + explicit + CsInfo(const Block& block); + + template + size_t + wireEncode(EncodingImpl& encoder) const; + + const Block& + wireEncode() const; + + void + wireDecode(const Block& wire); + + /** \brief get CS capacity (in number of packets) + */ + uint64_t + getCapacity() const + { + return m_capacity; + } + + CsInfo& + setCapacity(uint64_t capacity); + + /** \brief get CS_ENABLE_ADMIT flag + */ + bool + getEnableAdmit() const + { + return m_flags.test(BIT_CS_ENABLE_ADMIT); + } + + CsInfo& + setEnableAdmit(bool enableAdmit); + + /** \brief get CS_ENABLE_SERVE flag + */ + bool + getEnableServe() const + { + return m_flags.test(BIT_CS_ENABLE_SERVE); + } + + CsInfo& + setEnableServe(bool enableServe); + + /** \brief get number of stored CS entries + */ + uint64_t + getNEntries() const + { + return m_nEntries; + } + + CsInfo& + setNEntries(uint64_t nEntries); + + /** \brief get number of CS lookup hits since NFD starts + */ + uint64_t + getNHits() const + { + return m_nHits; + } + + CsInfo& + setNHits(uint64_t nHits); + + /** \brief get number of CS lookup misses since NFD starts + */ + uint64_t + getNMisses() const + { + return m_nMisses; + } + + CsInfo& + setNMisses(uint64_t nMisses); + +private: + using FlagsBitSet = std::bitset<2>; + + uint64_t m_capacity; + FlagsBitSet m_flags; + uint64_t m_nEntries; + uint64_t m_nHits; + uint64_t m_nMisses; + + mutable Block m_wire; +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(CsInfo); + +bool +operator==(const CsInfo& a, const CsInfo& b); + +inline bool +operator!=(const CsInfo& a, const CsInfo& b) +{ + return !(a == b); +} + +std::ostream& +operator<<(std::ostream& os, const CsInfo& csi); + +} // namespace nfd +} // namespace ndn + +#endif // NDN_MGMT_NFD_CS_INFO_HPP diff --git a/ndn-cxx/mgmt/nfd/face-event-notification.cpp b/ndn-cxx/mgmt/nfd/face-event-notification.cpp new file mode 100644 index 000000000..09a7e052e --- /dev/null +++ b/ndn-cxx/mgmt/nfd/face-event-notification.cpp @@ -0,0 +1,195 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/face-event-notification.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/encoding/tlv-nfd.hpp" +#include "ndn-cxx/util/concepts.hpp" +#include "ndn-cxx/util/string-helper.hpp" + +namespace ndn { +namespace nfd { + +BOOST_CONCEPT_ASSERT((NotificationStreamItem)); + +FaceEventNotification::FaceEventNotification() + : m_kind(FACE_EVENT_NONE) +{ +} + +FaceEventNotification::FaceEventNotification(const Block& block) +{ + this->wireDecode(block); +} + +template +size_t +FaceEventNotification::wireEncode(EncodingImpl& encoder) const +{ + size_t totalLength = 0; + + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Flags, m_flags); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::LinkType, m_linkType); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::FacePersistency, m_facePersistency); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::FaceScope, m_faceScope); + totalLength += prependStringBlock(encoder, tlv::nfd::LocalUri, m_localUri); + totalLength += prependStringBlock(encoder, tlv::nfd::Uri, m_remoteUri); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::FaceId, m_faceId); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::FaceEventKind, m_kind); + + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::nfd::FaceEventNotification); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(FaceEventNotification); + +const Block& +FaceEventNotification::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 +FaceEventNotification::wireDecode(const Block& block) +{ + if (block.type() != tlv::nfd::FaceEventNotification) { + NDN_THROW(Error("FaceEventNotification", block.type())); + } + + m_wire = block; + m_wire.parse(); + auto val = m_wire.elements_begin(); + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceEventKind) { + m_kind = readNonNegativeIntegerAs(*val); + ++val; + } + else { + NDN_THROW(Error("missing required FaceEventKind field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceId) { + m_faceId = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required FaceId field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::Uri) { + m_remoteUri = readString(*val); + ++val; + } + else { + NDN_THROW(Error("missing required Uri field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::LocalUri) { + m_localUri = readString(*val); + ++val; + } + else { + NDN_THROW(Error("missing required LocalUri field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceScope) { + m_faceScope = readNonNegativeIntegerAs(*val); + ++val; + } + else { + NDN_THROW(Error("missing required FaceScope field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::FacePersistency) { + m_facePersistency = readNonNegativeIntegerAs(*val); + ++val; + } + else { + NDN_THROW(Error("missing required FacePersistency field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::LinkType) { + m_linkType = readNonNegativeIntegerAs(*val); + ++val; + } + else { + NDN_THROW(Error("missing required LinkType field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::Flags) { + m_flags = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required Flags field")); + } +} + +FaceEventNotification& +FaceEventNotification::setKind(FaceEventKind kind) +{ + m_wire.reset(); + m_kind = kind; + return *this; +} + +bool +operator==(const FaceEventNotification& a, const FaceEventNotification& b) +{ + return a.getFaceId() == b.getFaceId() && + a.getRemoteUri() == b.getRemoteUri() && + a.getLocalUri() == b.getLocalUri() && + a.getFaceScope() == b.getFaceScope() && + a.getFacePersistency() == b.getFacePersistency() && + a.getLinkType() == b.getLinkType() && + a.getFlags() == b.getFlags() && + a.getKind() == b.getKind(); +} + +std::ostream& +operator<<(std::ostream& os, const FaceEventNotification& notification) +{ + os << "FaceEvent(Kind: " << notification.getKind() << ",\n" + << " FaceId: " << notification.getFaceId() << ",\n" + << " RemoteUri: " << notification.getRemoteUri() << ",\n" + << " LocalUri: " << notification.getLocalUri() << ",\n" + << " FaceScope: " << notification.getFaceScope() << ",\n" + << " FacePersistency: " << notification.getFacePersistency() << ",\n" + << " LinkType: " << notification.getLinkType() << ",\n" + << " Flags: " << AsHex{notification.getFlags()} << "\n"; + + return os << " )"; +} + +} // namespace nfd +} // namespace ndn diff --git a/src/mgmt/nfd/face-event-notification.hpp b/ndn-cxx/mgmt/nfd/face-event-notification.hpp similarity index 78% rename from src/mgmt/nfd/face-event-notification.hpp rename to ndn-cxx/mgmt/nfd/face-event-notification.hpp index 7d3121eec..20ff0de18 100644 --- a/src/mgmt/nfd/face-event-notification.hpp +++ b/ndn-cxx/mgmt/nfd/face-event-notification.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,26 +22,15 @@ #ifndef NDN_MGMT_NFD_FACE_EVENT_NOTIFICATION_HPP #define NDN_MGMT_NFD_FACE_EVENT_NOTIFICATION_HPP -#include "face-traits.hpp" -#include "../../encoding/block.hpp" +#include "ndn-cxx/mgmt/nfd/face-traits.hpp" namespace ndn { namespace nfd { -/** - * \ingroup management - */ -enum FaceEventKind { - FACE_EVENT_CREATED = 1, ///< face created - FACE_EVENT_DESTROYED = 2, ///< face destroyed - FACE_EVENT_UP = 3, ///< face went UP (from DOWN state) - FACE_EVENT_DOWN = 4 ///< face went DOWN (from UP state) -}; - /** * \ingroup management * \brief represents a Face status change notification - * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Face-Status-Change-Notification + * \sa https://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Face-Status-Change-Notification */ class FaceEventNotification : public FaceTraits { @@ -77,16 +66,21 @@ class FaceEventNotification : public FaceTraits FaceEventNotification& setKind(FaceEventKind kind); -protected: - void - wireReset() const; - private: FaceEventKind m_kind; - - mutable Block m_wire; }; +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(FaceEventNotification); + +bool +operator==(const FaceEventNotification& a, const FaceEventNotification& b); + +inline bool +operator!=(const FaceEventNotification& a, const FaceEventNotification& b) +{ + return !(a == b); +} + std::ostream& operator<<(std::ostream& os, const FaceEventNotification& notification); diff --git a/ndn-cxx/mgmt/nfd/face-monitor.cpp b/ndn-cxx/mgmt/nfd/face-monitor.cpp new file mode 100644 index 000000000..b86802bf8 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/face-monitor.cpp @@ -0,0 +1,39 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014-2018 Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/face-monitor.hpp" + +namespace ndn { +namespace nfd { + +FaceMonitor::FaceMonitor(Face& face) + : NotificationSubscriber(face, "ndn:/localhost/nfd/faces/events") +{ +} + +} // namespace nfd +} // namespace ndn diff --git a/ndn-cxx/mgmt/nfd/face-monitor.hpp b/ndn-cxx/mgmt/nfd/face-monitor.hpp new file mode 100644 index 000000000..7c9639e24 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/face-monitor.hpp @@ -0,0 +1,50 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014-2018 Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_MGMT_NFD_FACE_MONITOR_HPP +#define NDN_MGMT_NFD_FACE_MONITOR_HPP + +#include "ndn-cxx/mgmt/nfd/face-event-notification.hpp" +#include "ndn-cxx/util/notification-subscriber.hpp" + +namespace ndn { +namespace nfd { + +/** \brief A subscriber for Face status change notification stream + * \sa https://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Face-Status-Change-Notification + */ +class FaceMonitor : public util::NotificationSubscriber +{ +public: + explicit + FaceMonitor(Face& face); +}; + +} // namespace nfd +} // namespace ndn + +#endif // NDN_MGMT_NFD_FACE_MONITOR_HPP diff --git a/ndn-cxx/mgmt/nfd/face-query-filter.cpp b/ndn-cxx/mgmt/nfd/face-query-filter.cpp new file mode 100644 index 000000000..a0f8e19d0 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/face-query-filter.cpp @@ -0,0 +1,347 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/face-query-filter.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/encoding/tlv-nfd.hpp" +#include "ndn-cxx/util/concepts.hpp" + +namespace ndn { +namespace nfd { + +BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); +BOOST_CONCEPT_ASSERT((WireEncodable)); +BOOST_CONCEPT_ASSERT((WireDecodable)); +static_assert(std::is_base_of::value, + "FaceQueryFilter::Error must inherit from tlv::Error"); + +FaceQueryFilter::FaceQueryFilter() = default; + +FaceQueryFilter::FaceQueryFilter(const Block& block) +{ + this->wireDecode(block); +} + +template +size_t +FaceQueryFilter::wireEncode(EncodingImpl& encoder) const +{ + size_t totalLength = 0; + + if (m_linkType) { + totalLength += prependNonNegativeIntegerBlock(encoder, + tlv::nfd::LinkType, *m_linkType); + } + + if (m_facePersistency) { + totalLength += prependNonNegativeIntegerBlock(encoder, + tlv::nfd::FacePersistency, *m_facePersistency); + } + + if (m_faceScope) { + totalLength += prependNonNegativeIntegerBlock(encoder, + tlv::nfd::FaceScope, *m_faceScope); + } + + if (hasLocalUri()) { + totalLength += prependStringBlock(encoder, tlv::nfd::LocalUri, m_localUri); + } + + if (hasRemoteUri()) { + totalLength += prependStringBlock(encoder, tlv::nfd::Uri, m_remoteUri); + } + + if (hasUriScheme()) { + totalLength += prependStringBlock(encoder, tlv::nfd::UriScheme, m_uriScheme); + } + + if (m_faceId) { + totalLength += prependNonNegativeIntegerBlock(encoder, + tlv::nfd::FaceId, *m_faceId); + } + + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::nfd::FaceQueryFilter); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(FaceQueryFilter); + +const Block& +FaceQueryFilter::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 +FaceQueryFilter::wireDecode(const Block& block) +{ + if (block.type() != tlv::nfd::FaceQueryFilter) { + NDN_THROW(Error("FaceQueryFilter", block.type())); + } + + m_wire = block; + m_wire.parse(); + auto val = m_wire.elements_begin(); + + // all fields are optional + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceId) { + m_faceId = readNonNegativeInteger(*val); + ++val; + } + else { + m_faceId = nullopt; + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::UriScheme) { + m_uriScheme = readString(*val); + ++val; + } + else { + m_uriScheme.clear(); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::Uri) { + m_remoteUri = readString(*val); + ++val; + } + else { + m_remoteUri.clear(); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::LocalUri) { + m_localUri = readString(*val); + ++val; + } + else { + m_localUri.clear(); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceScope) { + m_faceScope = readNonNegativeIntegerAs(*val); + ++val; + } + else { + m_faceScope = nullopt; + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::FacePersistency) { + m_facePersistency = readNonNegativeIntegerAs(*val); + ++val; + } + else { + m_facePersistency = nullopt; + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::LinkType) { + m_linkType = readNonNegativeIntegerAs(*val); + ++val; + } + else { + m_linkType = nullopt; + } +} + +bool +FaceQueryFilter::empty() const +{ + return !this->hasFaceId() && + !this->hasUriScheme() && + !this->hasRemoteUri() && + !this->hasLocalUri() && + !this->hasFaceScope() && + !this->hasFacePersistency() && + !this->hasLinkType(); +} + +FaceQueryFilter& +FaceQueryFilter::setFaceId(uint64_t faceId) +{ + m_wire.reset(); + m_faceId = faceId; + return *this; +} + +FaceQueryFilter& +FaceQueryFilter::unsetFaceId() +{ + m_wire.reset(); + m_faceId = nullopt; + return *this; +} + +FaceQueryFilter& +FaceQueryFilter::setUriScheme(const std::string& uriScheme) +{ + m_wire.reset(); + m_uriScheme = uriScheme; + return *this; +} + +FaceQueryFilter& +FaceQueryFilter::unsetUriScheme() +{ + return this->setUriScheme(""); +} + +FaceQueryFilter& +FaceQueryFilter::setRemoteUri(const std::string& remoteUri) +{ + m_wire.reset(); + m_remoteUri = remoteUri; + return *this; +} + +FaceQueryFilter& +FaceQueryFilter::unsetRemoteUri() +{ + return this->setRemoteUri(""); +} + +FaceQueryFilter& +FaceQueryFilter::setLocalUri(const std::string& localUri) +{ + m_wire.reset(); + m_localUri = localUri; + return *this; +} + +FaceQueryFilter& +FaceQueryFilter::unsetLocalUri() +{ + return this->setLocalUri(""); +} + +FaceQueryFilter& +FaceQueryFilter::setFaceScope(FaceScope faceScope) +{ + m_wire.reset(); + m_faceScope = faceScope; + return *this; +} + +FaceQueryFilter& +FaceQueryFilter::unsetFaceScope() +{ + m_wire.reset(); + m_faceScope = nullopt; + return *this; +} + +FaceQueryFilter& +FaceQueryFilter::setFacePersistency(FacePersistency facePersistency) +{ + m_wire.reset(); + m_facePersistency = facePersistency; + return *this; +} + +FaceQueryFilter& +FaceQueryFilter::unsetFacePersistency() +{ + m_wire.reset(); + m_facePersistency = nullopt; + return *this; +} + +FaceQueryFilter& +FaceQueryFilter::setLinkType(LinkType linkType) +{ + m_wire.reset(); + m_linkType = linkType; + return *this; +} + +FaceQueryFilter& +FaceQueryFilter::unsetLinkType() +{ + m_wire.reset(); + m_linkType = nullopt; + return *this; +} + +bool +operator==(const FaceQueryFilter& a, const FaceQueryFilter& b) +{ + return a.hasFaceId() == b.hasFaceId() && + (!a.hasFaceId() || a.getFaceId() == b.getFaceId()) && + a.hasUriScheme() == b.hasUriScheme() && + (!a.hasUriScheme() || a.getUriScheme() == b.getUriScheme()) && + a.hasRemoteUri() == b.hasRemoteUri() && + (!a.hasRemoteUri() || a.getRemoteUri() == b.getRemoteUri()) && + a.hasLocalUri() == b.hasLocalUri() && + (!a.hasLocalUri() || a.getLocalUri() == b.getLocalUri()) && + a.hasFaceScope() == b.hasFaceScope() && + (!a.hasFaceScope() || a.getFaceScope() == b.getFaceScope()) && + a.hasFacePersistency() == b.hasFacePersistency() && + (!a.hasFacePersistency() || a.getFacePersistency() == b.getFacePersistency()) && + a.hasLinkType() == b.hasLinkType() && + (!a.hasLinkType() || a.getLinkType() == b.getLinkType()); +} + +std::ostream& +operator<<(std::ostream& os, const FaceQueryFilter& filter) +{ + os << "FaceQueryFilter("; + if (filter.hasFaceId()) { + os << "FaceID: " << filter.getFaceId() << ",\n"; + } + + if (filter.hasUriScheme()) { + os << "UriScheme: " << filter.getUriScheme() << ",\n"; + } + + if (filter.hasRemoteUri()) { + os << "RemoteUri: " << filter.getRemoteUri() << ",\n"; + } + + if (filter.hasLocalUri()) { + os << "LocalUri: " << filter.getLocalUri() << ",\n"; + } + + if (filter.hasFaceScope()) { + os << "FaceScope: " << filter.getFaceScope() << ",\n"; + } + + if (filter.hasFacePersistency()) { + os << "FacePersistency: " << filter.getFacePersistency() << ",\n"; + } + + if (filter.hasLinkType()) { + os << "LinkType: " << filter.getLinkType() << ",\n"; + } + os << ")"; + return os; +} + +} // namespace nfd +} // namespace ndn diff --git a/src/mgmt/nfd/face-query-filter.hpp b/ndn-cxx/mgmt/nfd/face-query-filter.hpp similarity index 78% rename from src/mgmt/nfd/face-query-filter.hpp rename to ndn-cxx/mgmt/nfd/face-query-filter.hpp index e0bb39367..3ef6e807c 100644 --- a/src/mgmt/nfd/face-query-filter.hpp +++ b/ndn-cxx/mgmt/nfd/face-query-filter.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,8 +22,8 @@ #ifndef NDN_MGMT_NFD_FACE_QUERY_FILTER_HPP #define NDN_MGMT_NFD_FACE_QUERY_FILTER_HPP -#include "../../encoding/block.hpp" -#include "../../encoding/nfd-constants.hpp" +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/encoding/nfd-constants.hpp" namespace ndn { namespace nfd { @@ -31,7 +31,7 @@ namespace nfd { /** * \ingroup management * \brief represents Face Query Filter - * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Query-Operation + * \sa https://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Query-Operation */ class FaceQueryFilter { @@ -39,11 +39,7 @@ class FaceQueryFilter class Error : public tlv::Error { public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } + using tlv::Error::Error; }; FaceQueryFilter(); @@ -67,19 +63,23 @@ class FaceQueryFilter void wireDecode(const Block& wire); -public: // getters & setters + /** \return whether the filter is empty + */ + bool + empty() const; +public: // getters & setters bool hasFaceId() const { - return m_hasFaceId; + return !!m_faceId; } uint64_t getFaceId() const { BOOST_ASSERT(this->hasFaceId()); - return m_faceId; + return *m_faceId; } FaceQueryFilter& @@ -91,7 +91,7 @@ class FaceQueryFilter bool hasUriScheme() const { - return m_hasUriScheme; + return !m_uriScheme.empty(); } const std::string& @@ -110,7 +110,7 @@ class FaceQueryFilter bool hasRemoteUri() const { - return m_hasRemoteUri; + return !m_remoteUri.empty(); } const std::string& @@ -129,7 +129,7 @@ class FaceQueryFilter bool hasLocalUri() const { - return m_hasLocalUri; + return !m_localUri.empty(); } const std::string& @@ -148,14 +148,14 @@ class FaceQueryFilter bool hasFaceScope() const { - return m_hasFaceScope; + return !!m_faceScope; } FaceScope getFaceScope() const { BOOST_ASSERT(this->hasFaceScope()); - return m_faceScope; + return *m_faceScope; } FaceQueryFilter& @@ -167,14 +167,14 @@ class FaceQueryFilter bool hasFacePersistency() const { - return m_hasFacePersistency; + return !!m_facePersistency; } FacePersistency getFacePersistency() const { BOOST_ASSERT(this->hasFacePersistency()); - return m_facePersistency; + return *m_facePersistency; } FaceQueryFilter& @@ -186,14 +186,14 @@ class FaceQueryFilter bool hasLinkType() const { - return m_hasLinkType; + return !!m_linkType; } LinkType getLinkType() const { BOOST_ASSERT(this->hasLinkType()); - return m_linkType; + return *m_linkType; } FaceQueryFilter& @@ -203,25 +203,28 @@ class FaceQueryFilter unsetLinkType(); private: - uint64_t m_faceId; + optional m_faceId; std::string m_uriScheme; std::string m_remoteUri; std::string m_localUri; - FaceScope m_faceScope; - FacePersistency m_facePersistency; - LinkType m_linkType; - - bool m_hasFaceId; - bool m_hasUriScheme; - bool m_hasRemoteUri; - bool m_hasLocalUri; - bool m_hasFaceScope; - bool m_hasFacePersistency; - bool m_hasLinkType; + optional m_faceScope; + optional m_facePersistency; + optional m_linkType; mutable Block m_wire; }; +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(FaceQueryFilter); + +bool +operator==(const FaceQueryFilter& a, const FaceQueryFilter& b); + +inline bool +operator!=(const FaceQueryFilter& a, const FaceQueryFilter& b) +{ + return !(a == b); +} + std::ostream& operator<<(std::ostream& os, const FaceQueryFilter& filter); diff --git a/ndn-cxx/mgmt/nfd/face-status.cpp b/ndn-cxx/mgmt/nfd/face-status.cpp new file mode 100644 index 000000000..8727b4030 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/face-status.cpp @@ -0,0 +1,477 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/face-status.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/encoding/tlv-nfd.hpp" +#include "ndn-cxx/util/concepts.hpp" +#include "ndn-cxx/util/string-helper.hpp" + +namespace ndn { +namespace nfd { + +BOOST_CONCEPT_ASSERT((StatusDatasetItem)); + +FaceStatus::FaceStatus() + : m_nInInterests(0) + , m_nInData(0) + , m_nInNacks(0) + , m_nOutInterests(0) + , m_nOutData(0) + , m_nOutNacks(0) + , m_nInBytes(0) + , m_nOutBytes(0) +{ +} + +FaceStatus::FaceStatus(const Block& block) +{ + this->wireDecode(block); +} + +template +size_t +FaceStatus::wireEncode(EncodingImpl& encoder) const +{ + size_t totalLength = 0; + + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Flags, m_flags); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NOutBytes, m_nOutBytes); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NInBytes, m_nInBytes); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NOutNacks, m_nOutNacks); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NOutData, m_nOutData); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NOutInterests, m_nOutInterests); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NInNacks, m_nInNacks); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NInData, m_nInData); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NInInterests, m_nInInterests); + if (m_mtu) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Mtu, *m_mtu); + } + if (m_defaultCongestionThreshold) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::DefaultCongestionThreshold, + *m_defaultCongestionThreshold); + } + if (m_baseCongestionMarkingInterval) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::BaseCongestionMarkingInterval, + m_baseCongestionMarkingInterval->count()); + } + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::LinkType, m_linkType); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::FacePersistency, m_facePersistency); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::FaceScope, m_faceScope); + if (m_expirationPeriod) { + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::ExpirationPeriod, + m_expirationPeriod->count()); + } + totalLength += prependStringBlock(encoder, tlv::nfd::LocalUri, m_localUri); + totalLength += prependStringBlock(encoder, tlv::nfd::Uri, m_remoteUri); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::FaceId, m_faceId); + + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::nfd::FaceStatus); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(FaceStatus); + +const Block& +FaceStatus::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 +FaceStatus::wireDecode(const Block& block) +{ + if (block.type() != tlv::nfd::FaceStatus) { + NDN_THROW(Error("FaceStatus", block.type())); + } + + m_wire = block; + m_wire.parse(); + auto val = m_wire.elements_begin(); + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceId) { + m_faceId = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required FaceId field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::Uri) { + m_remoteUri = readString(*val); + ++val; + } + else { + NDN_THROW(Error("missing required Uri field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::LocalUri) { + m_localUri = readString(*val); + ++val; + } + else { + NDN_THROW(Error("missing required LocalUri field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::ExpirationPeriod) { + m_expirationPeriod.emplace(readNonNegativeInteger(*val)); + ++val; + } + else { + m_expirationPeriod = nullopt; + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceScope) { + m_faceScope = readNonNegativeIntegerAs(*val); + ++val; + } + else { + NDN_THROW(Error("missing required FaceScope field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::FacePersistency) { + m_facePersistency = readNonNegativeIntegerAs(*val); + ++val; + } + else { + NDN_THROW(Error("missing required FacePersistency field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::LinkType) { + m_linkType = readNonNegativeIntegerAs(*val); + ++val; + } + else { + NDN_THROW(Error("missing required LinkType field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::BaseCongestionMarkingInterval) { + m_baseCongestionMarkingInterval.emplace(readNonNegativeInteger(*val)); + ++val; + } + else { + m_baseCongestionMarkingInterval = nullopt; + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::DefaultCongestionThreshold) { + m_defaultCongestionThreshold = readNonNegativeInteger(*val); + ++val; + } + else { + m_defaultCongestionThreshold = nullopt; + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::Mtu) { + m_mtu = readNonNegativeInteger(*val); + ++val; + } + else { + m_mtu = nullopt; + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInInterests) { + m_nInInterests = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NInInterests field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInData) { + m_nInData = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NInData field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInNacks) { + m_nInNacks = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NInNacks field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutInterests) { + m_nOutInterests = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NOutInterests field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutData) { + m_nOutData = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NOutData field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutNacks) { + m_nOutNacks = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NOutNacks field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInBytes) { + m_nInBytes = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NInBytes field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutBytes) { + m_nOutBytes = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NOutBytes field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::Flags) { + m_flags = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required Flags field")); + } +} + +FaceStatus& +FaceStatus::setExpirationPeriod(time::milliseconds expirationPeriod) +{ + m_wire.reset(); + m_expirationPeriod = expirationPeriod; + return *this; +} + +FaceStatus& +FaceStatus::unsetExpirationPeriod() +{ + m_wire.reset(); + m_expirationPeriod = nullopt; + return *this; +} + +FaceStatus& +FaceStatus::setBaseCongestionMarkingInterval(time::nanoseconds interval) +{ + m_wire.reset(); + m_baseCongestionMarkingInterval = interval; + return *this; +} + +FaceStatus& +FaceStatus::unsetBaseCongestionMarkingInterval() +{ + m_wire.reset(); + m_baseCongestionMarkingInterval = nullopt; + return *this; +} + +FaceStatus& +FaceStatus::setDefaultCongestionThreshold(uint64_t threshold) +{ + m_wire.reset(); + m_defaultCongestionThreshold = threshold; + return *this; +} + +FaceStatus& +FaceStatus::unsetDefaultCongestionThreshold() +{ + m_wire.reset(); + m_defaultCongestionThreshold = nullopt; + return *this; +} + +FaceStatus& +FaceStatus::setMtu(uint64_t mtu) +{ + m_wire.reset(); + m_mtu = mtu; + return *this; +} + +FaceStatus& +FaceStatus::unsetMtu() +{ + m_wire.reset(); + m_mtu = nullopt; + return *this; +} + +FaceStatus& +FaceStatus::setNInInterests(uint64_t nInInterests) +{ + m_wire.reset(); + m_nInInterests = nInInterests; + return *this; +} + +FaceStatus& +FaceStatus::setNInData(uint64_t nInData) +{ + m_wire.reset(); + m_nInData = nInData; + return *this; +} + +FaceStatus& +FaceStatus::setNInNacks(uint64_t nInNacks) +{ + m_wire.reset(); + m_nInNacks = nInNacks; + return *this; +} + +FaceStatus& +FaceStatus::setNOutInterests(uint64_t nOutInterests) +{ + m_wire.reset(); + m_nOutInterests = nOutInterests; + return *this; +} + +FaceStatus& +FaceStatus::setNOutData(uint64_t nOutData) +{ + m_wire.reset(); + m_nOutData = nOutData; + return *this; +} + +FaceStatus& +FaceStatus::setNOutNacks(uint64_t nOutNacks) +{ + m_wire.reset(); + m_nOutNacks = nOutNacks; + return *this; +} + +FaceStatus& +FaceStatus::setNInBytes(uint64_t nInBytes) +{ + m_wire.reset(); + m_nInBytes = nInBytes; + return *this; +} + +FaceStatus& +FaceStatus::setNOutBytes(uint64_t nOutBytes) +{ + m_wire.reset(); + m_nOutBytes = nOutBytes; + return *this; +} + +bool +operator==(const FaceStatus& a, const FaceStatus& b) +{ + return a.getFaceId() == b.getFaceId() && + a.getRemoteUri() == b.getRemoteUri() && + a.getLocalUri() == b.getLocalUri() && + a.getFaceScope() == b.getFaceScope() && + a.getFacePersistency() == b.getFacePersistency() && + a.getLinkType() == b.getLinkType() && + a.getFlags() == b.getFlags() && + a.hasExpirationPeriod() == b.hasExpirationPeriod() && + (!a.hasExpirationPeriod() || a.getExpirationPeriod() == b.getExpirationPeriod()) && + a.hasBaseCongestionMarkingInterval() == b.hasBaseCongestionMarkingInterval() && + (!a.hasBaseCongestionMarkingInterval() || + a.getBaseCongestionMarkingInterval() == b.getBaseCongestionMarkingInterval()) && + a.hasDefaultCongestionThreshold() == b.hasDefaultCongestionThreshold() && + (!a.hasDefaultCongestionThreshold() || + a.getDefaultCongestionThreshold() == b.getDefaultCongestionThreshold()) && + a.hasMtu() == b.hasMtu() && + (!a.hasMtu() || a.getMtu() == b.getMtu()) && + a.getNInInterests() == b.getNInInterests() && + a.getNInData() == b.getNInData() && + a.getNInNacks() == b.getNInNacks() && + a.getNOutInterests() == b.getNOutInterests() && + a.getNOutData() == b.getNOutData() && + a.getNOutNacks() == b.getNOutNacks() && + a.getNInBytes() == b.getNInBytes() && + a.getNOutBytes() == b.getNOutBytes(); +} + +std::ostream& +operator<<(std::ostream& os, const FaceStatus& status) +{ + os << "Face(FaceId: " << status.getFaceId() << ",\n" + << " RemoteUri: " << status.getRemoteUri() << ",\n" + << " LocalUri: " << status.getLocalUri() << ",\n"; + + if (status.hasExpirationPeriod()) { + os << " ExpirationPeriod: " << status.getExpirationPeriod() << ",\n"; + } + else { + os << " ExpirationPeriod: infinite,\n"; + } + + os << " FaceScope: " << status.getFaceScope() << ",\n" + << " FacePersistency: " << status.getFacePersistency() << ",\n" + << " LinkType: " << status.getLinkType() << ",\n"; + + if (status.hasBaseCongestionMarkingInterval()) { + os << " BaseCongestionMarkingInterval: " << status.getBaseCongestionMarkingInterval() << ",\n"; + } + + if (status.hasDefaultCongestionThreshold()) { + os << " DefaultCongestionThreshold: " << status.getDefaultCongestionThreshold() << " bytes,\n"; + } + + if (status.hasMtu()) { + os << " Mtu: " << status.getMtu() << " bytes,\n"; + } + + os << " Flags: " << AsHex{status.getFlags()} << ",\n" + << " Counters: {Interests: {in: " << status.getNInInterests() << ", " + << "out: " << status.getNOutInterests() << "},\n" + << " Data: {in: " << status.getNInData() << ", " + << "out: " << status.getNOutData() << "},\n" + << " Nacks: {in: " << status.getNInNacks() << ", " + << "out: " << status.getNOutNacks() << "},\n" + << " bytes: {in: " << status.getNInBytes() << ", " + << "out: " << status.getNOutBytes() << "}}\n"; + + return os << " )"; +} + +} // namespace nfd +} // namespace ndn diff --git a/ndn-cxx/mgmt/nfd/face-status.hpp b/ndn-cxx/mgmt/nfd/face-status.hpp new file mode 100644 index 000000000..f1b9ddd9d --- /dev/null +++ b/ndn-cxx/mgmt/nfd/face-status.hpp @@ -0,0 +1,253 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_MGMT_NFD_FACE_STATUS_HPP +#define NDN_MGMT_NFD_FACE_STATUS_HPP + +#include "ndn-cxx/mgmt/nfd/face-traits.hpp" +#include "ndn-cxx/util/time.hpp" + +namespace ndn { +namespace nfd { + +/** + * \ingroup management + * \brief represents an item in NFD Face dataset + * \sa https://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Face-Dataset + */ +class FaceStatus : public FaceTraits +{ +public: + FaceStatus(); + + explicit + FaceStatus(const Block& block); + + /** \brief prepend FaceStatus to the encoder + */ + template + size_t + wireEncode(EncodingImpl& encoder) const; + + /** \brief encode FaceStatus + */ + const Block& + wireEncode() const; + + /** \brief decode FaceStatus + */ + void + wireDecode(const Block& wire); + +public: // getters & setters + bool + hasExpirationPeriod() const + { + return !!m_expirationPeriod; + } + + time::milliseconds + getExpirationPeriod() const + { + BOOST_ASSERT(hasExpirationPeriod()); + return *m_expirationPeriod; + } + + FaceStatus& + setExpirationPeriod(time::milliseconds expirationPeriod); + + FaceStatus& + unsetExpirationPeriod(); + + bool + hasBaseCongestionMarkingInterval() const + { + return !!m_baseCongestionMarkingInterval; + } + + time::nanoseconds + getBaseCongestionMarkingInterval() const + { + BOOST_ASSERT(hasBaseCongestionMarkingInterval()); + return *m_baseCongestionMarkingInterval; + } + + FaceStatus& + setBaseCongestionMarkingInterval(time::nanoseconds interval); + + FaceStatus& + unsetBaseCongestionMarkingInterval(); + + bool + hasDefaultCongestionThreshold() const + { + return !!m_defaultCongestionThreshold; + } + + /** \brief get default congestion threshold (measured in bytes) + */ + uint64_t + getDefaultCongestionThreshold() const + { + BOOST_ASSERT(hasDefaultCongestionThreshold()); + return *m_defaultCongestionThreshold; + } + + /** \brief set default congestion threshold (measured in bytes) + */ + FaceStatus& + setDefaultCongestionThreshold(uint64_t threshold); + + FaceStatus& + unsetDefaultCongestionThreshold(); + + bool + hasMtu() const + { + return !!m_mtu; + } + + /** \brief get MTU (measured in bytes) + * + * This value is capped at MAX_NDN_PACKET_SIZE, even if the MTU of the face is unlimited. + */ + uint64_t + getMtu() const + { + BOOST_ASSERT(hasMtu()); + return *m_mtu; + } + + /** \brief set MTU (measured in bytes) + * + * This value is capped at MAX_NDN_PACKET_SIZE, even if the MTU of the face is unlimited. + */ + FaceStatus& + setMtu(uint64_t mtu); + + FaceStatus& + unsetMtu(); + + uint64_t + getNInInterests() const + { + return m_nInInterests; + } + + FaceStatus& + setNInInterests(uint64_t nInInterests); + + uint64_t + getNInData() const + { + return m_nInData; + } + + FaceStatus& + setNInData(uint64_t nInData); + + uint64_t + getNInNacks() const + { + return m_nInNacks; + } + + FaceStatus& + setNInNacks(uint64_t nInNacks); + + uint64_t + getNOutInterests() const + { + return m_nOutInterests; + } + + FaceStatus& + setNOutInterests(uint64_t nOutInterests); + + uint64_t + getNOutData() const + { + return m_nOutData; + } + + FaceStatus& + setNOutData(uint64_t nOutData); + + uint64_t + getNOutNacks() const + { + return m_nOutNacks; + } + + FaceStatus& + setNOutNacks(uint64_t nOutNacks); + + uint64_t + getNInBytes() const + { + return m_nInBytes; + } + + FaceStatus& + setNInBytes(uint64_t nInBytes); + + uint64_t + getNOutBytes() const + { + return m_nOutBytes; + } + + FaceStatus& + setNOutBytes(uint64_t nOutBytes); + +private: + optional m_expirationPeriod; + optional m_baseCongestionMarkingInterval; + optional m_defaultCongestionThreshold; + optional m_mtu; + uint64_t m_nInInterests; + uint64_t m_nInData; + uint64_t m_nInNacks; + uint64_t m_nOutInterests; + uint64_t m_nOutData; + uint64_t m_nOutNacks; + uint64_t m_nInBytes; + uint64_t m_nOutBytes; +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(FaceStatus); + +bool +operator==(const FaceStatus& a, const FaceStatus& b); + +inline bool +operator!=(const FaceStatus& a, const FaceStatus& b) +{ + return !(a == b); +} + +std::ostream& +operator<<(std::ostream& os, const FaceStatus& status); + +} // namespace nfd +} // namespace ndn + +#endif // NDN_MGMT_NFD_FACE_STATUS_HPP diff --git a/src/mgmt/nfd/face-traits.hpp b/ndn-cxx/mgmt/nfd/face-traits.hpp similarity index 80% rename from src/mgmt/nfd/face-traits.hpp rename to ndn-cxx/mgmt/nfd/face-traits.hpp index 48c262499..f685e71e7 100644 --- a/src/mgmt/nfd/face-traits.hpp +++ b/ndn-cxx/mgmt/nfd/face-traits.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,15 +22,16 @@ #ifndef NDN_MGMT_NFD_FACE_TRAITS_HPP #define NDN_MGMT_NFD_FACE_TRAITS_HPP -#include "../../encoding/tlv-nfd.hpp" +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/encoding/nfd-constants.hpp" namespace ndn { namespace nfd { -/** \ingroup management - * \brief providers getters and setters of face information fields - * \tparam C the concrete class; it must provide .wireReset() method - to clear wire encoding when a field changes +/** + * \ingroup management + * \brief provides getters and setters for face information fields + * \tparam C the concrete subclass */ template class FaceTraits @@ -39,22 +40,9 @@ class FaceTraits class Error : public tlv::Error { public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } + using tlv::Error::Error; }; - FaceTraits() - : m_faceId(0) - , m_faceScope(FACE_SCOPE_NON_LOCAL) - , m_facePersistency(FACE_PERSISTENCY_PERSISTENT) - , m_linkType(LINK_TYPE_POINT_TO_POINT) - , m_flags(0x0) - { - } - uint64_t getFaceId() const { @@ -64,7 +52,7 @@ class FaceTraits C& setFaceId(uint64_t faceId) { - wireReset(); + m_wire.reset(); m_faceId = faceId; return static_cast(*this); } @@ -78,7 +66,7 @@ class FaceTraits C& setRemoteUri(const std::string& remoteUri) { - wireReset(); + m_wire.reset(); m_remoteUri = remoteUri; return static_cast(*this); } @@ -92,7 +80,7 @@ class FaceTraits C& setLocalUri(const std::string& localUri) { - wireReset(); + m_wire.reset(); m_localUri = localUri; return static_cast(*this); } @@ -106,7 +94,7 @@ class FaceTraits C& setFaceScope(FaceScope faceScope) { - wireReset(); + m_wire.reset(); m_faceScope = faceScope; return static_cast(*this); } @@ -120,7 +108,7 @@ class FaceTraits C& setFacePersistency(FacePersistency facePersistency) { - wireReset(); + m_wire.reset(); m_facePersistency = facePersistency; return static_cast(*this); } @@ -134,7 +122,7 @@ class FaceTraits C& setLinkType(LinkType linkType) { - wireReset(); + m_wire.reset(); m_linkType = linkType; return static_cast(*this); } @@ -148,7 +136,7 @@ class FaceTraits C& setFlags(uint64_t flags) { - wireReset(); + m_wire.reset(); m_flags = flags; return static_cast(*this); } @@ -157,9 +145,8 @@ class FaceTraits getFlagBit(size_t bit) const { if (bit >= 64) { - BOOST_THROW_EXCEPTION(std::out_of_range("bit must be within range [0, 64)")); + NDN_THROW(std::out_of_range("bit must be within range [0, 64)")); } - return m_flags & (1 << bit); } @@ -167,10 +154,10 @@ class FaceTraits setFlagBit(size_t bit, bool value) { if (bit >= 64) { - BOOST_THROW_EXCEPTION(std::out_of_range("bit must be within range [0, 64)")); + NDN_THROW(std::out_of_range("bit must be within range [0, 64)")); } - wireReset(); + m_wire.reset(); if (value) { m_flags |= (1 << bit); @@ -183,8 +170,14 @@ class FaceTraits } protected: - virtual void - wireReset() const = 0; + FaceTraits() + : m_faceId(INVALID_FACE_ID) + , m_faceScope(FACE_SCOPE_NON_LOCAL) + , m_facePersistency(FACE_PERSISTENCY_PERSISTENT) + , m_linkType(LINK_TYPE_POINT_TO_POINT) + , m_flags(0) + { + } protected: uint64_t m_faceId; @@ -194,6 +187,8 @@ class FaceTraits FacePersistency m_facePersistency; LinkType m_linkType; uint64_t m_flags; + + mutable Block m_wire; }; } // namespace nfd diff --git a/ndn-cxx/mgmt/nfd/fib-entry.cpp b/ndn-cxx/mgmt/nfd/fib-entry.cpp new file mode 100644 index 000000000..e5438eb58 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/fib-entry.cpp @@ -0,0 +1,276 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/fib-entry.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/encoding/tlv-nfd.hpp" +#include "ndn-cxx/util/concepts.hpp" +#include "ndn-cxx/util/ostream-joiner.hpp" + +#include + +namespace ndn { +namespace nfd { + +BOOST_CONCEPT_ASSERT((StatusDatasetItem)); +BOOST_CONCEPT_ASSERT((StatusDatasetItem)); + +NextHopRecord::NextHopRecord() + : m_faceId(INVALID_FACE_ID) + , m_cost(0) +{ +} + +NextHopRecord::NextHopRecord(const Block& block) +{ + this->wireDecode(block); +} + +NextHopRecord& +NextHopRecord::setFaceId(uint64_t faceId) +{ + m_faceId = faceId; + m_wire.reset(); + return *this; +} + +NextHopRecord& +NextHopRecord::setCost(uint64_t cost) +{ + m_cost = cost; + m_wire.reset(); + return *this; +} + +template +size_t +NextHopRecord::wireEncode(EncodingImpl& block) const +{ + size_t totalLength = 0; + + totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::Cost, m_cost); + totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::FaceId, m_faceId); + + totalLength += block.prependVarNumber(totalLength); + totalLength += block.prependVarNumber(ndn::tlv::nfd::NextHopRecord); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(NextHopRecord); + +const Block& +NextHopRecord::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 +NextHopRecord::wireDecode(const Block& block) +{ + if (block.type() != tlv::nfd::NextHopRecord) { + NDN_THROW(Error("NextHopRecord", block.type())); + } + + m_wire = block; + m_wire.parse(); + auto val = m_wire.elements_begin(); + + if (val == m_wire.elements_end()) { + NDN_THROW(Error("unexpected end of NextHopRecord")); + } + else if (val->type() != tlv::nfd::FaceId) { + NDN_THROW(Error("FaceId", val->type())); + } + m_faceId = readNonNegativeInteger(*val); + ++val; + + if (val == m_wire.elements_end()) { + NDN_THROW(Error("unexpected end of NextHopRecord")); + } + else if (val->type() != tlv::nfd::Cost) { + NDN_THROW(Error("Cost", val->type())); + } + m_cost = readNonNegativeInteger(*val); + ++val; +} + +bool +operator==(const NextHopRecord& a, const NextHopRecord& b) +{ + return a.getFaceId() == b.getFaceId() && + a.getCost() == b.getCost(); +} + +std::ostream& +operator<<(std::ostream& os, const NextHopRecord& nh) +{ + return os << "NextHopRecord(" + << "FaceId: " << nh.getFaceId() << ", " + << "Cost: " << nh.getCost() + << ")"; +} + +//////////////////// + +FibEntry::FibEntry() = default; + +FibEntry::FibEntry(const Block& block) +{ + this->wireDecode(block); +} + +FibEntry& +FibEntry::setPrefix(const Name& prefix) +{ + m_prefix = prefix; + m_wire.reset(); + return *this; +} + +FibEntry& +FibEntry::addNextHopRecord(const NextHopRecord& nh) +{ + m_nextHopRecords.push_back(nh); + m_wire.reset(); + return *this; +} + +FibEntry& +FibEntry::clearNextHopRecords() +{ + m_nextHopRecords.clear(); + m_wire.reset(); + return *this; +} + +template +size_t +FibEntry::wireEncode(EncodingImpl& block) const +{ + size_t totalLength = 0; + + for (const auto& nh : m_nextHopRecords | boost::adaptors::reversed) { + totalLength += nh.wireEncode(block); + } + totalLength += m_prefix.wireEncode(block); + + totalLength += block.prependVarNumber(totalLength); + totalLength += block.prependVarNumber(tlv::nfd::FibEntry); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(FibEntry); + +const Block& +FibEntry::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 +FibEntry::wireDecode(const Block& block) +{ + if (block.type() != tlv::nfd::FibEntry) { + NDN_THROW(Error("FibEntry", block.type())); + } + + m_wire = block; + m_wire.parse(); + auto val = m_wire.elements_begin(); + + if (val == m_wire.elements_end()) { + NDN_THROW(Error("unexpected end of FibEntry")); + } + else if (val->type() != tlv::Name) { + NDN_THROW(Error("Name", val->type())); + } + m_prefix.wireDecode(*val); + ++val; + + m_nextHopRecords.clear(); + for (; val != m_wire.elements_end(); ++val) { + if (val->type() != tlv::nfd::NextHopRecord) { + NDN_THROW(Error("NextHopRecord", val->type())); + } + m_nextHopRecords.emplace_back(*val); + } +} + +bool +operator==(const FibEntry& a, const FibEntry& b) +{ + const auto& aNextHops = a.getNextHopRecords(); + const auto& bNextHops = b.getNextHopRecords(); + + if (a.getPrefix() != b.getPrefix() || + aNextHops.size() != bNextHops.size()) + return false; + + std::vector matched(bNextHops.size(), false); + return std::all_of(aNextHops.begin(), aNextHops.end(), + [&] (const NextHopRecord& nh) { + for (size_t i = 0; i < bNextHops.size(); ++i) { + if (!matched[i] && bNextHops[i] == nh) { + matched[i] = true; + return true; + } + } + return false; + }); +} + +std::ostream& +operator<<(std::ostream& os, const FibEntry& entry) +{ + os << "FibEntry(Prefix: " << entry.getPrefix() << ",\n" + << " NextHops: ["; + + std::copy(entry.getNextHopRecords().begin(), entry.getNextHopRecords().end(), + make_ostream_joiner(os, ",\n ")); + + os << "]\n"; + + return os << " )"; +} + +} // namespace nfd +} // namespace ndn diff --git a/ndn-cxx/mgmt/nfd/fib-entry.hpp b/ndn-cxx/mgmt/nfd/fib-entry.hpp new file mode 100644 index 000000000..74dd611af --- /dev/null +++ b/ndn-cxx/mgmt/nfd/fib-entry.hpp @@ -0,0 +1,179 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_MGMT_NFD_FIB_ENTRY_HPP +#define NDN_MGMT_NFD_FIB_ENTRY_HPP + +#include "ndn-cxx/name.hpp" +#include "ndn-cxx/encoding/block.hpp" + +namespace ndn { +namespace nfd { + +/** \ingroup management + * \sa https://redmine.named-data.net/projects/nfd/wiki/FibMgmt#FIB-Dataset + */ +class NextHopRecord +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + NextHopRecord(); + + explicit + NextHopRecord(const Block& block); + + uint64_t + getFaceId() const + { + return m_faceId; + } + + NextHopRecord& + setFaceId(uint64_t faceId); + + uint64_t + getCost() const + { + return m_cost; + } + + NextHopRecord& + setCost(uint64_t cost); + + template + size_t + wireEncode(EncodingImpl& block) const; + + const Block& + wireEncode() const; + + void + wireDecode(const Block& block); + +private: + uint64_t m_faceId; + uint64_t m_cost; + + mutable Block m_wire; +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(NextHopRecord); + +bool +operator==(const NextHopRecord& a, const NextHopRecord& b); + +inline bool +operator!=(const NextHopRecord& a, const NextHopRecord& b) +{ + return !(a == b); +} + +std::ostream& +operator<<(std::ostream& os, const NextHopRecord& nh); + + +/** \ingroup management + * \sa https://redmine.named-data.net/projects/nfd/wiki/FibMgmt#FIB-Dataset + */ +class FibEntry +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + FibEntry(); + + explicit + FibEntry(const Block& block); + + const Name& + getPrefix() const + { + return m_prefix; + } + + FibEntry& + setPrefix(const Name& prefix); + + const std::vector& + getNextHopRecords() const + { + return m_nextHopRecords; + } + + template + FibEntry& + setNextHopRecords(InputIt first, InputIt last) + { + m_nextHopRecords.assign(first, last); + m_wire.reset(); + return *this; + } + + FibEntry& + addNextHopRecord(const NextHopRecord& nh); + + FibEntry& + clearNextHopRecords(); + + template + size_t + wireEncode(EncodingImpl& block) const; + + const Block& + wireEncode() const; + + void + wireDecode(const Block& block); + +private: + Name m_prefix; + std::vector m_nextHopRecords; + + mutable Block m_wire; +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(FibEntry); + +bool +operator==(const FibEntry& a, const FibEntry& b); + +inline bool +operator!=(const FibEntry& a, const FibEntry& b) +{ + return !(a == b); +} + +std::ostream& +operator<<(std::ostream& os, const FibEntry& entry); + +} // namespace nfd +} // namespace ndn + +#endif // NDN_MGMT_NFD_FIB_ENTRY_HPP diff --git a/ndn-cxx/mgmt/nfd/forwarder-status.cpp b/ndn-cxx/mgmt/nfd/forwarder-status.cpp new file mode 100644 index 000000000..fc00be126 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/forwarder-status.cpp @@ -0,0 +1,417 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/forwarder-status.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/encoding/tlv-nfd.hpp" +#include "ndn-cxx/util/concepts.hpp" + +namespace ndn { +namespace nfd { + +BOOST_CONCEPT_ASSERT((StatusDatasetItem)); + +ForwarderStatus::ForwarderStatus() + : m_nNameTreeEntries(0) + , m_nFibEntries(0) + , m_nPitEntries(0) + , m_nMeasurementsEntries(0) + , m_nCsEntries(0) + , m_nInInterests(0) + , m_nInData(0) + , m_nInNacks(0) + , m_nOutInterests(0) + , m_nOutData(0) + , m_nOutNacks(0) + , m_nSatisfiedInterests(0) + , m_nUnsatisfiedInterests(0) +{ +} + +ForwarderStatus::ForwarderStatus(const Block& payload) +{ + this->wireDecode(payload); +} + +template +size_t +ForwarderStatus::wireEncode(EncodingImpl& encoder) const +{ + size_t totalLength = 0; + + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NUnsatisfiedInterests, m_nUnsatisfiedInterests); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NSatisfiedInterests, m_nSatisfiedInterests); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NOutNacks, m_nOutNacks); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NOutData, m_nOutData); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NOutInterests, m_nOutInterests); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NInNacks, m_nInNacks); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NInData, m_nInData); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NInInterests, m_nInInterests); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NCsEntries, m_nCsEntries); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NMeasurementsEntries, m_nMeasurementsEntries); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NPitEntries, m_nPitEntries); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NFibEntries, m_nFibEntries); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NNameTreeEntries, m_nNameTreeEntries); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::CurrentTimestamp, + time::toUnixTimestamp(m_currentTimestamp).count()); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::StartTimestamp, + time::toUnixTimestamp(m_startTimestamp).count()); + totalLength += prependStringBlock(encoder, tlv::nfd::NfdVersion, m_nfdVersion); + + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::Content); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(ForwarderStatus); + +const Block& +ForwarderStatus::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 +ForwarderStatus::wireDecode(const Block& block) +{ + if (block.type() != tlv::Content) { + NDN_THROW(Error("Content", block.type())); + } + + m_wire = block; + m_wire.parse(); + auto val = m_wire.elements_begin(); + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NfdVersion) { + m_nfdVersion = readString(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NfdVersion field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::StartTimestamp) { + m_startTimestamp = time::fromUnixTimestamp(time::milliseconds(readNonNegativeInteger(*val))); + ++val; + } + else { + NDN_THROW(Error("missing required StartTimestamp field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::CurrentTimestamp) { + m_currentTimestamp = time::fromUnixTimestamp(time::milliseconds(readNonNegativeInteger(*val))); + ++val; + } + else { + NDN_THROW(Error("missing required CurrentTimestamp field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NNameTreeEntries) { + m_nNameTreeEntries = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NNameTreeEntries field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NFibEntries) { + m_nFibEntries = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NFibEntries field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NPitEntries) { + m_nPitEntries = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NPitEntries field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NMeasurementsEntries) { + m_nMeasurementsEntries = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NMeasurementsEntries field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NCsEntries) { + m_nCsEntries = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NCsEntries field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInInterests) { + m_nInInterests = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NInInterests field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInData) { + m_nInData = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NInData field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInNacks) { + m_nInNacks = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NInNacks field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutInterests) { + m_nOutInterests = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NOutInterests field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutData) { + m_nOutData = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NOutData field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutNacks) { + m_nOutNacks = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NOutNacks field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NSatisfiedInterests) { + m_nSatisfiedInterests = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NSatisfiedInterests field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::NUnsatisfiedInterests) { + m_nUnsatisfiedInterests = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required NUnsatisfiedInterests field")); + } +} + +ForwarderStatus& +ForwarderStatus::setNfdVersion(const std::string& nfdVersion) +{ + m_wire.reset(); + m_nfdVersion = nfdVersion; + return *this; +} + +ForwarderStatus& +ForwarderStatus::setStartTimestamp(const time::system_clock::TimePoint& startTimestamp) +{ + m_wire.reset(); + m_startTimestamp = startTimestamp; + return *this; +} + +ForwarderStatus& +ForwarderStatus::setCurrentTimestamp(const time::system_clock::TimePoint& currentTimestamp) +{ + m_wire.reset(); + m_currentTimestamp = currentTimestamp; + return *this; +} + +ForwarderStatus& +ForwarderStatus::setNNameTreeEntries(uint64_t nNameTreeEntries) +{ + m_wire.reset(); + m_nNameTreeEntries = nNameTreeEntries; + return *this; +} + +ForwarderStatus& +ForwarderStatus::setNFibEntries(uint64_t nFibEntries) +{ + m_wire.reset(); + m_nFibEntries = nFibEntries; + return *this; +} + +ForwarderStatus& +ForwarderStatus::setNPitEntries(uint64_t nPitEntries) +{ + m_wire.reset(); + m_nPitEntries = nPitEntries; + return *this; +} + +ForwarderStatus& +ForwarderStatus::setNMeasurementsEntries(uint64_t nMeasurementsEntries) +{ + m_wire.reset(); + m_nMeasurementsEntries = nMeasurementsEntries; + return *this; +} + +ForwarderStatus& +ForwarderStatus::setNCsEntries(uint64_t nCsEntries) +{ + m_wire.reset(); + m_nCsEntries = nCsEntries; + return *this; +} + +ForwarderStatus& +ForwarderStatus::setNInInterests(uint64_t nInInterests) +{ + m_wire.reset(); + m_nInInterests = nInInterests; + return *this; +} + +ForwarderStatus& +ForwarderStatus::setNInData(uint64_t nInData) +{ + m_wire.reset(); + m_nInData = nInData; + return *this; +} + +ForwarderStatus& +ForwarderStatus::setNInNacks(uint64_t nInNacks) +{ + m_wire.reset(); + m_nInNacks = nInNacks; + return *this; +} + +ForwarderStatus& +ForwarderStatus::setNOutInterests(uint64_t nOutInterests) +{ + m_wire.reset(); + m_nOutInterests = nOutInterests; + return *this; +} + +ForwarderStatus& +ForwarderStatus::setNOutData(uint64_t nOutData) +{ + m_wire.reset(); + m_nOutData = nOutData; + return *this; +} + +ForwarderStatus& +ForwarderStatus::setNOutNacks(uint64_t nOutNacks) +{ + m_wire.reset(); + m_nOutNacks = nOutNacks; + return *this; +} + +ForwarderStatus& +ForwarderStatus::setNSatisfiedInterests(uint64_t nSatisfiedInterests) +{ + m_wire.reset(); + m_nSatisfiedInterests = nSatisfiedInterests; + return *this; +} + +ForwarderStatus& +ForwarderStatus::setNUnsatisfiedInterests(uint64_t nUnsatisfiedInterests) +{ + m_wire.reset(); + m_nUnsatisfiedInterests = nUnsatisfiedInterests; + return *this; +} + +bool +operator==(const ForwarderStatus& a, const ForwarderStatus& b) +{ + return a.getNfdVersion() == b.getNfdVersion() && + a.getStartTimestamp() == b.getStartTimestamp() && + a.getCurrentTimestamp() == b.getCurrentTimestamp() && + a.getNNameTreeEntries() == b.getNNameTreeEntries() && + a.getNFibEntries() == b.getNFibEntries() && + a.getNPitEntries() == b.getNPitEntries() && + a.getNMeasurementsEntries() == b.getNMeasurementsEntries() && + a.getNCsEntries() == b.getNCsEntries() && + a.getNInInterests() == b.getNInInterests() && + a.getNInData() == b.getNInData() && + a.getNInNacks() == b.getNInNacks() && + a.getNOutInterests() == b.getNOutInterests() && + a.getNOutData() == b.getNOutData() && + a.getNOutNacks() == b.getNOutNacks() && + a.getNSatisfiedInterests() == b.getNSatisfiedInterests() && + a.getNUnsatisfiedInterests() == b.getNUnsatisfiedInterests(); +} + +std::ostream& +operator<<(std::ostream& os, const ForwarderStatus& status) +{ + os << "GeneralStatus(NfdVersion: " << status.getNfdVersion() << ",\n" + << " StartTimestamp: " << status.getStartTimestamp() << ",\n" + << " CurrentTimestamp: " << status.getCurrentTimestamp() << ",\n" + << " Counters: {NameTreeEntries: " << status.getNNameTreeEntries() << ",\n" + << " FibEntries: " << status.getNFibEntries() << ",\n" + << " PitEntries: " << status.getNPitEntries() << ",\n" + << " MeasurementsEntries: " << status.getNMeasurementsEntries() << ",\n" + << " CsEntries: " << status.getNCsEntries() << ",\n" + << " Interests: {in: " << status.getNInInterests() << ", " + << "out: " << status.getNOutInterests() << "},\n" + << " Data: {in: " << status.getNInData() << ", " + << "out: " << status.getNOutData() << "},\n" + << " Nacks: {in: " << status.getNInNacks() << ", " + << "out: " << status.getNOutNacks() << "},\n" + << " SatisfiedInterests: " << status.getNSatisfiedInterests() << ",\n" + << " UnsatisfiedInterests: " << status.getNUnsatisfiedInterests() << "}\n" + << " )"; + + return os; +} + +} // namespace nfd +} // namespace ndn diff --git a/ndn-cxx/mgmt/nfd/forwarder-status.hpp b/ndn-cxx/mgmt/nfd/forwarder-status.hpp new file mode 100644 index 000000000..973533705 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/forwarder-status.hpp @@ -0,0 +1,255 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_MGMT_NFD_FORWARDER_STATUS_HPP +#define NDN_MGMT_NFD_FORWARDER_STATUS_HPP + +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/util/time.hpp" + +namespace ndn { +namespace nfd { + +/** + * \ingroup management + * \brief represents NFD General Status dataset + * \sa https://redmine.named-data.net/projects/nfd/wiki/ForwarderStatus#General-Status-Dataset + */ +class ForwarderStatus +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + ForwarderStatus(); + + explicit + ForwarderStatus(const Block& payload); + + /** \brief prepend ForwarderStatus as a Content block to the encoder + * + * The outermost Content element isn't part of ForwarderStatus structure. + */ + template + size_t + wireEncode(EncodingImpl& encoder) const; + + /** \brief encode ForwarderStatus as a Content block + * + * The outermost Content element isn't part of ForwarderStatus structure. + */ + const Block& + wireEncode() const; + + /** \brief decode ForwarderStatus from a Content block + * + * The outermost Content element isn't part of ForwarderStatus structure. + */ + void + wireDecode(const Block& wire); + +public: // getters & setters + const std::string& + getNfdVersion() const + { + return m_nfdVersion; + } + + ForwarderStatus& + setNfdVersion(const std::string& nfdVersion); + + const time::system_clock::TimePoint& + getStartTimestamp() const + { + return m_startTimestamp; + } + + ForwarderStatus& + setStartTimestamp(const time::system_clock::TimePoint& startTimestamp); + + const time::system_clock::TimePoint& + getCurrentTimestamp() const + { + return m_currentTimestamp; + } + + ForwarderStatus& + setCurrentTimestamp(const time::system_clock::TimePoint& currentTimestamp); + + uint64_t + getNNameTreeEntries() const + { + return m_nNameTreeEntries; + } + + ForwarderStatus& + setNNameTreeEntries(uint64_t nNameTreeEntries); + + uint64_t + getNFibEntries() const + { + return m_nFibEntries; + } + + ForwarderStatus& + setNFibEntries(uint64_t nFibEntries); + + uint64_t + getNPitEntries() const + { + return m_nPitEntries; + } + + ForwarderStatus& + setNPitEntries(uint64_t nPitEntries); + + uint64_t + getNMeasurementsEntries() const + { + return m_nMeasurementsEntries; + } + + ForwarderStatus& + setNMeasurementsEntries(uint64_t nMeasurementsEntries); + + uint64_t + getNCsEntries() const + { + return m_nCsEntries; + } + + ForwarderStatus& + setNCsEntries(uint64_t nCsEntries); + + uint64_t + getNInInterests() const + { + return m_nInInterests; + } + + ForwarderStatus& + setNInInterests(uint64_t nInInterests); + + uint64_t + getNInData() const + { + return m_nInData; + } + + ForwarderStatus& + setNInData(uint64_t nInData); + + uint64_t + getNInNacks() const + { + return m_nInNacks; + } + + ForwarderStatus& + setNInNacks(uint64_t nInNacks); + + uint64_t + getNOutInterests() const + { + return m_nOutInterests; + } + + ForwarderStatus& + setNOutInterests(uint64_t nOutInterests); + + uint64_t + getNOutData() const + { + return m_nOutData; + } + + ForwarderStatus& + setNOutData(uint64_t nOutData); + + uint64_t + getNOutNacks() const + { + return m_nOutNacks; + } + + ForwarderStatus& + setNOutNacks(uint64_t nOutNacks); + + uint64_t + getNSatisfiedInterests() const + { + return m_nSatisfiedInterests; + } + + ForwarderStatus& + setNSatisfiedInterests(uint64_t nSatisfiedInterests); + + uint64_t + getNUnsatisfiedInterests() const + { + return m_nUnsatisfiedInterests; + } + + ForwarderStatus& + setNUnsatisfiedInterests(uint64_t nUnsatisfiedInterests); + +private: + std::string m_nfdVersion; + time::system_clock::TimePoint m_startTimestamp; + time::system_clock::TimePoint m_currentTimestamp; + uint64_t m_nNameTreeEntries; + uint64_t m_nFibEntries; + uint64_t m_nPitEntries; + uint64_t m_nMeasurementsEntries; + uint64_t m_nCsEntries; + uint64_t m_nInInterests; + uint64_t m_nInData; + uint64_t m_nInNacks; + uint64_t m_nOutInterests; + uint64_t m_nOutData; + uint64_t m_nOutNacks; + uint64_t m_nSatisfiedInterests; + uint64_t m_nUnsatisfiedInterests; + + mutable Block m_wire; +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(ForwarderStatus); + +bool +operator==(const ForwarderStatus& a, const ForwarderStatus& b); + +inline bool +operator!=(const ForwarderStatus& a, const ForwarderStatus& b) +{ + return !(a == b); +} + +std::ostream& +operator<<(std::ostream& os, const ForwarderStatus& status); + +} // namespace nfd +} // namespace ndn + +#endif // NDN_MGMT_NFD_FORWARDER_STATUS_HPP diff --git a/ndn-cxx/mgmt/nfd/rib-entry.cpp b/ndn-cxx/mgmt/nfd/rib-entry.cpp new file mode 100644 index 000000000..a3551d0cb --- /dev/null +++ b/ndn-cxx/mgmt/nfd/rib-entry.cpp @@ -0,0 +1,355 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/rib-entry.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/encoding/tlv-nfd.hpp" +#include "ndn-cxx/util/concepts.hpp" +#include "ndn-cxx/util/ostream-joiner.hpp" +#include "ndn-cxx/util/string-helper.hpp" + +#include + +namespace ndn { +namespace nfd { + +BOOST_CONCEPT_ASSERT((StatusDatasetItem)); +BOOST_CONCEPT_ASSERT((StatusDatasetItem)); + +Route::Route() + : m_faceId(INVALID_FACE_ID) + , m_origin(ROUTE_ORIGIN_APP) + , m_cost(0) + , m_flags(ROUTE_FLAG_CHILD_INHERIT) +{ +} + +Route::Route(const Block& block) +{ + this->wireDecode(block); +} + +Route& +Route::setFaceId(uint64_t faceId) +{ + m_faceId = faceId; + m_wire.reset(); + return *this; +} + +Route& +Route::setOrigin(RouteOrigin origin) +{ + m_origin = origin; + m_wire.reset(); + return *this; +} + +Route& +Route::setCost(uint64_t cost) +{ + m_cost = cost; + m_wire.reset(); + return *this; +} + +Route& +Route::setFlags(uint64_t flags) +{ + m_flags = flags; + m_wire.reset(); + return *this; +} + +Route& +Route::setExpirationPeriod(time::milliseconds expirationPeriod) +{ + if (expirationPeriod == time::milliseconds::max()) + return unsetExpirationPeriod(); + + m_expirationPeriod = expirationPeriod; + m_wire.reset(); + return *this; +} + +Route& +Route::unsetExpirationPeriod() +{ + m_expirationPeriod = nullopt; + m_wire.reset(); + return *this; +} + +template +size_t +Route::wireEncode(EncodingImpl& block) const +{ + size_t totalLength = 0; + + if (m_expirationPeriod) { + totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::ExpirationPeriod, + static_cast(m_expirationPeriod->count())); + } + totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::Flags, m_flags); + totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::Cost, m_cost); + totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::Origin, m_origin); + totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::FaceId, m_faceId); + + totalLength += block.prependVarNumber(totalLength); + totalLength += block.prependVarNumber(ndn::tlv::nfd::Route); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Route); + +const Block& +Route::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 +Route::wireDecode(const Block& block) +{ + if (block.type() != tlv::nfd::Route) { + NDN_THROW(Error("Route", block.type())); + } + + m_wire = block; + m_wire.parse(); + auto val = m_wire.elements_begin(); + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceId) { + m_faceId = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required FaceId field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::Origin) { + m_origin = readNonNegativeIntegerAs(*val); + ++val; + } + else { + NDN_THROW(Error("missing required Origin field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::Cost) { + m_cost = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required Cost field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::Flags) { + m_flags = readNonNegativeInteger(*val); + ++val; + } + else { + NDN_THROW(Error("missing required Flags field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::ExpirationPeriod) { + m_expirationPeriod.emplace(readNonNegativeInteger(*val)); + ++val; + } + else { + m_expirationPeriod = nullopt; + } +} + +bool +operator==(const Route& a, const Route& b) +{ + return a.getFaceId() == b.getFaceId() && + a.getOrigin() == b.getOrigin() && + a.getCost() == b.getCost() && + a.getFlags() == b.getFlags() && + a.getExpirationPeriod() == b.getExpirationPeriod(); +} + +std::ostream& +operator<<(std::ostream& os, const Route& route) +{ + os << "Route(" + << "FaceId: " << route.getFaceId() << ", " + << "Origin: " << route.getOrigin() << ", " + << "Cost: " << route.getCost() << ", " + << "Flags: " << AsHex{route.getFlags()} << ", "; + + if (route.hasExpirationPeriod()) { + os << "ExpirationPeriod: " << route.getExpirationPeriod(); + } + else { + os << "ExpirationPeriod: infinite"; + } + + return os << ")"; +} + +//////////////////// + +RibEntry::RibEntry() = default; + +RibEntry::RibEntry(const Block& block) +{ + this->wireDecode(block); +} + +RibEntry& +RibEntry::setName(const Name& prefix) +{ + m_prefix = prefix; + m_wire.reset(); + return *this; +} + +RibEntry& +RibEntry::addRoute(const Route& route) +{ + m_routes.push_back(route); + m_wire.reset(); + return *this; +} + +RibEntry& +RibEntry::clearRoutes() +{ + m_routes.clear(); + m_wire.reset(); + return *this; +} + +template +size_t +RibEntry::wireEncode(EncodingImpl& block) const +{ + size_t totalLength = 0; + + for (const auto& route : m_routes | boost::adaptors::reversed) { + totalLength += route.wireEncode(block); + } + totalLength += m_prefix.wireEncode(block); + + totalLength += block.prependVarNumber(totalLength); + totalLength += block.prependVarNumber(tlv::nfd::RibEntry); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(RibEntry); + +const Block& +RibEntry::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 +RibEntry::wireDecode(const Block& block) +{ + if (block.type() != tlv::nfd::RibEntry) { + NDN_THROW(Error("RibEntry", block.type())); + } + + m_wire = block; + m_wire.parse(); + auto val = m_wire.elements_begin(); + + if (val == m_wire.elements_end()) { + NDN_THROW(Error("unexpected end of RibEntry")); + } + else if (val->type() != tlv::Name) { + NDN_THROW(Error("Name", val->type())); + } + m_prefix.wireDecode(*val); + ++val; + + m_routes.clear(); + for (; val != m_wire.elements_end(); ++val) { + if (val->type() != tlv::nfd::Route) { + NDN_THROW(Error("Route", val->type())); + } + m_routes.emplace_back(*val); + } +} + +bool +operator==(const RibEntry& a, const RibEntry& b) +{ + const auto& aRoutes = a.getRoutes(); + const auto& bRoutes = b.getRoutes(); + + if (a.getName() != b.getName() || + aRoutes.size() != bRoutes.size()) + return false; + + std::vector matched(bRoutes.size(), false); + return std::all_of(aRoutes.begin(), aRoutes.end(), + [&] (const Route& route) { + for (size_t i = 0; i < bRoutes.size(); ++i) { + if (!matched[i] && bRoutes[i] == route) { + matched[i] = true; + return true; + } + } + return false; + }); +} + +std::ostream& +operator<<(std::ostream& os, const RibEntry& entry) +{ + os << "RibEntry(Prefix: " << entry.getName() << ",\n" + << " Routes: ["; + + std::copy(entry.getRoutes().begin(), entry.getRoutes().end(), + make_ostream_joiner(os, ",\n ")); + + os << "]\n"; + + return os << " )"; +} + +} // namespace nfd +} // namespace ndn diff --git a/ndn-cxx/mgmt/nfd/rib-entry.hpp b/ndn-cxx/mgmt/nfd/rib-entry.hpp new file mode 100644 index 000000000..2745be676 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/rib-entry.hpp @@ -0,0 +1,231 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_MGMT_NFD_RIB_ENTRY_HPP +#define NDN_MGMT_NFD_RIB_ENTRY_HPP + +#include "ndn-cxx/name.hpp" +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/mgmt/nfd/route-flags-traits.hpp" +#include "ndn-cxx/util/time.hpp" + +namespace ndn { +namespace nfd { + +/** + * \ingroup management + * \brief represents a route in a RibEntry + * + * A route indicates the availability of content via a certain face and + * provides meta-information about the face. + * + * \sa https://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Route + */ +class Route : public RouteFlagsTraits +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + Route(); + + explicit + Route(const Block& block); + + uint64_t + getFaceId() const + { + return m_faceId; + } + + Route& + setFaceId(uint64_t faceId); + + RouteOrigin + getOrigin() const + { + return m_origin; + } + + Route& + setOrigin(RouteOrigin origin); + + uint64_t + getCost() const + { + return m_cost; + } + + Route& + setCost(uint64_t cost); + + uint64_t + getFlags() const + { + return m_flags; + } + + Route& + setFlags(uint64_t flags); + + bool + hasExpirationPeriod() const + { + return !!m_expirationPeriod; + } + + time::milliseconds + getExpirationPeriod() const + { + return m_expirationPeriod ? *m_expirationPeriod : time::milliseconds::max(); + } + + Route& + setExpirationPeriod(time::milliseconds expirationPeriod); + + Route& + unsetExpirationPeriod(); + + template + size_t + wireEncode(EncodingImpl& block) const; + + const Block& + wireEncode() const; + + void + wireDecode(const Block& block); + +private: + uint64_t m_faceId; + RouteOrigin m_origin; + uint64_t m_cost; + uint64_t m_flags; + optional m_expirationPeriod; + + mutable Block m_wire; +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(Route); + +bool +operator==(const Route& a, const Route& b); + +inline bool +operator!=(const Route& a, const Route& b) +{ + return !(a == b); +} + +std::ostream& +operator<<(std::ostream& os, const Route& route); + + +/** + * \ingroup management + * \brief represents an item in NFD RIB dataset + * + * A RIB entry contains one or more routes for a name prefix + * + * \sa https://redmine.named-data.net/projects/nfd/wiki/RibMgmt#RIB-Dataset + */ +class RibEntry +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + RibEntry(); + + explicit + RibEntry(const Block& block); + + const Name& + getName() const + { + return m_prefix; + } + + RibEntry& + setName(const Name& prefix); + + const std::vector& + getRoutes() const + { + return m_routes; + } + + template + RibEntry& + setRoutes(InputIt first, InputIt last) + { + m_routes.assign(first, last); + m_wire.reset(); + return *this; + } + + RibEntry& + addRoute(const Route& route); + + RibEntry& + clearRoutes(); + + template + size_t + wireEncode(EncodingImpl& block) const; + + const Block& + wireEncode() const; + + void + wireDecode(const Block& block); + +private: + Name m_prefix; + std::vector m_routes; + + mutable Block m_wire; +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(RibEntry); + +bool +operator==(const RibEntry& a, const RibEntry& b); + +inline bool +operator!=(const RibEntry& a, const RibEntry& b) +{ + return !(a == b); +} + +std::ostream& +operator<<(std::ostream& os, const RibEntry& entry); + +} // namespace nfd +} // namespace ndn + +#endif // NDN_MGMT_NFD_RIB_ENTRY_HPP diff --git a/ndn-cxx/mgmt/nfd/route-flags-traits.hpp b/ndn-cxx/mgmt/nfd/route-flags-traits.hpp new file mode 100644 index 000000000..8eff4c562 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/route-flags-traits.hpp @@ -0,0 +1,60 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_MGMT_NFD_ROUTE_FLAGS_TRAITS_HPP +#define NDN_MGMT_NFD_ROUTE_FLAGS_TRAITS_HPP + +#include "ndn-cxx/encoding/nfd-constants.hpp" + +namespace ndn { +namespace nfd { + +/** + * \ingroup management + * \brief defines getters for each route inheritance flag + * + * \tparam T class containing a RouteFlags field and implementing + * a `RouteFlags getFlags() const` member function + */ +template +class RouteFlagsTraits +{ +public: + bool + isChildInherit() const + { + return static_cast(this)->getFlags() & ROUTE_FLAG_CHILD_INHERIT; + } + + bool + isRibCapture() const + { + return static_cast(this)->getFlags() & ROUTE_FLAG_CAPTURE; + } + +protected: + RouteFlagsTraits() = default; +}; + +} // namespace nfd +} // namespace ndn + +#endif // NDN_MGMT_NFD_ROUTE_FLAGS_TRAITS_HPP diff --git a/src/mgmt/nfd/status-dataset.cpp b/ndn-cxx/mgmt/nfd/status-dataset.cpp similarity index 80% rename from src/mgmt/nfd/status-dataset.cpp rename to ndn-cxx/mgmt/nfd/status-dataset.cpp index ca5f5df95..3d2a3d362 100644 --- a/src/mgmt/nfd/status-dataset.cpp +++ b/ndn-cxx/mgmt/nfd/status-dataset.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,8 +19,8 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "status-dataset.hpp" -#include "../../util/concepts.hpp" +#include "ndn-cxx/mgmt/nfd/status-dataset.hpp" +#include "ndn-cxx/util/concepts.hpp" namespace ndn { namespace nfd { @@ -30,6 +30,8 @@ StatusDataset::StatusDataset(const PartialName& datasetName) { } +StatusDataset::~StatusDataset() = default; + Name StatusDataset::getDatasetPrefix(const Name& prefix) const { @@ -65,7 +67,7 @@ parseDatasetVector(ConstBufferPtr payload) Block block; std::tie(isOk, block) = Block::fromBuffer(payload, offset); if (!isOk) { - BOOST_THROW_EXCEPTION(StatusDataset::ParseResultError("cannot decode Block")); + NDN_THROW(StatusDataset::ParseResultError("cannot decode Block")); } offset += block.size(); @@ -83,7 +85,7 @@ ForwarderGeneralStatusDataset::ForwarderGeneralStatusDataset() ForwarderGeneralStatusDataset::ResultType ForwarderGeneralStatusDataset::parseResult(ConstBufferPtr payload) const { - return ForwarderStatus(Block(tlv::Content, payload)); + return ForwarderStatus(Block(tlv::Content, std::move(payload))); } FaceDatasetBase::FaceDatasetBase(const PartialName& datasetName) @@ -94,7 +96,7 @@ FaceDatasetBase::FaceDatasetBase(const PartialName& datasetName) FaceDatasetBase::ResultType FaceDatasetBase::parseResult(ConstBufferPtr payload) const { - return parseDatasetVector(payload); + return parseDatasetVector(std::move(payload)); } FaceDataset::FaceDataset() @@ -122,7 +124,7 @@ ChannelDataset::ChannelDataset() ChannelDataset::ResultType ChannelDataset::parseResult(ConstBufferPtr payload) const { - return parseDatasetVector(payload); + return parseDatasetVector(std::move(payload)); } FibDataset::FibDataset() @@ -133,7 +135,18 @@ FibDataset::FibDataset() FibDataset::ResultType FibDataset::parseResult(ConstBufferPtr payload) const { - return parseDatasetVector(payload); + return parseDatasetVector(std::move(payload)); +} + +CsInfoDataset::CsInfoDataset() + : StatusDataset("cs/info") +{ +} + +CsInfoDataset::ResultType +CsInfoDataset::parseResult(ConstBufferPtr payload) const +{ + return CsInfo(Block(std::move(payload))); } StrategyChoiceDataset::StrategyChoiceDataset() @@ -144,7 +157,7 @@ StrategyChoiceDataset::StrategyChoiceDataset() StrategyChoiceDataset::ResultType StrategyChoiceDataset::parseResult(ConstBufferPtr payload) const { - return parseDatasetVector(payload); + return parseDatasetVector(std::move(payload)); } RibDataset::RibDataset() @@ -155,7 +168,7 @@ RibDataset::RibDataset() RibDataset::ResultType RibDataset::parseResult(ConstBufferPtr payload) const { - return parseDatasetVector(payload); + return parseDatasetVector(std::move(payload)); } } // namespace nfd diff --git a/ndn-cxx/mgmt/nfd/status-dataset.hpp b/ndn-cxx/mgmt/nfd/status-dataset.hpp new file mode 100644 index 000000000..d80cd40ac --- /dev/null +++ b/ndn-cxx/mgmt/nfd/status-dataset.hpp @@ -0,0 +1,259 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_MGMT_NFD_STATUS_DATASET_HPP +#define NDN_MGMT_NFD_STATUS_DATASET_HPP + +#include "ndn-cxx/name.hpp" +#include "ndn-cxx/mgmt/nfd/forwarder-status.hpp" +#include "ndn-cxx/mgmt/nfd/face-status.hpp" +#include "ndn-cxx/mgmt/nfd/face-query-filter.hpp" +#include "ndn-cxx/mgmt/nfd/channel-status.hpp" +#include "ndn-cxx/mgmt/nfd/fib-entry.hpp" +#include "ndn-cxx/mgmt/nfd/cs-info.hpp" +#include "ndn-cxx/mgmt/nfd/strategy-choice.hpp" +#include "ndn-cxx/mgmt/nfd/rib-entry.hpp" + +namespace ndn { +namespace nfd { + +/** + * \ingroup management + * \brief base class of NFD StatusDataset + * \sa https://redmine.named-data.net/projects/nfd/wiki/StatusDataset + */ +class StatusDataset : noncopyable +{ +public: + virtual + ~StatusDataset(); + +#ifdef DOXYGEN + /** + * \brief if defined, specifies constructor argument type; + * otherwise, constructor has no argument + */ + using ParamType = int; +#endif + + /** + * \brief constructs a name prefix for the dataset + * \param prefix top-level prefix, such as ndn:/localhost/nfd + * \return name prefix without version and segment components + */ + Name + getDatasetPrefix(const Name& prefix) const; + +#ifdef DOXYGEN + /** + * \brief provides the result type, usually a vector + */ + using ResultType = std::vector; +#endif + + /** + * \brief indicates reassembled payload cannot be parsed as ResultType + */ + class ParseResultError : public tlv::Error + { + public: + using tlv::Error::Error; + }; + +#ifdef DOXYGEN + /** + * \brief parses a result from reassembled payload + * \param payload reassembled payload + * \throw tlv::Error cannot parse payload + */ + ResultType + parseResult(ConstBufferPtr payload) const; +#endif + +protected: + /** + * \brief constructs a StatusDataset instance with given sub-prefix + * \param datasetName dataset name after top-level prefix, such as faces/list + */ + explicit + StatusDataset(const PartialName& datasetName); + +private: + /** + * \brief appends parameters to the dataset name prefix + * \param[in,out] the dataset name prefix onto which parameter components can be appended + */ + virtual void + addParameters(Name& name) const; + +private: + PartialName m_datasetName; +}; + +/** + * \ingroup management + * \brief represents a status/general dataset + * \sa https://redmine.named-data.net/projects/nfd/wiki/ForwarderStatus#General-Status-Dataset + */ +class ForwarderGeneralStatusDataset : public StatusDataset +{ +public: + ForwarderGeneralStatusDataset(); + + using ResultType = ForwarderStatus; + + ResultType + parseResult(ConstBufferPtr payload) const; +}; + +/** + * \ingroup management + * \brief provides common functionality among FaceDataset and FaceQueryDataset + */ +class FaceDatasetBase : public StatusDataset +{ +public: + using ResultType = std::vector; + + ResultType + parseResult(ConstBufferPtr payload) const; + +protected: + explicit + FaceDatasetBase(const PartialName& datasetName); +}; + +/** + * \ingroup management + * \brief represents a faces/list dataset + * \sa https://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Face-Dataset + */ +class FaceDataset : public FaceDatasetBase +{ +public: + FaceDataset(); +}; + +/** + * \ingroup management + * \brief represents a faces/query dataset + * \sa https://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Query-Operation + */ +class FaceQueryDataset : public FaceDatasetBase +{ +public: + using ParamType = FaceQueryFilter; + + explicit + FaceQueryDataset(const FaceQueryFilter& filter); + +private: + void + addParameters(Name& name) const override; + +private: + FaceQueryFilter m_filter; +}; + +/** + * \ingroup management + * \brief represents a faces/channels dataset + * \sa https://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Channel-Dataset + */ +class ChannelDataset : public StatusDataset +{ +public: + ChannelDataset(); + + using ResultType = std::vector; + + ResultType + parseResult(ConstBufferPtr payload) const; +}; + +/** + * \ingroup management + * \brief represents a fib/list dataset + * \sa https://redmine.named-data.net/projects/nfd/wiki/FibMgmt#FIB-Dataset + */ +class FibDataset : public StatusDataset +{ +public: + FibDataset(); + + using ResultType = std::vector; + + ResultType + parseResult(ConstBufferPtr payload) const; +}; + +/** + * \ingroup management + * \brief represents a cs/info dataset + * \sa https://redmine.named-data.net/projects/nfd/wiki/CsMgmt#CS-Information-Dataset + */ +class CsInfoDataset : public StatusDataset +{ +public: + CsInfoDataset(); + + using ResultType = CsInfo; + + ResultType + parseResult(ConstBufferPtr payload) const; +}; + +/** + * \ingroup management + * \brief represents a strategy-choice/list dataset + * \sa https://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Strategy-Choice-Dataset + */ +class StrategyChoiceDataset : public StatusDataset +{ +public: + StrategyChoiceDataset(); + + using ResultType = std::vector; + + ResultType + parseResult(ConstBufferPtr payload) const; +}; + +/** + * \ingroup management + * \brief represents a rib/list dataset + * \sa https://redmine.named-data.net/projects/nfd/wiki/RibMgmt#RIB-Dataset + */ +class RibDataset : public StatusDataset +{ +public: + RibDataset(); + + using ResultType = std::vector; + + ResultType + parseResult(ConstBufferPtr payload) const; +}; + +} // namespace nfd +} // namespace ndn + +#endif // NDN_MGMT_NFD_STATUS_DATASET_HPP diff --git a/ndn-cxx/mgmt/nfd/strategy-choice.cpp b/ndn-cxx/mgmt/nfd/strategy-choice.cpp new file mode 100644 index 000000000..c2a752440 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/strategy-choice.cpp @@ -0,0 +1,138 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/strategy-choice.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/encoding/tlv-nfd.hpp" +#include "ndn-cxx/util/concepts.hpp" + +namespace ndn { +namespace nfd { + +BOOST_CONCEPT_ASSERT((StatusDatasetItem)); + +StrategyChoice::StrategyChoice() = default; + +StrategyChoice::StrategyChoice(const Block& payload) +{ + this->wireDecode(payload); +} + +template +size_t +StrategyChoice::wireEncode(EncodingImpl& encoder) const +{ + size_t totalLength = 0; + + totalLength += prependNestedBlock(encoder, tlv::nfd::Strategy, m_strategy); + totalLength += m_name.wireEncode(encoder); + + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::nfd::StrategyChoice); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(StrategyChoice); + +const Block& +StrategyChoice::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 +StrategyChoice::wireDecode(const Block& block) +{ + if (block.type() != tlv::nfd::StrategyChoice) { + NDN_THROW(Error("StrategyChoice", block.type())); + } + + m_wire = block; + m_wire.parse(); + auto val = m_wire.elements_begin(); + + if (val != m_wire.elements_end() && val->type() == tlv::Name) { + m_name.wireDecode(*val); + ++val; + } + else { + NDN_THROW(Error("missing required Name field")); + } + + if (val != m_wire.elements_end() && val->type() == tlv::nfd::Strategy) { + val->parse(); + if (val->elements().empty()) { + NDN_THROW(Error("expecting Strategy/Name")); + } + else { + m_strategy.wireDecode(*val->elements_begin()); + } + ++val; + } + else { + NDN_THROW(Error("missing required Strategy field")); + } +} + +StrategyChoice& +StrategyChoice::setName(const Name& name) +{ + m_wire.reset(); + m_name = name; + return *this; +} + +StrategyChoice& +StrategyChoice::setStrategy(const Name& strategy) +{ + m_wire.reset(); + m_strategy = strategy; + return *this; +} + +bool +operator==(const StrategyChoice& a, const StrategyChoice& b) +{ + return a.getName() == b.getName() && a.getStrategy() == b.getStrategy(); +} + +std::ostream& +operator<<(std::ostream& os, const StrategyChoice& sc) +{ + return os << "StrategyChoice(" + << "Name: " << sc.getName() << ", " + << "Strategy: " << sc.getStrategy() + << ")"; +} + +} // namespace nfd +} // namespace ndn diff --git a/ndn-cxx/mgmt/nfd/strategy-choice.hpp b/ndn-cxx/mgmt/nfd/strategy-choice.hpp new file mode 100644 index 000000000..d6c71d4d3 --- /dev/null +++ b/ndn-cxx/mgmt/nfd/strategy-choice.hpp @@ -0,0 +1,103 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_MGMT_NFD_STRATEGY_CHOICE_HPP +#define NDN_MGMT_NFD_STRATEGY_CHOICE_HPP + +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/name.hpp" + +namespace ndn { +namespace nfd { + +/** + * \ingroup management + * \brief represents an item in NFD StrategyChoice dataset + * \sa https://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Strategy-Choice-Dataset + */ +class StrategyChoice +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + StrategyChoice(); + + explicit + StrategyChoice(const Block& payload); + + template + size_t + wireEncode(EncodingImpl& encoder) const; + + const Block& + wireEncode() const; + + void + wireDecode(const Block& wire); + +public: // getters & setters + const Name& + getName() const + { + return m_name; + } + + StrategyChoice& + setName(const Name& name); + + const Name& + getStrategy() const + { + return m_strategy; + } + + StrategyChoice& + setStrategy(const Name& strategy); + +private: + Name m_name; // namespace + Name m_strategy; // strategy for the namespace + + mutable Block m_wire; +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(StrategyChoice); + +bool +operator==(const StrategyChoice& a, const StrategyChoice& b); + +inline bool +operator!=(const StrategyChoice& a, const StrategyChoice& b) +{ + return !(a == b); +} + +std::ostream& +operator<<(std::ostream& os, const StrategyChoice& sc); + +} // namespace nfd +} // namespace ndn + +#endif // NDN_MGMT_NFD_STRATEGY_CHOICE_HPP diff --git a/src/mgmt/status-dataset-context.cpp b/ndn-cxx/mgmt/status-dataset-context.cpp similarity index 85% rename from src/mgmt/status-dataset-context.cpp rename to ndn-cxx/mgmt/status-dataset-context.cpp index dbf6774f9..048706122 100644 --- a/src/mgmt/status-dataset-context.cpp +++ b/ndn-cxx/mgmt/status-dataset-context.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,12 +19,12 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "status-dataset-context.hpp" +#include "ndn-cxx/mgmt/status-dataset-context.hpp" namespace ndn { namespace mgmt { -const time::milliseconds DEFAULT_STATUS_DATASET_FRESHNESS_PERIOD = time::milliseconds(1000); +const time::milliseconds DEFAULT_STATUS_DATASET_FRESHNESS_PERIOD = 1_s; const Name& StatusDatasetContext::getPrefix() const @@ -36,11 +36,11 @@ StatusDatasetContext& StatusDatasetContext::setPrefix(const Name& prefix) { if (!m_interest.getName().isPrefixOf(prefix)) { - BOOST_THROW_EXCEPTION(std::invalid_argument("prefix does not start with Interest Name")); + NDN_THROW(std::invalid_argument("prefix does not start with Interest Name")); } if (m_state != State::INITIAL) { - BOOST_THROW_EXCEPTION(std::domain_error("state is not in INITIAL")); + NDN_THROW(std::domain_error("state is not in INITIAL")); } m_prefix = prefix; @@ -69,7 +69,7 @@ void StatusDatasetContext::append(const Block& block) { if (m_state == State::FINALIZED) { - BOOST_THROW_EXCEPTION(std::domain_error("state is in FINALIZED")); + NDN_THROW(std::domain_error("state is in FINALIZED")); } m_state = State::RESPONDED; @@ -86,7 +86,7 @@ StatusDatasetContext::append(const Block& block) makeBinaryBlock(tlv::Content, m_buffer->buf(), m_buffer->size()), m_expiry, false); - m_buffer = std::make_shared(); + m_buffer = make_shared(); } } } @@ -95,11 +95,10 @@ void StatusDatasetContext::end() { if (m_state == State::FINALIZED) { - BOOST_THROW_EXCEPTION(std::domain_error("state is in FINALIZED")); + NDN_THROW(std::domain_error("state is in FINALIZED")); } m_state = State::FINALIZED; - m_dataSender(Name(m_prefix).appendSegment(m_segmentNo), makeBinaryBlock(tlv::Content, m_buffer->buf(), m_buffer->size()), m_expiry, true); @@ -109,11 +108,10 @@ void StatusDatasetContext::reject(const ControlResponse& resp /*= a ControlResponse with 400*/) { if (m_state != State::INITIAL) { - BOOST_THROW_EXCEPTION(std::domain_error("state is in REPONSED or FINALIZED")); + NDN_THROW(std::domain_error("state is in RESPONDED or FINALIZED")); } m_state = State::FINALIZED; - m_nackSender(resp); } diff --git a/src/mgmt/status-dataset-context.hpp b/ndn-cxx/mgmt/status-dataset-context.hpp similarity index 94% rename from src/mgmt/status-dataset-context.hpp rename to ndn-cxx/mgmt/status-dataset-context.hpp index 42ad0c1ee..2fb07f9bd 100644 --- a/src/mgmt/status-dataset-context.hpp +++ b/ndn-cxx/mgmt/status-dataset-context.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,11 +22,11 @@ #ifndef NDN_MGMT_STATUS_DATASET_CONTEXT_HPP #define NDN_MGMT_STATUS_DATASET_CONTEXT_HPP -#include "../interest.hpp" -#include "../data.hpp" -#include "../util/time.hpp" -#include "../encoding/encoding-buffer.hpp" -#include "control-response.hpp" +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/mgmt/control-response.hpp" +#include "ndn-cxx/util/time.hpp" namespace ndn { namespace mgmt { diff --git a/ndn-cxx/name-component.cpp b/ndn-cxx/name-component.cpp new file mode 100644 index 000000000..4338cc42e --- /dev/null +++ b/ndn-cxx/name-component.cpp @@ -0,0 +1,541 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Jeff Thompson + * @author Alexander Afanasyev + * @author Zhenkai Zhu + */ + +#include "ndn-cxx/name-component.hpp" +#include "ndn-cxx/impl/name-component-types.hpp" + +#include +#include +#include + +namespace ndn { +namespace name { + +BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); +BOOST_CONCEPT_ASSERT((WireEncodable)); +BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); +BOOST_CONCEPT_ASSERT((WireDecodable)); +static_assert(std::is_base_of::value, + "name::Component::Error must inherit from tlv::Error"); + +static Convention g_conventionEncoding = Convention::MARKER; +static Convention g_conventionDecoding = Convention::EITHER; + +Convention +getConventionEncoding() +{ + return g_conventionEncoding; +} + +void +setConventionEncoding(Convention convention) +{ + switch (convention) { + case Convention::MARKER: + case Convention::TYPED: + g_conventionEncoding = convention; + break; + default: + NDN_THROW(std::invalid_argument("Unknown naming convention")); + } +} + +Convention +getConventionDecoding() +{ + return g_conventionDecoding; +} + +void +setConventionDecoding(Convention convention) +{ + g_conventionDecoding = convention; +} + +static bool +canDecodeMarkerConvention() +{ + return (to_underlying(g_conventionDecoding) & to_underlying(Convention::MARKER)) != 0; +} + +static bool +canDecodeTypedConvention() +{ + return (to_underlying(g_conventionDecoding) & to_underlying(Convention::TYPED)) != 0; +} + +static bool +chooseAltUri(UriFormat format) +{ + if (format == UriFormat::DEFAULT) { + static const char* env = std::getenv("NDN_NAME_ALT_URI"); + static bool defaultSetting = env == nullptr || env[0] != '0'; + return defaultSetting; + } + return format == UriFormat::ALTERNATE; +} + +void +Component::ensureValid() const +{ + if (type() < tlv::NameComponentMin || type() > tlv::NameComponentMax) { + NDN_THROW(Error("TLV-TYPE " + to_string(type()) + " is not a valid NameComponent")); + } + detail::getComponentTypeTable().get(type()).check(*this); +} + +Component::Component(uint32_t type) + : Block(type) +{ + ensureValid(); +} + +Component::Component(const Block& wire) + : Block(wire) +{ + ensureValid(); +} + +Component::Component(uint32_t type, ConstBufferPtr buffer) + : Block(type, std::move(buffer)) +{ + ensureValid(); +} + +Component::Component(uint32_t type, const uint8_t* value, size_t valueLen) + : Block(makeBinaryBlock(type, value, valueLen)) +{ + ensureValid(); +} + +Component::Component(const char* str) + : Block(makeBinaryBlock(tlv::GenericNameComponent, str, std::char_traits::length(str))) +{ +} + +Component::Component(const std::string& str) + : Block(makeStringBlock(tlv::GenericNameComponent, str)) +{ +} + +static Component +parseUriEscapedValue(uint32_t type, const char* input, size_t len) +{ + std::ostringstream oss; + unescape(oss, input, len); + std::string value = oss.str(); + if (value.find_first_not_of('.') == std::string::npos) { // all periods + if (value.size() < 3) { + NDN_THROW(Component::Error("Illegal URI (name component cannot be . or ..)")); + } + return Component(type, reinterpret_cast(value.data()), value.size() - 3); + } + return Component(type, reinterpret_cast(value.data()), value.size()); +} + +Component +Component::fromEscapedString(const std::string& input) +{ + size_t equalPos = input.find('='); + if (equalPos == std::string::npos) { + return parseUriEscapedValue(tlv::GenericNameComponent, input.data(), input.size()); + } + + auto typePrefix = input.substr(0, equalPos); + auto type = std::strtoul(typePrefix.data(), nullptr, 10); + if (type >= tlv::NameComponentMin && type <= tlv::NameComponentMax && + to_string(type) == typePrefix) { + size_t valuePos = equalPos + 1; + return parseUriEscapedValue(static_cast(type), + input.data() + valuePos, input.size() - valuePos); + } + + auto ct = detail::getComponentTypeTable().findByUriPrefix(typePrefix); + if (ct == nullptr) { + NDN_THROW(Error("Unknown TLV-TYPE '" + typePrefix + "' in NameComponent URI")); + } + return ct->parseAltUriValue(input.substr(equalPos + 1)); +} + +void +Component::toUri(std::ostream& os, UriFormat format) const +{ + if (chooseAltUri(format)) { + detail::getComponentTypeTable().get(type()).writeUri(os, *this); + } + else { + detail::ComponentType().writeUri(os, *this); + } +} + +std::string +Component::toUri(UriFormat format) const +{ + std::ostringstream os; + toUri(os, format); + return os.str(); +} + +//////////////////////////////////////////////////////////////////////////////// + +bool +Component::isNumber() const +{ + return value_size() == 1 || value_size() == 2 || + value_size() == 4 || value_size() == 8; +} + +bool +Component::isNumberWithMarker(uint8_t marker) const +{ + return (value_size() == 2 || value_size() == 3 || + value_size() == 5 || value_size() == 9) && value()[0] == marker; +} + +bool +Component::isVersion() const +{ + return (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent && isNumberWithMarker(VERSION_MARKER)) || + (canDecodeTypedConvention() && type() == tlv::VersionNameComponent && isNumber()); +} + +bool +Component::isSegment() const +{ + return (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent && isNumberWithMarker(SEGMENT_MARKER)) || + (canDecodeTypedConvention() && type() == tlv::SegmentNameComponent && isNumber()); +} + +bool +Component::isByteOffset() const +{ + return (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent && isNumberWithMarker(SEGMENT_OFFSET_MARKER)) || + (canDecodeTypedConvention() && type() == tlv::ByteOffsetNameComponent && isNumber()); +} + +bool +Component::isTimestamp() const +{ + return (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent && isNumberWithMarker(TIMESTAMP_MARKER)) || + (canDecodeTypedConvention() && type() == tlv::TimestampNameComponent && isNumber()); +} + +bool +Component::isSequenceNumber() const +{ + return (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent && isNumberWithMarker(SEQUENCE_NUMBER_MARKER)) || + (canDecodeTypedConvention() && type() == tlv::SequenceNumNameComponent && isNumber()); +} + +//////////////////////////////////////////////////////////////////////////////// + +uint64_t +Component::toNumber() const +{ + if (!isNumber()) + NDN_THROW(Error("Name component does not have nonNegativeInteger value")); + + return readNonNegativeInteger(*this); +} + +uint64_t +Component::toNumberWithMarker(uint8_t marker) const +{ + if (!isNumberWithMarker(marker)) + NDN_THROW(Error("Name component does not have the requested marker " + "or the value is not a nonNegativeInteger")); + + Buffer::const_iterator valueBegin = value_begin() + 1; + return tlv::readNonNegativeInteger(value_size() - 1, valueBegin, value_end()); +} + +uint64_t +Component::toVersion() const +{ + if (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent) { + return toNumberWithMarker(VERSION_MARKER); + } + if (canDecodeTypedConvention() && type() == tlv::VersionNameComponent) { + return toNumber(); + } + NDN_THROW(Error("Not a Version component")); +} + +uint64_t +Component::toSegment() const +{ + if (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent) { + return toNumberWithMarker(SEGMENT_MARKER); + } + if (canDecodeTypedConvention() && type() == tlv::SegmentNameComponent) { + return toNumber(); + } + NDN_THROW(Error("Not a Segment component")); +} + +uint64_t +Component::toByteOffset() const +{ + if (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent) { + return toNumberWithMarker(SEGMENT_OFFSET_MARKER); + } + if (canDecodeTypedConvention() && type() == tlv::ByteOffsetNameComponent) { + return toNumber(); + } + NDN_THROW(Error("Not a ByteOffset component")); +} + +time::system_clock::TimePoint +Component::toTimestamp() const +{ + uint64_t value = 0; + if (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent) { + value = toNumberWithMarker(TIMESTAMP_MARKER); + } + else if (canDecodeTypedConvention() && type() == tlv::TimestampNameComponent) { + value = toNumber(); + } + else { + NDN_THROW(Error("Not a Timestamp component")); + } + return time::getUnixEpoch() + time::microseconds(value); +} + +uint64_t +Component::toSequenceNumber() const +{ + if (canDecodeMarkerConvention() && type() == tlv::GenericNameComponent) { + return toNumberWithMarker(SEQUENCE_NUMBER_MARKER); + } + if (canDecodeTypedConvention() && type() == tlv::SequenceNumNameComponent) { + return toNumber(); + } + NDN_THROW(Error("Not a SequenceNumber component")); +} + +//////////////////////////////////////////////////////////////////////////////// + +Component +Component::fromNumber(uint64_t number, uint32_t type) +{ + return makeNonNegativeIntegerBlock(type, number); +} + +Component +Component::fromNumberWithMarker(uint8_t marker, uint64_t number) +{ + EncodingEstimator estimator; + + size_t valueLength = estimator.prependNonNegativeInteger(number); + valueLength += estimator.prependByteArray(&marker, 1); + size_t totalLength = valueLength; + totalLength += estimator.prependVarNumber(valueLength); + totalLength += estimator.prependVarNumber(tlv::GenericNameComponent); + + EncodingBuffer encoder(totalLength, 0); + encoder.prependNonNegativeInteger(number); + encoder.prependByteArray(&marker, 1); + encoder.prependVarNumber(valueLength); + encoder.prependVarNumber(tlv::GenericNameComponent); + + return encoder.block(); +} + +Component +Component::fromVersion(uint64_t version) +{ + return g_conventionEncoding == Convention::MARKER ? + fromNumberWithMarker(VERSION_MARKER, version) : + fromNumber(version, tlv::VersionNameComponent); +} + +Component +Component::fromSegment(uint64_t segmentNo) +{ + return g_conventionEncoding == Convention::MARKER ? + fromNumberWithMarker(SEGMENT_MARKER, segmentNo) : + fromNumber(segmentNo, tlv::SegmentNameComponent); +} + +Component +Component::fromByteOffset(uint64_t offset) +{ + return g_conventionEncoding == Convention::MARKER ? + fromNumberWithMarker(SEGMENT_OFFSET_MARKER, offset) : + fromNumber(offset, tlv::ByteOffsetNameComponent); +} + +Component +Component::fromTimestamp(const time::system_clock::TimePoint& timePoint) +{ + uint64_t value = time::duration_cast(timePoint - time::getUnixEpoch()).count(); + return g_conventionEncoding == Convention::MARKER ? + fromNumberWithMarker(TIMESTAMP_MARKER, value) : + fromNumber(value, tlv::TimestampNameComponent); +} + +Component +Component::fromSequenceNumber(uint64_t seqNo) +{ + return g_conventionEncoding == Convention::MARKER ? + fromNumberWithMarker(SEQUENCE_NUMBER_MARKER, seqNo) : + fromNumber(seqNo, tlv::SequenceNumNameComponent); +} + +//////////////////////////////////////////////////////////////////////////////// + +bool +Component::isGeneric() const +{ + return type() == tlv::GenericNameComponent; +} + +bool +Component::isImplicitSha256Digest() const +{ + return detail::getComponentType1().match(*this); +} + +Component +Component::fromImplicitSha256Digest(ConstBufferPtr digest) +{ + return detail::getComponentType1().create(digest); +} + +Component +Component::fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize) +{ + return detail::getComponentType1().create(digest, digestSize); +} + +bool +Component::isParametersSha256Digest() const +{ + return detail::getComponentType2().match(*this); +} + +Component +Component::fromParametersSha256Digest(ConstBufferPtr digest) +{ + return detail::getComponentType2().create(digest); +} + +Component +Component::fromParametersSha256Digest(const uint8_t* digest, size_t digestSize) +{ + return detail::getComponentType2().create(digest, digestSize); +} + +//////////////////////////////////////////////////////////////////////////////// + +bool +Component::equals(const Component& other) const +{ + return type() == other.type() && + value_size() == other.value_size() && + (empty() || // needed with Apple clang < 9.0.0 due to libc++ bug + std::equal(value_begin(), value_end(), other.value_begin())); +} + +int +Component::compare(const Component& other) const +{ + if (this->hasWire() && other.hasWire()) { + // In the common case where both components have wire encoding, + // it's more efficient to simply compare the wire encoding. + // This works because lexical order of TLV encoding happens to be + // the same as canonical order of the value. + return std::memcmp(wire(), other.wire(), std::min(size(), other.size())); + } + + int cmpType = type() - other.type(); + if (cmpType != 0) + return cmpType; + + int cmpSize = value_size() - other.value_size(); + if (cmpSize != 0) + return cmpSize; + + if (empty()) + return 0; + + return std::memcmp(value(), other.value(), value_size()); +} + +Component +Component::getSuccessor() const +{ + bool isOverflow = false; + Component successor; + std::tie(isOverflow, successor) = + detail::getComponentTypeTable().get(type()).getSuccessor(*this); + if (!isOverflow) { + return successor; + } + + uint32_t type = this->type() + 1; + const std::vector& value = detail::getComponentTypeTable().get(type).getMinValue(); + return Component(type, value.data(), value.size()); +} + +template +size_t +Component::wireEncode(EncodingImpl& encoder) const +{ + size_t totalLength = 0; + if (value_size() > 0) + totalLength += encoder.prependByteArray(value(), value_size()); + totalLength += encoder.prependVarNumber(value_size()); + totalLength += encoder.prependVarNumber(type()); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Component); + +const Block& +Component::wireEncode() const +{ + if (this->hasWire()) + return *this; + + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer); + + const_cast(*this) = buffer.block(); + return *this; +} + +void +Component::wireDecode(const Block& wire) +{ + *this = wire; + // validity check is done within Component(const Block& wire) +} + +} // namespace name +} // namespace ndn diff --git a/ndn-cxx/name-component.hpp b/ndn-cxx/name-component.hpp new file mode 100644 index 000000000..5f891101e --- /dev/null +++ b/ndn-cxx/name-component.hpp @@ -0,0 +1,660 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_NAME_COMPONENT_HPP +#define NDN_NAME_COMPONENT_HPP + +#include "ndn-cxx/detail/common.hpp" +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/util/time.hpp" + +namespace ndn { +namespace name { + +/** @brief Identify a format of URI representation. + */ +enum class UriFormat { + DEFAULT, ///< ALTERNATE, unless `NDN_NAME_ALT_URI` environment variable is set to '0' + CANONICAL, ///< always use = format + ALTERNATE, ///< prefer alternate format when available +}; + +/** @brief Identify a style of NDN Naming Conventions. + * @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/ + */ +enum class Convention { + MARKER = 1 << 0, ///< component markers (revision 1) + TYPED = 1 << 1, ///< typed name components (revision 2) + EITHER = MARKER | TYPED, +}; + +/** @brief Markers in Naming Conventions rev1 + */ +enum : uint8_t { + SEGMENT_MARKER = 0x00, + SEGMENT_OFFSET_MARKER = 0xFB, + VERSION_MARKER = 0xFD, + TIMESTAMP_MARKER = 0xFC, + SEQUENCE_NUMBER_MARKER = 0xFE, +}; + +/** @brief Return which Naming Conventions style to use while encoding. + * + * The current library default is Convention::MARKER, but this will change in the future. + */ +Convention +getConventionEncoding(); + +/** @brief Set which Naming Conventions style to use while encoding. + * @param convention either Convention::MARKER or Convention::TYPED. + */ +void +setConventionEncoding(Convention convention); + +/** @brief Return which Naming Conventions style(s) to accept while decoding. + * + * The current library default is Convention::EITHER, but this will change in the future. + */ +Convention +getConventionDecoding(); + +/** @brief Set which Naming Conventions style(s) to accept while decoding. + * @param convention Convention::MARKER or Convention::TYPED accepts the specified style only; + * Convention::EITHER accepts either. + */ +void +setConventionDecoding(Convention convention); + +/** @brief Represents a name component. + * + * The @c Component class provides a read-only view of a @c Block interpreted as a name component. + * Although it inherits mutation methods from @c Block base class, they must not be used, because + * the enclosing @c Name would not be updated correctly. + */ +class Component : public Block +{ +public: + class Error : public Block::Error + { + public: + using Block::Error::Error; + }; + +public: // constructors + /** + * @brief Construct a NameComponent of TLV-TYPE @p type, using empty TLV-VALUE. + * @throw Error the NameComponent is invalid (see @c ensureValid). + */ + explicit + Component(uint32_t type = tlv::GenericNameComponent); + + /** + * @brief Construct a NameComponent from @p block. + * @throw Error the NameComponent is invalid (see @c ensureValid). + * + * This contructor enables implicit conversion from @c Block. + */ + Component(const Block& wire); + + /** + * @brief Construct a NameComponent of TLV-TYPE @p type, using TLV-VALUE from @p buffer. + * @throw Error the NameComponent is invalid (see @c ensureValid). + * + * This constructor does not copy the underlying buffer, but retains a pointer to it. + * Therefore, the caller must not change the underlying buffer. + */ + Component(uint32_t type, ConstBufferPtr buffer); + + /** + * @brief Construct a GenericNameComponent, using TLV-VALUE from @p buffer. + * @throw Error the NameComponent is invalid (see @c ensureValid). + * + * This constructor does not copy the underlying buffer, but retains a pointer to it. + * Therefore, the caller must not change the underlying buffer. + */ + explicit + Component(ConstBufferPtr buffer) + : Component(tlv::GenericNameComponent, std::move(buffer)) + { + } + + /** + * @brief Construct a NameComponent of TLV-TYPE @p type, copying TLV-VALUE from @p buffer. + */ + Component(uint32_t type, const Buffer& buffer) + : Component(type, buffer.data(), buffer.size()) + { + } + + /** + * @brief Construct a GenericNameComponent, copying TLV-VALUE from @p buffer. + */ + explicit + Component(const Buffer& buffer) + : Component(tlv::GenericNameComponent, buffer) + { + } + + /** + * @brief Construct a NameComponent of TLV-TYPE @p type, copying @p count bytes at @p value as + * TLV-VALUE. + */ + Component(uint32_t type, const uint8_t* value, size_t count); + + /** + * @brief Construct a GenericNameComponent, copying @p count bytes at @p value as TLV-VALUE. + */ + Component(const uint8_t* value, size_t count) + : Component(tlv::GenericNameComponent, value, count) + { + } + + /** + * @brief Construct a NameComponent of TLV-TYPE @p type, copying TLV-VALUE from a range. + * @tparam Iterator an @c InputIterator dereferencing to a one-octet value type. More efficient + * implementation is available when it is a @c RandomAccessIterator. + * @param type the TLV-TYPE. + * @param first beginning of the range. + * @param last past-end of the range. + */ + template + Component(uint32_t type, Iterator first, Iterator last) + : Block(makeBinaryBlock(type, first, last)) + { + } + + /** + * @brief Construct a GenericNameComponent, copying TLV-VALUE from a range. + */ + template + Component(Iterator first, Iterator last) + : Component(tlv::GenericNameComponent, first, last) + { + } + + /** + * @brief Construct a GenericNameComponent, copying TLV-VALUE from a null-terminated string. + * + * Bytes from the string are copied as is, and not interpreted as URI component. + */ + explicit + Component(const char* str); + + /** + * @brief Construct a GenericNameComponent, copying TLV-VALUE from a string. + * + * Bytes from the string are copied as is, and not interpreted as URI component. + */ + explicit + Component(const std::string& str); + +public: // encoding and URI + /** + * @brief Fast encoding or block size estimation + */ + template + size_t + wireEncode(EncodingImpl& encoder) const; + + /** + * @brief Encode to a wire format + */ + const Block& + wireEncode() const; + + /** + * @brief Decode from the wire format + */ + void + wireDecode(const Block& wire); + + /** + * @brief Decode NameComponent from a URI component. + * + * The URI component is read from `[input+beginOffset, input+endOffset)` range. + * + * @throw Error URI component does not represent a valid NameComponent. + */ + static Component + fromEscapedString(const char* input, size_t beginOffset, size_t endOffset) + { + return fromEscapedString(std::string(input + beginOffset, input + endOffset)); + } + + /** + * @brief Decode NameComponent from a URI component. + * @throw Error URI component does not represent a valid NameComponent. + */ + static Component + fromEscapedString(const char* input) + { + return fromEscapedString(std::string(input)); + } + + /** + * @brief Decode NameComponent from a URI component. + * @throw Error URI component does not represent a valid NameComponent. + */ + static Component + fromEscapedString(const std::string& input); + + /** + * @brief Write *this to the output stream, escaping characters according to the NDN URI format. + * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme + */ + void + toUri(std::ostream& os, UriFormat format = UriFormat::DEFAULT) const; + + /** + * @brief Convert *this by escaping characters according to the NDN URI format. + * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme + */ + std::string + toUri(UriFormat format = UriFormat::DEFAULT) const; + +public: // naming conventions + /** + * @brief Check if the component is a nonNegativeInteger + * @sa https://named-data.net/doc/NDN-packet-spec/current/tlv.html#non-negative-integer-encoding + */ + bool + isNumber() const; + + /** + * @brief Check if the component is a NameComponentWithMarker per NDN naming conventions rev1 + * @sa NDN Naming Conventions revision 1: + * https://named-data.net/wp-content/uploads/2014/08/ndn-tr-22-ndn-memo-naming-conventions.pdf + */ + bool + isNumberWithMarker(uint8_t marker) const; + + /** + * @brief Check if the component is a version per NDN naming conventions + * @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/ + */ + bool + isVersion() const; + + /** + * @brief Check if the component is a segment number per NDN naming conventions + * @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/ + */ + bool + isSegment() const; + + /** + * @brief Check if the component is a byte offset per NDN naming conventions + * @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/ + */ + bool + isByteOffset() const; + + /// @deprecated use isByteOffset + bool + isSegmentOffset() const + { + return isByteOffset(); + } + + /** + * @brief Check if the component is a timestamp per NDN naming conventions + * @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/ + */ + bool + isTimestamp() const; + + /** + * @brief Check if the component is a sequence number per NDN naming conventions + * @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/ + */ + bool + isSequenceNumber() const; + + /** + * @brief Interpret this name component as nonNegativeInteger + * + * @sa https://named-data.net/doc/NDN-packet-spec/current/tlv.html#non-negative-integer-encoding + * + * @return The integer number. + */ + uint64_t + toNumber() const; + + /** + * @brief Interpret this name component as NameComponentWithMarker + * + * @sa NDN Naming Conventions revision 1: + * https://named-data.net/wp-content/uploads/2014/08/ndn-tr-22-ndn-memo-naming-conventions.pdf + * + * @param marker 1-byte octet of the marker + * @return The integer number. + * @throws Error if name component does not have the specified marker. + * tlv::Error if format does not follow NameComponentWithMarker specification. + */ + uint64_t + toNumberWithMarker(uint8_t marker) const; + + /** + * @brief Interpret as version component using NDN naming conventions + * + * @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/ + * + * @throw tlv::Error not a Version component interpreted by the chosen convention(s). + */ + uint64_t + toVersion() const; + + /** + * @brief Interpret as segment number component using NDN naming conventions + * + * @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/ + * + * @throw tlv::Error not a Segment component interpreted by the chosen convention(s). + */ + uint64_t + toSegment() const; + + /** + * @brief Interpret as byte offset component using NDN naming conventions + * + * @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/ + * + * @throw tlv::Error not a ByteOffset component interpreted by the chosen convention(s). + */ + uint64_t + toByteOffset() const; + + /// @deprecated use toByteOffset + uint64_t + toSegmentOffset() const + { + return toByteOffset(); + } + + /** + * @brief Interpret as timestamp component using NDN naming conventions + * + * @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/ + * + * @throw tlv::Error not a Timestamp component interpreted by the chosen convention(s). + */ + time::system_clock::TimePoint + toTimestamp() const; + + /** + * @brief Interpret as sequence number component using NDN naming conventions + * + * @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/ + * + * @throw tlv::Error not a SequenceNumber component interpreted by the chosen convention(s). + */ + uint64_t + toSequenceNumber() const; + + /** + * @brief Create a component encoded as nonNegativeInteger + * + * @sa https://named-data.net/doc/NDN-packet-spec/current/tlv.html#non-negative-integer-encoding + * + * @param number The non-negative number + * @param type TLV-TYPE + */ + static Component + fromNumber(uint64_t number, uint32_t type = tlv::GenericNameComponent); + + /** + * @brief Create a component encoded as NameComponentWithMarker + * + * NameComponentWithMarker is defined as: + * + * NameComponentWithMarker ::= NAME-COMPONENT-TYPE TLV-LENGTH + * Marker + * includedNonNegativeInteger + * Marker ::= BYTE + * includedNonNegativeInteger ::= BYTE{1,2,4,8} + * + * @sa NDN Naming Conventions revision 1: + * https://named-data.net/wp-content/uploads/2014/08/ndn-tr-22-ndn-memo-naming-conventions.pdf + * + * @param marker 1-byte marker octet + * @param number The non-negative number + */ + static Component + fromNumberWithMarker(uint8_t marker, uint64_t number); + + /** + * @brief Create version component using NDN naming conventions + * + * @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/ + */ + static Component + fromVersion(uint64_t version); + + /** + * @brief Create segment number component using NDN naming conventions + * + * @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/ + */ + static Component + fromSegment(uint64_t segmentNo); + + /** + * @brief Create byte offset component using NDN naming conventions + * + * @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/ + */ + static Component + fromByteOffset(uint64_t offset); + + /// @deprecated use fromByteOffset + static Component + fromSegmentOffset(uint64_t offset) + { + return fromByteOffset(offset); + } + + /** + * @brief Create sequence number component using NDN naming conventions + * + * @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/ + */ + static Component + fromTimestamp(const time::system_clock::TimePoint& timePoint); + + /** + * @brief Create sequence number component using NDN naming conventions + * + * @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/ + */ + static Component + fromSequenceNumber(uint64_t seqNo); + +public: // commonly used TLV-TYPEs + /** + * @brief Check if the component is GenericComponent + */ + bool + isGeneric() const; + + /** + * @brief Check if the component is ImplicitSha256DigestComponent + */ + bool + isImplicitSha256Digest() const; + + /** + * @brief Create ImplicitSha256DigestComponent component + */ + static Component + fromImplicitSha256Digest(ConstBufferPtr digest); + + /** + * @brief Create ImplicitSha256DigestComponent component + */ + static Component + fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize); + + /** + * @brief Check if the component is ParametersSha256DigestComponent + */ + bool + isParametersSha256Digest() const; + + /** + * @brief Create ParametersSha256DigestComponent component + */ + static Component + fromParametersSha256Digest(ConstBufferPtr digest); + + /** + * @brief Create ParametersSha256DigestComponent component + */ + static Component + fromParametersSha256Digest(const uint8_t* digest, size_t digestSize); + +public: // comparison + NDN_CXX_NODISCARD bool + empty() const + { + return value_size() == 0; + } + + /** + * @brief Check if this is the same component as other + * + * @param other The other Component to compare with + * @return true if the components are equal, otherwise false. + */ + bool + equals(const Component& other) const; + + /** + * @brief Compare this to the other Component using NDN canonical ordering + * + * @param other The other Component to compare with. + * @retval negative this comes before other in canonical ordering + * @retval zero this equals other + * @retval positive this comes after other in canonical ordering + * + * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#canonical-order + */ + int + compare(const Component& other) const; + + /** + * @brief Get the successor of this name component. + * + * The successor of a name component is defined as follows: + * + * C represents the set of name components, and X,Y ∈ C. + * Operator < is defined by canonical order on C. + * Y is the successor of X, if (a) X < Y, and (b) ∄ Z ∈ C s.t. X < Z < Y. + * + * In plain words, successor of a name component is the next possible name component. + * + * Examples: + * + * - successor of `sha256digest=0000000000000000000000000000000000000000000000000000000000000000` + * is `sha256digest=0000000000000000000000000000000000000000000000000000000000000001`. + * - successor of `sha256digest=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff` + * is `params-sha256=0000000000000000000000000000000000000000000000000000000000000000`. + * - successor of `params-sha256=0000000000000000000000000000000000000000000000000000000000000000` + * is `params-sha256=0000000000000000000000000000000000000000000000000000000000000001`. + * - successor of `params-sha256=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff` + * is `3=...`. + * - successor of `...` is `%00`. + * - successor of `A` is `B`. + * - successor of `%FF` is `%00%00`. + */ + Component + getSuccessor() const; + +private: + /** + * @brief Throw Error if this Component is invalid. + * + * A name component is invalid if its TLV-TYPE is outside the [1, 65535] range. + * Additionally, if it is an ImplicitSha256DigestComponent or a ParametersSha256DigestComponent, + * its TLV-LENGTH must be 32. + */ + void + ensureValid() const; + +private: // non-member operators + // NOTE: the following "hidden friend" operators are available via + // argument-dependent lookup only and must be defined inline. + + friend bool + operator==(const Component& lhs, const Component& rhs) + { + return lhs.equals(rhs); + } + + friend bool + operator!=(const Component& lhs, const Component& rhs) + { + return !lhs.equals(rhs); + } + + friend bool + operator<(const Component& lhs, const Component& rhs) + { + return lhs.compare(rhs) < 0; + } + + friend bool + operator<=(const Component& lhs, const Component& rhs) + { + return lhs.compare(rhs) <= 0; + } + + friend bool + operator>(const Component& lhs, const Component& rhs) + { + return lhs.compare(rhs) > 0; + } + + friend bool + operator>=(const Component& lhs, const Component& rhs) + { + return lhs.compare(rhs) >= 0; + } + + friend std::ostream& + operator<<(std::ostream& os, const Component& component) + { + component.toUri(os); + return os; + } + + // !!! NOTE TO IMPLEMENTOR !!! + // + // This class MUST NOT contain any data fields. + // Block can be reinterpret_cast'ed as Component type. +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(Component); + +} // namespace name +} // namespace ndn + +#endif // NDN_NAME_COMPONENT_HPP diff --git a/ndn-cxx/name.cpp b/ndn-cxx/name.cpp new file mode 100644 index 000000000..9763f251d --- /dev/null +++ b/ndn-cxx/name.cpp @@ -0,0 +1,390 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Jeff Thompson + * @author Alexander Afanasyev + * @author Zhenkai Zhu + */ + +#include "ndn-cxx/name.hpp" +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/util/time.hpp" + +#include +#include +#include +#include + +namespace ndn { + +BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); +BOOST_CONCEPT_ASSERT((WireEncodable)); +BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); +BOOST_CONCEPT_ASSERT((WireDecodable)); +BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator)); +BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator)); +BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator)); +BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator)); +BOOST_CONCEPT_ASSERT((boost::RandomAccessRangeConcept)); +static_assert(std::is_base_of::value, + "Name::Error must inherit from tlv::Error"); + +const size_t Name::npos = std::numeric_limits::max(); + +// ---- constructors, encoding, decoding ---- + +Name::Name() + : m_wire(tlv::Name) +{ +} + +Name::Name(const Block& wire) + : m_wire(wire) +{ + m_wire.parse(); +} + +Name::Name(const char* uri) + : Name(std::string(uri)) +{ +} + +Name::Name(std::string uri) +{ + if (uri.empty()) + return; + + size_t iColon = uri.find(':'); + if (iColon != std::string::npos) { + // Make sure the colon came before a '/'. + size_t iFirstSlash = uri.find('/'); + if (iFirstSlash == std::string::npos || iColon < iFirstSlash) { + // Omit the leading protocol such as ndn: + uri.erase(0, iColon + 1); + } + } + + // Trim the leading slash and possibly the authority. + if (uri[0] == '/') { + if (uri.size() >= 2 && uri[1] == '/') { + // Strip the authority following "//". + size_t iAfterAuthority = uri.find('/', 2); + if (iAfterAuthority == std::string::npos) + // Unusual case: there was only an authority. + return; + else { + uri.erase(0, iAfterAuthority + 1); + } + } + else { + uri.erase(0, 1); + } + } + + size_t iComponentStart = 0; + + // Unescape the components. + while (iComponentStart < uri.size()) { + size_t iComponentEnd = uri.find("/", iComponentStart); + if (iComponentEnd == std::string::npos) + iComponentEnd = uri.size(); + + append(Component::fromEscapedString(&uri[0], iComponentStart, iComponentEnd)); + iComponentStart = iComponentEnd + 1; + } +} + +template +size_t +Name::wireEncode(EncodingImpl& encoder) const +{ + size_t totalLength = 0; + for (const Component& comp : *this | boost::adaptors::reversed) { + totalLength += comp.wireEncode(encoder); + } + + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::Name); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Name); + +const Block& +Name::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(); + m_wire.parse(); + + return m_wire; +} + +void +Name::wireDecode(const Block& wire) +{ + if (wire.type() != tlv::Name) + NDN_THROW(tlv::Error("Name", wire.type())); + + m_wire = wire; + m_wire.parse(); +} + +Name +Name::deepCopy() const +{ + Name copiedName(*this); + copiedName.m_wire.resetWire(); + copiedName.wireEncode(); // "compress" the underlying buffer + return copiedName; +} + +// ---- accessors ---- + +const name::Component& +Name::at(ssize_t i) const +{ + if (i < 0) { + i += static_cast(size()); + } + + if (i < 0 || static_cast(i) >= size()) { + NDN_THROW(Error("Requested component does not exist (out of bounds)")); + } + + return reinterpret_cast(m_wire.elements()[i]); +} + +PartialName +Name::getSubName(ssize_t iStartComponent, size_t nComponents) const +{ + PartialName result; + + if (iStartComponent < 0) + iStartComponent += static_cast(size()); + size_t iStart = iStartComponent < 0 ? 0 : static_cast(iStartComponent); + + size_t iEnd = size(); + if (nComponents != npos) + iEnd = std::min(size(), iStart + nComponents); + + for (size_t i = iStart; i < iEnd; ++i) + result.append(at(i)); + + return result; +} + +// ---- modifiers ---- + +Name& +Name::set(ssize_t i, const Component& component) +{ + if (i < 0) { + i += static_cast(size()); + } + + const_cast(m_wire.elements())[i] = component; + m_wire.resetWire(); + return *this; +} + +Name& +Name::set(ssize_t i, Component&& component) +{ + if (i < 0) { + i += static_cast(size()); + } + + const_cast(m_wire.elements())[i] = std::move(component); + m_wire.resetWire(); + return *this; +} + +Name& +Name::appendVersion(optional version) +{ + return append(Component::fromVersion(version.value_or(time::toUnixTimestamp(time::system_clock::now()).count()))); +} + +Name& +Name::appendTimestamp(optional timestamp) +{ + return append(Component::fromTimestamp(timestamp.value_or(time::system_clock::now()))); +} + +Name& +Name::append(const PartialName& name) +{ + if (&name == this) + // Copying from this name, so need to make a copy first. + return append(PartialName(name)); + + for (size_t i = 0; i < name.size(); ++i) + append(name.at(i)); + + return *this; +} + +static constexpr uint8_t SHA256_OF_EMPTY_STRING[] = { + 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, + 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, + 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, + 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55, +}; + +Name& +Name::appendParametersSha256DigestPlaceholder() +{ + static const Component placeholder(tlv::ParametersSha256DigestComponent, + SHA256_OF_EMPTY_STRING, sizeof(SHA256_OF_EMPTY_STRING)); + return append(placeholder); +} + +void +Name::erase(ssize_t i) +{ + if (i < 0) { + i += static_cast(size()); + } + + m_wire.erase(m_wire.elements_begin() + i); +} + +void +Name::clear() +{ + m_wire = Block(tlv::Name); +} + +// ---- algorithms ---- + +Name +Name::getSuccessor() const +{ + if (empty()) { + static const Name n("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000"); + return n; + } + + return getPrefix(-1).append(get(-1).getSuccessor()); +} + +bool +Name::isPrefixOf(const Name& other) const +{ + // This name is longer than the name we are checking against. + if (size() > other.size()) + return false; + + // Check if at least one of given components doesn't match. + for (size_t i = 0; i < size(); ++i) { + if (get(i) != other.get(i)) + return false; + } + + return true; +} + +bool +Name::equals(const Name& other) const +{ + if (size() != other.size()) + return false; + + for (size_t i = 0; i < size(); ++i) { + if (get(i) != other.get(i)) + return false; + } + + return true; +} + +int +Name::compare(size_t pos1, size_t count1, const Name& other, size_t pos2, size_t count2) const +{ + count1 = std::min(count1, this->size() - pos1); + count2 = std::min(count2, other.size() - pos2); + size_t count = std::min(count1, count2); + + for (size_t i = 0; i < count; ++i) { + int comp = get(pos1 + i).compare(other.get(pos2 + i)); + if (comp != 0) { // i-th component differs + return comp; + } + } + // [pos1, pos1+count) of this Name equals [pos2, pos2+count) of other Name + return count1 - count2; +} + +// ---- URI representation ---- + +void +Name::toUri(std::ostream& os, name::UriFormat format) const +{ + if (empty()) { + os << "/"; + return; + } + + for (const auto& component : *this) { + os << "/"; + component.toUri(os, format); + } +} + +std::string +Name::toUri(name::UriFormat format) const +{ + std::ostringstream os; + toUri(os, format); + return os.str(); +} + +std::istream& +operator>>(std::istream& is, Name& name) +{ + std::string inputString; + is >> inputString; + name = Name(inputString); + + return is; +} + +} // namespace ndn + +namespace std { + +size_t +hash::operator()(const ndn::Name& name) const +{ + return boost::hash_range(name.wireEncode().wire(), + name.wireEncode().wire() + name.wireEncode().size()); +} + +} // namespace std diff --git a/ndn-cxx/name.hpp b/ndn-cxx/name.hpp new file mode 100644 index 000000000..d1c9c8d03 --- /dev/null +++ b/ndn-cxx/name.hpp @@ -0,0 +1,685 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Jeff Thompson + * @author Alexander Afanasyev + * @author Zhenkai Zhu + */ + +#ifndef NDN_NAME_HPP +#define NDN_NAME_HPP + +#include "ndn-cxx/name-component.hpp" + +#include + +namespace ndn { + +class Name; + +/** @brief Represents an arbitrary sequence of name components + */ +using PartialName = Name; + +/** @brief Represents an absolute name + */ +class Name +{ +public: // nested types + using Error = name::Component::Error; + + using Component = name::Component; + using component_container = std::vector; + + // Name appears as a container of name components + using value_type = Component; + using allocator_type = void; + using reference = Component&; + using const_reference = const Component&; + using pointer = Component*; + using const_pointer = const Component*; + using iterator = const Component*; // disallow modifying via iterator + using const_iterator = const Component*; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using difference_type = component_container::difference_type; + using size_type = component_container::size_type; + +public: // constructors, encoding, decoding + /** @brief Create an empty name + * @post empty() == true + */ + Name(); + + /** @brief Decode Name from wire encoding + * @throw tlv::Error wire encoding is invalid + * + * This is a more efficient equivalent for + * @code + * Name name; + * name.wireDecode(wire); + * @endcode + */ + explicit + Name(const Block& wire); + + /** @brief Parse name from NDN URI + * @param uri a null-terminated URI string + * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme + */ + Name(const char* uri); + + /** @brief Create name from NDN URI + * @param uri a URI string + * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme + */ + Name(std::string uri); + + /** @brief Write URI representation of the name to the output stream + * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme + */ + void + toUri(std::ostream& os, name::UriFormat format = name::UriFormat::DEFAULT) const; + + /** @brief Get URI representation of the name + * @return URI representation; "ndn:" scheme identifier is not included + * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme + * @note To print URI representation into a stream, it is more efficient to use ``os << name``. + */ + std::string + toUri(name::UriFormat format = name::UriFormat::DEFAULT) const; + + /** @brief Check if this Name instance already has wire encoding + */ + bool + hasWire() const + { + return m_wire.hasWire(); + } + + /** @brief Fast encoding or block size estimation + */ + template + size_t + wireEncode(EncodingImpl& encoder) const; + + /** @brief Perform wire encoding, or return existing wire encoding + * @post hasWire() == true + */ + const Block& + wireEncode() const; + + /** @brief Decode name from wire encoding + * @throw tlv::Error wire encoding is invalid + * @post hasWire() == true + */ + void + wireDecode(const Block& wire); + + /** @brief Make a deep copy of the name, reallocating the underlying memory buffer + */ + Name + deepCopy() const; + +public: // access + /** @brief Checks if the name is empty, i.e. has no components. + */ + NDN_CXX_NODISCARD bool + empty() const + { + return m_wire.elements().empty(); + } + + /** @brief Returns the number of components. + */ + size_t + size() const + { + return m_wire.elements_size(); + } + + /** @brief Returns an immutable reference to the component at the specified index. + * @param i zero-based index of the component to return; + * if negative, it is interpreted as offset from the end of the name + * @warning No bounds checking is performed, using an out-of-range index is undefined behavior. + */ + const Component& + get(ssize_t i) const + { + if (i < 0) { + i += static_cast(size()); + } + return reinterpret_cast(m_wire.elements()[i]); + } + + /** @brief Equivalent to `get(i)`. + */ + const Component& + operator[](ssize_t i) const + { + return get(i); + } + + /** @brief Returns an immutable reference to the component at the specified index, + * with bounds checking. + * @param i zero-based index of the component to return; + * if negative, it is interpreted as offset from the end of the name + * @throws Error The index is out of bounds. + */ + const Component& + at(ssize_t i) const; + + /** @brief Extracts some components as a sub-name (PartialName). + * @param iStartComponent zero-based index of the first component; + * if negative, size()+iStartComponent is used instead + * @param nComponents number of desired components, starting at @p iStartComponent; + * use @c npos to return all components until the end of the name + * @return a new PartialName containing the extracted components + * + * If @p iStartComponent is positive and indexes out of bounds, returns an empty PartialName. + * If @p iStartComponent is negative and indexes out of bounds, the sub-name will start from + * the beginning of the name instead. If @p nComponents is out of bounds, returns all components + * until the end of the name. + */ + PartialName + getSubName(ssize_t iStartComponent, size_t nComponents = npos) const; + + /** @brief Returns a prefix of the name. + * @param nComponents number of components; if negative, size()+nComponents is used instead + * + * Returns a new PartialName containing a prefix of this name up to `size() - nComponents`. + * For example, `getPrefix(-1)` returns the name without the final component. + */ + PartialName + getPrefix(ssize_t nComponents) const + { + if (nComponents < 0) + return getSubName(0, size() + nComponents); + else + return getSubName(0, nComponents); + } + +public: // iterators + /** @brief Begin iterator + */ + const_iterator + begin() const + { + return reinterpret_cast(m_wire.elements().data()); + } + + /** @brief End iterator + */ + const_iterator + end() const + { + return reinterpret_cast(m_wire.elements().data() + m_wire.elements().size()); + } + + /** @brief Reverse begin iterator + */ + const_reverse_iterator + rbegin() const + { + return const_reverse_iterator(end()); + } + + /** @brief Reverse end iterator + */ + const_reverse_iterator + rend() const + { + return const_reverse_iterator(begin()); + } + +public: // modifiers + /** @brief Replace the component at the specified index. + * @param i zero-based index of the component to replace; + * if negative, it is interpreted as offset from the end of the name + * @param component the new component to use as a replacement + * @return a reference to this name, to allow chaining. + * @warning No bounds checking is performed, using an out-of-range index is undefined behavior. + */ + Name& + set(ssize_t i, const Component& component); + + /** @brief Replace the component at the specified index. + * @param i zero-based index of the component to replace; + * if negative, it is interpreted as offset from the end of the name + * @param component the new component to use as a replacement + * @return a reference to this name, to allow chaining. + * @warning No bounds checking is performed, using an out-of-range index is undefined behavior. + */ + Name& + set(ssize_t i, Component&& component); + + /** @brief Append a component. + * @return a reference to this name, to allow chaining. + */ + Name& + append(const Component& component) + { + m_wire.push_back(component); + return *this; + } + + /** @brief Append a component. + * @return a reference to this name, to allow chaining. + */ + Name& + append(Component&& component) + { + m_wire.push_back(std::move(component)); + return *this; + } + + /** @brief Append a NameComponent of TLV-TYPE @p type, copying @p count bytes at @p value as + * TLV-VALUE. + * @return a reference to this name, to allow chaining. + */ + Name& + append(uint32_t type, const uint8_t* value, size_t count) + { + return append(Component(type, value, count)); + } + + /** @brief Append a GenericNameComponent, copying @p count bytes at @p value as TLV-VALUE. + * @return a reference to this name, to allow chaining. + */ + Name& + append(const uint8_t* value, size_t count) + { + return append(Component(value, count)); + } + + /** @brief Append a NameComponent of TLV-TYPE @p type, copying TLV-VALUE from a range. + * @tparam Iterator an @c InputIterator dereferencing to a one-octet value type. More efficient + * implementation is available when it is a @c RandomAccessIterator. + * @param type the TLV-TYPE. + * @param first beginning of the range. + * @param last past-end of the range. + * @return a reference to this name, to allow chaining. + */ + template + Name& + append(uint32_t type, Iterator first, Iterator last) + { + return append(Component(type, first, last)); + } + + /** @brief Append a GenericNameComponent, copying TLV-VALUE from a range. + * @tparam Iterator an @c InputIterator dereferencing to a one-octet value type. More efficient + * implementation is available when it is a @c RandomAccessIterator. + * @param first beginning of the range. + * @param last past-end of the range. + * @return a reference to this name, to allow chaining. + */ + template + Name& + append(Iterator first, Iterator last) + { + return append(Component(first, last)); + } + + /** @brief Append a GenericNameComponent, copying TLV-VALUE from a null-terminated string. + * @param str a null-terminated string. Bytes from the string are copied as is, and not + * interpreted as URI component. + * @return a reference to this name, to allow chaining. + */ + Name& + append(const char* str) + { + return append(Component(str)); + } + + /** @brief Append a GenericNameComponent from a TLV element. + * @param value a TLV element. If its TLV-TYPE is tlv::GenericNameComponent, it is + * appended as is. Otherwise, it is nested into a GenericNameComponent. + * @return a reference to this name, to allow chaining. + */ + Name& + append(Block value) + { + if (value.type() == tlv::GenericNameComponent) { + m_wire.push_back(std::move(value)); + } + else { + m_wire.push_back(Block(tlv::GenericNameComponent, std::move(value))); + } + return *this; + } + + /** @brief Append a PartialName. + * @param name the components to append + * @return a reference to this name, to allow chaining + */ + Name& + append(const PartialName& name); + + /** @brief Append a component with a nonNegativeInteger + * @sa number the number + * @return a reference to this name, to allow chaining + * @sa https://named-data.net/doc/NDN-packet-spec/current/tlv.html#non-negative-integer-encoding + */ + Name& + appendNumber(uint64_t number) + { + return append(Component::fromNumber(number)); + } + + /** @brief Append a component with a marked number + * @param marker 1-octet marker + * @param number the number + * + * The component is encoded as a 1-octet marker, followed by a nonNegativeInteger. + * + * @return a reference to this name, to allow chaining + * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf + */ + Name& + appendNumberWithMarker(uint8_t marker, uint64_t number) + { + return append(Component::fromNumberWithMarker(marker, number)); + } + + /** @brief Append a version component + * @param version the version number to append; if nullopt, the current UNIX time + * in milliseconds is used + * @return a reference to this name, to allow chaining + * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf + */ + Name& + appendVersion(optional version = nullopt); + + /** @brief Append a segment number (sequential) component + * @return a reference to this name, to allow chaining + * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf + */ + Name& + appendSegment(uint64_t segmentNo) + { + return append(Component::fromSegment(segmentNo)); + } + + /** @brief Append a byte offset component + * @return a reference to this name, to allow chaining + * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf + */ + Name& + appendByteOffset(uint64_t offset) + { + return append(Component::fromByteOffset(offset)); + } + + /// @deprecated use appendByteOffset + Name& + appendSegmentOffset(uint64_t offset) + { + return appendByteOffset(offset); + } + + /** @brief Append a timestamp component + * @param timestamp the timestamp to append; if nullopt, the current system time is used + * @return a reference to this name, to allow chaining + * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf + */ + Name& + appendTimestamp(optional timestamp = nullopt); + + /** @brief Append a sequence number component + * @return a reference to this name, to allow chaining + * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf + */ + Name& + appendSequenceNumber(uint64_t seqNo) + { + return append(Component::fromSequenceNumber(seqNo)); + } + + /** @brief Append an ImplicitSha256Digest component. + * @return a reference to this name, to allow chaining + */ + Name& + appendImplicitSha256Digest(ConstBufferPtr digest) + { + return append(Component::fromImplicitSha256Digest(std::move(digest))); + } + + /** @brief Append an ImplicitSha256Digest component. + * @return a reference to this name, to allow chaining + */ + Name& + appendImplicitSha256Digest(const uint8_t* digest, size_t digestSize) + { + return append(Component::fromImplicitSha256Digest(digest, digestSize)); + } + + /** @brief Append a ParametersSha256Digest component. + * @return a reference to this name, to allow chaining + */ + Name& + appendParametersSha256Digest(ConstBufferPtr digest) + { + return append(Component::fromParametersSha256Digest(std::move(digest))); + } + + /** @brief Append a ParametersSha256Digest component. + * @return a reference to this name, to allow chaining + */ + Name& + appendParametersSha256Digest(const uint8_t* digest, size_t digestSize) + { + return append(Component::fromParametersSha256Digest(digest, digestSize)); + } + + /** @brief Append a placeholder for a ParametersSha256Digest component. + * @return a reference to this name, to allow chaining + */ + Name& + appendParametersSha256DigestPlaceholder(); + + /** @brief Append a component + * @note This makes push_back an alias of append, giving Name a similar API as STL vector. + */ + template + void + push_back(const T& component) + { + append(component); + } + + /** @brief Erase the component at the specified index. + * @param i zero-based index of the component to replace; + * if negative, it is interpreted as offset from the end of the name + * @warning No bounds checking is performed, using an out-of-range index is undefined behavior. + */ + void + erase(ssize_t i); + + /** @brief Remove all components. + * @post `empty() == true` + */ + void + clear(); + +public: // algorithms + /** @brief Get the successor of a name + * + * The successor of a name is defined as follows: + * + * N represents the set of NDN Names, and X,Y ∈ N. + * Operator < is defined by canonical order on N. + * Y is the successor of X, if (a) X < Y, and (b) ∄ Z ∈ N s.t. X < Z < Y. + * + * In plain words, successor of a name is the same name, but with its last component + * advanced to a next possible value. + * + * Examples: + * + * - successor of `/` is + * `/sha256digest=0000000000000000000000000000000000000000000000000000000000000000`. + * - successor of `/sha256digest=0000000000000000000000000000000000000000000000000000000000000000` + * is `/sha256digest=0000000000000000000000000000000000000000000000000000000000000001`. + * - successor of `/sha256digest=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff` + * is `/2=...`. + * - successor of `/P/A` is `/P/B`. + * - successor of `/Q/%FF` is `/Q/%00%00`. + * + * @return a new Name containing the successor + */ + Name + getSuccessor() const; + + /** @brief Check if this name is a prefix of another name + * + * This name is a prefix of @p other if the N components of this name are same as the first N + * components of @p other. + * + * @retval true this name is a prefix of @p other + * @retval false this name is not a prefix of @p other + */ + bool + isPrefixOf(const Name& other) const; + + /** @brief Check if this name equals another name + * + * Two names are equal if they have the same number of components, and components at each index + * are equal. + */ + bool + equals(const Name& other) const; + + /** @brief Compare this to the other Name using NDN canonical ordering. + * + * If the first components of each name are not equal, this returns a negative value if + * the first comes before the second using the NDN canonical ordering for name + * components, or a positive value if it comes after. If they are equal, this compares + * the second components of each name, etc. If both names are the same up to the size + * of the shorter name, this returns a negative value if the first name is shorter than + * the second or a positive value if it is longer. For example, if you std::sort gives: + * /a/b/d /a/b/cc /c /c/a /bb . + * This is intuitive because all names with the prefix /a are next to each other. + * But it may be also be counter-intuitive because /c comes before /bb according + * to NDN canonical ordering since it is shorter. + * + * @param other The other Name to compare with. + * + * @retval negative this comes before other in canonical ordering + * @retval zero this equals other + * @retval positive this comes after other in canonical ordering + * + * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#canonical-order + */ + int + compare(const Name& other) const + { + return this->compare(0, npos, other); + } + + /** @brief compares [pos1, pos1+count1) components in this Name + * to [pos2, pos2+count2) components in @p other + * + * Equivalent to `getSubName(pos1, count1).compare(other.getSubName(pos2, count2))`. + */ + int + compare(size_t pos1, size_t count1, + const Name& other, size_t pos2 = 0, size_t count2 = npos) const; + +private: // non-member operators + // NOTE: the following "hidden friend" operators are available via + // argument-dependent lookup only and must be defined inline. + + friend bool + operator==(const Name& lhs, const Name& rhs) + { + return lhs.equals(rhs); + } + + friend bool + operator!=(const Name& lhs, const Name& rhs) + { + return !lhs.equals(rhs); + } + + friend bool + operator<(const Name& lhs, const Name& rhs) + { + return lhs.compare(rhs) < 0; + } + + friend bool + operator<=(const Name& lhs, const Name& rhs) + { + return lhs.compare(rhs) <= 0; + } + + friend bool + operator>(const Name& lhs, const Name& rhs) + { + return lhs.compare(rhs) > 0; + } + + friend bool + operator>=(const Name& lhs, const Name& rhs) + { + return lhs.compare(rhs) >= 0; + } + + /** @brief Print URI representation of a name + * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme + */ + friend std::ostream& + operator<<(std::ostream& os, const Name& name) + { + name.toUri(os); + return os; + } + +public: + /** @brief Indicates "until the end" in getSubName() and compare(). + */ + static const size_t npos; + +private: + mutable Block m_wire; +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(Name); + +/** @brief Parse URI from stream as Name + * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme + */ +std::istream& +operator>>(std::istream& is, Name& name); + +} // namespace ndn + +namespace std { + +template<> +struct hash +{ + size_t + operator()(const ndn::Name& name) const; +}; + +} // namespace std + +#endif // NDN_NAME_HPP diff --git a/src/util/ethernet.cpp b/ndn-cxx/net/ethernet.cpp similarity index 75% rename from src/util/ethernet.cpp rename to ndn-cxx/net/ethernet.cpp index 40d939121..28f69298c 100644 --- a/src/util/ethernet.cpp +++ b/ndn-cxx/net/ethernet.cpp @@ -1,6 +1,12 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2014-2018 Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,15 +25,15 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "ethernet.hpp" +#include "ndn-cxx/net/ethernet.hpp" #include #include +#include #include namespace ndn { -namespace util { namespace ethernet { Address::Address() @@ -75,7 +81,7 @@ Address::toString(char sep) const // - apparently gcc-4.6 does not support the 'hh' type modifier // - std::snprintf not found in some environments - // http://redmine.named-data.net/issues/2299 for more information + // https://redmine.named-data.net/issues/2299 for more information snprintf(s, sizeof(s), "%02x%c%02x%c%02x%c%02x%c%02x%c%02x", at(0), sep, at(1), sep, at(2), sep, at(3), sep, at(4), sep, at(5)); @@ -98,18 +104,17 @@ Address::fromString(const std::string& str) if (ret < 11 || static_cast(n) != str.length()) return Address(); - for (size_t i = 0; i < a.size(); ++i) - { - // check that all separators are actually the same char (: or -) - if (i < 5 && sep[i][0] != sep[0][0]) - return Address(); + for (size_t i = 0; i < a.size(); ++i) { + // check that all separators are actually the same char (: or -) + if (i < 5 && sep[i][0] != sep[0][0]) + return Address(); - // check that each value fits into a uint8_t - if (temp[i] > 0xFF) - return Address(); + // check that each value fits into a uint8_t + if (temp[i] > 0xFF) + return Address(); - a[i] = static_cast(temp[i]); - } + a[i] = static_cast(temp[i]); + } return a; } @@ -133,12 +138,10 @@ operator<<(std::ostream& o, const Address& a) } } // namespace ethernet -} // namespace util } // namespace ndn - std::size_t -std::hash::operator()(const ndn::util::ethernet::Address& a) const noexcept +std::hash::operator()(const ndn::ethernet::Address& a) const noexcept { return boost::hash_range(a.cbegin(), a.cend()); } diff --git a/src/util/ethernet.hpp b/ndn-cxx/net/ethernet.hpp similarity index 83% rename from src/util/ethernet.hpp rename to ndn-cxx/net/ethernet.hpp index ef227d4da..f5485dad3 100644 --- a/src/util/ethernet.hpp +++ b/ndn-cxx/net/ethernet.hpp @@ -1,12 +1,12 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2014, Regents of the University of California, - * Arizona Board of Regents, - * Colorado State University, - * University Pierre & Marie Curie, Sorbonne University, - * Washington University in St. Louis, - * Beijing Institute of Technology, - * The University of Memphis +/* + * Copyright (c) 2014-2018 Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -25,8 +25,8 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#ifndef NDN_UTIL_ETHERNET_HPP -#define NDN_UTIL_ETHERNET_HPP +#ifndef NDN_NET_ETHERNET_HPP +#define NDN_NET_ETHERNET_HPP #include #include @@ -34,7 +34,6 @@ #include namespace ndn { -namespace util { namespace ethernet { const uint16_t ETHERTYPE_NDN = 0x8624; @@ -109,20 +108,18 @@ std::ostream& operator<<(std::ostream& o, const Address& a); } // namespace ethernet -} // namespace util } // namespace ndn - namespace std { // specialize std::hash<> for ethernet::Address template<> -struct hash +struct hash { size_t - operator()(const ndn::util::ethernet::Address& a) const noexcept; + operator()(const ndn::ethernet::Address& a) const noexcept; }; } // namespace std -#endif // NDN_UTIL_ETHERNET_HPP +#endif // NDN_NET_ETHERNET_HPP diff --git a/ndn-cxx/net/face-uri.cpp b/ndn-cxx/net/face-uri.cpp new file mode 100644 index 000000000..94f96b49f --- /dev/null +++ b/ndn-cxx/net/face-uri.cpp @@ -0,0 +1,649 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/net/face-uri.hpp" +// #include "ndn-cxx/net/dns.hpp" +#include "ndn-cxx/util/string-helper.hpp" + +#include +#include +#include +#include + +#include +#include +#include + +namespace ndn { + +BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); + +FaceUri::FaceUri() + : m_isV6(false) +{ +} + +FaceUri::FaceUri(const std::string& uri) +{ + if (!parse(uri)) { + NDN_THROW(Error("Malformed URI: " + uri)); + } +} + +FaceUri::FaceUri(const char* uri) + : FaceUri(std::string(uri)) +{ +} + +bool +FaceUri::parse(const std::string& uri) +{ + m_scheme.clear(); + m_host.clear(); + m_port.clear(); + m_path.clear(); + m_isV6 = false; + + static const std::regex protocolExp("(\\w+\\d?(\\+\\w+)?)://([^/]*)(\\/[^?]*)?"); + std::smatch protocolMatch; + if (!std::regex_match(uri, protocolMatch, protocolExp)) { + return false; + } + m_scheme = protocolMatch[1]; + std::string authority = protocolMatch[3]; + m_path = protocolMatch[4]; + + // pattern for IPv6 link local address enclosed in [ ], with optional port number + static const std::regex v6LinkLocalExp("^\\[([a-fA-F0-9:]+)%([^\\s/:]+)\\](?:\\:(\\d+))?$"); + // pattern for IPv6 address enclosed in [ ], with optional port number + static const std::regex v6Exp("^\\[([a-fA-F0-9:]+)\\](?:\\:(\\d+))?$"); + // pattern for Ethernet address in standard hex-digits-and-colons notation + static const std::regex etherExp("^\\[((?:[a-fA-F0-9]{1,2}\\:){5}(?:[a-fA-F0-9]{1,2}))\\]$"); + // pattern for IPv4-mapped IPv6 address, with optional port number + static const std::regex v4MappedV6Exp("^\\[::ffff:(\\d+(?:\\.\\d+){3})\\](?:\\:(\\d+))?$"); + // pattern for IPv4/hostname/fd/ifname, with optional port number + static const std::regex v4HostExp("^([^:]+)(?:\\:(\\d+))?$"); + + if (authority.empty()) { + // UNIX, internal + } + else { + std::smatch match; + if (std::regex_match(authority, match, v6LinkLocalExp)) { + m_isV6 = true; + m_host = match[1].str() + "%" + match[2].str(); + m_port = match[3]; + return true; + } + + m_isV6 = std::regex_match(authority, match, v6Exp); + if (m_isV6 || + std::regex_match(authority, match, etherExp) || + std::regex_match(authority, match, v4MappedV6Exp) || + std::regex_match(authority, match, v4HostExp)) { + m_host = match[1]; + m_port = match[2]; + } + else { + return false; + } + } + + return true; +} + +FaceUri::FaceUri(const boost::asio::ip::udp::endpoint& endpoint) +{ + m_isV6 = endpoint.address().is_v6(); + m_scheme = m_isV6 ? "udp6" : "udp4"; + m_host = endpoint.address().to_string(); + m_port = to_string(endpoint.port()); +} + +FaceUri::FaceUri(const boost::asio::ip::tcp::endpoint& endpoint) +{ + m_isV6 = endpoint.address().is_v6(); + m_scheme = m_isV6 ? "tcp6" : "tcp4"; + m_host = endpoint.address().to_string(); + m_port = to_string(endpoint.port()); +} + +FaceUri::FaceUri(const boost::asio::ip::tcp::endpoint& endpoint, const std::string& scheme) +{ + m_isV6 = endpoint.address().is_v6(); + m_scheme = scheme; + m_host = endpoint.address().to_string(); + m_port = to_string(endpoint.port()); +} + +#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS +FaceUri::FaceUri(const boost::asio::local::stream_protocol::endpoint& endpoint) + : m_scheme("unix") + , m_path(endpoint.path()) + , m_isV6(false) +{ +} +#endif // BOOST_ASIO_HAS_LOCAL_SOCKETS + +FaceUri +FaceUri::fromFd(int fd) +{ + FaceUri uri; + uri.m_scheme = "fd"; + uri.m_host = to_string(fd); + return uri; +} + +FaceUri::FaceUri(const ethernet::Address& address) + : m_scheme("ether") + , m_host(address.toString()) + , m_isV6(true) +{ +} + +FaceUri +FaceUri::fromDev(const std::string& ifname) +{ + FaceUri uri; + uri.m_scheme = "dev"; + uri.m_host = ifname; + return uri; +} + +FaceUri +FaceUri::fromUdpDev(const boost::asio::ip::udp::endpoint& endpoint, const std::string& ifname) +{ + FaceUri uri; + uri.m_scheme = endpoint.address().is_v6() ? "udp6+dev" : "udp4+dev"; + uri.m_host = ifname; + uri.m_port = to_string(endpoint.port()); + return uri; +} + +std::string +FaceUri::toString() const +{ + std::ostringstream os; + os << *this; + return os.str(); +} + +std::ostream& +operator<<(std::ostream& os, const FaceUri& uri) +{ + os << uri.m_scheme << "://"; + if (uri.m_isV6) { + os << "[" << uri.m_host << "]"; + } + else { + os << uri.m_host; + } + if (!uri.m_port.empty()) { + os << ":" << uri.m_port; + } + os << uri.m_path; + return os; +} + + +/** \brief a CanonizeProvider provides FaceUri canonization functionality for a group of schemes + */ +class CanonizeProvider : noncopyable +{ +public: + virtual + ~CanonizeProvider() = default; + + virtual std::set + getSchemes() const = 0; + + virtual bool + isCanonical(const FaceUri& faceUri) const = 0; + + virtual void + canonize(const FaceUri& faceUri, + const FaceUri::CanonizeSuccessCallback& onSuccess, + const FaceUri::CanonizeFailureCallback& onFailure, + time::nanoseconds timeout) const = 0; +}; + +template +class IpHostCanonizeProvider : public CanonizeProvider +{ +public: + std::set + getSchemes() const override + { + return {m_baseScheme, m_v4Scheme, m_v6Scheme}; + } + + bool + isCanonical(const FaceUri& faceUri) const override + { + BOOST_THROW_EXCEPTION(std::runtime_error("IP host canonization not supported")); + // if (faceUri.getPort().empty()) { + // return false; + // } + // if (!faceUri.getPath().empty()) { + // return false; + // } + + // boost::system::error_code ec; + // auto addr = ip::addressFromString(unescapeHost(faceUri.getHost()), ec); + // if (ec) { + // return false; + // } + + // bool hasCorrectScheme = (faceUri.getScheme() == m_v4Scheme && addr.is_v4()) || + // (faceUri.getScheme() == m_v6Scheme && addr.is_v6()); + // if (!hasCorrectScheme) { + // return false; + // } + + // auto checkAddressWithUri = [] (const boost::asio::ip::address& addr, + // const FaceUri& faceUri) -> bool { + // if (addr.is_v4() || !addr.to_v6().is_link_local()) { + // return addr.to_string() == faceUri.getHost(); + // } + + // std::vector addrFields, faceUriFields; + // std::string addrString = addr.to_string(); + // std::string faceUriString = faceUri.getHost(); + + // boost::algorithm::split(addrFields, addrString, boost::is_any_of("%")); + // boost::algorithm::split(faceUriFields, faceUriString, boost::is_any_of("%")); + // if (addrFields.size() != 2 || faceUriFields.size() != 2) { + // return false; + // } + + // if (faceUriFields[1].size() > 2 && faceUriFields[1].compare(0, 2, "25") == 0) { + // // %25... is accepted, but not a canonical form + // return false; + // } + + // return addrFields[0] == faceUriFields[0] && + // addrFields[1] == faceUriFields[1]; + // }; + + // return checkAddressWithUri(addr, faceUri) && checkAddress(addr).first; + } + + void + canonize(const FaceUri& faceUri, + const FaceUri::CanonizeSuccessCallback& onSuccess, + const FaceUri::CanonizeFailureCallback& onFailure, + time::nanoseconds timeout) const override + { + BOOST_THROW_EXCEPTION(std::runtime_error("IP host canonization not supported")); + // if (this->isCanonical(faceUri)) { + // onSuccess(faceUri); + // return; + // } + + // // make a copy because caller may modify faceUri + // auto uri = make_shared(faceUri); + // boost::system::error_code ec; + // auto ipAddress = ip::addressFromString(unescapeHost(faceUri.getHost()), ec); + // if (!ec) { + // // No need to resolve IP address if host is already an IP + // if ((faceUri.getScheme() == m_v4Scheme && !ipAddress.is_v4()) || + // (faceUri.getScheme() == m_v6Scheme && !ipAddress.is_v6())) { + // return onFailure("IPv4/v6 mismatch"); + // } + + // onDnsSuccess(uri, onSuccess, onFailure, ipAddress); + // } + // else { + // dns::AddressSelector addressSelector; + // if (faceUri.getScheme() == m_v4Scheme) { + // addressSelector = dns::Ipv4Only(); + // } + // else if (faceUri.getScheme() == m_v6Scheme) { + // addressSelector = dns::Ipv6Only(); + // } + // else { + // BOOST_ASSERT(faceUri.getScheme() == m_baseScheme); + // addressSelector = dns::AnyAddress(); + // } + + // dns::asyncResolve(unescapeHost(faceUri.getHost()), + // bind(&IpHostCanonizeProvider::onDnsSuccess, this, uri, onSuccess, onFailure, _1), + // bind(&IpHostCanonizeProvider::onDnsFailure, this, uri, onFailure, _1), + // io, addressSelector, timeout); + // } + } + +protected: + explicit + IpHostCanonizeProvider(const std::string& baseScheme, + uint16_t defaultUnicastPort = 6363, + uint16_t defaultMulticastPort = 56363) + : m_baseScheme(baseScheme) + , m_v4Scheme(baseScheme + '4') + , m_v6Scheme(baseScheme + '6') + , m_defaultUnicastPort(defaultUnicastPort) + , m_defaultMulticastPort(defaultMulticastPort) + { + } + +private: + // void + // onDnsSuccess(const shared_ptr& faceUri, + // const FaceUri::CanonizeSuccessCallback& onSuccess, + // const FaceUri::CanonizeFailureCallback& onFailure, + // const dns::IpAddress& ipAddress) const + // { + // bool isOk = false; + // std::string reason; + // std::tie(isOk, reason) = this->checkAddress(ipAddress); + // if (!isOk) { + // return onFailure(reason); + // } + + // uint16_t port = 0; + // if (faceUri->getPort().empty()) { + // port = ipAddress.is_multicast() ? m_defaultMulticastPort : m_defaultUnicastPort; + // } + // else { + // try { + // port = boost::lexical_cast(faceUri->getPort()); + // } + // catch (const boost::bad_lexical_cast&) { + // return onFailure("invalid port number '" + faceUri->getPort() + "'"); + // } + // } + + // FaceUri canonicalUri(typename Protocol::endpoint(ipAddress, port)); + // BOOST_ASSERT(canonicalUri.isCanonical()); + // onSuccess(canonicalUri); + // } + + // void + // onDnsFailure(const shared_ptr& faceUri, + // const FaceUri::CanonizeFailureCallback& onFailure, + // const std::string& reason) const + // { + // onFailure(reason); + // } + + /** \brief when overriden in a subclass, check the IP address is allowable + * \return (true,ignored) if the address is allowable; + * (false,reason) if the address is not allowable. + */ + // virtual std::pair + // checkAddress(const dns::IpAddress& ipAddress) const + // { + // return {true, ""}; + // } + + static std::string + unescapeHost(std::string host) + { + auto escapePos = host.find("%25"); + if (escapePos != std::string::npos && escapePos < host.size() - 3) { + host = unescape(host); + } + return host; + } + +private: + std::string m_baseScheme; + std::string m_v4Scheme; + std::string m_v6Scheme; + uint16_t m_defaultUnicastPort; + uint16_t m_defaultMulticastPort; +}; + +class UdpCanonizeProvider : public IpHostCanonizeProvider +{ +public: + UdpCanonizeProvider() + : IpHostCanonizeProvider("udp") + { + } +}; + +class TcpCanonizeProvider : public IpHostCanonizeProvider +{ +public: + TcpCanonizeProvider() + : IpHostCanonizeProvider("tcp") + { + } + +protected: + // std::pair + // checkAddress(const dns::IpAddress& ipAddress) const override + // { + // if (ipAddress.is_multicast()) { + // return {false, "cannot use multicast address"}; + // } + // return {true, ""}; + // } +}; + +class EtherCanonizeProvider : public CanonizeProvider +{ +public: + std::set + getSchemes() const override + { + return {"ether"}; + } + + bool + isCanonical(const FaceUri& faceUri) const override + { + if (!faceUri.getPort().empty()) { + return false; + } + if (!faceUri.getPath().empty()) { + return false; + } + + auto addr = ethernet::Address::fromString(faceUri.getHost()); + return addr.toString() == faceUri.getHost(); + } + + void + canonize(const FaceUri& faceUri, + const FaceUri::CanonizeSuccessCallback& onSuccess, + const FaceUri::CanonizeFailureCallback& onFailure, + time::nanoseconds timeout) const override + { + auto addr = ethernet::Address::fromString(faceUri.getHost()); + if (addr.isNull()) { + return onFailure("invalid ethernet address '" + faceUri.getHost() + "'"); + } + + FaceUri canonicalUri(addr); + BOOST_ASSERT(canonicalUri.isCanonical()); + onSuccess(canonicalUri); + } +}; + +class DevCanonizeProvider : public CanonizeProvider +{ +public: + std::set + getSchemes() const override + { + return {"dev"}; + } + + bool + isCanonical(const FaceUri& faceUri) const override + { + return !faceUri.getHost().empty() && faceUri.getPort().empty() && faceUri.getPath().empty(); + } + + void + canonize(const FaceUri& faceUri, + const FaceUri::CanonizeSuccessCallback& onSuccess, + const FaceUri::CanonizeFailureCallback& onFailure, + time::nanoseconds timeout) const override + { + if (faceUri.getHost().empty()) { + onFailure("network interface name is missing"); + return; + } + if (!faceUri.getPort().empty()) { + onFailure("port number is not allowed"); + return; + } + if (!faceUri.getPath().empty() && faceUri.getPath() != "/") { // permit trailing slash only + onFailure("path is not allowed"); + return; + } + + FaceUri canonicalUri = FaceUri::fromDev(faceUri.getHost()); + BOOST_ASSERT(canonicalUri.isCanonical()); + onSuccess(canonicalUri); + } +}; + +class UdpDevCanonizeProvider : public CanonizeProvider +{ +public: + std::set + getSchemes() const override + { + return {"udp4+dev", "udp6+dev"}; + } + + bool + isCanonical(const FaceUri& faceUri) const override + { + if (faceUri.getPort().empty()) { + return false; + } + if (!faceUri.getPath().empty()) { + return false; + } + return true; + } + + void + canonize(const FaceUri& faceUri, + const FaceUri::CanonizeSuccessCallback& onSuccess, + const FaceUri::CanonizeFailureCallback& onFailure, + time::nanoseconds timeout) const override + { + if (this->isCanonical(faceUri)) { + onSuccess(faceUri); + } + else { + onFailure("cannot canonize " + faceUri.toString()); + } + } +}; + +using CanonizeProviders = boost::mpl::vector; +using CanonizeProviderTable = std::map>; + +class CanonizeProviderTableInitializer +{ +public: + explicit + CanonizeProviderTableInitializer(CanonizeProviderTable& providerTable) + : m_providerTable(providerTable) + { + } + + template + void + operator()(CP*) + { + shared_ptr cp = make_shared(); + auto schemes = cp->getSchemes(); + BOOST_ASSERT(!schemes.empty()); + + for (const auto& scheme : schemes) { + BOOST_ASSERT(m_providerTable.count(scheme) == 0); + m_providerTable[scheme] = cp; + } + } + +private: + CanonizeProviderTable& m_providerTable; +}; + +static const CanonizeProvider* +getCanonizeProvider(const std::string& scheme) +{ + static CanonizeProviderTable providerTable; + if (providerTable.empty()) { + boost::mpl::for_each(CanonizeProviderTableInitializer(providerTable)); + BOOST_ASSERT(!providerTable.empty()); + } + + auto it = providerTable.find(scheme); + return it == providerTable.end() ? nullptr : it->second.get(); +} + + +bool +FaceUri::canCanonize(const std::string& scheme) +{ + return getCanonizeProvider(scheme) != nullptr; +} + +bool +FaceUri::isCanonical() const +{ + const CanonizeProvider* cp = getCanonizeProvider(this->getScheme()); + if (cp == nullptr) { + return false; + } + + return cp->isCanonical(*this); +} + +void +FaceUri::canonize(const CanonizeSuccessCallback& onSuccess, + const CanonizeFailureCallback& onFailure, + time::nanoseconds timeout) const +{ + const CanonizeProvider* cp = getCanonizeProvider(this->getScheme()); + if (cp == nullptr) { + if (onFailure) { + onFailure("scheme not supported"); + } + return; + } + + cp->canonize(*this, + onSuccess ? onSuccess : [] (auto&&) {}, + onFailure ? onFailure : [] (auto&&) {}, + timeout); +} + +} // namespace ndn diff --git a/src/util/face-uri.hpp b/ndn-cxx/net/face-uri.hpp similarity index 77% rename from src/util/face-uri.hpp rename to ndn-cxx/net/face-uri.hpp index b22232326..87aa33084 100644 --- a/src/util/face-uri.hpp +++ b/ndn-cxx/net/face-uri.hpp @@ -1,12 +1,12 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2014-2016, Regents of the University of California, - * Arizona Board of Regents, - * Colorado State University, - * University Pierre & Marie Curie, Sorbonne University, - * Washington University in St. Louis, - * Beijing Institute of Technology, - * The University of Memphis +/* + * Copyright (c) 2013-2019 Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -25,21 +25,21 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#ifndef NDN_UTIL_FACE_URI_HPP -#define NDN_UTIL_FACE_URI_HPP +#ifndef NDN_NET_FACE_URI_HPP +#define NDN_NET_FACE_URI_HPP + +#include "ndn-cxx/detail/asio-fwd.hpp" +#include "ndn-cxx/net/ethernet.hpp" +#include "ndn-cxx/util/time.hpp" -#include "../common.hpp" -#include #include +#include #include -#include "ethernet.hpp" -#include "time.hpp" namespace ndn { -namespace util { /** \brief represents the underlying protocol and address used by a Face - * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#FaceUri + * \sa https://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#FaceUri */ class FaceUri { @@ -47,11 +47,7 @@ class FaceUri class Error : public std::invalid_argument { public: - explicit - Error(const std::string& what) - : std::invalid_argument(what) - { - } + using std::invalid_argument::invalid_argument; }; FaceUri(); @@ -70,7 +66,7 @@ class FaceUri FaceUri(const char* uri); /// exception-safe parsing - bool + NDN_CXX_NODISCARD bool parse(const std::string& uri); public: // scheme-specific construction @@ -82,7 +78,7 @@ class FaceUri explicit FaceUri(const boost::asio::ip::tcp::endpoint& endpoint); - /// construct tcp canonical FaceUri with customized scheme + /// construct tcp canonical FaceUri with custom scheme FaceUri(const boost::asio::ip::tcp::endpoint& endpoint, const std::string& scheme); #ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS @@ -140,13 +136,6 @@ class FaceUri std::string toString() const; -public: // EqualityComparable concept - bool - operator==(const FaceUri& rhs) const; - - bool - operator!=(const FaceUri& rhs) const; - public: // canonical FaceUri /** \return whether a FaceUri of the scheme can be canonized */ @@ -168,7 +157,6 @@ class FaceUri * \param onSuccess function to call after this FaceUri is converted to canonical form * \note A new FaceUri in canonical form will be created; this FaceUri is unchanged. * \param onFailure function to call if this FaceUri cannot be converted to canonical form - * \param io reference to `boost::asio::io_service` instance * \param timeout maximum allowable duration of the operations. * It's intentional not to provide a default value: the caller should set * a reasonable value in balance between network delay and user experience. @@ -176,15 +164,35 @@ class FaceUri void canonize(const CanonizeSuccessCallback& onSuccess, const CanonizeFailureCallback& onFailure, - boost::asio::io_service& io, const time::nanoseconds& timeout) const; + time::nanoseconds timeout) const; + +private: // non-member operators + // NOTE: the following "hidden friend" operators are available via + // argument-dependent lookup only and must be defined inline. + + friend bool + operator==(const FaceUri& lhs, const FaceUri& rhs) + { + return !(lhs != rhs); + } + + friend bool + operator!=(const FaceUri& lhs, const FaceUri& rhs) + { + return lhs.m_isV6 != rhs.m_isV6 || + lhs.m_scheme != rhs.m_scheme || + lhs.m_host != rhs.m_host || + lhs.m_port != rhs.m_port || + lhs.m_path != rhs.m_path; + } private: std::string m_scheme; std::string m_host; - /// whether to add [] around host when writing string - bool m_isV6; std::string m_port; std::string m_path; + /// whether to add [] around host when writing string + bool m_isV6; friend std::ostream& operator<<(std::ostream& os, const FaceUri& uri); }; @@ -192,7 +200,6 @@ class FaceUri std::ostream& operator<<(std::ostream& os, const FaceUri& uri); -} // namespace util } // namespace ndn -#endif // NDN_UTIL_FACE_URI_HPP +#endif // NDN_NET_FACE_URI_HPP diff --git a/ndn-cxx/net/impl/link-type-helper-osx.mm b/ndn-cxx/net/impl/link-type-helper-osx.mm new file mode 100644 index 000000000..048a78085 --- /dev/null +++ b/ndn-cxx/net/impl/link-type-helper-osx.mm @@ -0,0 +1,65 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/net/impl/link-type-helper.hpp" + +#ifndef NDN_CXX_HAVE_OSX_FRAMEWORKS +#error "This file should not be compiled ..." +#endif + +#import +#import +#import +#import + +namespace ndn { +namespace net { +namespace detail { + +ndn::nfd::LinkType +getLinkType(const std::string& ifName) +{ + @autoreleasepool { + NSString* interfaceName = [NSString stringWithCString:ifName.c_str() + encoding:[NSString defaultCStringEncoding]]; + + CWWiFiClient* wifiInterface = [CWWiFiClient sharedWiFiClient]; + if (wifiInterface == nullptr) { + return nfd::LINK_TYPE_NONE; + } + + CWInterface* airport = [wifiInterface interfaceWithName:interfaceName]; + if (airport == nullptr) { + return nfd::LINK_TYPE_NONE; + } + + if ([airport interfaceMode] == kCWInterfaceModeIBSS) { + return nfd::LINK_TYPE_AD_HOC; + } + else { + return nfd::LINK_TYPE_MULTI_ACCESS; + } + } +} + +} // namespace detail +} // namespace net +} // namespace ndn diff --git a/ndn-cxx/net/impl/link-type-helper.cpp b/ndn-cxx/net/impl/link-type-helper.cpp new file mode 100644 index 000000000..6ad4059f3 --- /dev/null +++ b/ndn-cxx/net/impl/link-type-helper.cpp @@ -0,0 +1,43 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/net/impl/link-type-helper.hpp" +#include "ndn-cxx/detail/config.hpp" + +#ifdef NDN_CXX_HAVE_OSX_FRAMEWORKS +// implemented in link-type-helper-osx.mm +#else + +namespace ndn { +namespace net { +namespace detail { + +ndn::nfd::LinkType +getLinkType(const std::string& ifName) +{ + return nfd::LINK_TYPE_NONE; +} + +} // namespace detail +} // namespace net +} // namespace ndn + +#endif // NDN_CXX_HAVE_OSX_FRAMEWORKS diff --git a/ndn-cxx/net/impl/link-type-helper.hpp b/ndn-cxx/net/impl/link-type-helper.hpp new file mode 100644 index 000000000..a1549f684 --- /dev/null +++ b/ndn-cxx/net/impl/link-type-helper.hpp @@ -0,0 +1,41 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_NET_IMPL_LINK_TYPE_HELPER_HPP +#define NDN_NET_IMPL_LINK_TYPE_HELPER_HPP + +#include "ndn-cxx/encoding/nfd-constants.hpp" + +namespace ndn { +namespace net { +namespace detail { + +/** + * @brief Obtain information about WiFi link type + */ +ndn::nfd::LinkType +getLinkType(const std::string& ifName); + +} // namespace detail +} // namespace net +} // namespace ndn + +#endif // NDN_NET_IMPL_LINK_TYPE_HELPER_HPP diff --git a/ndn-cxx/net/impl/linux-if-constants.cpp b/ndn-cxx/net/impl/linux-if-constants.cpp new file mode 100644 index 000000000..68bb9dbdc --- /dev/null +++ b/ndn-cxx/net/impl/linux-if-constants.cpp @@ -0,0 +1,51 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Davide Pesavento + */ + +#ifdef __linux__ + +#include "ndn-cxx/net/impl/linux-if-constants.hpp" + +#include +#include + +namespace ndn { +namespace net { +namespace linux_if { + +const uint32_t FLAG_LOWER_UP = IFF_LOWER_UP; +const uint32_t FLAG_DORMANT = IFF_DORMANT; +const uint32_t FLAG_ECHO = IFF_ECHO; + +const uint8_t OPER_STATE_UNKNOWN = IF_OPER_UNKNOWN; +const uint8_t OPER_STATE_NOTPRESENT = IF_OPER_NOTPRESENT; +const uint8_t OPER_STATE_DOWN = IF_OPER_DOWN; +const uint8_t OPER_STATE_LOWERLAYERDOWN = IF_OPER_LOWERLAYERDOWN; +const uint8_t OPER_STATE_TESTING = IF_OPER_TESTING; +const uint8_t OPER_STATE_DORMANT = IF_OPER_DORMANT; +const uint8_t OPER_STATE_UP = IF_OPER_UP; + +} // namespace linux_if +} // namespace net +} // namespace ndn + +#endif // __linux__ diff --git a/ndn-cxx/net/impl/linux-if-constants.hpp b/ndn-cxx/net/impl/linux-if-constants.hpp new file mode 100644 index 000000000..1bfece759 --- /dev/null +++ b/ndn-cxx/net/impl/linux-if-constants.hpp @@ -0,0 +1,58 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Davide Pesavento + */ + +#ifndef NDN_NET_LINUX_IF_CONSTANTS_HPP +#define NDN_NET_LINUX_IF_CONSTANTS_HPP +#ifdef __linux__ + +#include + +namespace ndn { +namespace net { +namespace linux_if { + +// linux/if.h and net/if.h cannot be (directly or indirectly) included in the +// same translation unit because they contain duplicate declarations, therefore +// we have to resort to this workaround when we need to include both linux/if.h +// and any other headers that pull in net/if.h (e.g. boost/asio.hpp) + +// net_device_flags missing from +extern const uint32_t FLAG_LOWER_UP; +extern const uint32_t FLAG_DORMANT; +extern const uint32_t FLAG_ECHO; + +// RFC 2863 operational status +extern const uint8_t OPER_STATE_UNKNOWN; +extern const uint8_t OPER_STATE_NOTPRESENT; +extern const uint8_t OPER_STATE_DOWN; +extern const uint8_t OPER_STATE_LOWERLAYERDOWN; +extern const uint8_t OPER_STATE_TESTING; +extern const uint8_t OPER_STATE_DORMANT; +extern const uint8_t OPER_STATE_UP; + +} // namespace linux_if +} // namespace net +} // namespace ndn + +#endif // __linux__ +#endif // NDN_NET_LINUX_IF_CONSTANTS_HPP diff --git a/ndn-cxx/net/impl/netlink-message.hpp b/ndn-cxx/net/impl/netlink-message.hpp new file mode 100644 index 000000000..4f0a74bb7 --- /dev/null +++ b/ndn-cxx/net/impl/netlink-message.hpp @@ -0,0 +1,313 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Davide Pesavento + */ + +#ifndef NDN_NET_NETLINK_MESSAGE_HPP +#define NDN_NET_NETLINK_MESSAGE_HPP + +#include "ndn-cxx/detail/common.hpp" +#include "ndn-cxx/net/ethernet.hpp" + +#ifndef NDN_CXX_HAVE_NETLINK +#error "This file should not be included ..." +#endif + +#include +#include +#include + +#include +#include + +#include + +namespace ndn { +namespace net { + +template +constexpr size_t +getAttributeLength(const T* attr); + +template<> +constexpr size_t +getAttributeLength(const nlattr* attr) +{ + return attr->nla_len; +} + +template<> +constexpr size_t +getAttributeLength(const rtattr* attr) +{ + return attr->rta_len; +} + +template +constexpr size_t +getAttributeLengthAligned(const T* attr); + +template<> +constexpr size_t +getAttributeLengthAligned(const nlattr* attr) +{ + return NLA_ALIGN(attr->nla_len); +} + +template<> +constexpr size_t +getAttributeLengthAligned(const rtattr* attr) +{ + return RTA_ALIGN(attr->rta_len); +} + +template +constexpr uint16_t +getAttributeType(const T* attr); + +template<> +constexpr uint16_t +getAttributeType(const nlattr* attr) +{ + return attr->nla_type & NLA_TYPE_MASK; +} + +template<> +constexpr uint16_t +getAttributeType(const rtattr* attr) +{ + return attr->rta_type; +} + +template +const uint8_t* +getAttributeValue(const T* attr); + +template<> +inline const uint8_t* +getAttributeValue(const nlattr* attr) +{ + return reinterpret_cast(attr) + NLA_HDRLEN; +} + +template<> +inline const uint8_t* +getAttributeValue(const rtattr* attr) +{ + return reinterpret_cast(RTA_DATA(const_cast(attr))); +} + +template +constexpr size_t +getAttributeValueLength(const T* attr); + +template<> +constexpr size_t +getAttributeValueLength(const nlattr* attr) +{ + return attr->nla_len - NLA_HDRLEN; +} + +template<> +constexpr size_t +getAttributeValueLength(const rtattr* attr) +{ + return RTA_PAYLOAD(attr); +} + +template +class NetlinkMessageAttributes; + +class NetlinkMessage +{ +public: + explicit + NetlinkMessage(const uint8_t* buf, size_t buflen) noexcept + : m_msg(reinterpret_cast(buf)) + , m_length(buflen) + { + BOOST_ASSERT(buf != nullptr); + } + + const nlmsghdr& + operator*() const noexcept + { + return *m_msg; + } + + const nlmsghdr* + operator->() const noexcept + { + return m_msg; + } + + bool + isValid() const noexcept + { + return NLMSG_OK(m_msg, m_length); + } + + NetlinkMessage + getNext() const noexcept + { + BOOST_ASSERT(isValid()); + + // mimic NLMSG_NEXT + auto thisLen = NLMSG_ALIGN(m_msg->nlmsg_len); + return NetlinkMessage{reinterpret_cast(m_msg) + thisLen, m_length - thisLen}; + } + + template + const T* + getPayload() const noexcept + { + BOOST_ASSERT(isValid()); + + if (m_msg->nlmsg_len < NLMSG_LENGTH(sizeof(T))) + return nullptr; + + return reinterpret_cast(NLMSG_DATA(const_cast(m_msg))); + } + + template + NetlinkMessageAttributes + getAttributes(const PayloadT* p) const noexcept + { + BOOST_ASSERT(isValid()); + + auto begin = reinterpret_cast(p) + NLMSG_ALIGN(sizeof(PayloadT)); + auto length = NLMSG_PAYLOAD(m_msg, sizeof(PayloadT)); + return NetlinkMessageAttributes{reinterpret_cast(begin), length}; + } + +private: + const nlmsghdr* m_msg; + size_t m_length; +}; + +template +class NetlinkMessageAttributes +{ + // empty type used to implement tag dispatching in getAttributeByType() + template + struct AttrValueTypeTag {}; + +public: + explicit + NetlinkMessageAttributes(const T* begin, size_t length) noexcept + { + for (; isAttrValid(begin, length); begin = getNextAttr(begin, length)) { + m_attrs[getAttributeType(begin)] = begin; + } + } + + size_t + size() const noexcept + { + return m_attrs.size(); + } + + template + optional + getAttributeByType(uint16_t attrType) const + { + auto it = m_attrs.find(attrType); + if (it == m_attrs.end()) + return nullopt; + + return convertAttrValue(getAttributeValue(it->second), + getAttributeValueLength(it->second), + AttrValueTypeTag{}); + } + +private: + static bool + isAttrValid(const T* attr, size_t nBytesRemaining) noexcept + { + return attr != nullptr && + nBytesRemaining >= sizeof(T) && + getAttributeLength(attr) >= sizeof(T) && + getAttributeLength(attr) <= nBytesRemaining; + } + + static const T* + getNextAttr(const T* attr, size_t& nBytesRemaining) noexcept + { + auto len = getAttributeLengthAligned(attr); + if (len > nBytesRemaining) // prevent integer underflow + return nullptr; + + nBytesRemaining -= len; + return reinterpret_cast(reinterpret_cast(attr) + len); + } + + template + static std::enable_if_t::value, optional> + convertAttrValue(const uint8_t* val, size_t len, AttrValueTypeTag) + { + if (len < sizeof(Integral)) + return nullopt; + + Integral i; + std::memcpy(&i, val, sizeof(Integral)); + return i; + } + + static optional + convertAttrValue(const uint8_t* val, size_t len, AttrValueTypeTag) + { + auto str = reinterpret_cast(val); + if (::strnlen(str, len) < len) + return std::string(str); + else + return nullopt; + } + + static optional + convertAttrValue(const uint8_t* val, size_t len, AttrValueTypeTag) + { + if (len < ethernet::ADDR_LEN) + return nullopt; + + return ethernet::Address(val); + } + + template + static std::enable_if_t::value || + std::is_same::value, optional> + convertAttrValue(const uint8_t* val, size_t len, AttrValueTypeTag) + { + typename IpAddress::bytes_type bytes; + if (len < bytes.size()) + return nullopt; + + std::copy_n(val, bytes.size(), bytes.begin()); + return IpAddress(bytes); + } + +private: + std::map m_attrs; +}; + +} // namespace net +} // namespace ndn + +#endif // NDN_NET_NETLINK_MESSAGE_HPP diff --git a/ndn-cxx/net/impl/netlink-socket.cpp b/ndn-cxx/net/impl/netlink-socket.cpp new file mode 100644 index 000000000..0b00c5049 --- /dev/null +++ b/ndn-cxx/net/impl/netlink-socket.cpp @@ -0,0 +1,613 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Davide Pesavento + */ + +#include "ndn-cxx/net/impl/netlink-socket.hpp" +#include "ndn-cxx/net/impl/netlink-message.hpp" +#include "ndn-cxx/util/logger.hpp" +#include "ndn-cxx/util/time.hpp" + +#include +#include + +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 +#endif +#ifndef NETLINK_CAP_ACK +#define NETLINK_CAP_ACK 10 +#endif +#ifndef NETLINK_GET_STRICT_CHK +#define NETLINK_GET_STRICT_CHK 12 +#endif + +NDN_LOG_INIT(ndn.NetworkMonitor); + +namespace ndn { +namespace net { + +// satisfies Asio's SettableSocketOption type requirements +template +class NetlinkSocketOption +{ +public: + explicit + NetlinkSocketOption(int val) + : m_value(val) + { + } + + template + int + level(const Protocol&) const + { + return SOL_NETLINK; + } + + template + int + name(const Protocol&) const + { + return OptName; + } + + template + const int* + data(const Protocol&) const + { + return &m_value; + } + + template + std::size_t + size(const Protocol&) const + { + return sizeof(m_value); + } + +private: + int m_value; +}; + +NetlinkSocket::NetlinkSocket(boost::asio::io_service& io) + : m_sock(make_shared(io)) + , m_pid(0) + , m_seqNum(static_cast(time::system_clock::now().time_since_epoch().count())) + , m_buffer(16 * 1024) // 16 KiB +{ +} + +NetlinkSocket::~NetlinkSocket() +{ + boost::system::error_code ec; + m_sock->close(ec); +} + +void +NetlinkSocket::open(int protocol) +{ + boost::asio::generic::raw_protocol proto(AF_NETLINK, protocol); + // open socket manually to set the close-on-exec flag atomically on creation + int fd = ::socket(proto.family(), proto.type() | SOCK_CLOEXEC, proto.protocol()); + if (fd < 0) { + NDN_THROW_ERRNO(Error("Cannot create netlink socket")); + } + + boost::system::error_code ec; + m_sock->assign(proto, fd, ec); + if (ec) { + NDN_THROW(Error("Cannot assign descriptor: " + ec.message())); + } + + // increase socket receive buffer to 1MB to avoid losing messages + m_sock->set_option(boost::asio::socket_base::receive_buffer_size(1 * 1024 * 1024), ec); + if (ec) { + // not a fatal error + NDN_LOG_DEBUG("setting receive buffer size failed: " << ec.message()); + } + + // enable control messages for received packets to get the destination group + m_sock->set_option(NetlinkSocketOption(true), ec); + if (ec) { + NDN_THROW(Error("Cannot enable NETLINK_PKTINFO: " + ec.message())); + } + + sockaddr_nl addr{}; + addr.nl_family = AF_NETLINK; + if (::bind(m_sock->native_handle(), reinterpret_cast(&addr), sizeof(addr)) < 0) { + NDN_THROW_ERRNO(Error("Cannot bind netlink socket")); + } + + // find out what pid has been assigned to us + socklen_t len = sizeof(addr); + if (::getsockname(m_sock->native_handle(), reinterpret_cast(&addr), &len) < 0) { + NDN_THROW_ERRNO(Error("Cannot obtain netlink socket address")); + } + if (len != sizeof(addr)) { + NDN_THROW(Error("Wrong address length (" + to_string(len) + ")")); + } + if (addr.nl_family != AF_NETLINK) { + NDN_THROW(Error("Wrong address family (" + to_string(addr.nl_family) + ")")); + } + m_pid = addr.nl_pid; + NDN_LOG_TRACE("our pid is " << m_pid); + + // tell the kernel it doesn't need to include the original payload in ACK messages + m_sock->set_option(NetlinkSocketOption(true), ec); + if (ec) { + // not a fatal error + NDN_LOG_DEBUG("setting NETLINK_CAP_ACK failed: " << ec.message()); + } + +#ifdef NDN_CXX_HAVE_NETLINK_EXT_ACK + // enable extended ACK reporting + m_sock->set_option(NetlinkSocketOption(true), ec); + if (ec) { + // not a fatal error + NDN_LOG_DEBUG("setting NETLINK_EXT_ACK failed: " << ec.message()); + } +#endif // NDN_CXX_HAVE_NETLINK_EXT_ACK + + // enable strict checking of get/dump requests + m_sock->set_option(NetlinkSocketOption(true), ec); + if (ec) { + // not a fatal error + NDN_LOG_DEBUG("setting NETLINK_GET_STRICT_CHK failed: " << ec.message()); + } +} + +void +NetlinkSocket::joinGroup(int group) +{ + boost::system::error_code ec; + m_sock->set_option(NetlinkSocketOption(group), ec); + if (ec) { + NDN_THROW(Error("Cannot join netlink group " + to_string(group) + ": " + ec.message())); + } +} + +void +NetlinkSocket::registerNotificationCallback(MessageCallback cb) +{ + registerRequestCallback(0, std::move(cb)); +} + +void +NetlinkSocket::registerRequestCallback(uint32_t seq, MessageCallback cb) +{ + if (cb == nullptr) { + m_pendingRequests.erase(seq); + } + else { + bool wasEmpty = m_pendingRequests.empty(); + m_pendingRequests.emplace(seq, std::move(cb)); + if (wasEmpty) + asyncWait(); + } +} + +std::string +NetlinkSocket::nlmsgTypeToString(uint16_t type) const +{ +#define NLMSG_STRINGIFY(x) case NLMSG_##x: return to_string(type) + "<" #x ">" + switch (type) { + NLMSG_STRINGIFY(NOOP); + NLMSG_STRINGIFY(ERROR); + NLMSG_STRINGIFY(DONE); + NLMSG_STRINGIFY(OVERRUN); + default: + return to_string(type); + } +#undef NLMSG_STRINGIFY +} + +void +NetlinkSocket::asyncWait() +{ + // capture a copy of 'm_sock' to prevent its deallocation while the handler is still pending + auto handler = [this, sock = m_sock] (const boost::system::error_code& ec) { + if (!sock->is_open() || ec == boost::asio::error::operation_aborted) { + // socket was closed, ignore the error + NDN_LOG_DEBUG("netlink socket closed or operation aborted"); + } + else if (ec) { + NDN_LOG_ERROR("read failed: " << ec.message()); + NDN_THROW(Error("Netlink socket read error (" + ec.message() + ")")); + } + else { + receiveAndValidate(); + if (!m_pendingRequests.empty()) + asyncWait(); + } + }; + +#if BOOST_VERSION >= 106600 + m_sock->async_wait(boost::asio::socket_base::wait_read, std::move(handler)); +#else + m_sock->async_receive(boost::asio::null_buffers(), + [h = std::move(handler)] (const boost::system::error_code& ec, size_t) { h(ec); }); +#endif +} + +void +NetlinkSocket::receiveAndValidate() +{ + sockaddr_nl sender{}; + iovec iov{}; + iov.iov_base = m_buffer.data(); + iov.iov_len = m_buffer.size(); + uint8_t cmsgBuffer[CMSG_SPACE(sizeof(nl_pktinfo))]; + msghdr msg{}; + msg.msg_name = &sender; + msg.msg_namelen = sizeof(sender); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsgBuffer; + msg.msg_controllen = sizeof(cmsgBuffer); + + ssize_t nBytesRead = ::recvmsg(m_sock->native_handle(), &msg, 0); + if (nBytesRead < 0) { + if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) { + // not a fatal error + NDN_LOG_DEBUG("recvmsg failed: " << std::strerror(errno)); + return; + } + NDN_LOG_ERROR("recvmsg failed: " << std::strerror(errno)); + NDN_THROW_ERRNO(Error("Netlink socket receive error")); + } + + NDN_LOG_TRACE("read " << nBytesRead << " bytes from netlink socket"); + + if (msg.msg_flags & MSG_TRUNC) { + NDN_LOG_ERROR("truncated message"); + NDN_THROW(Error("Received truncated netlink message")); + // TODO: grow the buffer and start over + } + + if (msg.msg_namelen >= sizeof(sender) && sender.nl_pid != 0) { + NDN_LOG_TRACE("ignoring message from pid=" << sender.nl_pid); + return; + } + + uint32_t nlGroup = 0; + for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_NETLINK && + cmsg->cmsg_type == NETLINK_PKTINFO && + cmsg->cmsg_len == CMSG_LEN(sizeof(nl_pktinfo))) { + const nl_pktinfo* pktinfo = reinterpret_cast(CMSG_DATA(cmsg)); + nlGroup = pktinfo->group; + } + } + + NetlinkMessage nlmsg(m_buffer.data(), static_cast(nBytesRead)); + for (; nlmsg.isValid(); nlmsg = nlmsg.getNext()) { + NDN_LOG_TRACE("parsing " << (nlmsg->nlmsg_flags & NLM_F_MULTI ? "multi-part " : "") << + "message type=" << nlmsgTypeToString(nlmsg->nlmsg_type) << + " len=" << nlmsg->nlmsg_len << + " seq=" << nlmsg->nlmsg_seq << + " pid=" << nlmsg->nlmsg_pid << + " group=" << nlGroup); + + auto cbIt = m_pendingRequests.end(); + if (nlGroup != 0) { + // it's a multicast notification + cbIt = m_pendingRequests.find(0); + } + else if (nlmsg->nlmsg_pid == m_pid) { + // it's for us + cbIt = m_pendingRequests.find(nlmsg->nlmsg_seq); + } + else { + NDN_LOG_TRACE(" pid mismatch, ignoring"); + continue; + } + + if (cbIt == m_pendingRequests.end()) { + NDN_LOG_TRACE(" no handler registered, ignoring"); + continue; + } + else if (nlmsg->nlmsg_flags & NLM_F_DUMP_INTR) { + NDN_LOG_ERROR("dump is inconsistent"); + NDN_THROW(Error("Inconsistency detected in netlink dump")); + // TODO: discard the rest of the message and retry the dump + } + else { + // invoke the callback + BOOST_ASSERT(cbIt->second); + cbIt->second(nlmsg); + } + + // garbage collect the handler if we don't need it anymore: + // do it only if this is a reply message (i.e. not a notification) and either + // (1) it's not a multi-part message, in which case this is the only fragment, or + // (2) it's the last fragment of a multi-part message + if (nlGroup == 0 && (!(nlmsg->nlmsg_flags & NLM_F_MULTI) || nlmsg->nlmsg_type == NLMSG_DONE)) { + NDN_LOG_TRACE("removing handler for seq=" << nlmsg->nlmsg_seq); + BOOST_ASSERT(cbIt != m_pendingRequests.end()); + m_pendingRequests.erase(cbIt); + } + } +} + +RtnlSocket::RtnlSocket(boost::asio::io_service& io) + : NetlinkSocket(io) +{ +} + +void +RtnlSocket::open() +{ + NDN_LOG_TRACE("opening rtnetlink socket"); + NetlinkSocket::open(NETLINK_ROUTE); +} + +void +RtnlSocket::sendDumpRequest(uint16_t nlmsgType, const void* payload, size_t payloadLen, + MessageCallback cb) +{ + struct RtnlMessageHeader + { + alignas(NLMSG_ALIGNTO) nlmsghdr nlh; + }; + static_assert(sizeof(RtnlMessageHeader) == NLMSG_HDRLEN, ""); + + auto hdr = make_shared(); + hdr->nlh.nlmsg_len = sizeof(RtnlMessageHeader) + payloadLen; + hdr->nlh.nlmsg_type = nlmsgType; + hdr->nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + hdr->nlh.nlmsg_seq = ++m_seqNum; + hdr->nlh.nlmsg_pid = m_pid; + + registerRequestCallback(hdr->nlh.nlmsg_seq, std::move(cb)); + + std::array bufs = { + boost::asio::buffer(hdr.get(), sizeof(RtnlMessageHeader)), + boost::asio::buffer(payload, payloadLen) + }; + m_sock->async_send(bufs, + // capture 'hdr' to prevent its premature deallocation + [this, hdr] (const boost::system::error_code& ec, size_t) { + if (!ec) { + NDN_LOG_TRACE("sent dump request type=" << nlmsgTypeToString(hdr->nlh.nlmsg_type) + << " seq=" << hdr->nlh.nlmsg_seq); + } + else if (ec != boost::asio::error::operation_aborted) { + NDN_LOG_ERROR("send failed: " << ec.message()); + NDN_THROW(Error("Failed to send netlink request (" + ec.message() + ")")); + } + }); +} + +std::string +RtnlSocket::nlmsgTypeToString(uint16_t type) const +{ +#define RTM_STRINGIFY(x) case RTM_##x: return to_string(type) + "<" #x ">" + switch (type) { + RTM_STRINGIFY(NEWLINK); + RTM_STRINGIFY(DELLINK); + RTM_STRINGIFY(GETLINK); + RTM_STRINGIFY(NEWADDR); + RTM_STRINGIFY(DELADDR); + RTM_STRINGIFY(GETADDR); + RTM_STRINGIFY(NEWROUTE); + RTM_STRINGIFY(DELROUTE); + RTM_STRINGIFY(GETROUTE); + default: + return NetlinkSocket::nlmsgTypeToString(type); + } +#undef RTM_STRINGIFY +} + +GenlSocket::GenlSocket(boost::asio::io_service& io) + : NetlinkSocket(io) +{ + m_cachedFamilyIds["nlctrl"] = GENL_ID_CTRL; +} + +void +GenlSocket::open() +{ + NDN_LOG_TRACE("opening genetlink socket"); + NetlinkSocket::open(NETLINK_GENERIC); +} + +void +GenlSocket::sendRequest(const std::string& familyName, uint8_t command, + const void* payload, size_t payloadLen, + MessageCallback messageCb, std::function errorCb) +{ + auto it = m_cachedFamilyIds.find(familyName); + if (it != m_cachedFamilyIds.end()) { + if (it->second >= GENL_MIN_ID) { + sendRequest(it->second, command, payload, payloadLen, std::move(messageCb)); + } + else if (errorCb) { + errorCb(); + } + return; + } + + auto ret = m_familyResolvers.emplace(std::piecewise_construct, + std::forward_as_tuple(familyName), + std::forward_as_tuple(familyName, *this)); + auto& resolver = ret.first->second; + if (ret.second) { + // cache the result + resolver.onResolved.connectSingleShot([=] (uint16_t familyId) { + m_cachedFamilyIds[familyName] = familyId; + }); + resolver.onError.connectSingleShot([=] { + m_cachedFamilyIds[familyName] = 0; + }); + } + resolver.onResolved.connectSingleShot([=, cb = std::move(messageCb)] (uint16_t familyId) { + sendRequest(familyId, command, payload, payloadLen, std::move(cb)); + }); + if (errorCb) { + resolver.onError.connectSingleShot(std::move(errorCb)); + } +} + +void +GenlSocket::sendRequest(uint16_t familyId, uint8_t command, + const void* payload, size_t payloadLen, MessageCallback cb) +{ + struct GenlMessageHeader + { + alignas(NLMSG_ALIGNTO) nlmsghdr nlh; + alignas(NLMSG_ALIGNTO) genlmsghdr genlh; + }; + static_assert(sizeof(GenlMessageHeader) == NLMSG_SPACE(GENL_HDRLEN), ""); + + auto hdr = make_shared(); + hdr->nlh.nlmsg_len = sizeof(GenlMessageHeader) + payloadLen; + hdr->nlh.nlmsg_type = familyId; + hdr->nlh.nlmsg_flags = NLM_F_REQUEST; + hdr->nlh.nlmsg_seq = ++m_seqNum; + hdr->nlh.nlmsg_pid = m_pid; + hdr->genlh.cmd = command; + hdr->genlh.version = 1; + + registerRequestCallback(hdr->nlh.nlmsg_seq, std::move(cb)); + + std::array bufs = { + boost::asio::buffer(hdr.get(), sizeof(GenlMessageHeader)), + boost::asio::buffer(payload, payloadLen) + }; + m_sock->async_send(bufs, + // capture 'hdr' to prevent its premature deallocation + [this, hdr] (const boost::system::error_code& ec, size_t) { + if (!ec) { + NDN_LOG_TRACE("sent genl request type=" << nlmsgTypeToString(hdr->nlh.nlmsg_type) << + " cmd=" << static_cast(hdr->genlh.cmd) << + " seq=" << hdr->nlh.nlmsg_seq); + } + else if (ec != boost::asio::error::operation_aborted) { + NDN_LOG_ERROR("send failed: " << ec.message()); + NDN_THROW(Error("Failed to send netlink request (" + ec.message() + ")")); + } + }); +} + +GenlFamilyResolver::GenlFamilyResolver(std::string familyName, GenlSocket& socket) + : m_sock(socket) + , m_family(std::move(familyName)) +{ + if (m_family.size() >= GENL_NAMSIZ) { + NDN_THROW(std::invalid_argument("netlink family name '" + m_family + "' too long")); + } + + NDN_LOG_TRACE("resolving netlink family " << m_family); + asyncResolve(); +} + +void +GenlFamilyResolver::asyncResolve() +{ + struct FamilyNameAttribute + { + alignas(NLA_ALIGNTO) nlattr nla; + alignas(NLA_ALIGNTO) char name[GENL_NAMSIZ]; + }; + + auto attr = make_shared(); + attr->nla.nla_type = CTRL_ATTR_FAMILY_NAME; + attr->nla.nla_len = NLA_HDRLEN + m_family.size() + 1; + ::strncpy(attr->name, m_family.data(), GENL_NAMSIZ); + + m_sock.sendRequest(GENL_ID_CTRL, CTRL_CMD_GETFAMILY, attr.get(), attr->nla.nla_len, + // capture 'attr' to prevent its premature deallocation + [this, attr] (const auto& msg) { this->handleResolve(msg); }); +} + +void +GenlFamilyResolver::handleResolve(const NetlinkMessage& nlmsg) +{ + switch (nlmsg->nlmsg_type) { + case NLMSG_ERROR: { + const nlmsgerr* err = nlmsg.getPayload(); + if (err == nullptr) { + NDN_LOG_WARN("malformed nlmsgerr"); + } + else if (err->error != 0) { + NDN_LOG_DEBUG(" failed to resolve netlink family " << m_family + << ": " << std::strerror(std::abs(err->error))); + } + onError(); + break; + } + + case GENL_ID_CTRL: { + const genlmsghdr* genlh = nlmsg.getPayload(); + if (genlh == nullptr) { + NDN_LOG_WARN("malformed genlmsghdr"); + return onError(); + } + if (genlh->cmd != CTRL_CMD_NEWFAMILY) { + NDN_LOG_WARN("unexpected genl cmd=" << static_cast(genlh->cmd)); + return onError(); + } + + auto attrs = nlmsg.getAttributes(genlh); + auto familyName = attrs.getAttributeByType(CTRL_ATTR_FAMILY_NAME); + if (familyName && *familyName != m_family) { + NDN_LOG_WARN("CTRL_ATTR_FAMILY_NAME mismatch: " << *familyName << " != " << m_family); + return onError(); + } + auto familyId = attrs.getAttributeByType(CTRL_ATTR_FAMILY_ID); + if (!familyId) { + NDN_LOG_WARN("missing CTRL_ATTR_FAMILY_ID"); + return onError(); + } + if (*familyId < GENL_MIN_ID) { + NDN_LOG_WARN("invalid CTRL_ATTR_FAMILY_ID=" << *familyId); + return onError(); + } + + NDN_LOG_TRACE(" resolved netlink family name=" << m_family << " id=" << *familyId); + onResolved(*familyId); + break; + } + + default: { + NDN_LOG_WARN("unexpected message type"); + onError(); + break; + } + } +} + +std::string +GenlSocket::nlmsgTypeToString(uint16_t type) const +{ + if (type >= GENL_MIN_ID) { + for (const auto& p : m_cachedFamilyIds) { + if (p.second == type) { + return to_string(type) + "<" + p.first + ">"; + } + } + } + + return NetlinkSocket::nlmsgTypeToString(type); +} + +} // namespace net +} // namespace ndn diff --git a/ndn-cxx/net/impl/netlink-socket.hpp b/ndn-cxx/net/impl/netlink-socket.hpp new file mode 100644 index 000000000..46ff6bc1d --- /dev/null +++ b/ndn-cxx/net/impl/netlink-socket.hpp @@ -0,0 +1,159 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Davide Pesavento + */ + +#ifndef NDN_NET_NETLINK_SOCKET_HPP +#define NDN_NET_NETLINK_SOCKET_HPP + +#include "ndn-cxx/net/network-monitor.hpp" +#include "ndn-cxx/util/signal/signal.hpp" + +#include +#include +#include + +#ifndef NDN_CXX_HAVE_NETLINK +#error "This file should not be included ..." +#endif + +namespace ndn { +namespace net { + +class NetlinkMessage; + +class NetlinkSocket : noncopyable +{ +public: + using Error = NetworkMonitor::Error; + using MessageCallback = std::function; + + void + joinGroup(int group); + + void + registerNotificationCallback(MessageCallback cb); + +protected: + explicit + NetlinkSocket(boost::asio::io_service& io); + + ~NetlinkSocket(); + + void + open(int protocol); + + void + registerRequestCallback(uint32_t seq, MessageCallback cb); + + virtual std::string + nlmsgTypeToString(uint16_t type) const; + +private: + void + asyncWait(); + + void + receiveAndValidate(); + +protected: + shared_ptr m_sock; ///< netlink socket descriptor + uint32_t m_pid; ///< port ID of this socket + uint32_t m_seqNum; ///< sequence number of the last netlink request sent to the kernel + +private: + std::vector m_buffer; ///< buffer for netlink messages from the kernel + std::map m_pendingRequests; ///< request sequence number => callback +}; + +class RtnlSocket final : public NetlinkSocket +{ +public: + explicit + RtnlSocket(boost::asio::io_service& io); + + void + open(); + + void + sendDumpRequest(uint16_t nlmsgType, + const void* payload, size_t payloadLen, + MessageCallback cb); + +protected: + std::string + nlmsgTypeToString(uint16_t type) const final; +}; + +class GenlSocket; + +class GenlFamilyResolver : noncopyable +{ +public: + GenlFamilyResolver(std::string familyName, GenlSocket& socket); + + util::Signal onResolved; + util::Signal onError; + +private: + void + asyncResolve(); + + void + handleResolve(const NetlinkMessage& nlmsg); + +private: + GenlSocket& m_sock; + std::string m_family; +}; + +class GenlSocket final : public NetlinkSocket +{ +public: + explicit + GenlSocket(boost::asio::io_service& io); + + void + open(); + + void + sendRequest(const std::string& familyName, uint8_t command, + const void* payload, size_t payloadLen, + MessageCallback messageCb, std::function errorCb); + + void + sendRequest(uint16_t familyId, uint8_t command, + const void* payload, size_t payloadLen, + MessageCallback messageCb); + +protected: + std::string + nlmsgTypeToString(uint16_t type) const final; + +private: + std::map m_cachedFamilyIds; ///< family name => family id + std::map m_familyResolvers; ///< family name => resolver instance +}; + +} // namespace net +} // namespace ndn + +#endif // NDN_NET_NETLINK_SOCKET_HPP diff --git a/ndn-cxx/net/impl/network-monitor-impl-netlink.cpp b/ndn-cxx/net/impl/network-monitor-impl-netlink.cpp new file mode 100644 index 000000000..39e6505be --- /dev/null +++ b/ndn-cxx/net/impl/network-monitor-impl-netlink.cpp @@ -0,0 +1,449 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Davide Pesavento + */ + +#include "ndn-cxx/net/impl/network-monitor-impl-netlink.hpp" +#include "ndn-cxx/net/impl/linux-if-constants.hpp" +#include "ndn-cxx/net/impl/netlink-message.hpp" +#include "ndn-cxx/net/network-address.hpp" +#include "ndn-cxx/net/network-interface.hpp" +#include "ndn-cxx/util/logger.hpp" + +#include +#include +#include + +#include +#include + +#ifndef RTEXT_FILTER_SKIP_STATS +#define RTEXT_FILTER_SKIP_STATS (1 << 3) +#endif + +NDN_LOG_INIT(ndn.NetworkMonitor); + +namespace ndn { +namespace net { + +NetworkMonitorImplNetlink::NetworkMonitorImplNetlink(boost::asio::io_service& io) + : m_rtnlSocket(io) + , m_genlSocket(io) +{ + m_rtnlSocket.open(); + + for (auto group : {RTNLGRP_LINK, + RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV4_ROUTE, + RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV6_ROUTE}) { + m_rtnlSocket.joinGroup(group); + } + m_rtnlSocket.registerNotificationCallback([this] (const auto& msg) { this->parseRtnlMessage(msg); }); + + enumerateLinks(); +} + +shared_ptr +NetworkMonitorImplNetlink::getNetworkInterface(const std::string& ifname) const +{ + for (const auto& interface : m_interfaces | boost::adaptors::map_values) { + if (interface->getName() == ifname) + return interface; + } + return nullptr; +} + +std::vector> +NetworkMonitorImplNetlink::listNetworkInterfaces() const +{ + std::vector> v; + v.reserve(m_interfaces.size()); + boost::push_back(v, m_interfaces | boost::adaptors::map_values); + return v; +} + +void +NetworkMonitorImplNetlink::enumerateLinks() +{ + NDN_LOG_TRACE("enumerating links"); + m_phase = ENUMERATING_LINKS; + + struct IfInfoMessage + { + alignas(NLMSG_ALIGNTO) ifinfomsg ifi; + alignas(RTA_ALIGNTO) rtattr rta; + alignas(RTA_ALIGNTO) uint32_t rtext; // space for IFLA_EXT_MASK + }; + + auto payload = make_shared(); + payload->ifi.ifi_family = AF_UNSPEC; + payload->rta.rta_type = IFLA_EXT_MASK; + payload->rta.rta_len = RTA_LENGTH(sizeof(payload->rtext)); + payload->rtext = RTEXT_FILTER_SKIP_STATS; + + m_rtnlSocket.sendDumpRequest(RTM_GETLINK, payload.get(), sizeof(IfInfoMessage), + // capture 'payload' to prevent its premature deallocation + [this, payload] (const auto& msg) { this->parseRtnlMessage(msg); }); +} + +void +NetworkMonitorImplNetlink::enumerateAddrs() +{ + NDN_LOG_TRACE("enumerating addresses"); + m_phase = ENUMERATING_ADDRS; + + struct IfAddrMessage + { + alignas(NLMSG_ALIGNTO) ifaddrmsg ifa; + }; + + auto payload = make_shared(); + payload->ifa.ifa_family = AF_UNSPEC; + + m_rtnlSocket.sendDumpRequest(RTM_GETADDR, payload.get(), sizeof(IfAddrMessage), + // capture 'payload' to prevent its premature deallocation + [this, payload] (const auto& msg) { this->parseRtnlMessage(msg); }); +} + +void +NetworkMonitorImplNetlink::enumerateRoutes() +{ + // TODO: enumerate routes + //NDN_LOG_TRACE("enumerating routes"); + //m_phase = ENUMERATING_ROUTES; + + NDN_LOG_DEBUG("enumeration complete"); + m_phase = ENUMERATION_COMPLETE; + this->emitSignal(onEnumerationCompleted); +} + +void +NetworkMonitorImplNetlink::parseRtnlMessage(const NetlinkMessage& nlmsg) +{ + switch (nlmsg->nlmsg_type) { + case RTM_NEWLINK: + case RTM_DELLINK: + parseLinkMessage(nlmsg); + if (m_phase == ENUMERATION_COMPLETE) + this->emitSignal(onNetworkStateChanged); // backward compat + break; + + case RTM_NEWADDR: + case RTM_DELADDR: + parseAddressMessage(nlmsg); + if (m_phase == ENUMERATION_COMPLETE) + this->emitSignal(onNetworkStateChanged); // backward compat + break; + + case RTM_NEWROUTE: + case RTM_DELROUTE: + parseRouteMessage(nlmsg); + if (m_phase == ENUMERATION_COMPLETE) + this->emitSignal(onNetworkStateChanged); // backward compat + break; + + case NLMSG_DONE: + parseDoneMessage(nlmsg); + break; + + case NLMSG_ERROR: + parseErrorMessage(nlmsg); + break; + } +} + +static InterfaceType +ifiTypeToInterfaceType(uint16_t type) +{ + switch (type) { + case ARPHRD_ETHER: + return InterfaceType::ETHERNET; + case ARPHRD_LOOPBACK: + return InterfaceType::LOOPBACK; + default: + return InterfaceType::UNKNOWN; + } +} + +static AddressFamily +ifaFamilyToAddressFamily(uint8_t family) +{ + switch (family) { + case AF_INET: + return AddressFamily::V4; + case AF_INET6: + return AddressFamily::V6; + default: + return AddressFamily::UNSPECIFIED; + } +} + +static AddressScope +ifaScopeToAddressScope(uint8_t scope) +{ + switch (scope) { + case RT_SCOPE_NOWHERE: + return AddressScope::NOWHERE; + case RT_SCOPE_HOST: + return AddressScope::HOST; + case RT_SCOPE_LINK: + return AddressScope::LINK; + default: + return AddressScope::GLOBAL; + } +} + +static void +updateInterfaceState(NetworkInterface& interface, uint8_t operState) +{ + if (operState == linux_if::OPER_STATE_UP) { + interface.setState(InterfaceState::RUNNING); + } + else if (operState == linux_if::OPER_STATE_DORMANT) { + interface.setState(InterfaceState::DORMANT); + } + else { + // fallback to flags + auto flags = interface.getFlags(); + if ((flags & linux_if::FLAG_LOWER_UP) && !(flags & linux_if::FLAG_DORMANT)) + interface.setState(InterfaceState::RUNNING); + else if (flags & IFF_UP) + interface.setState(InterfaceState::NO_CARRIER); + else + interface.setState(InterfaceState::DOWN); + } +} + +#ifdef NDN_CXX_HAVE_NETLINK_EXT_ACK +static void +parseExtAckAttributes(const NetlinkMessageAttributes& attrs, bool isError) +{ + NDN_LOG_TRACE(" message contains " << attrs.size() << " attributes"); + + auto msg = attrs.getAttributeByType(NLMSGERR_ATTR_MSG); + if (msg && !msg->empty()) { + if (isError) + NDN_LOG_ERROR(" extended err: " << *msg); + else + NDN_LOG_DEBUG(" extended msg: " << *msg); + } +} +#endif // NDN_CXX_HAVE_NETLINK_EXT_ACK + +void +NetworkMonitorImplNetlink::parseLinkMessage(const NetlinkMessage& nlmsg) +{ + const ifinfomsg* ifi = nlmsg.getPayload(); + if (ifi == nullptr) { + NDN_LOG_WARN("malformed ifinfomsg"); + return; + } + + if (ifiTypeToInterfaceType(ifi->ifi_type) == InterfaceType::UNKNOWN) { + NDN_LOG_DEBUG(" unhandled interface type " << ifi->ifi_type); + return; + } + + shared_ptr interface; + auto it = m_interfaces.find(ifi->ifi_index); + if (it != m_interfaces.end()) { + interface = it->second; + BOOST_ASSERT(interface != nullptr); + BOOST_ASSERT(interface->getIndex() == ifi->ifi_index); + } + + if (nlmsg->nlmsg_type == RTM_DELLINK) { + if (interface != nullptr) { + NDN_LOG_DEBUG(" removing interface " << interface->getName()); + m_interfaces.erase(it); + this->emitSignal(onInterfaceRemoved, interface); + } + return; + } + + if (interface == nullptr) { + interface = makeNetworkInterface(); + interface->setIndex(ifi->ifi_index); + } + interface->setType(ifiTypeToInterfaceType(ifi->ifi_type)); + interface->setFlags(ifi->ifi_flags); + + auto attrs = nlmsg.getAttributes(ifi); + NDN_LOG_TRACE(" message contains " << attrs.size() << " attributes"); + + auto address = attrs.getAttributeByType(IFLA_ADDRESS); + if (address) + interface->setEthernetAddress(*address); + + auto broadcast = attrs.getAttributeByType(IFLA_BROADCAST); + if (broadcast) + interface->setEthernetBroadcastAddress(*broadcast); + + auto name = attrs.getAttributeByType(IFLA_IFNAME); + if (name) + interface->setName(*name); + + auto mtu = attrs.getAttributeByType(IFLA_MTU); + if (mtu) + interface->setMtu(*mtu); + + auto state = attrs.getAttributeByType(IFLA_OPERSTATE); + updateInterfaceState(*interface, state ? *state : linux_if::OPER_STATE_UNKNOWN); + + if (it == m_interfaces.end()) { + NDN_LOG_DEBUG(" adding interface " << interface->getName()); + m_interfaces[interface->getIndex()] = interface; + this->emitSignal(onInterfaceAdded, interface); + } +} + +void +NetworkMonitorImplNetlink::parseAddressMessage(const NetlinkMessage& nlmsg) +{ + const ifaddrmsg* ifa = nlmsg.getPayload(); + if (ifa == nullptr) { + NDN_LOG_WARN("malformed ifaddrmsg"); + return; + } + + auto it = m_interfaces.find(ifa->ifa_index); + if (it == m_interfaces.end()) { + // unknown interface, ignore message + NDN_LOG_TRACE(" unknown interface index " << ifa->ifa_index); + return; + } + auto interface = it->second; + BOOST_ASSERT(interface != nullptr); + + auto attrs = nlmsg.getAttributes(ifa); + NDN_LOG_TRACE(" message contains " << attrs.size() << " attributes"); + + namespace ip = boost::asio::ip; + ip::address ipAddr, broadcastAddr; + if (ifa->ifa_family == AF_INET) { + auto v4 = attrs.getAttributeByType(IFA_LOCAL); + if (v4) + ipAddr = *v4; + + v4 = attrs.getAttributeByType(IFA_BROADCAST); + if (v4) + broadcastAddr = *v4; + } + else if (ifa->ifa_family == AF_INET6) { + auto v6 = attrs.getAttributeByType(IFA_ADDRESS); + if (v6) { + if (v6->is_link_local()) + v6->scope_id(ifa->ifa_index); + + ipAddr = *v6; + } + } + + uint32_t flags = ifa->ifa_flags; // overwritten by IFA_FLAGS if supported and present +#ifdef NDN_CXX_HAVE_IFA_FLAGS + auto extFlags = attrs.getAttributeByType(IFA_FLAGS); + if (extFlags) + flags = *extFlags; +#endif // NDN_CXX_HAVE_IFA_FLAGS + + NetworkAddress address(ifaFamilyToAddressFamily(ifa->ifa_family), + ipAddr, + broadcastAddr, + ifa->ifa_prefixlen, + ifaScopeToAddressScope(ifa->ifa_scope), + flags); + BOOST_ASSERT(address.getFamily() != AddressFamily::UNSPECIFIED); + + if (nlmsg->nlmsg_type == RTM_NEWADDR) + interface->addNetworkAddress(address); + else if (nlmsg->nlmsg_type == RTM_DELADDR) + interface->removeNetworkAddress(address); +} + +void +NetworkMonitorImplNetlink::parseRouteMessage(const NetlinkMessage& nlmsg) +{ + // TODO +} + +void +NetworkMonitorImplNetlink::parseDoneMessage(const NetlinkMessage& nlmsg) +{ + const int* errcode = nlmsg.getPayload(); + if (errcode == nullptr) { + NDN_LOG_WARN("malformed NLMSG_DONE"); + } + else { + if (*errcode != 0) { + NDN_LOG_ERROR("NLMSG_DONE err=" << *errcode << " " << std::strerror(std::abs(*errcode))); + } +#ifdef NDN_CXX_HAVE_NETLINK_EXT_ACK + if (nlmsg->nlmsg_flags & NLM_F_ACK_TLVS) { + parseExtAckAttributes(nlmsg.getAttributes(errcode), *errcode != 0); + } +#endif // NDN_CXX_HAVE_NETLINK_EXT_ACK + } + + switch (m_phase) { + case ENUMERATING_LINKS: + // links enumeration complete, now request all the addresses + enumerateAddrs(); + break; + case ENUMERATING_ADDRS: + // links and addresses enumeration complete, now request all the routes + enumerateRoutes(); + break; + default: + break; + } +} + +void +NetworkMonitorImplNetlink::parseErrorMessage(const NetlinkMessage& nlmsg) +{ + const nlmsgerr* err = nlmsg.getPayload(); + if (err == nullptr) { + NDN_LOG_WARN("malformed NLMSG_ERROR"); + return; + } + + if (err->error != 0) + NDN_LOG_ERROR("NLMSG_ERROR for seq=" << err->msg.nlmsg_seq + << " err=" << err->error << " " << std::strerror(std::abs(err->error))); + +#ifdef NDN_CXX_HAVE_NETLINK_EXT_ACK + if (!(nlmsg->nlmsg_flags & NLM_F_ACK_TLVS)) + return; + + size_t errLen = NLMSG_LENGTH(sizeof(nlmsgerr)); + if (!(nlmsg->nlmsg_flags & NLM_F_CAPPED)) + errLen += err->msg.nlmsg_len - NLMSG_HDRLEN; // don't count the inner nlmsghdr twice + + if (nlmsg->nlmsg_len <= errLen) + return; + + auto nla = reinterpret_cast(reinterpret_cast(&*nlmsg) + errLen); + auto attrs = NetlinkMessageAttributes(nla, nlmsg->nlmsg_len - errLen); + parseExtAckAttributes(attrs, err->error != 0); +#endif // NDN_CXX_HAVE_NETLINK_EXT_ACK +} + +} // namespace net +} // namespace ndn diff --git a/ndn-cxx/net/impl/network-monitor-impl-netlink.hpp b/ndn-cxx/net/impl/network-monitor-impl-netlink.hpp new file mode 100644 index 000000000..4bcc755b1 --- /dev/null +++ b/ndn-cxx/net/impl/network-monitor-impl-netlink.hpp @@ -0,0 +1,110 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Davide Pesavento + */ + +#ifndef NDN_NET_NETWORK_MONITOR_IMPL_NETLINK_HPP +#define NDN_NET_NETWORK_MONITOR_IMPL_NETLINK_HPP + +#include "ndn-cxx/detail/config.hpp" +#include "ndn-cxx/net/network-monitor.hpp" + +#ifndef NDN_CXX_HAVE_NETLINK +#error "This file should not be included ..." +#endif + +#include "ndn-cxx/net/impl/netlink-socket.hpp" + +#include + +namespace ndn { +namespace net { + +class NetworkMonitorImplNetlink : public NetworkMonitorImpl +{ +public: + /** \brief initialize netlink socket and start enumerating interfaces + */ + explicit + NetworkMonitorImplNetlink(boost::asio::io_service& io); + + uint32_t + getCapabilities() const final + { + return NetworkMonitor::CAP_ENUM | + NetworkMonitor::CAP_IF_ADD_REMOVE | + NetworkMonitor::CAP_STATE_CHANGE | + NetworkMonitor::CAP_MTU_CHANGE | + NetworkMonitor::CAP_ADDR_ADD_REMOVE; + } + + shared_ptr + getNetworkInterface(const std::string& ifname) const final; + + std::vector> + listNetworkInterfaces() const final; + +private: + void + enumerateLinks(); + + void + enumerateAddrs(); + + void + enumerateRoutes(); + + void + parseRtnlMessage(const NetlinkMessage& nlmsg); + + void + parseLinkMessage(const NetlinkMessage& nlmsg); + + void + parseAddressMessage(const NetlinkMessage& nlmsg); + + void + parseRouteMessage(const NetlinkMessage& nlmsg); + + void + parseDoneMessage(const NetlinkMessage& nlmsg); + + void + parseErrorMessage(const NetlinkMessage& nlmsg); + +private: + std::map> m_interfaces; ///< ifindex => interface + RtnlSocket m_rtnlSocket; ///< rtnetlink socket + GenlSocket m_genlSocket; ///< generic netlink socket to communicate with nl80211 + + enum { + ENUMERATION_NOT_STARTED, + ENUMERATING_LINKS, ///< a dump of all links (RTM_GETLINK) is in progress + ENUMERATING_ADDRS, ///< a dump of all addresses (RTM_GETADDR) is in progress + ENUMERATING_ROUTES, ///< a dump of all routes (RTM_GETROUTE) is in progress (unimplemented) + ENUMERATION_COMPLETE, + } m_phase = ENUMERATION_NOT_STARTED; +}; + +} // namespace net +} // namespace ndn + +#endif // NDN_NET_NETWORK_MONITOR_IMPL_NETLINK_HPP diff --git a/ndn-cxx/net/impl/network-monitor-impl-noop.hpp b/ndn-cxx/net/impl/network-monitor-impl-noop.hpp new file mode 100644 index 000000000..a8c79687d --- /dev/null +++ b/ndn-cxx/net/impl/network-monitor-impl-noop.hpp @@ -0,0 +1,62 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Davide Pesavento + */ + +#ifndef NDN_NET_NETWORK_MONITOR_IMPL_NOOP_HPP +#define NDN_NET_NETWORK_MONITOR_IMPL_NOOP_HPP + +#include "ndn-cxx/net/network-monitor.hpp" + +namespace ndn { +namespace net { + +class NetworkMonitorImplNoop : public NetworkMonitorImpl +{ +public: + explicit + NetworkMonitorImplNoop(boost::asio::io_service&) + { + } + + uint32_t + getCapabilities() const final + { + return NetworkMonitor::CAP_NONE; + } + + shared_ptr + getNetworkInterface(const std::string&) const final + { + return {}; + } + + std::vector> + listNetworkInterfaces() const final + { + return {}; + } +}; + +} // namespace net +} // namespace ndn + +#endif // NDN_NET_NETWORK_MONITOR_IMPL_NOOP_HPP diff --git a/ndn-cxx/net/impl/network-monitor-impl-osx.cpp b/ndn-cxx/net/impl/network-monitor-impl-osx.cpp new file mode 100644 index 000000000..b10c6eb9d --- /dev/null +++ b/ndn-cxx/net/impl/network-monitor-impl-osx.cpp @@ -0,0 +1,465 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * + * Parts of this implementation is based on daemondo command of MacPorts + * (https://www.macports.org/): + * + * Copyright (c) 2005-2007 James Berry + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The MacPorts Project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ndn-cxx/net/impl/network-monitor-impl-osx.hpp" +#include "ndn-cxx/name.hpp" +#include "ndn-cxx/detail/cf-string-osx.hpp" +#include "ndn-cxx/net/network-address.hpp" +#include "ndn-cxx/util/logger.hpp" + +#include // for getifaddrs() +#include // for if_nametoindex() +#include // for struct sockaddr_dl +#include // for IFT_* constants +#include // for struct sockaddr_in{,6} + +#include +#include +#include +#include +#include + +NDN_LOG_INIT(ndn.NetworkMonitor); + +namespace ndn { +namespace net { + +using detail::CFReleaser; + +class IfAddrs : noncopyable +{ +public: + IfAddrs() + { + if (::getifaddrs(&m_ifaList) < 0) { + NDN_THROW_ERRNO(NetworkMonitorImplOsx::Error("getifaddrs() failed")); + } + } + + ~IfAddrs() + { + if (m_ifaList != nullptr) { + ::freeifaddrs(m_ifaList); + } + } + + ifaddrs* + get() const noexcept + { + return m_ifaList; + } + +private: + ifaddrs* m_ifaList = nullptr; +}; + +NetworkMonitorImplOsx::NetworkMonitorImplOsx(boost::asio::io_service& io) + : m_scheduler(io) + , m_context{0, this, nullptr, nullptr, nullptr} + , m_scStore(SCDynamicStoreCreate(nullptr, CFSTR("net.named-data.ndn-cxx.NetworkMonitor"), + &NetworkMonitorImplOsx::onConfigChanged, &m_context)) + , m_loopSource(SCDynamicStoreCreateRunLoopSource(nullptr, m_scStore.get(), 0)) + , m_ioctlSocket(io, boost::asio::ip::udp::v4()) +{ + scheduleCfLoop(); + + // Notifications from Darwin Notify Center: + // + // com.apple.system.config.network_change + // + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), + static_cast(this), + &NetworkMonitorImplOsx::afterNotificationCenterEvent, + CFSTR("com.apple.system.config.network_change"), + nullptr, // object to observe + CFNotificationSuspensionBehaviorDeliverImmediately); + + CFRunLoopAddSource(CFRunLoopGetCurrent(), m_loopSource.get(), kCFRunLoopDefaultMode); + + // Notifications from SystemConfiguration: + // + // State:/Network/Interface/.*/Link + // State:/Network/Interface/.*/IPv4 + // State:/Network/Interface/.*/IPv6 + // State:/Network/Interface/.*/AirPort (not used) + // + // https://developer.apple.com/library/content/documentation/Networking/Conceptual/SystemConfigFrameworks/SC_UnderstandSchema/SC_UnderstandSchema.html + // + auto patterns = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/.*/Link")); + CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/.*/IPv4")); + CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/.*/IPv6")); + + if (!SCDynamicStoreSetNotificationKeys(m_scStore.get(), nullptr, patterns)) { + NDN_THROW(Error("SCDynamicStoreSetNotificationKeys failed")); + } + + io.post([this] { enumerateInterfaces(); }); +} + +NetworkMonitorImplOsx::~NetworkMonitorImplOsx() +{ + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_loopSource.get(), kCFRunLoopDefaultMode); + + CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDarwinNotifyCenter(), + static_cast(this)); +} + +shared_ptr +NetworkMonitorImplOsx::getNetworkInterface(const std::string& ifname) const +{ + auto it = m_interfaces.find(ifname); + return it == m_interfaces.end() ? nullptr : it->second; +} + +std::vector> +NetworkMonitorImplOsx::listNetworkInterfaces() const +{ + std::vector> v; + v.reserve(m_interfaces.size()); + boost::push_back(v, m_interfaces | boost::adaptors::map_values); + return v; +} + +void +NetworkMonitorImplOsx::afterNotificationCenterEvent(CFNotificationCenterRef center, + void* observer, + CFStringRef name, + const void* object, + CFDictionaryRef userInfo) +{ + static_cast(observer)->emitSignal(onNetworkStateChanged); +} + +void +NetworkMonitorImplOsx::scheduleCfLoop() +{ + // poll each second for new events + m_cfLoopEvent = m_scheduler.schedule(1_s, [this] { + // this should dispatch ready events and exit + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); + scheduleCfLoop(); + }); +} + +void +NetworkMonitorImplOsx::enumerateInterfaces() +{ + IfAddrs ifaList; + for (const auto& ifName : getInterfaceNames()) { + addNewInterface(ifName, ifaList); + } + this->emitSignal(onEnumerationCompleted); +} + +std::set +NetworkMonitorImplOsx::getInterfaceNames() const +{ + CFReleaser dict = + (CFDictionaryRef)SCDynamicStoreCopyValue(m_scStore.get(), CFSTR("State:/Network/Interface")); + if (dict.get() == nullptr) { + return {}; + } + + CFArrayRef interfaces = (CFArrayRef)CFDictionaryGetValue(dict.get(), CFSTR("Interfaces")); + if (interfaces == nullptr) { + return {}; + } + + std::set ifNames; + size_t count = CFArrayGetCount(interfaces); + for (size_t i = 0; i != count; ++i) { + auto ifName = (CFStringRef)CFArrayGetValueAtIndex(interfaces, i); + ifNames.insert(detail::cfstring::toStdString(ifName)); + } + return ifNames; +} + +void +NetworkMonitorImplOsx::addNewInterface(const std::string& ifName, const IfAddrs& ifaList) +{ + shared_ptr interface = makeNetworkInterface(); + interface->setName(ifName); + interface->setState(getInterfaceState(*interface)); + updateInterfaceInfo(*interface, ifaList); + + if (interface->getType() == InterfaceType::UNKNOWN) { + NDN_LOG_DEBUG("ignoring " << ifName << " due to unhandled interface type"); + return; + } + + NDN_LOG_DEBUG("adding interface " << interface->getName()); + m_interfaces[interface->getName()] = interface; + this->emitSignal(onInterfaceAdded, interface); +} + +InterfaceState +NetworkMonitorImplOsx::getInterfaceState(const NetworkInterface& netif) const +{ + CFReleaser linkName = + detail::cfstring::fromStdString("State:/Network/Interface/" + netif.getName() + "/Link"); + + CFReleaser dict = + (CFDictionaryRef)SCDynamicStoreCopyValue(m_scStore.get(), linkName.get()); + if (dict.get() == nullptr) { + return InterfaceState::UNKNOWN; + } + + CFBooleanRef isActive = (CFBooleanRef)CFDictionaryGetValue(dict.get(), CFSTR("Active")); + if (isActive == nullptr) { + return InterfaceState::UNKNOWN; + } + + return CFBooleanGetValue(isActive) ? InterfaceState::RUNNING : InterfaceState::DOWN; +} + +size_t +NetworkMonitorImplOsx::getInterfaceMtu(const NetworkInterface& netif) +{ + ifreq ifr{}; + std::strncpy(ifr.ifr_name, netif.getName().data(), sizeof(ifr.ifr_name) - 1); + + if (::ioctl(m_ioctlSocket.native_handle(), SIOCGIFMTU, &ifr) == 0) { + return static_cast(ifr.ifr_mtu); + } + + NDN_LOG_WARN("failed to get MTU of " << netif.getName() << ": " << std::strerror(errno)); + return ethernet::MAX_DATA_LEN; +} + +template +static uint8_t +computePrefixLength(const AddressBytes& mask) +{ + uint8_t prefixLength = 0; + for (auto byte : mask) { + while (byte != 0) { + ++prefixLength; + byte <<= 1; + } + } + return prefixLength; +} + +void +NetworkMonitorImplOsx::updateInterfaceInfo(NetworkInterface& netif, const IfAddrs& ifaList) +{ + BOOST_ASSERT(!netif.getName().empty()); + + netif.setMtu(getInterfaceMtu(netif)); + + for (ifaddrs* ifa = ifaList.get(); ifa != nullptr; ifa = ifa->ifa_next) { + if (ifa->ifa_name != netif.getName()) + continue; + + netif.setFlags(ifa->ifa_flags); + + if (ifa->ifa_addr == nullptr) + continue; + + namespace ip = boost::asio::ip; + AddressFamily addrFamily = AddressFamily::UNSPECIFIED; + ip::address ipAddr, broadcastAddr; + uint8_t prefixLength = 0; + + switch (ifa->ifa_addr->sa_family) { + case AF_INET: { + addrFamily = AddressFamily::V4; + + const sockaddr_in* sin = reinterpret_cast(ifa->ifa_addr); + ip::address_v4::bytes_type bytes; + std::copy_n(reinterpret_cast(&sin->sin_addr), bytes.size(), bytes.begin()); + ipAddr = ip::address_v4(bytes); + + const sockaddr_in* sinMask = reinterpret_cast(ifa->ifa_netmask); + std::copy_n(reinterpret_cast(&sinMask->sin_addr), bytes.size(), bytes.begin()); + prefixLength = computePrefixLength(bytes); + break; + } + + case AF_INET6: { + addrFamily = AddressFamily::V6; + + const sockaddr_in6* sin6 = reinterpret_cast(ifa->ifa_addr); + ip::address_v6::bytes_type bytes; + std::copy_n(reinterpret_cast(&sin6->sin6_addr), bytes.size(), bytes.begin()); + ip::address_v6 v6Addr(bytes); + if (v6Addr.is_link_local()) + v6Addr.scope_id(if_nametoindex(netif.getName().data())); + ipAddr = v6Addr; + + const sockaddr_in6* sinMask = reinterpret_cast(ifa->ifa_netmask); + std::copy_n(reinterpret_cast(&sinMask->sin6_addr), bytes.size(), bytes.begin()); + prefixLength = computePrefixLength(bytes); + break; + } + + case AF_LINK: { + const sockaddr_dl* sdl = reinterpret_cast(ifa->ifa_addr); + netif.setIndex(sdl->sdl_index); + + if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == ethernet::ADDR_LEN) { + netif.setType(InterfaceType::ETHERNET); + netif.setEthernetAddress(ethernet::Address(reinterpret_cast(LLADDR(sdl)))); + NDN_LOG_TRACE(netif.getName() << " has Ethernet address " << netif.getEthernetAddress()); + } + else if (sdl->sdl_type == IFT_LOOP) { + netif.setType(InterfaceType::LOOPBACK); + } + else { + netif.setType(InterfaceType::UNKNOWN); + } + break; + } + } + + if (netif.canBroadcast()) { + netif.setEthernetBroadcastAddress(ethernet::getBroadcastAddress()); + + if (addrFamily == AddressFamily::V4 && ifa->ifa_broadaddr != nullptr) { + const sockaddr_in* sin = reinterpret_cast(ifa->ifa_broadaddr); + ip::address_v4::bytes_type bytes; + std::copy_n(reinterpret_cast(&sin->sin_addr), bytes.size(), bytes.begin()); + broadcastAddr = ip::address_v4(bytes); + } + } + + if (addrFamily == AddressFamily::UNSPECIFIED) + continue; + + AddressScope scope = AddressScope::GLOBAL; + if (ipAddr.is_loopback()) { + scope = AddressScope::HOST; + } + else if ((ipAddr.is_v4() && (ipAddr.to_v4().to_ulong() & 0xFFFF0000) == 0xA9FE0000) || + (ipAddr.is_v6() && ipAddr.to_v6().is_link_local())) { + scope = AddressScope::LINK; + } + + netif.addNetworkAddress(NetworkAddress(addrFamily, ipAddr, broadcastAddr, prefixLength, scope, 0)); + } +} + +void +NetworkMonitorImplOsx::onConfigChanged(SCDynamicStoreRef m_scStore, CFArrayRef changedKeys, void* context) +{ + static_cast(context)->onConfigChanged(changedKeys); +} + +void +NetworkMonitorImplOsx::onConfigChanged(CFArrayRef changedKeys) +{ + IfAddrs ifaList; + + size_t count = CFArrayGetCount(changedKeys); + for (size_t i = 0; i != count; ++i) { + Name key(detail::cfstring::toStdString((CFStringRef)CFArrayGetValueAtIndex(changedKeys, i))); + std::string ifName = key.at(-2).toUri(); + + auto ifIt = m_interfaces.find(ifName); + if (ifIt == m_interfaces.end()) { + addNewInterface(ifName, ifaList); + return; + } + + auto removeInterface = [&] { + NDN_LOG_DEBUG("removing interface " << ifName); + shared_ptr removedNetif = ifIt->second; + m_interfaces.erase(ifIt); + this->emitSignal(onInterfaceRemoved, removedNetif); + }; + + NetworkInterface& netif = *ifIt->second; + std::string changedItem = key.at(-1).toUri(); + if (changedItem == "Link") { + auto newState = getInterfaceState(netif); + if (newState == InterfaceState::UNKNOWN) { + // check if it is really unknown or interface removed + if (getInterfaceNames().count(ifName) == 0) { + removeInterface(); + return; + } + } + NDN_LOG_TRACE(ifName << " status changed from " << netif.getState() << " to " << newState); + netif.setState(newState); + } + else if (changedItem == "IPv4" || changedItem == "IPv6") { + auto updatedNetif = makeNetworkInterface(); + updatedNetif->setName(ifName); + updateInterfaceInfo(*updatedNetif, ifaList); + if (updatedNetif->getType() == InterfaceType::UNKNOWN) { + NDN_LOG_DEBUG(ifName << " type changed to unknown"); + removeInterface(); + return; + } + + const auto& newAddrs = updatedNetif->getNetworkAddresses(); + const auto& oldAddrs = netif.getNetworkAddresses(); + std::set added; + std::set removed; + std::set_difference(newAddrs.begin(), newAddrs.end(), + oldAddrs.begin(), oldAddrs.end(), std::inserter(added, added.end())); + std::set_difference(oldAddrs.begin(), oldAddrs.end(), + newAddrs.begin(), newAddrs.end(), std::inserter(removed, removed.end())); + + for (const auto& addr : removed) { + netif.removeNetworkAddress(addr); + } + for (const auto& addr : added) { + netif.addNetworkAddress(addr); + } + } + } +} + +} // namespace net +} // namespace ndn diff --git a/ndn-cxx/net/impl/network-monitor-impl-osx.hpp b/ndn-cxx/net/impl/network-monitor-impl-osx.hpp new file mode 100644 index 000000000..f3a4cdcc8 --- /dev/null +++ b/ndn-cxx/net/impl/network-monitor-impl-osx.hpp @@ -0,0 +1,117 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_NET_NETWORK_MONITOR_IMPL_OSX_HPP +#define NDN_NET_NETWORK_MONITOR_IMPL_OSX_HPP + +#include "ndn-cxx/detail/config.hpp" +#include "ndn-cxx/net/network-monitor.hpp" + +#ifndef NDN_CXX_HAVE_OSX_FRAMEWORKS +#error "This file should not be included ..." +#endif + +#include "ndn-cxx/detail/cf-releaser-osx.hpp" +#include "ndn-cxx/util/scheduler.hpp" + +#include +#include + +#include +#include + +namespace ndn { +namespace net { + +class IfAddrs; + +class NetworkMonitorImplOsx : public NetworkMonitorImpl +{ +public: + NetworkMonitorImplOsx(boost::asio::io_service& io); + + ~NetworkMonitorImplOsx(); + + uint32_t + getCapabilities() const final + { + return NetworkMonitor::CAP_ENUM | + NetworkMonitor::CAP_IF_ADD_REMOVE | + NetworkMonitor::CAP_STATE_CHANGE | + NetworkMonitor::CAP_ADDR_ADD_REMOVE; + } + + shared_ptr + getNetworkInterface(const std::string& ifname) const final; + + std::vector> + listNetworkInterfaces() const final; + +private: + static void + afterNotificationCenterEvent(CFNotificationCenterRef center, void* observer, + CFStringRef name, const void* object, + CFDictionaryRef userInfo); + + void + scheduleCfLoop(); + + void + enumerateInterfaces(); + + std::set + getInterfaceNames() const; + + void + addNewInterface(const std::string& ifName, const IfAddrs& ifaList); + + InterfaceState + getInterfaceState(const NetworkInterface& netif) const; + + size_t + getInterfaceMtu(const NetworkInterface& netif); + + void + updateInterfaceInfo(NetworkInterface& netif, const IfAddrs& ifaList); + + static void + onConfigChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void* context); + + void + onConfigChanged(CFArrayRef changedKeys); + +private: + std::map> m_interfaces; ///< ifname => interface + + Scheduler m_scheduler; + scheduler::ScopedEventId m_cfLoopEvent; + + SCDynamicStoreContext m_context; + detail::CFReleaser m_scStore; + detail::CFReleaser m_loopSource; + + boost::asio::ip::udp::socket m_ioctlSocket; +}; + +} // namespace net +} // namespace ndn + +#endif // NDN_NET_NETWORK_MONITOR_IMPL_OSX_HPP diff --git a/ndn-cxx/net/network-address.cpp b/ndn-cxx/net/network-address.cpp new file mode 100644 index 000000000..6f9d743ad --- /dev/null +++ b/ndn-cxx/net/network-address.cpp @@ -0,0 +1,67 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Davide Pesavento + */ + +#include "ndn-cxx/net/network-address.hpp" + +namespace ndn { +namespace net { + +std::ostream& +operator<<(std::ostream& os, AddressScope scope) +{ + switch (scope) { + case AddressScope::NOWHERE: + return os << "nowhere"; + case AddressScope::HOST: + return os << "host"; + case AddressScope::LINK: + return os << "link"; + case AddressScope::GLOBAL: + return os << "global"; + } + return os; +} + +NetworkAddress::NetworkAddress(AddressFamily family, + boost::asio::ip::address ip, + boost::asio::ip::address broadcast, + uint8_t prefixLength, + AddressScope scope, + uint32_t flags) + : m_family(family) + , m_ip(ip) + , m_broadcast(broadcast) + , m_prefixLength(prefixLength) + , m_scope(scope) + , m_flags(flags) +{ +} + +std::ostream& +operator<<(std::ostream& os, const NetworkAddress& addr) +{ + return os << addr.getIp() << '/' << static_cast(addr.getPrefixLength()); +} + +} // namespace net +} // namespace ndn diff --git a/ndn-cxx/net/network-address.hpp b/ndn-cxx/net/network-address.hpp new file mode 100644 index 000000000..30fc148cc --- /dev/null +++ b/ndn-cxx/net/network-address.hpp @@ -0,0 +1,132 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Davide Pesavento + */ + +#ifndef NDN_NET_NETWORK_ADDRESS_HPP +#define NDN_NET_NETWORK_ADDRESS_HPP + +#include "ndn-cxx/detail/common.hpp" + +#include + +namespace ndn { +namespace net { + +enum class AddressFamily { + UNSPECIFIED, + V4, + V6, +}; + +enum class AddressScope { + NOWHERE, + HOST, + LINK, + GLOBAL, +}; + +std::ostream& +operator<<(std::ostream& os, AddressScope scope); + +/** + * @brief Stores one IP address supported by a network interface. + */ +class NetworkAddress +{ +public: + NetworkAddress(AddressFamily family, + boost::asio::ip::address ip, + boost::asio::ip::address broadcast, + uint8_t prefixLength, + AddressScope scope, + uint32_t flags); + + /** @brief Returns the address family + */ + AddressFamily + getFamily() const + { + return m_family; + } + + /** @brief Returns the IP address (v4 or v6) + */ + boost::asio::ip::address + getIp() const + { + return m_ip; + } + + /** @brief Returns the IP broadcast address + */ + boost::asio::ip::address + getBroadcast() const + { + return m_broadcast; + } + + /** @brief Returns the prefix length + */ + uint8_t + getPrefixLength() const + { + return m_prefixLength; + } + + /** @brief Returns the address scope + */ + AddressScope + getScope() const + { + return m_scope; + } + + /** @brief Returns a bitset of platform-specific flags enabled on the address + */ + uint32_t + getFlags() const + { + return m_flags; + } + + friend bool + operator<(const NetworkAddress& a, const NetworkAddress& b) + { + return a.m_ip < b.m_ip; + } + +private: + AddressFamily m_family; + boost::asio::ip::address m_ip; + boost::asio::ip::address m_broadcast; + uint8_t m_prefixLength; + AddressScope m_scope; + uint32_t m_flags; // IFA_F_* in if_addr.h +}; + +std::ostream& +operator<<(std::ostream& os, const NetworkAddress& address); + +} // namespace net +} // namespace ndn + +#endif // NDN_NET_NETWORK_ADDRESS_HPP diff --git a/ndn-cxx/net/network-interface.cpp b/ndn-cxx/net/network-interface.cpp new file mode 100644 index 000000000..d7a5e7f79 --- /dev/null +++ b/ndn-cxx/net/network-interface.cpp @@ -0,0 +1,240 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Davide Pesavento + */ + +#include "ndn-cxx/net/network-interface.hpp" +#include "ndn-cxx/net/impl/linux-if-constants.hpp" +#include "ndn-cxx/util/logger.hpp" +#include "ndn-cxx/util/string-helper.hpp" + +#include + +NDN_LOG_INIT(ndn.NetworkMonitor); + +namespace ndn { +namespace net { + +NetworkInterface::NetworkInterface() + : m_index(0) + , m_type(InterfaceType::UNKNOWN) + , m_flags(0) + , m_state(InterfaceState::UNKNOWN) + , m_mtu(0) +{ +} + +bool +NetworkInterface::addNetworkAddress(const NetworkAddress& address) +{ + if (!address.getIp().is_unspecified()) { + // need to erase the existing address before inserting + // because the address flags may have changed + bool isNew = m_netAddresses.erase(address) == 0; + m_netAddresses.insert(address); + if (isNew) { + NDN_LOG_DEBUG("added address " << address << " to " << m_name); + onAddressAdded(address); + return true; + } + } + return false; +} + +bool +NetworkInterface::removeNetworkAddress(const NetworkAddress& address) +{ + if (m_netAddresses.erase(address) > 0) { + NDN_LOG_DEBUG("removed address " << address << " from " << m_name); + onAddressRemoved(address); + return true; + } + return false; +} + +void +NetworkInterface::setIndex(int index) +{ + m_index = index; +} + +void +NetworkInterface::setName(const std::string& name) +{ + BOOST_ASSERT(!name.empty()); + m_name = name; +} + +void +NetworkInterface::setType(InterfaceType type) +{ + m_type = type; +} + +void +NetworkInterface::setFlags(uint32_t flags) +{ + m_flags = flags; +} + +void +NetworkInterface::setState(InterfaceState state) +{ + if (m_state != state) { + std::swap(m_state, state); + onStateChanged(state, m_state); + } +} + +void +NetworkInterface::setMtu(uint32_t mtu) +{ + if (m_mtu != mtu) { + std::swap(m_mtu, mtu); + onMtuChanged(mtu, m_mtu); + } +} + +void +NetworkInterface::setEthernetAddress(const ethernet::Address& address) +{ + m_etherAddress = address; +} + +void +NetworkInterface::setEthernetBroadcastAddress(const ethernet::Address& address) +{ + m_etherBrdAddress = address; +} + +std::ostream& +operator<<(std::ostream& os, InterfaceType type) +{ + switch (type) { + case InterfaceType::UNKNOWN: + return os << "unknown"; + case InterfaceType::LOOPBACK: + return os << "loopback"; + case InterfaceType::ETHERNET: + return os << "ether"; + } + return os; +} + +std::ostream& +operator<<(std::ostream& os, InterfaceState state) +{ + switch (state) { + case InterfaceState::UNKNOWN: + return os << "unknown"; + case InterfaceState::DOWN: + return os << "down"; + case InterfaceState::NO_CARRIER: + return os << "no-carrier"; + case InterfaceState::DORMANT: + return os << "dormant"; + case InterfaceState::RUNNING: + return os << "running"; + } + return os; +} + +static void +printFlag(std::ostream& os, uint32_t& flags, uint32_t flagVal, const char* flagStr) +{ + if (flags & flagVal) { + flags &= ~flagVal; + os << flagStr << (flags ? "," : ""); + } +} + +std::ostream& +operator<<(std::ostream& os, const NetworkInterface& netif) +{ + os << netif.getIndex() << ": " << netif.getName() << ": "; + + auto flags = netif.getFlags(); + os << "<"; +#define PRINT_IFF(flag) printFlag(os, flags, IFF_##flag, #flag) + PRINT_IFF(UP); + PRINT_IFF(BROADCAST); + PRINT_IFF(DEBUG); + PRINT_IFF(LOOPBACK); + PRINT_IFF(POINTOPOINT); +#if defined(IFF_NOTRAILERS) + PRINT_IFF(NOTRAILERS); +#endif + PRINT_IFF(RUNNING); + PRINT_IFF(NOARP); + PRINT_IFF(PROMISC); + PRINT_IFF(ALLMULTI); + PRINT_IFF(MULTICAST); +#if defined(__linux__) + PRINT_IFF(MASTER); + PRINT_IFF(SLAVE); + PRINT_IFF(PORTSEL); + PRINT_IFF(AUTOMEDIA); + PRINT_IFF(DYNAMIC); +#elif defined(__APPLE__) || defined(__FreeBSD__) + PRINT_IFF(OACTIVE); + PRINT_IFF(SIMPLEX); + PRINT_IFF(LINK0); + PRINT_IFF(LINK1); + PRINT_IFF(LINK2); +#endif +#if defined(__FreeBSD__) + PRINT_IFF(CANTCONFIG); + PRINT_IFF(PPROMISC); + PRINT_IFF(MONITOR); + PRINT_IFF(STATICARP); + PRINT_IFF(DYING); + PRINT_IFF(RENAMING); +#endif +#undef PRINT_IFF +#if defined(__linux__) +#define PRINT_IF_FLAG(flag) printFlag(os, flags, linux_if::FLAG_##flag, #flag) + PRINT_IF_FLAG(LOWER_UP); + PRINT_IF_FLAG(DORMANT); + PRINT_IF_FLAG(ECHO); +#undef PRINT_IF_FLAG +#endif + if (flags) { + // print unknown flags in hex + os << AsHex{flags}; + } + os << ">"; + + os << " state " << netif.getState() << " mtu " << netif.getMtu() << "\n" + << " link/" << netif.getType() << " " << netif.getEthernetAddress() + << " brd " << netif.getEthernetBroadcastAddress() << "\n"; + + for (const auto& addr : netif.getNetworkAddresses()) { + os << " " << (addr.getFamily() == AddressFamily::V4 ? "inet " : "inet6 ") << addr; + if (netif.canBroadcast() && !addr.getBroadcast().is_unspecified()) + os << " brd " << addr.getBroadcast(); + os << " scope " << addr.getScope() << "\n"; + } + + return os; +} + +} // namespace net +} // namespace ndn diff --git a/ndn-cxx/net/network-interface.hpp b/ndn-cxx/net/network-interface.hpp new file mode 100644 index 000000000..5044938e8 --- /dev/null +++ b/ndn-cxx/net/network-interface.hpp @@ -0,0 +1,255 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Davide Pesavento + */ + +#ifndef NDN_NET_NETWORK_INTERFACE_HPP +#define NDN_NET_NETWORK_INTERFACE_HPP + +#include "ndn-cxx/net/ethernet.hpp" +#include "ndn-cxx/net/network-address.hpp" +#include "ndn-cxx/util/signal.hpp" + +#include + +namespace ndn { +namespace net { + +/** @brief Indicates the hardware type of a network interface + */ +enum class InterfaceType { + UNKNOWN, + LOOPBACK, + ETHERNET, + // we do not support anything else for now +}; + +std::ostream& +operator<<(std::ostream& os, InterfaceType type); + +/** @brief Indicates the state of a network interface + */ +enum class InterfaceState { + UNKNOWN, ///< interface is in an unknown state + DOWN, ///< interface is administratively down + NO_CARRIER, ///< interface is administratively up but has no carrier + DORMANT, ///< interface has a carrier but it cannot send or receive normal user traffic yet + RUNNING, ///< interface can be used to send and receive packets +}; + +std::ostream& +operator<<(std::ostream& os, InterfaceState state); + +/** + * @brief Represents one network interface attached to the host. + * + * Each network interface has a unique index, a name, and a set of flags indicating its + * capabilities and current state. It may contain one hardware (Ethernet) address, and + * zero or more network-layer (IP) addresses. Specific signals are emitted when the + * interface data change. + */ +class NetworkInterface +{ +public: // signals, marked 'mutable' so they can be connected on 'const NetworkInterface' + /** @brief Fires when interface state changes + */ + mutable util::Signal onStateChanged; + + /** @brief Fires when interface mtu changes + */ + mutable util::Signal onMtuChanged; + + /** @brief Fires when a network-layer address is added to the interface + */ + mutable util::Signal onAddressAdded; + + /** @brief Fires when a network-layer address is removed from the interface + */ + mutable util::Signal onAddressRemoved; + +public: // getters + /** @brief Returns an opaque ID that uniquely identifies the interface on the system + */ + int + getIndex() const + { + return m_index; + } + + /** @brief Returns the name of the interface, unique on the system + */ + std::string + getName() const + { + return m_name; + } + + /** @brief Returns the hardware type of the interface + */ + InterfaceType + getType() const + { + return m_type; + } + + /** @brief Returns a bitset of platform-specific flags enabled on the interface + */ + uint32_t + getFlags() const + { + return m_flags; + } + + /** @brief Returns the current state of the interface + */ + InterfaceState + getState() const + { + return m_state; + } + + /** @brief Returns the MTU (maximum transmission unit) of the interface + */ + uint32_t + getMtu() const + { + return m_mtu; + } + + /** @brief Returns the link-layer (Ethernet) address of the interface + */ + ethernet::Address + getEthernetAddress() const + { + return m_etherAddress; + } + + /** @brief Returns the link-layer (Ethernet) broadcast address of the interface + */ + ethernet::Address + getEthernetBroadcastAddress() const + { + return m_etherBrdAddress; + } + + /** @brief Returns a list of all network-layer addresses present on the interface + */ + const std::set& + getNetworkAddresses() const + { + return m_netAddresses; + } + + /** @brief Returns true if the interface is a loopback interface + */ + bool + isLoopback() const + { + return (m_flags & IFF_LOOPBACK) != 0; + } + + /** @brief Returns true if the interface is a point-to-point interface + */ + bool + isPointToPoint() const + { + return (m_flags & IFF_POINTOPOINT) != 0; + } + + /** @brief Returns true if the interface supports broadcast communication + */ + bool + canBroadcast() const + { + return (m_flags & IFF_BROADCAST) != 0; + } + + /** @brief Returns true if the interface supports multicast communication + */ + bool + canMulticast() const + { + return (m_flags & IFF_MULTICAST) != 0; + } + + /** @brief Returns true if the interface is administratively up + */ + bool + isUp() const + { + return (m_flags & IFF_UP) != 0; + } + +public: // modifiers: they update information on this instance, but do not change netif in the OS + bool + addNetworkAddress(const NetworkAddress& address); + + bool + removeNetworkAddress(const NetworkAddress& address); + + void + setIndex(int index); + + void + setName(const std::string& name); + + void + setType(InterfaceType type); + + void + setFlags(uint32_t flags); + + void + setState(InterfaceState state); + + void + setMtu(uint32_t mtu); + + void + setEthernetAddress(const ethernet::Address& address); + + void + setEthernetBroadcastAddress(const ethernet::Address& address); + +private: // constructor + NetworkInterface(); // accessible through NetworkMonitorImpl::makeNetworkInterface + +private: + int m_index; + std::string m_name; + InterfaceType m_type; + uint32_t m_flags; // IFF_* in + InterfaceState m_state; + uint32_t m_mtu; + ethernet::Address m_etherAddress; + ethernet::Address m_etherBrdAddress; + std::set m_netAddresses; + + friend class NetworkMonitorImpl; +}; + +std::ostream& +operator<<(std::ostream& os, const NetworkInterface& interface); + +} // namespace net +} // namespace ndn + +#endif // NDN_NET_NETWORK_INTERFACE_HPP diff --git a/ndn-cxx/net/network-monitor-stub.cpp b/ndn-cxx/net/network-monitor-stub.cpp new file mode 100644 index 000000000..5dcc18537 --- /dev/null +++ b/ndn-cxx/net/network-monitor-stub.cpp @@ -0,0 +1,138 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Alexander Afanasyev + * @author Davide Pesavento + */ + +#include "ndn-cxx/net/network-monitor-stub.hpp" + +#include + +#include +#include + +namespace ndn { +namespace net { + +class NetworkMonitorImplStub : public NetworkMonitorImpl +{ +public: + explicit + NetworkMonitorImplStub(uint32_t capabilities) + : m_capabilities(capabilities) + { + } + + uint32_t + getCapabilities() const final + { + return m_capabilities; + } + + shared_ptr + getNetworkInterface(const std::string& ifname) const final + { + auto i = m_interfaces.find(ifname); + return i == m_interfaces.end() ? nullptr : i->second; + } + + std::vector> + listNetworkInterfaces() const final + { + std::vector> v; + boost::copy(m_interfaces | boost::adaptors::map_values, std::back_inserter(v)); + return v; + } + +public: // internal + using NetworkMonitorImpl::makeNetworkInterface; + + void + addInterface(shared_ptr netif) + { + BOOST_ASSERT(netif != nullptr); + bool isNew = m_interfaces.emplace(netif->getName(), netif).second; + if (!isNew) { + NDN_THROW(std::invalid_argument("duplicate ifname")); + } + this->emitSignal(onInterfaceAdded, netif); + } + + void + removeInterface(const std::string& ifname) + { + auto i = m_interfaces.find(ifname); + if (i == m_interfaces.end()) { + return; + } + shared_ptr netif = i->second; + m_interfaces.erase(i); + this->emitSignal(onInterfaceRemoved, netif); + } + + void + emitEnumerationCompleted() + { + this->emitSignal(onEnumerationCompleted); + } + +private: + uint32_t m_capabilities; + std::unordered_map> m_interfaces; +}; + +NetworkMonitorStub::NetworkMonitorStub(uint32_t capabilities) + : NetworkMonitor(make_unique(capabilities)) +{ +} + +NetworkMonitorImplStub& +NetworkMonitorStub::getImpl() +{ + return static_cast(this->NetworkMonitor::getImpl()); +} + +shared_ptr +NetworkMonitorStub::makeNetworkInterface() +{ + return NetworkMonitorImplStub::makeNetworkInterface(); +} + +void +NetworkMonitorStub::addInterface(shared_ptr netif) +{ + this->getImpl().addInterface(std::move(netif)); +} + +void +NetworkMonitorStub::removeInterface(const std::string& ifname) +{ + this->getImpl().removeInterface(ifname); +} + +void +NetworkMonitorStub::emitEnumerationCompleted() +{ + this->getImpl().emitEnumerationCompleted(); +} + +} // namespace net +} // namespace ndn diff --git a/ndn-cxx/net/network-monitor-stub.hpp b/ndn-cxx/net/network-monitor-stub.hpp new file mode 100644 index 000000000..4bd6c4739 --- /dev/null +++ b/ndn-cxx/net/network-monitor-stub.hpp @@ -0,0 +1,88 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_NET_NETWORK_MONITOR_STUB_HPP +#define NDN_NET_NETWORK_MONITOR_STUB_HPP + +#include "ndn-cxx/net/network-monitor.hpp" + +namespace ndn { +namespace net { + +class NetworkMonitorImplStub; + +/** \brief a stub NetworkMonitor for unit testing + */ +class NetworkMonitorStub : public NetworkMonitor +{ +public: + /** \brief constructor + * \param capabilities capabilities reported by \p getCapabilities + */ + explicit + NetworkMonitorStub(uint32_t capabilities); + + /** \brief create a NetworkInterface instance + */ + static shared_ptr + makeNetworkInterface(); + + /** \brief emit the \p onInterfaceAdded signal and add \p netif internally + * \param netif new network interface + * \post getNetworkInterface(netif->getName()) == netif + * \post listNetworkInterface() contains netif + * \throw std::invalid_argument a network interface with same name already exists + */ + void + addInterface(shared_ptr netif); + + /** \brief emit the \p onInterfaceRemoved signal and remove \p netif internally + * \param ifname network interface name + * \post getNetworkInterface(ifname) == nullptr + * \post listNetworkInterface() does not contains an interface with specified name + * \note If specified interface name does not exist, this operation has no effect. + */ + void + removeInterface(const std::string& ifname); + + /** \brief emit the \p onEnumerationCompleted signal + * + * A real NetworkMonitor starts with an "enumerating" state, during which the initial + * information about network interfaces is collected from the OS. Upon discovering a network + * interface, it emits the \p onInterfaceAdded signal. When the initial enumerating completes, + * it emits the onEnumerationCompleted signal. + * + * To simulate this procedure on a newly constructed MockNetworkMonitor, the caller should + * invoke \p addInterface once for each network interface that already exists, and then invoke + * \p signalEnumerationCompleted . + */ + void + emitEnumerationCompleted(); + +private: + NetworkMonitorImplStub& + getImpl(); +}; + +} // namespace net +} // namespace ndn + +#endif // NDN_NET_NETWORK_MONITOR_STUB_HPP diff --git a/ndn-cxx/net/network-monitor.cpp b/ndn-cxx/net/network-monitor.cpp new file mode 100644 index 000000000..511d750e9 --- /dev/null +++ b/ndn-cxx/net/network-monitor.cpp @@ -0,0 +1,98 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Alexander Afanasyev + * @author Davide Pesavento + */ + +#include "ndn-cxx/net/network-monitor.hpp" +#include "ndn-cxx/util/logger.hpp" + +#include "ndn-cxx/detail/config.hpp" +#include "ndn-cxx/net/impl/network-monitor-impl-noop.hpp" +#if defined(NDN_CXX_HAVE_OSX_FRAMEWORKS) +#include "ndn-cxx/net/impl/network-monitor-impl-osx.hpp" +#define NETWORK_MONITOR_IMPL_TYPE NetworkMonitorImplOsx +#elif defined(NDN_CXX_HAVE_NETLINK) +#include "ndn-cxx/net/impl/network-monitor-impl-netlink.hpp" +#define NETWORK_MONITOR_IMPL_TYPE NetworkMonitorImplNetlink +#else +#define NETWORK_MONITOR_IMPL_TYPE NetworkMonitorImplNoop +#endif + +NDN_LOG_INIT(ndn.NetworkMonitor); + +namespace ndn { +namespace net { + +static unique_ptr +makeNetworkMonitorImpl(boost::asio::io_service& io) +{ + try { + return make_unique(io); + } + catch (const std::runtime_error& e) { + NDN_LOG_WARN("failed to initialize " BOOST_STRINGIZE(NETWORK_MONITOR_IMPL_TYPE) ": " << e.what()); + // fallback to dummy implementation + return make_unique(io); + } +} + +NetworkMonitor::NetworkMonitor(boost::asio::io_service& io) + : NetworkMonitor(makeNetworkMonitorImpl(io)) +{ +} + +NetworkMonitor::NetworkMonitor(unique_ptr impl) + : m_impl(std::move(impl)) + , onEnumerationCompleted(m_impl->onEnumerationCompleted) + , onInterfaceAdded(m_impl->onInterfaceAdded) + , onInterfaceRemoved(m_impl->onInterfaceRemoved) + , onNetworkStateChanged(m_impl->onNetworkStateChanged) +{ +} + +uint32_t +NetworkMonitor::getCapabilities() const +{ + return m_impl->getCapabilities(); +} + +shared_ptr +NetworkMonitor::getNetworkInterface(const std::string& ifname) const +{ + return m_impl->getNetworkInterface(ifname); +} + +std::vector> +NetworkMonitor::listNetworkInterfaces() const +{ + return m_impl->listNetworkInterfaces(); +} + +shared_ptr +NetworkMonitorImpl::makeNetworkInterface() +{ + // cannot use make_shared because NetworkInterface constructor is private + return shared_ptr(new NetworkInterface); +} + +} // namespace net +} // namespace ndn diff --git a/ndn-cxx/net/network-monitor.hpp b/ndn-cxx/net/network-monitor.hpp new file mode 100644 index 000000000..84ef90c8d --- /dev/null +++ b/ndn-cxx/net/network-monitor.hpp @@ -0,0 +1,168 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Alexander Afanasyev + * @author Davide Pesavento + */ + +#ifndef NDN_NET_NETWORK_MONITOR_HPP +#define NDN_NET_NETWORK_MONITOR_HPP + +#include "ndn-cxx/detail/asio-fwd.hpp" +#include "ndn-cxx/net/network-interface.hpp" + +#include + +namespace ndn { +namespace net { + +class NetworkMonitorImpl; + +/** + * @brief Network interface monitor. + * + * Maintains an up-to-date view of every system network interface and notifies when an interface + * is added or removed. + * + * @note The implementation of this class is highly platform dependent, and not all platform + * backends provide all the features. On macOS, @e SystemConfiguration and + * @e CFNotificationCenterAddObserver are used (notification of MTU change is not supported). + * On Linux, @e netlink notifications from the kernel are used. See getCapabilities() for + * the detailed set of capabilities supported by the platform backend currently in use. + */ +class NetworkMonitor : noncopyable +{ +public: + class Error : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + }; + + /** + * @brief Construct instance, request enumeration of all network interfaces, and start + * monitoring for network state changes. + * @param io io_service instance that will dispatch events + */ + explicit + NetworkMonitor(boost::asio::io_service& io); + + enum Capability : uint32_t { + /// NetworkMonitor is not supported and is a no-op + CAP_NONE = 0, + /// listNetworkInterfaces() and getNetworkInterface() are supported + CAP_ENUM = 1 << 0, + /// NetworkMonitor onInterfaceAdded and onInterfaceRemoved signals are supported + CAP_IF_ADD_REMOVE = 1 << 1, + /// NetworkInterface onStateChanged signal is supported + CAP_STATE_CHANGE = 1 << 2, + /// NetworkInterface onMtuChanged signal is supported + CAP_MTU_CHANGE = 1 << 3, + /// NetworkInterface onAddressAdded and onAddressRemoved signals are supported + CAP_ADDR_ADD_REMOVE = 1 << 4 + }; + + /// Returns a bitwise OR'ed set of #Capability flags supported on the current platform. + uint32_t + getCapabilities() const; + + /// Returns the NetworkInterface with the given name, or @c nullptr if it does not exist. + shared_ptr + getNetworkInterface(const std::string& ifname) const; + + /** + * @brief Lists all network interfaces currently available on the system. + * @warning May return incomplete results if called before the + * #onEnumerationCompleted signal has been emitted. + */ + NDN_CXX_NODISCARD std::vector> + listNetworkInterfaces() const; + +protected: + explicit + NetworkMonitor(unique_ptr impl); + + NetworkMonitorImpl& + getImpl() + { + return *m_impl; + } + +private: + const unique_ptr m_impl; + // Intentional violation of code-style rule 1.4: m_impl must be assigned before its signals can + // be assigned to references below. + +public: // signals + /// Fires when the enumeration of all network interfaces on the system is complete. + util::Signal& onEnumerationCompleted; + + /// Fires whenever a new interface is detected on the system. + util::Signal>& onInterfaceAdded; + + /** + * @brief Fires whenever an interface disappears from the system. + * @note The NetworkInterface object has already been removed from the list + * returned by listNetworkInterfaces() when this signal is emitted. + */ + util::Signal>& onInterfaceRemoved; + + /// @deprecated Only for backward compatibility + util::Signal& onNetworkStateChanged; +}; + +class NetworkMonitorImpl : noncopyable +{ +public: + using Error = NetworkMonitor::Error; + + virtual + ~NetworkMonitorImpl() = default; + + virtual uint32_t + getCapabilities() const = 0; + + virtual shared_ptr + getNetworkInterface(const std::string&) const = 0; + + virtual std::vector> + listNetworkInterfaces() const = 0; + +protected: + static shared_ptr + makeNetworkInterface(); + +public: + util::Signal onEnumerationCompleted; + util::Signal> onInterfaceAdded; + util::Signal> onInterfaceRemoved; + util::Signal onNetworkStateChanged; + +protected: + DECLARE_SIGNAL_EMIT(onEnumerationCompleted) + DECLARE_SIGNAL_EMIT(onInterfaceAdded) + DECLARE_SIGNAL_EMIT(onInterfaceRemoved) + DECLARE_SIGNAL_EMIT(onNetworkStateChanged) +}; + +} // namespace net +} // namespace ndn + +#endif // NDN_NET_NETWORK_MONITOR_HPP diff --git a/ndn-cxx/prefix-announcement.cpp b/ndn-cxx/prefix-announcement.cpp new file mode 100644 index 000000000..da65e9304 --- /dev/null +++ b/ndn-cxx/prefix-announcement.cpp @@ -0,0 +1,135 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/prefix-announcement.hpp" +#include "ndn-cxx/encoding/tlv-nfd.hpp" + +namespace ndn { + +static const name::Component KEYWORD_PA_COMP = "20025041"_block; + +PrefixAnnouncement::PrefixAnnouncement() = default; + +PrefixAnnouncement::PrefixAnnouncement(Data data) + : m_data(std::move(data)) +{ + if (m_data->getContentType() != tlv::ContentType_PrefixAnn) { + NDN_THROW(Error("Data is not a prefix announcement: ContentType is " + + to_string(m_data->getContentType()))); + } + + const Name& dataName = m_data->getName(); + if (dataName.size() < 3 || dataName[-3] != KEYWORD_PA_COMP || + !dataName[-2].isVersion() || !dataName[-1].isSegment()) { + NDN_THROW(Error("Data is not a prefix announcement: wrong name structure")); + } + m_announcedName = dataName.getPrefix(-3); + + const Block& payload = m_data->getContent(); + payload.parse(); + + m_expiration = time::milliseconds(readNonNegativeInteger(payload.get(tlv::nfd::ExpirationPeriod))); + + auto validityElement = payload.find(tlv::ValidityPeriod); + if (validityElement != payload.elements_end()) { + m_validity.emplace(*validityElement); + } + + for (const Block& element : payload.elements()) { + if (element.type() != tlv::nfd::ExpirationPeriod && element.type() != tlv::ValidityPeriod && + tlv::isCriticalType(element.type())) { + NDN_THROW(Error("unrecognized element of critical type " + to_string(element.type()))); + } + } +} + +const Data& +PrefixAnnouncement::toData(KeyChain& keyChain, const ndn::security::SigningInfo& si, + optional version) const +{ + if (!m_data) { + Name dataName = m_announcedName; + dataName.append(KEYWORD_PA_COMP); + dataName.appendVersion(version.value_or(time::toUnixTimestamp(time::system_clock::now()).count())); + dataName.appendSegment(0); + m_data.emplace(dataName); + m_data->setContentType(tlv::ContentType_PrefixAnn); + + Block content(tlv::Content); + content.push_back(makeNonNegativeIntegerBlock(tlv::nfd::ExpirationPeriod, + m_expiration.count())); + if (m_validity) { + content.push_back(m_validity->wireEncode()); + } + content.encode(); + m_data->setContent(content); + + keyChain.sign(*m_data, si); + } + return *m_data; +} + +PrefixAnnouncement& +PrefixAnnouncement::setAnnouncedName(Name name) +{ + m_data.reset(); + m_announcedName = std::move(name); + return *this; +} + +PrefixAnnouncement& +PrefixAnnouncement::setExpiration(time::milliseconds expiration) +{ + if (expiration < 0_ms) { + NDN_THROW(std::invalid_argument("expiration period is negative")); + } + m_data.reset(); + m_expiration = expiration; + return *this; +} + +PrefixAnnouncement& +PrefixAnnouncement::setValidityPeriod(optional validity) +{ + m_data.reset(); + m_validity = std::move(validity); + return *this; +} + +bool +operator==(const PrefixAnnouncement& lhs, const PrefixAnnouncement& rhs) +{ + return lhs.getAnnouncedName() == rhs.getAnnouncedName() && + lhs.getExpiration() == rhs.getExpiration() && + lhs.getValidityPeriod() == rhs.getValidityPeriod(); +} + +std::ostream& +operator<<(std::ostream& os, const PrefixAnnouncement& pa) +{ + os << pa.getAnnouncedName() << " expires=" << pa.getExpiration(); + if (pa.getValidityPeriod()) { + os << " validity=" << *pa.getValidityPeriod(); + } + return os; +} + +} // namespace ndn diff --git a/ndn-cxx/prefix-announcement.hpp b/ndn-cxx/prefix-announcement.hpp new file mode 100644 index 000000000..7f6168f51 --- /dev/null +++ b/ndn-cxx/prefix-announcement.hpp @@ -0,0 +1,147 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_PREFIX_ANNOUNCEMENT_HPP +#define NDN_CXX_PREFIX_ANNOUNCEMENT_HPP + +#include "ndn-cxx/security/v2/key-chain.hpp" + +namespace ndn { + +/** \brief A prefix announcement object that represents an application's intent of registering a + * prefix toward itself. + * \sa https://redmine.named-data.net/projects/nfd/wiki/PrefixAnnouncement + */ +class PrefixAnnouncement +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + /** \brief Construct an empty prefix announcement. + * \post getData() == nullopt + * \post getAnnouncedName() == "/" + * \post getExpiration() == 0_ms + */ + PrefixAnnouncement(); + + /** \brief Decode a prefix announcement from Data. + * \throw tlv::Error the Data is not a prefix announcement. + * \post getData() == data + */ + explicit + PrefixAnnouncement(Data data); + + /** \brief Get the Data representing the prefix announcement, if available. + */ + const optional& + getData() const + { + return m_data; + } + + /** \brief Create a Data packet representing the prefix announcement, if it does not exist. + * \param keyChain KeyChain to sign the Data. + * \param si signing parameters. + * \param version version number in Data name; if nullopt, use current Unix timestamp (in + * milliseconds) as the version number. + * \post getData() == the returned Data + */ + const Data& + toData(KeyChain& keyChain, + const ndn::security::SigningInfo& si = KeyChain::getDefaultSigningInfo(), + optional version = nullopt) const; + + /** \brief Return announced name. + */ + const Name& + getAnnouncedName() const + { + return m_announcedName; + } + + /** \brief Set announced name. + * \post getData() == nullopt + */ + PrefixAnnouncement& + setAnnouncedName(Name name); + + /** \brief Return relative expiration period. + */ + time::milliseconds + getExpiration() const + { + return m_expiration; + } + + /** \brief Set relative expiration period. + * \throw std::invalid_argument expiration period is negative. + * \post getData() == nullopt + */ + PrefixAnnouncement& + setExpiration(time::milliseconds expiration); + + /** \brief Return absolute validity period. + */ + optional + getValidityPeriod() const + { + return m_validity; + } + + /** \brief Set absolute validity period. + * \post getData() == nullopt + */ + PrefixAnnouncement& + setValidityPeriod(optional validity); + +private: + mutable optional m_data; + Name m_announcedName; + time::milliseconds m_expiration = 0_ms; + optional m_validity; +}; + +/** \brief Test whether two prefix announcements has the same name, expiration period, + * and validity period. + */ +bool +operator==(const PrefixAnnouncement& lhs, const PrefixAnnouncement& rhs); + +inline bool +operator!=(const PrefixAnnouncement& lhs, const PrefixAnnouncement& rhs) +{ + return !(lhs == rhs); +} + +/** \brief Print prefix announcement to a stream. + * + * This string is for debugging purpose. Its syntax is not public API. + */ +std::ostream& +operator<<(std::ostream& os, const PrefixAnnouncement& pa); + +} // namespace ndn + +#endif // NDN_CXX_PREFIX_ANNOUNCEMENT_HPP diff --git a/ndn-cxx/security/command-interest-signer.cpp b/ndn-cxx/security/command-interest-signer.cpp new file mode 100644 index 000000000..63d37c98a --- /dev/null +++ b/ndn-cxx/security/command-interest-signer.cpp @@ -0,0 +1,65 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/command-interest-signer.hpp" +#include "ndn-cxx/util/random.hpp" + +namespace ndn { +namespace security { + +CommandInterestPreparer::CommandInterestPreparer() + : m_lastUsedTimestamp(0) +{ +} + +Name +CommandInterestPreparer::prepareCommandInterestName(Name name) +{ + time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now()); + if (timestamp <= m_lastUsedTimestamp) { + timestamp = m_lastUsedTimestamp + 1_ms; + } + m_lastUsedTimestamp = timestamp; + + name + .append(name::Component::fromNumber(timestamp.count())) + .append(name::Component::fromNumber(random::generateWord64())) // nonce + ; + + return name; +} + +CommandInterestSigner::CommandInterestSigner(KeyChain& keyChain) + : m_keyChain(keyChain) +{ +} + +Interest +CommandInterestSigner::makeCommandInterest(const Name& name, const SigningInfo& params) +{ + Interest commandInterest(prepareCommandInterestName(name)); + commandInterest.setCanBePrefix(false); + m_keyChain.sign(commandInterest, params); + return commandInterest; +} + +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/command-interest-signer.hpp b/ndn-cxx/security/command-interest-signer.hpp new file mode 100644 index 000000000..ab719ec9a --- /dev/null +++ b/ndn-cxx/security/command-interest-signer.hpp @@ -0,0 +1,95 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_COMMAND_INTEREST_SIGNER_HPP +#define NDN_SECURITY_COMMAND_INTEREST_SIGNER_HPP + +#include "ndn-cxx/security/v2/key-chain.hpp" + +namespace ndn { +namespace security { + +/** + * @brief Helper class to prepare command interest name + * + * The preparer adds timestamp and nonce name components to the supplied name. + * + * This class is primarily designed to be used as part of CommandInterestSigner, but can also + * be using in an application that defines custom signing methods not support by the KeyChain + * (such as HMAC-SHA1). + * + * @sa https://redmine.named-data.net/projects/ndn-cxx/wiki/CommandInterest + */ +class CommandInterestPreparer : noncopyable +{ +public: + CommandInterestPreparer(); + + /** + * @brief Prepare name of the CommandInterest + * + * This method appends the timestamp and nonce name components to the supplied name. + */ + Name + prepareCommandInterestName(Name name); + +private: + time::milliseconds m_lastUsedTimestamp; +}; + +/** + * @brief Helper class to create command interests + * + * The signer adds timestamp and nonce name components to the supplied name, creates an + * Interest, and signs it with the KeyChain. + * + * @sa https://redmine.named-data.net/projects/ndn-cxx/wiki/CommandInterest + */ +class CommandInterestSigner : private CommandInterestPreparer +{ +public: + explicit + CommandInterestSigner(KeyChain& keyChain); + + /** + * @brief Create CommandInterest + * + * This method appends the timestamp and nonce name components to the supplied name, create + * an Interest object and signs it with the keychain. + * + * Note that signature of the command interest covers only Name of the interest. Therefore, + * other fields in the returned interest can be changed without breaking validity of the + * signature, because s + * + * @sa https://redmine.named-data.net/projects/ndn-cxx/wiki/CommandInterest + */ + Interest + makeCommandInterest(const Name& name, const SigningInfo& params = KeyChain::getDefaultSigningInfo()); + +private: + KeyChain& m_keyChain; +}; + +} // namespace security +} // namespace ndn + + +#endif // NDN_SECURITY_COMMAND_INTEREST_SIGNER_HPP diff --git a/src/security/digest-sha256.cpp b/ndn-cxx/security/digest-sha256.cpp similarity index 85% rename from src/security/digest-sha256.cpp rename to ndn-cxx/security/digest-sha256.cpp index bbe2e10a9..6332d1be1 100644 --- a/src/security/digest-sha256.cpp +++ b/ndn-cxx/security/digest-sha256.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,7 +19,7 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "digest-sha256.hpp" +#include "ndn-cxx/security/digest-sha256.hpp" namespace ndn { @@ -32,7 +32,7 @@ DigestSha256::DigestSha256(const Signature& signature) : Signature(signature) { if (getType() != tlv::DigestSha256) - BOOST_THROW_EXCEPTION(Error("Incorrect signature type")); + NDN_THROW(Error("Cannot construct DigestSha256 from SignatureType " + to_string(getType()))); } } // namespace ndn diff --git a/ndn-cxx/security/digest-sha256.hpp b/ndn-cxx/security/digest-sha256.hpp new file mode 100644 index 000000000..5ed480c7d --- /dev/null +++ b/ndn-cxx/security/digest-sha256.hpp @@ -0,0 +1,50 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_DIGEST_SHA256_HPP +#define NDN_SECURITY_DIGEST_SHA256_HPP + +#include "ndn-cxx/signature.hpp" + +namespace ndn { + +/** @brief Represents a signature of DigestSha256 type + * + * This signature type provides integrity protection using SHA-256 digest, but no provenance of a + * Data packet or any kind of guarantee that packet is from the original source. + */ +class DigestSha256 : public Signature +{ +public: + /** @brief Create empty DigestSha256 signature + */ + DigestSha256(); + + /** @brief Convert base Signature to DigestSha256 signature + * @throw Signature::Error SignatureType is not DigestSha256 + */ + explicit + DigestSha256(const Signature& signature); +}; + +} // namespace ndn + +#endif // NDN_SECURITY_DIGEST_SHA256_HPP diff --git a/ndn-cxx/security/impl/openssl-helper.cpp b/ndn-cxx/security/impl/openssl-helper.cpp new file mode 100644 index 000000000..104723cfe --- /dev/null +++ b/ndn-cxx/security/impl/openssl-helper.cpp @@ -0,0 +1,141 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/impl/openssl-helper.hpp" + +namespace ndn { +namespace security { +namespace detail { + +const EVP_MD* +digestAlgorithmToEvpMd(DigestAlgorithm algo) +{ + switch (algo) { + case DigestAlgorithm::SHA224: + return EVP_sha224(); + case DigestAlgorithm::SHA256: + return EVP_sha256(); + case DigestAlgorithm::SHA384: + return EVP_sha384(); + case DigestAlgorithm::SHA512: + return EVP_sha512(); +#if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_BLAKE2) + case DigestAlgorithm::BLAKE2B_512: + return EVP_blake2b512(); + case DigestAlgorithm::BLAKE2S_256: + return EVP_blake2s256(); +#endif +#if OPENSSL_VERSION_NUMBER >= 0x10101001L + case DigestAlgorithm::SHA3_224: + return EVP_sha3_224(); + case DigestAlgorithm::SHA3_256: + return EVP_sha3_256(); + case DigestAlgorithm::SHA3_384: + return EVP_sha3_384(); + case DigestAlgorithm::SHA3_512: + return EVP_sha3_512(); +#endif + default: + return nullptr; + } +} + +int +getEvpPkeyType(EVP_PKEY* key) +{ + return +#if OPENSSL_VERSION_NUMBER < 0x1010000fL + EVP_PKEY_type(key->type); +#else + EVP_PKEY_base_id(key); +#endif +} + +EvpMdCtx::EvpMdCtx() +#if OPENSSL_VERSION_NUMBER < 0x1010000fL + : m_ctx(EVP_MD_CTX_create()) +#else + : m_ctx(EVP_MD_CTX_new()) +#endif +{ + if (m_ctx == nullptr) + NDN_THROW(std::runtime_error("EVP_MD_CTX creation failed")); +} + +EvpMdCtx::~EvpMdCtx() +{ +#if OPENSSL_VERSION_NUMBER < 0x1010000fL + EVP_MD_CTX_destroy(m_ctx); +#else + EVP_MD_CTX_free(m_ctx); +#endif +} + +EvpPkeyCtx::EvpPkeyCtx(EVP_PKEY* key) + : m_ctx(EVP_PKEY_CTX_new(key, nullptr)) +{ + if (m_ctx == nullptr) + NDN_THROW(std::runtime_error("EVP_PKEY_CTX creation failed")); +} + +EvpPkeyCtx::EvpPkeyCtx(int id) + : m_ctx(EVP_PKEY_CTX_new_id(id, nullptr)) +{ + if (m_ctx == nullptr) + NDN_THROW(std::runtime_error("EVP_PKEY_CTX creation failed")); +} + +EvpPkeyCtx::~EvpPkeyCtx() +{ + EVP_PKEY_CTX_free(m_ctx); +} + +Bio::Bio(Bio::MethodPtr method) + : m_bio(BIO_new(method)) +{ + if (m_bio == nullptr) + NDN_THROW(std::runtime_error("BIO creation failed")); +} + +Bio::~Bio() +{ + BIO_free_all(m_bio); +} + +bool +Bio::read(uint8_t* buf, size_t buflen) const noexcept +{ + BOOST_ASSERT(buflen <= std::numeric_limits::max()); + int n = BIO_read(m_bio, buf, static_cast(buflen)); + return n >= 0 && static_cast(n) == buflen; +} + +bool +Bio::write(const uint8_t* buf, size_t buflen) noexcept +{ + BOOST_ASSERT(buflen <= std::numeric_limits::max()); + int n = BIO_write(m_bio, buf, static_cast(buflen)); + return n >= 0 && static_cast(n) == buflen; +} + +} // namespace detail +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/impl/openssl-helper.hpp b/ndn-cxx/security/impl/openssl-helper.hpp new file mode 100644 index 000000000..679a69458 --- /dev/null +++ b/ndn-cxx/security/impl/openssl-helper.hpp @@ -0,0 +1,107 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_SECURITY_IMPL_OPENSSL_HELPER_HPP +#define NDN_CXX_SECURITY_IMPL_OPENSSL_HELPER_HPP + +#include "ndn-cxx/security/impl/openssl.hpp" +#include "ndn-cxx/security/security-common.hpp" + +namespace ndn { +namespace security { +namespace detail { + +NDN_CXX_NODISCARD const EVP_MD* +digestAlgorithmToEvpMd(DigestAlgorithm algo); + +NDN_CXX_NODISCARD int +getEvpPkeyType(EVP_PKEY* key); + +class EvpMdCtx : noncopyable +{ +public: + EvpMdCtx(); + + ~EvpMdCtx(); + + operator EVP_MD_CTX*() const + { + return m_ctx; + } + +private: + EVP_MD_CTX* m_ctx; +}; + +class EvpPkeyCtx : noncopyable +{ +public: + explicit + EvpPkeyCtx(EVP_PKEY* key); + + explicit + EvpPkeyCtx(int id); + + ~EvpPkeyCtx(); + + operator EVP_PKEY_CTX*() const + { + return m_ctx; + } + +private: + EVP_PKEY_CTX* m_ctx; +}; + +class Bio : noncopyable +{ +public: +#if OPENSSL_VERSION_NUMBER < 0x1010000fL + using MethodPtr = BIO_METHOD*; +#else + using MethodPtr = const BIO_METHOD*; +#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL + + explicit + Bio(MethodPtr method); + + ~Bio(); + + operator BIO*() const + { + return m_bio; + } + + NDN_CXX_NODISCARD bool + read(uint8_t* buf, size_t buflen) const noexcept; + + NDN_CXX_NODISCARD bool + write(const uint8_t* buf, size_t buflen) noexcept; + +private: + BIO* m_bio; +}; + +} // namespace detail +} // namespace security +} // namespace ndn + +#endif // NDN_CXX_SECURITY_IMPL_OPENSSL_HELPER_HPP diff --git a/ndn-cxx/security/impl/openssl.hpp b/ndn-cxx/security/impl/openssl.hpp new file mode 100644 index 000000000..58dd1dfec --- /dev/null +++ b/ndn-cxx/security/impl/openssl.hpp @@ -0,0 +1,45 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_IMPL_OPENSSL_HPP +#define NDN_SECURITY_IMPL_OPENSSL_HPP + +// suppress deprecation warnings on macOS >= 10.7 +#if defined(__APPLE__) && defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__APPLE__) && defined(__clang__) +#pragma clang diagnostic pop +#endif + +#endif // NDN_SECURITY_IMPL_OPENSSL_HPP diff --git a/ndn-cxx/security/key-chain.hpp b/ndn-cxx/security/key-chain.hpp new file mode 100644 index 000000000..d82cc3bad --- /dev/null +++ b/ndn-cxx/security/key-chain.hpp @@ -0,0 +1,28 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_SECURITY_KEY_CHAIN_HPP +#define NDN_CXX_SECURITY_KEY_CHAIN_HPP + +#include "ndn-cxx/security/security-common.hpp" +#include "ndn-cxx/security/v2/key-chain.hpp" + +#endif // NDN_CXX_SECURITY_KEY_CHAIN_HPP diff --git a/ndn-cxx/security/key-params.cpp b/ndn-cxx/security/key-params.cpp new file mode 100644 index 000000000..2b505193a --- /dev/null +++ b/ndn-cxx/security/key-params.cpp @@ -0,0 +1,114 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/key-params.hpp" + +namespace ndn { + +KeyParams::KeyParams(KeyType keyType, KeyIdType keyIdType) + : m_keyType(keyType) + , m_keyIdType(keyIdType) +{ + BOOST_ASSERT(keyIdType != KeyIdType::USER_SPECIFIED); +} + +KeyParams::KeyParams(KeyType keyType, const name::Component& keyId) + : m_keyType(keyType) + , m_keyIdType(KeyIdType::USER_SPECIFIED) + , m_keyId(keyId) +{ + BOOST_ASSERT(!keyId.empty()); +} + +KeyParams::~KeyParams() = default; + +namespace detail { + +const uint32_t MIN_RSA_KEY_SIZE = 2048; +const uint32_t DEFAULT_RSA_KEY_SIZE = 2048; +const uint32_t EC_KEY_SIZES[] = {224, 256, 384, 521}; +const uint32_t DEFAULT_EC_KEY_SIZE = 256; +const uint32_t AES_KEY_SIZES[] = {128, 192, 256}; +const uint32_t DEFAULT_AES_KEY_SIZE = 128; +const uint32_t DEFAULT_HMAC_KEY_SIZE = 256; + +uint32_t +RsaKeyParamsInfo::checkKeySize(uint32_t size) +{ + if (size < MIN_RSA_KEY_SIZE) + NDN_THROW(KeyParams::Error("Unsupported RSA key size " + to_string(size))); + return size; +} + +uint32_t +RsaKeyParamsInfo::getDefaultSize() +{ + return DEFAULT_RSA_KEY_SIZE; +} + +uint32_t +EcKeyParamsInfo::checkKeySize(uint32_t size) +{ + for (size_t i = 0; i < (sizeof(EC_KEY_SIZES) / sizeof(EC_KEY_SIZES[0])); i++) { + if (EC_KEY_SIZES[i] == size) + return size; + } + NDN_THROW(KeyParams::Error("Unsupported EC key size " + to_string(size))); +} + +uint32_t +EcKeyParamsInfo::getDefaultSize() +{ + return DEFAULT_EC_KEY_SIZE; +} + +uint32_t +AesKeyParamsInfo::checkKeySize(uint32_t size) +{ + for (size_t i = 0; i < (sizeof(AES_KEY_SIZES) / sizeof(AES_KEY_SIZES[0])); i++) { + if (AES_KEY_SIZES[i] == size) + return size; + } + NDN_THROW(KeyParams::Error("Unsupported AES key size " + to_string(size))); +} + +uint32_t +AesKeyParamsInfo::getDefaultSize() +{ + return DEFAULT_AES_KEY_SIZE; +} + +uint32_t +HmacKeyParamsInfo::checkKeySize(uint32_t size) +{ + if (size == 0 || size % 8 != 0) + NDN_THROW(KeyParams::Error("Unsupported HMAC key size " + to_string(size))); + return size; +} + +uint32_t +HmacKeyParamsInfo::getDefaultSize() +{ + return DEFAULT_HMAC_KEY_SIZE; +} + +} // namespace detail +} // namespace ndn diff --git a/ndn-cxx/security/key-params.hpp b/ndn-cxx/security/key-params.hpp new file mode 100644 index 000000000..4d424c427 --- /dev/null +++ b/ndn-cxx/security/key-params.hpp @@ -0,0 +1,313 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_KEY_PARAMS_HPP +#define NDN_SECURITY_KEY_PARAMS_HPP + +#include "ndn-cxx/security/security-common.hpp" +#include "ndn-cxx/name-component.hpp" + +namespace ndn { + +/** + * @brief Base class for key parameters. + * + * Its subclasses are used to store parameters for key generation. + */ +class KeyParams +{ +public: + class Error : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + }; + + virtual + ~KeyParams(); + + KeyType + getKeyType() const + { + return m_keyType; + } + + KeyIdType + getKeyIdType() const + { + return m_keyIdType; + } + + const name::Component& + getKeyId() const + { + return m_keyId; + } + + void + setKeyId(const name::Component& keyId) + { + m_keyId = keyId; + } + +protected: + /** + * @brief Constructor + * + * @param keyType Type of the created key + * @param keyIdType The method how the key id should be generated; must not be + * KeyIdType::USER_SPECIFIED + */ + KeyParams(KeyType keyType, KeyIdType keyIdType); + + /** + * @brief Constructor + * + * @param keyType Type of the created key + * @param keyId The user-specified key id. The keyIdType will be set to KeyIdType::USER_SPECIFIED. + * keyId MUST NOT be the empty component. + * @post getKeyIdType() == KeyIdType::USER_SPECIFIED + */ + KeyParams(KeyType keyType, const name::Component& keyId); + +private: + KeyType m_keyType; + KeyIdType m_keyIdType; + name::Component m_keyId; +}; + + +namespace detail { + +/// @brief RsaKeyParamInfo is used to instantiate SimplePublicKeyParams for RSA keys. +class RsaKeyParamsInfo +{ +public: + static constexpr KeyType + getType() + { + return KeyType::RSA; + } + + /** + * @brief check if @p size is valid and supported for this key type. + * + * @throw KeyParams::Error if the key size is not supported. + */ + static uint32_t + checkKeySize(uint32_t size); + + static uint32_t + getDefaultSize(); +}; + +/// @brief EcKeyParamInfo is used to instantiate SimplePublicKeyParams for elliptic curve keys. +class EcKeyParamsInfo +{ +public: + static constexpr KeyType + getType() + { + return KeyType::EC; + } + + /** + * @brief check if @p size is valid and supported for this key type. + * + * @throw KeyParams::Error if the key size is not supported. + */ + static uint32_t + checkKeySize(uint32_t size); + + static uint32_t + getDefaultSize(); +}; + +} // namespace detail + + +/// @brief SimplePublicKeyParams is a template for public keys with only one parameter: size. +template +class SimplePublicKeyParams : public KeyParams +{ +public: + /// @brief Create key parameters with user-specified key id. + explicit + SimplePublicKeyParams(const name::Component& keyId, + uint32_t size = KeyParamsInfo::getDefaultSize()) + : KeyParams(KeyParamsInfo::getType(), keyId) + { + setKeySize(size); + } + + /** + * @brief Create key parameters with auto-generated key id. + * + * This method is used only if user does not want to maintain the uniqueness of key name. + * By default, an 8-byte random number will be used as key id. + */ + explicit + SimplePublicKeyParams(uint32_t size = KeyParamsInfo::getDefaultSize(), + KeyIdType keyIdType = KeyIdType::RANDOM) + : KeyParams(KeyParamsInfo::getType(), keyIdType) + { + setKeySize(size); + } + + uint32_t + getKeySize() const + { + return m_size; + } + +private: + void + setKeySize(uint32_t size) + { + m_size = KeyParamsInfo::checkKeySize(size); + } + + uint32_t + getDefaultKeySize() const + { + return KeyParamsInfo::getDefaultSize(); + } + +private: + uint32_t m_size; +}; + +/// @brief RsaKeyParams carries parameters for RSA key. +typedef SimplePublicKeyParams RsaKeyParams; + +/// @brief EcKeyParams carries parameters for EC key. +typedef SimplePublicKeyParams EcKeyParams; + + +namespace detail { + +/// @brief AesKeyParamsInfo is used to instantiate SimpleSymmetricKeyParams for AES keys. +class AesKeyParamsInfo +{ +public: + static constexpr KeyType + getType() + { + return KeyType::AES; + } + + /** + * @brief check if @p size is valid and supported for this key type. + * + * @throw KeyParams::Error if the key size is not supported. + */ + static uint32_t + checkKeySize(uint32_t size); + + static uint32_t + getDefaultSize(); +}; + +/// @brief HmacKeyParamsInfo is used to instantiate SimpleSymmetricKeyParams for HMAC keys. +class HmacKeyParamsInfo +{ +public: + static constexpr KeyType + getType() + { + return KeyType::HMAC; + } + + /** + * @brief check if @p size is valid and supported for this key type. + * + * @throw KeyParams::Error if the key size is not supported. + */ + static uint32_t + checkKeySize(uint32_t size); + + static uint32_t + getDefaultSize(); +}; + +} // namespace detail + + +/// @brief SimpleSymmetricKeyParams is a template for symmetric keys with only one parameter: size. +template +class SimpleSymmetricKeyParams : public KeyParams +{ +public: + /// @brief Create key parameters with user-specified key id. + explicit + SimpleSymmetricKeyParams(const name::Component& keyId, + uint32_t size = KeyParamsInfo::getDefaultSize()) + : KeyParams(KeyParamsInfo::getType(), keyId) + { + setKeySize(size); + } + + /** + * @brief Create key parameters with auto-generated key id. + * + * This method is used only if user does not want to maintain the uniqueness of key name. + * By default, an 8-byte random number will be used as key id. + */ + explicit + SimpleSymmetricKeyParams(uint32_t size = KeyParamsInfo::getDefaultSize(), + KeyIdType keyIdType = KeyIdType::RANDOM) + : KeyParams(KeyParamsInfo::getType(), keyIdType) + { + setKeySize(size); + } + + uint32_t + getKeySize() const + { + return m_size; + } + +private: + void + setKeySize(uint32_t size) + { + m_size = KeyParamsInfo::checkKeySize(size); + } + + uint32_t + getDefaultKeySize() const + { + return KeyParamsInfo::getDefaultSize(); + } + +private: + uint32_t m_size; +}; + +/// @brief AesKeyParams carries parameters for AES key. +typedef SimpleSymmetricKeyParams AesKeyParams; + +/// @brief HmacKeyParams carries parameters for HMAC key. +typedef SimpleSymmetricKeyParams HmacKeyParams; + +} // namespace ndn + +#endif // NDN_SECURITY_KEY_PARAMS_HPP diff --git a/ndn-cxx/security/pib/certificate-container.cpp b/ndn-cxx/security/pib/certificate-container.cpp new file mode 100644 index 000000000..a2a676252 --- /dev/null +++ b/ndn-cxx/security/pib/certificate-container.cpp @@ -0,0 +1,168 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/certificate-container.hpp" +#include "ndn-cxx/security/pib/pib-impl.hpp" +#include "ndn-cxx/util/concepts.hpp" + +namespace ndn { +namespace security { +namespace pib { + +NDN_CXX_ASSERT_FORWARD_ITERATOR(CertificateContainer::const_iterator); + +CertificateContainer::const_iterator::const_iterator() + : m_container(nullptr) +{ +} + +CertificateContainer::const_iterator::const_iterator(std::set::const_iterator it, + const CertificateContainer& container) + : m_it(it) + , m_container(&container) +{ +} + +v2::Certificate +CertificateContainer::const_iterator::operator*() +{ + BOOST_ASSERT(m_container != nullptr); + return m_container->get(*m_it); +} + +CertificateContainer::const_iterator& +CertificateContainer::const_iterator::operator++() +{ + ++m_it; + return *this; +} + +CertificateContainer::const_iterator +CertificateContainer::const_iterator::operator++(int) +{ + BOOST_ASSERT(m_container != nullptr); + const_iterator it(m_it, *m_container); + ++m_it; + return it; +} + +bool +CertificateContainer::const_iterator::operator==(const const_iterator& other) const +{ + bool isThisEnd = m_container == nullptr || m_it == m_container->m_certNames.end(); + bool isOtherEnd = other.m_container == nullptr || other.m_it == other.m_container->m_certNames.end(); + return ((isThisEnd || isOtherEnd) ? + (isThisEnd == isOtherEnd) : + m_container->m_pib == other.m_container->m_pib && m_it == other.m_it); +} + +bool +CertificateContainer::const_iterator::operator!=(const const_iterator& other) const +{ + return !(*this == other); +} + +CertificateContainer::CertificateContainer(const Name& keyName, shared_ptr pibImpl) + : m_keyName(keyName) + , m_pib(std::move(pibImpl)) +{ + BOOST_ASSERT(m_pib != nullptr); + m_certNames = m_pib->getCertificatesOfKey(keyName); +} + +CertificateContainer::const_iterator +CertificateContainer::begin() const +{ + return const_iterator(m_certNames.begin(), *this); +} + +CertificateContainer::const_iterator +CertificateContainer::end() const +{ + return const_iterator(); +} + +CertificateContainer::const_iterator +CertificateContainer::find(const Name& certName) const +{ + return const_iterator(m_certNames.find(certName), *this); +} + +size_t +CertificateContainer::size() const +{ + return m_certNames.size(); +} + +void +CertificateContainer::add(const v2::Certificate& certificate) +{ + if (m_keyName != certificate.getKeyName()) + NDN_THROW(std::invalid_argument("Certificate name `" + certificate.getKeyName().toUri() + "` " + "does not match key name")); + + const Name& certName = certificate.getName(); + m_certNames.insert(certName); + m_certs[certName] = certificate; + m_pib->addCertificate(certificate); +} + +void +CertificateContainer::remove(const Name& certName) +{ + if (!v2::Certificate::isValidName(certName) || + v2::extractKeyNameFromCertName(certName) != m_keyName) { + NDN_THROW(std::invalid_argument("Certificate name `" + certName.toUri() + "` " + "is invalid or does not match key name")); + } + + m_certNames.erase(certName); + m_certs.erase(certName); + m_pib->removeCertificate(certName); +} + +v2::Certificate +CertificateContainer::get(const Name& certName) const +{ + auto it = m_certs.find(certName); + + if (it != m_certs.end()) + return it->second; + + if (!v2::Certificate::isValidName(certName) || + v2::extractKeyNameFromCertName(certName) != m_keyName) { + NDN_THROW(std::invalid_argument("Certificate name `" + certName.toUri() + "` " + "is invalid or does not match key name")); + } + + m_certs[certName] = m_pib->getCertificate(certName); + return m_certs[certName]; +} + +bool +CertificateContainer::isConsistent() const +{ + return m_certNames == m_pib->getCertificatesOfKey(m_keyName); +} + +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/pib/certificate-container.hpp b/ndn-cxx/security/pib/certificate-container.hpp new file mode 100644 index 000000000..2ab729287 --- /dev/null +++ b/ndn-cxx/security/pib/certificate-container.hpp @@ -0,0 +1,167 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_PIB_CERTIFICATE_CONTAINER_HPP +#define NDN_SECURITY_PIB_CERTIFICATE_CONTAINER_HPP + +#include "ndn-cxx/security/v2/certificate.hpp" + +#include +#include +#include + +namespace ndn { +namespace security { +namespace pib { + +class PibImpl; + +namespace detail { +class KeyImpl; +} // namespace detail + +/** + * @brief Container of certificates of a key + * + * The container is used to search/enumerate certificates of a key. + * The container can be created only by detail::KeyImpl. + */ +class CertificateContainer : noncopyable +{ +public: + class const_iterator + { + public: + using iterator_category = std::forward_iterator_tag; + using value_type = const v2::Certificate; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + + const_iterator(); + + v2::Certificate + operator*(); + + const_iterator& + operator++(); + + const_iterator + operator++(int); + + bool + operator==(const const_iterator& other) const; + + bool + operator!=(const const_iterator& other) const; + + private: + const_iterator(std::set::const_iterator it, const CertificateContainer& container); + + private: + std::set::const_iterator m_it; + const CertificateContainer* m_container; + + friend class CertificateContainer; + }; + + typedef const_iterator iterator; + +public: + const_iterator + begin() const; + + const_iterator + end() const; + + const_iterator + find(const Name& certName) const; + + size_t + size() const; + + /** + * @brief Add @p certificate into the container + * @throw std::invalid_argument the name of @p certificate does not match the key name + */ + void + add(const v2::Certificate& certificate); + + /** + * @brief Remove a certificate with @p certName from the container + * @throw std::invalid_argument @p certName does not match the key name + */ + void + remove(const Name& certName); + + /** + * @brief Get a certificate with @p certName from the container + * @throw std::invalid_argument @p certName does not match the key name + * @throw Pib::Error the certificate does not exist + */ + v2::Certificate + get(const Name& certName) const; + + /** + * @brief Check if the container is consistent with the backend storage + * @note this method is heavyweight and should be used in debugging mode only. + */ + bool + isConsistent() const; + +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: + /** + * @brief Create certificate container for a key with @p keyName + * @param pibImpl The PIB backend implementation. + */ + CertificateContainer(const Name& keyName, shared_ptr pibImpl); + + const std::set& + getCertNames() const + { + return m_certNames; + } + + const std::unordered_map& + getCache() const + { + return m_certs; + } + +private: + Name m_keyName; + std::set m_certNames; + /// @brief Cache of loaded certificates + mutable std::unordered_map m_certs; + + shared_ptr m_pib; + + friend class detail::KeyImpl; +}; + +} // namespace pib + +using pib::CertificateContainer; + +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_PIB_CERTIFICATE_CONTAINER_HPP diff --git a/ndn-cxx/security/pib/identity-container.cpp b/ndn-cxx/security/pib/identity-container.cpp new file mode 100644 index 000000000..3353ab928 --- /dev/null +++ b/ndn-cxx/security/pib/identity-container.cpp @@ -0,0 +1,163 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/identity-container.hpp" +#include "ndn-cxx/security/pib/pib-impl.hpp" +#include "ndn-cxx/security/pib/impl/identity-impl.hpp" +#include "ndn-cxx/util/concepts.hpp" + +namespace ndn { +namespace security { +namespace pib { + +NDN_CXX_ASSERT_FORWARD_ITERATOR(IdentityContainer::const_iterator); + +IdentityContainer::const_iterator::const_iterator() + : m_container(nullptr) +{ +} + +IdentityContainer::const_iterator::const_iterator(std::set::const_iterator it, + const IdentityContainer& container) + : m_it(it) + , m_container(&container) +{ +} + +Identity +IdentityContainer::const_iterator::operator*() +{ + BOOST_ASSERT(m_container != nullptr); + return m_container->get(*m_it); +} + +IdentityContainer::const_iterator& +IdentityContainer::const_iterator::operator++() +{ + ++m_it; + return *this; +} + +IdentityContainer::const_iterator +IdentityContainer::const_iterator::operator++(int) +{ + const_iterator it(*this); + ++m_it; + return it; +} + +bool +IdentityContainer::const_iterator::operator==(const const_iterator& other) +{ + bool isThisEnd = m_container == nullptr || m_it == m_container->m_identityNames.end(); + bool isOtherEnd = other.m_container == nullptr || other.m_it == other.m_container->m_identityNames.end(); + return ((isThisEnd || isOtherEnd) ? + (isThisEnd == isOtherEnd) : + m_container->m_pibImpl == other.m_container->m_pibImpl && m_it == other.m_it); +} + +bool +IdentityContainer::const_iterator::operator!=(const const_iterator& other) +{ + return !(*this == other); +} + +IdentityContainer::IdentityContainer(shared_ptr pibImpl) + : m_pibImpl(std::move(pibImpl)) +{ + BOOST_ASSERT(m_pibImpl != nullptr); + m_identityNames = m_pibImpl->getIdentities(); +} + +IdentityContainer::const_iterator +IdentityContainer::begin() const +{ + return const_iterator(m_identityNames.begin(), *this); +} + +IdentityContainer::const_iterator +IdentityContainer::end() const +{ + return const_iterator(); +} + +IdentityContainer::const_iterator +IdentityContainer::find(const Name& identity) const +{ + return const_iterator(m_identityNames.find(identity), *this); +} + +size_t +IdentityContainer::size() const +{ + return m_identityNames.size(); +} + +Identity +IdentityContainer::add(const Name& identityName) +{ + if (m_identityNames.count(identityName) == 0) { + m_identityNames.insert(identityName); + m_identities[identityName] = make_shared(identityName, m_pibImpl, true); + } + return get(identityName); +} + +void +IdentityContainer::remove(const Name& identityName) +{ + m_identityNames.erase(identityName); + m_identities.erase(identityName); + m_pibImpl->removeIdentity(identityName); +} + +Identity +IdentityContainer::get(const Name& identityName) const +{ + shared_ptr id; + auto it = m_identities.find(identityName); + + if (it != m_identities.end()) { + id = it->second; + } + else { + id = make_shared(identityName, m_pibImpl, false); + m_identities[identityName] = id; + } + return Identity(id); +} + +void +IdentityContainer::reset() +{ + m_identities.clear(); + m_identityNames = m_pibImpl->getIdentities(); +} + +bool +IdentityContainer::isConsistent() const +{ + return m_identityNames == m_pibImpl->getIdentities(); +} + +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/pib/identity-container.hpp b/ndn-cxx/security/pib/identity-container.hpp new file mode 100644 index 000000000..b31dc2c21 --- /dev/null +++ b/ndn-cxx/security/pib/identity-container.hpp @@ -0,0 +1,174 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_PIB_IDENTITY_CONTAINER_HPP +#define NDN_SECURITY_PIB_IDENTITY_CONTAINER_HPP + +#include "ndn-cxx/security/pib/identity.hpp" + +#include +#include +#include + +namespace ndn { +namespace security { +namespace pib { + +class PibImpl; + +namespace detail { +class IdentityImpl; +} // namespace detail + +/** + * @brief Container of identities of a Pib + * + * The container is used to search/enumerate identities of a Pib. + * The container can be created only by Pib. + */ +class IdentityContainer : noncopyable +{ +public: + class const_iterator + { + public: + using iterator_category = std::forward_iterator_tag; + using value_type = const Identity; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + + const_iterator(); + + Identity + operator*(); + + const_iterator& + operator++(); + + const_iterator + operator++(int); + + bool + operator==(const const_iterator& other); + + bool + operator!=(const const_iterator& other); + + private: + const_iterator(std::set::const_iterator it, const IdentityContainer& container); + + private: + std::set::const_iterator m_it; + const IdentityContainer* m_container; + + friend class IdentityContainer; + }; + + typedef const_iterator iterator; + +public: + const_iterator + begin() const; + + const_iterator + end() const; + + const_iterator + find(const Name& keyId) const; + + size_t + size() const; + + /** + * @brief Add @p identity into the container + */ + Identity + add(const Name& identityName); + + /** + * @brief Remove @p identity from the container + */ + void + remove(const Name& identity); + + /** + * @brief Get @p identity from the container + * @throw Pib::Error @p identity does not exist + */ + Identity + get(const Name& identity) const; + + /** + * @brief Reset state of the container + * + * This method removes all loaded identities and retrieves identity names from the PIB + * implementation. + */ + void + reset(); + + /** + * @brief Check if the container is consistent with the backend storage + * + * @note this method is heavyweight and should be used in debugging mode only. + */ + bool + isConsistent() const; + +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: + /** + * @brief Create identity container + * @param impl The PIB backend implementation. + */ + explicit + IdentityContainer(shared_ptr pibImpl); + + const std::set& + getIdentityNames() const + { + return m_identityNames; + } + + const std::unordered_map>& + getLoadedIdentities() const + { + return m_identities; + } + +private: + std::set m_identityNames; + /// @brief Cache of loaded detail::IdentityImpl. + mutable std::unordered_map> m_identities; + + shared_ptr m_pibImpl; + + friend class Pib; +}; + +} // namespace pib + +using pib::IdentityContainer; + +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_PIB_IDENTITY_CONTAINER_HPP diff --git a/ndn-cxx/security/pib/identity.cpp b/ndn-cxx/security/pib/identity.cpp new file mode 100644 index 000000000..c9bd82b1d --- /dev/null +++ b/ndn-cxx/security/pib/identity.cpp @@ -0,0 +1,120 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/identity.hpp" +#include "ndn-cxx/security/pib/impl/identity-impl.hpp" + +namespace ndn { +namespace security { +namespace pib { + +Identity::Identity() = default; + +Identity::Identity(weak_ptr impl) + : m_impl(impl) +{ +} + +const Name& +Identity::getName() const +{ + return lock()->getName(); +} + +Key +Identity::addKey(const uint8_t* key, size_t keyLen, const Name& keyName) const +{ + return lock()->addKey(key, keyLen, keyName); +} + +void +Identity::removeKey(const Name& keyName) const +{ + return lock()->removeKey(keyName); +} + +Key +Identity::getKey(const Name& keyName) const +{ + return lock()->getKey(keyName); +} + +const KeyContainer& +Identity::getKeys() const +{ + return lock()->getKeys(); +} + +const Key& +Identity::setDefaultKey(const Name& keyName) const +{ + return lock()->setDefaultKey(keyName); +} + +const Key& +Identity::setDefaultKey(const uint8_t* key, size_t keyLen, const Name& keyName) const +{ + return lock()->setDefaultKey(key, keyLen, keyName); +} + +const Key& +Identity::getDefaultKey() const +{ + return lock()->getDefaultKey(); +} + +Identity::operator bool() const +{ + return !m_impl.expired(); +} + +shared_ptr +Identity::lock() const +{ + auto impl = m_impl.lock(); + + if (impl == nullptr) + NDN_THROW(std::domain_error("Invalid Identity instance")); + + return impl; +} + +bool +operator!=(const Identity& lhs, const Identity& rhs) +{ + return lhs.m_impl.owner_before(rhs.m_impl) || rhs.m_impl.owner_before(lhs.m_impl); +} + +std::ostream& +operator<<(std::ostream& os, const Identity& id) +{ + if (id) { + os << id.getName(); + } + else { + os << "(empty)"; + } + return os; +} + +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/pib/identity.hpp b/ndn-cxx/security/pib/identity.hpp new file mode 100644 index 000000000..23a294085 --- /dev/null +++ b/ndn-cxx/security/pib/identity.hpp @@ -0,0 +1,177 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_PIB_IDENTITY_HPP +#define NDN_SECURITY_PIB_IDENTITY_HPP + +#include "ndn-cxx/security/pib/key-container.hpp" + +namespace ndn { +namespace security { +namespace pib { + +namespace detail { +class IdentityImpl; +} // namespace detail + +/** + * @brief A frontend handle of an Identity + * + * Identity is at the top level in PIB's Identity-Key-Certificate hierarchy. An identity has a + * Name, and contains zero or more keys, at most one of which is set as the default key of this + * identity. Properties of a key can be accessed after obtaining a Key object. + */ +class Identity +{ +public: + /** + * @brief Default Constructor + * + * Identity created using this default constructor is just a place holder. + * It can obtain an actual instance from Pib::getIdentity(...). A typical + * usage would be for exception handling: + * + * Identity id; + * try { + * id = pib.getIdentity(...); + * } + * catch (const Pib::Error&) { + * ... + * } + * + * An Identity instance created using this constructor is invalid. Calling a + * member method on an invalid Identity instance may cause an std::domain_error. + */ + Identity(); + + /** + * @brief Create an Identity with a backend implementation @p impl. + * + * This method should only be used by IdentityContainer. + */ + explicit + Identity(weak_ptr impl); + + /** + * @brief Get the name of the identity. + */ + const Name& + getName() const; + + /** + * @brief Get a key with id @p keyName. + * @throw std::invalid_argument @p keyName does not match identity + * @throw Pib::Error the key does not exist. + */ + Key + getKey(const Name& keyName) const; + + /** + * @brief Get all keys for this identity. + */ + const KeyContainer& + getKeys() const; + + /** + * @brief Get the default key for this Identity. + * @throw Pib::Error the default key does not exist. + */ + const Key& + getDefaultKey() const; + + /** + * @return True if the identity instance is valid + */ + explicit + operator bool() const; + +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: // write operations should be private + /** + * @brief Add a @p key of @p keyLen bytes (in PKCS#8 format) with @p keyName. + * @return the handle of added key + * @throw std::invalid_argument key name does not match identity + * + * If a key with the same name already exists, overwrite the key. + */ + Key + addKey(const uint8_t* key, size_t keyLen, const Name& keyName) const; + + /** + * @brief Remove a key with @p keyName + * @throw std::invalid_argument @p keyName does not match identity + */ + void + removeKey(const Name& keyName) const; + + /** + * @brief Set an existing key with @p keyName as the default key. + * @throw std::invalid_argument @p keyName does not match identity + * @throw Pib::Error the key does not exist. + * @return The default key + */ + const Key& + setDefaultKey(const Name& keyName) const; + + /** + * @brief Add a @p key of @p keyLen bytes with @p keyName and set it as the default key + * @throw std::invalid_argument @p keyName does not match identity + * @throw Pib::Error the key with the same name already exists. + * @return the default key + */ + const Key& + setDefaultKey(const uint8_t* key, size_t keyLen, const Name& keyName) const; + +private: + /** + * @brief Check the validity of the instance + * @return a shared_ptr when the instance is valid + * @throw std::domain_error the instance is invalid + */ + shared_ptr + lock() const; + +private: + weak_ptr m_impl; + + friend class v2::KeyChain; + friend bool operator!=(const Identity&, const Identity&); +}; + +bool +operator!=(const Identity& lhs, const Identity& rhs); + +inline bool +operator==(const Identity& lhs, const Identity& rhs) +{ + return !(lhs != rhs); +} + +std::ostream& +operator<<(std::ostream& os, const Identity& id); + +} // namespace pib + +using pib::Identity; + +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_PIB_IDENTITY_HPP diff --git a/ndn-cxx/security/pib/impl/identity-impl.cpp b/ndn-cxx/security/pib/impl/identity-impl.cpp new file mode 100644 index 000000000..dd77a1b84 --- /dev/null +++ b/ndn-cxx/security/pib/impl/identity-impl.cpp @@ -0,0 +1,114 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/impl/identity-impl.hpp" +#include "ndn-cxx/security/pib/pib-impl.hpp" +#include "ndn-cxx/security/pib/pib.hpp" + +namespace ndn { +namespace security { +namespace pib { +namespace detail { + +IdentityImpl::IdentityImpl(const Name& identityName, shared_ptr pibImpl, bool needInit) + : m_name(identityName) + , m_pib(std::move(pibImpl)) + , m_keys(identityName, m_pib) + , m_isDefaultKeyLoaded(false) +{ + BOOST_ASSERT(m_pib != nullptr); + + if (needInit) { + m_pib->addIdentity(m_name); + } + else if (!m_pib->hasIdentity(m_name)) { + NDN_THROW(Pib::Error("Identity " + m_name.toUri() + " does not exist")); + } +} + +Key +IdentityImpl::addKey(const uint8_t* key, size_t keyLen, const Name& keyName) +{ + BOOST_ASSERT(m_keys.isConsistent()); + return m_keys.add(key, keyLen, keyName); +} + +void +IdentityImpl::removeKey(const Name& keyName) +{ + BOOST_ASSERT(m_keys.isConsistent()); + + if (m_isDefaultKeyLoaded && m_defaultKey.getName() == keyName) + m_isDefaultKeyLoaded = false; + + m_keys.remove(keyName); +} + +Key +IdentityImpl::getKey(const Name& keyName) const +{ + BOOST_ASSERT(m_keys.isConsistent()); + return m_keys.get(keyName); +} + +const KeyContainer& +IdentityImpl::getKeys() const +{ + BOOST_ASSERT(m_keys.isConsistent()); + return m_keys; +} + +const Key& +IdentityImpl::setDefaultKey(const Name& keyName) +{ + BOOST_ASSERT(m_keys.isConsistent()); + + m_defaultKey = m_keys.get(keyName); + m_isDefaultKeyLoaded = true; + m_pib->setDefaultKeyOfIdentity(m_name, keyName); + return m_defaultKey; +} + +const Key& +IdentityImpl::setDefaultKey(const uint8_t* key, size_t keyLen, const Name& keyName) +{ + addKey(key, keyLen, keyName); + return setDefaultKey(keyName); +} + +const Key& +IdentityImpl::getDefaultKey() const +{ + BOOST_ASSERT(m_keys.isConsistent()); + + if (!m_isDefaultKeyLoaded) { + m_defaultKey = m_keys.get(m_pib->getDefaultKeyOfIdentity(m_name)); + m_isDefaultKeyLoaded = true; + } + BOOST_ASSERT(m_pib->getDefaultKeyOfIdentity(m_name) == m_defaultKey.getName()); + + return m_defaultKey; +} + +} // namespace detail +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/pib/impl/identity-impl.hpp b/ndn-cxx/security/pib/impl/identity-impl.hpp new file mode 100644 index 000000000..b78ec588a --- /dev/null +++ b/ndn-cxx/security/pib/impl/identity-impl.hpp @@ -0,0 +1,139 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_PIB_IMPL_IDENTITY_IMPL_HPP +#define NDN_SECURITY_PIB_IMPL_IDENTITY_IMPL_HPP + +#include "ndn-cxx/security/pib/key-container.hpp" + +namespace ndn { +namespace security { +namespace pib { + +class PibImpl; + +namespace detail { + +/** + * @brief Backend instance of Identity + * + * An Identity has only one backend instance, but may have multiple frontend handles. + * Each frontend handle is associated with the only one backend IdentityImpl. + * + * @throw PibImpl::Error when underlying implementation has non-semantic error. + */ +class IdentityImpl : noncopyable +{ +public: + /** + * @brief Create an Identity with @p identityName. + * + * @param identityName The name of the Identity. + * @param pibImpl The PIB backend implementation. + * @param needInit If true, create the identity in backend when the identity does not exist. + * Otherwise, throw Pib::Error when the identity does not exist. + */ + IdentityImpl(const Name& identityName, shared_ptr pibImpl, bool needInit = false); + + /** + * @brief Get the name of the identity. + */ + const Name& + getName() const + { + return m_name; + } + + /** + * @brief Add a @p key of @p keyLen bytes with @p keyName (in PKCS#8 format). + * + * If no default key is set before, the new key will be set as the default key of the identity. + * If a key with the same name already exists, overwrite the key. + * + * @return the added key. + * @throw std::invalid_argument key name does not match identity + */ + Key + addKey(const uint8_t* key, size_t keyLen, const Name& keyName); + + /** + * @brief Remove a key with @p keyName + * @throw std::invalid_argument @p keyName does not match identity + */ + void + removeKey(const Name& keyName); + + /** + * @brief Get a key with id @p keyName. + * + * @throw std::invalid_argument @p keyName does not match identity + * @throw Pib::Error the key does not exist. + */ + Key + getKey(const Name& keyName) const; + + /** + * @brief Get all keys for this Identity. + */ + const KeyContainer& + getKeys() const; + + /** + * @brief Set the key with id @p keyName. + * @throw std::invalid_argument @p keyName does not match identity + * @throw Pib::Error the key does not exist. + * @return The default key + */ + const Key& + setDefaultKey(const Name& keyName); + + /** + * @brief Add @p key of @p keyLen bytes with @p keyName and set it as the default key + * @throw std::invalid_argument @p keyName does not match identity + * @throw Pib::Error the key with the same name already exists + * @return the default key + */ + const Key& + setDefaultKey(const uint8_t* key, size_t keyLen, const Name& keyName); + + /** + * @brief Get the default key for this Identity. + * @throw Pib::Error the default key does not exist. + */ + const Key& + getDefaultKey() const; + +private: + Name m_name; + + shared_ptr m_pib; + + KeyContainer m_keys; + mutable bool m_isDefaultKeyLoaded; + mutable Key m_defaultKey; +}; + +} // namespace detail +} // namespace pib +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_PIB_IMPL_IDENTITY_IMPL_HPP diff --git a/ndn-cxx/security/pib/impl/key-impl.cpp b/ndn-cxx/security/pib/impl/key-impl.cpp new file mode 100644 index 000000000..79c03004d --- /dev/null +++ b/ndn-cxx/security/pib/impl/key-impl.cpp @@ -0,0 +1,137 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/impl/key-impl.hpp" +#include "ndn-cxx/security/pib/pib-impl.hpp" +#include "ndn-cxx/security/pib/pib.hpp" +#include "ndn-cxx/security/transform/public-key.hpp" + +namespace ndn { +namespace security { +namespace pib { +namespace detail { + +KeyImpl::KeyImpl(const Name& keyName, const uint8_t* key, size_t keyLen, shared_ptr pibImpl) + : m_identity(v2::extractIdentityFromKeyName(keyName)) + , m_keyName(keyName) + , m_key(key, keyLen) + , m_pib(std::move(pibImpl)) + , m_certificates(keyName, m_pib) + , m_isDefaultCertificateLoaded(false) +{ + BOOST_ASSERT(m_pib != nullptr); + + transform::PublicKey publicKey; + try { + publicKey.loadPkcs8(key, keyLen); + } + catch (const transform::PublicKey::Error&) { + NDN_THROW_NESTED(std::invalid_argument("Invalid key bits")); + } + m_keyType = publicKey.getKeyType(); + + m_pib->addKey(m_identity, m_keyName, key, keyLen); +} + +KeyImpl::KeyImpl(const Name& keyName, shared_ptr pibImpl) + : m_identity(v2::extractIdentityFromKeyName(keyName)) + , m_keyName(keyName) + , m_pib(std::move(pibImpl)) + , m_certificates(keyName, m_pib) + , m_isDefaultCertificateLoaded(false) +{ + BOOST_ASSERT(m_pib != nullptr); + + m_key = m_pib->getKeyBits(m_keyName); + + transform::PublicKey key; + key.loadPkcs8(m_key.data(), m_key.size()); + m_keyType = key.getKeyType(); +} + +void +KeyImpl::addCertificate(const v2::Certificate& certificate) +{ + BOOST_ASSERT(m_certificates.isConsistent()); + m_certificates.add(certificate); +} + +void +KeyImpl::removeCertificate(const Name& certName) +{ + BOOST_ASSERT(m_certificates.isConsistent()); + + if (m_isDefaultCertificateLoaded && m_defaultCertificate.getName() == certName) + m_isDefaultCertificateLoaded = false; + + m_certificates.remove(certName); +} + +v2::Certificate +KeyImpl::getCertificate(const Name& certName) const +{ + BOOST_ASSERT(m_certificates.isConsistent()); + return m_certificates.get(certName); +} + +const CertificateContainer& +KeyImpl::getCertificates() const +{ + BOOST_ASSERT(m_certificates.isConsistent()); + return m_certificates; +} + +const v2::Certificate& +KeyImpl::setDefaultCertificate(const Name& certName) +{ + BOOST_ASSERT(m_certificates.isConsistent()); + + m_defaultCertificate = m_certificates.get(certName); + m_pib->setDefaultCertificateOfKey(m_keyName, certName); + m_isDefaultCertificateLoaded = true; + return m_defaultCertificate; +} + +const v2::Certificate& +KeyImpl::setDefaultCertificate(const v2::Certificate& certificate) +{ + addCertificate(certificate); + return setDefaultCertificate(certificate.getName()); +} + +const v2::Certificate& +KeyImpl::getDefaultCertificate() const +{ + BOOST_ASSERT(m_certificates.isConsistent()); + + if (!m_isDefaultCertificateLoaded) { + m_defaultCertificate = m_pib->getDefaultCertificateOfKey(m_keyName); + m_isDefaultCertificateLoaded = true; + } + BOOST_ASSERT(m_pib->getDefaultCertificateOfKey(m_keyName).wireEncode() == m_defaultCertificate.wireEncode()); + + return m_defaultCertificate; +} + +} // namespace detail +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/pib/impl/key-impl.hpp b/ndn-cxx/security/pib/impl/key-impl.hpp new file mode 100644 index 000000000..4448ec498 --- /dev/null +++ b/ndn-cxx/security/pib/impl/key-impl.hpp @@ -0,0 +1,187 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_PIB_IMPL_KEY_IMPL_HPP +#define NDN_SECURITY_PIB_IMPL_KEY_IMPL_HPP + +#include "ndn-cxx/security/security-common.hpp" +#include "ndn-cxx/security/pib/certificate-container.hpp" + +namespace ndn { +namespace security { +namespace pib { + +class PibImpl; + +namespace detail { + +/** + * @brief Backend instance of Key + * + * An Key has only one backend instance, but may have multiple frontend handles. + * Each frontend handle is associated with the only one backend KeyImpl. + * + * @throw PibImpl::Error when underlying implementation has non-semantic error. + */ +class KeyImpl : noncopyable +{ +public: + /** + * @brief Create a KeyImpl with @p keyName. + * + * If the key does not exist in the backend, it will be added. + * If a key with the same name already exists, it will be overwritten. + * + * @param keyName The name of the key. + * @param key The public key to add. + * @param keyLen The length of the key. + * @param pibImpl The Pib backend implementation. + * @throw std::invalid_argument @p key is invalid. + */ + KeyImpl(const Name& keyName, const uint8_t* key, size_t keyLen, shared_ptr pibImpl); + + /** + * @brief Create a KeyImpl with @p keyName. + * + * @param keyName The name of the key. + * @param pibImpl The Pib backend implementation. + * @throw Pib::Error the key does not exist. + */ + KeyImpl(const Name& keyName, shared_ptr pibImpl); + + /** + * @brief Get the name of the key. + */ + const Name& + getName() const + { + return m_keyName; + } + + /** + * @brief Get the name of the belonging identity. + */ + const Name& + getIdentity() const + { + return m_identity; + } + + /** + * @brief Get key type. + */ + KeyType + getKeyType() const + { + return m_keyType; + } + + /** + * @brief Get public key bits. + */ + const Buffer& + getPublicKey() const + { + return m_key; + } + + /** + * @brief Add @p certificate. + * + * If no default certificate is set before, the new certificate will be set as the default + * certificate of the key. + * + * If a certificate with the same name (without implicit digest) already exists, it will + * be overwritten. + * + * @throw std::invalid_argument the certificate name does not match the key name. + */ + void + addCertificate(const v2::Certificate& certificate); + + /** + * @brief Remove a certificate with @p certName. + * @throw std::invalid_argument @p certName does not match the key name. + */ + void + removeCertificate(const Name& certName); + + /** + * @brief Get a certificate with @p certName. + * @throw std::invalid_argument @p certName does not match the key name. + * @throw Pib::Error the certificate does not exist. + */ + v2::Certificate + getCertificate(const Name& certName) const; + + /** + * @brief Get all the certificates for this key. + */ + const CertificateContainer& + getCertificates() const; + + /** + * @brief Set an existing certificate with name @p certName as the default certificate. + * @throw std::invalid_argument @p certName does not match the key name. + * @throw Pib::Error the certificate does not exist. + * @return the default certificate + */ + const v2::Certificate& + setDefaultCertificate(const Name& certName); + + /** + * @brief Add @p certificate and set it as the default certificate for this key. + * + * If a certificate with the same name (without implicit digest) already exists, it will + * be overwritten. + * + * @throw std::invalid_argument @p certificate does not match the key name. + * @return the default certificate + */ + const v2::Certificate& + setDefaultCertificate(const v2::Certificate& certificate); + + /** + * @brief Get the default certificate for this key. + * @throw Pib::Error the default certificate does not exist. + */ + const v2::Certificate& + getDefaultCertificate() const; + +private: + Name m_identity; + Name m_keyName; + Buffer m_key; + KeyType m_keyType; + + shared_ptr m_pib; + + CertificateContainer m_certificates; + mutable bool m_isDefaultCertificateLoaded; + mutable v2::Certificate m_defaultCertificate; +}; + +} // namespace detail +} // namespace pib +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_PIB_IMPL_KEY_IMPL_HPP diff --git a/ndn-cxx/security/pib/impl/pib-memory.cpp b/ndn-cxx/security/pib/impl/pib-memory.cpp new file mode 100644 index 000000000..c509851a0 --- /dev/null +++ b/ndn-cxx/security/pib/impl/pib-memory.cpp @@ -0,0 +1,281 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/impl/pib-memory.hpp" +#include "ndn-cxx/security/pib/pib.hpp" +#include "ndn-cxx/security/security-common.hpp" + +#include + +namespace ndn { +namespace security { +namespace pib { + +PibMemory::PibMemory(const std::string&) + : m_hasDefaultIdentity(false) +{ +} + +const std::string& +PibMemory::getScheme() +{ + static std::string scheme = "pib-memory"; + return scheme; +} + +void +PibMemory::setTpmLocator(const std::string& tpmLocator) +{ + m_tpmLocator = tpmLocator; +} + +std::string +PibMemory::getTpmLocator() const +{ + return m_tpmLocator; +} + +bool +PibMemory::hasIdentity(const Name& identity) const +{ + return (m_identities.count(identity) > 0); +} + +void +PibMemory::addIdentity(const Name& identity) +{ + m_identities.insert(identity); + + if (!m_hasDefaultIdentity) { + m_defaultIdentity = identity; + m_hasDefaultIdentity = true; + } +} + +void +PibMemory::removeIdentity(const Name& identity) +{ + m_identities.erase(identity); + if (identity == m_defaultIdentity) { + m_hasDefaultIdentity = false; + m_defaultIdentity.clear(); + } + + auto keyNames = getKeysOfIdentity(identity); + for (const Name& keyName : keyNames) { + removeKey(keyName); + } +} + +void +PibMemory::clearIdentities() +{ + m_hasDefaultIdentity = false; + m_defaultIdentity.clear(); + m_identities.clear(); + m_defaultKeys.clear(); + m_keys.clear(); + m_defaultCerts.clear(); + m_certs.clear(); +} + +std::set +PibMemory::getIdentities() const +{ + return m_identities; +} + +void +PibMemory::setDefaultIdentity(const Name& identityName) +{ + addIdentity(identityName); + m_defaultIdentity = identityName; + m_hasDefaultIdentity = true; +} + +Name +PibMemory::getDefaultIdentity() const +{ + if (m_hasDefaultIdentity) { + return m_defaultIdentity; + } + + NDN_THROW(Pib::Error("No default identity")); +} + +bool +PibMemory::hasKey(const Name& keyName) const +{ + return (m_keys.count(keyName) > 0); +} + +void +PibMemory::addKey(const Name& identity, const Name& keyName, + const uint8_t* key, size_t keyLen) +{ + addIdentity(identity); + + m_keys[keyName] = Buffer(key, keyLen); + + if (m_defaultKeys.count(identity) == 0) { + m_defaultKeys[identity] = keyName; + } +} + +void +PibMemory::removeKey(const Name& keyName) +{ + Name identity = v2::extractIdentityFromKeyName(keyName); + + m_keys.erase(keyName); + m_defaultKeys.erase(identity); + + auto certNames = getCertificatesOfKey(keyName); + for (const auto& certName : certNames) { + removeCertificate(certName); + } +} + +Buffer +PibMemory::getKeyBits(const Name& keyName) const +{ + if (!hasKey(keyName)) { + NDN_THROW(Pib::Error("Key `" + keyName.toUri() + "` not found")); + } + + auto key = m_keys.find(keyName); + BOOST_ASSERT(key != m_keys.end()); + return key->second; +} + +std::set +PibMemory::getKeysOfIdentity(const Name& identity) const +{ + std::set ids; + for (const auto& keyName : m_keys | boost::adaptors::map_keys) { + if (identity == v2::extractIdentityFromKeyName(keyName)) { + ids.insert(keyName); + } + } + return ids; +} + +void +PibMemory::setDefaultKeyOfIdentity(const Name& identity, const Name& keyName) +{ + if (!hasKey(keyName)) { + NDN_THROW(Pib::Error("Key `" + keyName.toUri() + "` not found")); + } + + m_defaultKeys[identity] = keyName; +} + +Name +PibMemory::getDefaultKeyOfIdentity(const Name& identity) const +{ + auto defaultKey = m_defaultKeys.find(identity); + if (defaultKey == m_defaultKeys.end()) { + NDN_THROW(Pib::Error("No default key for identity `" + identity.toUri() + "`")); + } + + return defaultKey->second; +} + +bool +PibMemory::hasCertificate(const Name& certName) const +{ + return (m_certs.count(certName) > 0); +} + +void +PibMemory::addCertificate(const v2::Certificate& certificate) +{ + Name certName = certificate.getName(); + Name keyName = certificate.getKeyName(); + Name identity = certificate.getIdentity(); + + addKey(identity, keyName, certificate.getContent().value(), certificate.getContent().value_size()); + + m_certs[certName] = certificate; + if (m_defaultCerts.count(keyName) == 0) { + m_defaultCerts[keyName] = certName; + } +} + +void +PibMemory::removeCertificate(const Name& certName) +{ + m_certs.erase(certName); + auto defaultCert = m_defaultCerts.find(v2::extractKeyNameFromCertName(certName)); + if (defaultCert != m_defaultCerts.end() && defaultCert->second == certName) { + m_defaultCerts.erase(defaultCert); + } +} + +v2::Certificate +PibMemory::getCertificate(const Name& certName) const +{ + if (!hasCertificate(certName)) { + NDN_THROW(Pib::Error("Certificate `" + certName.toUri() + "` does not exist")); + } + + auto it = m_certs.find(certName); + return it->second; +} + +std::set +PibMemory::getCertificatesOfKey(const Name& keyName) const +{ + std::set certNames; + for (const auto& it : m_certs) { + if (v2::extractKeyNameFromCertName(it.second.getName()) == keyName) { + certNames.insert(it.first); + } + } + return certNames; +} + +void +PibMemory::setDefaultCertificateOfKey(const Name& keyName, const Name& certName) +{ + if (!hasCertificate(certName)) { + NDN_THROW(Pib::Error("Certificate `" + certName.toUri() + "` does not exist")); + } + + m_defaultCerts[keyName] = certName; +} + +v2::Certificate +PibMemory::getDefaultCertificateOfKey(const Name& keyName) const +{ + auto it = m_defaultCerts.find(keyName); + if (it == m_defaultCerts.end()) { + NDN_THROW(Pib::Error("No default certificate for key `" + keyName.toUri() + "`")); + } + + auto certIt = m_certs.find(it->second); + BOOST_ASSERT(certIt != m_certs.end()); + return certIt->second; +} + +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/pib/impl/pib-memory.hpp b/ndn-cxx/security/pib/impl/pib-memory.hpp new file mode 100644 index 000000000..df3cb7a52 --- /dev/null +++ b/ndn-cxx/security/pib/impl/pib-memory.hpp @@ -0,0 +1,148 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_PIB_IMPL_PIB_MEMORY_HPP +#define NDN_SECURITY_PIB_IMPL_PIB_MEMORY_HPP + +#include "ndn-cxx/security/pib/pib-impl.hpp" + +namespace ndn { +namespace security { +namespace pib { + +/** + * @brief An in-memory implementation of Pib + * + * All the contents in Pib are stored in memory + * and have the same lifetime as the implementation instance. + */ +class PibMemory : public PibImpl +{ +public: + /** + * @brief Create memory based PIB backend + * @param location Not used (required by the PIB-registration interface) + */ + explicit + PibMemory(const std::string& location = ""); + + static const std::string& + getScheme(); + +public: // TpmLocator management + void + setTpmLocator(const std::string& tpmLocator) override; + + std::string + getTpmLocator() const override; + +public: // Identity management + bool + hasIdentity(const Name& identity) const override; + + void + addIdentity(const Name& identity) override; + + void + removeIdentity(const Name& identity) override; + + void + clearIdentities() override; + + std::set + getIdentities() const override; + + void + setDefaultIdentity(const Name& identityName) override; + + Name + getDefaultIdentity() const override; + +public: // Key management + bool + hasKey(const Name& keyName) const override; + + void + addKey(const Name& identity, const Name& keyName, const uint8_t* key, size_t keyLen) override; + + void + removeKey(const Name& keyName) override; + + Buffer + getKeyBits(const Name& keyName) const override; + + std::set + getKeysOfIdentity(const Name& identity) const override; + + void + setDefaultKeyOfIdentity(const Name& identity, const Name& keyName) override; + + Name + getDefaultKeyOfIdentity(const Name& identity) const override; + +public: // Certificate management + bool + hasCertificate(const Name& certName) const override; + + void + addCertificate(const v2::Certificate& certificate) override; + + void + removeCertificate(const Name& certName) override; + + v2::Certificate + getCertificate(const Name& certName) const override; + + std::set + getCertificatesOfKey(const Name& keyName) const override; + + void + setDefaultCertificateOfKey(const Name& keyName, const Name& certName) override; + + v2::Certificate + getDefaultCertificateOfKey(const Name& keyName) const override; + +private: + std::string m_tpmLocator; + + bool m_hasDefaultIdentity; + Name m_defaultIdentity; + + std::set m_identities; + + /// @brief identity => default key Name + std::map m_defaultKeys; + + /// @brief keyName => keyBits + std::map m_keys; + + /// @brief keyName => default certificate Name + std::map m_defaultCerts; + + /// @brief certificate Name => certificate + std::map m_certs; +}; + +} // namespace pib +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_PIB_IMPL_PIB_MEMORY_HPP diff --git a/ndn-cxx/security/pib/impl/pib-sqlite3.cpp b/ndn-cxx/security/pib/impl/pib-sqlite3.cpp new file mode 100644 index 000000000..ca736413e --- /dev/null +++ b/ndn-cxx/security/pib/impl/pib-sqlite3.cpp @@ -0,0 +1,592 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/impl/pib-sqlite3.hpp" +#include "ndn-cxx/security/pib/pib.hpp" +#include "ndn-cxx/security/security-common.hpp" +#include "ndn-cxx/util/sqlite3-statement.hpp" + +#include + +#include +#include + +namespace ndn { +namespace security { +namespace pib { + +using util::Sqlite3Statement; + +static const std::string INITIALIZATION = R"SQL( +CREATE TABLE IF NOT EXISTS + tpmInfo( + tpm_locator BLOB + ); + +CREATE TABLE IF NOT EXISTS + identities( + id INTEGER PRIMARY KEY, + identity BLOB NOT NULL, + is_default INTEGER DEFAULT 0 + ); + +CREATE UNIQUE INDEX IF NOT EXISTS + identityIndex ON identities(identity); + +CREATE TRIGGER IF NOT EXISTS + identity_default_before_insert_trigger + BEFORE INSERT ON identities + FOR EACH ROW + WHEN NEW.is_default=1 + BEGIN + UPDATE identities SET is_default=0; + END; + +CREATE TRIGGER IF NOT EXISTS + identity_default_after_insert_trigger + AFTER INSERT ON identities + FOR EACH ROW + WHEN NOT EXISTS + (SELECT id + FROM identities + WHERE is_default=1) + BEGIN + UPDATE identities + SET is_default=1 + WHERE identity=NEW.identity; + END; + +CREATE TRIGGER IF NOT EXISTS + identity_default_update_trigger + BEFORE UPDATE ON identities + FOR EACH ROW + WHEN NEW.is_default=1 AND OLD.is_default=0 + BEGIN + UPDATE identities SET is_default=0; + END; + +CREATE TABLE IF NOT EXISTS + keys( + id INTEGER PRIMARY KEY, + identity_id INTEGER NOT NULL, + key_name BLOB NOT NULL, + key_bits BLOB NOT NULL, + is_default INTEGER DEFAULT 0, + FOREIGN KEY(identity_id) + REFERENCES identities(id) + ON DELETE CASCADE + ON UPDATE CASCADE + ); + +CREATE UNIQUE INDEX IF NOT EXISTS + keyIndex ON keys(key_name); + +CREATE TRIGGER IF NOT EXISTS + key_default_before_insert_trigger + BEFORE INSERT ON keys + FOR EACH ROW + WHEN NEW.is_default=1 + BEGIN + UPDATE keys + SET is_default=0 + WHERE identity_id=NEW.identity_id; + END; + +CREATE TRIGGER IF NOT EXISTS + key_default_after_insert_trigger + AFTER INSERT ON keys + FOR EACH ROW + WHEN NOT EXISTS + (SELECT id + FROM keys + WHERE is_default=1 + AND identity_id=NEW.identity_id) + BEGIN + UPDATE keys + SET is_default=1 + WHERE key_name=NEW.key_name; + END; + +CREATE TRIGGER IF NOT EXISTS + key_default_update_trigger + BEFORE UPDATE ON keys + FOR EACH ROW + WHEN NEW.is_default=1 AND OLD.is_default=0 + BEGIN + UPDATE keys + SET is_default=0 + WHERE identity_id=NEW.identity_id; + END; + + +CREATE TABLE IF NOT EXISTS + certificates( + id INTEGER PRIMARY KEY, + key_id INTEGER NOT NULL, + certificate_name BLOB NOT NULL, + certificate_data BLOB NOT NULL, + is_default INTEGER DEFAULT 0, + FOREIGN KEY(key_id) + REFERENCES keys(id) + ON DELETE CASCADE + ON UPDATE CASCADE + ); + +CREATE UNIQUE INDEX IF NOT EXISTS + certIndex ON certificates(certificate_name); + +CREATE TRIGGER IF NOT EXISTS + cert_default_before_insert_trigger + BEFORE INSERT ON certificates + FOR EACH ROW + WHEN NEW.is_default=1 + BEGIN + UPDATE certificates + SET is_default=0 + WHERE key_id=NEW.key_id; + END; + +CREATE TRIGGER IF NOT EXISTS + cert_default_after_insert_trigger + AFTER INSERT ON certificates + FOR EACH ROW + WHEN NOT EXISTS + (SELECT id + FROM certificates + WHERE is_default=1 + AND key_id=NEW.key_id) + BEGIN + UPDATE certificates + SET is_default=1 + WHERE certificate_name=NEW.certificate_name; + END; + +CREATE TRIGGER IF NOT EXISTS + cert_default_update_trigger + BEFORE UPDATE ON certificates + FOR EACH ROW + WHEN NEW.is_default=1 AND OLD.is_default=0 + BEGIN + UPDATE certificates + SET is_default=0 + WHERE key_id=NEW.key_id; + END; +)SQL"; + +PibSqlite3::PibSqlite3(const std::string& location) +{ + // Determine the path of PIB DB + boost::filesystem::path dbDir; + if (!location.empty()) { + dbDir = boost::filesystem::path(location); + } +#ifdef NDN_CXX_HAVE_TESTS + else if (getenv("TEST_HOME") != nullptr) { + dbDir = boost::filesystem::path(getenv("TEST_HOME")) / ".ndn"; + } +#endif // NDN_CXX_HAVE_TESTS + else if (getenv("HOME") != nullptr) { + dbDir = boost::filesystem::path(getenv("HOME")) / ".ndn"; + } + else { + dbDir = boost::filesystem::current_path() / ".ndn"; + } + boost::filesystem::create_directories(dbDir); + + // Open PIB + int result = sqlite3_open_v2((dbDir / "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) { + NDN_THROW(PibImpl::Error("PIB database cannot be opened/created in " + dbDir.string())); + } + + // enable foreign key + sqlite3_exec(m_database, "PRAGMA foreign_keys=ON", nullptr, nullptr, nullptr); + + // initialize PIB tables + char* errmsg = nullptr; + result = sqlite3_exec(m_database, INITIALIZATION.c_str(), nullptr, nullptr, &errmsg); + if (result != SQLITE_OK && errmsg != nullptr) { + std::string what = "PIB database cannot be initialized: "s + errmsg; + sqlite3_free(errmsg); + NDN_THROW(PibImpl::Error(what)); + } +} + +PibSqlite3::~PibSqlite3() +{ + sqlite3_close(m_database); +} + +const std::string& +PibSqlite3::getScheme() +{ + static std::string scheme = "pib-sqlite3"; + return scheme; +} + +void +PibSqlite3::setTpmLocator(const std::string& tpmLocator) +{ + Sqlite3Statement statement(m_database, "UPDATE tpmInfo SET tpm_locator=?"); + statement.bind(1, tpmLocator, SQLITE_TRANSIENT); + statement.step(); + + if (sqlite3_changes(m_database) == 0) { + // no row is updated, tpm_locator does not exist, insert it directly + Sqlite3Statement insertStatement(m_database, "INSERT INTO tpmInfo (tpm_locator) values (?)"); + insertStatement.bind(1, tpmLocator, SQLITE_TRANSIENT); + insertStatement.step(); + } +} + +std::string +PibSqlite3::getTpmLocator() const +{ + Sqlite3Statement statement(m_database, "SELECT tpm_locator FROM tpmInfo"); + int res = statement.step(); + if (res == SQLITE_ROW) + return statement.getString(0); + else + return ""; +} + +bool +PibSqlite3::hasIdentity(const Name& identity) const +{ + Sqlite3Statement statement(m_database, "SELECT id FROM identities WHERE identity=?"); + statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT); + return statement.step() == SQLITE_ROW; +} + +void +PibSqlite3::addIdentity(const Name& identity) +{ + if (!hasIdentity(identity)) { + Sqlite3Statement statement(m_database, "INSERT INTO identities (identity) values (?)"); + statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT); + statement.step(); + } + + if (!hasDefaultIdentity()) { + setDefaultIdentity(identity); + } +} + +void +PibSqlite3::removeIdentity(const Name& identity) +{ + Sqlite3Statement statement(m_database, "DELETE FROM identities WHERE identity=?"); + statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT); + statement.step(); +} + +void +PibSqlite3::clearIdentities() +{ + Sqlite3Statement statement(m_database, "DELETE FROM identities"); + statement.step(); +} + +std::set +PibSqlite3::getIdentities() const +{ + std::set identities; + Sqlite3Statement statement(m_database, "SELECT identity FROM identities"); + + while (statement.step() == SQLITE_ROW) + identities.insert(Name(statement.getBlock(0))); + + return identities; +} + +void +PibSqlite3::setDefaultIdentity(const Name& identityName) +{ + Sqlite3Statement statement(m_database, "UPDATE identities SET is_default=1 WHERE identity=?"); + statement.bind(1, identityName.wireEncode(), SQLITE_TRANSIENT); + statement.step(); +} + +Name +PibSqlite3::getDefaultIdentity() const +{ + Sqlite3Statement statement(m_database, "SELECT identity FROM identities WHERE is_default=1"); + + if (statement.step() == SQLITE_ROW) + return Name(statement.getBlock(0)); + else + NDN_THROW(Pib::Error("No default identity")); +} + +bool +PibSqlite3::hasDefaultIdentity() const +{ + Sqlite3Statement statement(m_database, "SELECT identity FROM identities WHERE is_default=1"); + return (statement.step() == SQLITE_ROW); +} + +bool +PibSqlite3::hasKey(const Name& keyName) const +{ + Sqlite3Statement statement(m_database, "SELECT id FROM keys WHERE key_name=?"); + statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT); + + return (statement.step() == SQLITE_ROW); +} + +void +PibSqlite3::addKey(const Name& identity, const Name& keyName, + const uint8_t* key, size_t keyLen) +{ + // ensure identity exists + addIdentity(identity); + + if (!hasKey(keyName)) { + Sqlite3Statement statement(m_database, + "INSERT INTO keys (identity_id, key_name, key_bits) " + "VALUES ((SELECT id FROM identities WHERE identity=?), ?, ?)"); + statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT); + statement.bind(2, keyName.wireEncode(), SQLITE_TRANSIENT); + statement.bind(3, key, keyLen, SQLITE_STATIC); + statement.step(); + } + else { + Sqlite3Statement statement(m_database, + "UPDATE keys SET key_bits=? WHERE key_name=?"); + statement.bind(1, key, keyLen, SQLITE_STATIC); + statement.bind(2, keyName.wireEncode(), SQLITE_TRANSIENT); + statement.step(); + } + + if (!hasDefaultKeyOfIdentity(identity)) { + setDefaultKeyOfIdentity(identity, keyName); + } +} + +void +PibSqlite3::removeKey(const Name& keyName) +{ + Sqlite3Statement statement(m_database, "DELETE FROM keys WHERE key_name=?"); + statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT); + statement.step(); +} + +Buffer +PibSqlite3::getKeyBits(const Name& keyName) const +{ + Sqlite3Statement statement(m_database, "SELECT key_bits FROM keys WHERE key_name=?"); + statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT); + + if (statement.step() == SQLITE_ROW) + return Buffer(statement.getBlob(0), statement.getSize(0)); + else + NDN_THROW(Pib::Error("Key `" + keyName.toUri() + "` does not exist")); +} + +std::set +PibSqlite3::getKeysOfIdentity(const Name& identity) const +{ + std::set keyNames; + + Sqlite3Statement statement(m_database, + "SELECT key_name " + "FROM keys JOIN identities ON keys.identity_id=identities.id " + "WHERE identities.identity=?"); + statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT); + + while (statement.step() == SQLITE_ROW) { + keyNames.insert(Name(statement.getBlock(0))); + } + + return keyNames; +} + +void +PibSqlite3::setDefaultKeyOfIdentity(const Name& identity, const Name& keyName) +{ + if (!hasKey(keyName)) { + NDN_THROW(Pib::Error("Key `" + keyName.toUri() + "` does not exist")); + } + + Sqlite3Statement statement(m_database, "UPDATE keys SET is_default=1 WHERE key_name=?"); + statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT); + statement.step(); +} + +Name +PibSqlite3::getDefaultKeyOfIdentity(const Name& identity) const +{ + if (!hasIdentity(identity)) { + NDN_THROW(Pib::Error("Identity `" + identity.toUri() + "` does not exist")); + } + + Sqlite3Statement statement(m_database, + "SELECT key_name " + "FROM keys JOIN identities ON keys.identity_id=identities.id " + "WHERE identities.identity=? AND keys.is_default=1"); + statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT); + + if (statement.step() == SQLITE_ROW) { + return Name(statement.getBlock(0)); + } + else + NDN_THROW(Pib::Error("No default key for identity `" + identity.toUri() + "`")); +} + +bool +PibSqlite3::hasDefaultKeyOfIdentity(const Name& identity) const +{ + Sqlite3Statement statement(m_database, + "SELECT key_name " + "FROM keys JOIN identities ON keys.identity_id=identities.id " + "WHERE identities.identity=? AND keys.is_default=1"); + statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT); + + return (statement.step() == SQLITE_ROW); +} + +bool +PibSqlite3::hasCertificate(const Name& certName) const +{ + Sqlite3Statement statement(m_database, "SELECT id FROM certificates WHERE certificate_name=?"); + statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT); + return (statement.step() == SQLITE_ROW); +} + +void +PibSqlite3::addCertificate(const v2::Certificate& certificate) +{ + // ensure key exists + const Block& content = certificate.getContent(); + addKey(certificate.getIdentity(), certificate.getKeyName(), content.value(), content.value_size()); + + if (!hasCertificate(certificate.getName())) { + Sqlite3Statement statement(m_database, + "INSERT INTO certificates " + "(key_id, certificate_name, certificate_data) " + "VALUES ((SELECT id FROM keys WHERE key_name=?), ?, ?)"); + statement.bind(1, certificate.getKeyName().wireEncode(), SQLITE_TRANSIENT); + statement.bind(2, certificate.getName().wireEncode(), SQLITE_TRANSIENT); + statement.bind(3, certificate.wireEncode(), SQLITE_STATIC); + statement.step(); + } + else { + Sqlite3Statement statement(m_database, + "UPDATE certificates SET certificate_data=? WHERE certificate_name=?"); + statement.bind(1, certificate.wireEncode(), SQLITE_STATIC); + statement.bind(2, certificate.getName().wireEncode(), SQLITE_TRANSIENT); + statement.step(); + } + + if (!hasDefaultCertificateOfKey(certificate.getKeyName())) { + setDefaultCertificateOfKey(certificate.getKeyName(), certificate.getName()); + } +} + +void +PibSqlite3::removeCertificate(const Name& certName) +{ + Sqlite3Statement statement(m_database, "DELETE FROM certificates WHERE certificate_name=?"); + statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT); + statement.step(); +} + +v2::Certificate +PibSqlite3::getCertificate(const Name& certName) const +{ + Sqlite3Statement statement(m_database, + "SELECT certificate_data FROM certificates WHERE certificate_name=?"); + statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT); + + if (statement.step() == SQLITE_ROW) + return v2::Certificate(statement.getBlock(0)); + else + NDN_THROW(Pib::Error("Certificate `" + certName.toUri() + "` does not exit")); +} + +std::set +PibSqlite3::getCertificatesOfKey(const Name& keyName) const +{ + std::set certNames; + + Sqlite3Statement statement(m_database, + "SELECT certificate_name " + "FROM certificates JOIN keys ON certificates.key_id=keys.id " + "WHERE keys.key_name=?"); + statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT); + + while (statement.step() == SQLITE_ROW) + certNames.insert(Name(statement.getBlock(0))); + + return certNames; +} + +void +PibSqlite3::setDefaultCertificateOfKey(const Name& keyName, const Name& certName) +{ + if (!hasCertificate(certName)) { + NDN_THROW(Pib::Error("Certificate `" + certName.toUri() + "` does not exist")); + } + + Sqlite3Statement statement(m_database, + "UPDATE certificates SET is_default=1 WHERE certificate_name=?"); + statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT); + statement.step(); +} + +v2::Certificate +PibSqlite3::getDefaultCertificateOfKey(const Name& keyName) const +{ + Sqlite3Statement statement(m_database, + "SELECT certificate_data " + "FROM certificates JOIN keys ON certificates.key_id=keys.id " + "WHERE certificates.is_default=1 AND keys.key_name=?"); + statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT); + + if (statement.step() == SQLITE_ROW) + return v2::Certificate(statement.getBlock(0)); + else + NDN_THROW(Pib::Error("No default certificate for key `" + keyName.toUri() + "`")); +} + +bool +PibSqlite3::hasDefaultCertificateOfKey(const Name& keyName) const +{ + Sqlite3Statement statement(m_database, + "SELECT certificate_data " + "FROM certificates JOIN keys ON certificates.key_id=keys.id " + "WHERE certificates.is_default=1 AND keys.key_name=?"); + statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT); + + return statement.step() == SQLITE_ROW; +} + +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/pib/impl/pib-sqlite3.hpp b/ndn-cxx/security/pib/impl/pib-sqlite3.hpp new file mode 100644 index 000000000..ab80add9e --- /dev/null +++ b/ndn-cxx/security/pib/impl/pib-sqlite3.hpp @@ -0,0 +1,157 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITTY_PIB_IMPL_PIB_SQLITE3_HPP +#define NDN_SECURITTY_PIB_IMPL_PIB_SQLITE3_HPP + +#include "ndn-cxx/security/pib/pib-impl.hpp" + +struct sqlite3; + +namespace ndn { +namespace security { +namespace pib { + +/** + * @brief Pib backend implementation based on SQLite3 database + * + * All the contents in Pib are stored in a SQLite3 database file. + * This backend provides more persistent storage than PibMemory. + */ +class PibSqlite3 : public PibImpl +{ +public: + /** + * @brief Create sqlite3-based PIB backed + * + * This method will create a SQLite3 database file under the directory @p location. + * If the directory does not exist, it will be created automatically. + * It assumes that the directory does not contain a PIB database of an older version, + * It is user's responsibility to update the older version database or remove the database. + * + * @param location The directory where the database file is located. By default, it points to the + * $HOME/.ndn directory. + * @throw PibImpl::Error when initialization fails. + */ + explicit + PibSqlite3(const std::string& location = ""); + + /** + * @brief Destruct and cleanup internal state + */ + ~PibSqlite3(); + + static const std::string& + getScheme(); + +public: // TpmLocator management + void + setTpmLocator(const std::string& tpmLocator) final; + + std::string + getTpmLocator() const final; + +public: // Identity management + bool + hasIdentity(const Name& identity) const final; + + void + addIdentity(const Name& identity) final; + + void + removeIdentity(const Name& identity) final; + + void + clearIdentities() final; + + std::set + getIdentities() const final; + + void + setDefaultIdentity(const Name& identityName) final; + + Name + getDefaultIdentity() const final; + +public: // Key management + bool + hasKey(const Name& keyName) const final; + + void + addKey(const Name& identity, const Name& keyName, + const uint8_t* key, size_t keyLen) final; + + void + removeKey(const Name& keyName) final; + + Buffer + getKeyBits(const Name& keyName) const final; + + std::set + getKeysOfIdentity(const Name& identity) const final; + + void + setDefaultKeyOfIdentity(const Name& identity, const Name& keyName) final; + + Name + getDefaultKeyOfIdentity(const Name& identity) const final; + +public: // Certificate Management + bool + hasCertificate(const Name& certName) const final; + + void + addCertificate(const v2::Certificate& certificate) final; + + void + removeCertificate(const Name& certName) final; + + v2::Certificate + getCertificate(const Name& certName) const final; + + std::set + getCertificatesOfKey(const Name& keyName) const final; + + void + setDefaultCertificateOfKey(const Name& keyName, const Name& certName) final; + + v2::Certificate + getDefaultCertificateOfKey(const Name& keyName) const final; + +private: + bool + hasDefaultIdentity() const; + + bool + hasDefaultKeyOfIdentity(const Name& identity) const; + + bool + hasDefaultCertificateOfKey(const Name& keyName) const; + +private: + sqlite3* m_database; +}; + +} // namespace pib +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITTY_PIB_IMPL_PIB_SQLITE3_HPP diff --git a/ndn-cxx/security/pib/key-container.cpp b/ndn-cxx/security/pib/key-container.cpp new file mode 100644 index 000000000..ccf3ad033 --- /dev/null +++ b/ndn-cxx/security/pib/key-container.cpp @@ -0,0 +1,172 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/key-container.hpp" +#include "ndn-cxx/security/pib/pib-impl.hpp" +#include "ndn-cxx/security/pib/impl/key-impl.hpp" +#include "ndn-cxx/util/concepts.hpp" + +namespace ndn { +namespace security { +namespace pib { + +NDN_CXX_ASSERT_FORWARD_ITERATOR(KeyContainer::const_iterator); + +KeyContainer::const_iterator::const_iterator() + : m_container(nullptr) +{ +} + +KeyContainer::const_iterator::const_iterator(std::set::const_iterator it, + const KeyContainer& container) + : m_it(it) + , m_container(&container) +{ +} + +Key +KeyContainer::const_iterator::operator*() +{ + BOOST_ASSERT(m_container != nullptr); + return m_container->get(*m_it); +} + +KeyContainer::const_iterator& +KeyContainer::const_iterator::operator++() +{ + ++m_it; + return *this; +} + +KeyContainer::const_iterator +KeyContainer::const_iterator::operator++(int) +{ + const_iterator it(*this); + ++m_it; + return it; +} + +bool +KeyContainer::const_iterator::operator==(const const_iterator& other) +{ + bool isThisEnd = m_container == nullptr || m_it == m_container->m_keyNames.end(); + bool isOtherEnd = other.m_container == nullptr || other.m_it == other.m_container->m_keyNames.end(); + return ((isThisEnd || isOtherEnd) ? + (isThisEnd == isOtherEnd) : + m_container->m_pib == other.m_container->m_pib && m_it == other.m_it); +} + +bool +KeyContainer::const_iterator::operator!=(const const_iterator& other) +{ + return !(*this == other); +} + +KeyContainer::KeyContainer(const Name& identity, shared_ptr pibImpl) + : m_identity(identity) + , m_pib(std::move(pibImpl)) +{ + BOOST_ASSERT(m_pib != nullptr); + m_keyNames = m_pib->getKeysOfIdentity(identity); +} + +KeyContainer::const_iterator +KeyContainer::begin() const +{ + return const_iterator(m_keyNames.begin(), *this); +} + +KeyContainer::const_iterator +KeyContainer::end() const +{ + return const_iterator(); +} + +KeyContainer::const_iterator +KeyContainer::find(const Name& keyName) const +{ + return const_iterator(m_keyNames.find(keyName), *this); +} + +size_t +KeyContainer::size() const +{ + return m_keyNames.size(); +} + +Key +KeyContainer::add(const uint8_t* key, size_t keyLen, const Name& keyName) +{ + if (m_identity != v2::extractIdentityFromKeyName(keyName)) { + NDN_THROW(std::invalid_argument("Key name `" + keyName.toUri() + "` does not match identity " + "`" + m_identity.toUri() + "`")); + } + + m_keyNames.insert(keyName); + m_keys[keyName] = make_shared(keyName, key, keyLen, m_pib); + + return get(keyName); +} + +void +KeyContainer::remove(const Name& keyName) +{ + if (m_identity != v2::extractIdentityFromKeyName(keyName)) { + NDN_THROW(std::invalid_argument("Key name `" + keyName.toUri() + "` does not match identity " + "`" + m_identity.toUri() + "`")); + } + + m_keyNames.erase(keyName); + m_keys.erase(keyName); + m_pib->removeKey(keyName); +} + +Key +KeyContainer::get(const Name& keyName) const +{ + if (m_identity != v2::extractIdentityFromKeyName(keyName)) { + NDN_THROW(std::invalid_argument("Key name `" + keyName.toUri() + "` does not match identity " + "`" + m_identity.toUri() + "`")); + } + + shared_ptr key; + auto it = m_keys.find(keyName); + + if (it != m_keys.end()) { + key = it->second; + } + else { + key = make_shared(keyName, m_pib); + m_keys[keyName] = key; + } + + return Key(key); +} + +bool +KeyContainer::isConsistent() const +{ + return m_keyNames == m_pib->getKeysOfIdentity(m_identity); +} + +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/pib/key-container.hpp b/ndn-cxx/security/pib/key-container.hpp new file mode 100644 index 000000000..d84e362f0 --- /dev/null +++ b/ndn-cxx/security/pib/key-container.hpp @@ -0,0 +1,171 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_PIB_KEY_CONTAINER_HPP +#define NDN_SECURITY_PIB_KEY_CONTAINER_HPP + +#include "ndn-cxx/security/pib/key.hpp" + +#include +#include +#include + +namespace ndn { +namespace security { +namespace pib { + +class PibImpl; + +namespace detail { +class KeyImpl; +class IdentityImpl; +} // namespace detail + +/** + * @brief Container of keys of an identity + * + * The container is used to search/enumerate keys of an identity. + * The container can be created only by detail::IdentityImpl. + */ +class KeyContainer : noncopyable +{ +public: + class const_iterator + { + public: + using iterator_category = std::forward_iterator_tag; + using value_type = const Key; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + + const_iterator(); + + Key + operator*(); + + const_iterator& + operator++(); + + const_iterator + operator++(int); + + bool + operator==(const const_iterator& other); + + bool + operator!=(const const_iterator& other); + + private: + const_iterator(std::set::const_iterator it, const KeyContainer& container); + + private: + std::set::const_iterator m_it; + const KeyContainer* m_container; + + friend class KeyContainer; + }; + + typedef const_iterator iterator; + +public: + const_iterator + begin() const; + + const_iterator + end() const; + + const_iterator + find(const Name& keyName) const; + + size_t + size() const; + + /** + * @brief Add @p key of @p keyLen bytes with @p keyName into the container + * @throw std::invalid_argument @p keyName does not match the identity + * + * If a key with the same name already exists, overwrite the key. + */ + Key + add(const uint8_t* key, size_t keyLen, const Name& keyName); + + /** + * @brief Remove a key with @p keyName from the container + * @throw std::invalid_argument @p keyName does not match the identity + */ + void + remove(const Name& keyName); + + /** + * @brief Get a key with @p keyName from the container + * @throw std::invalid_argument @p keyName does not match the identity + * @throw Pib::Error the key does not exist + */ + Key + get(const Name& keyName) const; + + /** + * @brief Check if the container is consistent with the backend storage + * + * @note this method is heavyweight and should be used in debugging mode only. + */ + bool + isConsistent() const; + +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: + /** + * @brief Create key container for @p identity + * @param pibImpl The PIB backend implementation. + */ + KeyContainer(const Name& identity, shared_ptr pibImpl); + + const std::set& + getKeyNames() const + { + return m_keyNames; + } + + const std::unordered_map>& + getLoadedKeys() const + { + return m_keys; + } + +private: + Name m_identity; + std::set m_keyNames; + /// @brief Cache of loaded detail::KeyImpl. + mutable std::unordered_map> m_keys; + + shared_ptr m_pib; + + friend class detail::IdentityImpl; +}; + +} // namespace pib + +using pib::KeyContainer; + +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_PIB_KEY_CONTAINER_HPP diff --git a/ndn-cxx/security/pib/key.cpp b/ndn-cxx/security/pib/key.cpp new file mode 100644 index 000000000..293effa41 --- /dev/null +++ b/ndn-cxx/security/pib/key.cpp @@ -0,0 +1,172 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/key.hpp" +#include "ndn-cxx/security/pib/impl/key-impl.hpp" +#include "ndn-cxx/security/v2/certificate.hpp" + +namespace ndn { +namespace security { +namespace pib { + +Key::Key() = default; + +Key::Key(weak_ptr impl) + : m_impl(impl) +{ +} + +const Name& +Key::getName() const +{ + return lock()->getName(); +} + +const Name& +Key::getIdentity() const +{ + return lock()->getIdentity(); +} + +KeyType +Key::getKeyType() const +{ + return lock()->getKeyType(); +} + +const Buffer& +Key::getPublicKey() const +{ + return lock()->getPublicKey(); +} + +void +Key::addCertificate(const v2::Certificate& certificate) const +{ + return lock()->addCertificate(certificate); +} + +void +Key::removeCertificate(const Name& certName) const +{ + return lock()->removeCertificate(certName); +} + +v2::Certificate +Key::getCertificate(const Name& certName) const +{ + return lock()->getCertificate(certName); +} + +const CertificateContainer& +Key::getCertificates() const +{ + return lock()->getCertificates(); +} + +const v2::Certificate& +Key::setDefaultCertificate(const Name& certName) const +{ + return lock()->setDefaultCertificate(certName); +} + +const v2::Certificate& +Key::setDefaultCertificate(const v2::Certificate& certificate) const +{ + return lock()->setDefaultCertificate(certificate); +} + +const v2::Certificate& +Key::getDefaultCertificate() const +{ + return lock()->getDefaultCertificate(); +} + +Key::operator bool() const +{ + return !m_impl.expired(); +} + +shared_ptr +Key::lock() const +{ + auto impl = m_impl.lock(); + + if (impl == nullptr) { + NDN_THROW(std::domain_error("Invalid key instance")); + } + + return impl; +} + +bool +operator!=(const Key& lhs, const Key& rhs) +{ + return lhs.m_impl.owner_before(rhs.m_impl) || rhs.m_impl.owner_before(lhs.m_impl); +} + +std::ostream& +operator<<(std::ostream& os, const Key& key) +{ + if (key) { + os << key.getName(); + } + else { + os << "(empty)"; + } + return os; +} + +} // namespace pib + +namespace v2 { + +Name +constructKeyName(const Name& identity, const name::Component& keyId) +{ + Name keyName = identity; + keyName + .append(Certificate::KEY_COMPONENT) + .append(keyId); + return keyName; +} + +bool +isValidKeyName(const Name& keyName) +{ + return (keyName.size() >= Certificate::MIN_KEY_NAME_LENGTH && + keyName.get(-Certificate::MIN_KEY_NAME_LENGTH) == Certificate::KEY_COMPONENT); +} + +Name +extractIdentityFromKeyName(const Name& keyName) +{ + if (!isValidKeyName(keyName)) { + NDN_THROW(std::invalid_argument("Key name `" + keyName.toUri() + "` " + "does not respect the naming conventions")); + } + + return keyName.getPrefix(-Certificate::MIN_KEY_NAME_LENGTH); // trim everything after and including "KEY" +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/pib/key.hpp b/ndn-cxx/security/pib/key.hpp new file mode 100644 index 000000000..584828353 --- /dev/null +++ b/ndn-cxx/security/pib/key.hpp @@ -0,0 +1,223 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_PIB_KEY_HPP +#define NDN_SECURITY_PIB_KEY_HPP + +#include "ndn-cxx/security/pib/certificate-container.hpp" +#include "ndn-cxx/security/security-common.hpp" + +namespace ndn { +namespace security { + +namespace v2 { +class KeyChain; +} // namespace v2 + +namespace pib { + +namespace detail { +class KeyImpl; +} // namespace detail + +/** + * @brief A frontend handle of a key instance + * + * Key is at the second level in PIB's Identity-Key-Certificate hierarchy. A Key has a Name + * (identity + "KEY" + keyId), and contains one or more certificates, one of which is set as + * the default certificate of this key. A certificate can be directly accessed from a Key + * object. + */ +class Key +{ +public: + /** + * @brief Default Constructor + * + * Key created using this default constructor is just a place holder. + * It can obtain an actual instance from Identity::getKey(...). A typical + * usage would be for exception handling: + * + * Key key; + * try { + * key = identity.getKey(...); + * } + * catch (const Pib::Error&) { + * ... + * } + * + * A Key instance created using this constructor is invalid. Calling a + * member method on an invalid Key instance may cause an std::domain_error. + */ + Key(); + + /** + * @brief Create a Key with a backend implementation @p impl. + * + * This method should only be used by KeyContainer. + */ + explicit + Key(weak_ptr impl); + + /** + * @brief Get key name. + */ + const Name& + getName() const; + + /** + * @brief Get the name of the belonging identity. + */ + const Name& + getIdentity() const; + + /** + * @brief Get key type. + */ + KeyType + getKeyType() const; + + /** + * @brief Get public key bits. + */ + const Buffer& + getPublicKey() const; + + /** + * @brief Get a certificate with @p certName + * @throw std::invalid_argument @p certName does not match key name + * @throw Pib::Error the certificate does not exist. + */ + v2::Certificate + getCertificate(const Name& certName) const; + + /** + * @brief Get all certificates for this key. + */ + const CertificateContainer& + getCertificates() const; + + /** + * @brief Get the default certificate for this Key. + * @throw Pib::Error the default certificate does not exist. + */ + const v2::Certificate& + getDefaultCertificate() const; + + /** + * @brief Check if the Key instance is valid. + */ + explicit + operator bool() const; + +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: // write operations should be private + /** + * @brief Add @p certificate. + * @throw std::invalid_argument certificate name does not match key name + * + * If a certificate with the same name (without implicit digest) already exists, overwrite + * the certificate. + */ + void + addCertificate(const v2::Certificate& certificate) const; + + /** + * @brief Remove a certificate with @p certName + * @throw std::invalid_argument @p certName does not match key name + */ + void + removeCertificate(const Name& certName) const; + + /** + * @brief Set an existing certificate with @p certName as the default certificate + * @throw std::invalid_argument @p certName does not match key name + * @throw Pib::Error the certificate does not exist. + * @return the default certificate + */ + const v2::Certificate& + setDefaultCertificate(const Name& certName) const; + + /** + * @brief Add @p certificate and set it as the default certificate of the key + * @throw std::invalid_argument @p certificate does not match key name + * @return the default certificate + */ + const v2::Certificate& + setDefaultCertificate(const v2::Certificate& certificate) const; + +private: + /** + * @brief Check the validity of the instance + * @return a shared_ptr when the instance is valid + * @throw std::domain_error the instance is invalid + */ + shared_ptr + lock() const; + +private: + weak_ptr m_impl; + + friend class v2::KeyChain; + friend bool operator!=(const Key&, const Key&); +}; + +bool +operator!=(const Key& lhs, const Key& rhs); + +inline bool +operator==(const Key& lhs, const Key& rhs) +{ + return !(lhs != rhs); +} + +std::ostream& +operator<<(std::ostream& os, const Key& key); + +} // namespace pib + +using pib::Key; + +namespace v2 { + +/** + * @brief Construct key name based on the appropriate naming conventions + */ +Name +constructKeyName(const Name& identity, const name::Component& keyId); + +/** + * @brief Check if @p keyName follow the naming conventions for the key name + */ +bool +isValidKeyName(const Name& keyName); + +/** + * @brief Extract identity namespace from the key name @p keyName + */ +Name +extractIdentityFromKeyName(const Name& keyName); + +} // namespace v2 + +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_PIB_KEY_HPP diff --git a/ndn-cxx/security/pib/pib-impl.hpp b/ndn-cxx/security/pib/pib-impl.hpp new file mode 100644 index 000000000..7d39ad464 --- /dev/null +++ b/ndn-cxx/security/pib/pib-impl.hpp @@ -0,0 +1,283 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_PIB_PIB_IMPL_HPP +#define NDN_SECURITY_PIB_PIB_IMPL_HPP + +#include "ndn-cxx/security/pib/pib.hpp" +#include "ndn-cxx/security/v2/certificate.hpp" + +#include + +namespace ndn { +namespace security { +namespace pib { + +/** + * @brief Abstract class of PIB implementation + * + * This class defines the interface that an actual PIB (e.g., one based on sqlite3) + * implementation should provide. + */ +class PibImpl : noncopyable +{ +public: + /** + * @brief represents a non-semantic error + * + * A subclass of PibImpl may throw a subclass of this type when + * there's a non-semantic error, such as a storage problem. + */ + class Error : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + }; + +public: + virtual + ~PibImpl() = default; + +public: // TpmLocator management + /** + * @brief Set the corresponding TPM information to @p tpmLocator + * + * This method does not reset contents of the PIB + */ + virtual void + setTpmLocator(const std::string& tpmLocator) = 0; + + /** + * @brief Get TPM Locator + */ + virtual std::string + getTpmLocator() const = 0; + +public: // Identity management + /** + * @brief Check the existence of an identity. + * + * @param identity The name of the identity. + * @return true if the identity exists, otherwise false. + */ + virtual bool + hasIdentity(const Name& identity) const = 0; + + /** + * @brief Add an identity. + * + * If the identity already exists, do nothing. If no default identity has been set, set the + * added one as default identity. + * + * @param identity The name of the identity to add. + */ + virtual void + addIdentity(const Name& identity) = 0; + + /** + * @brief Remove an identity and related keys and certificates. + * + * If the default identity is being removed, no default identity will be selected. If the + * identity does not exist, do nothing. + * + * @param identity The name of the identity to remove. + */ + virtual void + removeIdentity(const Name& identity) = 0; + + /** + * @brief Erasing all certificates, keys, and identities + */ + virtual void + clearIdentities() = 0; + + /** + * @brief Get the name of all the identities + */ + virtual std::set + getIdentities() const = 0; + + /** + * @brief Set an identity with name @p identityName as the default identity. + * + * If @p identityName identity does not exist, it will be created. + * + * @param identityName The name for the default identity. + */ + virtual void + setDefaultIdentity(const Name& identityName) = 0; + + /** + * @brief Get the default identity. + * + * @return The name for the default identity. + * @throw Pib::Error no default identity. + */ + virtual Name + getDefaultIdentity() const = 0; + +public: // Key management + /** + * @brief Check the existence of a key with @p keyName. + * + * @return true if the key exists, otherwise false. Return false if the identity does not exist + */ + virtual bool + hasKey(const Name& keyName) const = 0; + + /** + * @brief Add a key. + * + * If a key with the same name already exists, overwrite the key. If the identity does not + * exist, it will be created. If no default key of the identity has been set, set the added + * one as default key of the identity. If no default identity has been set, @p identity + * becomes the default. + * + * @param identity The name of the belonged identity. + * @param keyName The key name. + * @param key The public key bits. + * @param keyLen The length of the public key. + */ + virtual void + addKey(const Name& identity, const Name& keyName, const uint8_t* key, size_t keyLen) = 0; + + /** + * @brief Remove a key with @p keyName and related certificates + * + * If the key does not exist, do nothing. + */ + virtual void + removeKey(const Name& keyName) = 0; + + /** + * @brief Get the key bits of a key with name @p keyName. + * + * @return key bits + * @throw Pib::Error the key does not exist. + */ + virtual Buffer + getKeyBits(const Name& keyName) const = 0; + + /** + * @brief Get all the key names of an identity with name @p identity + * + * The returned key names can be used to create a KeyContainer. With key name and backend + * implementation, one can create a Key frontend instance. + * + * @return the key name component set. If the identity does not exist, return an empty set. + */ + virtual std::set + getKeysOfIdentity(const Name& identity) const = 0; + + /** + * @brief Set an key with @p keyName as the default key of an identity with name @p identity. + * + * @throw Pib::Error the key does not exist. + */ + virtual void + setDefaultKeyOfIdentity(const Name& identity, const Name& keyName) = 0; + + /** + * @return The name of the default key of an identity with name @p identity. + * + * @throw Pib::Error no default key or the identity does not exist. + */ + virtual Name + getDefaultKeyOfIdentity(const Name& identity) const = 0; + +public: // Certificate Management + /** + * @brief Check the existence of a certificate with name @p certName. + * + * @param certName The name of the certificate. + * @return true if the certificate exists, otherwise false. + */ + virtual bool + hasCertificate(const Name& certName) const = 0; + + /** + * @brief Add a certificate. + * + * If a certificate with the same name (without implicit digest) already exists, overwrite + * the certificate. If the key or identity does not exist, they will be created. If no + * default certificate of the key has been set, set the added one as default certificate of + * the key. If no default key was set for the identity, it will be set as default key for + * the identity. If no default identity was selected, the certificate's identity becomes + * default. + * + * @param certificate The certificate to add. + */ + virtual void + addCertificate(const v2::Certificate& certificate) = 0; + + /** + * @brief Remove a certificate with name @p certName. + * + * If the certificate does not exist, do nothing. + * + * @param certName The name of the certificate. + */ + virtual void + removeCertificate(const Name& certName) = 0; + + /** + * @brief Get a certificate with name @p certName. + * + * @param certName The name of the certificate. + * @return the certificate. + * @throw Pib::Error the certificate does not exist. + */ + virtual v2::Certificate + getCertificate(const Name& certName) const = 0; + + /** + * @brief Get a list of certificate names of a key with id @p keyName. + * + * The returned certificate names can be used to create a CertificateContainer. With + * certificate name and backend implementation, one can obtain the certificate. + * + * @return The certificate name set. If the key does not exist, return an empty set. + */ + virtual std::set + getCertificatesOfKey(const Name& keyName) const = 0; + + /** + * @brief Set a cert with name @p certName as the default of a key with @p keyName. + * + * @throw Pib::Error the certificate with name @p certName does not exist. + */ + virtual void + setDefaultCertificateOfKey(const Name& keyName, const Name& certName) = 0; + + /** + * @return Get the default certificate of a key with @p keyName. + * + * @throw Pib::Error the default certificate does not exist. + */ + virtual v2::Certificate + getDefaultCertificateOfKey(const Name& keyName) const = 0; +}; + +} // namespace pib +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_PIB_PIB_IMPL_HPP diff --git a/ndn-cxx/security/pib/pib.cpp b/ndn-cxx/security/pib/pib.cpp new file mode 100644 index 000000000..a67bda51c --- /dev/null +++ b/ndn-cxx/security/pib/pib.cpp @@ -0,0 +1,146 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/pib.hpp" +#include "ndn-cxx/security/pib/pib-impl.hpp" +#include "ndn-cxx/util/logger.hpp" + +namespace ndn { +namespace security { +namespace pib { + +NDN_LOG_INIT(ndn.security.pib.Pib); + +Pib::Pib(const std::string& scheme, const std::string& location, shared_ptr impl) + : m_scheme(scheme) + , m_location(location) + , m_isDefaultIdentityLoaded(false) + , m_identities(impl) + , m_impl(std::move(impl)) +{ + BOOST_ASSERT(m_impl != nullptr); +} + +Pib::~Pib() = default; + +std::string +Pib::getPibLocator() const +{ + return m_scheme + ":" + m_location; +} + +void +Pib::setTpmLocator(const std::string& tpmLocator) +{ + if (tpmLocator == m_impl->getTpmLocator()) { + return; + } + reset(); + m_impl->setTpmLocator(tpmLocator); +} + +std::string +Pib::getTpmLocator() const +{ + std::string tpmLocator = m_impl->getTpmLocator(); + if (tpmLocator.empty()) { + NDN_THROW(Pib::Error("TPM info does not exist")); + } + return tpmLocator; +} + +void +Pib::reset() +{ + m_impl->clearIdentities(); + m_impl->setTpmLocator(""); + m_isDefaultIdentityLoaded = false; + m_identities.reset(); +} + +Identity +Pib::addIdentity(const Name& identity) +{ + BOOST_ASSERT(m_identities.isConsistent()); + + return m_identities.add(identity); +} + +void +Pib::removeIdentity(const Name& identity) +{ + BOOST_ASSERT(m_identities.isConsistent()); + + if (m_isDefaultIdentityLoaded && m_defaultIdentity.getName() == identity) { + m_isDefaultIdentityLoaded = false; + } + + m_identities.remove(identity); +} + +Identity +Pib::getIdentity(const Name& identity) const +{ + BOOST_ASSERT(m_identities.isConsistent()); + + return m_identities.get(identity); +} + +const IdentityContainer& +Pib::getIdentities() const +{ + BOOST_ASSERT(m_identities.isConsistent()); + + return m_identities; +} + +const Identity& +Pib::setDefaultIdentity(const Name& identityName) +{ + BOOST_ASSERT(m_identities.isConsistent()); + + m_defaultIdentity = m_identities.add(identityName); + m_isDefaultIdentityLoaded = true; + NDN_LOG_DEBUG("Default identity is set to " << identityName); + + m_impl->setDefaultIdentity(identityName); + return m_defaultIdentity; +} + +const Identity& +Pib::getDefaultIdentity() const +{ + BOOST_ASSERT(m_identities.isConsistent()); + + if (!m_isDefaultIdentityLoaded) { + m_defaultIdentity = m_identities.get(m_impl->getDefaultIdentity()); + m_isDefaultIdentityLoaded = true; + NDN_LOG_DEBUG("Default identity is " << m_defaultIdentity.getName()); + } + + BOOST_ASSERT(m_impl->getDefaultIdentity() == m_defaultIdentity.getName()); + + return m_defaultIdentity; +} + +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/pib/pib.hpp b/ndn-cxx/security/pib/pib.hpp new file mode 100644 index 000000000..26862be0d --- /dev/null +++ b/ndn-cxx/security/pib/pib.hpp @@ -0,0 +1,187 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_PIB_PIB_HPP +#define NDN_SECURITY_PIB_PIB_HPP + +#include "ndn-cxx/security/pib/identity-container.hpp" + +namespace ndn { +namespace security { +namespace pib { + +class PibImpl; + +/** + * @brief represents the PIB + * + * The PIB (Public Information Base) stores the public portion of a user's cryptography keys. + * The format and location of stored information is indicated by the PibLocator. + * The PIB is designed to work with a TPM (Trusted Platform Module) which stores private keys. + * There is a one-to-one association between PIB and TPM, and therefore the TpmLocator is recorded + * by the PIB to enforce this association and prevent one from operating on mismatched PIB and TPM. + * + * Information in the PIB is organized in a hierarchy of Identity-Key-Certificate. At the top level, + * the Pib class provides access to identities, and allows setting a default identity. Properties of + * an identity can be accessed after obtaining an Identity object. + * + * @note Pib instance is created and managed only by v2::KeyChain. v2::KeyChain::getPib() + * returns a const reference to the managed Pib instance, through which it is possible to + * retrieve information about identities, keys, and certificates. + * + * @throw PibImpl::Error when underlying implementation has non-semantic error. + */ +class Pib : noncopyable +{ +public: + /// @brief represents a semantic error + class Error : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + }; + +public: + ~Pib(); + + /** + * @brief return the scheme of the PIB Locator + */ + std::string + getScheme() const + { + return m_scheme; + } + + /** + * @brief Get PIB Locator + */ + std::string + getPibLocator() const; + + /** + * @brief Set the corresponding TPM information to @p tpmLocator. + * + * If the provided @p tpmLocator is different from the existing one, PIB will be reset. + * Otherwise, nothing will be changed. + */ + void + setTpmLocator(const std::string& tpmLocator); + + /** + * @brief Get TPM Locator + * @throws Error if TPM locator is empty + */ + std::string + getTpmLocator() const; + + /** + * @brief Reset content in PIB, including reset of the TPM locator + */ + void + reset(); + + /** + * @brief Get an identity with name @p identityName. + * @throw Pib::Error if the identity does not exist. + */ + Identity + getIdentity(const Name& identityName) const; + + /** + * @brief Get all the identities + */ + const IdentityContainer& + getIdentities() const; + + /** + * @brief Get the default identity. + * @throw Pib::Error if no default identity exists. + */ + const Identity& + getDefaultIdentity() const; + +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: // write operations should be private + /** + * @brief Create a Pib instance + * + * @param scheme The scheme for the Pib + * @param location The location for the Pib + * @param impl The backend implementation + */ + Pib(const std::string& scheme, const std::string& location, shared_ptr impl); + + /** + * @brief Add an identity. + * + * If no default identity is set before, the new identity will be set as the default identity + * + * @return handle of the added identity. + */ + Identity + addIdentity(const Name& identity); + + /** + * @brief Remove an identity. + * + * If the default identity is being removed, no default identity will be selected. + */ + void + removeIdentity(const Name& identity); + + /** + * @brief Set an identity as the default identity. + * + * Create the identity if it does not exist. + * + * @return handle of the default identity + */ + const Identity& + setDefaultIdentity(const Name& identity); + + shared_ptr + getImpl() + { + return m_impl; + } + +protected: + std::string m_scheme; + std::string m_location; + + mutable bool m_isDefaultIdentityLoaded; + mutable Identity m_defaultIdentity; + + IdentityContainer m_identities; + + shared_ptr m_impl; + + friend class v2::KeyChain; +}; + +} // namespace pib + +using pib::Pib; + +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_PIB_PIB_HPP diff --git a/ndn-cxx/security/safe-bag.cpp b/ndn-cxx/security/safe-bag.cpp new file mode 100644 index 000000000..af7067c7c --- /dev/null +++ b/ndn-cxx/security/safe-bag.cpp @@ -0,0 +1,130 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Zhiyi Zhang + */ + +#include "ndn-cxx/security/safe-bag.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/encoding/tlv-security.hpp" +#include "ndn-cxx/util/concepts.hpp" + +namespace ndn { +namespace security { + +BOOST_CONCEPT_ASSERT((WireEncodable)); +BOOST_CONCEPT_ASSERT((WireDecodable)); + +SafeBag::SafeBag() = default; + +SafeBag::SafeBag(const Block& wire) +{ + this->wireDecode(wire); +} + +SafeBag::SafeBag(const Data& certificate, + const Buffer& encryptedKeyBag) + : m_certificate(certificate) + , m_encryptedKeyBag(encryptedKeyBag) +{ +} + +SafeBag::SafeBag(const Data& certificate, + const uint8_t* encryptedKey, + size_t encryptedKeyLen) + : m_certificate(certificate) + , m_encryptedKeyBag(encryptedKey, encryptedKeyLen) +{ +} + +///////////////////////////////////////////////////// encode & decode + +template +size_t +SafeBag::wireEncode(EncodingImpl& encoder) const +{ + size_t totalLength = 0; + + // EncryptedKeyBag + totalLength += encoder.prependByteArrayBlock(tlv::security::EncryptedKeyBag, + m_encryptedKeyBag.data(), + m_encryptedKeyBag.size()); + + // Certificate + totalLength += this->m_certificate.wireEncode(encoder); + + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::security::SafeBag); + + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(SafeBag); + +const Block& +SafeBag::wireEncode() const +{ + EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator); + + EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer); + + m_wire = buffer.block(); + return m_wire; +} + +void +SafeBag::wireDecode(const Block& wire) +{ + if (wire.type() != tlv::security::SafeBag) { + NDN_THROW(tlv::Error("SafeBag", wire.type())); + } + + m_wire = wire; + m_wire.parse(); + auto it = m_wire.elements_begin(); + + // Certificate must be the first part + if (it != m_wire.elements_end()) { + m_certificate.wireDecode(*it); + it++; + } + else { + NDN_THROW(tlv::Error("Unexpected TLV structure when decoding Certificate")); + } + + // EncryptedKeyBag + if (it != m_wire.elements_end() && it->type() == tlv::security::EncryptedKeyBag) { + m_encryptedKeyBag = Buffer(it->value(), it->value_size()); + it++; + } + else { + NDN_THROW(tlv::Error("Unexpected TLV structure when decoding EncryptedKeyBag")); + } + + // Check if end + if (it != m_wire.elements_end()) { + NDN_THROW(tlv::Error("Unexpected TLV element at the end of SafeBag")); + } +} + +} // namespace security +} // namespace ndn diff --git a/src/security/safe-bag.hpp b/ndn-cxx/security/safe-bag.hpp similarity index 91% rename from src/security/safe-bag.hpp rename to ndn-cxx/security/safe-bag.hpp index 12555c9c5..71877d916 100644 --- a/src/security/safe-bag.hpp +++ b/ndn-cxx/security/safe-bag.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -20,15 +20,14 @@ * * @author Zhiyi Zhang */ + #ifndef NDN_CXX_SECURITY_SAFE_BAG_HPP #define NDN_CXX_SECURITY_SAFE_BAG_HPP -#include "../common.hpp" -#include "../data.hpp" -#include "../encoding/buffer.hpp" -#include "../encoding/encoder.hpp" -#include "../encoding/encoding-buffer.hpp" -#include "security-common.hpp" +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/encoding/buffer.hpp" +#include "ndn-cxx/security/security-common.hpp" namespace ndn { namespace security { @@ -115,6 +114,8 @@ class SafeBag mutable Block m_wire; }; +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(SafeBag); + } // namespace security } // namespace ndn diff --git a/ndn-cxx/security/security-common.cpp b/ndn-cxx/security/security-common.cpp new file mode 100644 index 000000000..abf0b328c --- /dev/null +++ b/ndn-cxx/security/security-common.cpp @@ -0,0 +1,114 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/security-common.hpp" + +#include + +namespace ndn { + +std::ostream& +operator<<(std::ostream& os, KeyIdType keyIdType) +{ + switch (keyIdType) { + case KeyIdType::USER_SPECIFIED: + return os << "USER-SPECIFIED"; + case KeyIdType::SHA256: + return os << "SHA256"; + case KeyIdType::RANDOM: + return os << "RANDOM"; + } + return os << to_underlying(keyIdType); +} + +std::ostream& +operator<<(std::ostream& os, KeyType keyType) +{ + switch (keyType) { + case KeyType::NONE: + return os << "NONE"; + case KeyType::RSA: + return os << "RSA"; + case KeyType::EC: + return os << "EC"; + case KeyType::AES: + return os << "AES"; + case KeyType::HMAC: + return os << "HMAC"; + } + return os << to_underlying(keyType); +} + +std::ostream& +operator<<(std::ostream& os, DigestAlgorithm algorithm) +{ + switch (algorithm) { + case DigestAlgorithm::NONE: + return os << "NONE"; + case DigestAlgorithm::SHA224: + return os << "SHA224"; + case DigestAlgorithm::SHA256: + return os << "SHA256"; + case DigestAlgorithm::SHA384: + return os << "SHA384"; + case DigestAlgorithm::SHA512: + return os << "SHA512"; + case DigestAlgorithm::BLAKE2B_512: + return os << "BLAKE2b-512"; + case DigestAlgorithm::BLAKE2S_256: + return os << "BLAKE2s-256"; + case DigestAlgorithm::SHA3_224: + return os << "SHA3-224"; + case DigestAlgorithm::SHA3_256: + return os << "SHA3-256"; + case DigestAlgorithm::SHA3_384: + return os << "SHA3-384"; + case DigestAlgorithm::SHA3_512: + return os << "SHA3-512"; + } + return os << to_underlying(algorithm); +} + +std::ostream& +operator<<(std::ostream& os, BlockCipherAlgorithm algorithm) +{ + switch (algorithm) { + case BlockCipherAlgorithm::NONE: + return os << "NONE"; + case BlockCipherAlgorithm::AES_CBC: + return os << "AES-CBC"; + } + return os << to_underlying(algorithm); +} + +std::ostream& +operator<<(std::ostream& os, CipherOperator op) +{ + switch (op) { + case CipherOperator::DECRYPT: + return os << "DECRYPT"; + case CipherOperator::ENCRYPT: + return os << "ENCRYPT"; + } + return os << to_underlying(op); +} + +} // namespace ndn diff --git a/ndn-cxx/security/security-common.hpp b/ndn-cxx/security/security-common.hpp new file mode 100644 index 000000000..1484cbcbf --- /dev/null +++ b/ndn-cxx/security/security-common.hpp @@ -0,0 +1,131 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_SECURITY_COMMON_HPP +#define NDN_SECURITY_SECURITY_COMMON_HPP + +#include "ndn-cxx/detail/common.hpp" + +namespace ndn { + +namespace signed_interest { + +const ssize_t POS_SIG_VALUE = -1; +const ssize_t POS_SIG_INFO = -2; + +/** \brief minimal number of components for Signed Interest + * \sa https://redmine.named-data.net/projects/ndn-cxx/wiki/SignedInterest + */ +const size_t MIN_SIZE = 2; + +} // namespace signed_interest + +namespace command_interest { + +using signed_interest::POS_SIG_VALUE; +using signed_interest::POS_SIG_INFO; +const ssize_t POS_RANDOM_VAL = -3; +const ssize_t POS_TIMESTAMP = -4; + +/** \brief minimal number of components for Command Interest + * \sa https://redmine.named-data.net/projects/ndn-cxx/wiki/CommandInterest + */ +const size_t MIN_SIZE = 4; + +} // namespace command_interest + +/** + * @brief The type of KeyId component in a key name. + */ +enum class KeyIdType { + /** + * @brief User-specified key id. + * + * It is the user's responsibility to ensure the uniqueness of the key names. + */ + USER_SPECIFIED = 0, + /** + * @brief Use the SHA256 hash of the public key as key id. + * + * This KeyIdType guarantees the uniqueness of the key names. + */ + SHA256 = 1, + /** + * @brief Use a 64-bit random number as key id. + * + * This KeyIdType provides uniqueness (with very high probability) of the key names. + */ + RANDOM = 2, +}; + +std::ostream& +operator<<(std::ostream& os, KeyIdType keyIdType); + +/** + * @brief The type of a cryptographic key. + */ +enum class KeyType { + NONE = 0, ///< Unknown or unsupported key type + RSA, ///< RSA key, supports sign/verify and encrypt/decrypt operations + EC, ///< Elliptic Curve key (e.g. for ECDSA), supports sign/verify operations + AES, ///< AES key, supports encrypt/decrypt operations + HMAC, ///< HMAC key, supports sign/verify operations +}; + +std::ostream& +operator<<(std::ostream& os, KeyType keyType); + +enum class DigestAlgorithm { + NONE = 0, + SHA224, + SHA256, + SHA384, + SHA512, + BLAKE2B_512, + BLAKE2S_256, + SHA3_224, + SHA3_256, + SHA3_384, + SHA3_512, +}; + +std::ostream& +operator<<(std::ostream& os, DigestAlgorithm algorithm); + +enum class BlockCipherAlgorithm { + NONE, + AES_CBC, +}; + +std::ostream& +operator<<(std::ostream& os, BlockCipherAlgorithm algorithm); + +enum class CipherOperator { + DECRYPT, + ENCRYPT, +}; + +std::ostream& +operator<<(std::ostream& os, CipherOperator op); + +} // namespace ndn + +#endif // NDN_SECURITY_SECURITY_COMMON_HPP diff --git a/src/security/signature-sha256-with-ecdsa.cpp b/ndn-cxx/security/signature-sha256-with-ecdsa.cpp similarity index 78% rename from src/security/signature-sha256-with-ecdsa.cpp rename to ndn-cxx/security/signature-sha256-with-ecdsa.cpp index 72a5acd9a..4c9251430 100644 --- a/src/security/signature-sha256-with-ecdsa.cpp +++ b/ndn-cxx/security/signature-sha256-with-ecdsa.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,7 +19,7 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "signature-sha256-with-ecdsa.hpp" +#include "ndn-cxx/security/signature-sha256-with-ecdsa.hpp" namespace ndn { @@ -32,17 +32,17 @@ SignatureSha256WithEcdsa::SignatureSha256WithEcdsa(const Signature& signature) : Signature(signature) { if (getType() != tlv::SignatureSha256WithEcdsa) - BOOST_THROW_EXCEPTION(Error("Incorrect signature type")); + NDN_THROW(Error("Cannot construct Sha256WithEcdsa from SignatureType " + to_string(getType()))); if (!hasKeyLocator()) { - BOOST_THROW_EXCEPTION(Error("KeyLocator is missing")); + NDN_THROW(Error("KeyLocator is missing in Sha256WithEcdsa signature")); } } void SignatureSha256WithEcdsa::unsetKeyLocator() { - BOOST_THROW_EXCEPTION(Error("KeyLocator cannot be reset for SignatureSha256WithEcdsa")); + NDN_THROW(Error("KeyLocator cannot be unset in Sha256WithEcdsa signature")); } } // namespace ndn diff --git a/ndn-cxx/security/signature-sha256-with-ecdsa.hpp b/ndn-cxx/security/signature-sha256-with-ecdsa.hpp new file mode 100644 index 000000000..5428825f4 --- /dev/null +++ b/ndn-cxx/security/signature-sha256-with-ecdsa.hpp @@ -0,0 +1,57 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_SIGNATURE_SHA256_WITH_ECDSA_HPP +#define NDN_SECURITY_SIGNATURE_SHA256_WITH_ECDSA_HPP + +#include "ndn-cxx/signature.hpp" + +namespace ndn { + +/** @brief Represents a signature of Sha256WithEcdsa type + * + * This signature type provides integrity and provenance protection using an ECDSA signature over a + * SHA-256 digest. + */ +class SignatureSha256WithEcdsa : public Signature +{ +public: + /** @brief Create Sha256WithEcdsa signature with specified KeyLocator + */ + explicit + SignatureSha256WithEcdsa(const KeyLocator& keyLocator = KeyLocator()); + + /** @brief Convert base Signature to Sha256WithEcdsa signature + * @throw Signature::Error SignatureType is not Sha256WithEcdsa + */ + explicit + SignatureSha256WithEcdsa(const Signature& signature); + +private: + /** @brief Prevent unsetting KeyLocator + */ + void + unsetKeyLocator(); +}; + +} // namespace ndn + +#endif // NDN_SECURITY_SIGNATURE_SHA256_WITH_ECDSA_HPP diff --git a/src/security/signature-sha256-with-rsa.cpp b/ndn-cxx/security/signature-sha256-with-rsa.cpp similarity index 78% rename from src/security/signature-sha256-with-rsa.cpp rename to ndn-cxx/security/signature-sha256-with-rsa.cpp index 72f5c8bc9..5fd1aeddd 100644 --- a/src/security/signature-sha256-with-rsa.cpp +++ b/ndn-cxx/security/signature-sha256-with-rsa.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,7 +19,7 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "signature-sha256-with-rsa.hpp" +#include "ndn-cxx/security/signature-sha256-with-rsa.hpp" namespace ndn { @@ -32,17 +32,17 @@ SignatureSha256WithRsa::SignatureSha256WithRsa(const Signature& signature) : Signature(signature) { if (getType() != tlv::SignatureSha256WithRsa) - BOOST_THROW_EXCEPTION(Error("Incorrect signature type")); + NDN_THROW(Error("Cannot construct Sha256WithRsa from SignatureType " + to_string(getType()))); if (!hasKeyLocator()) { - BOOST_THROW_EXCEPTION(Error("KeyLocator is missing")); + NDN_THROW(Error("KeyLocator is missing in Sha256WithRsa signature")); } } void SignatureSha256WithRsa::unsetKeyLocator() { - BOOST_THROW_EXCEPTION(Error("KeyLocator cannot be reset for SignatureSha256WithRsa")); + NDN_THROW(Error("KeyLocator cannot be unset in Sha256WithRsa signature")); } } // namespace ndn diff --git a/ndn-cxx/security/signature-sha256-with-rsa.hpp b/ndn-cxx/security/signature-sha256-with-rsa.hpp new file mode 100644 index 000000000..da7929228 --- /dev/null +++ b/ndn-cxx/security/signature-sha256-with-rsa.hpp @@ -0,0 +1,57 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_SIGNATURE_SHA256_WITH_RSA_HPP +#define NDN_SECURITY_SIGNATURE_SHA256_WITH_RSA_HPP + +#include "ndn-cxx/signature.hpp" + +namespace ndn { + +/** @brief Represents a signature of Sha256WithRsa type + * + * This signature type provides integrity and provenance protection using a RSA signature over a + * SHA-256 digest. + */ +class SignatureSha256WithRsa : public Signature +{ +public: + /** @brief Create Sha256WithRsa signature with specified KeyLocator + */ + explicit + SignatureSha256WithRsa(const KeyLocator& keyLocator = KeyLocator()); + + /** @brief Convert base Signature to Sha256WithRsa signature + * @throw Signature::Error SignatureType is not Sha256WithRsa + */ + explicit + SignatureSha256WithRsa(const Signature& signature); + +private: + /** @brief Prevent unsetting KeyLocator + */ + void + unsetKeyLocator(); +}; + +} // namespace ndn + +#endif // NDN_SECURITY_SIGNATURE_SHA256_WITH_RSA_HPP diff --git a/ndn-cxx/security/signing-helpers.cpp b/ndn-cxx/security/signing-helpers.cpp new file mode 100644 index 000000000..37851fa24 --- /dev/null +++ b/ndn-cxx/security/signing-helpers.cpp @@ -0,0 +1,70 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/signing-helpers.hpp" + +namespace ndn { +namespace security { + +SigningInfo +signingByIdentity(const Name& identityName) +{ + return SigningInfo(SigningInfo::SIGNER_TYPE_ID, identityName); +} + +SigningInfo +signingByIdentity(const Identity& identity) +{ + return SigningInfo(identity); +} + +SigningInfo +signingByKey(const Name& keyName) +{ + return SigningInfo(SigningInfo::SIGNER_TYPE_KEY, keyName); +} + +SigningInfo +signingByKey(const Key& key) +{ + return SigningInfo(key); +} + +SigningInfo +signingByCertificate(const Name& certName) +{ + return SigningInfo(SigningInfo::SIGNER_TYPE_CERT, certName); +} + +SigningInfo +signingByCertificate(const v2::Certificate& cert) +{ + return SigningInfo(SigningInfo::SIGNER_TYPE_CERT, cert.getName()); +} + +SigningInfo +signingWithSha256() +{ + return SigningInfo(SigningInfo::SIGNER_TYPE_SHA256); +} + +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/signing-helpers.hpp b/ndn-cxx/security/signing-helpers.hpp new file mode 100644 index 000000000..6be8ec8f2 --- /dev/null +++ b/ndn-cxx/security/signing-helpers.hpp @@ -0,0 +1,82 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_SECURITY_SIGNING_HELPERS_HPP +#define NDN_CXX_SECURITY_SIGNING_HELPERS_HPP + +#include "ndn-cxx/detail/common.hpp" +#include "ndn-cxx/security/signing-info.hpp" + +namespace ndn { +namespace security { + +/** + * \return a SigningInfo for signing with an identity + */ +SigningInfo +signingByIdentity(const Name& identityName); + +/** + * \return a SigningInfo for signing with an identity + */ +SigningInfo +signingByIdentity(const Identity& identity); + +/** + * \return a SigningInfo for signing with a key + */ +SigningInfo +signingByKey(const Name& keyName); + +/** + * \return a SigningInfo for signing with a key + */ +SigningInfo +signingByKey(const Key& key); + +/** + * \return a SigningInfo for signing with a certificate + */ +SigningInfo +signingByCertificate(const Name& certName); + +/** + * \return a SigningInfo for signing with a certificate + */ +SigningInfo +signingByCertificate(const v2::Certificate& cert); + +/** + * \return a SigningInfo for signing with Sha256 + */ +SigningInfo +signingWithSha256(); + +} // namespace security + +using security::signingByIdentity; +using security::signingByKey; +using security::signingByCertificate; +using security::signingWithSha256; + +} // namespace ndn + +#endif // NDN_CXX_SECURITY_SIGNING_HELPERS_HPP diff --git a/ndn-cxx/security/signing-info.cpp b/ndn-cxx/security/signing-info.cpp new file mode 100644 index 000000000..14d931265 --- /dev/null +++ b/ndn-cxx/security/signing-info.cpp @@ -0,0 +1,222 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/signing-info.hpp" + +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/transform/base64-decode.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/digest-filter.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" + +namespace ndn { +namespace security { + +const Name& +SigningInfo::getEmptyName() +{ + static Name emptyName; + return emptyName; +} + +const SignatureInfo& +SigningInfo::getEmptySignatureInfo() +{ + static SignatureInfo emptySignatureInfo; + return emptySignatureInfo; +} + +const Name& +SigningInfo::getDigestSha256Identity() +{ + static Name digestSha256Identity("/localhost/identity/digest-sha256"); + return digestSha256Identity; +} + +const Name& +SigningInfo::getHmacIdentity() +{ + static Name hmacIdentity("/localhost/identity/hmac"); + return hmacIdentity; +} + +SigningInfo::SigningInfo(SignerType signerType, + const Name& signerName, + const SignatureInfo& signatureInfo) + : m_type(signerType) + , m_name(signerName) + , m_digestAlgorithm(DigestAlgorithm::SHA256) + , m_info(signatureInfo) +{ + BOOST_ASSERT(signerType >= SIGNER_TYPE_NULL && signerType <= SIGNER_TYPE_HMAC); +} + +SigningInfo::SigningInfo(const Identity& identity) + : SigningInfo(SIGNER_TYPE_NULL) +{ + this->setPibIdentity(identity); +} + +SigningInfo::SigningInfo(const Key& key) + : SigningInfo(SIGNER_TYPE_NULL) +{ + this->setPibKey(key); +} + +SigningInfo::SigningInfo(const std::string& signingStr) + : SigningInfo(SIGNER_TYPE_NULL) +{ + if (signingStr.empty()) { + return; + } + + size_t pos = signingStr.find(':'); + if (pos == std::string::npos) { + NDN_THROW(std::invalid_argument("Invalid signing string cannot represent SigningInfo")); + } + + std::string scheme = signingStr.substr(0, pos); + std::string nameArg = signingStr.substr(pos + 1); + + if (scheme == "id") { + if (nameArg == getDigestSha256Identity().toUri()) { + setSha256Signing(); + } + else { + setSigningIdentity(nameArg); + } + } + else if (scheme == "key") { + setSigningKeyName(nameArg); + } + else if (scheme == "cert") { + setSigningCertName(nameArg); + } + else if (scheme == "hmac-sha256") { + setSigningHmacKey(nameArg); + setDigestAlgorithm(DigestAlgorithm::SHA256); + } + else { + NDN_THROW(std::invalid_argument("Invalid signing string scheme")); + } +} + +SigningInfo& +SigningInfo::setSigningIdentity(const Name& identity) +{ + m_type = SIGNER_TYPE_ID; + m_name = identity; + m_identity = Identity(); + return *this; +} + +SigningInfo& +SigningInfo::setSigningKeyName(const Name& keyName) +{ + m_type = SIGNER_TYPE_KEY; + m_name = keyName; + m_key = Key(); + return *this; +} + +SigningInfo& +SigningInfo::setSigningCertName(const Name& certificateName) +{ + m_type = SIGNER_TYPE_CERT; + m_name = certificateName; + return *this; +} + +SigningInfo& +SigningInfo::setSigningHmacKey(const std::string& hmacKey) +{ + m_type = SIGNER_TYPE_HMAC; + + OBufferStream os; + transform::bufferSource(hmacKey) >> + transform::base64Decode(false) >> + transform::streamSink(os); + m_hmacKey = make_shared(); + m_hmacKey->loadRaw(KeyType::HMAC, os.buf()->data(), os.buf()->size()); + + // generate key name + m_name = getHmacIdentity(); + m_name.append(name::Component(m_hmacKey->getKeyDigest(DigestAlgorithm::SHA256))); + + return *this; +} + +SigningInfo& +SigningInfo::setSha256Signing() +{ + m_type = SIGNER_TYPE_SHA256; + m_name.clear(); + return *this; +} + +SigningInfo& +SigningInfo::setPibIdentity(const Identity& identity) +{ + m_type = SIGNER_TYPE_ID; + m_name = identity ? identity.getName() : Name(); + m_identity = identity; + return *this; +} + +SigningInfo& +SigningInfo::setPibKey(const Key& key) +{ + m_type = SIGNER_TYPE_KEY; + m_name = key ? key.getName() : Name(); + m_key = key; + return *this; +} + +SigningInfo& +SigningInfo::setSignatureInfo(const SignatureInfo& signatureInfo) +{ + m_info = signatureInfo; + return *this; +} + +std::ostream& +operator<<(std::ostream& os, const SigningInfo& si) +{ + switch (si.getSignerType()) { + case SigningInfo::SIGNER_TYPE_NULL: + return os; + case SigningInfo::SIGNER_TYPE_ID: + return os << "id:" << si.getSignerName(); + case SigningInfo::SIGNER_TYPE_KEY: + return os << "key:" << si.getSignerName(); + case SigningInfo::SIGNER_TYPE_CERT: + return os << "cert:" << si.getSignerName(); + case SigningInfo::SIGNER_TYPE_SHA256: + return os << "id:" << SigningInfo::getDigestSha256Identity(); + case SigningInfo::SIGNER_TYPE_HMAC: + return os << "id:" << si.getSignerName(); + } + NDN_THROW(std::invalid_argument("Unknown signer type")); + return os; +} + +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/signing-info.hpp b/ndn-cxx/security/signing-info.hpp new file mode 100644 index 000000000..90894294f --- /dev/null +++ b/ndn-cxx/security/signing-info.hpp @@ -0,0 +1,293 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_SIGNING_INFO_HPP +#define NDN_SECURITY_SIGNING_INFO_HPP + +#include "ndn-cxx/name.hpp" +#include "ndn-cxx/signature-info.hpp" +#include "ndn-cxx/security/pib/identity.hpp" +#include "ndn-cxx/security/pib/key.hpp" +#include "ndn-cxx/security/security-common.hpp" +#include "ndn-cxx/security/transform/private-key.hpp" + +namespace ndn { +namespace security { + +/** + * @brief Signing parameters passed to KeyChain + * + * A SigningInfo is invalid if the specified identity/key/certificate does not exist, + * or the PIB Identity or Key instance is not valid. + */ +class SigningInfo +{ +public: + class Error : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + }; + + enum SignerType { + /// No signer is specified, use default setting or follow the trust schema. + SIGNER_TYPE_NULL = 0, + /// Signer is an identity, use its default key and default certificate. + SIGNER_TYPE_ID = 1, + /// Signer is a key, use its default certificate. + SIGNER_TYPE_KEY = 2, + /// Signer is a certificate, use it directly. + SIGNER_TYPE_CERT = 3, + /// Use a SHA-256 digest only, no signer needs to be specified. + SIGNER_TYPE_SHA256 = 4, + /// Signer is a HMAC key. + SIGNER_TYPE_HMAC = 5, + }; + +public: + /** + * @brief Constructor. + * + * @param signerType The type of signer + * @param signerName The name of signer; interpretation differs per signerType + * @param signatureInfo A semi-prepared SignatureInfo which contains other information except + * SignatureType and KeyLocator. If SignatureType and KeyLocator are + * specified, they may be overwritten by KeyChain. + */ + explicit + SigningInfo(SignerType signerType = SIGNER_TYPE_NULL, + const Name& signerName = getEmptyName(), + const SignatureInfo& signatureInfo = getEmptySignatureInfo()); + + /** + * @brief Construct from a PIB identity. + */ + explicit + SigningInfo(const Identity& identity); + + /** + * @brief Construct from a PIB key. + */ + explicit + SigningInfo(const Key& key); + + /** + * @brief Construct SigningInfo from its string representation. + * + * @param signingStr The representative signing string for SigningInfo signing method + * + * Syntax of the representative string is as follows: + * - default signing: "" (empty string) + * - sign with the default certificate of the default key of an identity: `id:/` + * - sign with the default certificate of a specific key: `key://ksk-1` + * - sign with a specific certificate: `cert://KEY/ksk-1/ID-CERT/%FD%01` + * - sign with HMAC-SHA-256: `hmac-sha256:` + * - sign with SHA-256 (digest only): `id:/localhost/identity/digest-sha256` + */ + explicit + SigningInfo(const std::string& signingStr); + + /** + * @brief Set signer as an identity with name @p identity + * @post Change the signerType to SIGNER_TYPE_ID + */ + SigningInfo& + setSigningIdentity(const Name& identity); + + /** + * @brief Set signer as a key with name @p keyName + * @post Change the signerType to SIGNER_TYPE_KEY + */ + SigningInfo& + setSigningKeyName(const Name& keyName); + + /** + * @brief Set signer as a certificate with name @p certificateName + * @post Change the signerType to SIGNER_TYPE_CERT + */ + SigningInfo& + setSigningCertName(const Name& certificateName); + + /** + * @brief Set signer to a base64-encoded HMAC key + * @post Change the signerType to SIGNER_TYPE_HMAC + */ + SigningInfo& + setSigningHmacKey(const std::string& hmacKey); + + /** + * @brief Set SHA-256 as the signing method + * @post Reset signerName, also change the signerType to SIGNER_TYPE_SHA256 + */ + SigningInfo& + setSha256Signing(); + + /** + * @brief Set signer as a PIB identity handler @p identity + * @post Change the signerType to SIGNER_TYPE_ID + */ + SigningInfo& + setPibIdentity(const Identity& identity); + + /** + * @brief Set signer as a PIB key handler @p key + * @post Change the signerType to SIGNER_TYPE_KEY + */ + SigningInfo& + setPibKey(const Key& key); + + /** + * @return Type of the signer + */ + SignerType + getSignerType() const + { + return m_type; + } + + /** + * @return Name of signer; interpretation differs per signerType + */ + const Name& + getSignerName() const + { + return m_name; + } + + /** + * @pre signerType must be SIGNER_TYPE_ID + * @return the identity handler of signer, or Identity() if getSignerName() should be used + * to find the identity + */ + const Identity& + getPibIdentity() const + { + BOOST_ASSERT(m_type == SIGNER_TYPE_ID); + return m_identity; + } + + /** + * @pre signerType must be SIGNER_TYPE_KEY + * @return the key handler of signer, or Key() if getSignerName() should be used to find the key + */ + const Key& + getPibKey() const + { + BOOST_ASSERT(m_type == SIGNER_TYPE_KEY); + return m_key; + } + + shared_ptr + getHmacKey() const + { + BOOST_ASSERT(m_type == SIGNER_TYPE_HMAC); + return m_hmacKey; + } + + /** + * @brief Set the digest algorithm for signing operations + */ + SigningInfo& + setDigestAlgorithm(const DigestAlgorithm& algorithm) + { + m_digestAlgorithm = algorithm; + return *this; + } + + /** + * @return The digest algorithm for signing operations + */ + DigestAlgorithm + getDigestAlgorithm() const + { + return m_digestAlgorithm; + } + + /** + * @brief Set a semi-prepared SignatureInfo; + */ + SigningInfo& + setSignatureInfo(const SignatureInfo& signatureInfo); + + /** + * @return Semi-prepared SignatureInfo + */ + const SignatureInfo& + getSignatureInfo() const + { + return m_info; + } + +public: + static const Name& + getEmptyName(); + + static const SignatureInfo& + getEmptySignatureInfo(); + + /** + * @brief A localhost identity to indicate that the signature is generated using SHA-256. + */ + static const Name& + getDigestSha256Identity(); + + /** + * @brief A localhost identity to indicate that the signature is generated using an HMAC key. + */ + static const Name& + getHmacIdentity(); + +private: // non-member operators + // NOTE: the following "hidden friend" operators are available via + // argument-dependent lookup only and must be defined inline. + + friend bool + operator==(const SigningInfo& lhs, const SigningInfo& rhs) + { + return !(lhs != rhs); + } + + friend bool + operator!=(const SigningInfo& lhs, const SigningInfo& rhs) + { + return lhs.m_type != rhs.m_type || + lhs.m_name != rhs.m_name || + lhs.m_digestAlgorithm != rhs.m_digestAlgorithm || + lhs.m_info != rhs.m_info; + } + +private: + SignerType m_type; + Name m_name; + Identity m_identity; + Key m_key; + shared_ptr m_hmacKey; + DigestAlgorithm m_digestAlgorithm; + SignatureInfo m_info; +}; + +std::ostream& +operator<<(std::ostream& os, const SigningInfo& si); + +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_SIGNING_INFO_HPP diff --git a/ndn-cxx/security/tpm/back-end.cpp b/ndn-cxx/security/tpm/back-end.cpp new file mode 100644 index 000000000..ec25623dd --- /dev/null +++ b/ndn-cxx/security/tpm/back-end.cpp @@ -0,0 +1,175 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/tpm/back-end.hpp" + +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/pib/key.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/digest-filter.hpp" +#include "ndn-cxx/security/transform/private-key.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" +#include "ndn-cxx/util/random.hpp" + +#include + +namespace ndn { +namespace security { +namespace tpm { + +BackEnd::~BackEnd() = default; + +bool +BackEnd::hasKey(const Name& keyName) const +{ + return doHasKey(keyName); +} + +unique_ptr +BackEnd::getKeyHandle(const Name& keyName) const +{ + return doGetKeyHandle(keyName); +} + +unique_ptr +BackEnd::createKey(const Name& identity, const KeyParams& params) +{ + if (params.getKeyType() == KeyType::HMAC) { + return doCreateKey(identity, params); + } + + switch (params.getKeyIdType()) { + case KeyIdType::USER_SPECIFIED: { + // check that the provided key id isn't already taken + Name keyName = v2::constructKeyName(identity, params.getKeyId()); + if (hasKey(keyName)) { + NDN_THROW(Error("Key `" + keyName.toUri() + "` already exists")); + } + break; + } + case KeyIdType::SHA256: + case KeyIdType::RANDOM: + // key id will be determined after key is generated + break; + default: + NDN_THROW(std::invalid_argument("Unsupported key id type " + + boost::lexical_cast(params.getKeyIdType()))); + } + + return doCreateKey(identity, params); +} + +void +BackEnd::deleteKey(const Name& keyName) +{ + doDeleteKey(keyName); +} + +ConstBufferPtr +BackEnd::exportKey(const Name& keyName, const char* pw, size_t pwLen) +{ + if (!hasKey(keyName)) { + NDN_THROW(Error("Key `" + keyName.toUri() + "` does not exist")); + } + return doExportKey(keyName, pw, pwLen); +} + +void +BackEnd::importKey(const Name& keyName, const uint8_t* pkcs8, size_t pkcs8Len, const char* pw, size_t pwLen) +{ + if (hasKey(keyName)) { + NDN_THROW(Error("Key `" + keyName.toUri() + "` already exists")); + } + doImportKey(keyName, pkcs8, pkcs8Len, pw, pwLen); +} + +void +BackEnd::importKey(const Name& keyName, shared_ptr key) +{ + if (hasKey(keyName)) { + NDN_THROW(Error("Key `" + keyName.toUri() + "` already exists")); + } + doImportKey(keyName, key); +} + +Name +BackEnd::constructAsymmetricKeyName(const KeyHandle& keyHandle, const Name& identity, + const KeyParams& params) const +{ + switch (params.getKeyIdType()) { + case KeyIdType::USER_SPECIFIED: { + return v2::constructKeyName(identity, params.getKeyId()); + } + case KeyIdType::SHA256: { + using namespace transform; + OBufferStream os; + bufferSource(*keyHandle.derivePublicKey()) >> + digestFilter(DigestAlgorithm::SHA256) >> + streamSink(os); + return v2::constructKeyName(identity, name::Component(os.buf())); + } + case KeyIdType::RANDOM: { + Name keyName; + do { + auto keyId = name::Component::fromNumber(random::generateSecureWord64()); + keyName = v2::constructKeyName(identity, keyId); + } while (hasKey(keyName)); + return keyName; + } + default: { + NDN_THROW(Error("Unsupported key id type " + boost::lexical_cast(params.getKeyIdType()))); + } + } +} + +Name +BackEnd::constructHmacKeyName(const transform::PrivateKey& key, const Name& identity, + const KeyParams& params) const +{ + return Name(identity).append(name::Component(key.getKeyDigest(DigestAlgorithm::SHA256))); +} + +bool +BackEnd::isTerminalMode() const +{ + return true; +} + +void +BackEnd::setTerminalMode(bool isTerminal) const +{ +} + +bool +BackEnd::isTpmLocked() const +{ + return false; +} + +bool +BackEnd::unlockTpm(const char* pw, size_t pwLen) const +{ + return !isTpmLocked(); +} + +} // namespace tpm +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/tpm/back-end.hpp b/ndn-cxx/security/tpm/back-end.hpp new file mode 100644 index 000000000..2874bdd47 --- /dev/null +++ b/ndn-cxx/security/tpm/back-end.hpp @@ -0,0 +1,204 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_TPM_BACK_END_HPP +#define NDN_SECURITY_TPM_BACK_END_HPP + +#include "ndn-cxx/security/tpm/tpm.hpp" + +namespace ndn { +namespace security { +namespace tpm { + +/** + * @brief Abstract interface for a TPM backend implementation. + * + * This class provides KeyHandle to the front-end and other TPM management operations. + */ +class BackEnd : noncopyable +{ +public: + using Error = Tpm::Error; + + virtual + ~BackEnd(); + +public: // key management + /** + * @brief Check if the key with name @p keyName exists in the TPM. + * + * @return True if the key exists, false otherwise. + */ + bool + hasKey(const Name& keyName) const; + + /** + * @brief Get the handle of the key with name @p keyName. + * + * Calling this function multiple times with the same @p keyName will return different KeyHandle + * objects that all refer to the same key. + * + * @return The handle of the key, or nullptr if the key does not exist. + */ + unique_ptr + getKeyHandle(const Name& keyName) const; + + /** + * @brief Create a key for @p identityName according to @p params. + * + * @return The handle of the created key. + * @throw std::invalid_argument @p params are invalid. + * @throw Error The key could not be created. + */ + unique_ptr + createKey(const Name& identityName, const KeyParams& params); + + /** + * @brief Delete the key with name @p keyName. + * + * @warning Continuing to use existing KeyHandle objects for a deleted key + * results in undefined behavior. + * + * @throw Error The key could not be deleted. + */ + void + deleteKey(const Name& keyName); + + /** + * @brief Get the private key with name @p keyName in encrypted PKCS #8 format. + * + * @param keyName The name of the key. + * @param pw The password to encrypt the private key. + * @param pwLen The length of the password. + * + * @return The encoded private key. + * @throw Error The key does not exist or cannot be exported. + */ + ConstBufferPtr + exportKey(const Name& keyName, const char* pw, size_t pwLen); + + /** + * @brief Import a private key in encrypted PKCS #8 format. + * + * @param keyName The name of the key to use in the TPM. + * @param pkcs8 Pointer to the key in encrypted PKCS #8 format. + * @param pkcs8Len The size of the key in encrypted PKCS #8 format. + * @param pw The password to decrypt the private key. + * @param pwLen The length of the password. + * + * @throw Error The key could not be imported. + */ + void + importKey(const Name& keyName, const uint8_t* pkcs8, size_t pkcs8Len, const char* pw, size_t pwLen); + + /** + * @brief Import a private key. + * + * @throw Error The key could not be imported. + */ + void + importKey(const Name& keyName, shared_ptr key); + + /** + * @brief Check if the TPM is in terminal mode. + * + * The default implementation always returns true. + * + * @return True if in terminal mode, false otherwise. + */ + virtual bool + isTerminalMode() const; + + /** + * @brief Set the terminal mode of the TPM. + * + * In terminal mode, the TPM will not ask for a password from the GUI. + * The default implementation does nothing. + */ + virtual void + setTerminalMode(bool isTerminal) const; + + /** + * @brief Check if the TPM is locked. + * + * The default implementation always returns false. + * + * @return True if locked, false otherwise. + */ + virtual bool + isTpmLocked() const; + + /** + * @brief Unlock the TPM. + * + * The default implementation does nothing and returns `!isTpmLocked()`. + * + * @param pw The password to unlock the TPM. + * @param pwLen The length of the password. + * + * @return True if the TPM was unlocked. + */ + NDN_CXX_NODISCARD virtual bool + unlockTpm(const char* pw, size_t pwLen) const; + +protected: // helper methods + /** + * @brief Construct and return the name of a RSA or EC key, based on @p identity and @p params. + */ + Name + constructAsymmetricKeyName(const KeyHandle& key, const Name& identity, + const KeyParams& params) const; + + /** + * @brief Construct and return the name of a HMAC key, based on @p identity and @p params. + */ + Name + constructHmacKeyName(const transform::PrivateKey& key, const Name& identity, + const KeyParams& params) const; + +private: // pure virtual methods + virtual bool + doHasKey(const Name& keyName) const = 0; + + virtual unique_ptr + doGetKeyHandle(const Name& keyName) const = 0; + + virtual unique_ptr + doCreateKey(const Name& identity, const KeyParams& params) = 0; + + virtual void + doDeleteKey(const Name& keyName) = 0; + + virtual ConstBufferPtr + doExportKey(const Name& keyName, const char* pw, size_t pwLen) = 0; + + virtual void + doImportKey(const Name& keyName, const uint8_t* pkcs8, size_t pkcs8Len, const char* pw, size_t pwLen) = 0; + + virtual void + doImportKey(const Name& keyName, shared_ptr key) = 0; +}; + +} // namespace tpm +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_TPM_BACK_END_HPP diff --git a/ndn-cxx/security/tpm/impl/back-end-file.cpp b/ndn-cxx/security/tpm/impl/back-end-file.cpp new file mode 100644 index 000000000..58e9aaf66 --- /dev/null +++ b/ndn-cxx/security/tpm/impl/back-end-file.cpp @@ -0,0 +1,227 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/tpm/impl/back-end-file.hpp" +#include "ndn-cxx/security/tpm/impl/key-handle-mem.hpp" +#include "ndn-cxx/security/transform.hpp" +#include "ndn-cxx/security/transform/private-key.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" + +#include +#include +#include + +#include +#include + +namespace ndn { +namespace security { +namespace tpm { + +namespace fs = boost::filesystem; +using transform::PrivateKey; + +class BackEndFile::Impl +{ +public: + explicit + Impl(const std::string& dir) + { + if (!dir.empty()) { + m_keystorePath = fs::path(dir); + } +#ifdef NDN_CXX_HAVE_TESTS + else if (std::getenv("TEST_HOME") != nullptr) { + m_keystorePath = fs::path(std::getenv("TEST_HOME")) / ".ndn"; + } +#endif // NDN_CXX_HAVE_TESTS + else if (std::getenv("HOME") != nullptr) { + m_keystorePath = fs::path(std::getenv("HOME")) / ".ndn"; + } + else { + m_keystorePath = fs::current_path() / ".ndn"; + } + + m_keystorePath /= "ndnsec-key-file"; + fs::create_directories(m_keystorePath); + } + + fs::path + toFileName(const Name& keyName) const + { + std::ostringstream os; + { + using namespace transform; + bufferSource(keyName.wireEncode().wire(), keyName.wireEncode().size()) + >> digestFilter(DigestAlgorithm::SHA256) + >> hexEncode() + >> streamSink(os); + } + return m_keystorePath / (os.str() + ".privkey"); + } + +private: + fs::path m_keystorePath; +}; + +BackEndFile::BackEndFile(const std::string& location) + : m_impl(make_unique(location)) +{ +} + +BackEndFile::~BackEndFile() = default; + +const std::string& +BackEndFile::getScheme() +{ + static std::string scheme = "tpm-file"; + return scheme; +} + +bool +BackEndFile::doHasKey(const Name& keyName) const +{ + if (!fs::exists(m_impl->toFileName(keyName))) + return false; + + try { + loadKey(keyName); + return true; + } + catch (const std::runtime_error&) { + return false; + } +} + +unique_ptr +BackEndFile::doGetKeyHandle(const Name& keyName) const +{ + if (!doHasKey(keyName)) + return nullptr; + + return make_unique(loadKey(keyName)); +} + +unique_ptr +BackEndFile::doCreateKey(const Name& identityName, const KeyParams& params) +{ + switch (params.getKeyType()) { + case KeyType::RSA: + case KeyType::EC: + break; + default: + NDN_THROW(std::invalid_argument("File-based TPM does not support creating a key of type " + + boost::lexical_cast(params.getKeyType()))); + } + + shared_ptr key(transform::generatePrivateKey(params).release()); + unique_ptr keyHandle = make_unique(key); + + Name keyName = constructAsymmetricKeyName(*keyHandle, identityName, params); + keyHandle->setKeyName(keyName); + + try { + saveKey(keyName, *key); + return keyHandle; + } + catch (const std::runtime_error&) { + NDN_THROW_NESTED(Error("Cannot write key to file")); + } +} + +void +BackEndFile::doDeleteKey(const Name& keyName) +{ + auto keyPath = m_impl->toFileName(keyName); + if (!fs::exists(keyPath)) + return; + + try { + fs::remove(keyPath); + } + catch (const fs::filesystem_error&) { + NDN_THROW_NESTED(Error("Cannot remove key file")); + } +} + +ConstBufferPtr +BackEndFile::doExportKey(const Name& keyName, const char* pw, size_t pwLen) +{ + unique_ptr key; + try { + key = loadKey(keyName); + } + catch (const PrivateKey::Error&) { + NDN_THROW_NESTED(Error("Cannot export private key")); + } + + OBufferStream os; + key->savePkcs8(os, pw, pwLen); + return os.buf(); +} + +void +BackEndFile::doImportKey(const Name& keyName, const uint8_t* buf, size_t size, const char* pw, size_t pwLen) +{ + try { + PrivateKey key; + key.loadPkcs8(buf, size, pw, pwLen); + saveKey(keyName, key); + } + catch (const PrivateKey::Error&) { + NDN_THROW_NESTED(Error("Cannot import private key")); + } +} + +void +BackEndFile::doImportKey(const Name& keyName, shared_ptr key) +{ + try { + saveKey(keyName, *key); + } + catch (const PrivateKey::Error&) { + NDN_THROW_NESTED(Error("Cannot import private key")); + } +} + +unique_ptr +BackEndFile::loadKey(const Name& keyName) const +{ + std::ifstream is(m_impl->toFileName(keyName).string()); + auto key = make_unique(); + key->loadPkcs1Base64(is); + return key; +} + +void +BackEndFile::saveKey(const Name& keyName, const PrivateKey& key) +{ + std::string fileName = m_impl->toFileName(keyName).string(); + std::ofstream os(fileName); + key.savePkcs1Base64(os); + + // set file permission + ::chmod(fileName.data(), 0000400); +} + +} // namespace tpm +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/tpm/impl/back-end-file.hpp b/ndn-cxx/security/tpm/impl/back-end-file.hpp new file mode 100644 index 000000000..2f956fe91 --- /dev/null +++ b/ndn-cxx/security/tpm/impl/back-end-file.hpp @@ -0,0 +1,102 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_TPM_IMPL_BACK_END_FILE_HPP +#define NDN_SECURITY_TPM_IMPL_BACK_END_FILE_HPP + +#include "ndn-cxx/security/tpm/back-end.hpp" + +namespace ndn { +namespace security { + +namespace transform { +class PrivateKey; +} // namespace transform + +namespace tpm { + +/** + * @brief The back-end implementation of a file-based TPM. + * + * In this TPM, each private key is stored in a separate file with permission 0400, i.e., + * owner read-only. The key is stored in PKCS #1 format in base64 encoding. + */ +class BackEndFile final : public BackEnd +{ +public: + /** + * @brief Create file-based TPM backend. + * + * @param location Directory to store private keys. + */ + explicit + BackEndFile(const std::string& location = ""); + + ~BackEndFile() final; + + static const std::string& + getScheme(); + +private: // inherited from tpm::BackEnd + bool + doHasKey(const Name& keyName) const final; + + unique_ptr + doGetKeyHandle(const Name& keyName) const final; + + unique_ptr + doCreateKey(const Name& identityName, const KeyParams& params) final; + + void + doDeleteKey(const Name& keyName) final; + + ConstBufferPtr + doExportKey(const Name& keyName, const char* pw, size_t pwLen) final; + + void + doImportKey(const Name& keyName, const uint8_t* buf, size_t size, const char* pw, size_t pwLen) final; + + void + doImportKey(const Name& keyName, shared_ptr key) final; + +private: + /** + * @brief Load a private key with name @p keyName from the key directory. + */ + unique_ptr + loadKey(const Name& keyName) const; + + /** + * @brief Save a private key with name @p keyName into the key directory. + */ + void + saveKey(const Name& keyName, const transform::PrivateKey& key); + +private: + class Impl; + const unique_ptr m_impl; +}; + +} // namespace tpm +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_TPM_IMPL_BACK_END_FILE_HPP diff --git a/ndn-cxx/security/tpm/impl/back-end-mem.cpp b/ndn-cxx/security/tpm/impl/back-end-mem.cpp new file mode 100644 index 000000000..dae98dbe1 --- /dev/null +++ b/ndn-cxx/security/tpm/impl/back-end-mem.cpp @@ -0,0 +1,136 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/tpm/impl/back-end-mem.hpp" +#include "ndn-cxx/security/tpm/impl/key-handle-mem.hpp" +#include "ndn-cxx/security/transform/private-key.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" + +#include + +#include + +namespace ndn { +namespace security { +namespace tpm { + +using transform::PrivateKey; + +class BackEndMem::Impl +{ +public: + std::unordered_map> keys; +}; + +BackEndMem::BackEndMem(const std::string&) + : m_impl(make_unique()) +{ +} + +BackEndMem::~BackEndMem() = default; + +const std::string& +BackEndMem::getScheme() +{ + static std::string scheme = "tpm-memory"; + return scheme; +} + +bool +BackEndMem::doHasKey(const Name& keyName) const +{ + return (m_impl->keys.count(keyName) > 0); +} + +unique_ptr +BackEndMem::doGetKeyHandle(const Name& keyName) const +{ + auto it = m_impl->keys.find(keyName); + if (it == m_impl->keys.end()) + return nullptr; + return make_unique(it->second); +} + +unique_ptr +BackEndMem::doCreateKey(const Name& identityName, const KeyParams& params) +{ + switch (params.getKeyType()) { + case KeyType::RSA: + case KeyType::EC: + case KeyType::HMAC: + break; + default: + NDN_THROW(std::invalid_argument("Memory-based TPM does not support creating a key of type " + + boost::lexical_cast(params.getKeyType()))); + } + + shared_ptr key(transform::generatePrivateKey(params).release()); + unique_ptr keyHandle = make_unique(key); + + Name keyName; + if (params.getKeyType() == KeyType::HMAC) { + keyName = constructHmacKeyName(*key, identityName, params); + } + else { + keyName = constructAsymmetricKeyName(*keyHandle, identityName, params); + } + keyHandle->setKeyName(keyName); + + m_impl->keys[keyName] = std::move(key); + return keyHandle; +} + +void +BackEndMem::doDeleteKey(const Name& keyName) +{ + m_impl->keys.erase(keyName); +} + +ConstBufferPtr +BackEndMem::doExportKey(const Name& keyName, const char* pw, size_t pwLen) +{ + OBufferStream os; + m_impl->keys[keyName]->savePkcs8(os, pw, pwLen); + return os.buf(); +} + +void +BackEndMem::doImportKey(const Name& keyName, const uint8_t* buf, size_t size, const char* pw, size_t pwLen) +{ + auto key = make_shared(); + try { + key->loadPkcs8(buf, size, pw, pwLen); + } + catch (const PrivateKey::Error&) { + NDN_THROW_NESTED(Error("Cannot import private key")); + } + doImportKey(keyName, std::move(key)); +} + +void +BackEndMem::doImportKey(const Name& keyName, shared_ptr key) +{ + m_impl->keys[keyName] = std::move(key); +} + +} // namespace tpm +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/tpm/impl/back-end-mem.hpp b/ndn-cxx/security/tpm/impl/back-end-mem.hpp new file mode 100644 index 000000000..b185ba3ae --- /dev/null +++ b/ndn-cxx/security/tpm/impl/back-end-mem.hpp @@ -0,0 +1,81 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_TPM_IMPL_BACK_END_MEM_HPP +#define NDN_SECURITY_TPM_IMPL_BACK_END_MEM_HPP + +#include "ndn-cxx/security/tpm/back-end.hpp" + +namespace ndn { +namespace security { +namespace tpm { + +/** + * @brief The back-end implementation of an in-memory TPM. + */ +class BackEndMem final : public BackEnd +{ +public: + /** + * @brief Create memory-based TPM backend. + * + * @param location Not used (required by the TPM registration interface). + */ + explicit + BackEndMem(const std::string& location = ""); + + ~BackEndMem() final; + + static const std::string& + getScheme(); + +private: // inherited from tpm::BackEnd + bool + doHasKey(const Name& keyName) const final; + + unique_ptr + doGetKeyHandle(const Name& keyName) const final; + + unique_ptr + doCreateKey(const Name& identityName, const KeyParams& params) final; + + void + doDeleteKey(const Name& keyName) final; + + ConstBufferPtr + doExportKey(const Name& keyName, const char* pw, size_t pwLen) final; + + void + doImportKey(const Name& keyName, const uint8_t* buf, size_t size, const char* pw, size_t pwLen) final; + + void + doImportKey(const Name& keyName, shared_ptr key) final; + +private: + class Impl; + const unique_ptr m_impl; +}; + +} // namespace tpm +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_TPM_IMPL_BACK_END_MEM_HPP diff --git a/ndn-cxx/security/tpm/impl/back-end-osx.cpp b/ndn-cxx/security/tpm/impl/back-end-osx.cpp new file mode 100644 index 000000000..85e05948c --- /dev/null +++ b/ndn-cxx/security/tpm/impl/back-end-osx.cpp @@ -0,0 +1,511 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/tpm/impl/back-end-osx.hpp" +#include "ndn-cxx/security/tpm/impl/key-handle-osx.hpp" +#include "ndn-cxx/security/transform/private-key.hpp" +#include "ndn-cxx/detail/cf-string-osx.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" + +#include +#include + +#include + +namespace ndn { +namespace security { +namespace tpm { + +namespace cfstring = detail::cfstring; +using detail::CFReleaser; + +class BackEndOsx::Impl +{ +public: + SecKeychainRef keyChainRef; + bool isTerminalMode = false; +}; + +static CFReleaser +makeCFDataNoCopy(const uint8_t* buf, size_t buflen) +{ + return CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buf, buflen, kCFAllocatorNull); +} + +static CFReleaser +makeCFMutableDictionary() +{ + return CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); +} + +static std::string +getErrorMessage(OSStatus status) +{ + CFReleaser msg = SecCopyErrorMessageString(status, nullptr); + if (msg != nullptr) + return cfstring::toStdString(msg.get()); + else + return ""; +} + +static std::string +getFailureReason(CFErrorRef err) +{ + CFReleaser reason = CFErrorCopyFailureReason(err); + if (reason != nullptr) + return cfstring::toStdString(reason.get()); + else + return ""; +} + +static CFTypeRef +getAsymKeyType(KeyType keyType) +{ + switch (keyType) { + case KeyType::RSA: + return kSecAttrKeyTypeRSA; + case KeyType::EC: + return kSecAttrKeyTypeECDSA; + default: + NDN_CXX_UNREACHABLE; + } +} + +static CFTypeRef +getDigestAlgorithm(DigestAlgorithm digestAlgo) +{ + switch (digestAlgo) { + case DigestAlgorithm::SHA224: + case DigestAlgorithm::SHA256: + case DigestAlgorithm::SHA384: + case DigestAlgorithm::SHA512: + return kSecDigestSHA2; + default: + return nullptr; + } +} + +static int +getDigestSize(DigestAlgorithm digestAlgo) +{ + switch (digestAlgo) { + case DigestAlgorithm::SHA224: + return 224; + case DigestAlgorithm::SHA256: + return 256; + case DigestAlgorithm::SHA384: + return 384; + case DigestAlgorithm::SHA512: + return 512; + default: + return -1; + } +} + +/** + * @brief Get reference to private key with name @p keyName. + */ +static KeyRefOsx +getKeyRef(const Name& keyName) +{ + auto keyLabel = cfstring::fromStdString(keyName.toUri()); + + auto query = makeCFMutableDictionary(); + CFDictionaryAddValue(query.get(), kSecClass, kSecClassKey); + CFDictionaryAddValue(query.get(), kSecAttrKeyClass, kSecAttrKeyClassPrivate); + CFDictionaryAddValue(query.get(), kSecAttrLabel, keyLabel.get()); + CFDictionaryAddValue(query.get(), kSecReturnRef, kCFBooleanTrue); + + KeyRefOsx keyRef; + // C-style cast is used as per Apple convention + OSStatus res = SecItemCopyMatching(query.get(), (CFTypeRef*)&keyRef.get()); + keyRef.retain(); + + if (res == errSecSuccess) { + return keyRef; + } + else if (res == errSecItemNotFound) { + return nullptr; + } + else { + NDN_THROW(Tpm::Error("Key lookup in keychain failed: " + getErrorMessage(res))); + } +} + +/** + * @brief Export a private key from the Keychain to @p outKey + */ +static void +exportItem(const KeyRefOsx& keyRef, transform::PrivateKey& outKey) +{ + // use a temporary password for PKCS8 encoding + const char pw[] = "correct horse battery staple"; + auto passphrase = cfstring::fromBuffer(reinterpret_cast(pw), std::strlen(pw)); + + SecItemImportExportKeyParameters keyParams; + std::memset(&keyParams, 0, sizeof(keyParams)); + keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; + keyParams.passphrase = passphrase.get(); + + CFReleaser exportedKey; + OSStatus res = SecItemExport(keyRef.get(), // secItemOrArray + kSecFormatWrappedPKCS8, // outputFormat + 0, // flags + &keyParams, // keyParams + &exportedKey.get()); // exportedData + + if (res != errSecSuccess) { + NDN_THROW(Tpm::Error("Failed to export private key: "s + getErrorMessage(res))); + } + + outKey.loadPkcs8(CFDataGetBytePtr(exportedKey.get()), CFDataGetLength(exportedKey.get()), + pw, std::strlen(pw)); +} + +BackEndOsx::BackEndOsx(const std::string&) + : m_impl(make_unique()) +{ + SecKeychainSetUserInteractionAllowed(!m_impl->isTerminalMode); + + OSStatus res = SecKeychainCopyDefault(&m_impl->keyChainRef); + if (res == errSecNoDefaultKeychain) { + NDN_THROW(Error("No default keychain, create one first")); + } +} + +BackEndOsx::~BackEndOsx() = default; + +const std::string& +BackEndOsx::getScheme() +{ + static std::string scheme = "tpm-osxkeychain"; + return scheme; +} + +bool +BackEndOsx::isTerminalMode() const +{ + return m_impl->isTerminalMode; +} + +void +BackEndOsx::setTerminalMode(bool isTerminal) const +{ + m_impl->isTerminalMode = isTerminal; + SecKeychainSetUserInteractionAllowed(!isTerminal); +} + +bool +BackEndOsx::isTpmLocked() const +{ + SecKeychainStatus keychainStatus; + OSStatus res = SecKeychainGetStatus(m_impl->keyChainRef, &keychainStatus); + if (res != errSecSuccess) + return true; + else + return (kSecUnlockStateStatus & keychainStatus) == 0; +} + +bool +BackEndOsx::unlockTpm(const char* pw, size_t pwLen) const +{ + // If the default key chain is already unlocked, return immediately. + if (!isTpmLocked()) + return true; + + if (m_impl->isTerminalMode) { + // Use the supplied password. + SecKeychainUnlock(m_impl->keyChainRef, pwLen, pw, true); + } + else { + // If inTerminal is not set, get the password from GUI. + SecKeychainUnlock(m_impl->keyChainRef, 0, nullptr, false); + } + + return !isTpmLocked(); +} + +ConstBufferPtr +BackEndOsx::sign(const KeyRefOsx& key, DigestAlgorithm digestAlgo, const uint8_t* buf, size_t size) +{ + CFReleaser error; + CFReleaser signer = SecSignTransformCreate(key.get(), &error.get()); + if (signer == nullptr) { + NDN_THROW(Error("Failed to create sign transform: " + getFailureReason(error.get()))); + } + + // Set input + auto data = makeCFDataNoCopy(buf, size); + SecTransformSetAttribute(signer.get(), kSecTransformInputAttributeName, data.get(), &error.get()); + if (error != nullptr) { + NDN_THROW(Error("Failed to configure input of sign transform: " + getFailureReason(error.get()))); + } + + // Enable use of padding + SecTransformSetAttribute(signer.get(), kSecPaddingKey, kSecPaddingPKCS1Key, &error.get()); + if (error != nullptr) { + NDN_THROW(Error("Failed to configure padding of sign transform: " + getFailureReason(error.get()))); + } + + // Set digest type + SecTransformSetAttribute(signer.get(), kSecDigestTypeAttribute, getDigestAlgorithm(digestAlgo), &error.get()); + if (error != nullptr) { + NDN_THROW(Error("Failed to configure digest type of sign transform: " + getFailureReason(error.get()))); + } + + // Set digest length + int digestSize = getDigestSize(digestAlgo); + CFReleaser cfDigestSize = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &digestSize); + SecTransformSetAttribute(signer.get(), kSecDigestLengthAttribute, cfDigestSize.get(), &error.get()); + if (error != nullptr) { + NDN_THROW(Error("Failed to configure digest length of sign transform: " + getFailureReason(error.get()))); + } + + // Actually sign + // C-style cast is used as per Apple convention + CFReleaser signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get()); + if (signature == nullptr) { + NDN_THROW(Error("Failed to sign data: " + getFailureReason(error.get()))); + } + + return make_shared(CFDataGetBytePtr(signature.get()), CFDataGetLength(signature.get())); +} + +ConstBufferPtr +BackEndOsx::decrypt(const KeyRefOsx& key, const uint8_t* cipherText, size_t cipherSize) +{ + CFReleaser error; + CFReleaser decryptor = SecDecryptTransformCreate(key.get(), &error.get()); + if (decryptor == nullptr) { + NDN_THROW(Error("Failed to create decrypt transform: " + getFailureReason(error.get()))); + } + + auto data = makeCFDataNoCopy(cipherText, cipherSize); + SecTransformSetAttribute(decryptor.get(), kSecTransformInputAttributeName, data.get(), &error.get()); + if (error != nullptr) { + NDN_THROW(Error("Failed to configure input of decrypt transform: " + getFailureReason(error.get()))); + } + + SecTransformSetAttribute(decryptor.get(), kSecPaddingKey, kSecPaddingOAEPKey, &error.get()); + if (error != nullptr) { + NDN_THROW(Error("Failed to configure padding of decrypt transform: " + getFailureReason(error.get()))); + } + + // C-style cast is used as per Apple convention + CFReleaser plainText = (CFDataRef)SecTransformExecute(decryptor.get(), &error.get()); + if (plainText == nullptr) { + NDN_THROW(Error("Failed to decrypt data: " + getFailureReason(error.get()))); + } + + return make_shared(CFDataGetBytePtr(plainText.get()), CFDataGetLength(plainText.get())); +} + +ConstBufferPtr +BackEndOsx::derivePublicKey(const KeyRefOsx& key) +{ + transform::PrivateKey privateKey; + exportItem(key, privateKey); + return privateKey.derivePublicKey(); +} + +bool +BackEndOsx::doHasKey(const Name& keyName) const +{ + return getKeyRef(keyName) != nullptr; +} + +unique_ptr +BackEndOsx::doGetKeyHandle(const Name& keyName) const +{ + KeyRefOsx keyRef = getKeyRef(keyName); + if (keyRef == nullptr) { + return nullptr; + } + + return make_unique(keyRef.get()); +} + +unique_ptr +BackEndOsx::doCreateKey(const Name& identityName, const KeyParams& params) +{ + KeyType keyType = params.getKeyType(); + uint32_t keySize; + switch (keyType) { + case KeyType::RSA: { + const RsaKeyParams& rsaParams = static_cast(params); + keySize = rsaParams.getKeySize(); + break; + } + case KeyType::EC: { + const EcKeyParams& ecParams = static_cast(params); + keySize = ecParams.getKeySize(); + break; + } + default: { + NDN_THROW(std::invalid_argument("macOS-based TPM does not support creating a key of type " + + boost::lexical_cast(keyType))); + } + } + CFReleaser cfKeySize = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &keySize); + + auto attrDict = makeCFMutableDictionary(); + CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, getAsymKeyType(keyType)); + CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get()); + + KeyRefOsx publicKey, privateKey; + OSStatus res = SecKeyGeneratePair(attrDict.get(), &publicKey.get(), &privateKey.get()); + publicKey.retain(); + privateKey.retain(); + + if (res != errSecSuccess) { + NDN_THROW(Error("Failed to generate key pair: " + getErrorMessage(res))); + } + + unique_ptr keyHandle = make_unique(privateKey.get()); + Name keyName = constructAsymmetricKeyName(*keyHandle, identityName, params); + keyHandle->setKeyName(keyName); + + SecKeychainAttribute attrs[1]; // maximum number of attributes + SecKeychainAttributeList attrList = {0, attrs}; + std::string keyUri = keyName.toUri(); + { + attrs[attrList.count].tag = kSecKeyPrintName; + attrs[attrList.count].length = keyUri.size(); + attrs[attrList.count].data = const_cast(keyUri.data()); + attrList.count++; + } + + SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)privateKey.get(), &attrList, 0, nullptr); + SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)publicKey.get(), &attrList, 0, nullptr); + + return keyHandle; +} + +void +BackEndOsx::doDeleteKey(const Name& keyName) +{ + auto keyLabel = cfstring::fromStdString(keyName.toUri()); + + auto query = makeCFMutableDictionary(); + CFDictionaryAddValue(query.get(), kSecClass, kSecClassKey); + CFDictionaryAddValue(query.get(), kSecAttrLabel, keyLabel.get()); + CFDictionaryAddValue(query.get(), kSecMatchLimit, kSecMatchLimitAll); + + OSStatus res = SecItemDelete(query.get()); + + if (res != errSecSuccess && res != errSecItemNotFound) { + NDN_THROW(Error("Failed to delete key pair: " + getErrorMessage(res))); + } +} + +ConstBufferPtr +BackEndOsx::doExportKey(const Name& keyName, const char* pw, size_t pwLen) +{ + KeyRefOsx keychainItem = getKeyRef(keyName); + if (keychainItem == nullptr) { + NDN_THROW(Error("Failed to export private key: " + getErrorMessage(errSecItemNotFound))); + } + + transform::PrivateKey exportedKey; + OBufferStream pkcs8; + try { + exportItem(keychainItem, exportedKey); + exportedKey.savePkcs8(pkcs8, pw, pwLen); + } + catch (const transform::PrivateKey::Error&) { + NDN_THROW_NESTED(Error("Failed to export private key")); + } + return pkcs8.buf(); +} + +void +BackEndOsx::doImportKey(const Name& keyName, const uint8_t* buf, size_t size, + const char* pw, size_t pwLen) +{ + transform::PrivateKey privKey; + OBufferStream pkcs1; + try { + // do the PKCS8 decoding ourselves, see bug #4450 + privKey.loadPkcs8(buf, size, pw, pwLen); + privKey.savePkcs1(pkcs1); + } + catch (const transform::PrivateKey::Error&) { + NDN_THROW_NESTED(Error("Failed to import private key")); + } + auto keyToImport = makeCFDataNoCopy(pkcs1.buf()->data(), pkcs1.buf()->size()); + + SecExternalFormat externalFormat = kSecFormatOpenSSL; + SecExternalItemType externalType = kSecItemTypePrivateKey; + + auto keyUri = keyName.toUri(); + auto keyLabel = cfstring::fromStdString(keyUri); + CFReleaser access; + OSStatus res = SecAccessCreate(keyLabel.get(), // descriptor + nullptr, // trustedlist (null == trust only the calling app) + &access.get()); // accessRef + + if (res != errSecSuccess) { + NDN_THROW(Error("Failed to import private key: " + getErrorMessage(res))); + } + + SecItemImportExportKeyParameters keyParams; + std::memset(&keyParams, 0, sizeof(keyParams)); + keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; + keyParams.accessRef = access.get(); + + CFReleaser outItems; + res = SecItemImport(keyToImport.get(), // importedData + nullptr, // fileNameOrExtension + &externalFormat, // inputFormat + &externalType, // itemType + 0, // flags + &keyParams, // keyParams + m_impl->keyChainRef, // importKeychain + &outItems.get()); // outItems + + if (res != errSecSuccess) { + NDN_THROW(Error("Failed to import private key: " + getErrorMessage(res))); + } + + // C-style cast is used as per Apple convention + SecKeychainItemRef keychainItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0); + SecKeychainAttribute attrs[1]; // maximum number of attributes + SecKeychainAttributeList attrList = {0, attrs}; + { + attrs[attrList.count].tag = kSecKeyPrintName; + attrs[attrList.count].length = keyUri.size(); + attrs[attrList.count].data = const_cast(keyUri.data()); + attrList.count++; + } + SecKeychainItemModifyAttributesAndData(keychainItem, &attrList, 0, nullptr); +} + +void +BackEndOsx::doImportKey(const Name& keyName, shared_ptr key) +{ + NDN_THROW(Error("macOS-based TPM does not support importing a transform::PrivateKey")); +} + +} // namespace tpm +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/tpm/impl/back-end-osx.hpp b/ndn-cxx/security/tpm/impl/back-end-osx.hpp new file mode 100644 index 000000000..18df66ad0 --- /dev/null +++ b/ndn-cxx/security/tpm/impl/back-end-osx.hpp @@ -0,0 +1,113 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_TPM_IMPL_BACK_END_OSX_HPP +#define NDN_SECURITY_TPM_IMPL_BACK_END_OSX_HPP + +#include "ndn-cxx/security/tpm/back-end.hpp" + +#ifndef NDN_CXX_HAVE_OSX_FRAMEWORKS +#error "This file should not be compiled ..." +#endif + +#include "ndn-cxx/security/tpm/impl/key-ref-osx.hpp" + +namespace ndn { +namespace security { +namespace tpm { + +/** + * @brief The back-end implementation of TPM based on macOS Keychain Services. + */ +class BackEndOsx final : public BackEnd +{ +public: + /** + * @brief Create TPM backed based on macOS Keychain Services. + * + * @param location Not used (required by the TPM registration interface). + */ + explicit + BackEndOsx(const std::string& location = ""); + + ~BackEndOsx() final; + + static const std::string& + getScheme(); + +public: // management + bool + isTerminalMode() const final; + + void + setTerminalMode(bool isTerminal) const final; + + bool + isTpmLocked() const final; + + bool + unlockTpm(const char* pw, size_t pwLen) const final; + +public: // crypto transformation + /** + * @brief Sign @p buf with @p key using @p digestAlgorithm. + */ + static ConstBufferPtr + sign(const KeyRefOsx& key, DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size); + + static ConstBufferPtr + decrypt(const KeyRefOsx& key, const uint8_t* cipherText, size_t cipherSize); + + static ConstBufferPtr + derivePublicKey(const KeyRefOsx& key); + +private: // inherited from tpm::BackEnd + bool + doHasKey(const Name& keyName) const final; + + unique_ptr + doGetKeyHandle(const Name& keyName) const final; + + unique_ptr + doCreateKey(const Name& identityName, const KeyParams& params) final; + + void + doDeleteKey(const Name& keyName) final; + + ConstBufferPtr + doExportKey(const Name& keyName, const char* pw, size_t pwLen) final; + + void + doImportKey(const Name& keyName, const uint8_t* buf, size_t size, const char* pw, size_t pwLen) final; + + void + doImportKey(const Name& keyName, shared_ptr key) final; + +private: + class Impl; + const unique_ptr m_impl; +}; + +} // namespace tpm +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_TPM_IMPL_BACK_END_OSX_HPP diff --git a/ndn-cxx/security/tpm/impl/key-handle-mem.cpp b/ndn-cxx/security/tpm/impl/key-handle-mem.cpp new file mode 100644 index 000000000..99275e890 --- /dev/null +++ b/ndn-cxx/security/tpm/impl/key-handle-mem.cpp @@ -0,0 +1,77 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/tpm/impl/key-handle-mem.hpp" +#include "ndn-cxx/security/transform/bool-sink.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/private-key.hpp" +#include "ndn-cxx/security/transform/signer-filter.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" +#include "ndn-cxx/security/transform/verifier-filter.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" + +namespace ndn { +namespace security { +namespace tpm { + +KeyHandleMem::KeyHandleMem(shared_ptr key) + : m_key(std::move(key)) +{ + BOOST_ASSERT(m_key != nullptr); +} + +ConstBufferPtr +KeyHandleMem::doSign(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size) const +{ + using namespace transform; + + OBufferStream sigOs; + bufferSource(buf, size) >> signerFilter(digestAlgorithm, *m_key) >> streamSink(sigOs); + return sigOs.buf(); +} + +bool +KeyHandleMem::doVerify(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size, + const uint8_t* sig, size_t sigLen) const +{ + using namespace transform; + + bool result = false; + bufferSource(buf, size) >> verifierFilter(digestAlgorithm, *m_key, sig, sigLen) + >> boolSink(result); + return result; +} + +ConstBufferPtr +KeyHandleMem::doDecrypt(const uint8_t* cipherText, size_t cipherTextLen) const +{ + return m_key->decrypt(cipherText, cipherTextLen); +} + +ConstBufferPtr +KeyHandleMem::doDerivePublicKey() const +{ + return m_key->derivePublicKey(); +} + +} // namespace tpm +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/tpm/impl/key-handle-mem.hpp b/ndn-cxx/security/tpm/impl/key-handle-mem.hpp new file mode 100644 index 000000000..5ed9dff7d --- /dev/null +++ b/ndn-cxx/security/tpm/impl/key-handle-mem.hpp @@ -0,0 +1,67 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_TPM_IMPL_KEY_HANDLE_MEM_HPP +#define NDN_SECURITY_TPM_IMPL_KEY_HANDLE_MEM_HPP + +#include "ndn-cxx/security/tpm/key-handle.hpp" + +namespace ndn { +namespace security { + +namespace transform { +class PrivateKey; +} // namespace transform + +namespace tpm { + +/** + * @brief A TPM key handle that keeps the private key in memory + */ +class KeyHandleMem : public KeyHandle +{ +public: + explicit + KeyHandleMem(shared_ptr key); + +private: + ConstBufferPtr + doSign(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size) const final; + + bool + doVerify(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size, + const uint8_t* sig, size_t sigLen) const final; + + ConstBufferPtr + doDecrypt(const uint8_t* cipherText, size_t cipherTextLen) const final; + + ConstBufferPtr + doDerivePublicKey() const final; + +private: + shared_ptr m_key; +}; + +} // namespace tpm +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_TPM_IMPL_KEY_HANDLE_MEM_HPP diff --git a/ndn-cxx/security/tpm/impl/key-handle-osx.cpp b/ndn-cxx/security/tpm/impl/key-handle-osx.cpp new file mode 100644 index 000000000..0ff3d5450 --- /dev/null +++ b/ndn-cxx/security/tpm/impl/key-handle-osx.cpp @@ -0,0 +1,63 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/tpm/impl/key-handle-osx.hpp" +#include "ndn-cxx/security/tpm/impl/back-end-osx.hpp" + +namespace ndn { +namespace security { +namespace tpm { + +KeyHandleOsx::KeyHandleOsx(const KeyRefOsx& key) + : m_key(key) +{ + if (m_key.get() == 0) + NDN_THROW(Error("Key is not set")); +} + +ConstBufferPtr +KeyHandleOsx::doSign(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size) const +{ + return BackEndOsx::sign(m_key, digestAlgorithm, buf, size); +} + +bool +KeyHandleOsx::doVerify(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size, + const uint8_t* sig, size_t sigLen) const +{ + NDN_THROW(Error("Signature verification is not supported with macOS Keychain-based TPM")); +} + +ConstBufferPtr +KeyHandleOsx::doDecrypt(const uint8_t* cipherText, size_t cipherTextLen) const +{ + return BackEndOsx::decrypt(m_key, cipherText, cipherTextLen); +} + +ConstBufferPtr +KeyHandleOsx::doDerivePublicKey() const +{ + return BackEndOsx::derivePublicKey(m_key); +} + +} // namespace tpm +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/tpm/impl/key-handle-osx.hpp b/ndn-cxx/security/tpm/impl/key-handle-osx.hpp new file mode 100644 index 000000000..bb659440b --- /dev/null +++ b/ndn-cxx/security/tpm/impl/key-handle-osx.hpp @@ -0,0 +1,68 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_TPM_IMPL_KEY_HANDLE_OSX_HPP +#define NDN_SECURITY_TPM_IMPL_KEY_HANDLE_OSX_HPP + +#include "ndn-cxx/security/tpm/key-handle.hpp" + +#ifndef NDN_CXX_HAVE_OSX_FRAMEWORKS +#error "This file should not be compiled ..." +#endif + +#include "ndn-cxx/security/tpm/impl/key-ref-osx.hpp" + +namespace ndn { +namespace security { +namespace tpm { + +/** + * @brief Abstraction of TPM key handle used by the TPM based on macOS Keychain Services. + */ +class KeyHandleOsx : public KeyHandle +{ +public: + explicit + KeyHandleOsx(const KeyRefOsx& key); + +private: + ConstBufferPtr + doSign(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size) const final; + + bool + doVerify(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size, + const uint8_t* sig, size_t sigLen) const final; + + ConstBufferPtr + doDecrypt(const uint8_t* cipherText, size_t cipherTextLen) const final; + + ConstBufferPtr + doDerivePublicKey() const final; + +private: + KeyRefOsx m_key; +}; + +} // namespace tpm +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_TPM_IMPL_KEY_HANDLE_OSX_HPP diff --git a/ndn-cxx/security/tpm/impl/key-ref-osx.hpp b/ndn-cxx/security/tpm/impl/key-ref-osx.hpp new file mode 100644 index 000000000..983338782 --- /dev/null +++ b/ndn-cxx/security/tpm/impl/key-ref-osx.hpp @@ -0,0 +1,45 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_TPM_IMPL_KEY_REF_OSX_HPP +#define NDN_SECURITY_TPM_IMPL_KEY_REF_OSX_HPP + +#include "ndn-cxx/detail/common.hpp" + +#ifndef NDN_CXX_HAVE_OSX_FRAMEWORKS +#error "This file should not be compiled ..." +#endif + +#include "ndn-cxx/detail/cf-releaser-osx.hpp" + +#include + +namespace ndn { +namespace security { +namespace tpm { + +using KeyRefOsx = detail::CFReleaser; + +} // namespace tpm +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_TPM_IMPL_KEY_REF_OSX_HPP diff --git a/ndn-cxx/security/tpm/key-handle.cpp b/ndn-cxx/security/tpm/key-handle.cpp new file mode 100644 index 000000000..56057a2a5 --- /dev/null +++ b/ndn-cxx/security/tpm/key-handle.cpp @@ -0,0 +1,57 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/tpm/key-handle.hpp" + +namespace ndn { +namespace security { +namespace tpm { + +KeyHandle::~KeyHandle() = default; + +ConstBufferPtr +KeyHandle::sign(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size) const +{ + return doSign(digestAlgorithm, buf, size); +} + +bool +KeyHandle::verify(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t bufLen, + const uint8_t* sig, size_t sigLen) const +{ + return doVerify(digestAlgorithm, buf, bufLen, sig, sigLen); +} + +ConstBufferPtr +KeyHandle::decrypt(const uint8_t* cipherText, size_t cipherTextLen) const +{ + return doDecrypt(cipherText, cipherTextLen); +} + +ConstBufferPtr +KeyHandle::derivePublicKey() const +{ + return doDerivePublicKey(); +} + +} // namespace tpm +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/tpm/key-handle.hpp b/ndn-cxx/security/tpm/key-handle.hpp new file mode 100644 index 000000000..0a4fd8a81 --- /dev/null +++ b/ndn-cxx/security/tpm/key-handle.hpp @@ -0,0 +1,109 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_TPM_KEY_HANDLE_HPP +#define NDN_SECURITY_TPM_KEY_HANDLE_HPP + +#include "ndn-cxx/name.hpp" +#include "ndn-cxx/security/security-common.hpp" + +namespace ndn { +namespace security { +namespace tpm { + +/** + * @brief Abstraction of TPM key handle. + * + * KeyHandle provides an interface to perform crypto operations with a key stored in the TPM. + */ +class KeyHandle : noncopyable +{ +public: + class Error : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + }; + +public: + virtual + ~KeyHandle(); + + /** + * @return a digital signature created on @p buf using this key with @p digestAlgorithm. + */ + ConstBufferPtr + sign(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size) const; + + /** + * @brief Verify the signature @p sig created on @p buf using this key and @p digestAlgorithm. + */ + bool + verify(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t bufLen, + const uint8_t* sig, size_t sigLen) const; + + /** + * @return plain text content decrypted from @p cipherText using this key. + */ + ConstBufferPtr + decrypt(const uint8_t* cipherText, size_t cipherTextLen) const; + + /** + * @return the PCKS#8 encoded public key bits derived from this key. + */ + ConstBufferPtr + derivePublicKey() const; + + Name + getKeyName() const + { + return m_keyName; + } + + void + setKeyName(const Name& keyName) + { + m_keyName = keyName; + } + +private: + virtual ConstBufferPtr + doSign(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t size) const = 0; + + virtual bool + doVerify(DigestAlgorithm digestAlgorithm, const uint8_t* buf, size_t bufLen, + const uint8_t* sig, size_t sigLen) const = 0; + + virtual ConstBufferPtr + doDecrypt(const uint8_t* cipherText, size_t cipherTextLen) const = 0; + + virtual ConstBufferPtr + doDerivePublicKey() const = 0; + +private: + Name m_keyName; +}; + +} // namespace tpm +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_TPM_KEY_HANDLE_HPP diff --git a/ndn-cxx/security/tpm/tpm.cpp b/ndn-cxx/security/tpm/tpm.cpp new file mode 100644 index 000000000..d3259557e --- /dev/null +++ b/ndn-cxx/security/tpm/tpm.cpp @@ -0,0 +1,178 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/tpm/tpm.hpp" +#include "ndn-cxx/security/tpm/back-end.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" + +#include + +namespace ndn { +namespace security { +namespace tpm { + +Tpm::Tpm(const std::string& scheme, const std::string& location, unique_ptr backEnd) + : m_scheme(scheme) + , m_location(location) + , m_backEnd(std::move(backEnd)) +{ +} + +Tpm::~Tpm() = default; + +std::string +Tpm::getTpmLocator() const +{ + return m_scheme + ":" + m_location; +} + +bool +Tpm::hasKey(const Name& keyName) const +{ + return m_backEnd->hasKey(keyName); +} + +Name +Tpm::createKey(const Name& identityName, const KeyParams& params) +{ + auto keyHandle = m_backEnd->createKey(identityName, params); + auto keyName = keyHandle->getKeyName(); + m_keys[keyName] = std::move(keyHandle); + return keyName; +} + +void +Tpm::deleteKey(const Name& keyName) +{ + auto it = m_keys.find(keyName); + if (it != m_keys.end()) + m_keys.erase(it); + + m_backEnd->deleteKey(keyName); +} + +ConstBufferPtr +Tpm::getPublicKey(const Name& keyName) const +{ + const KeyHandle* key = findKey(keyName); + + if (key == nullptr) + return nullptr; + else + return key->derivePublicKey(); +} + +ConstBufferPtr +Tpm::sign(const uint8_t* buf, size_t size, const Name& keyName, DigestAlgorithm digestAlgorithm) const +{ + const KeyHandle* key = findKey(keyName); + + if (key == nullptr) + return nullptr; + else + return key->sign(digestAlgorithm, buf, size); +} + +boost::logic::tribool +Tpm::verify(const uint8_t* buf, size_t bufLen, const uint8_t* sig, size_t sigLen, + const Name& keyName, DigestAlgorithm digestAlgorithm) const +{ + const KeyHandle* key = findKey(keyName); + + if (key == nullptr) + return boost::logic::indeterminate; + else + return key->verify(digestAlgorithm, buf, bufLen, sig, sigLen); +} + +ConstBufferPtr +Tpm::decrypt(const uint8_t* buf, size_t size, const Name& keyName) const +{ + const KeyHandle* key = findKey(keyName); + + if (key == nullptr) + return nullptr; + else + return key->decrypt(buf, size); +} + +bool +Tpm::isTerminalMode() const +{ + return m_backEnd->isTerminalMode(); +} + +void +Tpm::setTerminalMode(bool isTerminal) const +{ + m_backEnd->setTerminalMode(isTerminal); +} + +bool +Tpm::isTpmLocked() const +{ + return m_backEnd->isTpmLocked(); +} + +bool +Tpm::unlockTpm(const char* password, size_t passwordLength) const +{ + return m_backEnd->unlockTpm(password, passwordLength); +} + +ConstBufferPtr +Tpm::exportPrivateKey(const Name& keyName, const char* pw, size_t pwLen) const +{ + return m_backEnd->exportKey(keyName, pw, pwLen); +} + +void +Tpm::importPrivateKey(const Name& keyName, const uint8_t* pkcs8, size_t pkcs8Len, + const char* pw, size_t pwLen) +{ + m_backEnd->importKey(keyName, pkcs8, pkcs8Len, pw, pwLen); +} + +void +Tpm::importPrivateKey(const Name& keyName, shared_ptr key) +{ + m_backEnd->importKey(keyName, std::move(key)); +} + +const KeyHandle* +Tpm::findKey(const Name& keyName) const +{ + auto it = m_keys.find(keyName); + if (it != m_keys.end()) + return it->second.get(); + + auto handle = m_backEnd->getKeyHandle(keyName); + if (handle == nullptr) + return nullptr; + + const KeyHandle* key = handle.get(); + m_keys[keyName] = std::move(handle); + return key; +} + +} // namespace tpm +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/tpm/tpm.hpp b/ndn-cxx/security/tpm/tpm.hpp new file mode 100644 index 000000000..123d9ec7d --- /dev/null +++ b/ndn-cxx/security/tpm/tpm.hpp @@ -0,0 +1,255 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_TPM_TPM_HPP +#define NDN_SECURITY_TPM_TPM_HPP + +#include "ndn-cxx/name.hpp" +#include "ndn-cxx/security/key-params.hpp" +#include "ndn-cxx/security/tpm/key-handle.hpp" + +#include +#include + +namespace ndn { +namespace security { + +namespace transform { +class PrivateKey; +} // namespace transform + +namespace v2 { +class KeyChain; +} // namespace v2 + +namespace tpm { + +class BackEnd; + +/** + * @brief TPM front-end class. + * + * The TPM (Trusted Platform Module) stores the private portion of a user's cryptography keys. + * The format and location of stored information is indicated by the TpmLocator. + * The TPM is designed to work with a PIB (Public Information Base) which stores public keys and + * related information such as certificate. + * + * The TPM also provides functionalities of crypto transformation, such as signing and decryption. + * + * A TPM consists of a unified front-end interface and a back-end implementation. The front-end + * cache the handles of private keys which is provided by the back-end implementation. + * + * @note Tpm instance is created and managed only by v2::KeyChain. v2::KeyChain::getTpm() + * returns a const reference to the managed Tpm instance, through which it is possible to + * check existence of private keys, get public keys for the private keys, sign, and decrypt + * the supplied buffers using managed private keys. + */ +class Tpm : noncopyable +{ +public: + class Error : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + }; + + ~Tpm(); + + std::string + getTpmLocator() const; + + /** + * @brief Check if a private key exists. + * + * @param keyName The key name + * @return true if the key exists + */ + bool + hasKey(const Name& keyName) const; + + /** + * @return The public portion of an asymmetric key with name @p keyName, + * or nullptr if the key does not exist, + * + * The public key is in PKCS#8 format. + */ + ConstBufferPtr + getPublicKey(const Name& keyName) const; + + /** + * @brief Sign blob using the key with name @p keyName and using the digest @p digestAlgorithm. + * + * @return The signature, or nullptr if the key does not exist. + */ + ConstBufferPtr + sign(const uint8_t* buf, size_t size, const Name& keyName, DigestAlgorithm digestAlgorithm) const; + + /** + * @brief Verify blob using the key with name @p keyName and using the digest @p digestAlgorithm. + * + * @retval true the signature is valid + * @retval false the signature is not valid + * @retval indeterminate the key does not exist + */ + boost::logic::tribool + verify(const uint8_t* buf, size_t bufLen, const uint8_t* sig, size_t sigLen, + const Name& keyName, DigestAlgorithm digestAlgorithm) const; + + /** + * @brief Decrypt blob using the key with name @p keyName. + * + * @return The decrypted data, or nullptr if the key does not exist. + */ + ConstBufferPtr + decrypt(const uint8_t* buf, size_t size, const Name& keyName) const; + +public: // Management + /** + * @brief Check if the TPM is in terminal mode. + */ + bool + isTerminalMode() const; + + /** + * @brief Set the terminal mode of the TPM. + * + * When in terminal mode, the TPM will not ask user permission from GUI. + */ + void + setTerminalMode(bool isTerminal) const; + + /** + * @return true if the TPM is locked, otherwise false. + */ + bool + isTpmLocked() const; + + /** + * @brief Unlock the TPM. + * + * @param password The password to unlock the TPM. + * @param passwordLength The password size. + */ + NDN_CXX_NODISCARD bool + unlockTpm(const char* password, size_t passwordLength) const; + +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: + /** + * @brief Create a new TPM instance with the specified @p location. + * + * @param scheme The scheme for the TPM + * @param location The location for the TPM + * @param impl The back-end implementation + */ + Tpm(const std::string& scheme, const std::string& location, unique_ptr impl); + + /** + * @brief Create key for @p identityName according to @p params. + * + * The created key is named as follows: + * - RSA and EC keys: `//KEY/` + * - HMAC keys: `//` + * + * @return The key name. + * @throw Error The key already exists or @p params is invalid. + */ + Name + createKey(const Name& identityName, const KeyParams& params); + + /** + * @brief Delete a key pair with name @p keyName. + */ + void + deleteKey(const Name& keyName); + + /** + * @brief Export a private key. + * + * Export a private key in encrypted PKCS #8 format. + * + * @param keyName The private key name + * @param pw The password to encrypt the private key + * @param pwLen The length of the password + * @return The encoded private key wrapper. + * @throw Error The key does not exist or it could not be exported. + */ + ConstBufferPtr + exportPrivateKey(const Name& keyName, const char* pw, size_t pwLen) const; + + /** + * @brief Import a private key. + * + * @param keyName The private key name + * @param pkcs8 The private key wrapper + * @param pkcs8Len The length of the private key wrapper + * @param pw The password to encrypt the private key + * @param pwLen The length of the password + * @throw Error The key could not be imported. + */ + void + importPrivateKey(const Name& keyName, const uint8_t* pkcs8, size_t pkcs8Len, + const char* pw, size_t pwLen); + + /** + * @brief Import a private key. + */ + void + importPrivateKey(const Name& keyName, shared_ptr key); + + /** + * @brief Clear the key cache. + * + * An empty cache can force Tpm to do key lookup in the back-end. + */ + void + clearKeyCache() + { + m_keys.clear(); + } + +private: + /** + * @brief Internal KeyHandle lookup. + * + * @return A pointer to the handle of key @p keyName if it exists, otherwise nullptr. + */ + const KeyHandle* + findKey(const Name& keyName) const; + +private: + std::string m_scheme; + std::string m_location; + + mutable std::unordered_map> m_keys; + + const unique_ptr m_backEnd; + + friend class v2::KeyChain; +}; + +} // namespace tpm + +using tpm::Tpm; + +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_TPM_TPM_HPP diff --git a/ndn-cxx/security/transform.hpp b/ndn-cxx/security/transform.hpp new file mode 100644 index 000000000..91fda3b3a --- /dev/null +++ b/ndn-cxx/security/transform.hpp @@ -0,0 +1,45 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_SECURITY_TRANSFORM_HPP +#define NDN_CXX_SECURITY_TRANSFORM_HPP + +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/step-source.hpp" +#include "ndn-cxx/security/transform/stream-source.hpp" + +#include "ndn-cxx/security/transform/bool-sink.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" + +#include "ndn-cxx/security/transform/base64-decode.hpp" +#include "ndn-cxx/security/transform/base64-encode.hpp" +#include "ndn-cxx/security/transform/hex-decode.hpp" +#include "ndn-cxx/security/transform/hex-encode.hpp" +#include "ndn-cxx/security/transform/strip-space.hpp" + +#include "ndn-cxx/security/transform/block-cipher.hpp" +#include "ndn-cxx/security/transform/digest-filter.hpp" +#include "ndn-cxx/security/transform/private-key.hpp" +#include "ndn-cxx/security/transform/public-key.hpp" +#include "ndn-cxx/security/transform/signer-filter.hpp" +#include "ndn-cxx/security/transform/verifier-filter.hpp" + +#endif // NDN_CXX_SECURITY_TRANSFORM_HPP diff --git a/src/security/transform/base64-decode.cpp b/ndn-cxx/security/transform/base64-decode.cpp similarity index 89% rename from src/security/transform/base64-decode.cpp rename to ndn-cxx/security/transform/base64-decode.cpp index 8b047bcee..5b4de2531 100644 --- a/src/security/transform/base64-decode.cpp +++ b/ndn-cxx/security/transform/base64-decode.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,9 +19,8 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "base64-decode.hpp" -#include "../../encoding/buffer.hpp" -#include "../detail/openssl.hpp" +#include "ndn-cxx/security/transform/base64-decode.hpp" +#include "ndn-cxx/security/impl/openssl.hpp" namespace ndn { namespace security { @@ -59,12 +58,14 @@ class Base64Decode::Impl static const size_t BUFFER_LENGTH = 1024; Base64Decode::Base64Decode(bool expectNewlineEvery64Bytes) - : m_impl(new Impl) + : m_impl(make_unique()) { if (!expectNewlineEvery64Bytes) BIO_set_flags(m_impl->m_base64, BIO_FLAGS_BASE64_NO_NL); } +Base64Decode::~Base64Decode() = default; + void Base64Decode::preTransform() { @@ -85,7 +86,7 @@ Base64Decode::convert(const uint8_t* buf, size_t size) if (wLen <= 0) { // fail to write data if (!BIO_should_retry(m_impl->m_source)) { // we haven't written everything but some error happens, and we cannot retry - BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to accept more input")); + NDN_THROW(Error(getIndex(), "Failed to accept more input")); } return 0; } @@ -114,7 +115,7 @@ Base64Decode::fillOutputBuffer() // OpenSSL base64 BIO cannot give us the number bytes of partial decoded result, // so we just try to read a chunk. auto buffer = make_unique(BUFFER_LENGTH); - int rLen = BIO_read(m_impl->m_base64, &(*buffer)[0], buffer->size()); + int rLen = BIO_read(m_impl->m_base64, buffer->data(), buffer->size()); if (rLen <= 0) return; diff --git a/src/security/transform/base64-decode.hpp b/ndn-cxx/security/transform/base64-decode.hpp similarity index 92% rename from src/security/transform/base64-decode.hpp rename to ndn-cxx/security/transform/base64-decode.hpp index cfd5876dd..b7fdbe325 100644 --- a/src/security/transform/base64-decode.hpp +++ b/ndn-cxx/security/transform/base64-decode.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,7 +22,7 @@ #ifndef NDN_CXX_SECURITY_TRANSFORM_BASE64_DECODE_HPP #define NDN_CXX_SECURITY_TRANSFORM_BASE64_DECODE_HPP -#include "transform-base.hpp" +#include "ndn-cxx/security/transform/transform-base.hpp" namespace ndn { namespace security { @@ -44,12 +44,13 @@ class Base64Decode : public Transform explicit Base64Decode(bool expectNewlineEvery64Bytes = true); -private: + ~Base64Decode(); +private: /** * @brief Read partial transformation results into output buffer and write them into next module. */ - virtual void + void preTransform() final; /** @@ -57,7 +58,7 @@ class Base64Decode : public Transform * * @return number of bytes that have been accepted by the converter */ - virtual size_t + size_t convert(const uint8_t* buf, size_t size) final; /** @@ -65,7 +66,7 @@ class Base64Decode : public Transform * * This method with read all decoding results from the converter and write them into next module. */ - virtual void + void finalize() final; /** @@ -76,7 +77,7 @@ class Base64Decode : public Transform private: class Impl; - unique_ptr m_impl; + const unique_ptr m_impl; }; unique_ptr diff --git a/src/security/transform/base64-encode.cpp b/ndn-cxx/security/transform/base64-encode.cpp similarity index 87% rename from src/security/transform/base64-encode.cpp rename to ndn-cxx/security/transform/base64-encode.cpp index 60bc25fdd..f5813007e 100644 --- a/src/security/transform/base64-encode.cpp +++ b/ndn-cxx/security/transform/base64-encode.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,9 +19,8 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "base64-encode.hpp" -#include "../../encoding/buffer.hpp" -#include "../detail/openssl.hpp" +#include "ndn-cxx/security/transform/base64-encode.hpp" +#include "ndn-cxx/security/impl/openssl.hpp" namespace ndn { namespace security { @@ -53,12 +52,14 @@ class Base64Encode::Impl }; Base64Encode::Base64Encode(bool needBreak) - : m_impl(new Impl) + : m_impl(make_unique()) { if (!needBreak) BIO_set_flags(m_impl->m_base64, BIO_FLAGS_BASE64_NO_NL); } +Base64Encode::~Base64Encode() = default; + void Base64Encode::preTransform() { @@ -76,7 +77,7 @@ Base64Encode::convert(const uint8_t* data, size_t dataLen) if (wLen <= 0) { // fail to write data if (!BIO_should_retry(m_impl->m_base64)) { // we haven't written everything but some error happens, and we cannot retry - BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to accept more input")); + NDN_THROW(Error(getIndex(), "Failed to accept more input")); } return 0; } @@ -90,7 +91,7 @@ void Base64Encode::finalize() { if (BIO_flush(m_impl->m_base64) != 1) - BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to flush")); + NDN_THROW(Error(getIndex(), "Failed to flush")); while (!isConverterEmpty()) { fillOutputBuffer(); @@ -109,7 +110,7 @@ Base64Encode::fillOutputBuffer() // there is something to read from BIO auto buffer = make_unique(nRead); - int rLen = BIO_read(m_impl->m_sink, &(*buffer)[0], nRead); + int rLen = BIO_read(m_impl->m_sink, buffer->data(), nRead); if (rLen < 0) return; diff --git a/src/security/transform/base64-encode.hpp b/ndn-cxx/security/transform/base64-encode.hpp similarity index 90% rename from src/security/transform/base64-encode.hpp rename to ndn-cxx/security/transform/base64-encode.hpp index ac9c664ad..145d36c39 100644 --- a/src/security/transform/base64-encode.hpp +++ b/ndn-cxx/security/transform/base64-encode.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,7 +22,7 @@ #ifndef NDN_CXX_SECURITY_TRANSFORM_BASE64_ENCODE_HPP #define NDN_CXX_SECURITY_TRANSFORM_BASE64_ENCODE_HPP -#include "transform-base.hpp" +#include "ndn-cxx/security/transform/transform-base.hpp" namespace ndn { namespace security { @@ -42,18 +42,20 @@ class Base64Encode : public Transform explicit Base64Encode(bool needBreak = true); + ~Base64Encode(); + private: /** * @brief Read partial transformation result (if exists) from BIO */ - virtual void + void preTransform() final; /** - * @brief Encode @data into base64 format. + * @brief Encode @p data into base64 format. * @return The number of input bytes that have been accepted by the converter. */ - virtual size_t + size_t convert(const uint8_t* data, size_t dataLen) final; /** @@ -61,7 +63,7 @@ class Base64Encode : public Transform * * This method with read all encoding results from the converter and write them into next module. */ - virtual void + void finalize() final; /** @@ -78,7 +80,7 @@ class Base64Encode : public Transform private: class Impl; - unique_ptr m_impl; + const unique_ptr m_impl; }; unique_ptr diff --git a/ndn-cxx/security/transform/block-cipher.cpp b/ndn-cxx/security/transform/block-cipher.cpp new file mode 100644 index 000000000..985720e5e --- /dev/null +++ b/ndn-cxx/security/transform/block-cipher.cpp @@ -0,0 +1,169 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/transform/block-cipher.hpp" +#include "ndn-cxx/security/impl/openssl.hpp" + +#include + +namespace ndn { +namespace security { +namespace transform { + +class BlockCipher::Impl +{ +public: + Impl() noexcept + : m_cipher(BIO_new(BIO_f_cipher())) + , m_sink(BIO_new(BIO_s_mem())) + { + BIO_push(m_cipher, m_sink); + } + + ~Impl() + { + BIO_free_all(m_cipher); + } + +public: + BIO* m_cipher; + BIO* m_sink; // BIO_f_cipher alone does not work without a sink +}; + + +BlockCipher::BlockCipher(BlockCipherAlgorithm algo, CipherOperator op, + const uint8_t* key, size_t keyLen, + const uint8_t* iv, size_t ivLen) + : m_impl(make_unique()) +{ + switch (algo) { + case BlockCipherAlgorithm::AES_CBC: + initializeAesCbc(key, keyLen, iv, ivLen, op); + break; + default: + NDN_THROW(Error(getIndex(), "Unsupported block cipher algorithm " + + boost::lexical_cast(algo))); + } +} + +BlockCipher::~BlockCipher() = default; + +void +BlockCipher::preTransform() +{ + fillOutputBuffer(); +} + +size_t +BlockCipher::convert(const uint8_t* data, size_t dataLen) +{ + if (dataLen == 0) + return 0; + + int wLen = BIO_write(m_impl->m_cipher, data, dataLen); + + if (wLen <= 0) { // failed to write data + if (!BIO_should_retry(m_impl->m_cipher)) { + // we haven't written everything but some error happens, and we cannot retry + NDN_THROW(Error(getIndex(), "Failed to accept more input")); + } + return 0; + } + else { // update number of bytes written + fillOutputBuffer(); + return static_cast(wLen); + } +} + +void +BlockCipher::finalize() +{ + if (BIO_flush(m_impl->m_cipher) != 1) + NDN_THROW(Error(getIndex(), "Failed to flush")); + + while (!isConverterEmpty()) { + fillOutputBuffer(); + while (!isOutputBufferEmpty()) { + flushOutputBuffer(); + } + } +} + +void +BlockCipher::fillOutputBuffer() +{ + int nPending = BIO_pending(m_impl->m_sink); + if (nPending <= 0) + return; + + // there is something to read from BIO + auto buffer = make_unique(nPending); + int nRead = BIO_read(m_impl->m_sink, buffer->data(), nPending); + if (nRead < 0) + return; + + buffer->erase(buffer->begin() + nRead, buffer->end()); + setOutputBuffer(std::move(buffer)); +} + +bool +BlockCipher::isConverterEmpty() const +{ + return BIO_pending(m_impl->m_sink) <= 0; +} + +void +BlockCipher::initializeAesCbc(const uint8_t* key, size_t keyLen, + const uint8_t* iv, size_t ivLen, CipherOperator op) +{ + const EVP_CIPHER* cipherType = nullptr; + switch (keyLen) { + case 16: + cipherType = EVP_aes_128_cbc(); + break; + case 24: + cipherType = EVP_aes_192_cbc(); + break; + case 32: + cipherType = EVP_aes_256_cbc(); + break; + default: + NDN_THROW(Error(getIndex(), "Unsupported key length " + to_string(keyLen))); + } + + size_t requiredIvLen = static_cast(EVP_CIPHER_iv_length(cipherType)); + if (ivLen != requiredIvLen) + NDN_THROW(Error(getIndex(), "IV length must be " + to_string(requiredIvLen))); + + BIO_set_cipher(m_impl->m_cipher, cipherType, key, iv, op == CipherOperator::ENCRYPT ? 1 : 0); +} + +unique_ptr +blockCipher(BlockCipherAlgorithm algo, CipherOperator op, + const uint8_t* key, size_t keyLen, + const uint8_t* iv, size_t ivLen) +{ + return make_unique(algo, op, key, keyLen, iv, ivLen); +} + +} // namespace transform +} // namespace security +} // namespace ndn diff --git a/src/security/transform/block-cipher.hpp b/ndn-cxx/security/transform/block-cipher.hpp similarity index 75% rename from src/security/transform/block-cipher.hpp rename to ndn-cxx/security/transform/block-cipher.hpp index dd67858c5..3ea5ba5c2 100644 --- a/src/security/transform/block-cipher.hpp +++ b/ndn-cxx/security/transform/block-cipher.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,8 +22,8 @@ #ifndef NDN_CXX_SECURITY_TRANSFORM_BLOCK_CIPHER_HPP #define NDN_CXX_SECURITY_TRANSFORM_BLOCK_CIPHER_HPP -#include "transform-base.hpp" -#include "../security-common.hpp" +#include "ndn-cxx/security/transform/transform-base.hpp" +#include "ndn-cxx/security/security-common.hpp" namespace ndn { namespace security { @@ -32,7 +32,7 @@ namespace transform { /** * @brief The module to encrypt data using block cipher. * - * The padding scheme of the block cipher is set to the default padding scheme of OpenSSl, + * The padding scheme of the block cipher is set to the OpenSSL default, * which is PKCS padding. */ class BlockCipher : public Transform @@ -41,22 +41,24 @@ class BlockCipher : public Transform /** * @brief Create a block cipher * - * @param algo The block cipher algorithm (e.g., EncryptMode::AES_CBC). - * @param op The operation that the cipher needs to perform, e.g., CipherOperator::ENCRYPT or CipherOperator::DECRYPT - * @param key The pointer to the key. - * @param keyLen The size of the key. - * @param iv The pointer to the initial vector. - * @param ivLen The length of the initial vector. + * @param algo The block cipher algorithm to use. + * @param op Whether to encrypt or decrypt. + * @param key Pointer to the key. + * @param keyLen Size of the key. + * @param iv Pointer to the initialization vector. + * @param ivLen Length of the initialization vector. */ BlockCipher(BlockCipherAlgorithm algo, CipherOperator op, const uint8_t* key, size_t keyLen, const uint8_t* iv, size_t ivLen); + ~BlockCipher(); + private: /** * @brief Read partial transformation result (if exists) from BIO */ - virtual void + void preTransform() final; /** @@ -64,13 +66,13 @@ class BlockCipher : public Transform * * @return number of bytes that are actually accepted */ - virtual size_t + size_t convert(const uint8_t* data, size_t dataLen) final; /** * @brief Finalize the encryption */ - virtual void + void finalize() final; /** @@ -86,15 +88,13 @@ class BlockCipher : public Transform isConverterEmpty() const; private: - void initializeAesCbc(const uint8_t* key, size_t keyLen, - const uint8_t* iv, size_t ivLen, - CipherOperator op); + const uint8_t* iv, size_t ivLen, CipherOperator op); private: class Impl; - unique_ptr m_impl; + const unique_ptr m_impl; }; unique_ptr diff --git a/src/security/transform/bool-sink.cpp b/ndn-cxx/security/transform/bool-sink.cpp similarity index 92% rename from src/security/transform/bool-sink.cpp rename to ndn-cxx/security/transform/bool-sink.cpp index 1c45c76de..0c702e7f1 100644 --- a/src/security/transform/bool-sink.cpp +++ b/ndn-cxx/security/transform/bool-sink.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,7 +19,7 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "bool-sink.hpp" +#include "ndn-cxx/security/transform/bool-sink.hpp" namespace ndn { namespace security { diff --git a/src/security/transform/bool-sink.hpp b/ndn-cxx/security/transform/bool-sink.hpp similarity index 93% rename from src/security/transform/bool-sink.hpp rename to ndn-cxx/security/transform/bool-sink.hpp index 12e62c9ed..c270543fe 100644 --- a/src/security/transform/bool-sink.hpp +++ b/ndn-cxx/security/transform/bool-sink.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,7 +22,7 @@ #ifndef NDN_CXX_SECURITY_TRANSFORM_BOOL_SINK_HPP #define NDN_CXX_SECURITY_TRANSFORM_BOOL_SINK_HPP -#include "transform-base.hpp" +#include "ndn-cxx/security/transform/transform-base.hpp" namespace ndn { namespace security { @@ -49,13 +49,13 @@ class BoolSink : public Sink * * @return the same value as @p size. */ - virtual size_t + size_t doWrite(const uint8_t* buf, size_t size) final; /** * @brief Finalize sink processing */ - virtual void + void doEnd() final; private: diff --git a/src/security/transform/buffer-source.cpp b/ndn-cxx/security/transform/buffer-source.cpp similarity index 91% rename from src/security/transform/buffer-source.cpp rename to ndn-cxx/security/transform/buffer-source.cpp index b47e85562..95fd2d7bd 100644 --- a/src/security/transform/buffer-source.cpp +++ b/ndn-cxx/security/transform/buffer-source.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,7 +19,7 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "buffer-source.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" namespace ndn { namespace security { @@ -38,7 +38,7 @@ BufferSource::BufferSource(const std::string& string) } BufferSource::BufferSource(const Buffer& buffer) - : m_buf(buffer.buf()) + : m_buf(buffer.data()) , m_size(buffer.size()) { } diff --git a/src/security/transform/buffer-source.hpp b/ndn-cxx/security/transform/buffer-source.hpp similarity index 92% rename from src/security/transform/buffer-source.hpp rename to ndn-cxx/security/transform/buffer-source.hpp index 0833a0ff6..61199994b 100644 --- a/src/security/transform/buffer-source.hpp +++ b/ndn-cxx/security/transform/buffer-source.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,8 +22,8 @@ #ifndef NDN_CXX_SECURITY_TRANSFORM_BUFFER_SOURCE_HPP #define NDN_CXX_SECURITY_TRANSFORM_BUFFER_SOURCE_HPP -#include "transform-base.hpp" -#include "../../encoding/buffer.hpp" +#include "ndn-cxx/security/transform/transform-base.hpp" +#include "ndn-cxx/encoding/buffer.hpp" namespace ndn { namespace security { @@ -62,7 +62,7 @@ class BufferSource : public Source /** * @brief Write the whole buffer into the next module. */ - virtual void + void doPump() final; private: diff --git a/ndn-cxx/security/transform/digest-filter.cpp b/ndn-cxx/security/transform/digest-filter.cpp new file mode 100644 index 000000000..2293739c6 --- /dev/null +++ b/ndn-cxx/security/transform/digest-filter.cpp @@ -0,0 +1,83 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/transform/digest-filter.hpp" +#include "ndn-cxx/security/impl/openssl-helper.hpp" + +#include + +namespace ndn { +namespace security { +namespace transform { + +class DigestFilter::Impl +{ +public: + detail::EvpMdCtx ctx; +}; + + +DigestFilter::DigestFilter(DigestAlgorithm algo) + : m_impl(make_unique()) +{ + const EVP_MD* md = detail::digestAlgorithmToEvpMd(algo); + if (md == nullptr) + NDN_THROW(Error(getIndex(), "Unsupported digest algorithm " + boost::lexical_cast(algo))); + + if (EVP_DigestInit_ex(m_impl->ctx, md, nullptr) == 0) + NDN_THROW(Error(getIndex(), "Cannot initialize digest " + boost::lexical_cast(algo))); +} + +DigestFilter::~DigestFilter() = default; + +size_t +DigestFilter::convert(const uint8_t* buf, size_t size) +{ + if (EVP_DigestUpdate(m_impl->ctx, buf, size) == 0) + NDN_THROW(Error(getIndex(), "Failed to accept more input")); + + return size; +} + +void +DigestFilter::finalize() +{ + auto buffer = make_unique(EVP_MAX_MD_SIZE); + unsigned int mdLen = 0; + + if (EVP_DigestFinal_ex(m_impl->ctx, buffer->data(), &mdLen) == 0) + NDN_THROW(Error(getIndex(), "Failed to finalize digest")); + + buffer->erase(buffer->begin() + mdLen, buffer->end()); + setOutputBuffer(std::move(buffer)); + + flushAllOutput(); +} + +unique_ptr +digestFilter(DigestAlgorithm algo) +{ + return make_unique(algo); +} + +} // namespace transform +} // namespace security +} // namespace ndn diff --git a/src/security/transform/digest-filter.hpp b/ndn-cxx/security/transform/digest-filter.hpp similarity index 86% rename from src/security/transform/digest-filter.hpp rename to ndn-cxx/security/transform/digest-filter.hpp index 935899f6c..4a26bf01e 100644 --- a/src/security/transform/digest-filter.hpp +++ b/ndn-cxx/security/transform/digest-filter.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,8 +22,8 @@ #ifndef NDN_CXX_SECURITY_TRANSFORM_DIGEST_FILTER_HPP #define NDN_CXX_SECURITY_TRANSFORM_DIGEST_FILTER_HPP -#include "transform-base.hpp" -#include "../security-common.hpp" +#include "ndn-cxx/security/transform/transform-base.hpp" +#include "ndn-cxx/security/security-common.hpp" namespace ndn { namespace security { @@ -41,28 +41,30 @@ class DigestFilter : public Transform explicit DigestFilter(DigestAlgorithm algo); + ~DigestFilter(); + private: /** * @brief Append data @p buf into digest calculation * * @return The number of bytes that have been accepted */ - virtual size_t + size_t convert(const uint8_t* buf, size_t size) final; /** * @brief Finalize digest calculation and write the digest into next module. */ - virtual void + void finalize() final; private: class Impl; - unique_ptr m_impl; + const unique_ptr m_impl; }; unique_ptr -digestFilter(DigestAlgorithm algo = DigestAlgorithm::SHA256); +digestFilter(DigestAlgorithm algo); } // namespace transform } // namespace security diff --git a/src/security/transform/hex-decode.cpp b/ndn-cxx/security/transform/hex-decode.cpp similarity index 85% rename from src/security/transform/hex-decode.cpp rename to ndn-cxx/security/transform/hex-decode.cpp index aa82461e8..9a91ee6b7 100644 --- a/src/security/transform/hex-decode.cpp +++ b/ndn-cxx/security/transform/hex-decode.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,13 +19,14 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "hex-decode.hpp" +#include "ndn-cxx/security/transform/hex-decode.hpp" namespace ndn { namespace security { namespace transform { -static const int8_t C2H[256] = { // hex decoding pad. +// hex decoding pad +static const int8_t C2H[] = { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0-15 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16-31 @@ -44,6 +45,8 @@ static const int8_t C2H[256] = { // hex decoding pad. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 224-239 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 240-255 }; +static_assert(std::extent::value == 256, ""); + HexDecode::HexDecode() : m_hasOddByte(false) @@ -74,7 +77,7 @@ void HexDecode::finalize() { if (m_hasOddByte) - BOOST_THROW_EXCEPTION(Error(getIndex(), "Incomplete input")); + NDN_THROW(Error(getIndex(), "Incomplete input")); } unique_ptr @@ -82,24 +85,24 @@ HexDecode::toBytes(const uint8_t* hex, size_t hexLen) { size_t bufferSize = (hexLen + (m_hasOddByte ? 1 : 0)) >> 1; auto buffer = make_unique(bufferSize); - uint8_t* buf = &buffer->front(); + auto it = buffer->begin(); if (m_hasOddByte) { if (C2H[hex[0]] < 0 || C2H[m_oddByte] < 0) - BOOST_THROW_EXCEPTION(Error(getIndex(), "Wrong input byte")); + NDN_THROW(Error(getIndex(), "Wrong input byte")); - buf[0] = (C2H[m_oddByte] << 4) + (C2H[hex[0]]); - buf += 1; + *it = (C2H[m_oddByte] << 4) + C2H[hex[0]]; + ++it; hex += 1; hexLen -= 1; } - while (hexLen > 1) { + while (hexLen >= 2) { if (C2H[hex[0]] < 0 || C2H[hex[1]] < 0) - BOOST_THROW_EXCEPTION(Error(getIndex(), "Wrong input byte")); + NDN_THROW(Error(getIndex(), "Wrong input byte")); - buf[0] = (C2H[hex[0]] << 4) + (C2H[hex[1]]); - buf += 1; + *it = (C2H[hex[0]] << 4) + C2H[hex[1]]; + ++it; hex += 2; hexLen -= 2; } diff --git a/src/security/transform/hex-decode.hpp b/ndn-cxx/security/transform/hex-decode.hpp similarity index 93% rename from src/security/transform/hex-decode.hpp rename to ndn-cxx/security/transform/hex-decode.hpp index 77d477d3d..d57be64d5 100644 --- a/src/security/transform/hex-decode.hpp +++ b/ndn-cxx/security/transform/hex-decode.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,7 +22,7 @@ #ifndef NDN_CXX_SECURITY_TRANSFORM_HEX_DECODE_HPP #define NDN_CXX_SECURITY_TRANSFORM_HEX_DECODE_HPP -#include "transform-base.hpp" +#include "ndn-cxx/security/transform/transform-base.hpp" namespace ndn { namespace security { @@ -50,13 +50,13 @@ class HexDecode : public Transform * * @return number of input bytes that are accepted */ - virtual size_t + size_t convert(const uint8_t* buf, size_t size) final; /** * @throws Error if pending byte exists. */ - virtual void + void finalize() final; /** diff --git a/src/security/transform/hex-encode.cpp b/ndn-cxx/security/transform/hex-encode.cpp similarity index 78% rename from src/security/transform/hex-encode.cpp rename to ndn-cxx/security/transform/hex-encode.cpp index 6d54f0e04..219e14ed9 100644 --- a/src/security/transform/hex-encode.cpp +++ b/ndn-cxx/security/transform/hex-encode.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,21 +19,24 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "hex-encode.hpp" +#include "ndn-cxx/security/transform/hex-encode.hpp" namespace ndn { namespace security { namespace transform { -static const char H2CL[16] = { +static const uint8_t H2CL[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; +static_assert(std::extent::value == 16, ""); -static const char H2CU[16] = { +static const uint8_t H2CU[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; +static_assert(std::extent::value == 16, ""); + HexEncode::HexEncode(bool useUpperCase) : m_useUpperCase(useUpperCase) @@ -50,21 +53,19 @@ HexEncode::convert(const uint8_t* data, size_t dataLen) unique_ptr HexEncode::toHex(const uint8_t* data, size_t dataLen) { - const char* encodePad = (m_useUpperCase) ? H2CU : H2CL; - auto encoded = make_unique(dataLen * 2); - uint8_t* buf = &encoded->front(); + uint8_t* buf = encoded->data(); + const uint8_t* encodePad = m_useUpperCase ? H2CU : H2CL; + for (size_t i = 0; i < dataLen; i++) { - buf[0] = encodePad[((data[i] >> 4) & 0x0F)]; - buf++; - buf[0] = encodePad[(data[i] & 0x0F)]; - buf++; + buf[0] = encodePad[(data[i] >> 4) & 0x0F]; + buf[1] = encodePad[data[i] & 0x0F]; + buf += 2; } + return encoded; } - - unique_ptr hexEncode(bool useUpperCase) { diff --git a/src/security/transform/hex-encode.hpp b/ndn-cxx/security/transform/hex-encode.hpp similarity index 94% rename from src/security/transform/hex-encode.hpp rename to ndn-cxx/security/transform/hex-encode.hpp index 95fc6e884..a395616b4 100644 --- a/src/security/transform/hex-encode.hpp +++ b/ndn-cxx/security/transform/hex-encode.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,7 +22,7 @@ #ifndef NDN_CXX_SECURITY_TRANSFORM_HEX_ENCODE_HPP #define NDN_CXX_SECURITY_TRANSFORM_HEX_ENCODE_HPP -#include "transform-base.hpp" +#include "ndn-cxx/security/transform/transform-base.hpp" namespace ndn { namespace security { @@ -51,7 +51,7 @@ class HexEncode : public Transform * * @return The number of input bytes that have been accepted by the converter. */ - virtual size_t + size_t convert(const uint8_t* data, size_t dataLen) final; /** diff --git a/ndn-cxx/security/transform/private-key.cpp b/ndn-cxx/security/transform/private-key.cpp new file mode 100644 index 000000000..659de1169 --- /dev/null +++ b/ndn-cxx/security/transform/private-key.cpp @@ -0,0 +1,559 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/transform/private-key.hpp" +#include "ndn-cxx/security/transform/base64-decode.hpp" +#include "ndn-cxx/security/transform/base64-encode.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/digest-filter.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" +#include "ndn-cxx/security/transform/stream-source.hpp" +#include "ndn-cxx/security/impl/openssl-helper.hpp" +#include "ndn-cxx/security/key-params.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/util/random.hpp" + +#include +#include + +#define ENSURE_PRIVATE_KEY_LOADED(key) \ + do { \ + if ((key) == nullptr) \ + NDN_THROW(Error("Private key has not been loaded yet")); \ + } while (false) + +#define ENSURE_PRIVATE_KEY_NOT_LOADED(key) \ + do { \ + if ((key) != nullptr) \ + NDN_THROW(Error("Private key has already been loaded")); \ + } while (false) + +namespace ndn { +namespace security { +namespace transform { + +static void +opensslInitAlgorithms() +{ +#if OPENSSL_VERSION_NUMBER < 0x1010000fL + static bool isInitialized = false; + if (!isInitialized) { + OpenSSL_add_all_algorithms(); + isInitialized = true; + } +#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL +} + +class PrivateKey::Impl : noncopyable +{ +public: + ~Impl() + { + EVP_PKEY_free(key); + } + +public: + EVP_PKEY* key = nullptr; + +#if OPENSSL_VERSION_NUMBER < 0x1010100fL + size_t keySize = 0; // in bits, used only for HMAC +#endif +}; + +PrivateKey::PrivateKey() + : m_impl(make_unique()) +{ +} + +PrivateKey::~PrivateKey() = default; + +KeyType +PrivateKey::getKeyType() const +{ + if (!m_impl->key) + return KeyType::NONE; + + switch (detail::getEvpPkeyType(m_impl->key)) { + case EVP_PKEY_RSA: + return KeyType::RSA; + case EVP_PKEY_EC: + return KeyType::EC; + case EVP_PKEY_HMAC: + return KeyType::HMAC; + default: + return KeyType::NONE; + } +} + +size_t +PrivateKey::getKeySize() const +{ + switch (getKeyType()) { + case KeyType::RSA: + case KeyType::EC: + return static_cast(EVP_PKEY_bits(m_impl->key)); + case KeyType::HMAC: { +#if OPENSSL_VERSION_NUMBER >= 0x1010100fL + size_t nBytes = 0; + EVP_PKEY_get_raw_private_key(m_impl->key, nullptr, &nBytes); + return nBytes * 8; +#else + return m_impl->keySize; +#endif + } + default: + return 0; + } +} + +ConstBufferPtr +PrivateKey::getKeyDigest(DigestAlgorithm algo) const +{ + if (getKeyType() != KeyType::HMAC) + NDN_THROW(Error("Digest is not supported for key type " + + boost::lexical_cast(getKeyType()))); + + const uint8_t* buf = nullptr; + size_t len = 0; +#if OPENSSL_VERSION_NUMBER >= 0x1010000fL + buf = EVP_PKEY_get0_hmac(m_impl->key, &len); +#else + const auto* octstr = reinterpret_cast(EVP_PKEY_get0(m_impl->key)); + buf = octstr->data; + len = octstr->length; +#endif + if (buf == nullptr) + NDN_THROW(Error("Failed to obtain raw key pointer")); + if (len * 8 != getKeySize()) + NDN_THROW(Error("Key length mismatch")); + + OBufferStream os; + bufferSource(buf, len) >> digestFilter(algo) >> streamSink(os); + return os.buf(); +} + +void +PrivateKey::loadRaw(KeyType type, const uint8_t* buf, size_t size) +{ + ENSURE_PRIVATE_KEY_NOT_LOADED(m_impl->key); + + int pkeyType; + switch (type) { + case KeyType::HMAC: + pkeyType = EVP_PKEY_HMAC; + break; + default: + NDN_THROW(std::invalid_argument("Unsupported key type " + boost::lexical_cast(type))); + } + + m_impl->key = +#if OPENSSL_VERSION_NUMBER >= 0x1010100fL + EVP_PKEY_new_raw_private_key(pkeyType, nullptr, buf, size); +#else + EVP_PKEY_new_mac_key(pkeyType, nullptr, buf, static_cast(size)); +#endif + if (m_impl->key == nullptr) + NDN_THROW(Error("Failed to load private key")); + +#if OPENSSL_VERSION_NUMBER < 0x1010100fL + m_impl->keySize = size * 8; +#endif +} + +void +PrivateKey::loadPkcs1(const uint8_t* buf, size_t size) +{ + ENSURE_PRIVATE_KEY_NOT_LOADED(m_impl->key); + opensslInitAlgorithms(); + + if (d2i_AutoPrivateKey(&m_impl->key, &buf, static_cast(size)) == nullptr) + NDN_THROW(Error("Failed to load private key")); +} + +void +PrivateKey::loadPkcs1(std::istream& is) +{ + OBufferStream os; + streamSource(is) >> streamSink(os); + this->loadPkcs1(os.buf()->data(), os.buf()->size()); +} + +void +PrivateKey::loadPkcs1Base64(const uint8_t* buf, size_t size) +{ + OBufferStream os; + bufferSource(buf, size) >> base64Decode() >> streamSink(os); + this->loadPkcs1(os.buf()->data(), os.buf()->size()); +} + +void +PrivateKey::loadPkcs1Base64(std::istream& is) +{ + OBufferStream os; + streamSource(is) >> base64Decode() >> streamSink(os); + this->loadPkcs1(os.buf()->data(), os.buf()->size()); +} + +void +PrivateKey::loadPkcs8(const uint8_t* buf, size_t size, const char* pw, size_t pwLen) +{ + BOOST_ASSERT(std::strlen(pw) == pwLen); + ENSURE_PRIVATE_KEY_NOT_LOADED(m_impl->key); + opensslInitAlgorithms(); + + detail::Bio membio(BIO_s_mem()); + if (!membio.write(buf, size)) + NDN_THROW(Error("Failed to copy buffer")); + + if (d2i_PKCS8PrivateKey_bio(membio, &m_impl->key, nullptr, const_cast(pw)) == nullptr) + NDN_THROW(Error("Failed to load private key")); +} + +static inline int +passwordCallbackWrapper(char* buf, int size, int rwflag, void* u) +{ + BOOST_ASSERT(size >= 0); + auto cb = reinterpret_cast(u); + return (*cb)(buf, static_cast(size), rwflag); +} + +void +PrivateKey::loadPkcs8(const uint8_t* buf, size_t size, PasswordCallback pwCallback) +{ + ENSURE_PRIVATE_KEY_NOT_LOADED(m_impl->key); + opensslInitAlgorithms(); + + detail::Bio membio(BIO_s_mem()); + if (!membio.write(buf, size)) + NDN_THROW(Error("Failed to copy buffer")); + + if (pwCallback) + m_impl->key = d2i_PKCS8PrivateKey_bio(membio, nullptr, &passwordCallbackWrapper, &pwCallback); + else + m_impl->key = d2i_PKCS8PrivateKey_bio(membio, nullptr, nullptr, nullptr); + + if (m_impl->key == nullptr) + NDN_THROW(Error("Failed to load private key")); +} + +void +PrivateKey::loadPkcs8(std::istream& is, const char* pw, size_t pwLen) +{ + OBufferStream os; + streamSource(is) >> streamSink(os); + this->loadPkcs8(os.buf()->data(), os.buf()->size(), pw, pwLen); +} + +void +PrivateKey::loadPkcs8(std::istream& is, PasswordCallback pwCallback) +{ + OBufferStream os; + streamSource(is) >> streamSink(os); + this->loadPkcs8(os.buf()->data(), os.buf()->size(), pwCallback); +} + +void +PrivateKey::loadPkcs8Base64(const uint8_t* buf, size_t size, const char* pw, size_t pwLen) +{ + OBufferStream os; + bufferSource(buf, size) >> base64Decode() >> streamSink(os); + this->loadPkcs8(os.buf()->data(), os.buf()->size(), pw, pwLen); +} + +void +PrivateKey::loadPkcs8Base64(const uint8_t* buf, size_t size, PasswordCallback pwCallback) +{ + OBufferStream os; + bufferSource(buf, size) >> base64Decode() >> streamSink(os); + this->loadPkcs8(os.buf()->data(), os.buf()->size(), pwCallback); +} + +void +PrivateKey::loadPkcs8Base64(std::istream& is, const char* pw, size_t pwLen) +{ + OBufferStream os; + streamSource(is) >> base64Decode() >> streamSink(os); + this->loadPkcs8(os.buf()->data(), os.buf()->size(), pw, pwLen); +} + +void +PrivateKey::loadPkcs8Base64(std::istream& is, PasswordCallback pwCallback) +{ + OBufferStream os; + streamSource(is) >> base64Decode() >> streamSink(os); + this->loadPkcs8(os.buf()->data(), os.buf()->size(), pwCallback); +} + +void +PrivateKey::savePkcs1(std::ostream& os) const +{ + bufferSource(*this->toPkcs1()) >> streamSink(os); +} + +void +PrivateKey::savePkcs1Base64(std::ostream& os) const +{ + bufferSource(*this->toPkcs1()) >> base64Encode() >> streamSink(os); +} + +void +PrivateKey::savePkcs8(std::ostream& os, const char* pw, size_t pwLen) const +{ + bufferSource(*this->toPkcs8(pw, pwLen)) >> streamSink(os); +} + +void +PrivateKey::savePkcs8(std::ostream& os, PasswordCallback pwCallback) const +{ + bufferSource(*this->toPkcs8(pwCallback)) >> streamSink(os); +} + +void +PrivateKey::savePkcs8Base64(std::ostream& os, const char* pw, size_t pwLen) const +{ + bufferSource(*this->toPkcs8(pw, pwLen)) >> base64Encode() >> streamSink(os); +} + +void +PrivateKey::savePkcs8Base64(std::ostream& os, PasswordCallback pwCallback) const +{ + bufferSource(*this->toPkcs8(pwCallback)) >> base64Encode() >> streamSink(os); +} + +ConstBufferPtr +PrivateKey::derivePublicKey() const +{ + ENSURE_PRIVATE_KEY_LOADED(m_impl->key); + + uint8_t* pkcs8 = nullptr; + int len = i2d_PUBKEY(m_impl->key, &pkcs8); + if (len < 0) + NDN_THROW(Error("Failed to derive public key")); + + auto result = make_shared(pkcs8, len); + OPENSSL_free(pkcs8); + + return result; +} + +ConstBufferPtr +PrivateKey::decrypt(const uint8_t* cipherText, size_t cipherLen) const +{ + ENSURE_PRIVATE_KEY_LOADED(m_impl->key); + + int keyType = detail::getEvpPkeyType(m_impl->key); + switch (keyType) { + case EVP_PKEY_NONE: + NDN_THROW(Error("Failed to determine key type")); + case EVP_PKEY_RSA: + return rsaDecrypt(cipherText, cipherLen); + default: + NDN_THROW(Error("Decryption is not supported for key type " + to_string(keyType))); + } +} + +void* +PrivateKey::getEvpPkey() const +{ + return m_impl->key; +} + +ConstBufferPtr +PrivateKey::toPkcs1() const +{ + ENSURE_PRIVATE_KEY_LOADED(m_impl->key); + opensslInitAlgorithms(); + + detail::Bio membio(BIO_s_mem()); + if (!i2d_PrivateKey_bio(membio, m_impl->key)) + NDN_THROW(Error("Cannot convert key to PKCS #1 format")); + + auto buffer = make_shared(BIO_pending(membio)); + if (!membio.read(buffer->data(), buffer->size())) + NDN_THROW(Error("Read error during PKCS #1 conversion")); + + return buffer; +} + +ConstBufferPtr +PrivateKey::toPkcs8(const char* pw, size_t pwLen) const +{ + BOOST_ASSERT(std::strlen(pw) == pwLen); + ENSURE_PRIVATE_KEY_LOADED(m_impl->key); + opensslInitAlgorithms(); + + detail::Bio membio(BIO_s_mem()); + if (!i2d_PKCS8PrivateKey_bio(membio, m_impl->key, EVP_aes_256_cbc(), nullptr, 0, + nullptr, const_cast(pw))) + NDN_THROW(Error("Cannot convert key to PKCS #8 format")); + + auto buffer = make_shared(BIO_pending(membio)); + if (!membio.read(buffer->data(), buffer->size())) + NDN_THROW(Error("Read error during PKCS #8 conversion")); + + return buffer; +} + +ConstBufferPtr +PrivateKey::toPkcs8(PasswordCallback pwCallback) const +{ + ENSURE_PRIVATE_KEY_LOADED(m_impl->key); + opensslInitAlgorithms(); + + detail::Bio membio(BIO_s_mem()); + if (!i2d_PKCS8PrivateKey_bio(membio, m_impl->key, EVP_aes_256_cbc(), nullptr, 0, + &passwordCallbackWrapper, &pwCallback)) + NDN_THROW(Error("Cannot convert key to PKCS #8 format")); + + auto buffer = make_shared(BIO_pending(membio)); + if (!membio.read(buffer->data(), buffer->size())) + NDN_THROW(Error("Read error during PKCS #8 conversion")); + + return buffer; +} + +ConstBufferPtr +PrivateKey::rsaDecrypt(const uint8_t* cipherText, size_t cipherLen) const +{ + detail::EvpPkeyCtx ctx(m_impl->key); + + if (EVP_PKEY_decrypt_init(ctx) <= 0) + NDN_THROW(Error("Failed to initialize decryption context")); + + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) + NDN_THROW(Error("Failed to set padding")); + + size_t outlen = 0; + // Determine buffer length + if (EVP_PKEY_decrypt(ctx, nullptr, &outlen, cipherText, cipherLen) <= 0) + NDN_THROW(Error("Failed to estimate output length")); + + auto out = make_shared(outlen); + if (EVP_PKEY_decrypt(ctx, out->data(), &outlen, cipherText, cipherLen) <= 0) + NDN_THROW(Error("Failed to decrypt ciphertext")); + + out->resize(outlen); + return out; +} + +unique_ptr +PrivateKey::generateRsaKey(uint32_t keySize) +{ + detail::EvpPkeyCtx kctx(EVP_PKEY_RSA); + + if (EVP_PKEY_keygen_init(kctx) <= 0) + NDN_THROW(PrivateKey::Error("Failed to initialize RSA keygen context")); + + if (EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, static_cast(keySize)) <= 0) + NDN_THROW(PrivateKey::Error("Failed to set RSA key length")); + + auto privateKey = make_unique(); + if (EVP_PKEY_keygen(kctx, &privateKey->m_impl->key) <= 0) + NDN_THROW(PrivateKey::Error("Failed to generate RSA key")); + + return privateKey; +} + +unique_ptr +PrivateKey::generateEcKey(uint32_t keySize) +{ + detail::EvpPkeyCtx pctx(EVP_PKEY_EC); + + if (EVP_PKEY_paramgen_init(pctx) <= 0) + NDN_THROW(PrivateKey::Error("Failed to initialize EC paramgen context")); + + int ret; + switch (keySize) { + case 224: + ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_secp224r1); + break; + case 256: + ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1); // same as secp256r1 + break; + case 384: + ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_secp384r1); + break; + case 521: + ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_secp521r1); + break; + default: + NDN_THROW(std::invalid_argument("Unsupported EC key length " + to_string(keySize))); + } + if (ret <= 0) + NDN_THROW(PrivateKey::Error("Failed to set EC curve")); + + Impl params; + if (EVP_PKEY_paramgen(pctx, ¶ms.key) <= 0) + NDN_THROW(PrivateKey::Error("Failed to generate EC parameters")); + + detail::EvpPkeyCtx kctx(params.key); + if (EVP_PKEY_keygen_init(kctx) <= 0) + NDN_THROW(PrivateKey::Error("Failed to initialize EC keygen context")); + + auto privateKey = make_unique(); + if (EVP_PKEY_keygen(kctx, &privateKey->m_impl->key) <= 0) + NDN_THROW(PrivateKey::Error("Failed to generate EC key")); + + return privateKey; +} + +unique_ptr +PrivateKey::generateHmacKey(uint32_t keySize) +{ + std::vector rawKey(keySize / 8); + random::generateSecureBytes(rawKey.data(), rawKey.size()); + + auto privateKey = make_unique(); + try { + privateKey->loadRaw(KeyType::HMAC, rawKey.data(), rawKey.size()); + } + catch (const PrivateKey::Error&) { + NDN_THROW(PrivateKey::Error("Failed to generate HMAC key")); + } + + return privateKey; +} + +unique_ptr +generatePrivateKey(const KeyParams& keyParams) +{ + switch (keyParams.getKeyType()) { + case KeyType::RSA: { + const RsaKeyParams& rsaParams = static_cast(keyParams); + return PrivateKey::generateRsaKey(rsaParams.getKeySize()); + } + case KeyType::EC: { + const EcKeyParams& ecParams = static_cast(keyParams); + return PrivateKey::generateEcKey(ecParams.getKeySize()); + } + case KeyType::HMAC: { + const HmacKeyParams& hmacParams = static_cast(keyParams); + return PrivateKey::generateHmacKey(hmacParams.getKeySize()); + } + default: + NDN_THROW(std::invalid_argument("Unsupported key type " + + boost::lexical_cast(keyParams.getKeyType()))); + } +} + +} // namespace transform +} // namespace security +} // namespace ndn diff --git a/src/security/transform/private-key.hpp b/ndn-cxx/security/transform/private-key.hpp similarity index 75% rename from src/security/transform/private-key.hpp rename to ndn-cxx/security/transform/private-key.hpp index eae078752..85051f3d8 100644 --- a/src/security/transform/private-key.hpp +++ b/ndn-cxx/security/transform/private-key.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,8 +22,8 @@ #ifndef NDN_CXX_SECURITY_TRANSFORM_PRIVATE_KEY_HPP #define NDN_CXX_SECURITY_TRANSFORM_PRIVATE_KEY_HPP -#include "public-key.hpp" -#include "../../encoding/buffer.hpp" +#include "ndn-cxx/security/security-common.hpp" +#include "ndn-cxx/encoding/buffer.hpp" namespace ndn { @@ -41,34 +41,57 @@ class PrivateKey : noncopyable class Error : public std::runtime_error { public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } + using std::runtime_error::runtime_error; }; - friend class SignerFilter; - /** - * @brief Callback for application to handle password input + * @brief Callback for application to handle password input. * - * Password should be stored in @p buf and should not be longer than @p size. It is - * recommended to ask the user to verify the passphrase if @p shouldConfirm is true, e.g., by - * prompting for the password twice. + * The password must be written to @p buf and must not be longer than @p bufSize chars. + * It is recommended to ask the user to verify the password if @p shouldConfirm is true, + * e.g., by prompting for it twice. The callback must return the number of characters + * in the password or 0 if an error occurred. */ typedef function PasswordCallback; public: /** - * @brief Create a private key instance + * @brief Creates an empty private key instance. * - * One must call loadXXXX(...) to load private key. + * One must call `loadXXXX(...)` to load a private key. */ PrivateKey(); ~PrivateKey(); + /** + * @brief Returns the type of the private key. + */ + KeyType + getKeyType() const; + + /** + * @brief Returns the size of the private key in bits. + */ + size_t + getKeySize() const; + + /** + * @brief Returns a digest of the private key. + * + * @note Currently supports only HMAC keys. + */ + ConstBufferPtr + getKeyDigest(DigestAlgorithm algo) const; + + /** + * @brief Load a raw private key from a buffer @p buf + * + * @note Currently supports only HMAC keys. + */ + void + loadRaw(KeyType type, const uint8_t* buf, size_t size); + /** * @brief Load the private key in PKCS#1 format from a buffer @p buf */ @@ -95,7 +118,6 @@ class PrivateKey : noncopyable /** * @brief Load the private key in encrypted PKCS#8 format from a buffer @p buf with passphrase @p pw - * * @pre strlen(pw) == pwLen */ void @@ -112,7 +134,6 @@ class PrivateKey : noncopyable /** * @brief Load the private key in encrypted PKCS#8 format from a stream @p is with passphrase @p pw - * * @pre strlen(pw) == pwLen */ void @@ -130,7 +151,6 @@ class PrivateKey : noncopyable /** * @brief Load the private key in base64-encoded encrypted PKCS#8 format from a buffer @p buf * with passphrase @p pw - * * @pre strlen(pw) == pwLen */ void @@ -148,7 +168,6 @@ class PrivateKey : noncopyable /** * @brief Load the private key in base64-encoded encrypted PKCS#8 format from a stream @p is * with passphrase @p pw - * * @pre strlen(pw) == pwLen */ void @@ -212,7 +231,7 @@ class PrivateKey : noncopyable derivePublicKey() const; /** - * @return Plain text of @p cipherText decrypted using the private key. + * @return Plain text of @p cipherText decrypted using this private key. * * Only RSA encryption is supported for now. */ @@ -220,10 +239,13 @@ class PrivateKey : noncopyable decrypt(const uint8_t* cipherText, size_t cipherLen) const; private: + friend class SignerFilter; + friend class VerifierFilter; + /** - * @return A pointer to an EVP_PKEY instance. + * @return A pointer to an OpenSSL EVP_PKEY instance. * - * One need to explicitly cast the return value to EVP_PKEY*. + * The caller needs to explicitly cast the return value to `EVP_PKEY*`. */ void* getEvpPkey() const; @@ -241,18 +263,30 @@ class PrivateKey : noncopyable ConstBufferPtr rsaDecrypt(const uint8_t* cipherText, size_t cipherLen) const; +private: + friend unique_ptr generatePrivateKey(const KeyParams&); + + static unique_ptr + generateRsaKey(uint32_t keySize); + + static unique_ptr + generateEcKey(uint32_t keySize); + + static unique_ptr + generateHmacKey(uint32_t keySize); + private: class Impl; - unique_ptr m_impl; + const unique_ptr m_impl; }; /** - * @brief generate a private key according to @p keyParams. + * @brief Generate a private key according to @p keyParams * - * @note the public key can be derived from the private key + * @note The corresponding public key can be derived from the private key. * - * @throw std::argument_error if the key type is not supported - * @throw std::runtime_error when failing to generate the key + * @throw std::invalid_argument the specified key type is not supported + * @throw PrivateKey::Error key generation failed */ unique_ptr generatePrivateKey(const KeyParams& keyParams); diff --git a/ndn-cxx/security/transform/public-key.cpp b/ndn-cxx/security/transform/public-key.cpp new file mode 100644 index 000000000..d38b1d761 --- /dev/null +++ b/ndn-cxx/security/transform/public-key.cpp @@ -0,0 +1,196 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/transform/public-key.hpp" +#include "ndn-cxx/security/transform/base64-decode.hpp" +#include "ndn-cxx/security/transform/base64-encode.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" +#include "ndn-cxx/security/transform/stream-source.hpp" +#include "ndn-cxx/security/impl/openssl-helper.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" + +#define ENSURE_PUBLIC_KEY_LOADED(key) \ + do { \ + if ((key) == nullptr) \ + NDN_THROW(Error("Public key has not been loaded yet")); \ + } while (false) + +#define ENSURE_PUBLIC_KEY_NOT_LOADED(key) \ + do { \ + if ((key) != nullptr) \ + NDN_THROW(Error("Public key has already been loaded")); \ + } while (false) + +namespace ndn { +namespace security { +namespace transform { + +class PublicKey::Impl +{ +public: + Impl() noexcept + : key(nullptr) + { + } + + ~Impl() + { + EVP_PKEY_free(key); + } + +public: + EVP_PKEY* key; +}; + +PublicKey::PublicKey() + : m_impl(make_unique()) +{ +} + +PublicKey::~PublicKey() = default; + +KeyType +PublicKey::getKeyType() const +{ + if (!m_impl->key) + return KeyType::NONE; + + switch (detail::getEvpPkeyType(m_impl->key)) { + case EVP_PKEY_RSA: + return KeyType::RSA; + case EVP_PKEY_EC: + return KeyType::EC; + default: + return KeyType::NONE; + } +} + +void +PublicKey::loadPkcs8(const uint8_t* buf, size_t size) +{ + ENSURE_PUBLIC_KEY_NOT_LOADED(m_impl->key); + + if (d2i_PUBKEY(&m_impl->key, &buf, static_cast(size)) == nullptr) + NDN_THROW(Error("Failed to load public key")); +} + +void +PublicKey::loadPkcs8(std::istream& is) +{ + OBufferStream os; + streamSource(is) >> streamSink(os); + this->loadPkcs8(os.buf()->data(), os.buf()->size()); +} + +void +PublicKey::loadPkcs8Base64(const uint8_t* buf, size_t size) +{ + OBufferStream os; + bufferSource(buf, size) >> base64Decode() >> streamSink(os); + this->loadPkcs8(os.buf()->data(), os.buf()->size()); +} + +void +PublicKey::loadPkcs8Base64(std::istream& is) +{ + OBufferStream os; + streamSource(is) >> base64Decode() >> streamSink(os); + this->loadPkcs8(os.buf()->data(), os.buf()->size()); +} + +void +PublicKey::savePkcs8(std::ostream& os) const +{ + bufferSource(*this->toPkcs8()) >> streamSink(os); +} + +void +PublicKey::savePkcs8Base64(std::ostream& os) const +{ + bufferSource(*this->toPkcs8()) >> base64Encode() >> streamSink(os); +} + +ConstBufferPtr +PublicKey::encrypt(const uint8_t* plainText, size_t plainLen) const +{ + ENSURE_PUBLIC_KEY_LOADED(m_impl->key); + + int keyType = detail::getEvpPkeyType(m_impl->key); + switch (keyType) { + case EVP_PKEY_NONE: + NDN_THROW(Error("Failed to determine key type")); + case EVP_PKEY_RSA: + return rsaEncrypt(plainText, plainLen); + default: + NDN_THROW(Error("Encryption is not supported for key type " + to_string(keyType))); + } +} + +void* +PublicKey::getEvpPkey() const +{ + return m_impl->key; +} + +ConstBufferPtr +PublicKey::toPkcs8() const +{ + ENSURE_PUBLIC_KEY_LOADED(m_impl->key); + + uint8_t* pkcs8 = nullptr; + int len = i2d_PUBKEY(m_impl->key, &pkcs8); + if (len < 0) + NDN_THROW(Error("Cannot convert key to PKCS #8 format")); + + auto buffer = make_shared(pkcs8, len); + OPENSSL_free(pkcs8); + + return buffer; +} + +ConstBufferPtr +PublicKey::rsaEncrypt(const uint8_t* plainText, size_t plainLen) const +{ + detail::EvpPkeyCtx ctx(m_impl->key); + + if (EVP_PKEY_encrypt_init(ctx) <= 0) + NDN_THROW(Error("Failed to initialize encryption context")); + + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) + NDN_THROW(Error("Failed to set padding")); + + size_t outlen = 0; + // Determine buffer length + if (EVP_PKEY_encrypt(ctx, nullptr, &outlen, plainText, plainLen) <= 0) + NDN_THROW(Error("Failed to estimate output length")); + + auto out = make_shared(outlen); + if (EVP_PKEY_encrypt(ctx, out->data(), &outlen, plainText, plainLen) <= 0) + NDN_THROW(Error("Failed to encrypt plaintext")); + + out->resize(outlen); + return out; +} + +} // namespace transform +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/transform/public-key.hpp b/ndn-cxx/security/transform/public-key.hpp new file mode 100644 index 000000000..29c584bcc --- /dev/null +++ b/ndn-cxx/security/transform/public-key.hpp @@ -0,0 +1,131 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_SECURITY_TRANSFORM_PUBLIC_KEY_HPP +#define NDN_CXX_SECURITY_TRANSFORM_PUBLIC_KEY_HPP + +#include "ndn-cxx/security/security-common.hpp" +#include "ndn-cxx/encoding/buffer.hpp" + +namespace ndn { +namespace security { +namespace transform { + +/** + * @brief Abstraction of public key in crypto transformation + */ +class PublicKey : noncopyable +{ +public: + class Error : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + }; + +public: + /** + * @brief Create an empty public key instance + * + * One must call loadXXXX(...) to load a public key. + */ + PublicKey(); + + ~PublicKey(); + + /** + * @brief Get the type of the public key + */ + KeyType + getKeyType() const; + + /** + * @brief Load the public key in PKCS#8 format from a buffer @p buf + */ + void + loadPkcs8(const uint8_t* buf, size_t size); + + /** + * @brief Load the public key in PKCS#8 format from a stream @p is + */ + void + loadPkcs8(std::istream& is); + + /** + * @brief Load the public key in base64-encoded PKCS#8 format from a buffer @p buf + */ + void + loadPkcs8Base64(const uint8_t* buf, size_t size); + + /** + * @brief Load the public key in base64-encoded PKCS#8 format from a stream @p is + */ + void + loadPkcs8Base64(std::istream& is); + + /** + * @brief Save the public key in PKCS#8 format into a stream @p os + */ + void + savePkcs8(std::ostream& os) const; + + /** + * @brief Save the public key in base64-encoded PKCS#8 format into a stream @p os + */ + void + savePkcs8Base64(std::ostream& os) const; + + /** + * @return Cipher text of @p plainText encrypted using this public key. + * + * Only RSA encryption is supported for now. + */ + ConstBufferPtr + encrypt(const uint8_t* plainText, size_t plainLen) const; + +private: + friend class VerifierFilter; + + /** + * @return A pointer to an OpenSSL EVP_PKEY instance. + * + * The caller needs to explicitly cast the return value to `EVP_PKEY*`. + */ + void* + getEvpPkey() const; + +private: + ConstBufferPtr + toPkcs8() const; + + ConstBufferPtr + rsaEncrypt(const uint8_t* plainText, size_t plainLen) const; + +private: + class Impl; + const unique_ptr m_impl; +}; + +} // namespace transform +} // namespace security +} // namespace ndn + +#endif // NDN_CXX_SECURITY_TRANSFORM_PUBLIC_KEY_HPP diff --git a/ndn-cxx/security/transform/signer-filter.cpp b/ndn-cxx/security/transform/signer-filter.cpp new file mode 100644 index 000000000..33f380f7f --- /dev/null +++ b/ndn-cxx/security/transform/signer-filter.cpp @@ -0,0 +1,90 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/transform/signer-filter.hpp" +#include "ndn-cxx/security/transform/private-key.hpp" +#include "ndn-cxx/security/impl/openssl-helper.hpp" + +#include + +namespace ndn { +namespace security { +namespace transform { + +class SignerFilter::Impl +{ +public: + detail::EvpMdCtx ctx; +}; + + +SignerFilter::SignerFilter(DigestAlgorithm algo, const PrivateKey& key) + : m_impl(make_unique()) +{ + const EVP_MD* md = detail::digestAlgorithmToEvpMd(algo); + if (md == nullptr) + NDN_THROW(Error(getIndex(), "Unsupported digest algorithm " + + boost::lexical_cast(algo))); + + if (EVP_DigestSignInit(m_impl->ctx, nullptr, md, nullptr, + reinterpret_cast(key.getEvpPkey())) != 1) + NDN_THROW(Error(getIndex(), "Failed to initialize signing context with " + + boost::lexical_cast(algo) + " digest and " + + boost::lexical_cast(key.getKeyType()) + " key")); +} + +SignerFilter::~SignerFilter() = default; + +size_t +SignerFilter::convert(const uint8_t* buf, size_t size) +{ + if (EVP_DigestSignUpdate(m_impl->ctx, buf, size) != 1) + NDN_THROW(Error(getIndex(), "Failed to accept more input")); + + return size; +} + +void +SignerFilter::finalize() +{ + size_t sigLen = 0; + if (EVP_DigestSignFinal(m_impl->ctx, nullptr, &sigLen) != 1) + NDN_THROW(Error(getIndex(), "Failed to estimate buffer length")); + + auto buffer = make_unique(sigLen); + if (EVP_DigestSignFinal(m_impl->ctx, buffer->data(), &sigLen) != 1) + NDN_THROW(Error(getIndex(), "Failed to finalize signature")); + + buffer->erase(buffer->begin() + sigLen, buffer->end()); + setOutputBuffer(std::move(buffer)); + + flushAllOutput(); +} + +unique_ptr +signerFilter(DigestAlgorithm algo, const PrivateKey& key) +{ + return make_unique(algo, key); +} + +} // namespace transform +} // namespace security +} // namespace ndn diff --git a/src/security/transform/signer-filter.hpp b/ndn-cxx/security/transform/signer-filter.hpp similarity index 83% rename from src/security/transform/signer-filter.hpp rename to ndn-cxx/security/transform/signer-filter.hpp index 8db11f361..8cb573bad 100644 --- a/src/security/transform/signer-filter.hpp +++ b/ndn-cxx/security/transform/signer-filter.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,14 +22,15 @@ #ifndef NDN_CXX_SECURITY_TRANSFORM_SIGNER_FILTER_HPP #define NDN_CXX_SECURITY_TRANSFORM_SIGNER_FILTER_HPP -#include "transform-base.hpp" -#include "private-key.hpp" -#include "../security-common.hpp" +#include "ndn-cxx/security/transform/transform-base.hpp" +#include "ndn-cxx/security/security-common.hpp" namespace ndn { namespace security { namespace transform { +class PrivateKey; + /** * @brief The module to sign data. */ @@ -37,28 +38,30 @@ class SignerFilter : public Transform { public: /** - * @brief Create a signer module to generate signature using algorithm @p algo and @p key + * @brief Create a module to sign using digest algorithm @p algo and private key @p key */ SignerFilter(DigestAlgorithm algo, const PrivateKey& key); + ~SignerFilter(); + private: /** * @brief Write data @p buf into signer * * @return The number of bytes that are actually accepted */ - virtual size_t + size_t convert(const uint8_t* buf, size_t size) final; /** * @brief Finalize signing and write the signature into next module. */ - virtual void + void finalize() final; private: class Impl; - unique_ptr m_impl; + const unique_ptr m_impl; }; unique_ptr diff --git a/src/security/transform/step-source.cpp b/ndn-cxx/security/transform/step-source.cpp similarity index 91% rename from src/security/transform/step-source.cpp rename to ndn-cxx/security/transform/step-source.cpp index 432ebd966..0ff004b11 100644 --- a/src/security/transform/step-source.cpp +++ b/ndn-cxx/security/transform/step-source.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,7 +19,7 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "step-source.hpp" +#include "ndn-cxx/security/transform/step-source.hpp" namespace ndn { namespace security { diff --git a/src/security/transform/step-source.hpp b/ndn-cxx/security/transform/step-source.hpp similarity index 94% rename from src/security/transform/step-source.hpp rename to ndn-cxx/security/transform/step-source.hpp index 76388f7ec..a1e88c78b 100644 --- a/src/security/transform/step-source.hpp +++ b/ndn-cxx/security/transform/step-source.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,7 +22,7 @@ #ifndef NDN_CXX_SECURITY_TRANSFORM_STEP_SOURCE_HPP #define NDN_CXX_SECURITY_TRANSFORM_STEP_SOURCE_HPP -#include "transform-base.hpp" +#include "ndn-cxx/security/transform/transform-base.hpp" namespace ndn { namespace security { @@ -68,9 +68,8 @@ class StepSource : public Source * * use write() and end() method explicitly to input data. */ - virtual void + void doPump() final; - }; typedef StepSource stepSource; diff --git a/src/security/transform/stream-sink.cpp b/ndn-cxx/security/transform/stream-sink.cpp similarity index 87% rename from src/security/transform/stream-sink.cpp rename to ndn-cxx/security/transform/stream-sink.cpp index 58208c017..5eba76a45 100644 --- a/src/security/transform/stream-sink.cpp +++ b/ndn-cxx/security/transform/stream-sink.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,7 +19,9 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "stream-sink.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" + +#include namespace ndn { namespace security { @@ -36,7 +38,7 @@ StreamSink::doWrite(const uint8_t* buf, size_t size) m_os.write(reinterpret_cast(buf), size); if (m_os.bad()) - BOOST_THROW_EXCEPTION(Error(getIndex(), "Fail to write data into output stream")); + NDN_THROW(Error(getIndex(), "Fail to write data into output stream")); return size; } diff --git a/src/security/transform/stream-sink.hpp b/ndn-cxx/security/transform/stream-sink.hpp similarity index 92% rename from src/security/transform/stream-sink.hpp rename to ndn-cxx/security/transform/stream-sink.hpp index ed41cbd42..856c66b73 100644 --- a/src/security/transform/stream-sink.hpp +++ b/ndn-cxx/security/transform/stream-sink.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,8 +22,7 @@ #ifndef NDN_CXX_SECURITY_TRANSFORM_STREAM_SINK_HPP #define NDN_CXX_SECURITY_TRANSFORM_STREAM_SINK_HPP -#include "transform-base.hpp" -#include +#include "ndn-cxx/security/transform/transform-base.hpp" namespace ndn { namespace security { @@ -47,13 +46,13 @@ class StreamSink : public Sink * * @return number of bytes that have been written into the stream */ - virtual size_t + size_t doWrite(const uint8_t* buf, size_t size) final; /** * @brief Finalize sink processing */ - virtual void + void doEnd() final; private: diff --git a/src/security/transform/stream-source.cpp b/ndn-cxx/security/transform/stream-source.cpp similarity index 90% rename from src/security/transform/stream-source.cpp rename to ndn-cxx/security/transform/stream-source.cpp index 539506e55..40fb7a423 100644 --- a/src/security/transform/stream-source.cpp +++ b/ndn-cxx/security/transform/stream-source.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,7 +19,9 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "stream-source.hpp" +#include "ndn-cxx/security/transform/stream-source.hpp" + +#include #include namespace ndn { @@ -54,7 +56,7 @@ StreamSource::doPump() dataLen -= nBytesWritten; } else if (!m_is) { - BOOST_THROW_EXCEPTION(Error(getIndex(), "Input stream in bad state")); + NDN_THROW(Error(getIndex(), "Input stream in bad state")); } else if (m_is.good()) { m_is.read(reinterpret_cast(&buffer.front()), buffer.size()); diff --git a/src/security/transform/stream-source.hpp b/ndn-cxx/security/transform/stream-source.hpp similarity index 93% rename from src/security/transform/stream-source.hpp rename to ndn-cxx/security/transform/stream-source.hpp index b818fe737..2e022ff32 100644 --- a/src/security/transform/stream-source.hpp +++ b/ndn-cxx/security/transform/stream-source.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,8 +22,7 @@ #ifndef NDN_CXX_SECURITY_TRANSFORM_STREAM_SOURCE_HPP #define NDN_CXX_SECURITY_TRANSFORM_STREAM_SOURCE_HPP -#include "transform-base.hpp" -#include +#include "ndn-cxx/security/transform/transform-base.hpp" namespace ndn { namespace security { @@ -49,7 +48,7 @@ class StreamSource : public Source /** * @brief Read bytes from the input stream until EOF is reached and write them into the next module. */ - virtual void + void doPump() final; public: diff --git a/src/security/transform/strip-space.cpp b/ndn-cxx/security/transform/strip-space.cpp similarity index 93% rename from src/security/transform/strip-space.cpp rename to ndn-cxx/security/transform/strip-space.cpp index dad2cc31e..3ce8ead37 100644 --- a/src/security/transform/strip-space.cpp +++ b/ndn-cxx/security/transform/strip-space.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,7 +19,7 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "strip-space.hpp" +#include "ndn-cxx/security/transform/strip-space.hpp" namespace ndn { namespace security { diff --git a/src/security/transform/strip-space.hpp b/ndn-cxx/security/transform/strip-space.hpp similarity index 93% rename from src/security/transform/strip-space.hpp rename to ndn-cxx/security/transform/strip-space.hpp index 7cc4dc8e1..33295478d 100644 --- a/src/security/transform/strip-space.hpp +++ b/ndn-cxx/security/transform/strip-space.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,7 +22,8 @@ #ifndef NDN_CXX_SECURITY_TRANSFORM_STRIP_SPACE_HPP #define NDN_CXX_SECURITY_TRANSFORM_STRIP_SPACE_HPP -#include "transform-base.hpp" +#include "ndn-cxx/security/transform/transform-base.hpp" + #include #include @@ -44,7 +45,7 @@ class StripSpace : public Transform StripSpace(const char* whitespaces = DEFAULT_WHITESPACES); private: - virtual size_t + size_t convert(const uint8_t* buf, size_t buflen) final; private: diff --git a/src/security/transform/transform-base.cpp b/ndn-cxx/security/transform/transform-base.cpp similarity index 92% rename from src/security/transform/transform-base.cpp rename to ndn-cxx/security/transform/transform-base.cpp index b04c3f512..9bd661d92 100644 --- a/src/security/transform/transform-base.cpp +++ b/ndn-cxx/security/transform/transform-base.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,14 +19,14 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "transform-base.hpp" +#include "ndn-cxx/security/transform/transform-base.hpp" namespace ndn { namespace security { namespace transform { Error::Error(size_t index, const std::string& what) - : std::runtime_error("Error in module " + std::to_string(index) + ": " + what) + : std::runtime_error("Error in module " + to_string(index) + ": " + what) , m_index(index) { } @@ -41,7 +41,7 @@ size_t Downstream::write(const uint8_t* buf, size_t size) { if (m_isEnd) - BOOST_THROW_EXCEPTION(Error(getIndex(), "Module is closed, no more input")); + NDN_THROW(Error(getIndex(), "Module is closed, no more input")); size_t nBytesWritten = doWrite(buf, size); BOOST_ASSERT(nBytesWritten <= size); diff --git a/src/security/transform/transform-base.hpp b/ndn-cxx/security/transform/transform-base.hpp similarity index 98% rename from src/security/transform/transform-base.hpp rename to ndn-cxx/security/transform/transform-base.hpp index 94fd43caf..3a9ab9ce4 100644 --- a/src/security/transform/transform-base.hpp +++ b/ndn-cxx/security/transform/transform-base.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,7 +22,8 @@ #ifndef NDN_CXX_SECURITY_TRANSFORM_BASE_HPP #define NDN_CXX_SECURITY_TRANSFORM_BASE_HPP -#include "../../common.hpp" +#include "ndn-cxx/detail/common.hpp" + #include namespace ndn { @@ -30,7 +31,7 @@ namespace security { namespace transform { /** - * @file transform-base.hpp + * @file * * There are three types of module in a transformation chain: Source, Transform, and Sink. * The ideal usage of the transformation would be: @@ -222,7 +223,7 @@ class Transform : public Upstream, /** * @brief Abstraction of data processing in an intermediate module */ - virtual size_t + size_t doWrite(const uint8_t* data, size_t dataLen) final; /** @@ -230,7 +231,7 @@ class Transform : public Upstream, * * This method will not return until all transformation result is written into next module */ - virtual void + void doEnd() final; /** diff --git a/ndn-cxx/security/transform/verifier-filter.cpp b/ndn-cxx/security/transform/verifier-filter.cpp new file mode 100644 index 000000000..afcfd3def --- /dev/null +++ b/ndn-cxx/security/transform/verifier-filter.cpp @@ -0,0 +1,143 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/transform/verifier-filter.hpp" +#include "ndn-cxx/security/transform/private-key.hpp" +#include "ndn-cxx/security/transform/public-key.hpp" +#include "ndn-cxx/security/impl/openssl-helper.hpp" + +#include + +namespace ndn { +namespace security { +namespace transform { + +class VerifierFilter::Impl +{ +public: + Impl(const uint8_t* sig, size_t siglen) + : sig(sig) + , siglen(siglen) + { + } + +public: + detail::EvpMdCtx ctx; + const uint8_t* sig; + size_t siglen; +}; + + +VerifierFilter::VerifierFilter(DigestAlgorithm algo, const PublicKey& key, + const uint8_t* sig, size_t sigLen) + : m_impl(make_unique(sig, sigLen)) + , m_keyType(key.getKeyType()) +{ + init(algo, key.getEvpPkey()); +} + +VerifierFilter::VerifierFilter(DigestAlgorithm algo, const PrivateKey& key, + const uint8_t* sig, size_t sigLen) + : m_impl(make_unique(sig, sigLen)) + , m_keyType(key.getKeyType()) +{ + if (m_keyType != KeyType::HMAC) + NDN_THROW(Error(getIndex(), "VerifierFilter only supports private keys of HMAC type")); + + init(algo, key.getEvpPkey()); +} + +VerifierFilter::~VerifierFilter() = default; + +void +VerifierFilter::init(DigestAlgorithm algo, void* pkey) +{ + const EVP_MD* md = detail::digestAlgorithmToEvpMd(algo); + if (md == nullptr) + NDN_THROW(Error(getIndex(), "Unsupported digest algorithm " + + boost::lexical_cast(algo))); + + int ret; + if (m_keyType == KeyType::HMAC) + ret = EVP_DigestSignInit(m_impl->ctx, nullptr, md, nullptr, reinterpret_cast(pkey)); + else + ret = EVP_DigestVerifyInit(m_impl->ctx, nullptr, md, nullptr, reinterpret_cast(pkey)); + + if (ret != 1) + NDN_THROW(Error(getIndex(), "Failed to initialize verification context with " + + boost::lexical_cast(algo) + " digest and " + + boost::lexical_cast(m_keyType) + " key")); +} + +size_t +VerifierFilter::convert(const uint8_t* buf, size_t size) +{ + int ret; + if (m_keyType == KeyType::HMAC) + ret = EVP_DigestSignUpdate(m_impl->ctx, buf, size); + else + ret = EVP_DigestVerifyUpdate(m_impl->ctx, buf, size); + + if (ret != 1) + NDN_THROW(Error(getIndex(), "Failed to accept more input")); + + return size; +} + +void +VerifierFilter::finalize() +{ + bool ok = false; + if (m_keyType == KeyType::HMAC) { + auto hmacBuf = make_unique(EVP_MAX_MD_SIZE); + size_t hmacLen = 0; + + if (EVP_DigestSignFinal(m_impl->ctx, hmacBuf->data(), &hmacLen) != 1) + NDN_THROW(Error(getIndex(), "Failed to finalize HMAC")); + + ok = CRYPTO_memcmp(hmacBuf->data(), m_impl->sig, std::min(hmacLen, m_impl->siglen)) == 0; + } + else { + ok = EVP_DigestVerifyFinal(m_impl->ctx, m_impl->sig, m_impl->siglen) == 1; + } + + auto buffer = make_unique(1); + (*buffer)[0] = ok ? 1 : 0; + setOutputBuffer(std::move(buffer)); + + flushAllOutput(); +} + +unique_ptr +verifierFilter(DigestAlgorithm algo, const PublicKey& key, const uint8_t* sig, size_t sigLen) +{ + return make_unique(algo, key, sig, sigLen); +} + +unique_ptr +verifierFilter(DigestAlgorithm algo, const PrivateKey& key, const uint8_t* sig, size_t sigLen) +{ + return make_unique(algo, key, sig, sigLen); +} + +} // namespace transform +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/transform/verifier-filter.hpp b/ndn-cxx/security/transform/verifier-filter.hpp new file mode 100644 index 000000000..deda28014 --- /dev/null +++ b/ndn-cxx/security/transform/verifier-filter.hpp @@ -0,0 +1,90 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_CXX_SECURITY_TRANSFORM_VERIFIER_FILTER_HPP +#define NDN_CXX_SECURITY_TRANSFORM_VERIFIER_FILTER_HPP + +#include "ndn-cxx/security/transform/transform-base.hpp" +#include "ndn-cxx/security/security-common.hpp" + +namespace ndn { +namespace security { +namespace transform { + +class PrivateKey; +class PublicKey; + +/** + * @brief The module to verify signatures. + * + * The next module in the chain is usually BoolSink. + */ +class VerifierFilter : public Transform +{ +public: + /** + * @brief Create a verifier module to verify signature @p sig using algorithm @p algo and public key @p key + */ + VerifierFilter(DigestAlgorithm algo, const PublicKey& key, const uint8_t* sig, size_t sigLen); + + /** + * @brief Create a verifier module to verify signature @p sig using algorithm @p algo and HMAC key @p key + */ + VerifierFilter(DigestAlgorithm algo, const PrivateKey& key, const uint8_t* sig, size_t sigLen); + + ~VerifierFilter(); + +private: + void + init(DigestAlgorithm algo, void* pkey); + + /** + * @brief Write data @p buf into verifier + * + * @return The number of bytes that are actually written + */ + size_t + convert(const uint8_t* buf, size_t size) final; + + /** + * @brief Finalize verification and write the result (single byte) into next module. + */ + void + finalize() final; + +private: + class Impl; + const unique_ptr m_impl; + + KeyType m_keyType; +}; + +unique_ptr +verifierFilter(DigestAlgorithm algo, const PublicKey& key, const uint8_t* sig, size_t sigLen); + +unique_ptr +verifierFilter(DigestAlgorithm algo, const PrivateKey& key, const uint8_t* sig, size_t sigLen); + +} // namespace transform +} // namespace security +} // namespace ndn + +#endif // NDN_CXX_SECURITY_TRANSFORM_VERIFIER_FILTER_HPP diff --git a/ndn-cxx/security/v2/additional-description.cpp b/ndn-cxx/security/v2/additional-description.cpp new file mode 100644 index 000000000..f9aa2af22 --- /dev/null +++ b/ndn-cxx/security/v2/additional-description.cpp @@ -0,0 +1,181 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/additional-description.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/util/concepts.hpp" +#include "ndn-cxx/util/ostream-joiner.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); +BOOST_CONCEPT_ASSERT((WireEncodable)); +BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); +BOOST_CONCEPT_ASSERT((WireDecodable)); +static_assert(std::is_base_of::value, + "AdditionalDescription::Error must inherit from tlv::Error"); + +static const size_t KEY_OFFSET = 0; +static const size_t VALUE_OFFSET = 1; + +AdditionalDescription::AdditionalDescription(const Block& block) +{ + wireDecode(block); +} + +const std::string& +AdditionalDescription::get(const std::string& key) const +{ + auto it = m_info.find(key); + if (it == m_info.end()) + NDN_THROW(Error("Entry does not exist for key (" + key + ")")); + + return it->second; +} + +void +AdditionalDescription::set(const std::string& key, const std::string& value) +{ + m_info[key] = value; +} + +bool +AdditionalDescription::has(const std::string& key) const +{ + return (m_info.find(key) != m_info.end()); +} + +AdditionalDescription::iterator +AdditionalDescription::begin() +{ + return m_info.begin(); +} + +AdditionalDescription::iterator +AdditionalDescription::end() +{ + return m_info.end(); +} + +AdditionalDescription::const_iterator +AdditionalDescription::begin() const +{ + return m_info.begin(); +} + +AdditionalDescription::const_iterator +AdditionalDescription::end() const +{ + return m_info.end(); +} + +template +size_t +AdditionalDescription::wireEncode(EncodingImpl& encoder) const +{ + size_t totalLength = 0; + + for (auto it = m_info.rbegin(); it != m_info.rend(); it++) { + size_t entryLength = 0; + entryLength += prependStringBlock(encoder, tlv::DescriptionValue, it->second); + entryLength += prependStringBlock(encoder, tlv::DescriptionKey, it->first); + entryLength += encoder.prependVarNumber(entryLength); + entryLength += encoder.prependVarNumber(tlv::DescriptionEntry); + + totalLength += entryLength; + } + + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::AdditionalDescription); + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(AdditionalDescription); + +const Block& +AdditionalDescription::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(); + m_wire.parse(); + + return m_wire; +} + +void +AdditionalDescription::wireDecode(const Block& wire) +{ + if (!wire.hasWire()) { + NDN_THROW(Error("The supplied block does not contain wire format")); + } + + m_wire = wire; + m_wire.parse(); + + if (m_wire.type() != tlv::AdditionalDescription) + NDN_THROW(Error("AdditionalDescription", m_wire.type())); + + auto it = m_wire.elements_begin(); + while (it != m_wire.elements_end()) { + const Block& entry = *it; + entry.parse(); + + if (entry.type() != tlv::DescriptionEntry) + NDN_THROW(Error("DescriptionEntry", entry.type())); + + if (entry.elements_size() != 2) + NDN_THROW(Error("DescriptionEntry does not have two sub-TLVs")); + + if (entry.elements()[KEY_OFFSET].type() != tlv::DescriptionKey || + entry.elements()[VALUE_OFFSET].type() != tlv::DescriptionValue) + NDN_THROW(Error("Invalid DescriptionKey or DescriptionValue field")); + + m_info[readString(entry.elements()[KEY_OFFSET])] = readString(entry.elements()[VALUE_OFFSET]); + it++; + } +} + +std::ostream& +operator<<(std::ostream& os, const AdditionalDescription& desc) +{ + os << "["; + + auto join = make_ostream_joiner(os, ", "); + for (const auto& entry : desc) { + join = "(" + entry.first + ":" + entry.second + ")"; + } + + return os << "]"; +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/additional-description.hpp b/ndn-cxx/security/v2/additional-description.hpp new file mode 100644 index 000000000..5057ed58e --- /dev/null +++ b/ndn-cxx/security/v2/additional-description.hpp @@ -0,0 +1,147 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_ADDITIONAL_DESCRIPTION_HPP +#define NDN_SECURITY_V2_ADDITIONAL_DESCRIPTION_HPP + +#include "ndn-cxx/detail/common.hpp" +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/encoding/tlv.hpp" + +#include + +namespace ndn { +namespace security { +namespace v2 { + +/** + * @brief Abstraction of AdditionalDescription + * @sa docs/specs/certificate-format.rst + */ +class AdditionalDescription +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + typedef std::map::iterator iterator; + typedef std::map::const_iterator const_iterator; + +public: + /** + * @brief Create an empty AdditionalDescription + */ + AdditionalDescription() = default; + + /** + * @brief Create AdditionalDescription from @p block + */ + explicit + AdditionalDescription(const Block& block); + + const std::string& + get(const std::string& key) const; + + void + set(const std::string& key, const std::string& value); + + bool + has(const std::string& key) const; + + size_t + size() const + { + return m_info.size(); + } + + bool + empty() const + { + return m_info.empty(); + } + + iterator + begin(); + + iterator + end(); + + const_iterator + begin() const; + + const_iterator + end() const; + + /** @brief Fast encoding or block size estimation + */ + template + size_t + wireEncode(EncodingImpl& encoder) const; + + /** @brief Encode ValidityPeriod into TLV block + */ + const Block& + wireEncode() const; + + /** @brief Decode ValidityPeriod from TLV block + * @throw Error when an invalid TLV block supplied + */ + void + wireDecode(const Block& wire); + +private: // EqualityComparable concept + // NOTE: the following "hidden friend" operators are available via + // argument-dependent lookup only and must be defined inline. + + friend bool + operator==(const AdditionalDescription& lhs, const AdditionalDescription& rhs) + { + return lhs.m_info == rhs.m_info; + } + + friend bool + operator!=(const AdditionalDescription& lhs, const AdditionalDescription& rhs) + { + return lhs.m_info != rhs.m_info; + } + +private: + std::map m_info; + + mutable Block m_wire; +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(AdditionalDescription); + +std::ostream& +operator<<(std::ostream& os, const AdditionalDescription& desc); + +} // namespace v2 + +using v2::AdditionalDescription; + +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_ADDITIONAL_DESCRIPTION_HPP diff --git a/ndn-cxx/security/v2/certificate-bundle-fetcher.cpp b/ndn-cxx/security/v2/certificate-bundle-fetcher.cpp new file mode 100644 index 000000000..2113a4148 --- /dev/null +++ b/ndn-cxx/security/v2/certificate-bundle-fetcher.cpp @@ -0,0 +1,231 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/certificate-bundle-fetcher.hpp" +#include "ndn-cxx/face.hpp" +#include "ndn-cxx/util/logger.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +NDN_LOG_INIT(ndn.security.v2.CertificateBundleFetcher); + +#define NDN_LOG_DEBUG_DEPTH(x) NDN_LOG_DEBUG(std::string(state->getDepth() + 1, '>') << " " << x) +#define NDN_LOG_TRACE_DEPTH(x) NDN_LOG_TRACE(std::string(state->getDepth() + 1, '>') << " " << x) + +CertificateBundleFetcher::CertificateBundleFetcher(unique_ptr inner, + Face& face) + : m_inner(std::move(inner)) + , m_face(face) + , m_bundleInterestLifetime(1000) +{ + BOOST_ASSERT(m_inner != nullptr); +} + +void +CertificateBundleFetcher::setBundleInterestLifetime(time::milliseconds time) +{ + m_bundleInterestLifetime = time; +} + +time::milliseconds +CertificateBundleFetcher::getBundleInterestLifetime() const +{ + return m_bundleInterestLifetime; +} + +void +CertificateBundleFetcher::setCertificateStorage(CertificateStorage& certStorage) +{ + m_certStorage = &certStorage; + m_inner->setCertificateStorage(certStorage); +} + +void +CertificateBundleFetcher::doFetch(const shared_ptr& certRequest, + const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + auto dataValidationState = dynamic_pointer_cast(state); + if (dataValidationState == nullptr) { + return m_inner->fetch(certRequest, state, continueValidation); + } + + // check if a bundle segment was fetched before + shared_ptr bundleNameTag = state->getTag(); + if (bundleNameTag == nullptr) { + const Name& originalDataName = dataValidationState->getOriginalData().getName(); + if (originalDataName.empty()) { + return m_inner->fetch(certRequest, state, continueValidation); + } + // derive certificate bundle name from original data name + Name bundleNamePrefix = deriveBundleName(originalDataName); + fetchFirstBundleSegment(bundleNamePrefix, certRequest, state, continueValidation); + } + else { + Name fullBundleName = bundleNameTag->get(); + fetchNextBundleSegment(fullBundleName, fullBundleName.get(-1).getSuccessor(), + certRequest, state, continueValidation); + } +} + +void +CertificateBundleFetcher::fetchFirstBundleSegment(const Name& bundleNamePrefix, + const shared_ptr& certRequest, + const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + Interest bundleInterest = Interest(bundleNamePrefix); + bundleInterest.setCanBePrefix(true); + bundleInterest.setMustBeFresh(true); + bundleInterest.setInterestLifetime(m_bundleInterestLifetime); + + m_face.expressInterest(bundleInterest, + [=] (const Interest& interest, const Data& data) { + dataCallback(data, true, certRequest, state, continueValidation); + }, + [=] (const Interest& interest, const lp::Nack& nack) { + nackCallback(nack, certRequest, state, continueValidation, bundleNamePrefix); + }, + [=] (const Interest& interest) { + timeoutCallback(certRequest, state, continueValidation, bundleNamePrefix); + }); +} + +void +CertificateBundleFetcher::fetchNextBundleSegment(const Name& fullBundleName, const name::Component& segmentNo, + const shared_ptr& certRequest, + const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + shared_ptr finalBlockId = state->getTag(); + if (finalBlockId != nullptr && segmentNo > finalBlockId->get()) { + return m_inner->fetch(certRequest, state, continueValidation); + } + + Interest bundleInterest(fullBundleName.getPrefix(-1).append(segmentNo)); + bundleInterest.setCanBePrefix(false); + bundleInterest.setMustBeFresh(false); + bundleInterest.setInterestLifetime(m_bundleInterestLifetime); + + m_face.expressInterest(bundleInterest, + [=] (const Interest& interest, const Data& data) { + dataCallback(data, false, certRequest, state, continueValidation); + }, + [=] (const Interest& interest, const lp::Nack& nack) { + nackCallback(nack, certRequest, state, continueValidation, fullBundleName); + }, + [=] (const Interest& interest) { + timeoutCallback(certRequest, state, continueValidation, fullBundleName); + }); +} + +void +CertificateBundleFetcher::dataCallback(const Data& bundleData, + bool isSegmentZeroExpected, + const shared_ptr& certRequest, + const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + NDN_LOG_DEBUG_DEPTH("Fetched certificate bundle from network " << bundleData.getName()); + + name::Component currentSegment = bundleData.getName().get(-1); + if (!currentSegment.isSegment()) { + return m_inner->fetch(certRequest, state, continueValidation); + } + + if (isSegmentZeroExpected && currentSegment.toSegment() != 0) { + // fetch segment zero + fetchNextBundleSegment(bundleData.getName(), name::Component::fromSegment(0), + certRequest, state, continueValidation); + } + else { + state->setTag(make_shared(bundleData.getName())); + + const auto& finalBlockId = bundleData.getFinalBlock(); + if (!finalBlockId) { + state->setTag(make_shared(*finalBlockId)); + } + + Block bundleContent = bundleData.getContent(); + bundleContent.parse(); + + // store all the certificates in unverified cache + for (const auto& block : bundleContent.elements()) { + m_certStorage->cacheUnverifiedCert(Certificate(block)); + } + + auto cert = m_certStorage->getUnverifiedCertCache().find(certRequest->interest); + continueValidation(*cert, state); + } +} + +void +CertificateBundleFetcher::nackCallback(const lp::Nack& nack, + const shared_ptr& certRequest, + const shared_ptr& state, + const ValidationContinuation& continueValidation, + const Name& bundleName) +{ + NDN_LOG_DEBUG_DEPTH("NACK (" << nack.getReason() << ") while fetching certificate bundle" + << bundleName); + + m_inner->fetch(certRequest, state, continueValidation); +} + +void +CertificateBundleFetcher::timeoutCallback(const shared_ptr& certRequest, + const shared_ptr& state, + const ValidationContinuation& continueValidation, + const Name& bundleName) +{ + NDN_LOG_DEBUG_DEPTH("Timeout while fetching certificate bundle" << bundleName); + + m_inner->fetch(certRequest, state, continueValidation); +} + +Name +CertificateBundleFetcher::deriveBundleName(const Name& name) +{ + name::Component lastComponent = name.at(-1); + + Name bundleName = name; + if (lastComponent.isImplicitSha256Digest()) { + if (name.size() >= 2 && name.get(-2).isSegment()) { + bundleName = name.getPrefix(-2); + } + else { + bundleName = name.getPrefix(-1); + } + } + else if (lastComponent.isSegment()) { + bundleName = name.getPrefix(-1); + } + bundleName.append("_BUNDLE"); + bundleName.appendNumber(00); + + return bundleName; +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/certificate-bundle-fetcher.hpp b/ndn-cxx/security/v2/certificate-bundle-fetcher.hpp new file mode 100644 index 000000000..f14de46a5 --- /dev/null +++ b/ndn-cxx/security/v2/certificate-bundle-fetcher.hpp @@ -0,0 +1,149 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_CERTIFICATE_BUNDLE_FETCHER_HPP +#define NDN_SECURITY_V2_CERTIFICATE_BUNDLE_FETCHER_HPP + +#include "ndn-cxx/security/v2/certificate-fetcher-from-network.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +/** + * @brief Fetch certificate bundle from the network + * + * Currently bundle fetching is attempted only for Data validation. This may change in the + * future. Bundle fetching always goes to the infrastructure regardless of the inner + * fetcher. Inner fetcher is used when the bundle interest times out or returns a Nack or when + * additional certificates are needed for validation. + * + * @sa https://redmine.named-data.net/projects/ndn-cxx/wiki/Certificate_Bundle_Packet_Format + */ +class CertificateBundleFetcher : public CertificateFetcher +{ +public: + explicit + CertificateBundleFetcher(unique_ptr inner, + Face& face); + + /** + * @brief Set the lifetime of certificate bundle interest + */ + void + setBundleInterestLifetime(time::milliseconds time); + + /** + * @return The lifetime of certificate bundle interest + */ + time::milliseconds + getBundleInterestLifetime() const; + + /** + * Set the storage for this and inner certificate fetcher + */ + void + setCertificateStorage(CertificateStorage& certStorage) override; + +protected: + void + doFetch(const shared_ptr& certRequest, const shared_ptr& state, + const ValidationContinuation& continueValidation) override; + +private: + /** + * @brief Fetch the first bundle segment. + * + * After deriving the bundle name prefix, the exact version of the bundle is not yet known. + * This method express Interest for the bundle prefix to (1) retrieve first segment of the bundle and + * (2) discover bundle version. The bundle version will be recorded in the validation state as BundleNameTag + * and will be used in subsequent @p fetchNextBundleSegment calls to fetch further bundle segments if needed. + */ + void + fetchFirstBundleSegment(const Name& bundleNamePrefix, + const shared_ptr& certRequest, + const shared_ptr& state, + const ValidationContinuation& continueValidation); + + /** + * @brief Fetch the specified bundle segment. + */ + void + fetchNextBundleSegment(const Name& fullBundleName, const name::Component& segmentNo, + const shared_ptr& certRequest, + const shared_ptr& state, + const ValidationContinuation& continueValidation); + + /** + * @brief Derive bundle name from data name. + * + * Current naming conventions are as follows: + * //BUNDLE/// + * + * Current rules for derived(data_name): + * (1) If the last component is Implicit Digest AND the second last component is Segment number + * then derived(data_name) = data_name.getPrefix(-2) + * (2) If the last component is Implicit Digest + * then derived(data_name) = data_name.getPrefix(-1) + * (3) If the last component is Segment number + * then derived(data_name) = data_name.getPrefix(-1) + * + * component is "00" for single hierarchy trust models. + */ + static Name + deriveBundleName(const Name& name); + + /** + * @brief Callback invoked when certificate bundle is retrieved. + */ + void + dataCallback(const Data& data, bool isSegmentZeroExpected, + const shared_ptr& certRequest, const shared_ptr& state, + const ValidationContinuation& continueValidation); + + /** + * @brief Callback invoked when interest for fetching certificate bundle gets NACKed. + */ + void + nackCallback(const lp::Nack& nack, + const shared_ptr& certRequest, const shared_ptr& state, + const ValidationContinuation& continueValidation, const Name& bundleName); + + /** + * @brief Callback invoked when interest for fetching certificate times out. + */ + void + timeoutCallback(const shared_ptr& certRequest, const shared_ptr& state, + const ValidationContinuation& continueValidation, const Name& bundleName); + +private: + unique_ptr m_inner; + Face& m_face; + using BundleNameTag = SimpleTag; + using FinalBlockIdTag = SimpleTag; + time::milliseconds m_bundleInterestLifetime; +}; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_CERTIFICATE_BUNDLE_FETCHER_HPP diff --git a/ndn-cxx/security/v2/certificate-cache.cpp b/ndn-cxx/security/v2/certificate-cache.cpp new file mode 100644 index 000000000..aefa069a0 --- /dev/null +++ b/ndn-cxx/security/v2/certificate-cache.cpp @@ -0,0 +1,112 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/certificate-cache.hpp" +#include "ndn-cxx/util/logger.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +NDN_LOG_INIT(ndn.security.v2.CertificateCache); + +time::nanoseconds +CertificateCache::getDefaultLifetime() +{ + return 1_h; +} + +CertificateCache::CertificateCache(const time::nanoseconds& maxLifetime) + : m_certsByTime(m_certs.get<0>()) + , m_certsByName(m_certs.get<1>()) + , m_maxLifetime(maxLifetime) +{ +} + +void +CertificateCache::insert(const Certificate& cert) +{ + time::system_clock::TimePoint notAfterTime = cert.getValidityPeriod().getPeriod().second; + time::system_clock::TimePoint now = time::system_clock::now(); + if (notAfterTime < now) { + NDN_LOG_DEBUG("Not adding " << cert.getName() << ": already expired at " << time::toIsoString(notAfterTime)); + return; + } + + time::system_clock::TimePoint removalTime = std::min(notAfterTime, now + m_maxLifetime); + NDN_LOG_DEBUG("Adding " << cert.getName() << ", will remove in " + << time::duration_cast(removalTime - now)); + m_certs.insert(Entry(cert, removalTime)); +} + +void +CertificateCache::clear() +{ + m_certs.clear(); +} + +const Certificate* +CertificateCache::find(const Name& certPrefix) const +{ + const_cast(this)->refresh(); + if (certPrefix.size() > 0 && certPrefix[-1].isImplicitSha256Digest()) { + NDN_LOG_INFO("Certificate search using name with the implicit digest is not yet supported"); + } + auto itr = m_certsByName.lower_bound(certPrefix); + if (itr == m_certsByName.end() || !certPrefix.isPrefixOf(itr->getCertName())) + return nullptr; + return &itr->cert; +} + +const Certificate* +CertificateCache::find(const Interest& interest) const +{ + if (interest.getName().size() > 0 && interest.getName()[-1].isImplicitSha256Digest()) { + NDN_LOG_INFO("Certificate search using name with implicit digest is not yet supported"); + } + const_cast(this)->refresh(); + + for (auto i = m_certsByName.lower_bound(interest.getName()); + i != m_certsByName.end() && interest.getName().isPrefixOf(i->getCertName()); + ++i) { + const auto& cert = i->cert; + if (interest.matchesData(cert)) { + return &cert; + } + } + return nullptr; +} + +void +CertificateCache::refresh() +{ + time::system_clock::TimePoint now = time::system_clock::now(); + + auto cIt = m_certsByTime.begin(); + while (cIt != m_certsByTime.end() && cIt->removalTime < now) { + m_certsByTime.erase(cIt); + cIt = m_certsByTime.begin(); + } +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/certificate-cache.hpp b/ndn-cxx/security/v2/certificate-cache.hpp new file mode 100644 index 000000000..d0e412e91 --- /dev/null +++ b/ndn-cxx/security/v2/certificate-cache.hpp @@ -0,0 +1,148 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_CERTIFICATE_CACHE_HPP +#define NDN_SECURITY_V2_CERTIFICATE_CACHE_HPP + +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/security/v2/certificate.hpp" + +#include +#include +#include +#include + +namespace ndn { +namespace security { +namespace v2 { + +/** + * @brief Represents a container for verified certificates. + * + * A certificate is removed no later than its NotAfter time, or maxLifetime after it has been + * added to the cache. + */ +class CertificateCache : noncopyable +{ +public: + /** + * @brief Create an object for certificate cache. + * + * @param maxLifetime the maximum time that certificates could live inside cache (default: 1 hour) + */ + explicit + CertificateCache(const time::nanoseconds& maxLifetime = getDefaultLifetime()); + + /** + * @brief Insert certificate into cache. + * + * The inserted certificate will be removed no later than its NotAfter time, or maxLifetime + * defined during cache construction. + * + * @param cert the certificate packet. + */ + void + insert(const Certificate& cert); + + /** + * @brief Remove all certificates from cache + */ + void + clear(); + + /** + * @brief Get certificate given key name + * @param certPrefix Certificate prefix for searching the certificate. + * @return The found certificate, nullptr if not found. + * + * @note The returned value may be invalidated after next call to one of find methods. + */ + const Certificate* + find(const Name& certPrefix) const; + + /** + * @brief Find certificate given interest + * @param interest The input interest packet. + * @return The found certificate that matches the interest, nullptr if not found. + * + * @note The returned value may be invalidated after next call to one of find methods. + */ + const Certificate* + find(const Interest& interest) const; + +private: + class Entry + { + public: + Entry(const Certificate& cert, const time::system_clock::TimePoint& removalTime) + : cert(cert) + , removalTime(removalTime) + { + } + + const Name& + getCertName() const + { + return cert.getName(); + } + + public: + Certificate cert; + time::system_clock::TimePoint removalTime; + }; + + /** + * @brief Remove all outdated certificate entries. + */ + void + refresh(); + +public: + static time::nanoseconds + getDefaultLifetime(); + +private: + /// @todo Switch to InMemoryStorateTimeout after it is available (task #3917) + typedef boost::multi_index::multi_index_container< + Entry, + boost::multi_index::indexed_by< + boost::multi_index::ordered_non_unique< + boost::multi_index::member + >, + boost::multi_index::ordered_unique< + boost::multi_index::const_mem_fun + > + > + > CertIndex; + + typedef CertIndex::nth_index<0>::type CertIndexByTime; + typedef CertIndex::nth_index<1>::type CertIndexByName; + CertIndex m_certs; + CertIndexByTime& m_certsByTime; + CertIndexByName& m_certsByName; + time::nanoseconds m_maxLifetime; +}; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_CERTIFICATE_CACHE_HPP diff --git a/ndn-cxx/security/v2/certificate-fetcher-direct-fetch.cpp b/ndn-cxx/security/v2/certificate-fetcher-direct-fetch.cpp new file mode 100644 index 000000000..7a4cb4295 --- /dev/null +++ b/ndn-cxx/security/v2/certificate-fetcher-direct-fetch.cpp @@ -0,0 +1,96 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/certificate-fetcher-direct-fetch.hpp" +#include "ndn-cxx/face.hpp" +#include "ndn-cxx/lp/tags.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +CertificateFetcherDirectFetch::CertificateFetcherDirectFetch(Face& face) + : CertificateFetcherFromNetwork(face) +{ +} + +void +CertificateFetcherDirectFetch::setSendDirectInterestOnly(bool wantDirectInterestOnly) +{ + m_wantDirectInterestOnly = wantDirectInterestOnly; +} + +void +CertificateFetcherDirectFetch::doFetch(const shared_ptr& keyRequest, + const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + auto interestState = dynamic_pointer_cast(state); + uint64_t incomingFaceId = 0; + if (interestState != nullptr) { + auto incomingFaceIdTag = interestState->getOriginalInterest().getTag(); + if (incomingFaceIdTag != nullptr) { + incomingFaceId = incomingFaceIdTag->get(); + } + } + else { + auto dataState = dynamic_pointer_cast(state); + auto incomingFaceIdTag = dataState->getOriginalData().getTag(); + if (incomingFaceIdTag != nullptr) { + incomingFaceId = incomingFaceIdTag->get(); + } + } + if (incomingFaceId != 0) { + Interest directInterest(keyRequest->interest); + directInterest.refreshNonce(); + directInterest.setTag(make_shared(incomingFaceId)); + + if (!m_wantDirectInterestOnly) { + // disable callbacks + m_face.expressInterest(directInterest, nullptr, nullptr, nullptr); + } + else { + m_face.expressInterest(directInterest, + [=] (const Interest& interest, const Data& data) { + dataCallback(data, keyRequest, state, continueValidation); + }, + [=] (const Interest& interest, const lp::Nack& nack) { + nackCallback(nack, keyRequest, state, continueValidation); + }, + [=] (const Interest& interest) { + timeoutCallback(keyRequest, state, continueValidation); + }); + } + } + + if (!m_wantDirectInterestOnly) { + // send infrastructure Interest + CertificateFetcherFromNetwork::doFetch(keyRequest, state, continueValidation); + } + else if (incomingFaceId == 0) { + state->fail({ValidationError::Code::CANNOT_RETRIEVE_CERT, + "Cannot direct fetch certificate as IncomingFaceId tag is not set"}); + } +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/certificate-fetcher-direct-fetch.hpp b/ndn-cxx/security/v2/certificate-fetcher-direct-fetch.hpp new file mode 100644 index 000000000..0a5c480a5 --- /dev/null +++ b/ndn-cxx/security/v2/certificate-fetcher-direct-fetch.hpp @@ -0,0 +1,65 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_CERTIFICATE_FETCHER_DIRECT_FETCH_HPP +#define NDN_SECURITY_V2_CERTIFICATE_FETCHER_DIRECT_FETCH_HPP + +#include "ndn-cxx/security/v2/certificate-fetcher-from-network.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +/** + * @brief Extends CertificateFetcherFromNetwork to fetch certificates from the incoming face of + * the packet + * + * During Interest and Data validation, if IncomingFaceId tag is present on the original Interest, + * this fetcher will send a "direct Interest" to fetch certificates from the face where the original + * packet was received, in addition to fetching from the infrastructure. The application must + * enable NextHopFaceId privilege on the face used by this fetcher prior to the validation. + */ +class CertificateFetcherDirectFetch : public CertificateFetcherFromNetwork +{ +public: + explicit + CertificateFetcherDirectFetch(Face& face); + + /** + * If \p wantDirectInterestOnly, only the direct Interest will be sent out. + */ + void + setSendDirectInterestOnly(bool wantDirectInterestOnly); + +protected: + void + doFetch(const shared_ptr& keyRequest, const shared_ptr& state, + const ValidationContinuation& continueValidation) override; + +private: + bool m_wantDirectInterestOnly = false; +}; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_CERTIFICATE_FETCHER_DIRECT_FETCH_HPP diff --git a/ndn-cxx/security/v2/certificate-fetcher-from-network.cpp b/ndn-cxx/security/v2/certificate-fetcher-from-network.cpp new file mode 100644 index 000000000..9545f32b6 --- /dev/null +++ b/ndn-cxx/security/v2/certificate-fetcher-from-network.cpp @@ -0,0 +1,118 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/certificate-fetcher-from-network.hpp" +#include "ndn-cxx/face.hpp" +#include "ndn-cxx/util/logger.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +NDN_LOG_INIT(ndn.security.v2.CertificateFetcher.FromNetwork); + +#define NDN_LOG_DEBUG_DEPTH(x) NDN_LOG_DEBUG(std::string(state->getDepth() + 1, '>') << " " << x) +#define NDN_LOG_TRACE_DEPTH(x) NDN_LOG_TRACE(std::string(state->getDepth() + 1, '>') << " " << x) + +CertificateFetcherFromNetwork::CertificateFetcherFromNetwork(Face& face) + : m_face(face) + , m_scheduler(face.getIoService()) +{ +} + +void +CertificateFetcherFromNetwork::doFetch(const shared_ptr& certRequest, + const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + m_face.expressInterest(certRequest->interest, + [=] (const Interest& interest, const Data& data) { + dataCallback(data, certRequest, state, continueValidation); + }, + [=] (const Interest& interest, const lp::Nack& nack) { + nackCallback(nack, certRequest, state, continueValidation); + }, + [=] (const Interest& interest) { + timeoutCallback(certRequest, state, continueValidation); + }); +} + +void +CertificateFetcherFromNetwork::dataCallback(const Data& data, + const shared_ptr& certRequest, + const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + NDN_LOG_DEBUG_DEPTH("Fetched certificate from network " << data.getName()); + + Certificate cert; + try { + cert = Certificate(data); + } + catch (const tlv::Error& e) { + return state->fail({ValidationError::Code::MALFORMED_CERT, "Fetched a malformed certificate " + "`" + data.getName().toUri() + "` (" + e.what() + ")"}); + } + continueValidation(cert, state); +} + +void +CertificateFetcherFromNetwork::nackCallback(const lp::Nack& nack, + const shared_ptr& certRequest, + const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + NDN_LOG_DEBUG_DEPTH("NACK (" << nack.getReason() << ") while fetching certificate " + << certRequest->interest.getName()); + + --certRequest->nRetriesLeft; + if (certRequest->nRetriesLeft >= 0) { + m_scheduler.schedule(certRequest->waitAfterNack, + [=] { fetch(certRequest, state, continueValidation); }); + certRequest->waitAfterNack *= 2; + } + else { + state->fail({ValidationError::Code::CANNOT_RETRIEVE_CERT, "Cannot fetch certificate after all " + "retries `" + certRequest->interest.getName().toUri() + "`"}); + } +} + +void +CertificateFetcherFromNetwork::timeoutCallback(const shared_ptr& certRequest, + const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + NDN_LOG_DEBUG_DEPTH("Timeout while fetching certificate " << certRequest->interest.getName() + << ", retrying"); + + --certRequest->nRetriesLeft; + if (certRequest->nRetriesLeft >= 0) { + fetch(certRequest, state, continueValidation); + } + else { + state->fail({ValidationError::Code::CANNOT_RETRIEVE_CERT, "Cannot fetch certificate after all " + "retries `" + certRequest->interest.getName().toUri() + "`"}); + } +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/certificate-fetcher-from-network.hpp b/ndn-cxx/security/v2/certificate-fetcher-from-network.hpp new file mode 100644 index 000000000..35b960a6b --- /dev/null +++ b/ndn-cxx/security/v2/certificate-fetcher-from-network.hpp @@ -0,0 +1,87 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_CERTIFICATE_FETCHER_FROM_NETWORK_HPP +#define NDN_SECURITY_V2_CERTIFICATE_FETCHER_FROM_NETWORK_HPP + +#include "ndn-cxx/security/v2/certificate-fetcher.hpp" +#include "ndn-cxx/util/scheduler.hpp" + +namespace ndn { + +namespace lp { +class Nack; +} // namespace lp + +namespace security { +namespace v2 { + +/** + * @brief Fetch missing keys from the network + */ +class CertificateFetcherFromNetwork : public CertificateFetcher +{ +public: + explicit + CertificateFetcherFromNetwork(Face& face); + +protected: + void + doFetch(const shared_ptr& certRequest, const shared_ptr& state, + const ValidationContinuation& continueValidation) override; + + /** + * @brief Callback invoked when certificate is retrieved. + */ + void + dataCallback(const Data& data, + const shared_ptr& certRequest, const shared_ptr& state, + const ValidationContinuation& continueValidation); + + /** + * @brief Callback invoked when interest for fetching certificate gets NACKed. + * + * Retries with exponential backoff while `certRequest->nRetriesLeft > 0` + */ + void + nackCallback(const lp::Nack& nack, + const shared_ptr& certRequest, const shared_ptr& state, + const ValidationContinuation& continueValidation); + + /** + * @brief Callback invoked when interest for fetching certificate times out. + * + * It will retry if `certRequest->nRetriesLeft > 0` + */ + void + timeoutCallback(const shared_ptr& certRequest, const shared_ptr& state, + const ValidationContinuation& continueValidation); + +protected: + Face& m_face; + Scheduler m_scheduler; +}; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_CERTIFICATE_FETCHER_FROM_NETWORK_HPP diff --git a/ndn-cxx/security/v2/certificate-fetcher-offline.cpp b/ndn-cxx/security/v2/certificate-fetcher-offline.cpp new file mode 100644 index 000000000..589f9cd02 --- /dev/null +++ b/ndn-cxx/security/v2/certificate-fetcher-offline.cpp @@ -0,0 +1,39 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/certificate-fetcher-offline.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +void +CertificateFetcherOffline::doFetch(const shared_ptr& certRequest, + const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + state->fail({ValidationError::Code::CANNOT_RETRIEVE_CERT, + "Cannot fetch certificate " + certRequest->interest.getName().toUri() + " in offline mode"}); +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/certificate-fetcher-offline.hpp b/ndn-cxx/security/v2/certificate-fetcher-offline.hpp new file mode 100644 index 000000000..2cb7386d9 --- /dev/null +++ b/ndn-cxx/security/v2/certificate-fetcher-offline.hpp @@ -0,0 +1,46 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_CERTIFICATE_FETCHER_OFFLINE_HPP +#define NDN_SECURITY_V2_CERTIFICATE_FETCHER_OFFLINE_HPP + +#include "ndn-cxx/security/v2/certificate-fetcher.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +/** + * @brief Certificate fetcher realization that does not fetch keys (always offline) + */ +class CertificateFetcherOffline : public CertificateFetcher +{ +protected: + void + doFetch(const shared_ptr& certRequest, const shared_ptr& state, + const ValidationContinuation& continueValidation) override; +}; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_CERTIFICATE_FETCHER_OFFLINE_HPP diff --git a/ndn-cxx/security/v2/certificate-fetcher.cpp b/ndn-cxx/security/v2/certificate-fetcher.cpp new file mode 100644 index 000000000..672944fd2 --- /dev/null +++ b/ndn-cxx/security/v2/certificate-fetcher.cpp @@ -0,0 +1,67 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/certificate-fetcher.hpp" +#include "ndn-cxx/util/logger.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +NDN_LOG_INIT(ndn.security.v2.CertificateFetcher); + +#define NDN_LOG_DEBUG_DEPTH(x) NDN_LOG_DEBUG(std::string(state->getDepth() + 1, '>') << " " << x) + +CertificateFetcher::CertificateFetcher() + : m_certStorage(nullptr) +{ +} + +CertificateFetcher::~CertificateFetcher() = default; + +void +CertificateFetcher::setCertificateStorage(CertificateStorage& certStorage) +{ + m_certStorage = &certStorage; +} + +void +CertificateFetcher::fetch(const shared_ptr& certRequest, + const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + BOOST_ASSERT(m_certStorage != nullptr); + auto cert = m_certStorage->getUnverifiedCertCache().find(certRequest->interest); + if (cert != nullptr) { + NDN_LOG_DEBUG_DEPTH("Found certificate in **un**verified key cache " << cert->getName()); + continueValidation(*cert, state); + return; + } + doFetch(certRequest, state, + [continueValidation, this] (const Certificate& cert, const shared_ptr& state) { + m_certStorage->cacheUnverifiedCert(Certificate(cert)); + continueValidation(cert, state); + }); +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/certificate-fetcher.hpp b/ndn-cxx/security/v2/certificate-fetcher.hpp new file mode 100644 index 000000000..4a29a793f --- /dev/null +++ b/ndn-cxx/security/v2/certificate-fetcher.hpp @@ -0,0 +1,91 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_CERTIFICATE_FETCHER_HPP +#define NDN_SECURITY_V2_CERTIFICATE_FETCHER_HPP + +#include "ndn-cxx/security/v2/certificate-request.hpp" +#include "ndn-cxx/security/v2/certificate-storage.hpp" +#include "ndn-cxx/security/v2/validation-state.hpp" + +namespace ndn { + +class Face; + +namespace security { +namespace v2 { + +/** + * @brief Interface used by the validator to fetch missing certificates + */ +class CertificateFetcher : noncopyable +{ +public: + using ValidationContinuation = std::function& state)>; + + CertificateFetcher(); + + virtual + ~CertificateFetcher(); + + /** + * @brief Assign certificate storage to check known certificate and to cache unverified ones + * @note The supplied @p certStorage should be valid for the lifetime of CertificateFetcher + */ + virtual void + setCertificateStorage(CertificateStorage& certStorage); + + /** + * @brief Asynchronously fetch certificate + * @pre m_certStorage != nullptr + * + * If the requested certificate exists in the storage, then this method will immediately call + * continueValidation with the certification. If certificate is not available, the + * implementation-specific doFetch will be called to asynchronously fetch certificate. The + * successfully retrieved certificate will be automatically added to the unverified cache of + * the certificate storage. + * + * When the requested certificate is retrieved, continueValidation is called. Otherwise, the + * fetcher implementation call state->failed() with the appropriate error code and diagnostic + * message. + */ + void + fetch(const shared_ptr& certRequest, const shared_ptr& state, + const ValidationContinuation& continueValidation); + +private: + /** + * @brief Asynchronous certificate fetching implementation + */ + virtual void + doFetch(const shared_ptr& certRequest, const shared_ptr& state, + const ValidationContinuation& continueValidation) = 0; + +protected: + CertificateStorage* m_certStorage; +}; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_CERTIFICATE_FETCHER_HPP diff --git a/ndn-cxx/security/v2/certificate-request.hpp b/ndn-cxx/security/v2/certificate-request.hpp new file mode 100644 index 000000000..13859df31 --- /dev/null +++ b/ndn-cxx/security/v2/certificate-request.hpp @@ -0,0 +1,65 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_CERTIFICATE_REQUEST_HPP +#define NDN_SECURITY_V2_CERTIFICATE_REQUEST_HPP + +#include "ndn-cxx/interest.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +/** + * @brief Request for a certificate, associated with the number of attempts + */ +class CertificateRequest : noncopyable +{ +public: + CertificateRequest() = default; + + explicit + CertificateRequest(const Interest& interest) + : interest(interest) + , nRetriesLeft(3) + { + } + + explicit + CertificateRequest(const Name& name) + : CertificateRequest(Interest(name).setCanBePrefix(true)) + { + } + +public: + /// @brief the name for the requested data/certificate. + Interest interest; + /// @brief the number of remaining retries after timeout or NACK. + int nRetriesLeft = 0; + /// @brief the amount of time to wait before sending the next interest after a NACK. + time::milliseconds waitAfterNack = 500_ms; +}; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_CERTIFICATE_REQUEST_HPP diff --git a/ndn-cxx/security/v2/certificate-storage.cpp b/ndn-cxx/security/v2/certificate-storage.cpp new file mode 100644 index 000000000..e245f24b2 --- /dev/null +++ b/ndn-cxx/security/v2/certificate-storage.cpp @@ -0,0 +1,111 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/certificate-storage.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +CertificateStorage::CertificateStorage() + : m_verifiedCertCache(1_h) + , m_unverifiedCertCache(5_min) +{ +} + +const Certificate* +CertificateStorage::findTrustedCert(const Interest& interestForCert) const +{ + auto cert = m_trustAnchors.find(interestForCert); + if (cert != nullptr) { + return cert; + } + + cert = m_verifiedCertCache.find(interestForCert); + return cert; +} + +bool +CertificateStorage::isCertKnown(const Name& certName) const +{ + return (m_trustAnchors.find(certName) != nullptr || + m_verifiedCertCache.find(certName) != nullptr || + m_unverifiedCertCache.find(certName) != nullptr); +} + +void +CertificateStorage::loadAnchor(const std::string& groupId, Certificate&& cert) +{ + m_trustAnchors.insert(groupId, std::move(cert)); +} + +void +CertificateStorage::loadAnchor(const std::string& groupId, const std::string& certfilePath, + time::nanoseconds refreshPeriod, bool isDir) +{ + m_trustAnchors.insert(groupId, certfilePath, refreshPeriod, isDir); +} + +void +CertificateStorage::resetAnchors() +{ + m_trustAnchors.clear(); +} + +void +CertificateStorage::cacheVerifiedCert(Certificate&& cert) +{ + m_verifiedCertCache.insert(std::move(cert)); +} + +void +CertificateStorage::resetVerifiedCerts() +{ + m_verifiedCertCache.clear(); +} + +void +CertificateStorage::cacheUnverifiedCert(Certificate&& cert) +{ + m_unverifiedCertCache.insert(std::move(cert)); +} + +const TrustAnchorContainer& +CertificateStorage::getTrustAnchors() const +{ + return m_trustAnchors; +} + +const CertificateCache& +CertificateStorage::getVerifiedCertCache() const +{ + return m_verifiedCertCache; +} + +const CertificateCache& +CertificateStorage::getUnverifiedCertCache() const +{ + return m_unverifiedCertCache; +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/certificate-storage.hpp b/ndn-cxx/security/v2/certificate-storage.hpp new file mode 100644 index 000000000..412907a60 --- /dev/null +++ b/ndn-cxx/security/v2/certificate-storage.hpp @@ -0,0 +1,143 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_CERTIFICATE_STORAGE_HPP +#define NDN_SECURITY_V2_CERTIFICATE_STORAGE_HPP + +#include "ndn-cxx/security/v2/certificate.hpp" +#include "ndn-cxx/security/v2/certificate-cache.hpp" +#include "ndn-cxx/security/v2/trust-anchor-container.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +/** + * @brief Storage for trusted anchors, verified certificate cache, and unverified certificate cache. + */ +class CertificateStorage : noncopyable +{ +public: + CertificateStorage(); + + /** + * @brief Find a trusted certificate in trust anchor container or in verified cache + * @param interestForCert Interest for certificate + * @return found certificate, nullptr if not found. + * + * @note The returned pointer may get invalidated after next findTrustedCert or findCert calls. + */ + const Certificate* + findTrustedCert(const Interest& interestForCert) const; + + /** + * @brief Check if certificate exists in verified, unverified cache, or in the set of trust + * anchors + */ + bool + isCertKnown(const Name& certPrefix) const; + + /** + * @brief Cache unverified certificate for a period of time (5 minutes) + * @param cert The certificate packet + * + * @todo Add ability to customize time period + */ + void + cacheUnverifiedCert(Certificate&& cert); + + /** + * @return Trust anchor container + */ + const TrustAnchorContainer& + getTrustAnchors() const; + + /** + * @return Verified certificate cache + */ + const CertificateCache& + getVerifiedCertCache() const; + + /** + * @return Unverified certificate cache + */ + const CertificateCache& + getUnverifiedCertCache() const; + +protected: + /** + * @brief load static trust anchor. + * + * Static trust anchors are permanently associated with the validator and never expire. + * + * @param groupId Certificate group id. + * @param cert Certificate to load as a trust anchor. + */ + void + loadAnchor(const std::string& groupId, Certificate&& cert); + + /** + * @brief load dynamic trust anchors. + * + * Dynamic trust anchors are associated with the validator for as long as the underlying + * trust anchor file (set of files) exist(s). + * + * @param groupId Certificate group id, must not be empty. + * @param certfilePath Specifies the path to load the trust anchors. + * @param refreshPeriod Refresh period for the trust anchors, must be positive. + * @param isDir Tells whether the path is a directory or a single file. + */ + void + loadAnchor(const std::string& groupId, const std::string& certfilePath, + time::nanoseconds refreshPeriod, bool isDir = false); + + /** + * @brief remove any previously loaded static or dynamic trust anchor + */ + void + resetAnchors(); + + /** + * @brief Cache verified certificate a period of time (1 hour) + * @param cert The certificate packet + * + * @todo Add ability to customize time period + */ + void + cacheVerifiedCert(Certificate&& cert); + + /** + * @brief Remove any cached verified certificates + */ + void + resetVerifiedCerts(); + +protected: + TrustAnchorContainer m_trustAnchors; + CertificateCache m_verifiedCertCache; + CertificateCache m_unverifiedCertCache; +}; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_CERTIFICATE_STORAGE_HPP diff --git a/ndn-cxx/security/v2/certificate.cpp b/ndn-cxx/security/v2/certificate.cpp new file mode 100644 index 000000000..83e16567f --- /dev/null +++ b/ndn-cxx/security/v2/certificate.cpp @@ -0,0 +1,208 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Zhiyi Zhang + * @author Yingdi Yu + */ + +#include "ndn-cxx/security/v2/certificate.hpp" +#include "ndn-cxx/security/v2/additional-description.hpp" +#include "ndn-cxx/security/transform.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/util/indented-stream.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +BOOST_CONCEPT_ASSERT((WireEncodable)); +BOOST_CONCEPT_ASSERT((WireDecodable)); + +// //KEY/[KeyId]/[IssuerId]/[Version] + +const ssize_t Certificate::VERSION_OFFSET = -1; +const ssize_t Certificate::ISSUER_ID_OFFSET = -2; +const ssize_t Certificate::KEY_ID_OFFSET = -3; +const ssize_t Certificate::KEY_COMPONENT_OFFSET = -4; +const size_t Certificate::MIN_CERT_NAME_LENGTH = 4; +const size_t Certificate::MIN_KEY_NAME_LENGTH = 2; +const name::Component Certificate::KEY_COMPONENT("KEY"); + +Certificate::Certificate() +{ + setContentType(tlv::ContentType_Key); +} + +Certificate::Certificate(Data&& data) + : Data(data) +{ + if (!isValidName(getName())) { + NDN_THROW(Data::Error("Name does not follow the naming convention for certificate")); + } + if (getContentType() != tlv::ContentType_Key) { + NDN_THROW(Data::Error("Expecting ContentType Key, got " + to_string(getContentType()))); + } + if (getFreshnessPeriod() < time::seconds::zero()) { + NDN_THROW(Data::Error("FreshnessPeriod is not set")); + } + if (getContent().value_size() == 0) { + NDN_THROW(Data::Error("Content is empty")); + } +} + +Certificate::Certificate(const Data& data) + : Certificate(Data(data)) +{ +} + +Certificate::Certificate(const Block& block) + : Certificate(Data(block)) +{ +} + +Name +Certificate::getKeyName() const +{ + return getName().getPrefix(KEY_ID_OFFSET + 1); +} + +Name +Certificate::getIdentity() const +{ + return getName().getPrefix(KEY_COMPONENT_OFFSET); +} + +name::Component +Certificate::getKeyId() const +{ + return getName().at(KEY_ID_OFFSET); +} + +name::Component +Certificate::getIssuerId() const +{ + return getName().at(ISSUER_ID_OFFSET); +} + +Buffer +Certificate::getPublicKey() const +{ + if (getContent().value_size() == 0) + NDN_THROW(Data::Error("Content is empty")); + return Buffer(getContent().value(), getContent().value_size()); +} + +ValidityPeriod +Certificate::getValidityPeriod() const +{ + return getSignature().getSignatureInfo().getValidityPeriod(); +} + +bool +Certificate::isValid(const time::system_clock::TimePoint& ts) const +{ + return getSignature().getSignatureInfo().getValidityPeriod().isValid(ts); +} + +const Block& +Certificate::getExtension(uint32_t type) const +{ + return getSignature().getSignatureInfo().getTypeSpecificTlv(type); +} + +bool +Certificate::isValidName(const Name& certName) +{ + // //KEY/[KeyId]/[IssuerId]/[Version] + return (certName.size() >= Certificate::MIN_CERT_NAME_LENGTH && + certName.get(Certificate::KEY_COMPONENT_OFFSET) == Certificate::KEY_COMPONENT); +} + +std::ostream& +operator<<(std::ostream& os, const Certificate& cert) +{ + os << "Certificate name:\n"; + os << " " << cert.getName() << "\n"; + os << "Validity:\n"; + { + os << " NotBefore: " << time::toIsoString(cert.getValidityPeriod().getPeriod().first) << "\n"; + os << " NotAfter: " << time::toIsoString(cert.getValidityPeriod().getPeriod().second) << "\n"; + } + + try { + const Block& info = cert.getSignature().getSignatureInfo().getTypeSpecificTlv(tlv::AdditionalDescription); + os << "Additional Description:\n"; + for (const auto& item : v2::AdditionalDescription(info)) { + os << " " << item.first << ": " << item.second << "\n"; + } + } + catch (const SignatureInfo::Error&) { + // ignore + } + + os << "Public key bits:\n"; + { + using namespace transform; + util::IndentedStream os2(os, " "); + bufferSource(cert.getPublicKey().data(), cert.getPublicKey().size()) >> base64Encode() >> streamSink(os2); + } + + os << "Signature Information:\n"; + { + os << " Signature Type: " << cert.getSignature().getType() << "\n"; + + if (cert.getSignature().hasKeyLocator()) { + os << " Key Locator: "; + const auto& keyLocator = cert.getSignature().getKeyLocator(); + if (keyLocator.getType() == tlv::Name && keyLocator.getName() == cert.getKeyName()) { + os << "Self-Signed "; + } + os << keyLocator << "\n"; + } + } + + return os; +} + +Name +extractIdentityFromCertName(const Name& certName) +{ + if (!Certificate::isValidName(certName)) { + NDN_THROW(std::invalid_argument("Certificate name `" + certName.toUri() + "` " + "does not respect the naming conventions")); + } + + return certName.getPrefix(Certificate::KEY_COMPONENT_OFFSET); // trim everything after and including "KEY" +} + +Name +extractKeyNameFromCertName(const Name& certName) +{ + if (!Certificate::isValidName(certName)) { + NDN_THROW(std::invalid_argument("Certificate name `" + certName.toUri() + "` " + "does not respect the naming conventions")); + } + + return certName.getPrefix(Certificate::KEY_ID_OFFSET + 1); // trim everything after key id +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/certificate.hpp b/ndn-cxx/security/v2/certificate.hpp new file mode 100644 index 000000000..12621ea34 --- /dev/null +++ b/ndn-cxx/security/v2/certificate.hpp @@ -0,0 +1,194 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Zhiyi Zhang + * @author Yingdi Yu + */ + +#ifndef NDN_SECURITY_V2_CERTIFICATE_HPP +#define NDN_SECURITY_V2_CERTIFICATE_HPP + +#include "ndn-cxx/data.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +/** + * @brief The certificate following the certificate format naming convention + * + * Overview of NDN certificate format: + * + * CertificateV2 ::= DATA-TLV TLV-LENGTH + * Name (= //KEY/[KeyId]/[IssuerId]/[Version]) + * MetaInfo (.ContentType = KEY) + * Content (= X509PublicKeyContent) + * SignatureInfo (= CertificateV2SignatureInfo) + * SignatureValue + * + * X509PublicKeyContent ::= CONTENT-TLV TLV-LENGTH + * BYTE+ (= public key bits in PKCS#8 format) + * + * CertificateV2SignatureInfo ::= SIGNATURE-INFO-TYPE TLV-LENGTH + * SignatureType + * KeyLocator + * ValidityPeriod + * ... optional critical or non-critical extension blocks ... + * + * An example of NDN certificate name: + * + * /edu/ucla/cs/yingdi/KEY/%03%CD...%F1/%9F%D3...%B7/%FD%d2...%8E + * \_________________/ \___________/ \___________/\___________/ + * Certificate Namespace Key Id Issuer Id Version + * (Identity) + * \__________________________________/ + * Key Name + * + * Notes: + * + * - `Key Id` is opaque name component to identify an instance of the public key for the + * certificate namespace. The value of `Key ID` is controlled by the namespace owner. The + * library includes helpers for generation of key IDs using 8-byte random number, SHA-256 + * digest of the public key, timestamp, and the specified numerical identifiers. + * + * - `Issuer Id` is opaque name component to identify issuer of the certificate. The value is + * controlled by the issuer. The library includes helpers to set issuer ID to a 8-byte + * random number, SHA-256 digest of the issuer's public key, and the specified numerical + * identifiers. + * + * - `Key Name` is a logical name of the key used for management pursposes. Key Name includes + * the certificate namespace, keyword `KEY`, and `KeyId` components. + * + * @see doc/specs/certificate-format.rst + */ +class Certificate : public Data +{ +public: + Certificate(); + + /** + * @brief Construct certificate from a data object + * @throw tlv::Error if data does not follow certificate format + */ + explicit + Certificate(Data&& data); + + /** + * @brief Construct certificate from a data object + * @throw tlv::Error if data does not follow certificate format + */ + explicit + Certificate(const Data& data); + + /** + * @brief Construct certificate from a wire encoding + * @throw tlv::Error if wire encoding is invalid or does not follow certificate format + */ + explicit + Certificate(const Block& block); + + /** + * @brief Get key name + */ + Name + getKeyName() const; + + /** + * @brief Get identity name + */ + Name + getIdentity() const; + + /** + * @brief Get key ID + */ + name::Component + getKeyId() const; + + /** + * @brief Get issuer ID + */ + name::Component + getIssuerId() const; + + /** + * @brief Get public key bits (in PKCS#8 format) + * @throw Error If content is empty + */ + Buffer + getPublicKey() const; + + /** + * @brief Get validity period of the certificate + */ + ValidityPeriod + getValidityPeriod() const; + + /** + * @brief Check if the certificate is valid at @p ts. + */ + bool + isValid(const time::system_clock::TimePoint& ts = time::system_clock::now()) const; + + /** + * @brief Get extension with TLV @p type + * @throw ndn::SignatureInfo::Error if the specified block type does not exist + */ + const Block& + getExtension(uint32_t type) const; + + // @TODO Implement extension enumeration (Issue #3907) +public: + /** + * @brief Check if the specified name follows the naming convention for the certificate + */ + static bool + isValidName(const Name& certName); + +public: + static const ssize_t VERSION_OFFSET; + static const ssize_t ISSUER_ID_OFFSET; + static const ssize_t KEY_COMPONENT_OFFSET; + static const ssize_t KEY_ID_OFFSET; + static const size_t MIN_CERT_NAME_LENGTH; + static const size_t MIN_KEY_NAME_LENGTH; + static const name::Component KEY_COMPONENT; +}; + +std::ostream& +operator<<(std::ostream& os, const Certificate& cert); + +/** + * @brief Extract identity namespace from the certificate name @p certName + */ +Name +extractIdentityFromCertName(const Name& certName); + +/** + * @brief Extract key name from the certificate name @p certName + */ +Name +extractKeyNameFromCertName(const Name& certName); + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_CERTIFICATE_HPP diff --git a/ndn-cxx/security/v2/key-chain.cpp b/ndn-cxx/security/v2/key-chain.cpp new file mode 100644 index 000000000..63f1d985d --- /dev/null +++ b/ndn-cxx/security/v2/key-chain.cpp @@ -0,0 +1,726 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/key-chain.hpp" + +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/util/config-file.hpp" +#include "ndn-cxx/util/logger.hpp" +#include "ndn-cxx/util/sha256.hpp" + +#include "ndn-cxx/security/pib/impl/pib-memory.hpp" +#include "ndn-cxx/security/pib/impl/pib-sqlite3.hpp" + +#include "ndn-cxx/security/tpm/impl/back-end-file.hpp" +#include "ndn-cxx/security/tpm/impl/back-end-mem.hpp" +#ifdef NDN_CXX_HAVE_OSX_FRAMEWORKS +#include "ndn-cxx/security/tpm/impl/back-end-osx.hpp" +#endif // NDN_CXX_HAVE_OSX_FRAMEWORKS + +#include "ndn-cxx/security/transform/bool-sink.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/private-key.hpp" +#include "ndn-cxx/security/transform/public-key.hpp" +#include "ndn-cxx/security/transform/verifier-filter.hpp" + +#include + +namespace ndn { +namespace security { + +// When static library is used, not everything is compiled into the resulting binary. +// Therefore, the following standard PIB and TPMs need to be registered here. +// http://stackoverflow.com/q/9459980/2150331 + +namespace pib { +NDN_CXX_V2_KEYCHAIN_REGISTER_PIB_BACKEND(PibSqlite3); +NDN_CXX_V2_KEYCHAIN_REGISTER_PIB_BACKEND(PibMemory); +} // namespace pib + +namespace tpm { +#if defined(NDN_CXX_HAVE_OSX_FRAMEWORKS) && defined(NDN_CXX_WITH_OSX_KEYCHAIN) +NDN_CXX_V2_KEYCHAIN_REGISTER_TPM_BACKEND(BackEndOsx); +#endif // defined(NDN_CXX_HAVE_OSX_FRAMEWORKS) && defined(NDN_CXX_WITH_OSX_KEYCHAIN) +NDN_CXX_V2_KEYCHAIN_REGISTER_TPM_BACKEND(BackEndFile); +NDN_CXX_V2_KEYCHAIN_REGISTER_TPM_BACKEND(BackEndMem); +} // namespace tpm + +namespace v2 { + +NDN_LOG_INIT(ndn.security.v2.KeyChain); + +std::string KeyChain::s_defaultPibLocator; +std::string KeyChain::s_defaultTpmLocator; + +KeyChain::PibFactories& +KeyChain::getPibFactories() +{ + static PibFactories pibFactories; + return pibFactories; +} + +KeyChain::TpmFactories& +KeyChain::getTpmFactories() +{ + static TpmFactories tpmFactories; + return tpmFactories; +} + +const std::string& +KeyChain::getDefaultPibScheme() +{ + return pib::PibSqlite3::getScheme(); +} + +const std::string& +KeyChain::getDefaultTpmScheme() +{ +#if defined(NDN_CXX_HAVE_OSX_FRAMEWORKS) && defined(NDN_CXX_WITH_OSX_KEYCHAIN) + return tpm::BackEndOsx::getScheme(); +#else + return tpm::BackEndFile::getScheme(); +#endif // defined(NDN_CXX_HAVE_OSX_FRAMEWORKS) && defined(NDN_CXX_WITH_OSX_KEYCHAIN) +} + +const std::string& +KeyChain::getDefaultPibLocator() +{ + if (!s_defaultPibLocator.empty()) + return s_defaultPibLocator; + + if (getenv("NDN_CLIENT_PIB") != nullptr) { + s_defaultPibLocator = getenv("NDN_CLIENT_PIB"); + } + else { + ConfigFile config; + s_defaultPibLocator = config.getParsedConfiguration().get("pib", getDefaultPibScheme() + ":"); + } + + std::string pibScheme, pibLocation; + std::tie(pibScheme, pibLocation) = parseAndCheckPibLocator(s_defaultPibLocator); + s_defaultPibLocator = pibScheme + ":" + pibLocation; + + return s_defaultPibLocator; +} + +const std::string& +KeyChain::getDefaultTpmLocator() +{ + if (!s_defaultTpmLocator.empty()) + return s_defaultTpmLocator; + + if (getenv("NDN_CLIENT_TPM") != nullptr) { + s_defaultTpmLocator = getenv("NDN_CLIENT_TPM"); + } + else { + ConfigFile config; + s_defaultTpmLocator = config.getParsedConfiguration().get("tpm", getDefaultTpmScheme() + ":"); + } + + std::string tpmScheme, tpmLocation; + std::tie(tpmScheme, tpmLocation) = parseAndCheckTpmLocator(s_defaultTpmLocator); + s_defaultTpmLocator = tpmScheme + ":" + tpmLocation; + + return s_defaultTpmLocator; +} + + +// Other defaults + +const SigningInfo& +KeyChain::getDefaultSigningInfo() +{ + static SigningInfo signingInfo; + return signingInfo; +} + +const KeyParams& +KeyChain::getDefaultKeyParams() +{ + static EcKeyParams keyParams; + return keyParams; +} + +// + +KeyChain::KeyChain() + : KeyChain(getDefaultPibLocator(), getDefaultTpmLocator(), true) +{ +} + +KeyChain::KeyChain(const std::string& pibLocator, const std::string& tpmLocator, bool allowReset) +{ + // PIB Locator + std::string pibScheme, pibLocation; + std::tie(pibScheme, pibLocation) = parseAndCheckPibLocator(pibLocator); + std::string canonicalPibLocator = pibScheme + ":" + pibLocation; + + // Create PIB + m_pib = createPib(canonicalPibLocator); + std::string oldTpmLocator; + try { + oldTpmLocator = m_pib->getTpmLocator(); + } + catch (const Pib::Error&) { + // TPM locator is not set in PIB yet. + } + + // TPM Locator + std::string tpmScheme, tpmLocation; + std::tie(tpmScheme, tpmLocation) = parseAndCheckTpmLocator(tpmLocator); + std::string canonicalTpmLocator = tpmScheme + ":" + tpmLocation; + + if (canonicalPibLocator == getDefaultPibLocator()) { + // Default PIB must use default TPM + if (!oldTpmLocator.empty() && oldTpmLocator != getDefaultTpmLocator()) { + m_pib->reset(); + canonicalTpmLocator = getDefaultTpmLocator(); + } + } + else { + // non-default PIB check consistency + if (!oldTpmLocator.empty() && oldTpmLocator != canonicalTpmLocator) { + if (allowReset) + m_pib->reset(); + else + NDN_THROW(LocatorMismatchError("TPM locator supplied does not match TPM locator in PIB: " + + oldTpmLocator + " != " + canonicalTpmLocator)); + } + } + + // note that key mismatch may still happen if the TPM locator is initially set to a + // wrong one or if the PIB was shared by more than one TPMs before. This is due to the + // old PIB does not have TPM info, new pib should not have this problem. + m_tpm = createTpm(canonicalTpmLocator); + m_pib->setTpmLocator(canonicalTpmLocator); +} + +KeyChain::~KeyChain() = default; + +// public: management + +Identity +KeyChain::createIdentity(const Name& identityName, const KeyParams& params) +{ + Identity id = m_pib->addIdentity(identityName); + + Key key; + try { + key = id.getDefaultKey(); + } + catch (const Pib::Error&) { + key = createKey(id, params); + } + + try { + key.getDefaultCertificate(); + } + catch (const Pib::Error&) { + NDN_LOG_DEBUG("No default cert for " << key.getName() << ", requesting self-signing"); + selfSign(key); + } + + return id; +} + +void +KeyChain::deleteIdentity(const Identity& identity) +{ + BOOST_ASSERT(static_cast(identity)); + + Name identityName = identity.getName(); + + for (const auto& key : identity.getKeys()) { + m_tpm->deleteKey(key.getName()); + } + + m_pib->removeIdentity(identityName); +} + +void +KeyChain::setDefaultIdentity(const Identity& identity) +{ + BOOST_ASSERT(static_cast(identity)); + + m_pib->setDefaultIdentity(identity.getName()); +} + +Key +KeyChain::createKey(const Identity& identity, const KeyParams& params) +{ + BOOST_ASSERT(static_cast(identity)); + + // create key in TPM + Name keyName = m_tpm->createKey(identity.getName(), params); + + // set up key info in PIB + ConstBufferPtr pubKey = m_tpm->getPublicKey(keyName); + Key key = identity.addKey(pubKey->data(), pubKey->size(), keyName); + + NDN_LOG_DEBUG("Requesting self-signing for newly created key " << key.getName()); + selfSign(key); + + return key; +} + +Name +KeyChain::createHmacKey(const Name& prefix, const HmacKeyParams& params) +{ + return m_tpm->createKey(prefix, params); +} + +void +KeyChain::deleteKey(const Identity& identity, const Key& key) +{ + BOOST_ASSERT(static_cast(identity)); + BOOST_ASSERT(static_cast(key)); + + Name keyName = key.getName(); + if (identity.getName() != key.getIdentity()) { + NDN_THROW(std::invalid_argument("Identity `" + identity.getName().toUri() + "` " + "does not match key `" + keyName.toUri() + "`")); + } + + identity.removeKey(keyName); + m_tpm->deleteKey(keyName); +} + +void +KeyChain::setDefaultKey(const Identity& identity, const Key& key) +{ + BOOST_ASSERT(static_cast(identity)); + BOOST_ASSERT(static_cast(key)); + + if (identity.getName() != key.getIdentity()) + NDN_THROW(std::invalid_argument("Identity `" + identity.getName().toUri() + "` " + "does not match key `" + key.getName().toUri() + "`")); + + identity.setDefaultKey(key.getName()); +} + +void +KeyChain::addCertificate(const Key& key, const Certificate& certificate) +{ + BOOST_ASSERT(static_cast(key)); + + if (key.getName() != certificate.getKeyName() || + !std::equal(certificate.getContent().value_begin(), certificate.getContent().value_end(), + key.getPublicKey().begin())) + NDN_THROW(std::invalid_argument("Key `" + key.getName().toUri() + "` " + "does not match certificate `" + certificate.getName().toUri() + "`")); + + key.addCertificate(certificate); +} + +void +KeyChain::deleteCertificate(const Key& key, const Name& certificateName) +{ + BOOST_ASSERT(static_cast(key)); + + if (!Certificate::isValidName(certificateName)) { + NDN_THROW(std::invalid_argument("Wrong certificate name `" + certificateName.toUri() + "`")); + } + + key.removeCertificate(certificateName); +} + +void +KeyChain::setDefaultCertificate(const Key& key, const Certificate& cert) +{ + BOOST_ASSERT(static_cast(key)); + + addCertificate(key, cert); + key.setDefaultCertificate(cert.getName()); +} + +shared_ptr +KeyChain::exportSafeBag(const Certificate& certificate, const char* pw, size_t pwLen) +{ + Name identity = certificate.getIdentity(); + Name keyName = certificate.getKeyName(); + + ConstBufferPtr encryptedKey; + try { + encryptedKey = m_tpm->exportPrivateKey(keyName, pw, pwLen); + } + catch (const Tpm::Error&) { + NDN_THROW_NESTED(Error("Failed to export private key `" + keyName.toUri() + "`")); + } + + return make_shared(certificate, *encryptedKey); +} + +void +KeyChain::importSafeBag(const SafeBag& safeBag, const char* pw, size_t pwLen) +{ + Data certData = safeBag.getCertificate(); + Certificate cert(std::move(certData)); + Name identity = cert.getIdentity(); + Name keyName = cert.getKeyName(); + const Buffer publicKeyBits = cert.getPublicKey(); + + if (m_tpm->hasKey(keyName)) { + NDN_THROW(Error("Private key `" + keyName.toUri() + "` already exists")); + } + + try { + Identity existingId = m_pib->getIdentity(identity); + existingId.getKey(keyName); + NDN_THROW(Error("Public key `" + keyName.toUri() + "` already exists")); + } + catch (const Pib::Error&) { + // Either identity or key doesn't exist. OK to import. + } + + try { + m_tpm->importPrivateKey(keyName, + safeBag.getEncryptedKeyBag().data(), safeBag.getEncryptedKeyBag().size(), + pw, pwLen); + } + catch (const Tpm::Error&) { + NDN_THROW_NESTED(Error("Failed to import private key `" + keyName.toUri() + "`")); + } + + // check the consistency of private key and certificate + const uint8_t content[] = {0x01, 0x02, 0x03, 0x04}; + ConstBufferPtr sigBits; + try { + sigBits = m_tpm->sign(content, 4, keyName, DigestAlgorithm::SHA256); + } + catch (const std::runtime_error&) { + m_tpm->deleteKey(keyName); + NDN_THROW(Error("Invalid private key `" + keyName.toUri() + "`")); + } + bool isVerified = false; + { + using namespace transform; + PublicKey publicKey; + publicKey.loadPkcs8(publicKeyBits.data(), publicKeyBits.size()); + bufferSource(content, sizeof(content)) >> verifierFilter(DigestAlgorithm::SHA256, publicKey, + sigBits->data(), sigBits->size()) + >> boolSink(isVerified); + } + if (!isVerified) { + m_tpm->deleteKey(keyName); + NDN_THROW(Error("Certificate `" + cert.getName().toUri() + "` " + "and private key `" + keyName.toUri() + "` do not match")); + } + + Identity id = m_pib->addIdentity(identity); + Key key = id.addKey(cert.getPublicKey().data(), cert.getPublicKey().size(), keyName); + key.addCertificate(cert); +} + +void +KeyChain::importPrivateKey(const Name& keyName, shared_ptr key) +{ + if (m_tpm->hasKey(keyName)) { + NDN_THROW(Error("Private key `" + keyName.toUri() + "` already exists")); + } + + try { + m_tpm->importPrivateKey(keyName, std::move(key)); + } + catch (const Tpm::Error&) { + NDN_THROW_NESTED(Error("Failed to import private key `" + keyName.toUri() + "`")); + } +} + +// public: signing + +void +KeyChain::sign(Data& data, const SigningInfo& params) +{ + Name keyName; + SignatureInfo sigInfo; + std::tie(keyName, sigInfo) = prepareSignatureInfo(params); + + data.setSignature(Signature(sigInfo)); + + EncodingBuffer encoder; + data.wireEncode(encoder, true); + + Block sigValue = sign(encoder.buf(), encoder.size(), keyName, params.getDigestAlgorithm()); + + data.wireEncode(encoder, sigValue); +} + +void +KeyChain::sign(Interest& interest, const SigningInfo& params) +{ + Name keyName; + SignatureInfo sigInfo; + std::tie(keyName, sigInfo) = prepareSignatureInfo(params); + + Name signedName = interest.getName(); + signedName.append(sigInfo.wireEncode()); // signatureInfo + + Block sigValue = sign(signedName.wireEncode().value(), signedName.wireEncode().value_size(), + keyName, params.getDigestAlgorithm()); + + sigValue.encode(); + signedName.append(sigValue); // signatureValue + interest.setName(signedName); +} + +Block +KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const SigningInfo& params) +{ + Name keyName; + SignatureInfo sigInfo; + std::tie(keyName, sigInfo) = prepareSignatureInfo(params); + + return sign(buffer, bufferLength, keyName, params.getDigestAlgorithm()); +} + +// public: PIB/TPM creation helpers + +static inline std::tuple +parseLocatorUri(const std::string& uri) +{ + size_t pos = uri.find(':'); + if (pos != std::string::npos) { + return std::make_tuple(uri.substr(0, pos), uri.substr(pos + 1)); + } + else { + return std::make_tuple(uri, ""); + } +} + +std::tuple +KeyChain::parseAndCheckPibLocator(const std::string& pibLocator) +{ + std::string pibScheme, pibLocation; + std::tie(pibScheme, pibLocation) = parseLocatorUri(pibLocator); + + if (pibScheme.empty()) { + pibScheme = getDefaultPibScheme(); + } + + auto pibFactory = getPibFactories().find(pibScheme); + if (pibFactory == getPibFactories().end()) { + NDN_THROW(KeyChain::Error("PIB scheme `" + pibScheme + "` is not supported")); + } + + return std::make_tuple(pibScheme, pibLocation); +} + +unique_ptr +KeyChain::createPib(const std::string& pibLocator) +{ + std::string pibScheme, pibLocation; + std::tie(pibScheme, pibLocation) = parseAndCheckPibLocator(pibLocator); + auto pibFactory = getPibFactories().find(pibScheme); + BOOST_ASSERT(pibFactory != getPibFactories().end()); + return unique_ptr(new Pib(pibScheme, pibLocation, pibFactory->second(pibLocation))); +} + +std::tuple +KeyChain::parseAndCheckTpmLocator(const std::string& tpmLocator) +{ + std::string tpmScheme, tpmLocation; + std::tie(tpmScheme, tpmLocation) = parseLocatorUri(tpmLocator); + + if (tpmScheme.empty()) { + tpmScheme = getDefaultTpmScheme(); + } + auto tpmFactory = getTpmFactories().find(tpmScheme); + if (tpmFactory == getTpmFactories().end()) { + NDN_THROW(KeyChain::Error("TPM scheme `" + tpmScheme + "` is not supported")); + } + + return std::make_tuple(tpmScheme, tpmLocation); +} + +unique_ptr +KeyChain::createTpm(const std::string& tpmLocator) +{ + std::string tpmScheme, tpmLocation; + std::tie(tpmScheme, tpmLocation) = parseAndCheckTpmLocator(tpmLocator); + auto tpmFactory = getTpmFactories().find(tpmScheme); + BOOST_ASSERT(tpmFactory != getTpmFactories().end()); + return unique_ptr(new Tpm(tpmScheme, tpmLocation, tpmFactory->second(tpmLocation))); +} + +// private: signing + +Certificate +KeyChain::selfSign(Key& key) +{ + Certificate certificate; + + // set name + Name certificateName = key.getName(); + certificateName + .append("self") + .appendVersion(); + certificate.setName(certificateName); + + // set metainfo + certificate.setContentType(tlv::ContentType_Key); + certificate.setFreshnessPeriod(1_h); + + // set content + certificate.setContent(key.getPublicKey().data(), key.getPublicKey().size()); + + // set signature-info + SignatureInfo signatureInfo; + // Note time::system_clock::max() or other NotAfter date results in incorrect encoded value + // because of overflow during conversion to boost::posix_time::ptime (bug #3915). + signatureInfo.setValidityPeriod(ValidityPeriod(time::system_clock::TimePoint(), + time::system_clock::now() + 20 * 365_days)); + + sign(certificate, SigningInfo(key).setSignatureInfo(signatureInfo)); + + key.addCertificate(certificate); + return certificate; +} + +std::tuple +KeyChain::prepareSignatureInfo(const SigningInfo& params) +{ + SignatureInfo sigInfo = params.getSignatureInfo(); + pib::Identity identity; + pib::Key key; + + switch (params.getSignerType()) { + case SigningInfo::SIGNER_TYPE_NULL: { + try { + identity = m_pib->getDefaultIdentity(); + } + catch (const Pib::Error&) { // no default identity, use sha256 for signing. + sigInfo.setSignatureType(tlv::DigestSha256); + NDN_LOG_TRACE("Prepared signature info: " << sigInfo); + return std::make_tuple(SigningInfo::getDigestSha256Identity(), sigInfo); + } + break; + } + case SigningInfo::SIGNER_TYPE_ID: { + identity = params.getPibIdentity(); + if (!identity) { + try { + identity = m_pib->getIdentity(params.getSignerName()); + } + catch (const Pib::Error&) { + NDN_THROW_NESTED(InvalidSigningInfoError("Signing identity `" + + params.getSignerName().toUri() + "` does not exist")); + } + } + break; + } + case SigningInfo::SIGNER_TYPE_KEY: { + key = params.getPibKey(); + if (!key) { + Name identityName = extractIdentityFromKeyName(params.getSignerName()); + try { + key = m_pib->getIdentity(identityName).getKey(params.getSignerName()); + } + catch (const Pib::Error&) { + NDN_THROW_NESTED(InvalidSigningInfoError("Signing key `" + + params.getSignerName().toUri() + "` does not exist")); + } + } + break; + } + case SigningInfo::SIGNER_TYPE_CERT: { + Name identityName = extractIdentityFromCertName(params.getSignerName()); + Name keyName = extractKeyNameFromCertName(params.getSignerName()); + try { + identity = m_pib->getIdentity(identityName); + key = identity.getKey(keyName); + } + catch (const Pib::Error&) { + NDN_THROW_NESTED(InvalidSigningInfoError("Signing certificate `" + + params.getSignerName().toUri() + "` does not exist")); + } + break; + } + case SigningInfo::SIGNER_TYPE_SHA256: { + sigInfo.setSignatureType(tlv::DigestSha256); + NDN_LOG_TRACE("Prepared signature info: " << sigInfo); + return std::make_tuple(SigningInfo::getDigestSha256Identity(), sigInfo); + } + case SigningInfo::SIGNER_TYPE_HMAC: { + const Name& keyName = params.getSignerName(); + if (!m_tpm->hasKey(keyName)) { + m_tpm->importPrivateKey(keyName, params.getHmacKey()); + } + sigInfo.setSignatureType(getSignatureType(KeyType::HMAC, params.getDigestAlgorithm())); + sigInfo.setKeyLocator(keyName); + NDN_LOG_TRACE("Prepared signature info: " << sigInfo); + return std::make_tuple(keyName, sigInfo); + } + default: { + NDN_THROW(InvalidSigningInfoError("Unrecognized signer type " + + boost::lexical_cast(params.getSignerType()))); + } + } + + if (!key) { + if (!identity) { + NDN_THROW(InvalidSigningInfoError("Cannot determine signing parameters")); + } + try { + key = identity.getDefaultKey(); + } + catch (const Pib::Error&) { + NDN_THROW_NESTED(InvalidSigningInfoError("Signing identity `" + identity.getName().toUri() + + "` does not have a default certificate")); + } + } + + BOOST_ASSERT(key); + + sigInfo.setSignatureType(getSignatureType(key.getKeyType(), params.getDigestAlgorithm())); + sigInfo.setKeyLocator(key.getName()); + + NDN_LOG_TRACE("Prepared signature info: " << sigInfo); + return std::make_tuple(key.getName(), sigInfo); +} + +Block +KeyChain::sign(const uint8_t* buf, size_t size, + const Name& keyName, DigestAlgorithm digestAlgorithm) const +{ + if (keyName == SigningInfo::getDigestSha256Identity()) + return Block(tlv::SignatureValue, util::Sha256::computeDigest(buf, size)); + + return Block(tlv::SignatureValue, m_tpm->sign(buf, size, keyName, digestAlgorithm)); +} + +tlv::SignatureTypeValue +KeyChain::getSignatureType(KeyType keyType, DigestAlgorithm) +{ + switch (keyType) { + case KeyType::RSA: + return tlv::SignatureSha256WithRsa; + case KeyType::EC: + return tlv::SignatureSha256WithEcdsa; + case KeyType::HMAC: + return tlv::SignatureHmacWithSha256; + default: + NDN_THROW(Error("Unsupported key type " + boost::lexical_cast(keyType))); + } +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/key-chain.hpp b/ndn-cxx/security/v2/key-chain.hpp new file mode 100644 index 000000000..1021e8b5a --- /dev/null +++ b/ndn-cxx/security/v2/key-chain.hpp @@ -0,0 +1,518 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_KEY_CHAIN_HPP +#define NDN_SECURITY_V2_KEY_CHAIN_HPP + +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/security/key-params.hpp" +#include "ndn-cxx/security/pib/pib.hpp" +#include "ndn-cxx/security/safe-bag.hpp" +#include "ndn-cxx/security/security-common.hpp" +#include "ndn-cxx/security/signing-info.hpp" +#include "ndn-cxx/security/tpm/tpm.hpp" +#include "ndn-cxx/security/v2/certificate.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +/** + * @brief The interface of signing key management. + * + * The KeyChain class provides an interface to manage entities related to packet signing, + * such as Identity, Key, and Certificates. It consists of two parts: a private key module + * (TPM) and a public key information base (PIB). Managing signing key and its related + * entities through KeyChain interface guarantees the consistency between TPM and PIB. + */ +class KeyChain : noncopyable +{ +public: + class Error : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + }; + + /** + * @brief Error indicating that the supplied TPM locator does not match the locator stored in PIB. + */ + class LocatorMismatchError : public Error + { + public: + using Error::Error; + }; + + /** + * @brief Error indicating that the supplied SigningInfo is invalid. + */ + class InvalidSigningInfoError : public Error + { + public: + using Error::Error; + }; + + /** + * @brief Constructor to create KeyChain with default PIB and TPM. + * + * Default PIB and TPM are platform-dependent and can be overriden system-wide or + * individually for the user. + * + * @sa manpage ndn-client.conf + * + * @todo Add detailed description about config file behavior here + */ + KeyChain(); + + /** + * @brief KeyChain constructor + * + * @sa manpage ndn-client.conf + * + * @param pibLocator PIB locator, e.g., `pib-sqlite3:/example/dir` + * @param tpmLocator TPM locator, e.g., `tpm-memory:` + * @param allowReset if true, the PIB will be reset when the supplied @p tpmLocator + * does not match the one in the PIB + */ + KeyChain(const std::string& pibLocator, const std::string& tpmLocator, bool allowReset = false); + + ~KeyChain(); + + const Pib& + getPib() const + { + return *m_pib; + } + + const Tpm& + getTpm() const + { + return *m_tpm; + } + +public: // Identity management + /** + * @brief Create an identity @p identityName. + * + * This method will check if the identity exists in PIB and whether the identity has a + * default key and default certificate. If the identity does not exist, this method will + * create the identity in PIB. If the identity's default key does not exist, this method + * will create a key pair and set it as the identity's default key. If the key's default + * certificate is missing, this method will create a self-signed certificate for the key. + * + * If @p identityName did not exist and no default identity was selected before, the created + * identity will be set as the default identity + * + * @param identityName The name of the identity. + * @param params The key parameters if a key needs to be created for the identity (default: + * EC key with random key id) + * @return The created Identity instance. + */ + Identity + createIdentity(const Name& identityName, const KeyParams& params = getDefaultKeyParams()); + + /** + * @brief delete @p identity. + * + * @pre @p identity must be valid. + * @post @p identity becomes invalid. + */ + void + deleteIdentity(const Identity& identity); + + /** + * @brief Set @p identity as the default identity. + * @pre @p identity must be valid. + */ + void + setDefaultIdentity(const Identity& identity); + +public: // Key management + /** + * @brief Create a new key for @p identity. + * + * @param identity Reference to a valid Identity object + * @param params Key creation parameters (default: EC key with random key id) + * @pre @p identity must be valid. + * + * If @p identity had no default key selected, the created key will be set as the default for + * this identity. + * + * This method will also create a self-signed certificate for the created key. + */ + Key + createKey(const Identity& identity, const KeyParams& params = getDefaultKeyParams()); + + /** + * @brief Create a new HMAC key. + * + * @param prefix Prefix used to construct the key name (default: `/localhost/identity/hmac`); + * the full key name will include additional components according to @p params + * @param params Key creation parameters + * @return A name that can be subsequently used to reference the created key. + * + * The newly created key will be inserted in the TPM. HMAC keys don't have any PIB entries. + */ + Name + createHmacKey(const Name& prefix = SigningInfo::getHmacIdentity(), + const HmacKeyParams& params = HmacKeyParams()); + + /** + * @brief Delete a key @p key of @p identity. + * + * @pre @p identity must be valid. + * @pre @p key must be valid. + * @post @p key becomes invalid. + * @throw std::invalid_argument @p key does not belong to @p identity + */ + void + deleteKey(const Identity& identity, const Key& key); + + /** + * @brief Set @p key as the default key of @p identity. + * + * @pre @p identity must be valid. + * @pre @p key must be valid. + * @throw std::invalid_argument @p key does not belong to @p identity + */ + void + setDefaultKey(const Identity& identity, const Key& key); + +public: // Certificate management + /** + * @brief Add a certificate @p certificate for @p key + * + * If @p key had no default certificate selected, the added certificate will be set as the + * default certificate for this key. + * + * @note This method overwrites certificate with the same name, without considering the + * implicit digest. + * + * @pre @p key must be valid. + * @throw std::invalid_argument @p key does not match @p certificate + */ + void + addCertificate(const Key& key, const Certificate& certificate); + + /** + * @brief delete a certificate with name @p certificateName of @p key. + * + * If the certificate @p certificateName does not exist, this method has no effect. + * + * @pre @p key must be valid. + * @throw std::invalid_argument @p certificateName does not follow certificate naming convention. + */ + void + deleteCertificate(const Key& key, const Name& certificateName); + + /** + * @brief Set @p cert as the default certificate of @p key. + * + * The certificate @p cert will be added to the @p key, potentially overriding existing + * certificate if it has the same name (without considering implicit digest). + * + * @pre @p key must be valid. + * @throw std::invalid_argument @p key does not match @p certificate + */ + void + setDefaultCertificate(const Key& key, const Certificate& certificate); + +public: // signing + /** + * @brief Sign data according to the supplied signing information. + * + * This method uses the supplied signing information @p params to create the SignatureInfo block: + * - it selects a private key and its certificate to sign the packet + * - sets the KeyLocator field with the certificate name, and + * - adds other requested information to the SignatureInfo block. + * + * After that, the method assigns the created SignatureInfo to the data packets, generate a + * signature and sets as part of the SignatureValue block. + * + * @note The exception throwing semantics has changed from v1::KeyChain. + * If the requested identity/key/certificate does not exist, it will **not** be created + * and exception will be thrown. + * + * @param data The data to sign + * @param params The signing parameters. + * @throw Error signing fails + * @throw InvalidSigningInfoError invalid @p params is specified or specified identity, key, + * or certificate does not exist + * @see SigningInfo + */ + void + sign(Data& data, const SigningInfo& params = getDefaultSigningInfo()); + + /** + * @brief Sign interest according to the supplied signing information + * + * This method uses the supplied signing information @p params to create the SignatureInfo block: + * - it selects a private key and its certificate to sign the packet + * - sets the KeyLocator field with the certificate name, and + * - adds other requested information to the SignatureInfo block. + * + * After that, the method appends the created SignatureInfo to the interest name, generate a + * signature and appends it as part of the SignatureValue block to the interest name. + * + * @note The exception throwing semantics has changed from v1::KeyChain. If the requested + * identity/key/certificate does not exist, it will **not** be created and exception + * will be thrown. + * + * @param interest The interest to sign + * @param params The signing parameters. + * @throw Error signing fails + * @throw InvalidSigningInfoError invalid @p params is specified or specified identity, key, + * or certificate does not exist + * @see SigningInfo + * @see docs/specs/signed-interest.rst + */ + void + sign(Interest& interest, const SigningInfo& params = getDefaultSigningInfo()); + + /** + * @brief Sign buffer according to the supplied signing information @p params + * + * If @p params refers to an identity, the method selects the default key of the identity. + * If @p params refers to a key or certificate, the method select the corresponding key. + * + * @param buffer The buffer to sign + * @param bufferLength The buffer size + * @param params The signing parameters. + * @return a SignatureValue TLV block + * @throw Error signing fails + * @see SigningInfo + */ + Block + sign(const uint8_t* buffer, size_t bufferLength, const SigningInfo& params = getDefaultSigningInfo()); + +public: // export & import + /** + * @brief Export a certificate and its corresponding private key. + * + * @param certificate The certificate to export. + * @param pw The password to secure the private key. + * @param pwLen The length of password. + * @return A SafeBag carrying the certificate and encrypted private key. + * @throw Error the certificate or private key does not exist + */ + shared_ptr + exportSafeBag(const Certificate& certificate, const char* pw, size_t pwLen); + + /** + * @brief Import a certificate and its corresponding private key from a SafeBag. + * + * If the certificate and key are imported properly, the default setting will be updated as if + * a new key and certificate is added into KeyChain. + * + * @param safeBag The encoded data to import. + * @param pw The password to secure the private key. + * @param pwLen The length of password. + * @throw Error any of following conditions: + * - the safebag cannot be decoded or its content does not match; + * - private key cannot be imported; + * - a private/public key of the same name already exists; + * - a certificate of the same name already exists. + */ + void + importSafeBag(const SafeBag& safeBag, const char* pw, size_t pwLen); + + /** + * @brief Import a private key into the TPM. + */ + void + importPrivateKey(const Name& keyName, shared_ptr key); + +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: + /** + * @brief Derive SignatureTypeValue according to key type and digest algorithm. + */ + static tlv::SignatureTypeValue + getSignatureType(KeyType keyType, DigestAlgorithm digestAlgorithm); + +public: // PIB & TPM backend registry + /** + * @brief Register a new PIB backend + * @param scheme Name for the registered PIB backend scheme + * + * @note This interface is implementation detail and may change without notice. + */ + template + static void + registerPibBackend(const std::string& scheme); + + /** + * @brief Register a new TPM backend + * @param scheme Name for the registered TPM backend scheme + * + * @note This interface is implementation detail and may change without notice. + */ + template + static void + registerTpmBackend(const std::string& scheme); + +private: + typedef std::map(const std::string& location)>> PibFactories; + typedef std::map(const std::string& location)>> TpmFactories; + + static PibFactories& + getPibFactories(); + + static TpmFactories& + getTpmFactories(); + + static std::tuple + parseAndCheckPibLocator(const std::string& pibLocator); + + static std::tuple + parseAndCheckTpmLocator(const std::string& tpmLocator); + + static const std::string& + getDefaultPibScheme(); + + static const std::string& + getDefaultTpmScheme(); + + /** + * @brief Create a PIB according to @p pibLocator + */ + static unique_ptr + createPib(const std::string& pibLocator); + + /** + * @brief Create a TPM according to @p tpmLocator + */ + static unique_ptr + createTpm(const std::string& tpmLocator); + +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: + static const std::string& + getDefaultPibLocator(); + + static const std::string& + getDefaultTpmLocator(); + +private: // signing + /** + * @brief Generate a self-signed certificate for a public key. + * + * The self-signed certificate will also be added to the PIB. + */ + Certificate + selfSign(Key& key); + + /** + * @brief Prepare a SignatureInfo TLV according to signing information and return the signing + * key name. + * + * @param params The signing parameters. + * @return The signing key name and prepared SignatureInfo. + * @throw InvalidSigningInfoError when the requested signing method cannot be satisfied. + */ + std::tuple + prepareSignatureInfo(const SigningInfo& params); + + /** + * @brief Generate a SignatureValue block for a buffer @p buf of size @p size using + * a key with name @p keyName and digest algorithm @p digestAlgorithm. + */ + Block + sign(const uint8_t* buf, size_t size, const Name& keyName, DigestAlgorithm digestAlgorithm) const; + +public: + static const SigningInfo& + getDefaultSigningInfo(); + + static const KeyParams& + getDefaultKeyParams(); + +private: + std::unique_ptr m_pib; + std::unique_ptr m_tpm; + + static std::string s_defaultPibLocator; + static std::string s_defaultTpmLocator; +}; + +template +inline void +KeyChain::registerPibBackend(const std::string& scheme) +{ + getPibFactories().emplace(scheme, [] (const std::string& locator) { + return unique_ptr(new PibType(locator)); + }); +} + +template +inline void +KeyChain::registerTpmBackend(const std::string& scheme) +{ + getTpmFactories().emplace(scheme, [] (const std::string& locator) { + return unique_ptr(new TpmType(locator)); + }); +} + +/** + * @brief Register Pib backend class in KeyChain + * + * This macro should be placed once in the implementation file of the + * Pib backend class within the namespace where the type is declared. + * + * @note This interface is implementation detail and may change without notice. + */ +#define NDN_CXX_V2_KEYCHAIN_REGISTER_PIB_BACKEND(PibType) \ +static class NdnCxxAuto ## PibType ## PibRegistrationClass \ +{ \ +public: \ + NdnCxxAuto ## PibType ## PibRegistrationClass() \ + { \ + ::ndn::security::v2::KeyChain::registerPibBackend(PibType::getScheme()); \ + } \ +} ndnCxxAuto ## PibType ## PibRegistrationVariable + +/** + * @brief Register Tpm backend class in KeyChain + * + * This macro should be placed once in the implementation file of the + * Tpm backend class within the namespace where the type is declared. + * + * @note This interface is implementation detail and may change without notice. + */ +#define NDN_CXX_V2_KEYCHAIN_REGISTER_TPM_BACKEND(TpmType) \ +static class NdnCxxAuto ## TpmType ## TpmRegistrationClass \ +{ \ +public: \ + NdnCxxAuto ## TpmType ## TpmRegistrationClass() \ + { \ + ::ndn::security::v2::KeyChain::registerTpmBackend(TpmType::getScheme()); \ + } \ +} ndnCxxAuto ## TpmType ## TpmRegistrationVariable + +} // namespace v2 + +using v2::KeyChain; + +} // namespace security + +using security::v2::KeyChain; + +} // namespace ndn + +#endif // NDN_SECURITY_V2_KEY_CHAIN_HPP diff --git a/ndn-cxx/security/v2/trust-anchor-container.cpp b/ndn-cxx/security/v2/trust-anchor-container.cpp new file mode 100644 index 000000000..f77f23320 --- /dev/null +++ b/ndn-cxx/security/v2/trust-anchor-container.cpp @@ -0,0 +1,133 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/trust-anchor-container.hpp" + +#include + +namespace ndn { +namespace security { +namespace v2 { + +void +TrustAnchorContainer::AnchorContainer::add(Certificate&& cert) +{ + AnchorContainerBase::insert(std::move(cert)); +} + +void +TrustAnchorContainer::AnchorContainer::remove(const Name& certName) +{ + AnchorContainerBase::erase(certName); +} + +void +TrustAnchorContainer::AnchorContainer::clear() +{ + AnchorContainerBase::clear(); +} + +void +TrustAnchorContainer::insert(const std::string& groupId, Certificate&& cert) +{ + auto group = m_groups.find(groupId); + if (group == m_groups.end()) { + std::tie(group, std::ignore) = m_groups.insert(make_shared(m_anchors, groupId)); + } + auto* staticGroup = dynamic_cast(&**group); + if (staticGroup == nullptr) { + NDN_THROW(Error("Cannot add static anchor to a non-static anchor group " + groupId)); + } + staticGroup->add(std::move(cert)); +} + +void +TrustAnchorContainer::insert(const std::string& groupId, const boost::filesystem::path& path, + time::nanoseconds refreshPeriod, bool isDir) +{ + if (m_groups.count(groupId) != 0) { + NDN_THROW(Error("Cannot create dynamic group, because group " + groupId + " already exists")); + } + + m_groups.insert(make_shared(m_anchors, groupId, path, refreshPeriod, isDir)); +} + +void +TrustAnchorContainer::clear() +{ + m_groups.clear(); + m_anchors.clear(); +} + +const Certificate* +TrustAnchorContainer::find(const Name& keyName) const +{ + const_cast(this)->refresh(); + + auto cert = m_anchors.lower_bound(keyName); + if (cert == m_anchors.end() || !keyName.isPrefixOf(cert->getName())) + return nullptr; + + return &*cert; +} + +const Certificate* +TrustAnchorContainer::find(const Interest& interest) const +{ + const_cast(this)->refresh(); + + for (auto cert = m_anchors.lower_bound(interest.getName()); + cert != m_anchors.end() && interest.getName().isPrefixOf(cert->getName()); + ++cert) { + if (interest.matchesData(*cert)) { + return &*cert; + } + } + return nullptr; +} + +TrustAnchorGroup& +TrustAnchorContainer::getGroup(const std::string& groupId) const +{ + auto group = m_groups.find(groupId); + if (group == m_groups.end()) { + NDN_THROW(Error("Trust anchor group " + groupId + " does not exist")); + } + return **group; +} + +size_t +TrustAnchorContainer::size() const +{ + return m_anchors.size(); +} + +void +TrustAnchorContainer::refresh() +{ + for (auto it = m_groups.begin(); it != m_groups.end(); ++it) { + m_groups.modify(it, [] (const auto& group) { group->refresh(); }); + } +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/trust-anchor-container.hpp b/ndn-cxx/security/v2/trust-anchor-container.hpp new file mode 100644 index 000000000..e69a74fb3 --- /dev/null +++ b/ndn-cxx/security/v2/trust-anchor-container.hpp @@ -0,0 +1,180 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_TRUST_ANCHOR_CONTAINER_HPP +#define NDN_SECURITY_V2_TRUST_ANCHOR_CONTAINER_HPP + +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/security/v2/certificate.hpp" +#include "ndn-cxx/security/v2/trust-anchor-group.hpp" + +#include +#include +#include +#include + +namespace ndn { +namespace security { +namespace v2 { + +/** + * @brief represents a container for trust anchors. + * + * There are two kinds of anchors: + * - static anchors that are permanent for the lifetime of the container + * - dynamic anchors that are periodically updated. + * + * Trust anchors are organized in groups. Each group has a unique group id. The same anchor + * certificate (same name without considering the implicit digest) can be inserted into + * multiple groups, but no more than once into each. + * + * Dynamic groups are created using the appropriate TrustAnchorContainer::insert method. Once + * created, the dynamic anchor group cannot be updated. + * + * The returned pointer to Certificate from `find` methods is only guaranteed to be valid until + * the next invocation of `find` and may be invalidated afterwards. + */ +class TrustAnchorContainer : noncopyable +{ +public: + class Error : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + }; + + /** + * @brief Insert a static trust anchor. + * + * @param groupId Certificate group id. + * @param cert Certificate to insert. + * + * If @p cert (same name without considering implicit digest) already exists in the group @p + * groupId, this method has no effect. + * + * @throw Error @p groupId is a dynamic anchor group . + */ + void + insert(const std::string& groupId, Certificate&& cert); + + /** + * @brief Insert dynamic trust anchors from path. + * + * @param groupId Certificate group id, must not be empty. + * @param path Specifies the path to load the trust anchors. + * @param refreshPeriod Refresh period for the trust anchors, must be positive. + * Relevant trust anchors will only be updated when find is called + * @param isDir Tells whether the path is a directory or a single file. + * + * @throw std::invalid_argument @p refreshPeriod is not positive + * @throw Error a group with @p groupId already exists + */ + void + insert(const std::string& groupId, const boost::filesystem::path& path, + time::nanoseconds refreshPeriod, bool isDir = false); + + /** + * @brief Remove all static or dynamic anchors + */ + void + clear(); + + /** + * @brief Search for certificate across all groups (longest prefix match) + * @param keyName Key name prefix for searching the certificate. + * @return The found certificate, nullptr if not found. + * + * @note The returned value may be invalidated after next call to one of `find` methods. + */ + const Certificate* + find(const Name& keyName) const; + + /** + * @brief Find certificate given interest + * @param interest The input interest packet. + * @return The found certificate, nullptr if not found. + * + * @note The returned value may be invalidated after next call to one of `find` methods. + * + * @note Interest with implicit digest is not supported. + */ + const Certificate* + find(const Interest& interest) const; + + /** + * @brief Get trusted anchor group + * @throw Error @p groupId does not exist + */ + TrustAnchorGroup& + getGroup(const std::string& groupId) const; + + /** + * @brief Get number of trust anchors across all groups + */ + size_t + size() const; + +private: + void + refresh(); + +private: + using AnchorContainerBase = boost::multi_index::multi_index_container< + Certificate, + boost::multi_index::indexed_by< + boost::multi_index::ordered_unique< + boost::multi_index::const_mem_fun + > + > + >; + + class AnchorContainer : public CertContainerInterface, + public AnchorContainerBase + { + public: + void + add(Certificate&& cert) final; + + void + remove(const Name& certName) final; + + void + clear(); + }; + + using GroupContainer = boost::multi_index::multi_index_container< + shared_ptr, + boost::multi_index::indexed_by< + boost::multi_index::hashed_unique< + boost::multi_index::const_mem_fun + > + > + >; + + GroupContainer m_groups; + AnchorContainer m_anchors; +}; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_TRUST_ANCHOR_CONTAINER_HPP diff --git a/ndn-cxx/security/v2/trust-anchor-group.cpp b/ndn-cxx/security/v2/trust-anchor-group.cpp new file mode 100644 index 000000000..1c27a41ff --- /dev/null +++ b/ndn-cxx/security/v2/trust-anchor-group.cpp @@ -0,0 +1,145 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/trust-anchor-group.hpp" +#include "ndn-cxx/util/io.hpp" +#include "ndn-cxx/util/logger.hpp" + +#include +#include +#include +#include + +namespace ndn { +namespace security { +namespace v2 { + +NDN_LOG_INIT(ndn.security.v2.TrustAnchorGroup); + +namespace fs = boost::filesystem; + +TrustAnchorGroup::TrustAnchorGroup(CertContainerInterface& certContainer, const std::string& id) + : m_certs(certContainer) + , m_id(id) +{ +} + +TrustAnchorGroup::~TrustAnchorGroup() = default; + +size_t +TrustAnchorGroup::size() const +{ + return m_anchorNames.size(); +} + +void +TrustAnchorGroup::refresh() +{ + // base method does nothing +} + +////////////// + +StaticTrustAnchorGroup::StaticTrustAnchorGroup(CertContainerInterface& certContainer, const std::string& id) + : TrustAnchorGroup(certContainer, id) +{ +} + +void +StaticTrustAnchorGroup::add(Certificate&& cert) +{ + if (m_anchorNames.count(cert.getName()) != 0) { + return; + } + + m_anchorNames.insert(cert.getName()); + m_certs.add(std::move(cert)); +} + +void +StaticTrustAnchorGroup::remove(const Name& certName) +{ + m_anchorNames.erase(certName); + m_certs.remove(certName); +} + +///////////// + +DynamicTrustAnchorGroup::DynamicTrustAnchorGroup(CertContainerInterface& certContainer, const std::string& id, + const boost::filesystem::path& path, + time::nanoseconds refreshPeriod, bool isDir) + : TrustAnchorGroup(certContainer, id) + , m_isDir(isDir) + , m_path(path) + , m_refreshPeriod(refreshPeriod) +{ + if (refreshPeriod <= time::nanoseconds::zero()) { + NDN_THROW(std::runtime_error("Refresh period for the dynamic group must be positive")); + } + + NDN_LOG_TRACE("Create dynamic trust anchor group " << id << " for file/dir " << path + << " with refresh time " << refreshPeriod); + refresh(); +} + +void +DynamicTrustAnchorGroup::refresh() +{ + if (m_expireTime > time::steady_clock::now()) { + return; + } + m_expireTime = time::steady_clock::now() + m_refreshPeriod; + NDN_LOG_TRACE("Reloading dynamic trust anchor group"); + + std::set oldAnchorNames = m_anchorNames; + + auto loadCert = [this, &oldAnchorNames] (const fs::path& file) { + auto cert = io::load(file.string()); + if (cert != nullptr) { + if (m_anchorNames.count(cert->getName()) == 0) { + m_anchorNames.insert(cert->getName()); + m_certs.add(std::move(*cert)); + } + else { + oldAnchorNames.erase(cert->getName()); + } + } + }; + + if (!m_isDir) { + loadCert(m_path); + } + else { + if (fs::exists(m_path)) { + std::for_each(fs::directory_iterator(m_path), fs::directory_iterator(), loadCert); + } + } + + // remove old certs + for (const auto& oldAnchorName : oldAnchorNames) { + m_anchorNames.erase(oldAnchorName); + m_certs.remove(oldAnchorName); + } +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/trust-anchor-group.hpp b/ndn-cxx/security/v2/trust-anchor-group.hpp new file mode 100644 index 000000000..2afe3f5a1 --- /dev/null +++ b/ndn-cxx/security/v2/trust-anchor-group.hpp @@ -0,0 +1,170 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_TRUST_ANCHOR_GROUP_HPP +#define NDN_SECURITY_V2_TRUST_ANCHOR_GROUP_HPP + +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/security/v2/certificate.hpp" + +#include +#include + +namespace ndn { +namespace security { +namespace v2 { + +class CertContainerInterface +{ +public: + virtual + ~CertContainerInterface() = default; + + virtual void + add(Certificate&& cert) = 0; + + virtual void + remove(const Name& certName) = 0; +}; + +/** + * @brief A group of trust anchors + */ +class TrustAnchorGroup : noncopyable +{ +public: + /** + * @brief Create an anchor group + */ + TrustAnchorGroup(CertContainerInterface& certContainer, const std::string& id); + + virtual + ~TrustAnchorGroup(); + + /** + * @return group id + */ + const std::string& + getId() const + { + return m_id; + } + + /** + * @return number of certificates in the group + */ + size_t + size() const; + + /** + * @brief Request certificate refresh + */ + virtual void + refresh(); + +protected: + CertContainerInterface& m_certs; + std::set m_anchorNames; + +private: + std::string m_id; +}; + +/** + * @brief Static trust anchor group + */ +class StaticTrustAnchorGroup : public TrustAnchorGroup +{ +public: + /** + * @brief Create a static trust anchor group + * @param certContainer Reference to CertContainerInterface instance + * @param id Group id + */ + StaticTrustAnchorGroup(CertContainerInterface& certContainer, const std::string& id); + + /** + * @brief Load static anchor @p cert + */ + void + add(Certificate&& cert); + + /** + * @brief Remove static anchor @p certName + */ + void + remove(const Name& certName); +}; + +/** + * @brief Dynamic trust anchor group + */ +class DynamicTrustAnchorGroup : public TrustAnchorGroup +{ +public: + /** + * @brief Create a dynamic trust anchor group + * + * This contructor would load all the certificates from @p path and will be refreshing + * certificates every @p refreshPeriod time period. + * + * Note that refresh is not scheduled, but is performed upon "find" operations. + * + * When @p isDir is false and @p path doesn't point to a valid certificate (file doesn't + * exist or content is not a valid certificate), the dynamic anchor group will be empty until + * file gets created. If file disappears or gets corrupted, the anchor group becomes empty. + * + * When @p idDir is true and @p path does't point to a valid folder, folder is empty, or + * doesn't contain valid certificates, the group will be empty until certificate files are + * placed in the folder. If folder is removed, becomes empty, or no longer contains valid + * certificates, the anchor group becomes empty. + * + * Upon refresh, the existing certificates are not changed. + * + * @param certContainer A certificate container into which trust anchors from the group will + * be added + * @param id Group id + * @param path File path for trust anchor(s), could be directory or file. If it is a + * directory, all the certificates in the directory will be loaded. + * @param refreshPeriod Refresh time for the anchors under @p path, must be positive. + * @param isDir Tells whether the path is a directory or a single file. + * + * @throw std::invalid_argument @p refreshPeriod is negative + */ + DynamicTrustAnchorGroup(CertContainerInterface& certContainer, const std::string& id, + const boost::filesystem::path& path, time::nanoseconds refreshPeriod, + bool isDir = false); + + void + refresh() override; + +private: + bool m_isDir; + boost::filesystem::path m_path; + time::nanoseconds m_refreshPeriod; + time::steady_clock::TimePoint m_expireTime; +}; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_TRUST_ANCHOR_GROUP_HPP diff --git a/ndn-cxx/security/v2/validation-callback.hpp b/ndn-cxx/security/v2/validation-callback.hpp new file mode 100644 index 000000000..5ce1db1da --- /dev/null +++ b/ndn-cxx/security/v2/validation-callback.hpp @@ -0,0 +1,58 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_VALIDATION_CALLBACK_HPP +#define NDN_SECURITY_V2_VALIDATION_CALLBACK_HPP + +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/security/security-common.hpp" +#include "ndn-cxx/security/v2/validation-error.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +/** + * @brief Callback to report a successful Data validation. + */ +typedef function DataValidationSuccessCallback; + +/** + * @brief Callback to report a failed Data validation. + */ +typedef function DataValidationFailureCallback; + +/** + * @brief Callback to report a successful Interest validation. + */ +typedef function InterestValidationSuccessCallback; + +/** + * @brief Callback to report a failed Interest validation. + */ +typedef function InterestValidationFailureCallback; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_VALIDATION_CALLBACK_HPP diff --git a/ndn-cxx/security/v2/validation-error.cpp b/ndn-cxx/security/v2/validation-error.cpp new file mode 100644 index 000000000..6df5f239d --- /dev/null +++ b/ndn-cxx/security/v2/validation-error.cpp @@ -0,0 +1,79 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validation-error.hpp" + +#include + +namespace ndn { +namespace security { +namespace v2 { + +std::ostream& +operator<<(std::ostream& os, ValidationError::Code code) +{ + switch (code) { + case ValidationError::Code::NO_ERROR: + return os << "No error"; + case ValidationError::Code::INVALID_SIGNATURE: + return os << "Invalid signature"; + case ValidationError::Code::NO_SIGNATURE: + return os << "Missing signature"; + case ValidationError::Code::CANNOT_RETRIEVE_CERT: + return os << "Cannot retrieve certificate"; + case ValidationError::Code::EXPIRED_CERT: + return os << "Certificate expired"; + case ValidationError::Code::LOOP_DETECTED: + return os << "Loop detected in certification chain"; + case ValidationError::Code::MALFORMED_CERT: + return os << "Malformed certificate"; + case ValidationError::Code::EXCEEDED_DEPTH_LIMIT: + return os << "Exceeded validation depth limit"; + case ValidationError::Code::INVALID_KEY_LOCATOR: + return os << "Key locator violates validation policy"; + case ValidationError::Code::POLICY_ERROR: + return os << "Validation policy error"; + case ValidationError::Code::IMPLEMENTATION_ERROR: + return os << "Internal implementation error"; + case ValidationError::Code::USER_MIN: + break; + } + if (code >= ValidationError::Code::USER_MIN) { + return os << "Custom error code " << to_underlying(code); + } + else { + return os << "Unrecognized error code " << to_underlying(code); + } +} + +std::ostream& +operator<<(std::ostream& os, const ValidationError& error) +{ + os << static_cast(error.getCode()); + if (!error.getInfo().empty()) { + os << " (" << error.getInfo() << ")"; + } + return os; +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/validation-error.hpp b/ndn-cxx/security/v2/validation-error.hpp new file mode 100644 index 000000000..826cd1828 --- /dev/null +++ b/ndn-cxx/security/v2/validation-error.hpp @@ -0,0 +1,93 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_VALIDATION_ERROR_HPP +#define NDN_SECURITY_V2_VALIDATION_ERROR_HPP + +#include "ndn-cxx/detail/common.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +/** + * @brief Validation error code and optional detailed error message + */ +class ValidationError +{ +public: + /** + * @brief Known validation error code + * @sa specs/validation-error-code.rst + */ + enum Code : uint32_t { + NO_ERROR = 0, + INVALID_SIGNATURE = 1, + NO_SIGNATURE = 2, + CANNOT_RETRIEVE_CERT = 3, + EXPIRED_CERT = 4, + LOOP_DETECTED = 5, + MALFORMED_CERT = 6, + EXCEEDED_DEPTH_LIMIT = 7, + INVALID_KEY_LOCATOR = 8, + POLICY_ERROR = 9, + IMPLEMENTATION_ERROR = 255, + USER_MIN = 256 // custom error codes should use >=256 + }; + +public: + /** + * @brief Validation error, implicitly convertible from an error code and info + */ + ValidationError(uint32_t code, const std::string& info = "") + : m_code(code) + , m_info(info) + { + } + + uint32_t + getCode() const + { + return m_code; + } + + const std::string& + getInfo() const + { + return m_info; + } + +private: + uint32_t m_code; + std::string m_info; +}; + +std::ostream& +operator<<(std::ostream& os, ValidationError::Code code); + +std::ostream& +operator<<(std::ostream& os, const ValidationError& error); + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_VALIDATION_ERROR_HPP diff --git a/ndn-cxx/security/v2/validation-policy-accept-all.hpp b/ndn-cxx/security/v2/validation-policy-accept-all.hpp new file mode 100644 index 000000000..9ed54abab --- /dev/null +++ b/ndn-cxx/security/v2/validation-policy-accept-all.hpp @@ -0,0 +1,56 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_VALIDATION_POLICY_ACCEPT_ALL_HPP +#define NDN_SECURITY_V2_VALIDATION_POLICY_ACCEPT_ALL_HPP + +#include "ndn-cxx/security/v2/validation-policy.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +/** + * @brief A validator policy that accepts any signature of data and interest packets + */ +class ValidationPolicyAcceptAll : public ValidationPolicy +{ +public: + void + checkPolicy(const Data& data, const shared_ptr& state, + const ValidationContinuation& continueValidation) final + { + continueValidation(nullptr, state); + } + + void + checkPolicy(const Interest& interest, const shared_ptr& state, + const ValidationContinuation& continueValidation) final + { + continueValidation(nullptr, state); + } +}; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_VALIDATION_POLICY_ACCEPT_ALL_HPP diff --git a/ndn-cxx/security/v2/validation-policy-command-interest.cpp b/ndn-cxx/security/v2/validation-policy-command-interest.cpp new file mode 100644 index 000000000..52f276dbf --- /dev/null +++ b/ndn-cxx/security/v2/validation-policy-command-interest.cpp @@ -0,0 +1,156 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validation-policy-command-interest.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +ValidationPolicyCommandInterest::ValidationPolicyCommandInterest(unique_ptr inner, + const Options& options) + : m_options(options) + , m_index(m_container.get<0>()) + , m_queue(m_container.get<1>()) +{ + if (inner == nullptr) { + NDN_THROW(std::invalid_argument("inner policy is missing")); + } + setInnerPolicy(std::move(inner)); + + m_options.gracePeriod = std::max(m_options.gracePeriod, 0_ns); +} + +void +ValidationPolicyCommandInterest::checkPolicy(const Data& data, const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + getInnerPolicy().checkPolicy(data, state, continueValidation); +} + +void +ValidationPolicyCommandInterest::checkPolicy(const Interest& interest, const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + bool isOk = false; + Name keyName; + uint64_t timestamp = 0; + std::tie(isOk, keyName, timestamp) = parseCommandInterest(interest, state); + if (!isOk) { + return; + } + + if (!checkTimestamp(state, keyName, timestamp)) { + return; + } + getInnerPolicy().checkPolicy(interest, state, std::bind(continueValidation, _1, _2)); +} + +void +ValidationPolicyCommandInterest::cleanup() +{ + auto expiring = time::steady_clock::now() - m_options.recordLifetime; + + while ((!m_queue.empty() && m_queue.front().lastRefreshed <= expiring) || + (m_options.maxRecords >= 0 && + m_queue.size() > static_cast(m_options.maxRecords))) { + m_queue.pop_front(); + } +} + +std::tuple +ValidationPolicyCommandInterest::parseCommandInterest(const Interest& interest, + const shared_ptr& state) const +{ + const Name& name = interest.getName(); + if (name.size() < command_interest::MIN_SIZE) { + state->fail({ValidationError::POLICY_ERROR, "Command interest name `" + + interest.getName().toUri() + "` is too short"}); + return std::make_tuple(false, Name(), 0); + } + + const name::Component& timestampComp = name.at(command_interest::POS_TIMESTAMP); + if (!timestampComp.isNumber()) { + state->fail({ValidationError::POLICY_ERROR, "Command interest `" + + interest.getName().toUri() + "` doesn't include timestamp component"}); + return std::make_tuple(false, Name(), 0); + } + + Name klName = getKeyLocatorName(interest, *state); + if (!state->getOutcome()) { // already failed + return std::make_tuple(false, Name(), 0); + } + + return std::make_tuple(true, klName, timestampComp.toNumber()); +} + +bool +ValidationPolicyCommandInterest::checkTimestamp(const shared_ptr& state, + const Name& keyName, uint64_t timestamp) +{ + this->cleanup(); + + auto now = time::system_clock::now(); + auto timestampPoint = time::fromUnixTimestamp(time::milliseconds(timestamp)); + if (timestampPoint < now - m_options.gracePeriod || timestampPoint > now + m_options.gracePeriod) { + state->fail({ValidationError::POLICY_ERROR, + "Timestamp is outside the grace period for key " + keyName.toUri()}); + return false; + } + + auto it = m_index.find(keyName); + if (it != m_index.end()) { + if (timestamp <= it->timestamp) { + state->fail({ValidationError::POLICY_ERROR, + "Timestamp is reordered for key " + keyName.toUri()}); + return false; + } + } + + auto interestState = dynamic_pointer_cast(state); + BOOST_ASSERT(interestState != nullptr); + interestState->afterSuccess.connect([=] (const Interest&) { insertNewRecord(keyName, timestamp); }); + return true; +} + +void +ValidationPolicyCommandInterest::insertNewRecord(const Name& keyName, uint64_t timestamp) +{ + // try to insert new record + auto now = time::steady_clock::now(); + auto i = m_queue.end(); + bool isNew = false; + LastTimestampRecord newRecord{keyName, timestamp, now}; + std::tie(i, isNew) = m_queue.push_back(newRecord); + + if (!isNew) { + BOOST_ASSERT(i->keyName == keyName); + + // set lastRefreshed field, and move to queue tail + m_queue.erase(i); + isNew = m_queue.push_back(newRecord).second; + BOOST_VERIFY(isNew); + } +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/validation-policy-command-interest.hpp b/ndn-cxx/security/v2/validation-policy-command-interest.hpp new file mode 100644 index 000000000..6ac35b89b --- /dev/null +++ b/ndn-cxx/security/v2/validation-policy-command-interest.hpp @@ -0,0 +1,159 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_VALIDATION_POLICY_COMMAND_INTEREST_HPP +#define NDN_SECURITY_V2_VALIDATION_POLICY_COMMAND_INTEREST_HPP + +#include "ndn-cxx/security/v2/validation-policy.hpp" + +#include +#include +#include +#include + +namespace ndn { +namespace security { +namespace v2 { + +/** \brief Validation policy for stop-and-wait command Interests + * \sa https://redmine.named-data.net/projects/ndn-cxx/wiki/CommandInterest + * + * This policy checks the timestamp field of a stop-and-wait command Interest. + * Signed Interest validation and Data validation requests are delegated to an inner policy. + */ +class ValidationPolicyCommandInterest : public ValidationPolicy +{ +public: + class Options + { + public: + Options() + { + } + + public: + /** \brief tolerance of initial timestamp + * + * A stop-and-wait command Interest is considered "initial" if the validator + * has not recorded the last timestamp from the same public key, or when + * such knowledge has been erased. + * For an initial command Interest, its timestamp is compared to the current + * system clock, and the command Interest is rejected if the absolute difference + * is greater than the grace interval. + * + * This should be positive. + * Setting this option to 0 or negative causes the validator to require exactly same + * timestamp as the system clock, which most likely rejects all command Interests. + */ + time::nanoseconds gracePeriod = 2_min; + + /** \brief max number of distinct public keys of which to record the last timestamp + * + * The validator records last timestamps for every public key. + * For a subsequent command Interest using the same public key, + * its timestamp is compared to the last timestamp from that public key, + * and the command Interest is rejected if its timestamp is + * less than or equal to the recorded timestamp. + * + * This option limits the number of distinct public keys being tracked. + * If the limit is exceeded, the oldest record is deleted. + * + * Setting this option to -1 allows tracking unlimited public keys. + * Setting this option to 0 disables last timestamp records and causes + * every command Interest to be processed as initial. + */ + ssize_t maxRecords = 1000; + + /** \brief max lifetime of a last timestamp record + * + * A last timestamp record expires and can be deleted if it has not been refreshed + * within this duration. + * Setting this option to 0 or negative makes last timestamp records expire immediately + * and causes every command Interest to be processed as initial. + */ + time::nanoseconds recordLifetime = 1_h; + }; + + /** \brief constructor + * \param inner a Validator for signed Interest signature validation and Data validation; + * this must not be nullptr + * \param options stop-and-wait command Interest validation options + * \throw std::invalid_argument inner policy is nullptr + */ + explicit + ValidationPolicyCommandInterest(unique_ptr inner, + const Options& options = {}); + +protected: + void + checkPolicy(const Data& data, const shared_ptr& state, + const ValidationContinuation& continueValidation) override; + + void + checkPolicy(const Interest& interest, const shared_ptr& state, + const ValidationContinuation& continueValidation) override; + +private: + void + cleanup(); + + std::tuple + parseCommandInterest(const Interest& interest, const shared_ptr& state) const; + + bool + checkTimestamp(const shared_ptr& state, + const Name& keyName, uint64_t timestamp); + + void + insertNewRecord(const Name& keyName, uint64_t timestamp); + +private: + Options m_options; + + struct LastTimestampRecord + { + Name keyName; + uint64_t timestamp; + time::steady_clock::TimePoint lastRefreshed; + }; + + using Container = boost::multi_index_container< + LastTimestampRecord, + boost::multi_index::indexed_by< + boost::multi_index::ordered_unique< + boost::multi_index::member + >, + boost::multi_index::sequenced<> + > + >; + using Index = Container::nth_index<0>::type; + using Queue = Container::nth_index<1>::type; + + Container m_container; + Index& m_index; + Queue& m_queue; +}; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_VALIDATION_POLICY_COMMAND_INTEREST_HPP diff --git a/ndn-cxx/security/v2/validation-policy-config.cpp b/ndn-cxx/security/v2/validation-policy-config.cpp new file mode 100644 index 000000000..d723b94bd --- /dev/null +++ b/ndn-cxx/security/v2/validation-policy-config.cpp @@ -0,0 +1,294 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validation-policy-config.hpp" +#include "ndn-cxx/security/v2/validator.hpp" +#include "ndn-cxx/util/io.hpp" + +#include +#include +#include +#include + +#include + +namespace ndn { +namespace security { +namespace v2 { +namespace validator_config { + +void +ValidationPolicyConfig::load(const std::string& filename) +{ + std::ifstream inputFile(filename); + if (!inputFile) { + NDN_THROW(Error("Failed to read configuration file: " + filename)); + } + load(inputFile, filename); +} + +void +ValidationPolicyConfig::load(const std::string& input, const std::string& filename) +{ + std::istringstream inputStream(input); + load(inputStream, filename); +} + +void +ValidationPolicyConfig::load(std::istream& input, const std::string& filename) +{ + ConfigSection tree; + try { + boost::property_tree::read_info(input, tree); + } + catch (const boost::property_tree::info_parser_error& e) { + NDN_THROW(Error("Failed to parse configuration file " + filename + + " line " + to_string(e.line()) + ": " + e.message())); + } + load(tree, filename); +} + +void +ValidationPolicyConfig::load(const ConfigSection& configSection, const std::string& filename) +{ + BOOST_ASSERT(!filename.empty()); + + if (m_validator == nullptr) { + NDN_THROW(Error("Validator instance not assigned on the policy")); + } + if (m_isConfigured) { + m_shouldBypass = false; + m_dataRules.clear(); + m_interestRules.clear(); + m_validator->resetAnchors(); + m_validator->resetVerifiedCertificates(); + } + m_isConfigured = true; + + for (const auto& subSection : configSection) { + const std::string& sectionName = subSection.first; + const ConfigSection& section = subSection.second; + + if (boost::iequals(sectionName, "rule")) { + auto rule = Rule::create(section, filename); + if (rule->getPktType() == tlv::Data) { + m_dataRules.push_back(std::move(rule)); + } + else if (rule->getPktType() == tlv::Interest) { + m_interestRules.push_back(std::move(rule)); + } + } + else if (boost::iequals(sectionName, "trust-anchor")) { + processConfigTrustAnchor(section, filename); + } + else { + NDN_THROW(Error("Error processing configuration file " + filename + + ": unrecognized section " + sectionName)); + } + } +} + +void +ValidationPolicyConfig::processConfigTrustAnchor(const ConfigSection& configSection, + const std::string& filename) +{ + using namespace boost::filesystem; + + auto propertyIt = configSection.begin(); + + // Get trust-anchor.type + if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) { + NDN_THROW(Error("Expecting ")); + } + + std::string type = propertyIt->second.data(); + propertyIt++; + + if (boost::iequals(type, "file")) { + // Get trust-anchor.file + if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "file-name")) { + NDN_THROW(Error("Expecting ")); + } + + std::string file = propertyIt->second.data(); + propertyIt++; + + time::nanoseconds refresh = getRefreshPeriod(propertyIt, configSection.end()); + if (propertyIt != configSection.end()) + NDN_THROW(Error("Expecting end of ")); + + m_validator->loadAnchor(filename, absolute(file, path(filename).parent_path()).string(), + refresh, false); + } + else if (boost::iequals(type, "base64")) { + // Get trust-anchor.base64-string + if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "base64-string")) + NDN_THROW(Error("Expecting ")); + + std::stringstream ss(propertyIt->second.data()); + propertyIt++; + + if (propertyIt != configSection.end()) + NDN_THROW(Error("Expecting end of ")); + + auto idCert = io::load(ss); + if (idCert != nullptr) { + m_validator->loadAnchor("", std::move(*idCert)); + } + else { + NDN_THROW(Error("Cannot decode certificate from base64-string")); + } + } + else if (boost::iequals(type, "dir")) { + if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "dir")) + NDN_THROW(Error("Expecting ")); + + std::string dirString(propertyIt->second.data()); + propertyIt++; + + time::nanoseconds refresh = getRefreshPeriod(propertyIt, configSection.end()); + if (propertyIt != configSection.end()) + NDN_THROW(Error("Expecting end of ")); + + path dirPath = absolute(dirString, path(filename).parent_path()); + m_validator->loadAnchor(dirString, dirPath.string(), refresh, true); + } + else if (boost::iequals(type, "any")) { + m_shouldBypass = true; + } + else { + NDN_THROW(Error("Unrecognized : " + type)); + } +} + +time::nanoseconds +ValidationPolicyConfig::getRefreshPeriod(ConfigSection::const_iterator& it, + const ConfigSection::const_iterator& end) +{ + auto refresh = time::nanoseconds::max(); + if (it == end) { + return refresh; + } + + if (!boost::iequals(it->first, "refresh")) { + NDN_THROW(Error("Expecting ")); + } + + std::string inputString = it->second.data(); + ++it; + char unit = inputString[inputString.size() - 1]; + std::string refreshString = inputString.substr(0, inputString.size() - 1); + + int32_t refreshPeriod = -1; + try { + refreshPeriod = boost::lexical_cast(refreshString); + } + catch (const boost::bad_lexical_cast&) { + // pass + } + if (refreshPeriod < 0) { + NDN_THROW(Error("Bad refresh value: " + refreshString)); + } + + if (refreshPeriod == 0) { + return getDefaultRefreshPeriod(); + } + + switch (unit) { + case 'h': + return time::hours(refreshPeriod); + case 'm': + return time::minutes(refreshPeriod); + case 's': + return time::seconds(refreshPeriod); + default: + NDN_THROW(Error("Bad refresh time unit: "s + unit)); + } +} + +time::nanoseconds +ValidationPolicyConfig::getDefaultRefreshPeriod() +{ + return 1_h; +} + +void +ValidationPolicyConfig::checkPolicy(const Data& data, const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + BOOST_ASSERT_MSG(!hasInnerPolicy(), "ValidationPolicyConfig must be a terminal inner policy"); + + if (m_shouldBypass) { + return continueValidation(nullptr, state); + } + + Name klName = getKeyLocatorName(data, *state); + if (!state->getOutcome()) { // already failed + return; + } + + for (const auto& rule : m_dataRules) { + if (rule->match(tlv::Data, data.getName())) { + if (rule->check(tlv::Data, data.getName(), klName, state)) { + return continueValidation(make_shared(klName), state); + } + // rule->check calls state->fail(...) if the check fails + return; + } + } + + return state->fail({ValidationError::POLICY_ERROR, + "No rule matched for data `" + data.getName().toUri() + "`"}); +} + +void +ValidationPolicyConfig::checkPolicy(const Interest& interest, const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + BOOST_ASSERT_MSG(!hasInnerPolicy(), "ValidationPolicyConfig must be a terminal inner policy"); + + if (m_shouldBypass) { + return continueValidation(nullptr, state); + } + + Name klName = getKeyLocatorName(interest, *state); + if (!state->getOutcome()) { // already failed + return; + } + + for (const auto& rule : m_interestRules) { + if (rule->match(tlv::Interest, interest.getName())) { + if (rule->check(tlv::Interest, interest.getName(), klName, state)) { + return continueValidation(make_shared(klName), state); + } + // rule->check calls state->fail(...) if the check fails + return; + } + } + + return state->fail({ValidationError::POLICY_ERROR, + "No rule matched for interest `" + interest.getName().toUri() + "`"}); +} + +} // namespace validator_config +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/validation-policy-config.hpp b/ndn-cxx/security/v2/validation-policy-config.hpp new file mode 100644 index 000000000..e94ccec68 --- /dev/null +++ b/ndn-cxx/security/v2/validation-policy-config.hpp @@ -0,0 +1,112 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_VALIDATION_POLICY_CONFIG_HPP +#define NDN_SECURITY_V2_VALIDATION_POLICY_CONFIG_HPP + +#include "ndn-cxx/security/v2/validation-policy.hpp" +#include "ndn-cxx/security/v2/validator-config/rule.hpp" + +namespace ndn { +namespace security { +namespace v2 { +namespace validator_config { + +/** + * @brief A validator that can be set up via a configuration file. + * + * @note For command Interest validation, this policy must be combined with + * @p ValidationPolicyCommandInterest, in order to guard against replay attacks. + * @note This policy does not support inner policies (a sole policy or a terminal inner policy) + * @sa https://named-data.net/doc/ndn-cxx/current/tutorials/security-validator-config.html + */ +class ValidationPolicyConfig : public ValidationPolicy +{ +public: + /** + * @brief Load policy from file @p filename + * @throw Error Validator instance not assigned to the policy (m_validator == nullptr) + */ + void + load(const std::string& filename); + + /** + * @brief Load policy from direct @p input + * @throw Error Validator instance not assigned to the policy (m_validator == nullptr) + */ + void + load(const std::string& input, const std::string& filename); + + /** + * @brief Load policy from direct @p input + * @throw Error Validator instance not assigned to the policy (m_validator == nullptr) + */ + void + load(std::istream& input, const std::string& filename); + + /** + * @brief Load policy from @p configSection + * @throw Error Validator instance not assigned to the policy (m_validator == nullptr) + */ + void + load(const ConfigSection& configSection, const std::string& filename); + +protected: + void + checkPolicy(const Data& data, const shared_ptr& state, + const ValidationContinuation& continueValidation) override; + + void + checkPolicy(const Interest& interest, const shared_ptr& state, + const ValidationContinuation& continueValidation) override; + +private: + void + processConfigTrustAnchor(const ConfigSection& section, const std::string& filename); + + time::nanoseconds + getRefreshPeriod(ConfigSection::const_iterator& it, const ConfigSection::const_iterator& end); + + time::nanoseconds + getDefaultRefreshPeriod(); + +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: + /** @brief Whether to always bypass validation. + * + * This is set to true when 'any' is specified as a trust anchor. + * It causes all packets to bypass validation. + */ + bool m_shouldBypass = false; + bool m_isConfigured = false; + + std::vector> m_dataRules; + std::vector> m_interestRules; +}; + +} // namespace validator_config + +using validator_config::ValidationPolicyConfig; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_VALIDATION_POLICY_CONFIG_HPP diff --git a/ndn-cxx/security/v2/validation-policy-simple-hierarchy.cpp b/ndn-cxx/security/v2/validation-policy-simple-hierarchy.cpp new file mode 100644 index 000000000..b026bbd75 --- /dev/null +++ b/ndn-cxx/security/v2/validation-policy-simple-hierarchy.cpp @@ -0,0 +1,66 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validation-policy-simple-hierarchy.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +void +ValidationPolicySimpleHierarchy::checkPolicy(const Data& data, const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + Name klName = getKeyLocatorName(data, *state); + if (!state->getOutcome()) { // already failed + return; + } + + if (klName.getPrefix(-2).isPrefixOf(data.getName())) { + continueValidation(make_shared(klName), state); + } + else { + state->fail({ValidationError::Code::INVALID_KEY_LOCATOR, "Data signing policy violation for " + + data.getName().toUri() + " by " + klName.toUri()}); + } +} + +void +ValidationPolicySimpleHierarchy::checkPolicy(const Interest& interest, const shared_ptr& state, + const ValidationContinuation& continueValidation) +{ + Name klName = getKeyLocatorName(interest, *state); + if (!state->getOutcome()) { // already failed + return; + } + + if (klName.getPrefix(-2).isPrefixOf(interest.getName())) { + continueValidation(make_shared(klName), state); + } + else { + state->fail({ValidationError::Code::INVALID_KEY_LOCATOR, "Interest signing policy violation for " + + interest.getName().toUri() + " by " + klName.toUri()}); + } +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/validation-policy-simple-hierarchy.hpp b/ndn-cxx/security/v2/validation-policy-simple-hierarchy.hpp new file mode 100644 index 000000000..790807572 --- /dev/null +++ b/ndn-cxx/security/v2/validation-policy-simple-hierarchy.hpp @@ -0,0 +1,50 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_VALIDATION_POLICY_SIMPLE_HIERARCHY_HPP +#define NDN_SECURITY_V2_VALIDATION_POLICY_SIMPLE_HIERARCHY_HPP + +#include "ndn-cxx/security/v2/validation-policy.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +/** + * @brief Validation policy for a simple hierarchical trust model + */ +class ValidationPolicySimpleHierarchy : public ValidationPolicy +{ +public: + void + checkPolicy(const Data& data, const shared_ptr& state, + const ValidationContinuation& continueValidation) override; + + void + checkPolicy(const Interest& interest, const shared_ptr& state, + const ValidationContinuation& continueValidation) override; +}; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_VALIDATION_POLICY_SIMPLE_HIERARCHY_HPP diff --git a/ndn-cxx/security/v2/validation-policy.cpp b/ndn-cxx/security/v2/validation-policy.cpp new file mode 100644 index 000000000..23a63e2af --- /dev/null +++ b/ndn-cxx/security/v2/validation-policy.cpp @@ -0,0 +1,115 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validation-policy.hpp" +#include "ndn-cxx/security/signing-info.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +void +ValidationPolicy::setInnerPolicy(unique_ptr innerPolicy) +{ + if (innerPolicy == nullptr) { + NDN_THROW(std::invalid_argument("Inner policy argument cannot be nullptr")); + } + + if (m_validator != nullptr) { + innerPolicy->setValidator(*m_validator); + } + + if (m_innerPolicy == nullptr) { + m_innerPolicy = std::move(innerPolicy); + } + else { + m_innerPolicy->setInnerPolicy(std::move(innerPolicy)); + } +} + +ValidationPolicy& +ValidationPolicy::getInnerPolicy() +{ + return *m_innerPolicy; +} + +void +ValidationPolicy::setValidator(Validator& validator) +{ + m_validator = &validator; + if (m_innerPolicy != nullptr) { + m_innerPolicy->setValidator(validator); + } +} + +static Name +getKeyLocatorName(const SignatureInfo& si, ValidationState& state) +{ + if (si.getSignatureType() == tlv::DigestSha256) { + return SigningInfo::getDigestSha256Identity(); + } + + if (!si.hasKeyLocator()) { + state.fail({ValidationError::Code::INVALID_KEY_LOCATOR, "KeyLocator is missing"}); + return Name(); + } + + const KeyLocator& kl = si.getKeyLocator(); + if (kl.getType() != tlv::Name) { + state.fail({ValidationError::Code::INVALID_KEY_LOCATOR, "KeyLocator type is not Name"}); + return Name(); + } + + return kl.getName(); +} + +Name +getKeyLocatorName(const Data& data, ValidationState& state) +{ + return getKeyLocatorName(data.getSignature().getSignatureInfo(), state); +} + +Name +getKeyLocatorName(const Interest& interest, ValidationState& state) +{ + const Name& name = interest.getName(); + if (name.size() < signed_interest::MIN_SIZE) { + state.fail({ValidationError::INVALID_KEY_LOCATOR, + "Invalid signed Interest: name too short"}); + return Name(); + } + + SignatureInfo si; + try { + si.wireDecode(name.at(signed_interest::POS_SIG_INFO).blockFromValue()); + } + catch (const tlv::Error& e) { + state.fail({ValidationError::Code::INVALID_KEY_LOCATOR, + "Invalid signed Interest: " + std::string(e.what())}); + return Name(); + } + + return getKeyLocatorName(si, state); +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/validation-policy.hpp b/ndn-cxx/security/v2/validation-policy.hpp new file mode 100644 index 000000000..c5b52c599 --- /dev/null +++ b/ndn-cxx/security/v2/validation-policy.hpp @@ -0,0 +1,170 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_VALIDATION_POLICY_HPP +#define NDN_SECURITY_V2_VALIDATION_POLICY_HPP + +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/security/v2/certificate-request.hpp" +#include "ndn-cxx/security/v2/validation-state.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +/** + * @brief Abstraction that implements validation policy for Data and Interest packets + */ +class ValidationPolicy : noncopyable +{ +public: + using ValidationContinuation = std::function& certRequest, + const shared_ptr& state)>; + + virtual + ~ValidationPolicy() = default; + + /** + * @brief Set inner policy + * + * Multiple assignments of the inner policy will create a "chain" of linked policies. + * The inner policy from the latest invocation of setInnerPolicy will be at the bottom + * of the policy list. + * + * For example, sequence of `this->setInnerPolicy(policy1)` and + * `this->setInnerPolicy(policy2)`, will result in `this->m_innerPolicy == policy1`, + * this->m_innerPolicy->m_innerPolicy == policy2', and + * `this->m_innerPolicy->m_innerPolicy->m_innerPolicy == nullptr`. + * + * @throw std::invalid_argument exception, if @p innerPolicy is nullptr. + */ + void + setInnerPolicy(unique_ptr innerPolicy); + + /** + * @brief Check if inner policy is set + */ + bool + hasInnerPolicy() const + { + return m_innerPolicy != nullptr; + } + + /** + * @brief Return the inner policy + * + * If the inner policy was not set, behavior is undefined. + */ + ValidationPolicy& + getInnerPolicy(); + + /** + * @brief Set validator to which the policy is associated + */ + void + setValidator(Validator& validator); + + /** + * @brief Check @p data against the policy + * + * Depending on implementation of the policy, this check can be done synchronously or + * asynchronously. + * + * Semantics of checkPolicy has changed from v1::Validator + * - If packet violates policy, the policy should call `state->fail` with appropriate error + * code and error description. + * - If packet conforms to the policy and no further certificate retrievals are necessary, + * the policy should call continueValidation(nullptr, state) + * - If packet conforms to the policy and a certificate needs to be fetched, the policy should + * call continueValidation(, state) + */ + virtual void + checkPolicy(const Data& data, const shared_ptr& state, + const ValidationContinuation& continueValidation) = 0; + + /** + * @brief Check @p interest against the policy + * + * Depending on implementation of the policy, this check can be done synchronously or + * asynchronously. + * + * Semantics of checkPolicy has changed from v1::Validator + * - If packet violates policy, the policy should call `state->fail` with appropriate error + * code and error description. + * - If packet conforms to the policy and no further certificate retrievals are necessary, + * the policy should call continueValidation(nullptr, state) + * - If packet conforms to the policy and a certificate needs to be fetched, the policy should + * call continueValidation(, state) + */ + virtual void + checkPolicy(const Interest& interest, const shared_ptr& state, + const ValidationContinuation& continueValidation) = 0; + + /** + * @brief Check @p certificate against the policy + * + * Unless overridden by the policy, this check defaults to `checkPolicy(const Data&, ...)`. + * + * Depending on implementation of the policy, this check can be done synchronously or + * asynchronously. + * + * Semantics of checkPolicy has changed from v1::Validator + * - If packet violates policy, the policy should call `state->fail` with appropriate error + * code and error description. + * - If packet conforms to the policy and no further certificate retrievals are necessary, + * the policy should call continueValidation(nullptr, state) + * - If packet conforms to the policy and a certificate needs to be fetched, the policy should + * call continueValidation(, state) + */ + virtual void + checkPolicy(const Certificate& certificate, const shared_ptr& state, + const ValidationContinuation& continueValidation) + { + checkPolicy(static_cast(certificate), state, continueValidation); + } + +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED: + Validator* m_validator = nullptr; + unique_ptr m_innerPolicy; +}; + +/** \brief extract KeyLocator.Name from Data + * + * Data must contain a KeyLocator of Name type. + * Otherwise, state.fail is invoked with INVALID_KEY_LOCATOR error. + */ +Name +getKeyLocatorName(const Data& data, ValidationState& state); + +/** \brief extract KeyLocator.Name from signed Interest + * + * Interest must have SignatureInfo and contain a KeyLocator of Name type. + * Otherwise, state.fail is invoked with INVALID_KEY_LOCATOR error. + */ +Name +getKeyLocatorName(const Interest& interest, ValidationState& state); + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_VALIDATION_POLICY_HPP diff --git a/ndn-cxx/security/v2/validation-state.cpp b/ndn-cxx/security/v2/validation-state.cpp new file mode 100644 index 000000000..f6ee8d27a --- /dev/null +++ b/ndn-cxx/security/v2/validation-state.cpp @@ -0,0 +1,208 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validation-state.hpp" +#include "ndn-cxx/security/v2/validator.hpp" +#include "ndn-cxx/security/verification-helpers.hpp" +#include "ndn-cxx/util/logger.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +NDN_LOG_INIT(ndn.security.v2.ValidationState); + +#define NDN_LOG_DEBUG_DEPTH(x) NDN_LOG_DEBUG(std::string(this->getDepth() + 1, '>') << " " << x) +#define NDN_LOG_TRACE_DEPTH(x) NDN_LOG_TRACE(std::string(this->getDepth() + 1, '>') << " " << x) + +ValidationState::ValidationState() + : m_outcome(boost::logic::indeterminate) +{ +} + +ValidationState::~ValidationState() +{ + NDN_LOG_TRACE(__func__); + BOOST_ASSERT(!boost::logic::indeterminate(m_outcome)); +} + +size_t +ValidationState::getDepth() const +{ + return m_certificateChain.size(); +} + +bool +ValidationState::hasSeenCertificateName(const Name& certName) +{ + return !m_seenCertificateNames.insert(certName).second; +} + +void +ValidationState::addCertificate(const Certificate& cert) +{ + m_certificateChain.push_front(cert); +} + +const Certificate* +ValidationState::verifyCertificateChain(const Certificate& trustedCert) +{ + const Certificate* validatedCert = &trustedCert; + for (auto it = m_certificateChain.begin(); it != m_certificateChain.end(); ++it) { + const auto& certToValidate = *it; + + if (!verifySignature(certToValidate, *validatedCert)) { + this->fail({ValidationError::Code::INVALID_SIGNATURE, "Invalid signature of certificate `" + + certToValidate.getName().toUri() + "`"}); + m_certificateChain.erase(it, m_certificateChain.end()); + return nullptr; + } + else { + NDN_LOG_TRACE_DEPTH("OK signature for certificate `" << certToValidate.getName() << "`"); + validatedCert = &certToValidate; + } + } + return validatedCert; +} + +/////// DataValidationState + +DataValidationState::DataValidationState(const Data& data, + const DataValidationSuccessCallback& successCb, + const DataValidationFailureCallback& failureCb) + : m_data(data) + , m_successCb(successCb) + , m_failureCb(failureCb) +{ + BOOST_ASSERT(m_successCb != nullptr); + BOOST_ASSERT(m_failureCb != nullptr); +} + +DataValidationState::~DataValidationState() +{ + if (boost::logic::indeterminate(m_outcome)) { + this->fail({ValidationError::Code::IMPLEMENTATION_ERROR, + "Validator/policy did not invoke success or failure callback"}); + } +} + +void +DataValidationState::verifyOriginalPacket(const Certificate& trustedCert) +{ + if (verifySignature(m_data, trustedCert)) { + NDN_LOG_TRACE_DEPTH("OK signature for data `" << m_data.getName() << "`"); + m_successCb(m_data); + BOOST_ASSERT(boost::logic::indeterminate(m_outcome)); + m_outcome = true; + } + else { + this->fail({ValidationError::Code::INVALID_SIGNATURE, "Invalid signature of data `" + + m_data.getName().toUri() + "`"}); + } +} + +void +DataValidationState::bypassValidation() +{ + NDN_LOG_TRACE_DEPTH("Signature verification bypassed for data `" << m_data.getName() << "`"); + m_successCb(m_data); + BOOST_ASSERT(boost::logic::indeterminate(m_outcome)); + m_outcome = true; +} + +void +DataValidationState::fail(const ValidationError& error) +{ + NDN_LOG_DEBUG_DEPTH(error); + m_failureCb(m_data, error); + BOOST_ASSERT(boost::logic::indeterminate(m_outcome)); + m_outcome = false; +} + +const Data& +DataValidationState::getOriginalData() const +{ + return m_data; +} + +/////// InterestValidationState + +InterestValidationState::InterestValidationState(const Interest& interest, + const InterestValidationSuccessCallback& successCb, + const InterestValidationFailureCallback& failureCb) + : m_interest(interest) + , m_failureCb(failureCb) +{ + afterSuccess.connect(successCb); + BOOST_ASSERT(successCb != nullptr); + BOOST_ASSERT(m_failureCb != nullptr); +} + +InterestValidationState::~InterestValidationState() +{ + if (boost::logic::indeterminate(m_outcome)) { + this->fail({ValidationError::Code::IMPLEMENTATION_ERROR, + "Validator/policy did not invoke success or failure callback"}); + } +} + +void +InterestValidationState::verifyOriginalPacket(const Certificate& trustedCert) +{ + if (verifySignature(m_interest, trustedCert)) { + NDN_LOG_TRACE_DEPTH("OK signature for interest `" << m_interest.getName() << "`"); + this->afterSuccess(m_interest); + BOOST_ASSERT(boost::logic::indeterminate(m_outcome)); + m_outcome = true; + } + else { + this->fail({ValidationError::Code::INVALID_SIGNATURE, "Invalid signature of interest `" + + m_interest.getName().toUri() + "`"}); + } +} + +void +InterestValidationState::bypassValidation() +{ + NDN_LOG_TRACE_DEPTH("Signature verification bypassed for interest `" << m_interest.getName() << "`"); + this->afterSuccess(m_interest); + BOOST_ASSERT(boost::logic::indeterminate(m_outcome)); + m_outcome = true; +} + +void +InterestValidationState::fail(const ValidationError& error) +{ + NDN_LOG_DEBUG_DEPTH(error); + m_failureCb(m_interest, error); + BOOST_ASSERT(boost::logic::indeterminate(m_outcome)); + m_outcome = false; +} + +const Interest& +InterestValidationState::getOriginalInterest() const +{ + return m_interest; +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/validation-state.hpp b/ndn-cxx/security/v2/validation-state.hpp new file mode 100644 index 000000000..4ebf31cd6 --- /dev/null +++ b/ndn-cxx/security/v2/validation-state.hpp @@ -0,0 +1,254 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_VALIDATION_STATE_HPP +#define NDN_SECURITY_V2_VALIDATION_STATE_HPP + +#include "ndn-cxx/detail/tag-host.hpp" +#include "ndn-cxx/security/v2/validation-callback.hpp" +#include "ndn-cxx/security/v2/certificate.hpp" +#include "ndn-cxx/util/signal.hpp" + +#include +#include +#include + +namespace ndn { +namespace security { +namespace v2 { + +class Validator; + +/** + * @brief Validation state + * + * One instance of the validation state is kept for the validation of the whole certificate + * chain. + * + * The state collects the certificate chain that adheres to the selected validation policy to + * validate data or interest packets. Certificate, data, and interest packet signatures are + * verified only after the validator determines that the chain terminates with a trusted + * certificate (a trusted anchor or a previously validated certificate). This model allows + * filtering out invalid certificate chains without incurring (costly) cryptographic signature + * verification overhead and mitigates some forms of denial-of-service attacks. + * + * Validation policy and/or key fetcher may add custom information associated with the + * validation state using tags (@sa TagHost) + * + * @sa DataValidationState, InterestValidationState + */ +class ValidationState : public TagHost, noncopyable +{ +public: + /** + * @brief Create validation state + */ + ValidationState(); + + virtual + ~ValidationState(); + + boost::logic::tribool + getOutcome() const + { + return m_outcome; + } + + /** + * @brief Call the failure callback + */ + virtual void + fail(const ValidationError& error) = 0; + + /** + * @return Depth of certificate chain + */ + size_t + getDepth() const; + + /** + * @brief Check if @p certName has been previously seen and record the supplied name + */ + bool + hasSeenCertificateName(const Name& certName); + + /** + * @brief Add @p cert to the top of the certificate chain + * + * If m_certificateChain is empty, @p cert should be the signer of the original + * packet. If m_certificateChain is not empty, @p cert should be the signer of + * m_certificateChain.front(). + * + * @post m_certificateChain.front() == cert + * @note This function does not verify the signature bits. + */ + void + addCertificate(const Certificate& cert); + +private: // Interface intended to be used only by Validator class + /** + * @brief Verify signature of the original packet + * + * @param trustCert The certificate that signs the original packet + */ + virtual void + verifyOriginalPacket(const Certificate& trustedCert) = 0; + + /** + * @brief Call success callback of the original packet without signature validation + */ + virtual void + bypassValidation() = 0; + + /** + * @brief Verify signatures of certificates in the certificate chain + * + * When certificate chain cannot be verified, this method will call this->fail() with + * INVALID_SIGNATURE error code and the appropriate diagnostic message. + * + * @retval nullptr Signatures of at least one certificate in the chain is invalid. All unverified + * certificates have been removed from m_certificateChain. + * @retval Certificate to validate original data packet, either m_certificateChain.back() or + * trustedCert if the certificate chain is empty. + * + * @post m_certificateChain includes a list of certificates successfully verified by + * @p trustedCert. + */ + const Certificate* + verifyCertificateChain(const Certificate& trustedCert); + +protected: + boost::logic::tribool m_outcome; + +private: + std::unordered_set m_seenCertificateNames; + + /** + * @brief the certificate chain + * + * Each certificate in the chain signs the next certificate. The last certificate signs the + * original packet. + */ + std::list m_certificateChain; + + friend class Validator; +}; + +/** + * @brief Validation state for a data packet + */ +class DataValidationState final : public ValidationState +{ +public: + /** + * @brief Create validation state for @p data + * + * The caller must ensure that state instance is valid until validation finishes (i.e., until + * after validateCertificateChain() and validateOriginalPacket() are called) + */ + DataValidationState(const Data& data, + const DataValidationSuccessCallback& successCb, + const DataValidationFailureCallback& failureCb); + + /** + * @brief Destructor + * + * If neither success callback nor failure callback was called, the destructor will call + * failure callback with IMPLEMENTATION_ERROR error code. + */ + ~DataValidationState() final; + + void + fail(const ValidationError& error) final; + + /** + * @return Original data being validated + */ + const Data& + getOriginalData() const; + +private: + void + verifyOriginalPacket(const Certificate& trustedCert) final; + + void + bypassValidation() final; + +private: + Data m_data; + DataValidationSuccessCallback m_successCb; + DataValidationFailureCallback m_failureCb; +}; + +/** + * @brief Validation state for an interest packet + */ +class InterestValidationState final : public ValidationState +{ +public: + /** + * @brief Create validation state for @p interest + * + * The caller must ensure that state instance is valid until validation finishes (i.e., until + * after validateCertificateChain() and validateOriginalPacket() are called) + */ + InterestValidationState(const Interest& interest, + const InterestValidationSuccessCallback& successCb, + const InterestValidationFailureCallback& failureCb); + + /** + * @brief Destructor + * + * If neither success callback nor failure callback was called, the destructor will call + * failure callback with IMPLEMENTATION_ERROR error code. + */ + ~InterestValidationState() final; + + void + fail(const ValidationError& error) final; + + /** + * @return Original interest being validated + */ + const Interest& + getOriginalInterest() const; + +public: + util::Signal afterSuccess; + +private: + void + verifyOriginalPacket(const Certificate& trustedCert) final; + + void + bypassValidation() final; + +private: + Interest m_interest; + InterestValidationSuccessCallback m_successCb; + InterestValidationFailureCallback m_failureCb; +}; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_VALIDATION_STATE_HPP diff --git a/ndn-cxx/security/v2/validator-config/checker.cpp b/ndn-cxx/security/v2/validator-config/checker.cpp new file mode 100644 index 000000000..db07441ae --- /dev/null +++ b/ndn-cxx/security/v2/validator-config/checker.cpp @@ -0,0 +1,326 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validator-config/checker.hpp" +#include "ndn-cxx/security/v2/validation-state.hpp" +#include "ndn-cxx/security/verification-helpers.hpp" +#include "ndn-cxx/security/pib/key.hpp" + +#include + +namespace ndn { +namespace security { +namespace v2 { +namespace validator_config { + +bool +Checker::check(uint32_t pktType, const Name& pktName, const Name& klName, + const shared_ptr& state) +{ + BOOST_ASSERT(pktType == tlv::Interest || pktType == tlv::Data); + + if (pktType == tlv::Interest) { + if (pktName.size() < signed_interest::MIN_SIZE) + return false; + + return checkNames(pktName.getPrefix(-signed_interest::MIN_SIZE), klName, state); + } + else { + return checkNames(pktName, klName, state); + } +} + +NameRelationChecker::NameRelationChecker(const Name& name, const NameRelation& relation) + : m_name(name) + , m_relation(relation) +{ +} + +bool +NameRelationChecker::checkNames(const Name& pktName, const Name& klName, + const shared_ptr& state) +{ + // pktName not used in this check + Name identity = extractIdentityFromKeyName(klName); + bool result = checkNameRelation(m_relation, m_name, identity); + if (!result) { + std::ostringstream os; + os << "KeyLocator check failed: name relation " << m_name << " " << m_relation + << " for packet " << pktName << " is invalid" + << " (KeyLocator=" << klName << ", identity=" << identity << ")"; + state->fail({ValidationError::POLICY_ERROR, os.str()}); + } + return result; +} + +RegexChecker::RegexChecker(const Regex& regex) + : m_regex(regex) +{ +} + +bool +RegexChecker::checkNames(const Name& pktName, const Name& klName, const shared_ptr& state) +{ + bool result = m_regex.match(klName); + if (!result) { + std::ostringstream os; + os << "KeyLocator check failed: regex " << m_regex << " for packet " << pktName << " is invalid" + << " (KeyLocator=" << klName << ")"; + state->fail({ValidationError::POLICY_ERROR, os.str()}); + } + return result; +} + +HyperRelationChecker::HyperRelationChecker(const std::string& pktNameExpr, const std::string pktNameExpand, + const std::string& klNameExpr, const std::string klNameExpand, + const NameRelation& hyperRelation) + : m_hyperPRegex(pktNameExpr, pktNameExpand) + , m_hyperKRegex(klNameExpr, klNameExpand) + , m_hyperRelation(hyperRelation) +{ +} + +bool +HyperRelationChecker::checkNames(const Name& pktName, const Name& klName, + const shared_ptr& state) +{ + if (!m_hyperPRegex.match(pktName) || !m_hyperKRegex.match(klName)) { + std::ostringstream os; + os << "Packet " << pktName << " (" << "KeyLocator=" << klName << ") does not match " + << "the hyper relation rule pkt=" << m_hyperPRegex << ", key=" << m_hyperKRegex; + state->fail({ValidationError::POLICY_ERROR, os.str()}); + return false; + } + + bool result = checkNameRelation(m_hyperRelation, m_hyperKRegex.expand(), m_hyperPRegex.expand()); + if (!result) { + std::ostringstream os; + os << "KeyLocator check failed: hyper relation " << m_hyperRelation + << " pkt=" << m_hyperPRegex << ", key=" << m_hyperKRegex + << " of packet " << pktName << " (KeyLocator=" << klName << ") is invalid"; + state->fail({ValidationError::POLICY_ERROR, os.str()}); + } + return result; +} + +unique_ptr +Checker::create(const ConfigSection& configSection, const std::string& configFilename) +{ + auto propertyIt = configSection.begin(); + + // Get checker.type + if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) { + NDN_THROW(Error("Expecting ")); + } + + std::string type = propertyIt->second.data(); + if (boost::iequals(type, "customized")) { + return createCustomizedChecker(configSection, configFilename); + } + else if (boost::iequals(type, "hierarchical")) { + return createHierarchicalChecker(configSection, configFilename); + } + else { + NDN_THROW(Error("Unrecognized : " + type)); + } +} + +unique_ptr +Checker::createCustomizedChecker(const ConfigSection& configSection, + const std::string& configFilename) +{ + auto propertyIt = configSection.begin(); + propertyIt++; + + // TODO implement restrictions based on signature type (outside this checker) + + if (propertyIt != configSection.end() && boost::iequals(propertyIt->first, "sig-type")) { + // ignore sig-type + propertyIt++; + } + + // Get checker.key-locator + if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "key-locator")) { + NDN_THROW(Error("Expecting ")); + } + + auto checker = createKeyLocatorChecker(propertyIt->second, configFilename); + propertyIt++; + + if (propertyIt != configSection.end()) { + NDN_THROW(Error("Expecting end of ")); + } + return checker; +} + +unique_ptr +Checker::createHierarchicalChecker(const ConfigSection& configSection, + const std::string& configFilename) +{ + auto propertyIt = configSection.begin(); + propertyIt++; + + // TODO implement restrictions based on signature type (outside this checker) + + if (propertyIt != configSection.end() && boost::iequals(propertyIt->first, "sig-type")) { + // ignore sig-type + propertyIt++; + } + + if (propertyIt != configSection.end()) { + NDN_THROW(Error("Expecting end of ")); + } + return make_unique("^(<>*)$", "\\1", + "^(<>*)<>$", "\\1", + NameRelation::IS_PREFIX_OF); +} + +unique_ptr +Checker::createKeyLocatorChecker(const ConfigSection& configSection, + const std::string& configFilename) +{ + auto propertyIt = configSection.begin(); + + // Get checker.key-locator.type + if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) + NDN_THROW(Error("Expecting ")); + + std::string type = propertyIt->second.data(); + if (boost::iequals(type, "name")) + return createKeyLocatorNameChecker(configSection, configFilename); + else + NDN_THROW(Error("Unrecognized : " + type)); +} + +unique_ptr +Checker::createKeyLocatorNameChecker(const ConfigSection& configSection, + const std::string& configFilename) +{ + auto propertyIt = configSection.begin(); + propertyIt++; + + if (propertyIt == configSection.end()) + NDN_THROW(Error("Unexpected end of ")); + + if (boost::iequals(propertyIt->first, "name")) { + Name name; + try { + name = Name(propertyIt->second.data()); + } + catch (const Name::Error&) { + NDN_THROW_NESTED(Error("Invalid : " + propertyIt->second.data())); + } + propertyIt++; + + if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation")) { + NDN_THROW(Error("Expecting ")); + } + + std::string relationString = propertyIt->second.data(); + propertyIt++; + + NameRelation relation = getNameRelationFromString(relationString); + + if (propertyIt != configSection.end()) { + NDN_THROW(Error("Expecting end of ")); + } + return make_unique(name, relation); + } + else if (boost::iequals(propertyIt->first, "regex")) { + std::string regexString = propertyIt->second.data(); + propertyIt++; + + if (propertyIt != configSection.end()) { + NDN_THROW(Error("Expecting end of ")); + } + + try { + return make_unique(Regex(regexString)); + } + catch (const Regex::Error&) { + NDN_THROW_NESTED(Error("Invalid : " + regexString)); + } + } + else if (boost::iequals(propertyIt->first, "hyper-relation")) { + const ConfigSection& hSection = propertyIt->second; + auto hPropertyIt = hSection.begin(); + + // Get k-regex + if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-regex")) { + NDN_THROW(Error("Expecting ")); + } + + std::string kRegex = hPropertyIt->second.data(); + hPropertyIt++; + + // Get k-expand + if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-expand")) { + NDN_THROW(Error("Expecting ")); + } + + std::string kExpand = hPropertyIt->second.data(); + hPropertyIt++; + + // Get h-relation + if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "h-relation")) { + NDN_THROW(Error("Expecting ")); + } + + std::string hRelation = hPropertyIt->second.data(); + hPropertyIt++; + + // Get p-regex + if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-regex")) { + NDN_THROW(Error("Expecting ")); + } + + std::string pRegex = hPropertyIt->second.data(); + hPropertyIt++; + + // Get p-expand + if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-expand")) { + NDN_THROW(Error("Expecting ")); + } + + std::string pExpand = hPropertyIt->second.data(); + hPropertyIt++; + + if (hPropertyIt != hSection.end()) { + NDN_THROW(Error("Expecting end of ")); + } + + NameRelation relation = getNameRelationFromString(hRelation); + try { + return make_unique(pRegex, pExpand, kRegex, kExpand, relation); + } + catch (const Regex::Error&) { + NDN_THROW_NESTED(Error("Invalid regex for ")); + } + } + else { + NDN_THROW(Error("Unrecognized : " + propertyIt->first)); + } +} + +} // namespace validator_config +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/validator-config/checker.hpp b/ndn-cxx/security/v2/validator-config/checker.hpp new file mode 100644 index 000000000..fb9a169dc --- /dev/null +++ b/ndn-cxx/security/v2/validator-config/checker.hpp @@ -0,0 +1,136 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_VALIDATOR_CONFIG_CHECKER_HPP +#define NDN_SECURITY_V2_VALIDATOR_CONFIG_CHECKER_HPP + +#include "ndn-cxx/name.hpp" +#include "ndn-cxx/security/v2/validator-config/common.hpp" +#include "ndn-cxx/security/v2/validator-config/name-relation.hpp" +#include "ndn-cxx/util/regex.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +class ValidationState; + +namespace validator_config { + +class Checker : noncopyable +{ +public: + virtual + ~Checker() = default; + + /** + * @brief Check if packet name ane KeyLocator satisfy the checker's conditions + * + * @param pktType tlv::Interest or tlv::Data + * @param pktName packet's name + * @param klName KeyLocator's name + * @param state Validation state + * + * @retval false data is immediately invalid. Will call state::fail() with proper code and message. + * @retval true further signature verification is needed. + */ + bool + check(uint32_t pktType, const Name& pktName, const Name& klName, const shared_ptr& state); + + /** + * @brief create a checker from configuration section + * + * @param configSection The section containing the definition of checker. + * @param configFilename The configuration file name. + * @return a checker created from configuration + */ + static unique_ptr + create(const ConfigSection& configSection, const std::string& configFilename); + +private: + static unique_ptr + createCustomizedChecker(const ConfigSection& configSection, const std::string& configFilename); + + static unique_ptr + createHierarchicalChecker(const ConfigSection& configSection, const std::string& configFilename); + + static unique_ptr + createKeyLocatorChecker(const ConfigSection& configSection, const std::string& configFilename); + + static unique_ptr + createKeyLocatorNameChecker(const ConfigSection& configSection, const std::string& configFilename); + +protected: + virtual bool + checkNames(const Name& pktName, const Name& klName, const shared_ptr& state) = 0; +}; + +class NameRelationChecker : public Checker +{ +public: + NameRelationChecker(const Name& name, const NameRelation& relation); + +protected: + bool + checkNames(const Name& pktName, const Name& klName, const shared_ptr& state) override; + +private: + Name m_name; + NameRelation m_relation; +}; + +class RegexChecker : public Checker +{ +public: + explicit + RegexChecker(const Regex& regex); + +protected: + bool + checkNames(const Name& pktName, const Name& klName, const shared_ptr& state) override; + +private: + Regex m_regex; +}; + +class HyperRelationChecker : public Checker +{ +public: + HyperRelationChecker(const std::string& pktNameExpr, const std::string pktNameExpand, + const std::string& klNameExpr, const std::string klNameExpand, + const NameRelation& hyperRelation); + +protected: + bool + checkNames(const Name& pktName, const Name& klName, const shared_ptr& state) override; + +private: + Regex m_hyperPRegex; + Regex m_hyperKRegex; + NameRelation m_hyperRelation; +}; + +} // namespace validator_config +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_VALIDATOR_CONFIG_CHECKER_HPP diff --git a/ndn-cxx/security/v2/validator-config/common.hpp b/ndn-cxx/security/v2/validator-config/common.hpp new file mode 100644 index 000000000..21c690f98 --- /dev/null +++ b/ndn-cxx/security/v2/validator-config/common.hpp @@ -0,0 +1,49 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#ifndef NDN_SECURITY_V2_VALIDATOR_CONFIG_COMMON_HPP +#define NDN_SECURITY_V2_VALIDATOR_CONFIG_COMMON_HPP + +#include "ndn-cxx/detail/common.hpp" + +#include + +namespace ndn { +namespace security { +namespace v2 { +namespace validator_config { + +typedef boost::property_tree::ptree ConfigSection; + +class Error : public std::runtime_error +{ +public: + using std::runtime_error::runtime_error; +}; + +} // namespace validator_config +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_VALIDATOR_CONFIG_COMMON_HPP diff --git a/ndn-cxx/security/v2/validator-config/filter.cpp b/ndn-cxx/security/v2/validator-config/filter.cpp new file mode 100644 index 000000000..8fa8b2eda --- /dev/null +++ b/ndn-cxx/security/v2/validator-config/filter.cpp @@ -0,0 +1,147 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validator-config/filter.hpp" + +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/security/security-common.hpp" +#include "ndn-cxx/util/regex.hpp" + +#include + +namespace ndn { +namespace security { +namespace v2 { +namespace validator_config { + +bool +Filter::match(uint32_t pktType, const Name& pktName) +{ + BOOST_ASSERT(pktType == tlv::Interest || pktType == tlv::Data); + + if (pktType == tlv::Interest) { + if (pktName.size() < signed_interest::MIN_SIZE) + return false; + + return matchName(pktName.getPrefix(-signed_interest::MIN_SIZE)); + } + else { + return matchName(pktName); + } +} + +RelationNameFilter::RelationNameFilter(const Name& name, NameRelation relation) + : m_name(name) + , m_relation(relation) +{ +} + +bool +RelationNameFilter::matchName(const Name& name) +{ + return checkNameRelation(m_relation, m_name, name); +} + +RegexNameFilter::RegexNameFilter(const Regex& regex) + : m_regex(regex) +{ +} + +bool +RegexNameFilter::matchName(const Name& name) +{ + return m_regex.match(name); +} + +unique_ptr +Filter::create(const ConfigSection& configSection, const std::string& configFilename) +{ + auto propertyIt = configSection.begin(); + + if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) { + NDN_THROW(Error("Expecting ")); + } + + std::string type = propertyIt->second.data(); + if (boost::iequals(type, "name")) + return createNameFilter(configSection, configFilename); + else + NDN_THROW(Error("Unrecognized : " + type)); +} + +unique_ptr +Filter::createNameFilter(const ConfigSection& configSection, const std::string& configFilename) +{ + auto propertyIt = configSection.begin(); + propertyIt++; + + if (propertyIt == configSection.end()) + NDN_THROW(Error("Unexpected end of ")); + + if (boost::iequals(propertyIt->first, "name")) { + // Get filter.name + Name name; + try { + name = Name(propertyIt->second.data()); + } + catch (const Name::Error&) { + NDN_THROW_NESTED(Error("Invalid : " + propertyIt->second.data())); + } + + propertyIt++; + + // Get filter.relation + if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation")) { + NDN_THROW(Error("Expecting ")); + } + + NameRelation relation = getNameRelationFromString(propertyIt->second.data()); + propertyIt++; + + if (propertyIt != configSection.end()) + NDN_THROW(Error("Expecting end of ")); + + return make_unique(name, relation); + } + else if (boost::iequals(propertyIt->first, "regex")) { + std::string regexString = propertyIt->second.data(); + propertyIt++; + + if (propertyIt != configSection.end()) + NDN_THROW(Error("Expecting end of ")); + + try { + return make_unique(Regex(regexString)); + } + catch (const Regex::Error&) { + NDN_THROW_NESTED(Error("Invalid : " + regexString)); + } + } + else { + NDN_THROW(Error("Unrecognized property: " + propertyIt->first)); + } +} + +} // namespace validator_config +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/validator-config/filter.hpp b/ndn-cxx/security/v2/validator-config/filter.hpp new file mode 100644 index 000000000..f5af85ee1 --- /dev/null +++ b/ndn-cxx/security/v2/validator-config/filter.hpp @@ -0,0 +1,142 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_VALIDATOR_CONFIG_FILTER_HPP +#define NDN_SECURITY_V2_VALIDATOR_CONFIG_FILTER_HPP + +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/security/v2/validator-config/common.hpp" +#include "ndn-cxx/security/v2/validator-config/name-relation.hpp" +#include "ndn-cxx/util/regex.hpp" + +namespace ndn { +namespace security { +namespace v2 { +namespace validator_config { + +/** + * @brief Filter is one of the classes used by ValidatorConfig. + * + * The ValidatorConfig class consists of a set of rules. + * The Filter class is a part of a rule and is used to match packet. + * Matched packets will be checked against the checkers defined in the rule. + */ +class Filter : noncopyable +{ +public: + virtual + ~Filter() = default; + + bool + match(uint32_t pktType, const Name& pktName); + +public: + /** + * @brief Create a filter from the configuration section + * + * @param configSection The section containing the definition of filter. + * @param configFilename The configuration file name. + * @return a filter created from configuration + */ + static unique_ptr + create(const ConfigSection& configSection, const std::string& configFilename); + +private: + static unique_ptr + createNameFilter(const ConfigSection& configSection, const std::string& configFilename); + +private: + virtual bool + matchName(const Name& pktName) = 0; +}; + +/** + * @brief Check that name is in relation to the packet name + * + * The following configuration + * @code + * filter + * { + * type name + * name /example + * relation is-prefix-of + * } + * @endcode + * + * creates + * @code + * RelationNameFilter("/example", RelationNameFilter::RELATION_IS_PREFIX_OF); + * @endcode + */ +class RelationNameFilter : public Filter +{ +public: + RelationNameFilter(const Name& name, NameRelation relation); + +private: + bool + matchName(const Name& pktName) override; + +private: + Name m_name; + NameRelation m_relation; +}; + +/** + * @brief Filter to check that packet name matches the specified regular expression + * + * The following configuration + * @code + * filter + * { + * type name + * regex ^[^]*<>*$ + * } + * @endcode + * + * creates + * @code + * RegexNameFilter("^[^]*<>*$"); + * @endcode + * + * @sa Regex + */ +class RegexNameFilter : public Filter +{ +public: + explicit + RegexNameFilter(const Regex& regex); + +private: + bool + matchName(const Name& pktName) override; + +private: + Regex m_regex; +}; + +} // namespace validator_config +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_VALIDATOR_CONFIG_FILTER_HPP diff --git a/ndn-cxx/security/v2/validator-config/name-relation.cpp b/ndn-cxx/security/v2/validator-config/name-relation.cpp new file mode 100644 index 000000000..ec9991df4 --- /dev/null +++ b/ndn-cxx/security/v2/validator-config/name-relation.cpp @@ -0,0 +1,79 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validator-config/name-relation.hpp" + +#include + +namespace ndn { +namespace security { +namespace v2 { +namespace validator_config { + +std::ostream& +operator<<(std::ostream& os, NameRelation relation) +{ + switch (relation) { + case NameRelation::EQUAL: + return os << "equal"; + case NameRelation::IS_PREFIX_OF: + return os << "is-prefix-of"; + case NameRelation::IS_STRICT_PREFIX_OF: + return os << "is-strict-prefix-of"; + } + return os; +} + +bool +checkNameRelation(NameRelation relation, const Name& name1, const Name& name2) +{ + switch (relation) { + case NameRelation::EQUAL: + return name1 == name2; + case NameRelation::IS_PREFIX_OF: + return name1.isPrefixOf(name2); + case NameRelation::IS_STRICT_PREFIX_OF: + return name1.isPrefixOf(name2) && name1.size() < name2.size(); + } + return false; +} + +NameRelation +getNameRelationFromString(const std::string& relationString) +{ + if (boost::iequals(relationString, "equal")) { + return NameRelation::EQUAL; + } + else if (boost::iequals(relationString, "is-prefix-of")) { + return NameRelation::IS_PREFIX_OF; + } + else if (boost::iequals(relationString, "is-strict-prefix-of")) { + return NameRelation::IS_STRICT_PREFIX_OF; + } + else { + NDN_THROW(Error("Unsupported relation: " + relationString)); + } +} + +} // namespace validator_config +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/validator-config/name-relation.hpp b/ndn-cxx/security/v2/validator-config/name-relation.hpp new file mode 100644 index 000000000..aa236df61 --- /dev/null +++ b/ndn-cxx/security/v2/validator-config/name-relation.hpp @@ -0,0 +1,60 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_VALIDATOR_CONFIG_NAME_RELATION_HPP +#define NDN_SECURITY_V2_VALIDATOR_CONFIG_NAME_RELATION_HPP + +#include "ndn-cxx/name.hpp" +#include "ndn-cxx/security/v2/validator-config/common.hpp" + +namespace ndn { +namespace security { +namespace v2 { +namespace validator_config { + +enum class NameRelation { + EQUAL, + IS_PREFIX_OF, + IS_STRICT_PREFIX_OF +}; + +std::ostream& +operator<<(std::ostream& os, NameRelation relation); + +/** + * @brief check whether @p name1 and @p name2 satisfies @p relation + */ +bool +checkNameRelation(NameRelation relation, const Name& name1, const Name& name2); + +/** + * @brief convert @p relationString to NameRelation + * @throw Error if @p relationString cannot be converted + */ +NameRelation +getNameRelationFromString(const std::string& relationString); + +} // namespace validator_config +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_VALIDATOR_CONFIG_NAME_RELATION_HPP diff --git a/ndn-cxx/security/v2/validator-config/rule.cpp b/ndn-cxx/security/v2/validator-config/rule.cpp new file mode 100644 index 000000000..f0a52498a --- /dev/null +++ b/ndn-cxx/security/v2/validator-config/rule.cpp @@ -0,0 +1,169 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validator-config/rule.hpp" +#include "ndn-cxx/util/logger.hpp" + +#include + +NDN_LOG_INIT(ndn.security.validator_config.Rule); + +namespace ndn { +namespace security { +namespace v2 { +namespace validator_config { + +Rule::Rule(const std::string& id, uint32_t pktType) + : m_id(id) + , m_pktType(pktType) +{ +} + +void +Rule::addFilter(unique_ptr filter) +{ + m_filters.push_back(std::move(filter)); +} + +void +Rule::addChecker(unique_ptr checker) +{ + m_checkers.push_back(std::move(checker)); +} + +bool +Rule::match(uint32_t pktType, const Name& pktName) const +{ + NDN_LOG_TRACE("Trying to match " << pktName); + if (pktType != m_pktType) { + NDN_THROW(Error("Invalid packet type supplied (" + to_string(pktType) + + " != " + to_string(m_pktType) + ")")); + } + + if (m_filters.empty()) { + return true; + } + + bool retval = false; + for (const auto& filter : m_filters) { + retval |= filter->match(pktType, pktName); + if (retval) { + break; + } + } + return retval; +} + +bool +Rule::check(uint32_t pktType, const Name& pktName, const Name& klName, + const shared_ptr& state) const +{ + NDN_LOG_TRACE("Trying to check " << pktName << " with keyLocator " << klName); + + if (pktType != m_pktType) { + NDN_THROW(Error("Invalid packet type supplied (" + to_string(pktType) + + " != " + to_string(m_pktType) + ")")); + } + + bool hasPendingResult = false; + for (const auto& checker : m_checkers) { + bool result = checker->check(pktType, pktName, klName, state); + if (!result) { + return result; + } + hasPendingResult = true; + } + + return hasPendingResult; +} + +unique_ptr +Rule::create(const ConfigSection& configSection, const std::string& configFilename) +{ + auto propertyIt = configSection.begin(); + + // Get rule.id + if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "id")) { + NDN_THROW(Error("Expecting ")); + } + + std::string ruleId = propertyIt->second.data(); + propertyIt++; + + // Get rule.for + if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "for")) { + NDN_THROW(Error("Expecting in rule: " + ruleId)); + } + + std::string usage = propertyIt->second.data(); + propertyIt++; + + bool isForData = false; + if (boost::iequals(usage, "data")) { + isForData = true; + } + else if (boost::iequals(usage, "interest")) { + isForData = false; + } + else { + NDN_THROW(Error("Unrecognized : " + usage + " in rule: " + ruleId)); + } + + auto rule = make_unique(ruleId, isForData ? tlv::Data : tlv::Interest); + + // Get rule.filter(s) + for (; propertyIt != configSection.end(); propertyIt++) { + if (!boost::iequals(propertyIt->first, "filter")) { + if (boost::iequals(propertyIt->first, "checker")) { + break; + } + NDN_THROW(Error("Expecting in rule: " + ruleId)); + } + + rule->addFilter(Filter::create(propertyIt->second, configFilename)); + } + + // Get rule.checker(s) + bool hasCheckers = false; + for (; propertyIt != configSection.end(); propertyIt++) { + if (!boost::iequals(propertyIt->first, "checker")) { + NDN_THROW(Error("Expecting in rule: " + ruleId)); + } + + rule->addChecker(Checker::create(propertyIt->second, configFilename)); + hasCheckers = true; + } + + if (propertyIt != configSection.end()) { + NDN_THROW(Error("Expecting end of : " + ruleId)); + } + + if (!hasCheckers) { + NDN_THROW(Error("No is specified in rule: " + ruleId)); + } + + return rule; +} + +} // namespace validator_config +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/validator-config/rule.hpp b/ndn-cxx/security/v2/validator-config/rule.hpp new file mode 100644 index 000000000..53dc81cc6 --- /dev/null +++ b/ndn-cxx/security/v2/validator-config/rule.hpp @@ -0,0 +1,113 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_VALIDATOR_CONFIG_RULE_HPP +#define NDN_SECURITY_V2_VALIDATOR_CONFIG_RULE_HPP + +#include "ndn-cxx/security/v2/validator-config/checker.hpp" +#include "ndn-cxx/security/v2/validator-config/filter.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +class ValidationState; + +namespace validator_config { + +class Rule : noncopyable +{ +public: + Rule(const std::string& id, uint32_t pktType); + + const std::string& + getId() const + { + return m_id; + } + + uint32_t + getPktType() const + { + return m_pktType; + } + + void + addFilter(unique_ptr filter); + + void + addChecker(unique_ptr checker); + + /** + * @brief check if the packet name matches rule's filter + * + * If no filters were added, the rule matches everything. + * + * @param pktType tlv::Interest or tlv::Data + * @param pktName packet name, for signed Interests the last two components are not removed + * @retval true If at least one filter matches @p pktName + * @retval false If none of the filters match @p pktName + * + * @throw Error the supplied pktType doesn't match one for which the rule is designed + */ + bool + match(uint32_t pktType, const Name& pktName) const; + + /** + * @brief check if packet satisfies rule's condition + * + * @param pktType tlv::Interest or tlv::Data + * @param pktName packet name, for signed Interests the last two components are not removed + * @param klName KeyLocator name + * @param state Validation state + * + * @retval false packet violates at least one checker. Will call state::fail() with proper code and message. + * @retval true packet satisfies all checkers, further validation is needed + * + * @throw Error the supplied pktType doesn't match one for which the rule is designed + */ + bool + check(uint32_t pktType, const Name& pktName, const Name& klName, const shared_ptr& state) const; + +public: + /** + * @brief create a rule from configuration section + * + * @param configSection The section containing the definition of checker. + * @param configFilename The configuration file name. + * @return a rule created from configuration + */ + static unique_ptr + create(const ConfigSection& configSection, const std::string& configFilename); + +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: + std::string m_id; + uint32_t m_pktType; + std::vector> m_filters; + std::vector> m_checkers; +}; + +} // namespace validator_config +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_VALIDATOR_CONFIG_RULE_HPP diff --git a/ndn-cxx/security/v2/validator.cpp b/ndn-cxx/security/v2/validator.cpp new file mode 100644 index 000000000..1219f4c0f --- /dev/null +++ b/ndn-cxx/security/v2/validator.cpp @@ -0,0 +1,217 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validator.hpp" + +#include "ndn-cxx/face.hpp" +#include "ndn-cxx/security/transform/public-key.hpp" +#include "ndn-cxx/util/logger.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +NDN_LOG_INIT(ndn.security.v2.Validator); + +#define NDN_LOG_DEBUG_DEPTH(x) NDN_LOG_DEBUG(std::string(state->getDepth() + 1, '>') << " " << x) +#define NDN_LOG_TRACE_DEPTH(x) NDN_LOG_TRACE(std::string(state->getDepth() + 1, '>') << " " << x) + +Validator::Validator(unique_ptr policy, unique_ptr certFetcher) + : m_policy(std::move(policy)) + , m_certFetcher(std::move(certFetcher)) + , m_maxDepth(25) +{ + BOOST_ASSERT(m_policy != nullptr); + BOOST_ASSERT(m_certFetcher != nullptr); + m_policy->setValidator(*this); + m_certFetcher->setCertificateStorage(*this); +} + +Validator::~Validator() = default; + +ValidationPolicy& +Validator::getPolicy() +{ + return *m_policy; +} + +CertificateFetcher& +Validator::getFetcher() +{ + return *m_certFetcher; +} + +void +Validator::setMaxDepth(size_t depth) +{ + m_maxDepth = depth; +} + +size_t +Validator::getMaxDepth() const +{ + return m_maxDepth; +} + +void +Validator::validate(const Data& data, + const DataValidationSuccessCallback& successCb, + const DataValidationFailureCallback& failureCb) +{ + auto state = make_shared(data, successCb, failureCb); + NDN_LOG_DEBUG_DEPTH("Start validating data " << data.getName()); + + m_policy->checkPolicy(data, state, + [this] (const shared_ptr& certRequest, const shared_ptr& state) { + if (certRequest == nullptr) { + state->bypassValidation(); + } + else { + // need to fetch key and validate it + requestCertificate(certRequest, state); + } + }); +} + +void +Validator::validate(const Interest& interest, + const InterestValidationSuccessCallback& successCb, + const InterestValidationFailureCallback& failureCb) +{ + auto state = make_shared(interest, successCb, failureCb); + NDN_LOG_DEBUG_DEPTH("Start validating interest " << interest.getName()); + + m_policy->checkPolicy(interest, state, + [this] (const shared_ptr& certRequest, const shared_ptr& state) { + if (certRequest == nullptr) { + state->bypassValidation(); + } + else { + // need to fetch key and validate it + requestCertificate(certRequest, state); + } + }); +} + +void +Validator::validate(const Certificate& cert, const shared_ptr& state) +{ + NDN_LOG_DEBUG_DEPTH("Start validating certificate " << cert.getName()); + + if (!cert.isValid()) { + return state->fail({ValidationError::Code::EXPIRED_CERT, "Retrieved certificate is not yet valid or expired " + "`" + cert.getName().toUri() + "`"}); + } + + m_policy->checkPolicy(cert, state, + [this, cert] (const shared_ptr& certRequest, const shared_ptr& state) { + if (certRequest == nullptr) { + state->fail({ValidationError::POLICY_ERROR, "Validation policy is not allowed to designate `" + + cert.getName().toUri() + "` as a trust anchor"}); + } + else { + // need to fetch key and validate it + state->addCertificate(cert); + requestCertificate(certRequest, state); + } + }); +} + +void +Validator::requestCertificate(const shared_ptr& certRequest, + const shared_ptr& state) +{ + // TODO configurable check for the maximum number of steps + if (state->getDepth() >= m_maxDepth) { + state->fail({ValidationError::Code::EXCEEDED_DEPTH_LIMIT, + "Exceeded validation depth limit (" + to_string(m_maxDepth) + ")"}); + return; + } + + if (state->hasSeenCertificateName(certRequest->interest.getName())) { + state->fail({ValidationError::Code::LOOP_DETECTED, + "Validation loop detected for certificate `" + certRequest->interest.getName().toUri() + "`"}); + return; + } + + NDN_LOG_DEBUG_DEPTH("Retrieving " << certRequest->interest.getName()); + + auto cert = findTrustedCert(certRequest->interest); + if (cert != nullptr) { + NDN_LOG_TRACE_DEPTH("Found trusted certificate " << cert->getName()); + + cert = state->verifyCertificateChain(*cert); + if (cert != nullptr) { + state->verifyOriginalPacket(*cert); + } + for (auto trustedCert = std::make_move_iterator(state->m_certificateChain.begin()); + trustedCert != std::make_move_iterator(state->m_certificateChain.end()); + ++trustedCert) { + cacheVerifiedCertificate(*trustedCert); + } + return; + } + + m_certFetcher->fetch(certRequest, state, [this] (const Certificate& cert, const shared_ptr& state) { + validate(cert, state); + }); +} + +//////////////////////////////////////////////////////////////////////// +// Trust anchor management +//////////////////////////////////////////////////////////////////////// + +// to change visibility from protected to public + +void +Validator::loadAnchor(const std::string& groupId, Certificate&& cert) +{ + CertificateStorage::loadAnchor(groupId, std::move(cert)); +} + +void +Validator::loadAnchor(const std::string& groupId, const std::string& certfilePath, + time::nanoseconds refreshPeriod, bool isDir) +{ + CertificateStorage::loadAnchor(groupId, certfilePath, refreshPeriod, isDir); +} + +void +Validator::resetAnchors() +{ + CertificateStorage::resetAnchors(); +} + +void +Validator::cacheVerifiedCertificate(Certificate&& cert) +{ + CertificateStorage::cacheVerifiedCert(std::move(cert)); +} + +void +Validator::resetVerifiedCertificates() +{ + CertificateStorage::resetVerifiedCerts(); +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/v2/validator.hpp b/ndn-cxx/security/v2/validator.hpp new file mode 100644 index 000000000..04e0d95b3 --- /dev/null +++ b/ndn-cxx/security/v2/validator.hpp @@ -0,0 +1,189 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_V2_VALIDATOR_HPP +#define NDN_SECURITY_V2_VALIDATOR_HPP + +#include "ndn-cxx/security/v2/certificate-fetcher.hpp" +#include "ndn-cxx/security/v2/certificate-request.hpp" +#include "ndn-cxx/security/v2/certificate-storage.hpp" +#include "ndn-cxx/security/v2/validation-callback.hpp" +#include "ndn-cxx/security/v2/validation-policy.hpp" +#include "ndn-cxx/security/v2/validation-state.hpp" + +namespace ndn { + +class Face; + +namespace security { +namespace v2 { + +/** + * @brief Interface for validating data and interest packets. + * + * Every time a validation process initiated, it creates a ValidationState that exist until + * validation finishes with either success or failure. This state serves several purposes: + * - record Interest or Data packet being validated + * - record failure callback + * - record certificates in the certification chain for the Interest or Data packet being validated + * - record names of the requested certificates to detect loops in the certificate chain + * - keep track of the validation chain size (aka validation "depth") + * + * During validation, policy and/or key fetcher can augment validation state with policy- and + * fetcher-specific information using ndn::Tag's. + * + * A validator has a trust anchor cache to save static and dynamic trust anchors, a verified + * certificate cache for saving certificates that are already verified and an unverified + * certificate cache for saving prefetched but not yet verified certificates. + * + * @todo Limit the maximum time the validation process is allowed to run before declaring failure + * @todo Ability to customize maximum lifetime for trusted and untrusted certificate caches. + * Current implementation hard-codes them to be 1 hour and 5 minutes. + */ +class Validator : public CertificateStorage +{ +public: + /** + * @brief Validator constructor. + * + * @param policy Validation policy to be associated with the validator + * @param certFetcher Certificate fetcher implementation. + */ + Validator(unique_ptr policy, unique_ptr certFetcher); + + ~Validator(); + + ValidationPolicy& + getPolicy(); + + CertificateFetcher& + getFetcher(); + + /** + * @brief Set the maximum depth of the certificate chain + */ + void + setMaxDepth(size_t depth); + + /** + * @return The maximum depth of the certificate chain + */ + size_t + getMaxDepth() const; + + /** + * @brief Asynchronously validate @p data + * + * @note @p successCb and @p failureCb must not be nullptr + */ + void + validate(const Data& data, + const DataValidationSuccessCallback& successCb, + const DataValidationFailureCallback& failureCb); + + /** + * @brief Asynchronously validate @p interest + * + * @note @p successCb and @p failureCb must not be nullptr + */ + void + validate(const Interest& interest, + const InterestValidationSuccessCallback& successCb, + const InterestValidationFailureCallback& failureCb); + +public: // anchor management + /** + * @brief load static trust anchor. + * + * Static trust anchors are permanently associated with the validator and never expire. + * + * @param groupId Certificate group id. + * @param cert Certificate to load as a trust anchor. + */ + void + loadAnchor(const std::string& groupId, Certificate&& cert); + + /** + * @brief load dynamic trust anchors. + * + * Dynamic trust anchors are associated with the validator for as long as the underlying + * trust anchor file (set of files) exist(s). + * + * @param groupId Certificate group id, must not be empty. + * @param certfilePath Specifies the path to load the trust anchors. + * @param refreshPeriod Refresh period for the trust anchors, must be positive. + * @param isDir Tells whether the path is a directory or a single file. + */ + void + loadAnchor(const std::string& groupId, const std::string& certfilePath, + time::nanoseconds refreshPeriod, bool isDir = false); + + /** + * @brief remove any previously loaded static or dynamic trust anchor + */ + void + resetAnchors(); + + /** + * @brief Cache verified @p cert a period of time (1 hour) + * + * @todo Add ability to customize time period + */ + void + cacheVerifiedCertificate(Certificate&& cert); + + /** + * @brief Remove any cached verified certificates + */ + void + resetVerifiedCertificates(); + +private: // Common validator operations + /** + * @brief Recursive validation of the certificate in the certification chain + * + * @param cert The certificate to check. + * @param state The current validation state. + */ + void + validate(const Certificate& cert, const shared_ptr& state); + + /** + * @brief Request certificate for further validation. + * + * @param certRequest Certificate request. + * @param state The current validation state. + */ + void + requestCertificate(const shared_ptr& certRequest, + const shared_ptr& state); + +private: + unique_ptr m_policy; + unique_ptr m_certFetcher; + size_t m_maxDepth; +}; + +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_V2_VALIDATOR_HPP diff --git a/ndn-cxx/security/validator-config.cpp b/ndn-cxx/security/validator-config.cpp new file mode 100644 index 000000000..25e46ebe3 --- /dev/null +++ b/ndn-cxx/security/validator-config.cpp @@ -0,0 +1,67 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/validator-config.hpp" +#include "ndn-cxx/security/v2/certificate-fetcher-from-network.hpp" + +namespace ndn { +namespace security { + +ValidatorConfig::ValidatorConfig(std::unique_ptr fetcher, const Options& options) + : v2::Validator(make_unique(make_unique(), + options), + std::move(fetcher)) + , m_policyConfig(static_cast(getPolicy().getInnerPolicy())) +{ +} + +ValidatorConfig::ValidatorConfig(Face& face, const Options& options) + : ValidatorConfig(make_unique(face), options) +{ +} + +void +ValidatorConfig::load(const std::string& filename) +{ + m_policyConfig.load(filename); +} + +void +ValidatorConfig::load(const std::string& input, const std::string& filename) +{ + m_policyConfig.load(input, filename); +} + +void +ValidatorConfig::load(std::istream& input, const std::string& filename) +{ + m_policyConfig.load(input, filename); +} + +void +ValidatorConfig::load(const v2::validator_config::ConfigSection& configSection, + const std::string& filename) +{ + m_policyConfig.load(configSection, filename); +} + +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/validator-config.hpp b/ndn-cxx/security/validator-config.hpp new file mode 100644 index 000000000..c3d158654 --- /dev/null +++ b/ndn-cxx/security/validator-config.hpp @@ -0,0 +1,71 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_VALIDATOR_CONFIG_HPP +#define NDN_SECURITY_VALIDATOR_CONFIG_HPP + +#include "ndn-cxx/security/v2/validator.hpp" +#include "ndn-cxx/security/v2/validation-policy-command-interest.hpp" +#include "ndn-cxx/security/v2/validation-policy-config.hpp" + +namespace ndn { +namespace security { + +/** + * @brief Helper for validator that uses CommandInterest + Config policy and NetworkFetcher + */ +class ValidatorConfig : public v2::Validator +{ +public: + using v2::Validator::Validator; + using Options = v2::ValidationPolicyCommandInterest::Options; + + explicit + ValidatorConfig(std::unique_ptr fetcher, const Options& options = Options()); + + explicit + ValidatorConfig(Face& face, const Options& options = Options()); + +public: // helpers for ValidationPolicyConfig + void + load(const std::string& filename); + + void + load(const std::string& input, const std::string& filename); + + void + load(std::istream& input, const std::string& filename); + + void + load(const v2::validator_config::ConfigSection& configSection, + const std::string& filename); + +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: + v2::ValidationPolicyConfig& m_policyConfig; +}; + +} // namespace security + +using security::ValidatorConfig; + +} // namespace ndn + +#endif // NDN_SECURITY_VALIDATOR_CONFIG_HPP diff --git a/ndn-cxx/security/validator-null.cpp b/ndn-cxx/security/validator-null.cpp new file mode 100644 index 000000000..4299d8250 --- /dev/null +++ b/ndn-cxx/security/validator-null.cpp @@ -0,0 +1,44 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/validator-null.hpp" +#include "ndn-cxx/security/v2/validation-policy-accept-all.hpp" +#include "ndn-cxx/security/v2/certificate-fetcher-offline.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +ValidatorNull::ValidatorNull() + : Validator(make_unique(), make_unique()) +{ +} + +security::v2::Validator& +getAcceptAllValidator() +{ + static security::ValidatorNull validator; + return validator; +} + +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/validator-null.hpp b/ndn-cxx/security/validator-null.hpp new file mode 100644 index 000000000..7ed55e8e1 --- /dev/null +++ b/ndn-cxx/security/validator-null.hpp @@ -0,0 +1,51 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_VALIDATOR_NULL_HPP +#define NDN_SECURITY_VALIDATOR_NULL_HPP + +#include "ndn-cxx/security/v2/validator.hpp" + +namespace ndn { +namespace security { +namespace v2 { + +/** + * @brief Validator with "accept-all" policy and offline certificate fetcher + */ +class ValidatorNull : public Validator +{ +public: + ValidatorNull(); +}; + +security::v2::Validator& +getAcceptAllValidator(); + +} // namespace v2 + +using v2::ValidatorNull; +using v2::getAcceptAllValidator; + +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_VALIDATOR_NULL_HPP diff --git a/src/security/validity-period.cpp b/ndn-cxx/security/validity-period.cpp similarity index 80% rename from src/security/validity-period.cpp rename to ndn-cxx/security/validity-period.cpp index c6f602651..554d2c1fc 100644 --- a/src/security/validity-period.cpp +++ b/ndn-cxx/security/validity-period.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,9 +19,9 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "validity-period.hpp" -#include "../encoding/block-helpers.hpp" -#include "../util/concepts.hpp" +#include "ndn-cxx/security/validity-period.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/util/concepts.hpp" namespace ndn { namespace security { @@ -39,6 +39,12 @@ static const size_t NOT_AFTER_OFFSET = 1; using boost::chrono::time_point_cast; +ValidityPeriod::ValidityPeriod() + : ValidityPeriod(time::system_clock::TimePoint() + 1_ns, + time::system_clock::TimePoint()) +{ +} + ValidityPeriod::ValidityPeriod(const time::system_clock::TimePoint& notBefore, const time::system_clock::TimePoint& notAfter) : m_notBefore(time_point_cast(notBefore + TimePoint::duration(1) - @@ -66,11 +72,7 @@ ValidityPeriod::wireEncode(EncodingImpl& encoder) const return totalLength; } -template size_t -ValidityPeriod::wireEncode(EncodingImpl& encoder) const; - -template size_t -ValidityPeriod::wireEncode(EncodingImpl& encoder) const; +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(ValidityPeriod); const Block& ValidityPeriod::wireEncode() const @@ -94,23 +96,23 @@ void ValidityPeriod::wireDecode(const Block& wire) { if (!wire.hasWire()) { - BOOST_THROW_EXCEPTION(Error("The supplied block does not contain wire format")); + NDN_THROW(Error("The supplied block does not contain wire format")); } m_wire = wire; m_wire.parse(); if (m_wire.type() != tlv::ValidityPeriod) - BOOST_THROW_EXCEPTION(Error("Unexpected TLV type when decoding ValidityPeriod")); + NDN_THROW(Error("ValidityPeriod", m_wire.type())); if (m_wire.elements_size() != 2) - BOOST_THROW_EXCEPTION(Error("Does not have two sub-TLVs")); + NDN_THROW(Error("ValidityPeriod does not have two sub-TLVs")); if (m_wire.elements()[NOT_BEFORE_OFFSET].type() != tlv::NotBefore || m_wire.elements()[NOT_BEFORE_OFFSET].value_size() != ISO_DATETIME_SIZE || m_wire.elements()[NOT_AFTER_OFFSET].type() != tlv::NotAfter || m_wire.elements()[NOT_AFTER_OFFSET].value_size() != ISO_DATETIME_SIZE) { - BOOST_THROW_EXCEPTION(Error("Invalid NotBefore or NotAfter field")); + NDN_THROW(Error("Invalid NotBefore or NotAfter field")); } try { @@ -120,7 +122,7 @@ ValidityPeriod::wireDecode(const Block& wire) time::fromIsoString(readString(m_wire.elements()[NOT_AFTER_OFFSET]))); } catch (const std::bad_cast&) { - BOOST_THROW_EXCEPTION(Error("Invalid date format in NOT-BEFORE or NOT-AFTER field")); + NDN_THROW(Error("Invalid date format in NOT-BEFORE or NOT-AFTER field")); } } @@ -144,20 +146,7 @@ ValidityPeriod::getPeriod() const bool ValidityPeriod::isValid(const time::system_clock::TimePoint& now) const { - return m_notBefore < now && now < m_notAfter; -} - -bool -ValidityPeriod::operator==(const ValidityPeriod& other) const -{ - return (this->m_notBefore == other.m_notBefore && - this->m_notAfter == other.m_notAfter); -} - -bool -ValidityPeriod::operator!=(const ValidityPeriod& other) const -{ - return !(*this == other); + return m_notBefore <= now && now <= m_notAfter; } std::ostream& diff --git a/src/security/validity-period.hpp b/ndn-cxx/security/validity-period.hpp similarity index 75% rename from src/security/validity-period.hpp rename to ndn-cxx/security/validity-period.hpp index ab24d6814..7249ade3b 100644 --- a/src/security/validity-period.hpp +++ b/ndn-cxx/security/validity-period.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,17 +22,17 @@ #ifndef NDN_SECURITY_VALIDITY_PERIOD_HPP #define NDN_SECURITY_VALIDITY_PERIOD_HPP -#include "../common.hpp" -#include "../encoding/tlv.hpp" -#include "../encoding/block.hpp" -#include "../util/time.hpp" +#include "ndn-cxx/detail/common.hpp" +#include "ndn-cxx/encoding/tlv.hpp" +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/util/time.hpp" namespace ndn { namespace security { /** @brief Abstraction of validity period - * @sa docs/tutorials/certificate-format.rst + * @sa docs/specs/certificate-format.rst */ class ValidityPeriod { @@ -40,24 +40,20 @@ class ValidityPeriod class Error : public tlv::Error { public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } + using tlv::Error::Error; }; public: - /** @brief Set validity period (UNIX epoch, UNIX epoch) that is always invalid + /** @brief Set validity period [UNIX epoch + 1 nanosecond, UNIX epoch] that is always invalid */ - ValidityPeriod() = default; + ValidityPeriod(); /** @brief Create validity period from @p block */ explicit ValidityPeriod(const Block& block); - /** @brief Create validity period (@p notBefore, @p notAfter) + /** @brief Create validity period [@p notBefore, @p notAfter] * @param notBefore exclusive beginning of the validity period range * @param notAfter exclusive end of the validity period range * @@ -70,12 +66,12 @@ class ValidityPeriod /** @brief Check if @p now falls within the validity period * @param now Time point to check if it falls within the period - * @return periodBegin < @p now and @p now < periodEnd + * @return periodBegin <= @p now and @p now <= periodEnd */ bool isValid(const time::system_clock::TimePoint& now = time::system_clock::now()) const; - /** @brief Set validity period (@p notBefore, @p notAfter) + /** @brief Set validity period [@p notBefore, @p notAfter] * @param notBefore exclusive beginning of the validity period range * @param notAfter exclusive end of the validity period range * @@ -109,12 +105,22 @@ class ValidityPeriod void wireDecode(const Block& wire); -public: // EqualityComparable concept - bool - operator==(const ValidityPeriod& other) const; +private: // EqualityComparable concept + // NOTE: the following "hidden friend" operators are available via + // argument-dependent lookup only and must be defined inline. - bool - operator!=(const ValidityPeriod& other) const; + friend bool + operator==(const ValidityPeriod& lhs, const ValidityPeriod& rhs) + { + return !(lhs != rhs); + } + + friend bool + operator!=(const ValidityPeriod& lhs, const ValidityPeriod& rhs) + { + return lhs.m_notBefore != rhs.m_notBefore || + lhs.m_notAfter != rhs.m_notAfter; + } private: typedef boost::chrono::time_point TimePoint; @@ -125,6 +131,8 @@ class ValidityPeriod mutable Block m_wire; }; +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(ValidityPeriod); + std::ostream& operator<<(std::ostream& os, const ValidityPeriod& period); diff --git a/ndn-cxx/security/verification-helpers.cpp b/ndn-cxx/security/verification-helpers.cpp new file mode 100644 index 000000000..cbca64f63 --- /dev/null +++ b/ndn-cxx/security/verification-helpers.cpp @@ -0,0 +1,247 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/verification-helpers.hpp" + +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/impl/openssl.hpp" +#include "ndn-cxx/security/pib/key.hpp" +#include "ndn-cxx/security/tpm/key-handle.hpp" +#include "ndn-cxx/security/tpm/tpm.hpp" +#include "ndn-cxx/security/transform/bool-sink.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/digest-filter.hpp" +#include "ndn-cxx/security/transform/public-key.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" +#include "ndn-cxx/security/transform/verifier-filter.hpp" +#include "ndn-cxx/security/v2/certificate.hpp" + +namespace ndn { +namespace security { + +namespace { + +struct ParseResult +{ + bool isParsable = false; + const uint8_t* buf = nullptr; + size_t bufLen = 0; + const uint8_t* sig = nullptr; + size_t sigLen = 0; +}; + +} // namespace + +bool +verifySignature(const uint8_t* blob, size_t blobLen, const uint8_t* sig, size_t sigLen, + const transform::PublicKey& key) +{ + bool result = false; + try { + using namespace transform; + bufferSource(blob, blobLen) >> verifierFilter(DigestAlgorithm::SHA256, key, sig, sigLen) + >> boolSink(result); + } + catch (const transform::Error&) { + return false; + } + return result; +} + +bool +verifySignature(const uint8_t* data, size_t dataLen, const uint8_t* sig, size_t sigLen, + const uint8_t* key, size_t keyLen) +{ + transform::PublicKey pKey; + try { + pKey.loadPkcs8(key, keyLen); + } + catch (const transform::Error&) { + return false; + } + + return verifySignature(data, dataLen, sig, sigLen, pKey); +} + +static ParseResult +parse(const Data& data) +{ + try { + return {true, + data.wireEncode().value(), + data.wireEncode().value_size() - data.getSignature().getValue().size(), + data.getSignature().getValue().value(), + data.getSignature().getValue().value_size()}; + } + catch (const tlv::Error&) { + return ParseResult(); + } +} + +static ParseResult +parse(const Interest& interest) +{ + const Name& interestName = interest.getName(); + + if (interestName.size() < signed_interest::MIN_SIZE) + return ParseResult(); + + try { + const Block& nameBlock = interestName.wireEncode(); + return {true, + nameBlock.value(), + nameBlock.value_size() - interestName[signed_interest::POS_SIG_VALUE].size(), + interestName[signed_interest::POS_SIG_VALUE].blockFromValue().value(), + interestName[signed_interest::POS_SIG_VALUE].blockFromValue().value_size()}; + } + catch (const tlv::Error&) { + return ParseResult(); + } +} + +static bool +verifySignature(ParseResult params, const transform::PublicKey& key) +{ + return params.isParsable && verifySignature(params.buf, params.bufLen, + params.sig, params.sigLen, key); +} + +static bool +verifySignature(ParseResult params, const tpm::Tpm& tpm, const Name& keyName, + DigestAlgorithm digestAlgorithm) +{ + return params.isParsable && bool(tpm.verify(params.buf, params.bufLen, + params.sig, params.sigLen, keyName, digestAlgorithm)); +} + +static bool +verifySignature(ParseResult params, const uint8_t* key, size_t keyLen) +{ + return params.isParsable && verifySignature(params.buf, params.bufLen, + params.sig, params.sigLen, key, keyLen); +} + +bool +verifySignature(const Data& data, const transform::PublicKey& key) +{ + return verifySignature(parse(data), key); +} + +bool +verifySignature(const Interest& interest, const transform::PublicKey& key) +{ + return verifySignature(parse(interest), key); +} + +bool +verifySignature(const Data& data, const pib::Key& key) +{ + return verifySignature(parse(data), key.getPublicKey().data(), key.getPublicKey().size()); +} + +bool +verifySignature(const Interest& interest, const pib::Key& key) +{ + return verifySignature(parse(interest), key.getPublicKey().data(), key.getPublicKey().size()); +} + +bool +verifySignature(const Data& data, const uint8_t* key, size_t keyLen) +{ + return verifySignature(parse(data), key, keyLen); +} + +bool +verifySignature(const Interest& interest, const uint8_t* key, size_t keyLen) +{ + return verifySignature(parse(interest), key, keyLen); +} + +bool +verifySignature(const Data& data, const v2::Certificate& cert) +{ + return verifySignature(parse(data), cert.getContent().value(), cert.getContent().value_size()); +} + +bool +verifySignature(const Interest& interest, const v2::Certificate& cert) +{ + return verifySignature(parse(interest), cert.getContent().value(), cert.getContent().value_size()); +} + +bool +verifySignature(const Data& data, const tpm::Tpm& tpm, + const Name& keyName, DigestAlgorithm digestAlgorithm) +{ + return verifySignature(parse(data), tpm, keyName, digestAlgorithm); +} + +bool +verifySignature(const Interest& interest, const tpm::Tpm& tpm, + const Name& keyName, DigestAlgorithm digestAlgorithm) +{ + return verifySignature(parse(interest), tpm, keyName, digestAlgorithm); +} + +/////////////////////////////////////////////////////////////////////// + +bool +verifyDigest(const uint8_t* blob, size_t blobLen, const uint8_t* digest, size_t digestLen, + DigestAlgorithm algorithm) +{ + using namespace transform; + + OBufferStream os; + try { + bufferSource(blob, blobLen) >> digestFilter(algorithm) >> streamSink(os); + } + catch (const transform::Error&) { + return false; + } + ConstBufferPtr result = os.buf(); + + if (result->size() != digestLen) + return false; + + // constant-time buffer comparison to mitigate timing attacks + return CRYPTO_memcmp(result->data(), digest, digestLen) == 0; +} + +bool +verifyDigest(const Data& data, DigestAlgorithm algorithm) +{ + ParseResult parseResult = parse(data); + return parseResult.isParsable && verifyDigest(parseResult.buf, parseResult.bufLen, + parseResult.sig, parseResult.sigLen, algorithm); +} + +bool +verifyDigest(const Interest& interest, DigestAlgorithm algorithm) +{ + ParseResult parseResult = parse(interest); + return parseResult.isParsable && verifyDigest(parseResult.buf, parseResult.bufLen, + parseResult.sig, parseResult.sigLen, algorithm); +} + +} // namespace security +} // namespace ndn diff --git a/ndn-cxx/security/verification-helpers.hpp b/ndn-cxx/security/verification-helpers.hpp new file mode 100644 index 000000000..3399821cc --- /dev/null +++ b/ndn-cxx/security/verification-helpers.hpp @@ -0,0 +1,166 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SECURITY_VERIFICATION_HELPERS_HPP +#define NDN_SECURITY_VERIFICATION_HELPERS_HPP + +#include "ndn-cxx/name.hpp" +#include "ndn-cxx/security/security-common.hpp" + +namespace ndn { + +class Interest; +class Data; + +namespace security { + +namespace pib { +class Key; +} // namespace pib + +namespace tpm { +class Tpm; +} // namespace tpm + +namespace transform { +class PublicKey; +} // namespace transform + +namespace v2 { +class Certificate; +} // namespace v2 + +/** + * @brief Verify @p blob using @p key against @p sig. + */ +bool +verifySignature(const uint8_t* blob, size_t blobLen, const uint8_t* sig, size_t sigLen, + const transform::PublicKey& key); + +/** + * @brief Verify @p blob using @p key against @p sig. + * @note @p key must be a public key in PKCS #8 format. + */ +bool +verifySignature(const uint8_t* blob, size_t blobLen, const uint8_t* sig, size_t sigLen, + const uint8_t* key, size_t keyLen); + +/** + * @brief Verify @p data using @p key. + * @note @p key must be a public key in PKCS #8 format. + */ +bool +verifySignature(const Data& data, const uint8_t* key, size_t keyLen); + +/** + * @brief Verify @p interest using @p key. + * @note @p key must be a public key in PKCS #8 format. + * @note This method verifies only signature of the signed interest. + * @sa docs/specs/signed-interest.rst + */ +bool +verifySignature(const Interest& interest, const uint8_t* key, size_t keyLen); + +/** + * @brief Verify @p data using @p key. + */ +bool +verifySignature(const Data& data, const transform::PublicKey& key); + +/** + * @brief Verify @p interest using @p key. + * @note This method verifies only signature of the signed interest. + * @sa docs/specs/signed-interest.rst + */ +bool +verifySignature(const Interest& interest, const transform::PublicKey& key); + +/** + * @brief Verify @p data using @p key. + */ +bool +verifySignature(const Data& data, const pib::Key& key); + +/** + * @brief Verify @p interest using @p key. + * @note This method verifies only signature of the signed interest. + * @sa docs/specs/signed-interest.rst + */ +bool +verifySignature(const Interest& interest, const pib::Key& key); + +/** + * @brief Verify @p data using @p cert. + */ +bool +verifySignature(const Data& data, const v2::Certificate& cert); + +/** + * @brief Verify @p interest using @p cert. + * @note This method verifies only signature of the signed interest. + * @sa docs/specs/signed-interest.rst + */ +bool +verifySignature(const Interest& interest, const v2::Certificate& cert); + +/** + * @brief Verify @p data using @p tpm and @p keyName with the @p digestAlgorithm. + */ +bool +verifySignature(const Data& data, const tpm::Tpm& tpm, const Name& keyName, + DigestAlgorithm digestAlgorithm); + +/** + * @brief Verify @p interest using @p tpm and @p keyName with the @p digestAlgorithm. + * @note This method verifies only signature of the signed interest. + * @sa docs/specs/signed-interest.rst + */ +bool +verifySignature(const Interest& interest, const tpm::Tpm& tpm, const Name& keyName, + DigestAlgorithm digestAlgorithm); + +////////////////////////////////////////////////////////////////// + +/** + * @brief Verify @p blob against @p digest using @p algorithm. + */ +bool +verifyDigest(const uint8_t* blob, size_t blobLen, const uint8_t* digest, size_t digestLen, + DigestAlgorithm algorithm); + +/** + * @brief Verify @p data against digest @p algorithm. + */ +bool +verifyDigest(const Data& data, DigestAlgorithm algorithm); + +/** + * @brief Verify @p interest against digest @p algorithm. + * @note This method verifies only signature of the signed interest. + * @sa docs/specs/signed-interest.rst + */ +bool +verifyDigest(const Interest& interest, DigestAlgorithm algorithm); + +} // namespace security +} // namespace ndn + +#endif // NDN_SECURITY_VERIFICATION_HELPERS_HPP diff --git a/ndn-cxx/signature-info.cpp b/ndn-cxx/signature-info.cpp new file mode 100644 index 000000000..41f1cb2df --- /dev/null +++ b/ndn-cxx/signature-info.cpp @@ -0,0 +1,250 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/signature-info.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/util/concepts.hpp" + +namespace ndn { + +BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); +BOOST_CONCEPT_ASSERT((WireEncodable)); +BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); +BOOST_CONCEPT_ASSERT((WireDecodable)); +static_assert(std::is_base_of::value, + "SignatureInfo::Error must inherit from tlv::Error"); + +SignatureInfo::SignatureInfo() + : m_type(-1) + , m_hasKeyLocator(false) +{ +} + +SignatureInfo::SignatureInfo(tlv::SignatureTypeValue type) + : m_type(type) + , m_hasKeyLocator(false) +{ +} + +SignatureInfo::SignatureInfo(tlv::SignatureTypeValue type, const KeyLocator& keyLocator) + : m_type(type) + , m_hasKeyLocator(true) + , m_keyLocator(keyLocator) +{ +} + +SignatureInfo::SignatureInfo(const Block& block) +{ + wireDecode(block); +} + +template +size_t +SignatureInfo::wireEncode(EncodingImpl& encoder) const +{ + if (m_type == -1) { + NDN_THROW(Error("Cannot encode invalid SignatureInfo")); + } + + // SignatureInfo ::= SIGNATURE-INFO-TLV TLV-LENGTH + // SignatureType + // KeyLocator? + // ValidityPeriod? (if present, stored as first item of m_otherTlvs) + // other SignatureType-specific sub-elements* + + size_t totalLength = 0; + + for (auto i = m_otherTlvs.rbegin(); i != m_otherTlvs.rend(); i++) { + totalLength += encoder.prependBlock(*i); + } + + if (m_hasKeyLocator) + totalLength += m_keyLocator.wireEncode(encoder); + + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::SignatureType, + static_cast(m_type)); + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::SignatureInfo); + + return totalLength; +} + +NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(SignatureInfo); + +const Block& +SignatureInfo::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 +SignatureInfo::wireDecode(const Block& wire) +{ + m_type = -1; + m_hasKeyLocator = false; + m_otherTlvs.clear(); + + m_wire = wire; + m_wire.parse(); + + if (m_wire.type() != tlv::SignatureInfo) + NDN_THROW(Error("SignatureInfo", m_wire.type())); + + auto it = m_wire.elements_begin(); + + // the first sub-element must be SignatureType + if (it == m_wire.elements_end() || it->type() != tlv::SignatureType) + NDN_THROW(Error("Missing SignatureType in SignatureInfo")); + + m_type = readNonNegativeIntegerAs(*it); + ++it; + + // the second sub-element could be KeyLocator + if (it != m_wire.elements_end() && it->type() == tlv::KeyLocator) { + m_keyLocator.wireDecode(*it); + m_hasKeyLocator = true; + ++it; + } + + // store SignatureType-specific sub-elements, if any + while (it != m_wire.elements_end()) { + m_otherTlvs.push_back(*it); + ++it; + } +} + +void +SignatureInfo::setSignatureType(tlv::SignatureTypeValue type) +{ + m_wire.reset(); + m_type = type; +} + +const KeyLocator& +SignatureInfo::getKeyLocator() const +{ + if (m_hasKeyLocator) + return m_keyLocator; + else + NDN_THROW(Error("KeyLocator does not exist in SignatureInfo")); +} + +void +SignatureInfo::setKeyLocator(const KeyLocator& keyLocator) +{ + m_wire.reset(); + m_keyLocator = keyLocator; + m_hasKeyLocator = true; +} + +void +SignatureInfo::unsetKeyLocator() +{ + m_wire.reset(); + m_keyLocator = KeyLocator(); + m_hasKeyLocator = false; +} + +security::ValidityPeriod +SignatureInfo::getValidityPeriod() const +{ + if (m_otherTlvs.empty() || m_otherTlvs.front().type() != tlv::ValidityPeriod) { + NDN_THROW(Error("ValidityPeriod does not exist in SignatureInfo")); + } + + return security::ValidityPeriod(m_otherTlvs.front()); +} + +void +SignatureInfo::setValidityPeriod(const security::ValidityPeriod& validityPeriod) +{ + unsetValidityPeriod(); + m_otherTlvs.push_front(validityPeriod.wireEncode()); +} + +void +SignatureInfo::unsetValidityPeriod() +{ + if (!m_otherTlvs.empty() && m_otherTlvs.front().type() == tlv::ValidityPeriod) { + m_otherTlvs.pop_front(); + m_wire.reset(); + } +} + +const Block& +SignatureInfo::getTypeSpecificTlv(uint32_t type) const +{ + for (const Block& block : m_otherTlvs) { + if (block.type() == type) + return block; + } + + NDN_THROW(Error("TLV-TYPE " + to_string(type) + " sub-element does not exist in SignatureInfo")); +} + +void +SignatureInfo::appendTypeSpecificTlv(const Block& block) +{ + m_wire.reset(); + m_otherTlvs.push_back(block); +} + +bool +operator==(const SignatureInfo& lhs, const SignatureInfo& rhs) +{ + return lhs.m_type == rhs.m_type && + lhs.m_hasKeyLocator == rhs.m_hasKeyLocator && + lhs.m_keyLocator == rhs.m_keyLocator && + lhs.m_otherTlvs == rhs.m_otherTlvs; +} + +std::ostream& +operator<<(std::ostream& os, const SignatureInfo& info) +{ + if (info.getSignatureType() == -1) + return os << "Invalid SignatureInfo"; + + os << static_cast(info.getSignatureType()); + if (info.hasKeyLocator()) { + os << " " << info.getKeyLocator(); + } + if (!info.m_otherTlvs.empty()) { + os << " { "; + for (const auto& block : info.m_otherTlvs) { + os << block.type() << " "; + } + os << "}"; + } + + return os; +} + +} // namespace ndn diff --git a/ndn-cxx/signature-info.hpp b/ndn-cxx/signature-info.hpp new file mode 100644 index 000000000..7cfc24882 --- /dev/null +++ b/ndn-cxx/signature-info.hpp @@ -0,0 +1,178 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SIGNATURE_INFO_HPP +#define NDN_SIGNATURE_INFO_HPP + +#include "ndn-cxx/key-locator.hpp" +#include "ndn-cxx/security/validity-period.hpp" + +#include + +namespace ndn { + +/** @brief Represents a SignatureInfo TLV element + */ +class SignatureInfo +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + /** @brief Create an invalid SignatureInfo + */ + SignatureInfo(); + + /** @brief Create with specified type + */ + explicit + SignatureInfo(tlv::SignatureTypeValue type); + + /** @brief Create with specified type and KeyLocator + */ + SignatureInfo(tlv::SignatureTypeValue type, const KeyLocator& keyLocator); + + /** @brief Create from wire encoding + * @throw tlv::Error decode error + */ + explicit + SignatureInfo(const Block& wire); + + /** @brief Fast encoding or block size estimation + * @param encoder EncodingEstimator or EncodingBuffer instance + */ + template + size_t + wireEncode(EncodingImpl& encoder) const; + + /** @brief Encode to wire format + */ + const Block& + wireEncode() const; + + /** @brief Decode from wire format + * @throw tlv::Error decode error + */ + void + wireDecode(const Block& wire); + +public: // field access + /** @brief Get SignatureType + * @return tlv::SignatureTypeValue, or -1 to indicate invalid SignatureInfo + */ + int32_t + getSignatureType() const + { + return m_type; + } + + /** @brief Set SignatureType + */ + void + setSignatureType(tlv::SignatureTypeValue type); + + /** @brief Check if KeyLocator exists + */ + bool + hasKeyLocator() const + { + return m_hasKeyLocator; + } + + /** @brief Get KeyLocator + * @throw Error KeyLocator does not exist + */ + const KeyLocator& + getKeyLocator() const; + + /** @brief Set KeyLocator + */ + void + setKeyLocator(const KeyLocator& keyLocator); + + /** @brief Unset KeyLocator + */ + void + unsetKeyLocator(); + + /** @brief Get ValidityPeriod + * @throw Error ValidityPeriod does not exist + */ + security::ValidityPeriod + getValidityPeriod() const; + + /** @brief Set ValidityPeriod + */ + void + setValidityPeriod(const security::ValidityPeriod& validityPeriod); + + /** @brief Unset ValidityPeriod + */ + void + unsetValidityPeriod(); + + /** @brief Get SignatureType-specific sub-element + * @param type TLV-TYPE of sub-element + * @throw Error sub-element of specified type does not exist + */ + const Block& + getTypeSpecificTlv(uint32_t type) const; + + /** @brief Append SignatureType-specific sub-element + */ + void + appendTypeSpecificTlv(const Block& element); + +private: + int32_t m_type; + bool m_hasKeyLocator; + KeyLocator m_keyLocator; + std::list m_otherTlvs; + + mutable Block m_wire; + + friend bool + operator==(const SignatureInfo& lhs, const SignatureInfo& rhs); + + friend std::ostream& + operator<<(std::ostream& os, const SignatureInfo& info); +}; + +NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(SignatureInfo); + +bool +operator==(const SignatureInfo& lhs, const SignatureInfo& rhs); + +inline bool +operator!=(const SignatureInfo& lhs, const SignatureInfo& rhs) +{ + return !(lhs == rhs); +} + +std::ostream& +operator<<(std::ostream& os, const SignatureInfo& info); + +} // namespace ndn + +#endif // NDN_SIGNATURE_INFO_HPP diff --git a/src/signature.cpp b/ndn-cxx/signature.cpp similarity index 81% rename from src/signature.cpp rename to ndn-cxx/signature.cpp index af18ec2d5..e3a07eb2c 100644 --- a/src/signature.cpp +++ b/ndn-cxx/signature.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,11 +19,10 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "signature.hpp" +#include "ndn-cxx/signature.hpp" namespace ndn { -BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); static_assert(std::is_base_of::value, "Signature::Error must inherit from tlv::Error"); @@ -40,6 +39,15 @@ Signature::Signature(const SignatureInfo& info, const Block& value) { } +tlv::SignatureTypeValue +Signature::getType() const +{ + if (!*this) { + NDN_THROW(Error("Signature is invalid")); + } + return static_cast(m_info.getSignatureType()); +} + void Signature::setInfo(const Block& info) { @@ -50,7 +58,7 @@ void Signature::setValue(const Block& value) { if (value.type() != tlv::SignatureValue) { - BOOST_THROW_EXCEPTION(Error("The supplied block is not SignatureValue")); + NDN_THROW(Error("SignatureValue", value.type())); } m_value = value; } diff --git a/ndn-cxx/signature.hpp b/ndn-cxx/signature.hpp new file mode 100644 index 000000000..1c02c60a7 --- /dev/null +++ b/ndn-cxx/signature.hpp @@ -0,0 +1,156 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_SIGNATURE_HPP +#define NDN_SIGNATURE_HPP + +#include "ndn-cxx/signature-info.hpp" + +namespace ndn { + +/** @brief Holds SignatureInfo and SignatureValue in a Data packet + * + * A Signature is not a TLV element itself. It collects SignatureInfo and SignatureValue TLV + * elements together for easy access. + * In most cases, an application should use a subclass of Signature such as @p DigestSha256 , @p + * SignatureSha256WithRsa , or @p SignatureSha256WithEcdsa instead of using @p Signature type + * directly. + */ +class Signature +{ +public: + class Error : public tlv::Error + { + public: + using tlv::Error::Error; + }; + + Signature() = default; + + explicit + Signature(const Block& info, const Block& value = Block()); + + explicit + Signature(const SignatureInfo& info, const Block& value = Block()); + + /** @brief Determine whether SignatureInfo is valid + */ + explicit + operator bool() const + { + return m_info.getSignatureType() != -1; + } + + /** @brief Get SignatureInfo + */ + const SignatureInfo& + getSignatureInfo() const + { + return m_info; + } + + /** @brief Get SignatureInfo as wire format + */ + const Block& + getInfo() const + { + return m_info.wireEncode(); + } + + /** @brief Decode SignatureInfo from wire format + * @throw tlv::Error decode error + */ + void + setInfo(const Block& info); + + /** @brief Set SignatureInfo + */ + void + setInfo(const SignatureInfo& info) + { + m_info = info; + } + + /** @brief Get SignatureValue + */ + const Block& + getValue() const + { + return m_value; + } + + /** @brief Set SignatureValue + * @throws tlv::Error TLV-TYPE of supplied block is not SignatureValue, or the block does not have TLV-VALUE + */ + void + setValue(const Block& value); + +public: // SignatureInfo fields + /** @brief Get SignatureType + * @throw Error signature is invalid + */ + tlv::SignatureTypeValue + getType() const; + + /** @brief Check if KeyLocator exists in SignatureInfo + */ + bool + hasKeyLocator() const + { + return m_info.hasKeyLocator(); + } + + /** @brief Get KeyLocator + * @throw tlv::Error KeyLocator does not exist in SignatureInfo + */ + const KeyLocator& + getKeyLocator() const + { + return m_info.getKeyLocator(); + } + + /** @brief Set KeyLocator + */ + void + setKeyLocator(const KeyLocator& keyLocator) + { + m_info.setKeyLocator(keyLocator); + } + + /** @brief Unset KeyLocator + * + * @note Subclasses of Signature may provide advisory (non-virtual) override to prevent unsetting + * KeyLocator if it is required by the specification. + */ + void + unsetKeyLocator() + { + m_info.unsetKeyLocator(); + } + +protected: + SignatureInfo m_info; + mutable Block m_value; +}; + +} // namespace ndn + +#endif // NDN_SIGNATURE_HPP diff --git a/src/tag.hpp b/ndn-cxx/tag.hpp similarity index 85% rename from src/tag.hpp rename to ndn-cxx/tag.hpp index cd364455b..1a2db36af 100644 --- a/src/tag.hpp +++ b/ndn-cxx/tag.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -34,13 +34,13 @@ class Tag ~Tag(); /** - * @fn static constexpr int getTypeId() + * @fn static constexpr int getTypeId() noexcept * @return an integer that uniquely identifies this Tag type - * @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PacketTagTypes + * @sa https://redmine.named-data.net/projects/ndn-cxx/wiki/PacketTagTypes */ #ifdef DOXYGEN static constexpr int - getTypeId() + getTypeId() noexcept { return ; } @@ -59,15 +59,15 @@ class SimpleTag : public Tag { public: static constexpr int - getTypeId() + getTypeId() noexcept { return TypeId; } /** \brief explicitly convertible from T */ - explicit - SimpleTag(const T& value) + constexpr explicit + SimpleTag(const T& value) noexcept : m_value(value) { } @@ -82,8 +82,8 @@ class SimpleTag : public Tag /** \return the enclosed value */ - const T& - get() const + constexpr const T& + get() const noexcept { return m_value; } diff --git a/ndn-cxx/transport/transport.cpp b/ndn-cxx/transport/transport.cpp new file mode 100644 index 000000000..05fa481ba --- /dev/null +++ b/ndn-cxx/transport/transport.cpp @@ -0,0 +1,39 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/transport/transport.hpp" + +namespace ndn { + +Transport::Error::Error(const boost::system::error_code& code, const std::string& msg) + : std::runtime_error(msg + (code.value() ? " (" + code.message() + ")" : "")) +{ +} + +void +Transport::connect(ReceiveCallback receiveCallback) +{ + BOOST_ASSERT(receiveCallback != nullptr); + + m_receiveCallback = std::move(receiveCallback); +} + +} // namespace ndn diff --git a/ndn-cxx/transport/transport.hpp b/ndn-cxx/transport/transport.hpp new file mode 100644 index 000000000..9154183ad --- /dev/null +++ b/ndn-cxx/transport/transport.hpp @@ -0,0 +1,119 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TRANSPORT_TRANSPORT_HPP +#define NDN_TRANSPORT_TRANSPORT_HPP + +#include "ndn-cxx/detail/asio-fwd.hpp" +#include "ndn-cxx/detail/common.hpp" +#include "ndn-cxx/encoding/block.hpp" + +#include + +namespace ndn { + +/** \brief Provides TLV-block delivery service. + */ +class Transport : noncopyable +{ +public: + class Error : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + + Error(const boost::system::error_code& code, const std::string& msg); + }; + + using ReceiveCallback = std::function; + using ErrorCallback = std::function; + + virtual + ~Transport() = default; + + /** \brief Asynchronously open the connection. + * \param receiveCallback callback function when a TLV block is received; must not be empty + * \throw boost::system::system_error connection cannot be established + */ + virtual void + connect(ReceiveCallback receiveCallback); + + /** \brief Close the connection. + */ + virtual void + close() = 0; + + /** \brief send a TLV block through the transport + */ + virtual void + send(const Block& wire) = 0; + + /** \brief send two memory blocks through the transport + * + * Scatter/gather API is utilized to send two non-consecutive memory blocks together + * (as part of the same message in datagram-oriented transports). + */ + virtual void + send(const Block& header, const Block& payload) = 0; + + /** \brief pause the transport + * \post the receive callback will not be invoked + * \note This operation has no effect if transport has been paused, + * or when connection is being established. + */ + virtual void + pause() = 0; + + /** \brief resume the transport + * \post the receive callback will be invoked + * \note This operation has no effect if transport is not paused, + * or when connection is being established. + */ + virtual void + resume() = 0; + + /** \retval true connection has been established + * \retval false connection is not yet established or has been closed + */ + bool + isConnected() const noexcept + { + return m_isConnected; + } + + /** \retval true incoming packets are expected, the receive callback will be invoked + * \retval false incoming packets are not expected, the receive callback will not be invoked + */ + bool + isReceiving() const noexcept + { + return m_isReceiving; + } + +protected: + ReceiveCallback m_receiveCallback; + bool m_isConnected = false; + bool m_isReceiving = false; +}; + +} // namespace ndn + +#endif // NDN_TRANSPORT_TRANSPORT_HPP diff --git a/ndn-cxx/util/backports.hpp b/ndn-cxx/util/backports.hpp new file mode 100644 index 000000000..aac4eb6e4 --- /dev/null +++ b/ndn-cxx/util/backports.hpp @@ -0,0 +1,172 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_BACKPORTS_HPP +#define NDN_UTIL_BACKPORTS_HPP + +#include "ndn-cxx/detail/common.hpp" + +#include +#include +#include + +#ifdef __has_cpp_attribute +# define NDN_CXX_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define NDN_CXX_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +#ifdef __has_include +# define NDN_CXX_HAS_INCLUDE(x) __has_include(x) +#else +# define NDN_CXX_HAS_INCLUDE(x) 0 +#endif + +// +// http://wg21.link/P0188 +// [[fallthrough]] attribute (C++17) +// +#if (__cplusplus > 201402L) && NDN_CXX_HAS_CPP_ATTRIBUTE(fallthrough) +# define NDN_CXX_FALLTHROUGH [[fallthrough]] +#elif NDN_CXX_HAS_CPP_ATTRIBUTE(clang::fallthrough) +# define NDN_CXX_FALLTHROUGH [[clang::fallthrough]] +#elif NDN_CXX_HAS_CPP_ATTRIBUTE(gnu::fallthrough) +# define NDN_CXX_FALLTHROUGH [[gnu::fallthrough]] +#elif BOOST_COMP_GNUC >= BOOST_VERSION_NUMBER(7,0,0) +# define NDN_CXX_FALLTHROUGH __attribute__((fallthrough)) +#else +# define NDN_CXX_FALLTHROUGH ((void)0) +#endif + +// +// http://wg21.link/P0189 +// [[nodiscard]] attribute (C++17) +// +#if (__cplusplus > 201402L) && NDN_CXX_HAS_CPP_ATTRIBUTE(nodiscard) +# define NDN_CXX_NODISCARD [[nodiscard]] +#elif NDN_CXX_HAS_CPP_ATTRIBUTE(gnu::warn_unused_result) +# define NDN_CXX_NODISCARD [[gnu::warn_unused_result]] +#else +# define NDN_CXX_NODISCARD +#endif + +#ifndef NDEBUG +# define NDN_CXX_UNREACHABLE BOOST_ASSERT(false) +#elif BOOST_COMP_GNUC || BOOST_COMP_CLANG +# define NDN_CXX_UNREACHABLE __builtin_unreachable() +#elif BOOST_COMP_MSVC +# define NDN_CXX_UNREACHABLE __assume(0) +#else +# include +# define NDN_CXX_UNREACHABLE std::abort() +#endif + +#include "ndn-cxx/util/nonstd/any.hpp" +#include "ndn-cxx/util/nonstd/optional.hpp" +#include "ndn-cxx/util/nonstd/variant.hpp" +#include "ndn-cxx/util/ostream-joiner.hpp" + +#ifndef NDN_CXX_HAVE_STD_TO_STRING +#include +#endif + +namespace ndn { + +// +// https://redmine.named-data.net/issues/2743 +// std::to_string() (C++11) +// +#ifdef NDN_CXX_HAVE_STD_TO_STRING +using std::to_string; +#else +template +inline std::string +to_string(const T& val) +{ + return boost::lexical_cast(val); +} +#endif // NDN_CXX_HAVE_STD_TO_STRING + +// +// https://wg21.link/P0025 +// std::clamp() (C++17) +// +#if __cpp_lib_clamp >= 201603L +using std::clamp; +#else +template +constexpr const T& +clamp(const T& v, const T& lo, const T& hi, Compare comp) +{ + BOOST_ASSERT(!comp(hi, lo)); + return comp(v, lo) ? lo : comp(hi, v) ? hi : v; +} + +template +constexpr const T& +clamp(const T& v, const T& lo, const T& hi) +{ + BOOST_ASSERT(!(hi < lo)); + return (v < lo) ? lo : (hi < v) ? hi : v; +} +#endif // __cpp_lib_clamp + +// +// https://wg21.link/P1682 +// std::to_underlying() (approved for LWG as of July 2019) +// +#if __cpp_lib_to_underlying >= 202002L +using std::to_underlying; +#else +template +constexpr std::underlying_type_t +to_underlying(T val) noexcept +{ + static_assert(std::is_enum::value, ""); + return static_cast>(val); +} +#endif // __cpp_lib_to_underlying + +using ::nonstd::any; +using ::nonstd::any_cast; +using ::nonstd::bad_any_cast; +using ::nonstd::make_any; + +using ::nonstd::optional; +using ::nonstd::bad_optional_access; +using ::nonstd::nullopt; +using ::nonstd::nullopt_t; +using ::nonstd::in_place; +using ::nonstd::in_place_t; +using ::nonstd::make_optional; + +using ::nonstd::variant; +using ::nonstd::bad_variant_access; +using ::nonstd::monostate; +using ::nonstd::variant_npos; +using ::nonstd::get; +using ::nonstd::get_if; +using ::nonstd::holds_alternative; +using ::nonstd::visit; + +} // namespace ndn + +#endif // NDN_UTIL_BACKPORTS_HPP diff --git a/ndn-cxx/util/concepts.hpp b/ndn-cxx/util/concepts.hpp new file mode 100644 index 000000000..5509ed305 --- /dev/null +++ b/ndn-cxx/util/concepts.hpp @@ -0,0 +1,164 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014-2018 Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_CONCEPTS_HPP +#define NDN_UTIL_CONCEPTS_HPP + +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/encoding/encoding-buffer.hpp" + +#include +#include +#include +#include + +namespace ndn { + +/** \brief a concept check for TLV abstraction with .wireEncode method + */ +template +class WireEncodable +{ +public: + BOOST_CONCEPT_USAGE(WireEncodable) + { + Block block = j.wireEncode(); + block.size(); // avoid 'unused variable block' + } + +private: + X j; +}; + +/** \brief a concept check for TLV abstraction with .wireEncode method + */ +template +class WireEncodableWithEncodingBuffer +{ +public: + BOOST_CONCEPT_USAGE(WireEncodableWithEncodingBuffer) + { + EncodingEstimator estimator; + size_t estimatedSize = j.wireEncode(estimator); + + EncodingBuffer encoder(estimatedSize, 0); + j.wireEncode(encoder); + } + +private: + X j; +}; + +/** \brief a concept check for TLV abstraction with .wireDecode method + * and constructible from Block + */ +template +class WireDecodable +{ +public: + BOOST_CONCEPT_USAGE(WireDecodable) + { + Block block; + X j(block); + j.wireDecode(block); + } +}; + +namespace detail { + +template +class NfdMgmtProtocolStruct : public WireEncodable + , public WireEncodableWithEncodingBuffer + , public WireDecodable +{ +public: + BOOST_CONCEPT_USAGE(NfdMgmtProtocolStruct) + { + static_assert(std::is_default_constructible::value, ""); + static_assert(boost::has_equal_to::value, ""); + static_assert(boost::has_not_equal_to::value, ""); + static_assert(boost::has_left_shift::value, ""); + static_assert(std::is_base_of::value, ""); + } +}; + +} // namespace detail + +/** \brief concept check for an item in a Status Dataset + * \sa https://redmine.named-data.net/projects/nfd/wiki/StatusDataset + */ +template +class StatusDatasetItem : public detail::NfdMgmtProtocolStruct +{ +}; + +/** \brief concept check for an item in a Notification Stream + * \sa https://redmine.named-data.net/projects/nfd/wiki/Notification + */ +template +class NotificationStreamItem : public detail::NfdMgmtProtocolStruct +{ +}; + +// NDN_CXX_ASSERT_DEFAULT_CONSTRUCTIBLE and NDN_CXX_ASSERT_FORWARD_ITERATOR +// originally written as part of NFD codebase + +namespace detail { + +// As of Boost 1.61.0, the internal implementation of BOOST_CONCEPT_ASSERT does not allow +// multiple assertions on the same line, so we have to combine multiple concepts together. + +template +class StlForwardIteratorConcept : public boost::ForwardIterator + , public boost::DefaultConstructible +{ +}; + +} // namespace detail + +// std::is_default_constructible is broken in gcc-4.8, see bug #3882 +/** \brief assert T is default constructible + * \sa http://en.cppreference.com/w/cpp/concept/DefaultConstructible + */ +#define NDN_CXX_ASSERT_DEFAULT_CONSTRUCTIBLE(T) \ + static_assert(std::is_default_constructible::value, \ + #T " must be default-constructible"); \ + BOOST_CONCEPT_ASSERT((boost::DefaultConstructible)) + +/** \brief assert T is a forward iterator + * \sa http://en.cppreference.com/w/cpp/concept/ForwardIterator + * \note A forward iterator should be default constructible, but boost::ForwardIterator follows + * SGI standard which doesn't require DefaultConstructible, so a separate check is needed. + */ +#define NDN_CXX_ASSERT_FORWARD_ITERATOR(T) \ + static_assert(std::is_default_constructible::value, \ + #T " must be default-constructible"); \ + BOOST_CONCEPT_ASSERT((::ndn::detail::StlForwardIteratorConcept)) + +} // namespace ndn + +#endif // NDN_UTIL_CONCEPTS_HPP diff --git a/ndn-cxx/util/config-file.cpp b/ndn-cxx/util/config-file.cpp new file mode 100644 index 000000000..f08d3eb6e --- /dev/null +++ b/ndn-cxx/util/config-file.cpp @@ -0,0 +1,124 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/config-file.hpp" + +#include +#include + +namespace ndn { + +ConfigFile::ConfigFile() + : m_path(findConfigFile()) +{ + if (open()) { + parse(); + close(); + } +} + +ConfigFile::~ConfigFile() +{ + close(); +} + +boost::filesystem::path +ConfigFile::findConfigFile() +{ + using namespace boost::filesystem; + +#ifdef NDN_CXX_HAVE_TESTS + if (std::getenv("TEST_HOME")) { + path testHome(std::getenv("TEST_HOME")); + testHome /= ".ndn/client.conf"; + if (exists(testHome)) { + return absolute(testHome); + } + } +#endif // NDN_CXX_HAVE_TESTS + + if (std::getenv("HOME")) { + path home(std::getenv("HOME")); + home /= ".ndn/client.conf"; + if (exists(home)) { + return absolute(home); + } + } + +#ifdef NDN_CXX_SYSCONFDIR + path sysconfdir(NDN_CXX_SYSCONFDIR); + sysconfdir /= "ndn/client.conf"; + if (exists(sysconfdir)) { + return absolute(sysconfdir); + } +#endif // NDN_CXX_SYSCONFDIR + + path etc("/etc/ndn/client.conf"); + if (exists(etc)) { + return absolute(etc); + } + + return {}; +} + +bool +ConfigFile::open() +{ + if (m_path.empty()) { + return false; + } + + m_input.open(m_path.c_str()); + if (!m_input.good() || !m_input.is_open()) { + return false; + } + return true; +} + +void +ConfigFile::close() +{ + if (m_input.is_open()) { + m_input.close(); + } +} + +const ConfigFile::Parsed& +ConfigFile::parse() +{ + if (m_path.empty()) { + NDN_THROW(Error("Failed to locate configuration file for parsing")); + } + if (!m_input.is_open() && !open()) { + NDN_THROW(Error("Failed to open configuration file for parsing")); + } + + try { + boost::property_tree::read_ini(m_input, m_config); + } + catch (const boost::property_tree::ini_parser_error& error) { + NDN_THROW(Error("Failed to parse configuration file " + error.filename() + + " line " + to_string(error.line()) + ": " + error.message())); + } + return m_config; +} + +} // namespace ndn diff --git a/src/util/config-file.hpp b/ndn-cxx/util/config-file.hpp similarity index 94% rename from src/util/config-file.hpp rename to ndn-cxx/util/config-file.hpp index 2bb6c2d75..600e1cce7 100644 --- a/src/util/config-file.hpp +++ b/ndn-cxx/util/config-file.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,12 +22,12 @@ #ifndef NDN_MANAGEMENT_CONFIG_FILE_HPP #define NDN_MANAGEMENT_CONFIG_FILE_HPP -#include "../common.hpp" +#include "ndn-cxx/detail/common.hpp" #include -#include #include +#include namespace ndn { @@ -48,15 +48,10 @@ namespace ndn { class ConfigFile : noncopyable { public: - class Error : public std::runtime_error { public: - Error(const std::string& what) - : std::runtime_error(what) - { - - } + using std::runtime_error::runtime_error; }; typedef boost::property_tree::ptree Parsed; @@ -77,7 +72,6 @@ class ConfigFile : noncopyable getParsedConfiguration() const; private: - bool open(); @@ -108,7 +102,6 @@ class ConfigFile : noncopyable * * @return path to preferred configuration (according to above order) or empty path on failure */ - boost::filesystem::path findConfigFile(); @@ -132,5 +125,4 @@ ConfigFile::getParsedConfiguration() const } // namespace ndn - #endif // NDN_MANAGEMENT_CONFIG_FILE_HPP diff --git a/ndn-cxx/util/dummy-client-face.cpp b/ndn-cxx/util/dummy-client-face.cpp new file mode 100644 index 000000000..9f2cb9eed --- /dev/null +++ b/ndn-cxx/util/dummy-client-face.cpp @@ -0,0 +1,343 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/dummy-client-face.hpp" +#include "ndn-cxx/impl/lp-field-tag.hpp" +#include "ndn-cxx/lp/packet.hpp" +#include "ndn-cxx/lp/tags.hpp" +#include "ndn-cxx/mgmt/nfd/controller.hpp" +#include "ndn-cxx/mgmt/nfd/control-response.hpp" +#include "ndn-cxx/transport/transport.hpp" + +#include + +namespace ndn { +namespace util { + +class DummyClientFace::Transport : public ndn::Transport +{ +public: + void + receive(Block block) const + { + block.encode(); + if (m_receiveCallback) { + m_receiveCallback(block); + } + } + + void + close() override + { + } + + void + pause() override + { + } + + void + resume() override + { + } + + void + send(const Block& wire) override + { + onSendBlock(wire); + } + + void + send(const Block& header, const Block& payload) override + { + EncodingBuffer encoder(header.size() + payload.size(), header.size() + payload.size()); + encoder.appendByteArray(header.wire(), header.size()); + encoder.appendByteArray(payload.wire(), payload.size()); + + this->send(encoder.block()); + } + + boost::asio::io_service& + getIoService() + { + return *m_ioService; + } + +public: + Signal onSendBlock; +}; + +struct DummyClientFace::BroadcastLink +{ + std::vector faces; +}; + +DummyClientFace::AlreadyLinkedError::AlreadyLinkedError() + : Error("Face has already been linked to another face") +{ +} + +DummyClientFace::DummyClientFace(const Options& options) + : Face(make_shared()) + , m_internalKeyChain(make_unique()) + , m_keyChain(*m_internalKeyChain) +{ + this->construct(options); +} + +DummyClientFace::DummyClientFace(KeyChain& keyChain, const Options& options) + : Face(make_shared(), keyChain) + , m_keyChain(keyChain) +{ + this->construct(options); +} + +DummyClientFace::DummyClientFace(boost::asio::io_service& ioService, const Options& options) + : Face(make_shared(), ioService) + , m_internalKeyChain(make_unique()) + , m_keyChain(*m_internalKeyChain) +{ + this->construct(options); +} + +DummyClientFace::DummyClientFace(boost::asio::io_service& ioService, KeyChain& keyChain, const Options& options) + : Face(make_shared(), ioService, keyChain) + , m_keyChain(keyChain) +{ + this->construct(options); +} + +DummyClientFace::~DummyClientFace() +{ + unlink(); +} + +void +DummyClientFace::construct(const Options& options) +{ + static_pointer_cast(getTransport())->onSendBlock.connect([this] (const Block& blockFromDaemon) { + Block packet(blockFromDaemon); + packet.encode(); + lp::Packet lpPacket(packet); + + Buffer::const_iterator begin, end; + std::tie(begin, end) = lpPacket.get(); + Block block(&*begin, std::distance(begin, end)); + + if (block.type() == tlv::Interest) { + shared_ptr interest = make_shared(block); + if (lpPacket.has()) { + shared_ptr nack = make_shared(std::move(*interest)); + nack->setHeader(lpPacket.get()); + addTagFromField(*nack, lpPacket); + onSendNack(*nack); + } + else { + addTagFromField(*interest, lpPacket); + addTagFromField(*interest, lpPacket); + onSendInterest(*interest); + } + } + else if (block.type() == tlv::Data) { + shared_ptr data = make_shared(block); + addTagFromField(*data, lpPacket); + addTagFromField(*data, lpPacket); + onSendData(*data); + } + }); + + if (options.enablePacketLogging) + this->enablePacketLogging(); + + if (options.enableRegistrationReply) + this->enableRegistrationReply(); + + m_processEventsOverride = options.processEventsOverride; + + enableBroadcastLink(); +} + +void +DummyClientFace::enableBroadcastLink() +{ + this->onSendInterest.connect([this] (const Interest& interest) { + if (m_bcastLink != nullptr) { + for (auto otherFace : m_bcastLink->faces) { + if (otherFace != this) { + otherFace->receive(interest); + } + } + } + }); + this->onSendData.connect([this] (const Data& data) { + if (m_bcastLink != nullptr) { + for (auto otherFace : m_bcastLink->faces) { + if (otherFace != this) { + otherFace->receive(data); + } + } + } + }); + this->onSendNack.connect([this] (const lp::Nack& nack) { + if (m_bcastLink != nullptr) { + for (auto otherFace : m_bcastLink->faces) { + if (otherFace != this) { + otherFace->receive(nack); + } + } + } + }); +} + +void +DummyClientFace::enablePacketLogging() +{ + onSendInterest.connect([this] (const Interest& interest) { + this->sentInterests.push_back(interest); + }); + onSendData.connect([this] (const Data& data) { + this->sentData.push_back(data); + }); + onSendNack.connect([this] (const lp::Nack& nack) { + this->sentNacks.push_back(nack); + }); +} + +void +DummyClientFace::enableRegistrationReply() +{ + onSendInterest.connect([this] (const Interest& interest) { + static const Name localhostRegistration("/localhost/nfd/rib"); + if (!localhostRegistration.isPrefixOf(interest.getName())) + return; + + nfd::ControlParameters params(interest.getName().get(-5).blockFromValue()); + params.setFaceId(1); + params.setOrigin(nfd::ROUTE_ORIGIN_APP); + if (interest.getName().get(3) == name::Component("register")) { + params.setCost(0); + } + + nfd::ControlResponse resp; + resp.setCode(200); + resp.setBody(params.wireEncode()); + + shared_ptr data = make_shared(interest.getName()); + data->setContent(resp.wireEncode()); + + m_keyChain.sign(*data, security::SigningInfo(security::SigningInfo::SIGNER_TYPE_SHA256)); + + this->getIoService().post([this, data] { this->receive(*data); }); + }); +} + +void +DummyClientFace::receive(const Interest& interest) +{ + lp::Packet lpPacket(interest.wireEncode()); + + addFieldFromTag(lpPacket, interest); + addFieldFromTag(lpPacket, interest); + addFieldFromTag(lpPacket, interest); + + static_pointer_cast(getTransport())->receive(lpPacket.wireEncode()); +} + +void +DummyClientFace::receive(const Data& data) +{ + lp::Packet lpPacket(data.wireEncode()); + + addFieldFromTag(lpPacket, data); + addFieldFromTag(lpPacket, data); + + static_pointer_cast(getTransport())->receive(lpPacket.wireEncode()); +} + +void +DummyClientFace::receive(const lp::Nack& nack) +{ + lp::Packet lpPacket; + lpPacket.add(nack.getHeader()); + Block interest = nack.getInterest().wireEncode(); + lpPacket.add(make_pair(interest.begin(), interest.end())); + + addFieldFromTag(lpPacket, nack); + addFieldFromTag(lpPacket, nack); + + static_pointer_cast(getTransport())->receive(lpPacket.wireEncode()); +} + +void +DummyClientFace::linkTo(DummyClientFace& other) +{ + if (m_bcastLink != nullptr && other.m_bcastLink != nullptr) { + if (m_bcastLink != other.m_bcastLink) { + // already on different links + NDN_THROW(AlreadyLinkedError()); + } + } + else if (m_bcastLink == nullptr && other.m_bcastLink != nullptr) { + m_bcastLink = other.m_bcastLink; + m_bcastLink->faces.push_back(this); + } + else if (m_bcastLink != nullptr && other.m_bcastLink == nullptr) { + other.m_bcastLink = m_bcastLink; + m_bcastLink->faces.push_back(&other); + } + else { + m_bcastLink = other.m_bcastLink = make_shared(); + m_bcastLink->faces.push_back(this); + m_bcastLink->faces.push_back(&other); + } +} + +void +DummyClientFace::unlink() +{ + if (m_bcastLink == nullptr) { + return; + } + + auto it = std::find(m_bcastLink->faces.begin(), m_bcastLink->faces.end(), this); + BOOST_ASSERT(it != m_bcastLink->faces.end()); + m_bcastLink->faces.erase(it); + + if (m_bcastLink->faces.size() == 1) { + m_bcastLink->faces[0]->m_bcastLink = nullptr; + m_bcastLink->faces.clear(); + } + m_bcastLink = nullptr; +} + +void +DummyClientFace::doProcessEvents(time::milliseconds timeout, bool keepThread) +{ + if (m_processEventsOverride != nullptr) { + m_processEventsOverride(timeout); + } + else { + this->Face::doProcessEvents(timeout, keepThread); + } +} + +} // namespace util +} // namespace ndn diff --git a/src/util/dummy-client-face.hpp b/ndn-cxx/util/dummy-client-face.hpp similarity index 83% rename from src/util/dummy-client-face.hpp rename to ndn-cxx/util/dummy-client-face.hpp index 7d661a790..e85b279ba 100644 --- a/src/util/dummy-client-face.hpp +++ b/ndn-cxx/util/dummy-client-face.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,9 +22,9 @@ #ifndef NDN_UTIL_DUMMY_CLIENT_FACE_HPP #define NDN_UTIL_DUMMY_CLIENT_FACE_HPP -#include "../face.hpp" -#include "signal.hpp" -#include "../security/key-chain.hpp" +#include "ndn-cxx/face.hpp" +#include "ndn-cxx/util/signal.hpp" +#include "ndn-cxx/security/key-chain.hpp" namespace ndn { namespace util { @@ -72,6 +72,12 @@ class DummyClientFace : public ndn::Face std::function processEventsOverride; }; + class AlreadyLinkedError : public Error + { + public: + AlreadyLinkedError(); + }; + /** \brief Create a dummy face with internal IO service */ explicit @@ -92,12 +98,32 @@ class DummyClientFace : public ndn::Face DummyClientFace(boost::asio::io_service& ioService, KeyChain& keyChain, const Options& options = Options()); - /** \brief cause the Face to receive a packet - * \tparam Packet either Interest or Data + ~DummyClientFace(); + + /** \brief cause the Face to receive an interest + */ + void + receive(const Interest& interest); + + /** \brief cause the Face to receive a data + */ + void + receive(const Data& data); + + /** \brief cause the Face to receive a nack */ - template void - receive(const Packet& packet); + receive(const lp::Nack& nack); + + /** \brief link another DummyClientFace through a broadcast media + */ + void + linkTo(DummyClientFace& other); + + /** \brief unlink the broadcast media if previously linked + */ + void + unlink(); private: class Transport; @@ -105,14 +131,17 @@ class DummyClientFace : public ndn::Face void construct(const Options& options); + void + enableBroadcastLink(); + void enablePacketLogging(); void enableRegistrationReply(); - virtual void - doProcessEvents(const time::milliseconds& timeout, bool keepThread) override; + void + doProcessEvents(time::milliseconds timeout, bool keepThread) override; public: /** \brief Interests sent out of this DummyClientFace @@ -157,16 +186,14 @@ class DummyClientFace : public ndn::Face */ Signal onSendNack; -private: +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: + struct BroadcastLink; + shared_ptr m_bcastLink; std::unique_ptr m_internalKeyChain; KeyChain& m_keyChain; std::function m_processEventsOverride; }; -template<> -void -DummyClientFace::receive(const lp::Nack& nack); - } // namespace util } // namespace ndn diff --git a/ndn-cxx/util/exception.cpp b/ndn-cxx/util/exception.cpp new file mode 100644 index 000000000..d14369200 --- /dev/null +++ b/ndn-cxx/util/exception.cpp @@ -0,0 +1,45 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/exception.hpp" + +#include + +namespace ndn { +namespace exception { + +#ifdef NDN_CXX_HAVE_STACKTRACE +std::string +to_string(const errinfo_stacktrace& x) +{ + if (x.value().empty()) + return ""; + + std::ostringstream out; + out << "===== Stacktrace =====\n" + << x.value() + << "======================\n"; + return out.str(); +} +#endif + +} // namespace exception +} // namespace ndn diff --git a/ndn-cxx/util/exception.hpp b/ndn-cxx/util/exception.hpp new file mode 100644 index 000000000..1cdcc3ba0 --- /dev/null +++ b/ndn-cxx/util/exception.hpp @@ -0,0 +1,74 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_EXCEPTION_HPP +#define NDN_UTIL_EXCEPTION_HPP + +#include "ndn-cxx/detail/common.hpp" + +#include + +#include +#include +#include +#include +#include + +#ifdef NDN_CXX_HAVE_STACKTRACE +#include +#endif + +namespace ndn { +namespace exception { + +#ifdef NDN_CXX_HAVE_STACKTRACE +using errinfo_stacktrace = boost::error_info; + +std::string +to_string(const errinfo_stacktrace&); +#endif + +} // namespace exception +} // namespace ndn + +/** \cond */ +#ifdef NDN_CXX_HAVE_STACKTRACE +#define NDN_DETAIL_THROW_STACKTRACE \ + << ndn::exception::errinfo_stacktrace(boost::stacktrace::stacktrace()) +#else +#define NDN_DETAIL_THROW_STACKTRACE +#endif +/** \endcond */ + +#define NDN_THROW(e) \ + throw boost::enable_current_exception(boost::enable_error_info(e)) \ + << boost::throw_file(__FILE__) \ + << boost::throw_line(__LINE__) \ + << boost::throw_function(__func__) \ + NDN_DETAIL_THROW_STACKTRACE + +#define NDN_THROW_ERRNO(e) \ + NDN_THROW(e) << boost::errinfo_errno(errno) + +#define NDN_THROW_NESTED(e) \ + NDN_THROW(e) << boost::errinfo_nested_exception(boost::current_exception()) + +#endif // NDN_UTIL_EXCEPTION_HPP diff --git a/ndn-cxx/util/impl/steady-timer.hpp b/ndn-cxx/util/impl/steady-timer.hpp new file mode 100644 index 000000000..b7a35b3e3 --- /dev/null +++ b/ndn-cxx/util/impl/steady-timer.hpp @@ -0,0 +1,60 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_IMPL_STEADY_TIMER_HPP +#define NDN_UTIL_IMPL_STEADY_TIMER_HPP + +#include "ndn-cxx/util/time.hpp" + +#include +#include + +namespace boost { +namespace asio { + +template<> +struct wait_traits +{ + static ndn::time::steady_clock::duration + to_wait_duration(const ndn::time::steady_clock::duration& d) + { + return ndn::time::steady_clock::to_wait_duration(d); + } +}; + +} // namespace asio +} // namespace boost + +namespace ndn { +namespace util { +namespace detail { + +class SteadyTimer : public boost::asio::basic_waitable_timer +{ +public: + using boost::asio::basic_waitable_timer::basic_waitable_timer; +}; + +} // namespace detail +} // namespace util +} // namespace ndn + +#endif // NDN_UTIL_IMPL_STEADY_TIMER_HPP diff --git a/src/util/indented-stream.cpp b/ndn-cxx/util/indented-stream.cpp similarity index 94% rename from src/util/indented-stream.cpp rename to ndn-cxx/util/indented-stream.cpp index b875db4a1..ba78f338a 100644 --- a/src/util/indented-stream.cpp +++ b/ndn-cxx/util/indented-stream.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,7 +19,7 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "indented-stream.hpp" +#include "ndn-cxx/util/indented-stream.hpp" #include diff --git a/src/util/indented-stream.hpp b/ndn-cxx/util/indented-stream.hpp similarity index 95% rename from src/util/indented-stream.hpp rename to ndn-cxx/util/indented-stream.hpp index 31e583900..7b1376ca8 100644 --- a/src/util/indented-stream.hpp +++ b/ndn-cxx/util/indented-stream.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -56,7 +56,6 @@ class IndentedStream : public std::ostream public: IndentedStream(std::ostream& os, const std::string& indent); - virtual ~IndentedStream() override; private: @@ -66,7 +65,7 @@ class IndentedStream : public std::ostream public: StreamBuf(std::ostream& os, const std::string& indent); - virtual int + int sync() override; private: diff --git a/ndn-cxx/util/io.cpp b/ndn-cxx/util/io.cpp new file mode 100644 index 000000000..a385eea26 --- /dev/null +++ b/ndn-cxx/util/io.cpp @@ -0,0 +1,108 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/io.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/transform/base64-decode.hpp" +#include "ndn-cxx/security/transform/base64-encode.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/hex-decode.hpp" +#include "ndn-cxx/security/transform/hex-encode.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" +#include "ndn-cxx/security/transform/stream-source.hpp" +#include "ndn-cxx/security/transform/strip-space.hpp" + +namespace ndn { +namespace io { + +shared_ptr +loadBuffer(std::istream& is, IoEncoding encoding) +{ + namespace t = ndn::security::transform; + + OBufferStream os; + try { + switch (encoding) { + case NO_ENCODING: + t::streamSource(is) >> t::streamSink(os); + return os.buf(); + case BASE64: + t::streamSource(is) >> t::stripSpace("\n") >> t::base64Decode(false) >> t::streamSink(os); + return os.buf(); + case HEX: + t::streamSource(is) >> t::hexDecode() >> t::streamSink(os); + return os.buf(); + } + } + catch (const t::Error& e) { + NDN_THROW_NESTED(Error(e.what())); + } + + NDN_THROW(std::invalid_argument("Unknown IoEncoding " + to_string(encoding))); +} + +optional +loadBlock(std::istream& is, IoEncoding encoding) +{ + try { + return make_optional(loadBuffer(is, encoding)); + } + catch (const std::invalid_argument&) { + return nullopt; + } + catch (const std::runtime_error&) { + return nullopt; + } +} + +void +saveBuffer(const uint8_t* buf, size_t size, std::ostream& os, IoEncoding encoding) +{ + namespace t = ndn::security::transform; + + try { + switch (encoding) { + case NO_ENCODING: + t::bufferSource(buf, size) >> t::streamSink(os); + return; + case BASE64: + t::bufferSource(buf, size) >> t::base64Encode() >> t::streamSink(os); + return; + case HEX: + t::bufferSource(buf, size) >> t::hexEncode(true) >> t::streamSink(os); + return; + } + } + catch (const t::Error& e) { + NDN_THROW_NESTED(Error(e.what())); + } + + NDN_THROW(std::invalid_argument("Unknown IoEncoding " + to_string(encoding))); +} + +void +saveBlock(const Block& block, std::ostream& os, IoEncoding encoding) +{ + saveBuffer(block.wire(), block.size(), os, encoding); +} + +} // namespace io +} // namespace ndn diff --git a/ndn-cxx/util/io.hpp b/ndn-cxx/util/io.hpp new file mode 100644 index 000000000..709fe5df3 --- /dev/null +++ b/ndn-cxx/util/io.hpp @@ -0,0 +1,186 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_IO_HPP +#define NDN_UTIL_IO_HPP + +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/util/concepts.hpp" + +#include + +namespace ndn { +namespace io { + +class Error : public std::runtime_error +{ +public: + using std::runtime_error::runtime_error; +}; + +/** \brief Indicates how a file or stream of bytes is encoded. + */ +enum IoEncoding { + /** \brief Raw binary, without encoding + */ + NO_ENCODING, + + /** \brief Base64 encoding + * + * `save()` inserts a newline after every 64 characters, + * `load()` can accept base64 text with or without newlines. + */ + BASE64, + + /** \brief Hexadecimal encoding + * + * `save()` uses uppercase letters A-F, `load()` can accept mixed-case. + */ + HEX, +}; + +namespace detail { + +template +static void +checkInnerError(typename T::Error*) +{ + static_assert(std::is_convertible::value, + "T::Error, if defined, must be a subclass of ndn::tlv::Error"); +} + +template +static void +checkInnerError(...) +{ + // T::Error is not defined +} + +} // namespace detail + +/** \brief Reads bytes from a stream until EOF. + * \return a Buffer containing the bytes read from the stream + * \throw Error error during loading + * \throw std::invalid_argument the specified encoding is not supported + */ +shared_ptr +loadBuffer(std::istream& is, IoEncoding encoding = BASE64); + +/** \brief Reads a TLV block from a stream. + * \return a Block, or nullopt if an error occurs + */ +optional +loadBlock(std::istream& is, IoEncoding encoding = BASE64); + +/** \brief Reads a TLV element from a stream. + * \tparam T type of TLV element; `T` must be WireDecodable and the nested type + * `T::Error`, if defined, must be a subclass of ndn::tlv::Error + * \return the TLV element, or nullptr if an error occurs + */ +template +shared_ptr +load(std::istream& is, IoEncoding encoding = BASE64) +{ + BOOST_CONCEPT_ASSERT((WireDecodable)); + detail::checkInnerError(nullptr); + + auto block = loadBlock(is, encoding); + if (!block) { + return nullptr; + } + + try { + return make_shared(*block); + } + catch (const tlv::Error&) { + return nullptr; + } +} + +/** \brief Reads a TLV element from a file. + * \tparam T type of TLV element; `T` must be WireDecodable and the nested type + * `T::Error`, if defined, must be a subclass of ndn::tlv::Error + * \return the TLV element, or nullptr if an error occurs + */ +template +shared_ptr +load(const std::string& filename, IoEncoding encoding = BASE64) +{ + std::ifstream is(filename); + return load(is, encoding); +} + +/** \brief Writes a byte buffer to a stream. + * \throw Error error during saving + * \throw std::invalid_argument the specified encoding is not supported + */ +void +saveBuffer(const uint8_t* buf, size_t size, std::ostream& os, IoEncoding encoding = BASE64); + +/** \brief Writes a TLV block to a stream. + * \throw Error error during saving + * \throw std::invalid_argument the specified encoding is not supported + */ +void +saveBlock(const Block& block, std::ostream& os, IoEncoding encoding = BASE64); + +/** \brief Writes a TLV element to a stream. + * \tparam T type of TLV element; `T` must be WireEncodable and the nested type + * `T::Error`, if defined, must be a subclass of ndn::tlv::Error + * \throw Error error during encoding or saving + * \throw std::invalid_argument the specified encoding is not supported + */ +template +void +save(const T& obj, std::ostream& os, IoEncoding encoding = BASE64) +{ + BOOST_CONCEPT_ASSERT((WireEncodable)); + detail::checkInnerError(nullptr); + + Block block; + try { + block = obj.wireEncode(); + } + catch (const tlv::Error&) { + NDN_THROW_NESTED(Error("Encode error during save")); + } + + saveBlock(block, os, encoding); +} + +/** \brief Writes a TLV element to a file. + * \tparam T type of TLV element; `T` must be WireEncodable and the nested type + * `T::Error`, if defined, must be a subclass of ndn::tlv::Error + * \throw Error error during encoding or saving + * \throw std::invalid_argument the specified encoding is not supported + */ +template +void +save(const T& obj, const std::string& filename, IoEncoding encoding = BASE64) +{ + std::ofstream os(filename); + save(obj, os, encoding); +} + +} // namespace io +} // namespace ndn + +#endif // NDN_UTIL_IO_HPP diff --git a/ndn-cxx/util/logger.cpp b/ndn-cxx/util/logger.cpp new file mode 100644 index 000000000..c17c2198f --- /dev/null +++ b/ndn-cxx/util/logger.cpp @@ -0,0 +1,77 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/logger.hpp" +#include "ndn-cxx/detail/common.hpp" + +namespace ndn { +namespace util { + +std::ostream& +operator<<(std::ostream& os, LogLevel level) +{ + switch (level) { + case LogLevel::FATAL: + return os << "FATAL"; + case LogLevel::NONE: + return os << "NONE"; + case LogLevel::ERROR: + return os << "ERROR"; + case LogLevel::WARN: + return os << "WARN"; + case LogLevel::INFO: + return os << "INFO"; + case LogLevel::DEBUG: + return os << "DEBUG"; + case LogLevel::TRACE: + return os << "TRACE"; + case LogLevel::ALL: + return os << "ALL"; + } + + NDN_THROW(std::invalid_argument("unknown log level " + to_string(to_underlying(level)))); +} + +LogLevel +parseLogLevel(const std::string& s) +{ + if (s == "FATAL") + return LogLevel::FATAL; + else if (s == "NONE") + return LogLevel::NONE; + else if (s == "ERROR") + return LogLevel::ERROR; + else if (s == "WARN") + return LogLevel::WARN; + else if (s == "INFO") + return LogLevel::INFO; + else if (s == "DEBUG") + return LogLevel::DEBUG; + else if (s == "TRACE") + return LogLevel::TRACE; + else if (s == "ALL") + return LogLevel::ALL; + + NDN_THROW(std::invalid_argument("unrecognized log level '" + s + "'")); +} + +} // namespace util +} // namespace ndn diff --git a/ndn-cxx/util/logger.hpp b/ndn-cxx/util/logger.hpp new file mode 100644 index 000000000..65fce893f --- /dev/null +++ b/ndn-cxx/util/logger.hpp @@ -0,0 +1,108 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_LOGGER_HPP +#define NDN_UTIL_LOGGER_HPP + +#include "ns3/log.h" + +namespace ndn { +namespace util { + +/** \brief Indicates the severity level of a log message. + */ +enum class LogLevel { + FATAL = -1, ///< fatal (will be logged unconditionally) + NONE = 0, ///< no messages + ERROR = 1, ///< serious error messages + WARN = 2, ///< warning messages + INFO = 3, ///< informational messages + DEBUG = 4, ///< debug messages + TRACE = 5, ///< trace messages (most verbose) + ALL = 255 ///< all messages +}; + +/** \brief Output LogLevel as a string. + * \throw std::invalid_argument unknown \p level + */ +std::ostream& +operator<<(std::ostream& os, LogLevel level); + +/** \brief Parse LogLevel from a string. + * \throw std::invalid_argument unknown level name + */ +LogLevel +parseLogLevel(const std::string& s); + +namespace detail { + +/** \cond */ +template +struct ExtractArgument; + +template +struct ExtractArgument +{ + using type = U; +}; + +template +struct ExtractArgument +{ + using type = U; +}; + +template +using ArgumentType = typename ExtractArgument::type; +/** \endcond */ + +} // namespace detail + +/** \brief declare a log module + */ +#define NDN_LOG_INIT(name) NS_LOG_COMPONENT_DEFINE("ndn-cxx." BOOST_STRINGIZE(name)) + +#define NDN_LOG_MEMBER_DECL() \ + static ::ns3::LogComponent g_log + +#define NDN_LOG_MEMBER_INIT(cls, name) \ + ::ns3::LogComponent cls::g_log = ::ns3::LogComponent("ndn-cxx." BOOST_STRINGIZE(name), __FILE__) + +// ::ns3::LogComponent ::ndn::util::detail::ArgumentType::g_log = ::ns3::LogComponent("ndn-cxx." BOOST_STRINGIZE(name), __FILE__) + +#define NDN_LOG_MEMBER_DECL_SPECIALIZED(cls) \ + static ::ns3::LogComponent g_log + +#define NDN_LOG_MEMBER_INIT_SPECIALIZED(cls, name) \ + template<> \ + ::ns3::LogComponent ::ndn::util::detail::ArgumentType::g_log = ::ns3::LogComponent("ndn-cxx." BOOST_STRINGIZE(name), __FILE__) + +#define NDN_LOG_TRACE(expression) NS_LOG_LOGIC(expression) +#define NDN_LOG_DEBUG(expression) NS_LOG_DEBUG(expression) +#define NDN_LOG_INFO(expression) NS_LOG_INFO(expression) +#define NDN_LOG_WARN(expression) NS_LOG_ERROR(expression) +#define NDN_LOG_ERROR(expression) NS_LOG_WARN(expression) +#define NDN_LOG_FATAL(expression) NS_LOG_FATAL(expression) + +} // namespace util +} // namespace ndn + +#endif // NDN_UTIL_LOGGER_HPP diff --git a/ndn-cxx/util/nonstd/any.hpp b/ndn-cxx/util/nonstd/any.hpp new file mode 100644 index 000000000..cf5071e87 --- /dev/null +++ b/ndn-cxx/util/nonstd/any.hpp @@ -0,0 +1,702 @@ +// +// Copyright (c) 2016-2018 Martin Moene +// +// https://github.com/martinmoene/any-lite +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#pragma once + +#ifndef NONSTD_ANY_LITE_HPP +#define NONSTD_ANY_LITE_HPP + +#define any_lite_MAJOR 0 +#define any_lite_MINOR 1 +#define any_lite_PATCH 0 + +#define any_lite_VERSION any_STRINGIFY(any_lite_MAJOR) "." any_STRINGIFY(any_lite_MINOR) "." any_STRINGIFY(any_lite_PATCH) + +#define any_STRINGIFY( x ) any_STRINGIFY_( x ) +#define any_STRINGIFY_( x ) #x + +// any-lite configuration: + +#define any_ANY_DEFAULT 0 +#define any_ANY_NONSTD 1 +#define any_ANY_STD 2 + +#if !defined( any_CONFIG_SELECT_ANY ) +# define any_CONFIG_SELECT_ANY ( any_HAVE_STD_ANY ? any_ANY_STD : any_ANY_NONSTD ) +#endif + +// Control presence of exception handling (try and auto discover): + +#ifndef any_CONFIG_NO_EXCEPTIONS +# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) +# define any_CONFIG_NO_EXCEPTIONS 0 +# else +# define any_CONFIG_NO_EXCEPTIONS 1 +# endif +#endif + +// C++ language version detection (C++20 is speculative): +// Note: VC14.0/1900 (VS2015) lacks too much from C++14. + +#ifndef any_CPLUSPLUS +# if defined(_MSVC_LANG ) && !defined(__clang__) +# define any_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) +# else +# define any_CPLUSPLUS __cplusplus +# endif +#endif + +#define any_CPP98_OR_GREATER ( any_CPLUSPLUS >= 199711L ) +#define any_CPP11_OR_GREATER ( any_CPLUSPLUS >= 201103L ) +#define any_CPP14_OR_GREATER ( any_CPLUSPLUS >= 201402L ) +#define any_CPP17_OR_GREATER ( any_CPLUSPLUS >= 201703L ) +#define any_CPP20_OR_GREATER ( any_CPLUSPLUS >= 202000L ) + +// Use C++17 std::any if available and requested: + +#if any_CPP17_OR_GREATER && defined(__has_include ) +# if __has_include( ) +# define any_HAVE_STD_ANY 1 +# else +# define any_HAVE_STD_ANY 0 +# endif +#else +# define any_HAVE_STD_ANY 0 +#endif + +#define any_USES_STD_ANY ( (any_CONFIG_SELECT_ANY == any_ANY_STD) || ((any_CONFIG_SELECT_ANY == any_ANY_DEFAULT) && any_HAVE_STD_ANY) ) + +// +// in_place: code duplicated in any-lite, expected-lite, optional-lite, value-ptr-lite, variant-lite: +// + +#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES +#define nonstd_lite_HAVE_IN_PLACE_TYPES 1 + +// C++17 std::in_place in : + +#if any_CPP17_OR_GREATER + +#include + +namespace nonstd { + +using std::in_place; +using std::in_place_type; +using std::in_place_index; +using std::in_place_t; +using std::in_place_type_t; +using std::in_place_index_t; + +#define nonstd_lite_in_place_t( T) std::in_place_t +#define nonstd_lite_in_place_type_t( T) std::in_place_type_t +#define nonstd_lite_in_place_index_t(K) std::in_place_index_t + +#define nonstd_lite_in_place( T) std::in_place_t{} +#define nonstd_lite_in_place_type( T) std::in_place_type_t{} +#define nonstd_lite_in_place_index(K) std::in_place_index_t{} + +} // namespace nonstd + +#else // any_CPP17_OR_GREATER + +#include + +namespace nonstd { +namespace detail { + +template< class T > +struct in_place_type_tag {}; + +template< std::size_t K > +struct in_place_index_tag {}; + +} // namespace detail + +struct in_place_t {}; + +template< class T > +inline in_place_t in_place( detail::in_place_type_tag = detail::in_place_type_tag() ) +{ + return in_place_t(); +} + +template< std::size_t K > +inline in_place_t in_place( detail::in_place_index_tag = detail::in_place_index_tag() ) +{ + return in_place_t(); +} + +template< class T > +inline in_place_t in_place_type( detail::in_place_type_tag = detail::in_place_type_tag() ) +{ + return in_place_t(); +} + +template< std::size_t K > +inline in_place_t in_place_index( detail::in_place_index_tag = detail::in_place_index_tag() ) +{ + return in_place_t(); +} + +// mimic templated typedef: + +#define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) +#define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) +#define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag ) + +#define nonstd_lite_in_place( T) nonstd::in_place_type +#define nonstd_lite_in_place_type( T) nonstd::in_place_type +#define nonstd_lite_in_place_index(K) nonstd::in_place_index + +} // namespace nonstd + +#endif // any_CPP17_OR_GREATER +#endif // nonstd_lite_HAVE_IN_PLACE_TYPES + +// +// Using std::any: +// + +#if any_USES_STD_ANY + +#include +#include + +namespace nonstd { + + using std::any; + using std::any_cast; + using std::make_any; + using std::swap; + using std::bad_any_cast; +} + +#else // any_USES_STD_ANY + +#include + +// Compiler versions: +// +// MSVC++ 6.0 _MSC_VER == 1200 (Visual Studio 6.0) +// MSVC++ 7.0 _MSC_VER == 1300 (Visual Studio .NET 2002) +// MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio .NET 2003) +// MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) +// MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) +// MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) +// MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) +// MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) +// MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) +// MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017) + +#if defined(_MSC_VER ) && !defined(__clang__) +# define any_COMPILER_MSVC_VER (_MSC_VER ) +# define any_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) +#else +# define any_COMPILER_MSVC_VER 0 +# define any_COMPILER_MSVC_VERSION 0 +#endif + +#define any_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) ) + +#if defined(__clang__) +# define any_COMPILER_CLANG_VERSION any_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) +#else +# define any_COMPILER_CLANG_VERSION 0 +#endif + +#if defined(__GNUC__) && !defined(__clang__) +# define any_COMPILER_GNUC_VERSION any_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#else +# define any_COMPILER_GNUC_VERSION 0 +#endif + +// half-open range [lo..hi): +//#define any_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) + +// Presence of language and library features: + +#define any_HAVE( feature ) ( any_HAVE_##feature ) + +#ifdef _HAS_CPP0X +# define any_HAS_CPP0X _HAS_CPP0X +#else +# define any_HAS_CPP0X 0 +#endif + +#define any_CPP11_90 (any_CPP11_OR_GREATER || any_COMPILER_MSVC_VER >= 1500) +#define any_CPP11_100 (any_CPP11_OR_GREATER || any_COMPILER_MSVC_VER >= 1600) +#define any_CPP11_120 (any_CPP11_OR_GREATER || any_COMPILER_MSVC_VER >= 1800) +#define any_CPP11_140 (any_CPP11_OR_GREATER || any_COMPILER_MSVC_VER >= 1900) + +#define any_CPP14_000 (any_CPP14_OR_GREATER) +#define any_CPP17_000 (any_CPP17_OR_GREATER) + +// Presence of C++11 language features: + +#define any_HAVE_CONSTEXPR_11 any_CPP11_140 +#define any_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG \ + any_CPP11_120 +#define any_HAVE_INITIALIZER_LIST any_CPP11_120 +#define any_HAVE_NOEXCEPT any_CPP11_140 +#define any_HAVE_NULLPTR any_CPP11_100 +#define any_HAVE_TYPE_TRAITS any_CPP11_90 +#define any_HAVE_STATIC_ASSERT any_CPP11_100 +#define any_HAVE_ADD_CONST any_CPP11_90 +#define any_HAVE_REMOVE_REFERENCE any_CPP11_90 + +#define any_HAVE_TR1_ADD_CONST (!! any_COMPILER_GNUC_VERSION ) +#define any_HAVE_TR1_REMOVE_REFERENCE (!! any_COMPILER_GNUC_VERSION ) +#define any_HAVE_TR1_TYPE_TRAITS (!! any_COMPILER_GNUC_VERSION ) + +// Presence of C++14 language features: + +#define any_HAVE_CONSTEXPR_14 any_CPP14_000 + +// Presence of C++17 language features: + +#define any_HAVE_NODISCARD any_CPP17_000 + +// Presence of C++ language features: + +#if any_HAVE_CONSTEXPR_11 +# define any_constexpr constexpr +#else +# define any_constexpr /*constexpr*/ +#endif + +#if any_HAVE_CONSTEXPR_14 +# define any_constexpr14 constexpr +#else +# define any_constexpr14 /*constexpr*/ +#endif + +#if any_HAVE_NOEXCEPT +# define any_noexcept noexcept +#else +# define any_noexcept /*noexcept*/ +#endif + +#if any_HAVE_NULLPTR +# define any_nullptr nullptr +#else +# define any_nullptr NULL +#endif + +#if any_HAVE_NODISCARD +# define any_nodiscard [[nodiscard]] +#else +# define any_nodiscard /*[[nodiscard]]*/ +#endif + +// additional includes: + +#if any_CONFIG_NO_EXCEPTIONS +# include +#else +# include +#endif + +#if ! any_HAVE_NULLPTR +# include +#endif + +#if any_HAVE_INITIALIZER_LIST +# include +#endif + +#if any_HAVE_TYPE_TRAITS +# include +#elif any_HAVE_TR1_TYPE_TRAITS +# include +#endif + +// Method enabling + +#if any_CPP11_OR_GREATER + +#define any_REQUIRES_0(...) \ + template< bool B = (__VA_ARGS__), typename std::enable_if::type = 0 > + +#define any_REQUIRES_T(...) \ + , typename = typename std::enable_if< (__VA_ARGS__), nonstd::any_lite::detail::enabler >::type + +#define any_REQUIRES_R(R, ...) \ + typename std::enable_if<__VA_ARGS__, R>::type + +#define any_REQUIRES_A(...) \ + , typename std::enable_if<__VA_ARGS__, void*>::type = nullptr + +#endif + +// +// any: +// + +namespace nonstd { namespace any_lite { + +// C++11 emulation: + +namespace std11 { + +#if any_HAVE_ADD_CONST + +using std::add_const; + +#elif any_HAVE_TR1_ADD_CONST + +using std::tr1::add_const; + +#else + +template< class T > struct add_const { typedef const T type; }; + +#endif // any_HAVE_ADD_CONST + +#if any_HAVE_REMOVE_REFERENCE + +using std::remove_reference; + +#elif any_HAVE_TR1_REMOVE_REFERENCE + +using std::tr1::remove_reference; + +#else + +template< class T > struct remove_reference { typedef T type; }; +template< class T > struct remove_reference { typedef T type; }; + +#endif // any_HAVE_REMOVE_REFERENCE + +} // namespace std11 + +namespace detail { + +// for any_REQUIRES_T + +/*enum*/ class enabler{}; + +} // namespace detail + +#if ! any_CONFIG_NO_EXCEPTIONS + +class bad_any_cast : public std::bad_cast +{ +public: +#if any_CPP11_OR_GREATER + virtual const char* what() const any_noexcept +#else + virtual const char* what() const throw() +#endif + { + return "any-lite: bad any_cast"; + } +}; + +#endif // any_CONFIG_NO_EXCEPTIONS + +class any +{ +public: + any_constexpr any() any_noexcept + : content( any_nullptr ) + {} + + any( any const & other ) + : content( other.content ? other.content->clone() : any_nullptr ) + {} + +#if any_CPP11_OR_GREATER + + any( any && other ) any_noexcept + : content( std::move( other.content ) ) + { + other.content = any_nullptr; + } + + template< + class ValueType, class T = typename std::decay::type + any_REQUIRES_T( ! std::is_same::value ) + > + any( ValueType && value ) any_noexcept + : content( new holder( std::move( value ) ) ) + {} + + template< + class T, class... Args + any_REQUIRES_T( std::is_constructible::value ) + > + explicit any( nonstd_lite_in_place_type_t(T), Args&&... args ) + : content( new holder( T( std::forward(args)... ) ) ) + {} + + template< + class T, class U, class... Args + any_REQUIRES_T( std::is_constructible&, Args&&...>::value ) + > + explicit any( nonstd_lite_in_place_type_t(T), std::initializer_list il, Args&&... args ) + : content( new holder( T( il, std::forward(args)... ) ) ) + {} + +#else + + template< class ValueType > + any( ValueType const & value ) + : content( new holder( value ) ) + {} + +#endif // any_CPP11_OR_GREATER + + ~any() + { + reset(); + } + + any & operator=( any const & other ) + { + any( other ).swap( *this ); + return *this; + } + +#if any_CPP11_OR_GREATER + + any & operator=( any && other ) any_noexcept + { + any( std::move( other ) ).swap( *this ); + return *this; + } + + template< + class ValueType, class T = typename std::decay::type + any_REQUIRES_T( ! std::is_same::value ) + > + any & operator=( ValueType && value ) + { + any( std::move( value ) ).swap( *this ); + return *this; + } + + template< class T, class... Args > + void emplace( Args && ... args ) + { + any( T( std::forward(args)... ) ).swap( *this ); + } + + template< + class T, class U, class... Args + any_REQUIRES_T( std::is_constructible&, Args&&...>::value ) + > + void emplace( std::initializer_list il, Args&&... args ) + { + any( T( il, std::forward(args)... ) ).swap( *this ); + } + +#else + + template< class ValueType > + any & operator=( ValueType const & value ) + { + any( value ).swap( *this ); + return *this; + } + +#endif // any_CPP11_OR_GREATER + + void reset() any_noexcept + { + delete content; content = any_nullptr; + } + + void swap( any & other ) any_noexcept + { + std::swap( content, other.content ); + } + + bool has_value() const any_noexcept + { + return content != any_nullptr; + } + + const std::type_info & type() const any_noexcept + { + return has_value() ? content->type() : typeid( void ); + } + + // + // non-standard: + // + + template< class ValueType > + const ValueType * to_ptr() const + { + return &( static_cast *>( content )->held ); + } + + template< class ValueType > + ValueType * to_ptr() + { + return &( static_cast *>( content )->held ); + } + +private: + class placeholder + { + public: + virtual ~placeholder() + { + } + + virtual std::type_info const & type() const = 0; + + virtual placeholder * clone() const = 0; + }; + + template< typename ValueType > + class holder : public placeholder + { + public: + holder( ValueType const & value ) + : held( value ) + {} + +#if any_CPP11_OR_GREATER + holder( ValueType && value ) + : held( std::move( value ) ) + {} +#endif + + virtual std::type_info const & type() const + { + return typeid( ValueType ); + } + + virtual placeholder * clone() const + { + return new holder( held ); + } + + ValueType held; + }; + + placeholder * content; +}; + +inline void swap( any & x, any & y ) any_noexcept +{ + x.swap( y ); +} + +#if any_CPP11_OR_GREATER + +template< class T, class ...Args > +inline any make_any( Args&& ...args ) +{ + return any( nonstd_lite_in_place_type(T), std::forward(args)...); +} + +template< class T, class U, class ...Args > +inline any make_any( std::initializer_list il, Args&& ...args ) +{ + return any( nonstd_lite_in_place_type(T), il, std::forward(args)...); +} + +#endif // any_CPP11_OR_GREATER + +template< + class ValueType +#if any_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG +// any_REQUIRES_T(...) Allow for VC120 (VS2013): + , typename = typename std::enable_if< (std::is_reference::value || std::is_copy_constructible::value), nonstd::any_lite::detail::enabler >::type +#endif +> +any_nodiscard inline ValueType any_cast( any const & operand ) +{ + const ValueType * result = any_cast< typename std11::add_const< typename std11::remove_reference::type >::type >( &operand ); + +#if any_CONFIG_NO_EXCEPTIONS + assert( result ); +#else + if ( ! result ) + { + throw bad_any_cast(); + } +#endif + + return *result; +} + +template< + class ValueType +#if any_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG +// any_REQUIRES_T(...) Allow for VC120 (VS2013): + , typename = typename std::enable_if< (std::is_reference::value || std::is_copy_constructible::value), nonstd::any_lite::detail::enabler >::type +#endif +> +any_nodiscard inline ValueType any_cast( any & operand ) +{ + const ValueType * result = any_cast< typename std11::remove_reference::type >( &operand ); + +#if any_CONFIG_NO_EXCEPTIONS + assert( result ); +#else + if ( ! result ) + { + throw bad_any_cast(); + } +#endif + + return *result; +} + +#if any_CPP11_OR_GREATER + +template< + class ValueType +#if any_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG + any_REQUIRES_T( std::is_reference::value || std::is_copy_constructible::value ) +#endif +> +any_nodiscard inline ValueType any_cast( any && operand ) +{ + const ValueType * result = any_cast< typename std11::remove_reference::type >( &operand ); + +#if any_CONFIG_NO_EXCEPTIONS + assert( result ); +#else + if ( ! result ) + { + throw bad_any_cast(); + } +#endif + + return *result; +} + +#endif // any_CPP11_OR_GREATER + +template< class ValueType > +any_nodiscard inline ValueType const * any_cast( any const * operand ) any_noexcept +{ + return operand != any_nullptr && operand->type() == typeid(ValueType) ? operand->to_ptr() : any_nullptr; +} + +template +any_nodiscard inline ValueType * any_cast( any * operand ) any_noexcept +{ + return operand != any_nullptr && operand->type() == typeid(ValueType) ? operand->to_ptr() : any_nullptr; +} + +} // namespace any_lite + +using namespace any_lite; + +} // namespace nonstd + +#endif // any_USES_STD_ANY + +#endif // NONSTD_ANY_LITE_HPP diff --git a/ndn-cxx/util/nonstd/optional.hpp b/ndn-cxx/util/nonstd/optional.hpp new file mode 100644 index 000000000..d05d1c59b --- /dev/null +++ b/ndn-cxx/util/nonstd/optional.hpp @@ -0,0 +1,1698 @@ +// +// Copyright (c) 2014-2018 Martin Moene +// +// https://github.com/martinmoene/optional-lite +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#pragma once + +#ifndef NONSTD_OPTIONAL_LITE_HPP +#define NONSTD_OPTIONAL_LITE_HPP + +#define optional_lite_MAJOR 3 +#define optional_lite_MINOR 1 +#define optional_lite_PATCH 1 + +#define optional_lite_VERSION optional_STRINGIFY(optional_lite_MAJOR) "." optional_STRINGIFY(optional_lite_MINOR) "." optional_STRINGIFY(optional_lite_PATCH) + +#define optional_STRINGIFY( x ) optional_STRINGIFY_( x ) +#define optional_STRINGIFY_( x ) #x + +// optional-lite configuration: + +#define optional_OPTIONAL_DEFAULT 0 +#define optional_OPTIONAL_NONSTD 1 +#define optional_OPTIONAL_STD 2 + +#if !defined( optional_CONFIG_SELECT_OPTIONAL ) +# define optional_CONFIG_SELECT_OPTIONAL ( optional_HAVE_STD_OPTIONAL ? optional_OPTIONAL_STD : optional_OPTIONAL_NONSTD ) +#endif + +// Control presence of exception handling (try and auto discover): + +#ifndef optional_CONFIG_NO_EXCEPTIONS +# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) +# define optional_CONFIG_NO_EXCEPTIONS 0 +# else +# define optional_CONFIG_NO_EXCEPTIONS 1 +# endif +#endif + +// C++ language version detection (C++20 is speculative): +// Note: VC14.0/1900 (VS2015) lacks too much from C++14. + +#ifndef optional_CPLUSPLUS +# if defined(_MSVC_LANG ) && !defined(__clang__) +# define optional_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) +# else +# define optional_CPLUSPLUS __cplusplus +# endif +#endif + +#define optional_CPP98_OR_GREATER ( optional_CPLUSPLUS >= 199711L ) +#define optional_CPP11_OR_GREATER ( optional_CPLUSPLUS >= 201103L ) +#define optional_CPP11_OR_GREATER_ ( optional_CPLUSPLUS >= 201103L ) +#define optional_CPP14_OR_GREATER ( optional_CPLUSPLUS >= 201402L ) +#define optional_CPP17_OR_GREATER ( optional_CPLUSPLUS >= 201703L ) +#define optional_CPP20_OR_GREATER ( optional_CPLUSPLUS >= 202000L ) + +// C++ language version (represent 98 as 3): + +#define optional_CPLUSPLUS_V ( optional_CPLUSPLUS / 100 - (optional_CPLUSPLUS > 200000 ? 2000 : 1994) ) + +// Use C++17 std::optional if available and requested: + +#if optional_CPP17_OR_GREATER && defined(__has_include ) +# if __has_include( ) +# define optional_HAVE_STD_OPTIONAL 1 +# else +# define optional_HAVE_STD_OPTIONAL 0 +# endif +#else +# define optional_HAVE_STD_OPTIONAL 0 +#endif + +#define optional_USES_STD_OPTIONAL ( (optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_STD) || ((optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_DEFAULT) && optional_HAVE_STD_OPTIONAL) ) + +// +// in_place: code duplicated in any-lite, expected-lite, optional-lite, value-ptr-lite, variant-lite: +// + +#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES +#define nonstd_lite_HAVE_IN_PLACE_TYPES 1 + +// C++17 std::in_place in : + +#if optional_CPP17_OR_GREATER + +#include + +namespace nonstd { + +using std::in_place; +using std::in_place_type; +using std::in_place_index; +using std::in_place_t; +using std::in_place_type_t; +using std::in_place_index_t; + +#define nonstd_lite_in_place_t( T) std::in_place_t +#define nonstd_lite_in_place_type_t( T) std::in_place_type_t +#define nonstd_lite_in_place_index_t(K) std::in_place_index_t + +#define nonstd_lite_in_place( T) std::in_place_t{} +#define nonstd_lite_in_place_type( T) std::in_place_type_t{} +#define nonstd_lite_in_place_index(K) std::in_place_index_t{} + +} // namespace nonstd + +#else // optional_CPP17_OR_GREATER + +#include + +namespace nonstd { +namespace detail { + +template< class T > +struct in_place_type_tag {}; + +template< std::size_t K > +struct in_place_index_tag {}; + +} // namespace detail + +struct in_place_t {}; + +template< class T > +inline in_place_t in_place( detail::in_place_type_tag /*unused*/ = detail::in_place_type_tag() ) +{ + return in_place_t(); +} + +template< std::size_t K > +inline in_place_t in_place( detail::in_place_index_tag /*unused*/ = detail::in_place_index_tag() ) +{ + return in_place_t(); +} + +template< class T > +inline in_place_t in_place_type( detail::in_place_type_tag /*unused*/ = detail::in_place_type_tag() ) +{ + return in_place_t(); +} + +template< std::size_t K > +inline in_place_t in_place_index( detail::in_place_index_tag /*unused*/ = detail::in_place_index_tag() ) +{ + return in_place_t(); +} + +// mimic templated typedef: + +#define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) +#define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) +#define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag ) + +#define nonstd_lite_in_place( T) nonstd::in_place_type +#define nonstd_lite_in_place_type( T) nonstd::in_place_type +#define nonstd_lite_in_place_index(K) nonstd::in_place_index + +} // namespace nonstd + +#endif // optional_CPP17_OR_GREATER +#endif // nonstd_lite_HAVE_IN_PLACE_TYPES + +// +// Using std::optional: +// + +#if optional_USES_STD_OPTIONAL + +#include + +namespace nonstd { + + using std::optional; + using std::bad_optional_access; + using std::hash; + + using std::nullopt; + using std::nullopt_t; + + using std::operator==; + using std::operator!=; + using std::operator<; + using std::operator<=; + using std::operator>; + using std::operator>=; + using std::make_optional; + using std::swap; +} + +#else // optional_USES_STD_OPTIONAL + +#include +#include + +// optional-lite alignment configuration: + +#ifndef optional_CONFIG_MAX_ALIGN_HACK +# define optional_CONFIG_MAX_ALIGN_HACK 0 +#endif + +#ifndef optional_CONFIG_ALIGN_AS +// no default, used in #if defined() +#endif + +#ifndef optional_CONFIG_ALIGN_AS_FALLBACK +# define optional_CONFIG_ALIGN_AS_FALLBACK double +#endif + +// Compiler warning suppression: + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wundef" +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wundef" +#elif defined(_MSC_VER ) +# pragma warning( push ) +#endif + +// half-open range [lo..hi): +#define optional_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) + +// Compiler versions: +// +// MSVC++ 6.0 _MSC_VER == 1200 (Visual Studio 6.0) +// MSVC++ 7.0 _MSC_VER == 1300 (Visual Studio .NET 2002) +// MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio .NET 2003) +// MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) +// MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) +// MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) +// MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) +// MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) +// MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) +// MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017) + +#if defined(_MSC_VER ) && !defined(__clang__) +# define optional_COMPILER_MSVC_VER (_MSC_VER ) +# define optional_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) +#else +# define optional_COMPILER_MSVC_VER 0 +# define optional_COMPILER_MSVC_VERSION 0 +#endif + +#define optional_COMPILER_VERSION( major, minor, patch ) ( 10 * (10 * (major) + (minor) ) + (patch) ) + +#if defined(__GNUC__) && !defined(__clang__) +# define optional_COMPILER_GNUC_VERSION optional_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#else +# define optional_COMPILER_GNUC_VERSION 0 +#endif + +#if defined(__clang__) +# define optional_COMPILER_CLANG_VERSION optional_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) +#else +# define optional_COMPILER_CLANG_VERSION 0 +#endif + +#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 140 ) +# pragma warning( disable: 4345 ) // initialization behavior changed +#endif + +#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 150 ) +# pragma warning( disable: 4814 ) // in C++14 'constexpr' will not imply 'const' +#endif + +// Presence of language and library features: + +#define optional_HAVE(FEATURE) ( optional_HAVE_##FEATURE ) + +#ifdef _HAS_CPP0X +# define optional_HAS_CPP0X _HAS_CPP0X +#else +# define optional_HAS_CPP0X 0 +#endif + +// Unless defined otherwise below, consider VC14 as C++11 for optional-lite: + +#if optional_COMPILER_MSVC_VER >= 1900 +# undef optional_CPP11_OR_GREATER +# define optional_CPP11_OR_GREATER 1 +#endif + +#define optional_CPP11_90 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1500) +#define optional_CPP11_100 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1600) +#define optional_CPP11_110 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1700) +#define optional_CPP11_120 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1800) +#define optional_CPP11_140 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1900) +#define optional_CPP11_141 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1910) + +#define optional_CPP14_000 (optional_CPP14_OR_GREATER) +#define optional_CPP17_000 (optional_CPP17_OR_GREATER) + +// Presence of C++11 language features: + +#define optional_HAVE_CONSTEXPR_11 optional_CPP11_140 +#define optional_HAVE_IS_DEFAULT optional_CPP11_140 +#define optional_HAVE_NOEXCEPT optional_CPP11_140 +#define optional_HAVE_NULLPTR optional_CPP11_100 +#define optional_HAVE_REF_QUALIFIER optional_CPP11_140 + +// Presence of C++14 language features: + +#define optional_HAVE_CONSTEXPR_14 optional_CPP14_000 + +// Presence of C++17 language features: + +#define optional_HAVE_NODISCARD optional_CPP17_000 + +// Presence of C++ library features: + +#define optional_HAVE_CONDITIONAL optional_CPP11_120 +#define optional_HAVE_REMOVE_CV optional_CPP11_120 +#define optional_HAVE_TYPE_TRAITS optional_CPP11_90 + +#define optional_HAVE_TR1_TYPE_TRAITS (!! optional_COMPILER_GNUC_VERSION ) +#define optional_HAVE_TR1_ADD_POINTER (!! optional_COMPILER_GNUC_VERSION ) + +// C++ feature usage: + +#if optional_HAVE( CONSTEXPR_11 ) +# define optional_constexpr constexpr +#else +# define optional_constexpr /*constexpr*/ +#endif + +#if optional_HAVE( IS_DEFAULT ) +# define optional_is_default = default; +#else +# define optional_is_default {} +#endif + +#if optional_HAVE( CONSTEXPR_14 ) +# define optional_constexpr14 constexpr +#else +# define optional_constexpr14 /*constexpr*/ +#endif + +#if optional_HAVE( NODISCARD ) +# define optional_nodiscard [[nodiscard]] +#else +# define optional_nodiscard /*[[nodiscard]]*/ +#endif + +#if optional_HAVE( NOEXCEPT ) +# define optional_noexcept noexcept +#else +# define optional_noexcept /*noexcept*/ +#endif + +#if optional_HAVE( NULLPTR ) +# define optional_nullptr nullptr +#else +# define optional_nullptr NULL +#endif + +#if optional_HAVE( REF_QUALIFIER ) +// NOLINTNEXTLINE( bugprone-macro-parentheses ) +# define optional_ref_qual & +# define optional_refref_qual && +#else +# define optional_ref_qual /*&*/ +# define optional_refref_qual /*&&*/ +#endif + +// additional includes: + +#if optional_CONFIG_NO_EXCEPTIONS +// already included: +#else +# include +#endif + +#if optional_CPP11_OR_GREATER +# include +#endif + +#if optional_HAVE( INITIALIZER_LIST ) +# include +#endif + +#if optional_HAVE( TYPE_TRAITS ) +# include +#elif optional_HAVE( TR1_TYPE_TRAITS ) +# include +#endif + +// Method enabling + +#if optional_CPP11_OR_GREATER + +#define optional_REQUIRES_0(...) \ + template< bool B = (__VA_ARGS__), typename std::enable_if::type = 0 > + +#define optional_REQUIRES_T(...) \ + , typename = typename std::enable_if< (__VA_ARGS__), nonstd::optional_lite::detail::enabler >::type + +#define optional_REQUIRES_R(R, ...) \ + typename std::enable_if< (__VA_ARGS__), R>::type + +#define optional_REQUIRES_A(...) \ + , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr + +#endif + +// +// optional: +// + +namespace nonstd { namespace optional_lite { + +namespace std11 { + +#if optional_CPP11_OR_GREATER + using std::move; +#else + template< typename T > T & move( T & t ) { return t; } +#endif + +#if optional_HAVE( CONDITIONAL ) + using std::conditional; +#else + template< bool B, typename T, typename F > struct conditional { typedef T type; }; + template< typename T, typename F > struct conditional { typedef F type; }; +#endif // optional_HAVE_CONDITIONAL + +} // namespace std11 + +#if optional_CPP11_OR_GREATER + +/// type traits C++17: + +namespace std17 { + +#if optional_CPP17_OR_GREATER + +using std::is_swappable; +using std::is_nothrow_swappable; + +#elif optional_CPP11_OR_GREATER + +namespace detail { + +using std::swap; + +struct is_swappable +{ + template< typename T, typename = decltype( swap( std::declval(), std::declval() ) ) > + static std::true_type test( int /*unused*/ ); + + template< typename > + static std::false_type test(...); +}; + +struct is_nothrow_swappable +{ + // wrap noexcept(expr) in separate function as work-around for VC140 (VS2015): + + template< typename T > + static constexpr bool satisfies() + { + return noexcept( swap( std::declval(), std::declval() ) ); + } + + template< typename T > + static auto test( int /*unused*/ ) -> std::integral_constant()>{} + + template< typename > + static auto test(...) -> std::false_type; +}; + +} // namespace detail + +// is [nothow] swappable: + +template< typename T > +struct is_swappable : decltype( detail::is_swappable::test(0) ){}; + +template< typename T > +struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test(0) ){}; + +#endif // optional_CPP17_OR_GREATER + +} // namespace std17 + +/// type traits C++20: + +namespace std20 { + +template< typename T > +struct remove_cvref +{ + typedef typename std::remove_cv< typename std::remove_reference::type >::type type; +}; + +} // namespace std20 + +#endif // optional_CPP11_OR_GREATER + +/// class optional + +template< typename T > +class optional; + +namespace detail { + +// for optional_REQUIRES_T + +#if optional_CPP11_OR_GREATER +enum class enabler{}; +#endif + +// C++11 emulation: + +struct nulltype{}; + +template< typename Head, typename Tail > +struct typelist +{ + typedef Head head; + typedef Tail tail; +}; + +#if optional_CONFIG_MAX_ALIGN_HACK + +// Max align, use most restricted type for alignment: + +#define optional_UNIQUE( name ) optional_UNIQUE2( name, __LINE__ ) +#define optional_UNIQUE2( name, line ) optional_UNIQUE3( name, line ) +#define optional_UNIQUE3( name, line ) name ## line + +#define optional_ALIGN_TYPE( type ) \ + type optional_UNIQUE( _t ); struct_t< type > optional_UNIQUE( _st ) + +template< typename T > +struct struct_t { T _; }; + +union max_align_t +{ + optional_ALIGN_TYPE( char ); + optional_ALIGN_TYPE( short int ); + optional_ALIGN_TYPE( int ); + optional_ALIGN_TYPE( long int ); + optional_ALIGN_TYPE( float ); + optional_ALIGN_TYPE( double ); + optional_ALIGN_TYPE( long double ); + optional_ALIGN_TYPE( char * ); + optional_ALIGN_TYPE( short int * ); + optional_ALIGN_TYPE( int * ); + optional_ALIGN_TYPE( long int * ); + optional_ALIGN_TYPE( float * ); + optional_ALIGN_TYPE( double * ); + optional_ALIGN_TYPE( long double * ); + optional_ALIGN_TYPE( void * ); + +#ifdef HAVE_LONG_LONG + optional_ALIGN_TYPE( long long ); +#endif + + struct Unknown; + + Unknown ( * optional_UNIQUE(_) )( Unknown ); + Unknown * Unknown::* optional_UNIQUE(_); + Unknown ( Unknown::* optional_UNIQUE(_) )( Unknown ); + + struct_t< Unknown ( * )( Unknown) > optional_UNIQUE(_); + struct_t< Unknown * Unknown::* > optional_UNIQUE(_); + struct_t< Unknown ( Unknown::* )(Unknown) > optional_UNIQUE(_); +}; + +#undef optional_UNIQUE +#undef optional_UNIQUE2 +#undef optional_UNIQUE3 + +#undef optional_ALIGN_TYPE + +#elif defined( optional_CONFIG_ALIGN_AS ) // optional_CONFIG_MAX_ALIGN_HACK + +// Use user-specified type for alignment: + +#define optional_ALIGN_AS( unused ) \ + optional_CONFIG_ALIGN_AS + +#else // optional_CONFIG_MAX_ALIGN_HACK + +// Determine POD type to use for alignment: + +#define optional_ALIGN_AS( to_align ) \ + typename type_of_size< alignment_types, alignment_of< to_align >::value >::type + +template< typename T > +struct alignment_of; + +template< typename T > +struct alignment_of_hack +{ + char c; + T t; + alignment_of_hack(); +}; + +template< size_t A, size_t S > +struct alignment_logic +{ + enum { value = A < S ? A : S }; +}; + +template< typename T > +struct alignment_of +{ + enum { value = alignment_logic< + sizeof( alignment_of_hack ) - sizeof(T), sizeof(T) >::value }; +}; + +template< typename List, size_t N > +struct type_of_size +{ + typedef typename std11::conditional< + N == sizeof( typename List::head ), + typename List::head, + typename type_of_size::type >::type type; +}; + +template< size_t N > +struct type_of_size< nulltype, N > +{ + typedef optional_CONFIG_ALIGN_AS_FALLBACK type; +}; + +template< typename T> +struct struct_t { T _; }; + +#define optional_ALIGN_TYPE( type ) \ + typelist< type , typelist< struct_t< type > + +struct Unknown; + +typedef + optional_ALIGN_TYPE( char ), + optional_ALIGN_TYPE( short ), + optional_ALIGN_TYPE( int ), + optional_ALIGN_TYPE( long ), + optional_ALIGN_TYPE( float ), + optional_ALIGN_TYPE( double ), + optional_ALIGN_TYPE( long double ), + + optional_ALIGN_TYPE( char *), + optional_ALIGN_TYPE( short * ), + optional_ALIGN_TYPE( int * ), + optional_ALIGN_TYPE( long * ), + optional_ALIGN_TYPE( float * ), + optional_ALIGN_TYPE( double * ), + optional_ALIGN_TYPE( long double * ), + + optional_ALIGN_TYPE( Unknown ( * )( Unknown ) ), + optional_ALIGN_TYPE( Unknown * Unknown::* ), + optional_ALIGN_TYPE( Unknown ( Unknown::* )( Unknown ) ), + + nulltype + > > > > > > > > > > > > > > + > > > > > > > > > > > > > > + > > > > > > + alignment_types; + +#undef optional_ALIGN_TYPE + +#endif // optional_CONFIG_MAX_ALIGN_HACK + +/// C++03 constructed union to hold value. + +template< typename T > +union storage_t +{ +//private: +// template< typename > friend class optional; + + typedef T value_type; + + storage_t() optional_is_default + + explicit storage_t( value_type const & v ) + { + construct_value( v ); + } + + void construct_value( value_type const & v ) + { + ::new( value_ptr() ) value_type( v ); + } + +#if optional_CPP11_OR_GREATER + + explicit storage_t( value_type && v ) + { + construct_value( std::move( v ) ); + } + + void construct_value( value_type && v ) + { + ::new( value_ptr() ) value_type( std::move( v ) ); + } + + template< class... Args > + void emplace( Args&&... args ) + { + ::new( value_ptr() ) value_type( std::forward(args)... ); + } + + template< class U, class... Args > + void emplace( std::initializer_list il, Args&&... args ) + { + ::new( value_ptr() ) value_type( il, std::forward(args)... ); + } + +#endif + + void destruct_value() + { + value_ptr()->~T(); + } + + optional_nodiscard value_type const * value_ptr() const + { + return as(); + } + + value_type * value_ptr() + { + return as(); + } + + optional_nodiscard value_type const & value() const optional_ref_qual + { + return * value_ptr(); + } + + value_type & value() optional_ref_qual + { + return * value_ptr(); + } + +#if optional_CPP11_OR_GREATER + + optional_nodiscard value_type const && value() const optional_refref_qual + { + return std::move( value() ); + } + + value_type && value() optional_refref_qual + { + return std::move( value() ); + } + +#endif + +#if optional_CPP11_OR_GREATER + + using aligned_storage_t = typename std::aligned_storage< sizeof(value_type), alignof(value_type) >::type; + aligned_storage_t data; + +#elif optional_CONFIG_MAX_ALIGN_HACK + + typedef struct { unsigned char data[ sizeof(value_type) ]; } aligned_storage_t; + + max_align_t hack; + aligned_storage_t data; + +#else + typedef optional_ALIGN_AS(value_type) align_as_type; + + typedef struct { align_as_type data[ 1 + ( sizeof(value_type) - 1 ) / sizeof(align_as_type) ]; } aligned_storage_t; + aligned_storage_t data; + +# undef optional_ALIGN_AS + +#endif // optional_CONFIG_MAX_ALIGN_HACK + + optional_nodiscard void * ptr() optional_noexcept + { + return &data; + } + + optional_nodiscard void const * ptr() const optional_noexcept + { + return &data; + } + + template + optional_nodiscard U * as() + { + return reinterpret_cast( ptr() ); + } + + template + optional_nodiscard U const * as() const + { + return reinterpret_cast( ptr() ); + } +}; + +} // namespace detail + +/// disengaged state tag + +struct nullopt_t +{ + struct init{}; + explicit optional_constexpr nullopt_t( init /*unused*/ ) optional_noexcept {} +}; + +#if optional_HAVE( CONSTEXPR_11 ) +constexpr nullopt_t nullopt{ nullopt_t::init{} }; +#else +// extra parenthesis to prevent the most vexing parse: +const nullopt_t nullopt(( nullopt_t::init() )); +#endif + +/// optional access error + +#if ! optional_CONFIG_NO_EXCEPTIONS + +class bad_optional_access : public std::logic_error +{ +public: + explicit bad_optional_access() + : logic_error( "bad optional access" ) {} +}; + +#endif //optional_CONFIG_NO_EXCEPTIONS + +/// optional + +template< typename T> +class optional +{ +private: + template< typename > friend class optional; + + typedef void (optional::*safe_bool)() const; + +public: + typedef T value_type; + + // x.x.3.1, constructors + + // 1a - default construct + optional_constexpr optional() optional_noexcept + : has_value_( false ) + , contained() + {} + + // 1b - construct explicitly empty + // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) + optional_constexpr optional( nullopt_t /*unused*/ ) optional_noexcept + : has_value_( false ) + , contained() + {} + + // 2 - copy-construct + optional_constexpr14 optional( optional const & other +#if optional_CPP11_OR_GREATER + optional_REQUIRES_A( + true || std::is_copy_constructible::value + ) +#endif + ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( other.contained.value() ); + } + } + +#if optional_CPP11_OR_GREATER + + // 3 (C++11) - move-construct from optional + optional_constexpr14 optional( optional && other + optional_REQUIRES_A( + true || std::is_move_constructible::value + ) + // NOLINTNEXTLINE( performance-noexcept-move-constructor ) + ) noexcept( std::is_nothrow_move_constructible::value ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( std::move( other.contained.value() ) ); + } + } + + // 4a (C++11) - explicit converting copy-construct from optional + template< typename U > + explicit optional( optional const & other + optional_REQUIRES_A( + std::is_constructible::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && !std::is_convertible< U const & , T>::value /*=> explicit */ + ) + ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( T{ other.contained.value() } ); + } + } +#endif // optional_CPP11_OR_GREATER + + // 4b (C++98 and later) - non-explicit converting copy-construct from optional + template< typename U > + // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) + optional( optional const & other +#if optional_CPP11_OR_GREATER + optional_REQUIRES_A( + std::is_constructible::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && std::is_convertible< U const & , T>::value /*=> non-explicit */ + ) +#endif // optional_CPP11_OR_GREATER + ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( other.contained.value() ); + } + } + +#if optional_CPP11_OR_GREATER + + // 5a (C++11) - explicit converting move-construct from optional + template< typename U > + explicit optional( optional && other + optional_REQUIRES_A( + std::is_constructible::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && !std::is_convertible< U &&, T>::value /*=> explicit */ + ) + ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( T{ std::move( other.contained.value() ) } ); + } + } + + // 5a (C++11) - non-explicit converting move-construct from optional + template< typename U > + // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) + optional( optional && other + optional_REQUIRES_A( + std::is_constructible::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && std::is_convertible< U &&, T>::value /*=> non-explicit */ + ) + ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( std::move( other.contained.value() ) ); + } + } + + // 6 (C++11) - in-place construct + template< typename... Args + optional_REQUIRES_T( + std::is_constructible::value + ) + > + optional_constexpr explicit optional( nonstd_lite_in_place_t(T), Args&&... args ) + : has_value_( true ) + , contained( T( std::forward(args)...) ) + {} + + // 7 (C++11) - in-place construct, initializer-list + template< typename U, typename... Args + optional_REQUIRES_T( + std::is_constructible&, Args&&...>::value + ) + > + optional_constexpr explicit optional( nonstd_lite_in_place_t(T), std::initializer_list il, Args&&... args ) + : has_value_( true ) + , contained( T( il, std::forward(args)...) ) + {} + + // 8a (C++11) - explicit move construct from value + template< typename U = value_type > + optional_constexpr explicit optional( U && value + optional_REQUIRES_A( + std::is_constructible::value + && !std::is_same::type, nonstd_lite_in_place_t(U)>::value + && !std::is_same::type, optional>::value + && !std::is_convertible::value /*=> explicit */ + ) + ) + : has_value_( true ) + , contained( T{ std::forward( value ) } ) + {} + + // 8b (C++11) - non-explicit move construct from value + template< typename U = value_type > + // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) + optional_constexpr optional( U && value + optional_REQUIRES_A( + std::is_constructible::value + && !std::is_same::type, nonstd_lite_in_place_t(U)>::value + && !std::is_same::type, optional>::value + && std::is_convertible::value /*=> non-explicit */ + ) + ) + : has_value_( true ) + , contained( std::forward( value ) ) + {} + +#else // optional_CPP11_OR_GREATER + + // 8 (C++98) + optional( value_type const & value ) + : has_value_( true ) + , contained( value ) + {} + +#endif // optional_CPP11_OR_GREATER + + // x.x.3.2, destructor + + ~optional() + { + if ( has_value() ) + { + contained.destruct_value(); + } + } + + // x.x.3.3, assignment + + // 1 (C++98and later) - assign explicitly empty + optional & operator=( nullopt_t /*unused*/) optional_noexcept + { + reset(); + return *this; + } + + // 2 (C++98and later) - copy-assign from optional +#if optional_CPP11_OR_GREATER + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional &, + true +// std::is_copy_constructible::value +// && std::is_copy_assignable::value + ) + operator=( optional const & other ) + noexcept( + std::is_nothrow_move_assignable::value + && std::is_nothrow_move_constructible::value + ) +#else + optional & operator=( optional const & other ) +#endif + { + if ( (has_value() == true ) && (other.has_value() == false) ) { reset(); } + else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( *other ); } + else if ( (has_value() == true ) && (other.has_value() == true ) ) { contained.value() = *other; } + return *this; + } + +#if optional_CPP11_OR_GREATER + + // 3 (C++11) - move-assign from optional + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional &, + true +// std::is_move_constructible::value +// && std::is_move_assignable::value + ) + operator=( optional && other ) noexcept + { + if ( (has_value() == true ) && (other.has_value() == false) ) { reset(); } + else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( std::move( *other ) ); } + else if ( (has_value() == true ) && (other.has_value() == true ) ) { contained.value() = std::move( *other ); } + return *this; + } + + // 4 (C++11) - move-assign from value + template< typename U = T > + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional &, + std::is_constructible::value + && std::is_assignable::value + && !std::is_same::type, nonstd_lite_in_place_t(U)>::value + && !std::is_same::type, optional>::value + && !(std::is_scalar::value && std::is_same::type>::value) + ) + operator=( U && value ) + { + if ( has_value() ) + { + contained.value() = std::forward( value ); + } + else + { + initialize( T( std::forward( value ) ) ); + } + return *this; + } + +#else // optional_CPP11_OR_GREATER + + // 4 (C++98) - copy-assign from value + template< typename U /*= T*/ > + optional & operator=( U const & value ) + { + if ( has_value() ) contained.value() = value; + else initialize( T( value ) ); + return *this; + } + +#endif // optional_CPP11_OR_GREATER + + // 5 (C++98 and later) - converting copy-assign from optional + template< typename U > +#if optional_CPP11_OR_GREATER + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional&, + std::is_constructible< T , U const &>::value + && std::is_assignable< T&, U const &>::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && !std::is_assignable< T&, optional & >::value + && !std::is_assignable< T&, optional && >::value + && !std::is_assignable< T&, optional const & >::value + && !std::is_assignable< T&, optional const && >::value + ) +#else + optional& +#endif // optional_CPP11_OR_GREATER + operator=( optional const & other ) + { + return *this = optional( other ); + } + +#if optional_CPP11_OR_GREATER + + // 6 (C++11) - converting move-assign from optional + template< typename U > + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional&, + std::is_constructible< T , U>::value + && std::is_assignable< T&, U>::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && !std::is_assignable< T&, optional & >::value + && !std::is_assignable< T&, optional && >::value + && !std::is_assignable< T&, optional const & >::value + && !std::is_assignable< T&, optional const && >::value + ) + operator=( optional && other ) + { + return *this = optional( std::move( other ) ); + } + + // 7 (C++11) - emplace + template< typename... Args + optional_REQUIRES_T( + std::is_constructible::value + ) + > + T& emplace( Args&&... args ) + { + *this = nullopt; + contained.emplace( std::forward(args)... ); + has_value_ = true; + return contained.value(); + } + + // 8 (C++11) - emplace, initializer-list + template< typename U, typename... Args + optional_REQUIRES_T( + std::is_constructible&, Args&&...>::value + ) + > + T& emplace( std::initializer_list il, Args&&... args ) + { + *this = nullopt; + contained.emplace( il, std::forward(args)... ); + has_value_ = true; + return contained.value(); + } + +#endif // optional_CPP11_OR_GREATER + + // x.x.3.4, swap + + void swap( optional & other ) +#if optional_CPP11_OR_GREATER + noexcept( + std::is_nothrow_move_constructible::value + && std17::is_nothrow_swappable::value + ) +#endif + { + using std::swap; + if ( (has_value() == true ) && (other.has_value() == true ) ) { swap( **this, *other ); } + else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( std11::move(*other) ); other.reset(); } + else if ( (has_value() == true ) && (other.has_value() == false) ) { other.initialize( std11::move(**this) ); reset(); } + } + + // x.x.3.5, observers + + optional_constexpr value_type const * operator ->() const + { + return assert( has_value() ), + contained.value_ptr(); + } + + optional_constexpr14 value_type * operator ->() + { + return assert( has_value() ), + contained.value_ptr(); + } + + optional_constexpr value_type const & operator *() const optional_ref_qual + { + return assert( has_value() ), + contained.value(); + } + + optional_constexpr14 value_type & operator *() optional_ref_qual + { + return assert( has_value() ), + contained.value(); + } + +#if optional_HAVE( REF_QUALIFIER ) && ( !optional_COMPILER_GNUC_VERSION || optional_COMPILER_GNUC_VERSION >= 490 ) + + optional_constexpr value_type const && operator *() const optional_refref_qual + { + return std::move( **this ); + } + + optional_constexpr14 value_type && operator *() optional_refref_qual + { + return std::move( **this ); + } + +#endif + +#if optional_CPP11_OR_GREATER + optional_constexpr explicit operator bool() const optional_noexcept + { + return has_value(); + } +#else + optional_constexpr operator safe_bool() const optional_noexcept + { + return has_value() ? &optional::this_type_does_not_support_comparisons : 0; + } +#endif + + // NOLINTNEXTLINE( modernize-use-nodiscard ) + /*optional_nodiscard*/ optional_constexpr bool has_value() const optional_noexcept + { + return has_value_; + } + + // NOLINTNEXTLINE( modernize-use-nodiscard ) + /*optional_nodiscard*/ optional_constexpr14 value_type const & value() const optional_ref_qual + { +#if optional_CONFIG_NO_EXCEPTIONS + assert( has_value() ); +#else + if ( ! has_value() ) + { + throw bad_optional_access(); + } +#endif + return contained.value(); + } + + optional_constexpr14 value_type & value() optional_ref_qual + { +#if optional_CONFIG_NO_EXCEPTIONS + assert( has_value() ); +#else + if ( ! has_value() ) + { + throw bad_optional_access(); + } +#endif + return contained.value(); + } + +#if optional_HAVE( REF_QUALIFIER ) && ( !optional_COMPILER_GNUC_VERSION || optional_COMPILER_GNUC_VERSION >= 490 ) + + // NOLINTNEXTLINE( modernize-use-nodiscard ) + /*optional_nodiscard*/ optional_constexpr value_type const && value() const optional_refref_qual + { + return std::move( value() ); + } + + optional_constexpr14 value_type && value() optional_refref_qual + { + return std::move( value() ); + } + +#endif + +#if optional_CPP11_OR_GREATER + + template< typename U > + optional_constexpr value_type value_or( U && v ) const optional_ref_qual + { + return has_value() ? contained.value() : static_cast(std::forward( v ) ); + } + + template< typename U > + optional_constexpr14 value_type value_or( U && v ) optional_refref_qual + { + return has_value() ? std::move( contained.value() ) : static_cast(std::forward( v ) ); + } + +#else + + template< typename U > + optional_constexpr value_type value_or( U const & v ) const + { + return has_value() ? contained.value() : static_cast( v ); + } + +#endif // optional_CPP11_OR_GREATER + + // x.x.3.6, modifiers + + void reset() optional_noexcept + { + if ( has_value() ) + { + contained.destruct_value(); + } + + has_value_ = false; + } + +private: + void this_type_does_not_support_comparisons() const {} + + template< typename V > + void initialize( V const & value ) + { + assert( ! has_value() ); + contained.construct_value( value ); + has_value_ = true; + } + +#if optional_CPP11_OR_GREATER + template< typename V > + void initialize( V && value ) + { + assert( ! has_value() ); + contained.construct_value( std::move( value ) ); + has_value_ = true; + } + +#endif + +private: + bool has_value_; + detail::storage_t< value_type > contained; + +}; + +// Relational operators + +template< typename T, typename U > +inline optional_constexpr bool operator==( optional const & x, optional const & y ) +{ + return bool(x) != bool(y) ? false : !bool( x ) ? true : *x == *y; +} + +template< typename T, typename U > +inline optional_constexpr bool operator!=( optional const & x, optional const & y ) +{ + return !(x == y); +} + +template< typename T, typename U > +inline optional_constexpr bool operator<( optional const & x, optional const & y ) +{ + return (!y) ? false : (!x) ? true : *x < *y; +} + +template< typename T, typename U > +inline optional_constexpr bool operator>( optional const & x, optional const & y ) +{ + return (y < x); +} + +template< typename T, typename U > +inline optional_constexpr bool operator<=( optional const & x, optional const & y ) +{ + return !(y < x); +} + +template< typename T, typename U > +inline optional_constexpr bool operator>=( optional const & x, optional const & y ) +{ + return !(x < y); +} + +// Comparison with nullopt + +template< typename T > +inline optional_constexpr bool operator==( optional const & x, nullopt_t /*unused*/ ) optional_noexcept +{ + return (!x); +} + +template< typename T > +inline optional_constexpr bool operator==( nullopt_t /*unused*/, optional const & x ) optional_noexcept +{ + return (!x); +} + +template< typename T > +inline optional_constexpr bool operator!=( optional const & x, nullopt_t /*unused*/ ) optional_noexcept +{ + return bool(x); +} + +template< typename T > +inline optional_constexpr bool operator!=( nullopt_t /*unused*/, optional const & x ) optional_noexcept +{ + return bool(x); +} + +template< typename T > +inline optional_constexpr bool operator<( optional const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept +{ + return false; +} + +template< typename T > +inline optional_constexpr bool operator<( nullopt_t /*unused*/, optional const & x ) optional_noexcept +{ + return bool(x); +} + +template< typename T > +inline optional_constexpr bool operator<=( optional const & x, nullopt_t /*unused*/ ) optional_noexcept +{ + return (!x); +} + +template< typename T > +inline optional_constexpr bool operator<=( nullopt_t /*unused*/, optional const & /*unused*/ ) optional_noexcept +{ + return true; +} + +template< typename T > +inline optional_constexpr bool operator>( optional const & x, nullopt_t /*unused*/ ) optional_noexcept +{ + return bool(x); +} + +template< typename T > +inline optional_constexpr bool operator>( nullopt_t /*unused*/, optional const & /*unused*/ ) optional_noexcept +{ + return false; +} + +template< typename T > +inline optional_constexpr bool operator>=( optional const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept +{ + return true; +} + +template< typename T > +inline optional_constexpr bool operator>=( nullopt_t /*unused*/, optional const & x ) optional_noexcept +{ + return (!x); +} + +// Comparison with T + +template< typename T, typename U > +inline optional_constexpr bool operator==( optional const & x, U const & v ) +{ + return bool(x) ? *x == v : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator==( U const & v, optional const & x ) +{ + return bool(x) ? v == *x : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator!=( optional const & x, U const & v ) +{ + return bool(x) ? *x != v : true; +} + +template< typename T, typename U > +inline optional_constexpr bool operator!=( U const & v, optional const & x ) +{ + return bool(x) ? v != *x : true; +} + +template< typename T, typename U > +inline optional_constexpr bool operator<( optional const & x, U const & v ) +{ + return bool(x) ? *x < v : true; +} + +template< typename T, typename U > +inline optional_constexpr bool operator<( U const & v, optional const & x ) +{ + return bool(x) ? v < *x : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator<=( optional const & x, U const & v ) +{ + return bool(x) ? *x <= v : true; +} + +template< typename T, typename U > +inline optional_constexpr bool operator<=( U const & v, optional const & x ) +{ + return bool(x) ? v <= *x : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator>( optional const & x, U const & v ) +{ + return bool(x) ? *x > v : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator>( U const & v, optional const & x ) +{ + return bool(x) ? v > *x : true; +} + +template< typename T, typename U > +inline optional_constexpr bool operator>=( optional const & x, U const & v ) +{ + return bool(x) ? *x >= v : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator>=( U const & v, optional const & x ) +{ + return bool(x) ? v >= *x : true; +} + +// Specialized algorithms + +template< typename T +#if optional_CPP11_OR_GREATER + optional_REQUIRES_T( + std::is_move_constructible::value + && std17::is_swappable::value ) +#endif +> +void swap( optional & x, optional & y ) +#if optional_CPP11_OR_GREATER + noexcept( noexcept( x.swap(y) ) ) +#endif +{ + x.swap( y ); +} + +#if optional_CPP11_OR_GREATER + +template< typename T > +optional_constexpr optional< typename std::decay::type > make_optional( T && value ) +{ + return optional< typename std::decay::type >( std::forward( value ) ); +} + +template< typename T, typename...Args > +optional_constexpr optional make_optional( Args&&... args ) +{ + return optional( nonstd_lite_in_place(T), std::forward(args)...); +} + +template< typename T, typename U, typename... Args > +optional_constexpr optional make_optional( std::initializer_list il, Args&&... args ) +{ + return optional( nonstd_lite_in_place(T), il, std::forward(args)...); +} + +#else + +template< typename T > +optional make_optional( T const & value ) +{ + return optional( value ); +} + +#endif // optional_CPP11_OR_GREATER + +} // namespace optional_lite + +using optional_lite::optional; +using optional_lite::nullopt_t; +using optional_lite::nullopt; +using optional_lite::bad_optional_access; + +using optional_lite::make_optional; + +} // namespace nonstd + +#if optional_CPP11_OR_GREATER + +// specialize the std::hash algorithm: + +namespace std { + +template< class T > +struct hash< nonstd::optional > +{ +public: + std::size_t operator()( nonstd::optional const & v ) const optional_noexcept + { + return bool( v ) ? std::hash{}( *v ) : 0; + } +}; + +} //namespace std + +#endif // optional_CPP11_OR_GREATER + +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#elif defined(_MSC_VER ) +# pragma warning( pop ) +#endif + +#endif // optional_USES_STD_OPTIONAL + +#endif // NONSTD_OPTIONAL_LITE_HPP diff --git a/ndn-cxx/util/nonstd/variant.hpp b/ndn-cxx/util/nonstd/variant.hpp new file mode 100644 index 000000000..f0e70b92f --- /dev/null +++ b/ndn-cxx/util/nonstd/variant.hpp @@ -0,0 +1,2401 @@ +// Copyright 2016-2018 by Martin Moene +// +// https://github.com/martinmoene/variant-lite +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#pragma once + +#ifndef NONSTD_VARIANT_LITE_HPP +#define NONSTD_VARIANT_LITE_HPP + +#define variant_lite_MAJOR 1 +#define variant_lite_MINOR 1 +#define variant_lite_PATCH 0 + +#define variant_lite_VERSION variant_STRINGIFY(variant_lite_MAJOR) "." variant_STRINGIFY(variant_lite_MINOR) "." variant_STRINGIFY(variant_lite_PATCH) + +#define variant_STRINGIFY( x ) variant_STRINGIFY_( x ) +#define variant_STRINGIFY_( x ) #x + +// variant-lite configuration: + +#define variant_VARIANT_DEFAULT 0 +#define variant_VARIANT_NONSTD 1 +#define variant_VARIANT_STD 2 + +#if !defined( variant_CONFIG_SELECT_VARIANT ) +# define variant_CONFIG_SELECT_VARIANT ( variant_HAVE_STD_VARIANT ? variant_VARIANT_STD : variant_VARIANT_NONSTD ) +#endif + +#ifndef variant_CONFIG_OMIT_VARIANT_SIZE_V_MACRO +# define variant_CONFIG_OMIT_VARIANT_SIZE_V_MACRO 0 +#endif + +#ifndef variant_CONFIG_OMIT_VARIANT_ALTERNATIVE_T_MACRO +# define variant_CONFIG_OMIT_VARIANT_ALTERNATIVE_T_MACRO 0 +#endif + +// Control presence of exception handling (try and auto discover): + +#ifndef variant_CONFIG_NO_EXCEPTIONS +# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) +# define variant_CONFIG_NO_EXCEPTIONS 0 +# else +# define variant_CONFIG_NO_EXCEPTIONS 1 +# endif +#endif + +// C++ language version detection (C++20 is speculative): +// Note: VC14.0/1900 (VS2015) lacks too much from C++14. + +#ifndef variant_CPLUSPLUS +# if defined(_MSVC_LANG ) && !defined(__clang__) +# define variant_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) +# else +# define variant_CPLUSPLUS __cplusplus +# endif +#endif + +#define variant_CPP98_OR_GREATER ( variant_CPLUSPLUS >= 199711L ) +#define variant_CPP11_OR_GREATER ( variant_CPLUSPLUS >= 201103L ) +#define variant_CPP11_OR_GREATER_ ( variant_CPLUSPLUS >= 201103L ) +#define variant_CPP14_OR_GREATER ( variant_CPLUSPLUS >= 201402L ) +#define variant_CPP17_OR_GREATER ( variant_CPLUSPLUS >= 201703L ) +#define variant_CPP20_OR_GREATER ( variant_CPLUSPLUS >= 202000L ) + +// Use C++17 std::variant if available and requested: + +#if variant_CPP17_OR_GREATER && defined(__has_include ) +# if __has_include( ) +# define variant_HAVE_STD_VARIANT 1 +# else +# define variant_HAVE_STD_VARIANT 0 +# endif +#else +# define variant_HAVE_STD_VARIANT 0 +#endif + +#define variant_USES_STD_VARIANT ( (variant_CONFIG_SELECT_VARIANT == variant_VARIANT_STD) || ((variant_CONFIG_SELECT_VARIANT == variant_VARIANT_DEFAULT) && variant_HAVE_STD_VARIANT) ) + +// +// in_place: code duplicated in any-lite, expected-lite, optional-lite, value-ptr-lite, variant-lite: +// + +#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES +#define nonstd_lite_HAVE_IN_PLACE_TYPES 1 + +// C++17 std::in_place in : + +#if variant_CPP17_OR_GREATER + +#include + +namespace nonstd { + +using std::in_place; +using std::in_place_type; +using std::in_place_index; +using std::in_place_t; +using std::in_place_type_t; +using std::in_place_index_t; + +#define nonstd_lite_in_place_t( T) std::in_place_t +#define nonstd_lite_in_place_type_t( T) std::in_place_type_t +#define nonstd_lite_in_place_index_t(K) std::in_place_index_t + +#define nonstd_lite_in_place( T) std::in_place_t{} +#define nonstd_lite_in_place_type( T) std::in_place_type_t{} +#define nonstd_lite_in_place_index(K) std::in_place_index_t{} + +} // namespace nonstd + +#else // variant_CPP17_OR_GREATER + +#include + +namespace nonstd { +namespace detail { + +template< class T > +struct in_place_type_tag {}; + +template< std::size_t K > +struct in_place_index_tag {}; + +} // namespace detail + +struct in_place_t {}; + +template< class T > +inline in_place_t in_place( detail::in_place_type_tag = detail::in_place_type_tag() ) +{ + return in_place_t(); +} + +template< std::size_t K > +inline in_place_t in_place( detail::in_place_index_tag = detail::in_place_index_tag() ) +{ + return in_place_t(); +} + +template< class T > +inline in_place_t in_place_type( detail::in_place_type_tag = detail::in_place_type_tag() ) +{ + return in_place_t(); +} + +template< std::size_t K > +inline in_place_t in_place_index( detail::in_place_index_tag = detail::in_place_index_tag() ) +{ + return in_place_t(); +} + +// mimic templated typedef: + +#define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) +#define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) +#define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag ) + +#define nonstd_lite_in_place( T) nonstd::in_place_type +#define nonstd_lite_in_place_type( T) nonstd::in_place_type +#define nonstd_lite_in_place_index(K) nonstd::in_place_index + +} // namespace nonstd + +#endif // variant_CPP17_OR_GREATER +#endif // nonstd_lite_HAVE_IN_PLACE_TYPES + +// +// Use C++17 std::variant: +// + +#if variant_USES_STD_VARIANT + +#include // std::hash<> +#include + +#if ! variant_CONFIG_OMIT_VARIANT_SIZE_V_MACRO +# define variant_size_V(T) nonstd::variant_size::value +#endif + +#if ! variant_CONFIG_OMIT_VARIANT_ALTERNATIVE_T_MACRO +# define variant_alternative_T(K,T) typename nonstd::variant_alternative::type +#endif + +namespace nonstd { + + using std::variant; + using std::monostate; + using std::bad_variant_access; + using std::variant_size; + using std::variant_size_v; + using std::variant_alternative; + using std::variant_alternative_t; + using std::hash; + + using std::visit; + using std::holds_alternative; + using std::get; + using std::get_if; + using std::operator==; + using std::operator!=; + using std::operator<; + using std::operator<=; + using std::operator>; + using std::operator>=; + using std::swap; + + constexpr auto variant_npos = std::variant_npos; +} + +#else // variant_USES_STD_VARIANT + +#include +#include +#include +#include + +#if variant_CONFIG_NO_EXCEPTIONS +# include +#else +# include +#endif + +// variant-lite type and visitor argument count configuration (script/generate_header.py): + +#define variant_CONFIG_MAX_TYPE_COUNT 16 +#define variant_CONFIG_MAX_VISITOR_ARG_COUNT 5 + +// variant-lite alignment configuration: + +#ifndef variant_CONFIG_MAX_ALIGN_HACK +# define variant_CONFIG_MAX_ALIGN_HACK 0 +#endif + +#ifndef variant_CONFIG_ALIGN_AS +// no default, used in #if defined() +#endif + +#ifndef variant_CONFIG_ALIGN_AS_FALLBACK +# define variant_CONFIG_ALIGN_AS_FALLBACK double +#endif + +// half-open range [lo..hi): +#define variant_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) + +// Compiler versions: +// +// MSVC++ 6.0 _MSC_VER == 1200 (Visual Studio 6.0) +// MSVC++ 7.0 _MSC_VER == 1300 (Visual Studio .NET 2002) +// MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio .NET 2003) +// MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) +// MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) +// MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) +// MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) +// MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) +// MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) +// MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017) + +#if defined(_MSC_VER ) && !defined(__clang__) +# define variant_COMPILER_MSVC_VER (_MSC_VER ) +# define variant_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) +#else +# define variant_COMPILER_MSVC_VER 0 +# define variant_COMPILER_MSVC_VERSION 0 +#endif + +#define variant_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) ) + +#if defined(__clang__) +# define variant_COMPILER_CLANG_VERSION variant_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) +#else +# define variant_COMPILER_CLANG_VERSION 0 +#endif + +#if defined(__GNUC__) && !defined(__clang__) +# define variant_COMPILER_GNUC_VERSION variant_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#else +# define variant_COMPILER_GNUC_VERSION 0 +#endif + +#if variant_BETWEEN( variant_COMPILER_MSVC_VER, 1300, 1900 ) +# pragma warning( push ) +# pragma warning( disable: 4345 ) // initialization behavior changed +#endif + +// Presence of language and library features: + +#define variant_HAVE( feature ) ( variant_HAVE_##feature ) + +#ifdef _HAS_CPP0X +# define variant_HAS_CPP0X _HAS_CPP0X +#else +# define variant_HAS_CPP0X 0 +#endif + +// Unless defined otherwise below, consider VC14 as C++11 for variant-lite: + +#if variant_COMPILER_MSVC_VER >= 1900 +# undef variant_CPP11_OR_GREATER +# define variant_CPP11_OR_GREATER 1 +#endif + +#define variant_CPP11_90 (variant_CPP11_OR_GREATER_ || variant_COMPILER_MSVC_VER >= 1500) +#define variant_CPP11_100 (variant_CPP11_OR_GREATER_ || variant_COMPILER_MSVC_VER >= 1600) +#define variant_CPP11_110 (variant_CPP11_OR_GREATER_ || variant_COMPILER_MSVC_VER >= 1700) +#define variant_CPP11_120 (variant_CPP11_OR_GREATER_ || variant_COMPILER_MSVC_VER >= 1800) +#define variant_CPP11_140 (variant_CPP11_OR_GREATER_ || variant_COMPILER_MSVC_VER >= 1900) +#define variant_CPP11_141 (variant_CPP11_OR_GREATER_ || variant_COMPILER_MSVC_VER >= 1910) + +#define variant_CPP14_000 (variant_CPP14_OR_GREATER) +#define variant_CPP17_000 (variant_CPP17_OR_GREATER) + +// Presence of C++11 language features: + +#define variant_HAVE_CONSTEXPR_11 variant_CPP11_140 +#define variant_HAVE_INITIALIZER_LIST variant_CPP11_120 +#define variant_HAVE_NOEXCEPT variant_CPP11_140 +#define variant_HAVE_NULLPTR variant_CPP11_100 +#define variant_HAVE_OVERRIDE variant_CPP11_140 + +// Presence of C++14 language features: + +#define variant_HAVE_CONSTEXPR_14 variant_CPP14_000 + +// Presence of C++17 language features: + +// no flag + +// Presence of C++ library features: + +#define variant_HAVE_CONDITIONAL variant_CPP11_120 +#define variant_HAVE_REMOVE_CV variant_CPP11_120 +#define variant_HAVE_STD_ADD_POINTER variant_CPP11_90 +#define variant_HAVE_TYPE_TRAITS variant_CPP11_90 + +#define variant_HAVE_TR1_TYPE_TRAITS (!! variant_COMPILER_GNUC_VERSION ) +#define variant_HAVE_TR1_ADD_POINTER (!! variant_COMPILER_GNUC_VERSION ) + +// C++ feature usage: + +#if variant_HAVE_CONSTEXPR_11 +# define variant_constexpr constexpr +#else +# define variant_constexpr /*constexpr*/ +#endif + +#if variant_HAVE_CONSTEXPR_14 +# define variant_constexpr14 constexpr +#else +# define variant_constexpr14 /*constexpr*/ +#endif + +#if variant_HAVE_NOEXCEPT +# define variant_noexcept noexcept +#else +# define variant_noexcept /*noexcept*/ +#endif + +#if variant_HAVE_NULLPTR +# define variant_nullptr nullptr +#else +# define variant_nullptr NULL +#endif + +#if variant_HAVE_OVERRIDE +# define variant_override override +#else +# define variant_override /*override*/ +#endif + +// additional includes: + +#if variant_CPP11_OR_GREATER +# include // std::hash +#endif + +#if variant_HAVE_INITIALIZER_LIST +# include +#endif + +#if variant_HAVE_TYPE_TRAITS +# include +#elif variant_HAVE_TR1_TYPE_TRAITS +# include +#endif + +// Method enabling + +#if variant_CPP11_OR_GREATER + +#define variant_REQUIRES_0(...) \ + template< bool B = (__VA_ARGS__), typename std::enable_if::type = 0 > + +#define variant_REQUIRES_T(...) \ + , typename = typename std::enable_if< (__VA_ARGS__), nonstd::variants::detail::enabler >::type + +#define variant_REQUIRES_R(R, ...) \ + typename std::enable_if< (__VA_ARGS__), R>::type + +#define variant_REQUIRES_A(...) \ + , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr + +#endif + +// +// variant: +// + +namespace nonstd { namespace variants { + +// C++11 emulation: + +namespace std11 { + +#if variant_HAVE_STD_ADD_POINTER + +using std::add_pointer; + +#elif variant_HAVE_TR1_ADD_POINTER + +using std::tr1::add_pointer; + +#else + +template< class T > struct remove_reference { typedef T type; }; +template< class T > struct remove_reference { typedef T type; }; + +template< class T > struct add_pointer +{ + typedef typename remove_reference::type * type; +}; + +#endif // variant_HAVE_STD_ADD_POINTER + +#if variant_HAVE_REMOVE_CV + +using std::remove_cv; + +#else + +template< class T > struct remove_const { typedef T type; }; +template< class T > struct remove_const { typedef T type; }; + +template< class T > struct remove_volatile { typedef T type; }; +template< class T > struct remove_volatile { typedef T type; }; + +template< class T > +struct remove_cv +{ + typedef typename remove_volatile::type>::type type; +}; + +#endif // variant_HAVE_REMOVE_CV + +#if variant_HAVE_CONDITIONAL + +using std::conditional; + +#else + +template< bool Cond, class Then, class Else > +struct conditional; + +template< class Then, class Else > +struct conditional< true , Then, Else > { typedef Then type; }; + +template< class Then, class Else > +struct conditional< false, Then, Else > { typedef Else type; }; + +#endif // variant_HAVE_CONDITIONAL + +} // namespace std11 + +/// type traits C++17: + +namespace std17 { + +#if variant_CPP17_OR_GREATER + +using std::is_swappable; +using std::is_nothrow_swappable; + +#elif variant_CPP11_OR_GREATER + +namespace detail { + +using std::swap; + +struct is_swappable +{ + template< typename T, typename = decltype( swap( std::declval(), std::declval() ) ) > + static std::true_type test( int ); + + template< typename > + static std::false_type test(...); +}; + +struct is_nothrow_swappable +{ + // wrap noexcept(epr) in separate function as work-around for VC140 (VS2015): + + template< typename T > + static constexpr bool test() + { + return noexcept( swap( std::declval(), std::declval() ) ); + } + + template< typename T > + static auto test( int ) -> std::integral_constant()>{} + + template< typename > + static std::false_type test(...); +}; + +} // namespace detail + +// is [nothow] swappable: + +template< typename T > +struct is_swappable : decltype( detail::is_swappable::test(0) ){}; + +template< typename T > +struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test(0) ){}; + +#endif // variant_CPP17_OR_GREATER + +} // namespace std17 + +// detail: + +namespace detail { + +// for variant_REQUIRES_T(): + +/*enum*/ class enabler{}; + +// typelist: + +#define variant_TL1( T1 ) detail::typelist< T1, detail::nulltype > +#define variant_TL2( T1, T2) detail::typelist< T1, variant_TL1( T2) > +#define variant_TL3( T1, T2, T3) detail::typelist< T1, variant_TL2( T2, T3) > +#define variant_TL4( T1, T2, T3, T4) detail::typelist< T1, variant_TL3( T2, T3, T4) > +#define variant_TL5( T1, T2, T3, T4, T5) detail::typelist< T1, variant_TL4( T2, T3, T4, T5) > +#define variant_TL6( T1, T2, T3, T4, T5, T6) detail::typelist< T1, variant_TL5( T2, T3, T4, T5, T6) > +#define variant_TL7( T1, T2, T3, T4, T5, T6, T7) detail::typelist< T1, variant_TL6( T2, T3, T4, T5, T6, T7) > +#define variant_TL8( T1, T2, T3, T4, T5, T6, T7, T8) detail::typelist< T1, variant_TL7( T2, T3, T4, T5, T6, T7, T8) > +#define variant_TL9( T1, T2, T3, T4, T5, T6, T7, T8, T9) detail::typelist< T1, variant_TL8( T2, T3, T4, T5, T6, T7, T8, T9) > +#define variant_TL10( T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) detail::typelist< T1, variant_TL9( T2, T3, T4, T5, T6, T7, T8, T9, T10) > +#define variant_TL11( T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) detail::typelist< T1, variant_TL10( T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) > +#define variant_TL12( T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) detail::typelist< T1, variant_TL11( T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) > +#define variant_TL13( T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) detail::typelist< T1, variant_TL12( T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) > +#define variant_TL14( T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) detail::typelist< T1, variant_TL13( T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) > +#define variant_TL15( T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) detail::typelist< T1, variant_TL14( T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) > +#define variant_TL16( T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16) detail::typelist< T1, variant_TL15( T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16) > + + +// variant parameter unused type tags: + +template< class T > +struct TX : T +{ + inline TX operator+ ( ) const { return TX(); } + inline TX operator- ( ) const { return TX(); } + + inline TX operator! ( ) const { return TX(); } + inline TX operator~ ( ) const { return TX(); } + + inline TX*operator& ( ) const { return variant_nullptr; } + + template< class U > inline TX operator* ( U const & ) const { return TX(); } + template< class U > inline TX operator/ ( U const & ) const { return TX(); } + + template< class U > inline TX operator% ( U const & ) const { return TX(); } + template< class U > inline TX operator+ ( U const & ) const { return TX(); } + template< class U > inline TX operator- ( U const & ) const { return TX(); } + + template< class U > inline TX operator<<( U const & ) const { return TX(); } + template< class U > inline TX operator>>( U const & ) const { return TX(); } + + inline bool operator==( T const & ) const { return false; } + inline bool operator< ( T const & ) const { return false; } + + template< class U > inline TX operator& ( U const & ) const { return TX(); } + template< class U > inline TX operator| ( U const & ) const { return TX(); } + template< class U > inline TX operator^ ( U const & ) const { return TX(); } + + template< class U > inline TX operator&&( U const & ) const { return TX(); } + template< class U > inline TX operator||( U const & ) const { return TX(); } +}; + +struct S0{}; typedef TX T0; +struct S1{}; typedef TX T1; +struct S2{}; typedef TX T2; +struct S3{}; typedef TX T3; +struct S4{}; typedef TX T4; +struct S5{}; typedef TX T5; +struct S6{}; typedef TX T6; +struct S7{}; typedef TX T7; +struct S8{}; typedef TX T8; +struct S9{}; typedef TX T9; +struct S10{}; typedef TX T10; +struct S11{}; typedef TX T11; +struct S12{}; typedef TX T12; +struct S13{}; typedef TX T13; +struct S14{}; typedef TX T14; +struct S15{}; typedef TX T15; + + +struct nulltype{}; + +template< class Head, class Tail > +struct typelist +{ + typedef Head head; + typedef Tail tail; +}; + +// typelist max element size: + +template< class List > +struct typelist_max; + +template<> +struct typelist_max< nulltype > +{ + enum V { value = 0 } ; + typedef void type; +}; + +template< class Head, class Tail > +struct typelist_max< typelist > +{ +private: + enum TV { tail_value = size_t( typelist_max::value ) }; + + typedef typename typelist_max::type tail_type; + +public: + enum V { value = (sizeof( Head ) > tail_value) ? sizeof( Head ) : std::size_t( tail_value ) } ; + + typedef typename std11::conditional< (sizeof( Head ) > tail_value), Head, tail_type>::type type; +}; + +#if variant_CPP11_OR_GREATER + +// typelist max alignof element type: + +template< class List > +struct typelist_max_alignof; + +template<> +struct typelist_max_alignof< nulltype > +{ + enum V { value = 0 } ; +}; + +template< class Head, class Tail > +struct typelist_max_alignof< typelist > +{ +private: + enum TV { tail_value = size_t( typelist_max_alignof::value ) }; + +public: + enum V { value = (alignof( Head ) > tail_value) ? alignof( Head ) : std::size_t( tail_value ) }; +}; + +#endif + +// typelist size (length): + +template< class List > +struct typelist_size +{ + enum V { value = 1 }; +}; + +template<> struct typelist_size< T0 > { enum V { value = 0 }; }; +template<> struct typelist_size< T1 > { enum V { value = 0 }; }; +template<> struct typelist_size< T2 > { enum V { value = 0 }; }; +template<> struct typelist_size< T3 > { enum V { value = 0 }; }; +template<> struct typelist_size< T4 > { enum V { value = 0 }; }; +template<> struct typelist_size< T5 > { enum V { value = 0 }; }; +template<> struct typelist_size< T6 > { enum V { value = 0 }; }; +template<> struct typelist_size< T7 > { enum V { value = 0 }; }; +template<> struct typelist_size< T8 > { enum V { value = 0 }; }; +template<> struct typelist_size< T9 > { enum V { value = 0 }; }; +template<> struct typelist_size< T10 > { enum V { value = 0 }; }; +template<> struct typelist_size< T11 > { enum V { value = 0 }; }; +template<> struct typelist_size< T12 > { enum V { value = 0 }; }; +template<> struct typelist_size< T13 > { enum V { value = 0 }; }; +template<> struct typelist_size< T14 > { enum V { value = 0 }; }; +template<> struct typelist_size< T15 > { enum V { value = 0 }; }; + + +template<> struct typelist_size< nulltype > { enum V { value = 0 } ; }; + +template< class Head, class Tail > +struct typelist_size< typelist > +{ + enum V { value = typelist_size::value + typelist_size::value }; +}; + +// typelist index of type: + +template< class List, class T > +struct typelist_index_of; + +template< class T > +struct typelist_index_of< nulltype, T > +{ + enum V { value = -1 }; +}; + +template< class Tail, class T > +struct typelist_index_of< typelist, T > +{ + enum V { value = 0 }; +}; + +template< class Head, class Tail, class T > +struct typelist_index_of< typelist, T > +{ +private: + enum TV { nextVal = typelist_index_of::value }; + +public: + enum V { value = nextVal == -1 ? -1 : 1 + nextVal } ; +}; + +// typelist type at index: + +template< class List, std::size_t i> +struct typelist_type_at; + +template< class Head, class Tail > +struct typelist_type_at< typelist, 0 > +{ + typedef Head type; +}; + +template< class Head, class Tail, std::size_t i > +struct typelist_type_at< typelist, i > +{ + typedef typename typelist_type_at::type type; +}; + +#if variant_CONFIG_MAX_ALIGN_HACK + +// Max align, use most restricted type for alignment: + +#define variant_UNIQUE( name ) variant_UNIQUE2( name, __LINE__ ) +#define variant_UNIQUE2( name, line ) variant_UNIQUE3( name, line ) +#define variant_UNIQUE3( name, line ) name ## line + +#define variant_ALIGN_TYPE( type ) \ + type variant_UNIQUE( _t ); struct_t< type > variant_UNIQUE( _st ) + +template< class T > +struct struct_t { T _; }; + +union max_align_t +{ + variant_ALIGN_TYPE( char ); + variant_ALIGN_TYPE( short int ); + variant_ALIGN_TYPE( int ); + variant_ALIGN_TYPE( long int ); + variant_ALIGN_TYPE( float ); + variant_ALIGN_TYPE( double ); + variant_ALIGN_TYPE( long double ); + variant_ALIGN_TYPE( char * ); + variant_ALIGN_TYPE( short int * ); + variant_ALIGN_TYPE( int * ); + variant_ALIGN_TYPE( long int * ); + variant_ALIGN_TYPE( float * ); + variant_ALIGN_TYPE( double * ); + variant_ALIGN_TYPE( long double * ); + variant_ALIGN_TYPE( void * ); + +#ifdef HAVE_LONG_LONG + variant_ALIGN_TYPE( long long ); +#endif + + struct Unknown; + + Unknown ( * variant_UNIQUE(_) )( Unknown ); + Unknown * Unknown::* variant_UNIQUE(_); + Unknown ( Unknown::* variant_UNIQUE(_) )( Unknown ); + + struct_t< Unknown ( * )( Unknown) > variant_UNIQUE(_); + struct_t< Unknown * Unknown::* > variant_UNIQUE(_); + struct_t< Unknown ( Unknown::* )(Unknown) > variant_UNIQUE(_); +}; + +#undef variant_UNIQUE +#undef variant_UNIQUE2 +#undef variant_UNIQUE3 + +#undef variant_ALIGN_TYPE + +#elif defined( variant_CONFIG_ALIGN_AS ) // variant_CONFIG_MAX_ALIGN_HACK + +// Use user-specified type for alignment: + +#define variant_ALIGN_AS( unused ) \ + variant_CONFIG_ALIGN_AS + +#else // variant_CONFIG_MAX_ALIGN_HACK + +// Determine POD type to use for alignment: + +#define variant_ALIGN_AS( to_align ) \ + typename detail::type_of_size< detail::alignment_types, detail::alignment_of< to_align >::value >::type + +template< typename T > +struct alignment_of; + +template< typename T > +struct alignment_of_hack +{ + char c; + T t; + alignment_of_hack(); +}; + +template< size_t A, size_t S > +struct alignment_logic +{ + enum V { value = A < S ? A : S }; +}; + +template< typename T > +struct alignment_of +{ + enum V { value = alignment_logic< + sizeof( alignment_of_hack ) - sizeof(T), sizeof(T) >::value }; +}; + +template< typename List, size_t N > +struct type_of_size +{ + typedef typename std11::conditional< + N == sizeof( typename List::head ), + typename List::head, + typename type_of_size::type >::type type; +}; + +template< size_t N > +struct type_of_size< nulltype, N > +{ + typedef variant_CONFIG_ALIGN_AS_FALLBACK type; +}; + +template< typename T> +struct struct_t { T _; }; + +#define variant_ALIGN_TYPE( type ) \ + typelist< type , typelist< struct_t< type > + +struct Unknown; + +typedef + variant_ALIGN_TYPE( char ), + variant_ALIGN_TYPE( short ), + variant_ALIGN_TYPE( int ), + variant_ALIGN_TYPE( long ), + variant_ALIGN_TYPE( float ), + variant_ALIGN_TYPE( double ), + variant_ALIGN_TYPE( long double ), + + variant_ALIGN_TYPE( char *), + variant_ALIGN_TYPE( short * ), + variant_ALIGN_TYPE( int * ), + variant_ALIGN_TYPE( long * ), + variant_ALIGN_TYPE( float * ), + variant_ALIGN_TYPE( double * ), + variant_ALIGN_TYPE( long double * ), + + variant_ALIGN_TYPE( Unknown ( * )( Unknown ) ), + variant_ALIGN_TYPE( Unknown * Unknown::* ), + variant_ALIGN_TYPE( Unknown ( Unknown::* )( Unknown ) ), + + nulltype + > > > > > > > > > > > > > > + > > > > > > > > > > > > > > + > > > > > > + alignment_types; + +#undef variant_ALIGN_TYPE + +#endif // variant_CONFIG_MAX_ALIGN_HACK + +#if variant_CPP11_OR_GREATER + +template< typename T> +inline std::size_t hash( T const & v ) +{ + return std::hash()( v ); +} + +inline std::size_t hash( T0 const & ) { return 0; } +inline std::size_t hash( T1 const & ) { return 0; } +inline std::size_t hash( T2 const & ) { return 0; } +inline std::size_t hash( T3 const & ) { return 0; } +inline std::size_t hash( T4 const & ) { return 0; } +inline std::size_t hash( T5 const & ) { return 0; } +inline std::size_t hash( T6 const & ) { return 0; } +inline std::size_t hash( T7 const & ) { return 0; } +inline std::size_t hash( T8 const & ) { return 0; } +inline std::size_t hash( T9 const & ) { return 0; } +inline std::size_t hash( T10 const & ) { return 0; } +inline std::size_t hash( T11 const & ) { return 0; } +inline std::size_t hash( T12 const & ) { return 0; } +inline std::size_t hash( T13 const & ) { return 0; } +inline std::size_t hash( T14 const & ) { return 0; } +inline std::size_t hash( T15 const & ) { return 0; } + + +#endif // variant_CPP11_OR_GREATER + + + + + +template< class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +struct helper +{ + typedef signed char type_index_t; + typedef variant_TL16( T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 ) variant_types; + + template< class U > + static U * as( void * data ) + { + return reinterpret_cast( data ); + } + + template< class U > + static U const * as( void const * data ) + { + return reinterpret_cast( data ); + } + + static type_index_t to_index_t( std::size_t index ) + { + return static_cast( index ); + } + + static void destroy( type_index_t index, void * data ) + { + switch ( index ) + { + case 0: as( data )->~T0(); break; + case 1: as( data )->~T1(); break; + case 2: as( data )->~T2(); break; + case 3: as( data )->~T3(); break; + case 4: as( data )->~T4(); break; + case 5: as( data )->~T5(); break; + case 6: as( data )->~T6(); break; + case 7: as( data )->~T7(); break; + case 8: as( data )->~T8(); break; + case 9: as( data )->~T9(); break; + case 10: as( data )->~T10(); break; + case 11: as( data )->~T11(); break; + case 12: as( data )->~T12(); break; + case 13: as( data )->~T13(); break; + case 14: as( data )->~T14(); break; + case 15: as( data )->~T15(); break; + + } + } + +#if variant_CPP11_OR_GREATER + template< class T, class... Args > + static type_index_t construct_t( void * data, Args&&... args ) + { + new( data ) T( std::forward(args)... ); + + return to_index_t( detail::typelist_index_of< variant_types, T>::value ); + } + + template< std::size_t K, class... Args > + static type_index_t construct_i( void * data, Args&&... args ) + { + using type = typename detail::typelist_type_at< variant_types, K >::type; + + construct_t< type >( data, std::forward(args)... ); + + return to_index_t( K ); + } + + static type_index_t move_construct( type_index_t const from_index, void * from_value, void * to_value ) + { + switch ( from_index ) + { + case 0: new( to_value ) T0( std::move( *as( from_value ) ) ); break; + case 1: new( to_value ) T1( std::move( *as( from_value ) ) ); break; + case 2: new( to_value ) T2( std::move( *as( from_value ) ) ); break; + case 3: new( to_value ) T3( std::move( *as( from_value ) ) ); break; + case 4: new( to_value ) T4( std::move( *as( from_value ) ) ); break; + case 5: new( to_value ) T5( std::move( *as( from_value ) ) ); break; + case 6: new( to_value ) T6( std::move( *as( from_value ) ) ); break; + case 7: new( to_value ) T7( std::move( *as( from_value ) ) ); break; + case 8: new( to_value ) T8( std::move( *as( from_value ) ) ); break; + case 9: new( to_value ) T9( std::move( *as( from_value ) ) ); break; + case 10: new( to_value ) T10( std::move( *as( from_value ) ) ); break; + case 11: new( to_value ) T11( std::move( *as( from_value ) ) ); break; + case 12: new( to_value ) T12( std::move( *as( from_value ) ) ); break; + case 13: new( to_value ) T13( std::move( *as( from_value ) ) ); break; + case 14: new( to_value ) T14( std::move( *as( from_value ) ) ); break; + case 15: new( to_value ) T15( std::move( *as( from_value ) ) ); break; + + } + return from_index; + } + + static type_index_t move_assign( type_index_t const from_index, void * from_value, void * to_value ) + { + switch ( from_index ) + { + case 0: *as( to_value ) = std::move( *as( from_value ) ); break; + case 1: *as( to_value ) = std::move( *as( from_value ) ); break; + case 2: *as( to_value ) = std::move( *as( from_value ) ); break; + case 3: *as( to_value ) = std::move( *as( from_value ) ); break; + case 4: *as( to_value ) = std::move( *as( from_value ) ); break; + case 5: *as( to_value ) = std::move( *as( from_value ) ); break; + case 6: *as( to_value ) = std::move( *as( from_value ) ); break; + case 7: *as( to_value ) = std::move( *as( from_value ) ); break; + case 8: *as( to_value ) = std::move( *as( from_value ) ); break; + case 9: *as( to_value ) = std::move( *as( from_value ) ); break; + case 10: *as( to_value ) = std::move( *as( from_value ) ); break; + case 11: *as( to_value ) = std::move( *as( from_value ) ); break; + case 12: *as( to_value ) = std::move( *as( from_value ) ); break; + case 13: *as( to_value ) = std::move( *as( from_value ) ); break; + case 14: *as( to_value ) = std::move( *as( from_value ) ); break; + case 15: *as( to_value ) = std::move( *as( from_value ) ); break; + + } + return from_index; + } +#endif + + static type_index_t copy_construct( type_index_t const from_index, const void * from_value, void * to_value ) + { + switch ( from_index ) + { + case 0: new( to_value ) T0( *as( from_value ) ); break; + case 1: new( to_value ) T1( *as( from_value ) ); break; + case 2: new( to_value ) T2( *as( from_value ) ); break; + case 3: new( to_value ) T3( *as( from_value ) ); break; + case 4: new( to_value ) T4( *as( from_value ) ); break; + case 5: new( to_value ) T5( *as( from_value ) ); break; + case 6: new( to_value ) T6( *as( from_value ) ); break; + case 7: new( to_value ) T7( *as( from_value ) ); break; + case 8: new( to_value ) T8( *as( from_value ) ); break; + case 9: new( to_value ) T9( *as( from_value ) ); break; + case 10: new( to_value ) T10( *as( from_value ) ); break; + case 11: new( to_value ) T11( *as( from_value ) ); break; + case 12: new( to_value ) T12( *as( from_value ) ); break; + case 13: new( to_value ) T13( *as( from_value ) ); break; + case 14: new( to_value ) T14( *as( from_value ) ); break; + case 15: new( to_value ) T15( *as( from_value ) ); break; + + } + return from_index; + } + + static type_index_t copy_assign( type_index_t const from_index, const void * from_value, void * to_value ) + { + switch ( from_index ) + { + case 0: *as( to_value ) = *as( from_value ); break; + case 1: *as( to_value ) = *as( from_value ); break; + case 2: *as( to_value ) = *as( from_value ); break; + case 3: *as( to_value ) = *as( from_value ); break; + case 4: *as( to_value ) = *as( from_value ); break; + case 5: *as( to_value ) = *as( from_value ); break; + case 6: *as( to_value ) = *as( from_value ); break; + case 7: *as( to_value ) = *as( from_value ); break; + case 8: *as( to_value ) = *as( from_value ); break; + case 9: *as( to_value ) = *as( from_value ); break; + case 10: *as( to_value ) = *as( from_value ); break; + case 11: *as( to_value ) = *as( from_value ); break; + case 12: *as( to_value ) = *as( from_value ); break; + case 13: *as( to_value ) = *as( from_value ); break; + case 14: *as( to_value ) = *as( from_value ); break; + case 15: *as( to_value ) = *as( from_value ); break; + + } + return from_index; + } +}; + +} // namespace detail + +// +// Variant: +// + +template< class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +class variant; + +// 19.7.8 Class monostate + +class monostate{}; + +// 19.7.9 monostate relational operators + +inline variant_constexpr bool operator< ( monostate, monostate ) variant_noexcept { return false; } +inline variant_constexpr bool operator> ( monostate, monostate ) variant_noexcept { return false; } +inline variant_constexpr bool operator<=( monostate, monostate ) variant_noexcept { return true; } +inline variant_constexpr bool operator>=( monostate, monostate ) variant_noexcept { return true; } +inline variant_constexpr bool operator==( monostate, monostate ) variant_noexcept { return true; } +inline variant_constexpr bool operator!=( monostate, monostate ) variant_noexcept { return false; } + +// 19.7.4 variant helper classes + +// obtain the size of the variant's list of alternatives at compile time + +template< class T > +struct variant_size; /* undefined */ + +template< class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +struct variant_size< variant > +{ + enum _ { value = detail::typelist_size< variant_TL16(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) >::value }; +}; + +#if variant_CPP14_OR_GREATER +template< class T > +constexpr std::size_t variant_size_v = variant_size::value; +#endif + +#if ! variant_CONFIG_OMIT_VARIANT_SIZE_V_MACRO +# define variant_size_V(T) nonstd::variant_size::value +#endif + +// obtain the type of the alternative specified by its index, at compile time: + +template< std::size_t K, class T > +struct variant_alternative; /* undefined */ + +template< std::size_t K, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +struct variant_alternative< K, variant > +{ + typedef typename detail::typelist_type_at::type type; +}; + +#if variant_CPP11_OR_GREATER +template< std::size_t K, class T > +using variant_alternative_t = typename variant_alternative::type; +#endif + +#if ! variant_CONFIG_OMIT_VARIANT_ALTERNATIVE_T_MACRO +# define variant_alternative_T(K,T) typename nonstd::variant_alternative::type +#endif + +// NTS:implement specializes the std::uses_allocator type trait +// std::uses_allocator + +// index of the variant in the invalid state (constant) + +#if variant_CPP11_OR_GREATER +variant_constexpr std::size_t variant_npos = static_cast( -1 ); +#else +static const std::size_t variant_npos = static_cast( -1 ); +#endif + +#if ! variant_CONFIG_NO_EXCEPTIONS + +// 19.7.11 Class bad_variant_access + +class bad_variant_access : public std::exception +{ +public: +#if variant_CPP11_OR_GREATER + virtual const char* what() const variant_noexcept variant_override +#else + virtual const char* what() const throw() +#endif + { + return "bad variant access"; + } +}; + +#endif // variant_CONFIG_NO_EXCEPTIONS + +// 19.7.3 Class template variant + +template< + class T0, + class T1 = detail::T1, + class T2 = detail::T2, + class T3 = detail::T3, + class T4 = detail::T4, + class T5 = detail::T5, + class T6 = detail::T6, + class T7 = detail::T7, + class T8 = detail::T8, + class T9 = detail::T9, + class T10 = detail::T10, + class T11 = detail::T11, + class T12 = detail::T12, + class T13 = detail::T13, + class T14 = detail::T14, + class T15 = detail::T15 + > +class variant +{ + typedef detail::helper< T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 > helper_type; + typedef variant_TL16( T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 ) variant_types; + +public: + // 19.7.3.1 Constructors + + variant() : type_index( 0 ) { new( ptr() ) T0(); } + + variant( T0 const & t0 ) : type_index( 0 ) { new( ptr() ) T0( t0 ); } + variant( T1 const & t1 ) : type_index( 1 ) { new( ptr() ) T1( t1 ); } + variant( T2 const & t2 ) : type_index( 2 ) { new( ptr() ) T2( t2 ); } + variant( T3 const & t3 ) : type_index( 3 ) { new( ptr() ) T3( t3 ); } + variant( T4 const & t4 ) : type_index( 4 ) { new( ptr() ) T4( t4 ); } + variant( T5 const & t5 ) : type_index( 5 ) { new( ptr() ) T5( t5 ); } + variant( T6 const & t6 ) : type_index( 6 ) { new( ptr() ) T6( t6 ); } + variant( T7 const & t7 ) : type_index( 7 ) { new( ptr() ) T7( t7 ); } + variant( T8 const & t8 ) : type_index( 8 ) { new( ptr() ) T8( t8 ); } + variant( T9 const & t9 ) : type_index( 9 ) { new( ptr() ) T9( t9 ); } + variant( T10 const & t10 ) : type_index( 10 ) { new( ptr() ) T10( t10 ); } + variant( T11 const & t11 ) : type_index( 11 ) { new( ptr() ) T11( t11 ); } + variant( T12 const & t12 ) : type_index( 12 ) { new( ptr() ) T12( t12 ); } + variant( T13 const & t13 ) : type_index( 13 ) { new( ptr() ) T13( t13 ); } + variant( T14 const & t14 ) : type_index( 14 ) { new( ptr() ) T14( t14 ); } + variant( T15 const & t15 ) : type_index( 15 ) { new( ptr() ) T15( t15 ); } + + +#if variant_CPP11_OR_GREATER + variant( T0 && t0 ) : type_index( 0 ) { new( ptr() ) T0( std::move(t0) ); } + variant( T1 && t1 ) : type_index( 1 ) { new( ptr() ) T1( std::move(t1) ); } + variant( T2 && t2 ) : type_index( 2 ) { new( ptr() ) T2( std::move(t2) ); } + variant( T3 && t3 ) : type_index( 3 ) { new( ptr() ) T3( std::move(t3) ); } + variant( T4 && t4 ) : type_index( 4 ) { new( ptr() ) T4( std::move(t4) ); } + variant( T5 && t5 ) : type_index( 5 ) { new( ptr() ) T5( std::move(t5) ); } + variant( T6 && t6 ) : type_index( 6 ) { new( ptr() ) T6( std::move(t6) ); } + variant( T7 && t7 ) : type_index( 7 ) { new( ptr() ) T7( std::move(t7) ); } + variant( T8 && t8 ) : type_index( 8 ) { new( ptr() ) T8( std::move(t8) ); } + variant( T9 && t9 ) : type_index( 9 ) { new( ptr() ) T9( std::move(t9) ); } + variant( T10 && t10 ) : type_index( 10 ) { new( ptr() ) T10( std::move(t10) ); } + variant( T11 && t11 ) : type_index( 11 ) { new( ptr() ) T11( std::move(t11) ); } + variant( T12 && t12 ) : type_index( 12 ) { new( ptr() ) T12( std::move(t12) ); } + variant( T13 && t13 ) : type_index( 13 ) { new( ptr() ) T13( std::move(t13) ); } + variant( T14 && t14 ) : type_index( 14 ) { new( ptr() ) T14( std::move(t14) ); } + variant( T15 && t15 ) : type_index( 15 ) { new( ptr() ) T15( std::move(t15) ); } + +#endif + + variant(variant const & other) + : type_index( other.type_index ) + { + (void) helper_type::copy_construct( other.type_index, other.ptr(), ptr() ); + } + +#if variant_CPP11_OR_GREATER + + variant( variant && other ) noexcept( + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value) + : type_index( other.type_index ) + { + (void) helper_type::move_construct( other.type_index, other.ptr(), ptr() ); + } + + template< std::size_t K > + using type_at_t = typename detail::typelist_type_at< variant_types, K >::type; + + template< class T, class... Args + variant_REQUIRES_T( std::is_constructible< T, Args...>::value ) + > + explicit variant( nonstd_lite_in_place_type_t(T), Args&&... args) + { + type_index = variant_npos_internal(); + type_index = helper_type::template construct_t( ptr(), std::forward(args)... ); + } + + template< class T, class U, class... Args + variant_REQUIRES_T( std::is_constructible< T, std::initializer_list&, Args...>::value ) + > + explicit variant( nonstd_lite_in_place_type_t(T), std::initializer_list il, Args&&... args ) + { + type_index = variant_npos_internal(); + type_index = helper_type::template construct_t( ptr(), il, std::forward(args)... ); + } + + template< std::size_t K, class... Args + variant_REQUIRES_T( std::is_constructible< type_at_t, Args...>::value ) + > + explicit variant( nonstd_lite_in_place_index_t(K), Args&&... args ) + { + type_index = variant_npos_internal(); + type_index = helper_type::template construct_i( ptr(), std::forward(args)... ); + } + + template< size_t K, class U, class... Args + variant_REQUIRES_T( std::is_constructible< type_at_t, std::initializer_list&, Args...>::value ) + > + explicit variant( nonstd_lite_in_place_index_t(K), std::initializer_list il, Args&&... args ) + { + type_index = variant_npos_internal(); + type_index = helper_type::template construct_i( ptr(), il, std::forward(args)... ); + } + +#endif // variant_CPP11_OR_GREATER + + // 19.7.3.2 Destructor + + ~variant() + { + if ( ! valueless_by_exception() ) + { + helper_type::destroy( type_index, ptr() ); + } + } + + // 19.7.3.3 Assignment + + variant & operator=( variant const & other ) + { + return copy_assign( other ); + } + +#if variant_CPP11_OR_GREATER + + variant & operator=( variant && other ) noexcept( + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_assignable::value) + { + return move_assign( std::move( other ) ); + } + + variant & operator=( T0 && t0 ) { return assign_value<0>( std::move( t0 ) ); } + variant & operator=( T1 && t1 ) { return assign_value<1>( std::move( t1 ) ); } + variant & operator=( T2 && t2 ) { return assign_value<2>( std::move( t2 ) ); } + variant & operator=( T3 && t3 ) { return assign_value<3>( std::move( t3 ) ); } + variant & operator=( T4 && t4 ) { return assign_value<4>( std::move( t4 ) ); } + variant & operator=( T5 && t5 ) { return assign_value<5>( std::move( t5 ) ); } + variant & operator=( T6 && t6 ) { return assign_value<6>( std::move( t6 ) ); } + variant & operator=( T7 && t7 ) { return assign_value<7>( std::move( t7 ) ); } + variant & operator=( T8 && t8 ) { return assign_value<8>( std::move( t8 ) ); } + variant & operator=( T9 && t9 ) { return assign_value<9>( std::move( t9 ) ); } + variant & operator=( T10 && t10 ) { return assign_value<10>( std::move( t10 ) ); } + variant & operator=( T11 && t11 ) { return assign_value<11>( std::move( t11 ) ); } + variant & operator=( T12 && t12 ) { return assign_value<12>( std::move( t12 ) ); } + variant & operator=( T13 && t13 ) { return assign_value<13>( std::move( t13 ) ); } + variant & operator=( T14 && t14 ) { return assign_value<14>( std::move( t14 ) ); } + variant & operator=( T15 && t15 ) { return assign_value<15>( std::move( t15 ) ); } + + +#endif + + variant & operator=( T0 const & t0 ) { return assign_value<0>( t0 ); } + variant & operator=( T1 const & t1 ) { return assign_value<1>( t1 ); } + variant & operator=( T2 const & t2 ) { return assign_value<2>( t2 ); } + variant & operator=( T3 const & t3 ) { return assign_value<3>( t3 ); } + variant & operator=( T4 const & t4 ) { return assign_value<4>( t4 ); } + variant & operator=( T5 const & t5 ) { return assign_value<5>( t5 ); } + variant & operator=( T6 const & t6 ) { return assign_value<6>( t6 ); } + variant & operator=( T7 const & t7 ) { return assign_value<7>( t7 ); } + variant & operator=( T8 const & t8 ) { return assign_value<8>( t8 ); } + variant & operator=( T9 const & t9 ) { return assign_value<9>( t9 ); } + variant & operator=( T10 const & t10 ) { return assign_value<10>( t10 ); } + variant & operator=( T11 const & t11 ) { return assign_value<11>( t11 ); } + variant & operator=( T12 const & t12 ) { return assign_value<12>( t12 ); } + variant & operator=( T13 const & t13 ) { return assign_value<13>( t13 ); } + variant & operator=( T14 const & t14 ) { return assign_value<14>( t14 ); } + variant & operator=( T15 const & t15 ) { return assign_value<15>( t15 ); } + + + std::size_t index() const + { + return variant_npos_internal() == type_index ? variant_npos : static_cast( type_index ); + } + + // 19.7.3.4 Modifiers + +#if variant_CPP11_OR_GREATER + template< class T, class... Args + variant_REQUIRES_T( std::is_constructible< T, Args...>::value ) + > + T& emplace( Args&&... args ) + { + helper_type::destroy( type_index, ptr() ); + type_index = variant_npos_internal(); + type_index = helper_type::template construct_t( ptr(), std::forward(args)... ); + + return *as(); + } + + template< class T, class U, class... Args + variant_REQUIRES_T( std::is_constructible< T, std::initializer_list&, Args...>::value ) + > + T& emplace( std::initializer_list il, Args&&... args ) + { + helper_type::destroy( type_index, ptr() ); + type_index = variant_npos_internal(); + type_index = helper_type::template construct_t( ptr(), il, std::forward(args)... ); + + return *as(); + } + + template< size_t K, class... Args + variant_REQUIRES_T( std::is_constructible< type_at_t, Args...>::value ) + > + variant_alternative_t & emplace( Args&&... args ) + { + return this->template emplace< type_at_t >( std::forward(args)... ); + } + + template< size_t K, class U, class... Args + variant_REQUIRES_T( std::is_constructible< type_at_t, std::initializer_list&, Args...>::value ) + > + variant_alternative_t & emplace( std::initializer_list il, Args&&... args ) + { + return this->template emplace< type_at_t >( il, std::forward(args)... ); + } + +#endif // variant_CPP11_OR_GREATER + + // 19.7.3.5 Value status + + bool valueless_by_exception() const + { + return type_index == variant_npos_internal(); + } + + // 19.7.3.6 Swap + + void swap( variant & other ) +#if variant_CPP11_OR_GREATER + noexcept( + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std17::is_nothrow_swappable::value + + ) +#endif + { + if ( valueless_by_exception() && other.valueless_by_exception() ) + { + // no effect + } + else if ( type_index == other.type_index ) + { + this->swap_value( type_index, other ); + } + else + { +#if variant_CPP11_OR_GREATER + variant tmp( std::move( *this ) ); + *this = std::move( other ); + other = std::move( tmp ); +#else + variant tmp( *this ); + *this = other; + other = tmp; +#endif + } + } + + // + // non-standard: + // + + template< class T > + static variant_constexpr std::size_t index_of() variant_noexcept + { + return to_size_t( detail::typelist_index_of::type >::value ); + } + + template< class T > + T & get() + { + const std::size_t i = index_of(); + +#if variant_CONFIG_NO_EXCEPTIONS + assert( i == index() ); +#else + if ( i != index() ) + { + throw bad_variant_access(); + } +#endif + return *as(); + } + + template< class T > + T const & get() const + { + const std::size_t i = index_of(); + +#if variant_CONFIG_NO_EXCEPTIONS + assert( i == index() ); +#else + if ( i != index() ) + { + throw bad_variant_access(); + } +#endif + return *as(); + } + + template< std::size_t K > + typename variant_alternative< K, variant >::type & + get() + { + return this->template get< typename detail::typelist_type_at< variant_types, K >::type >(); + } + + template< std::size_t K > + typename variant_alternative< K, variant >::type const & + get() const + { + return this->template get< typename detail::typelist_type_at< variant_types, K >::type >(); + } + +private: + typedef typename helper_type::type_index_t type_index_t; + + void * ptr() variant_noexcept + { + return &data; + } + + void const * ptr() const variant_noexcept + { + return &data; + } + + template< class U > + U * as() + { + return reinterpret_cast( ptr() ); + } + + template< class U > + U const * as() const + { + return reinterpret_cast( ptr() ); + } + + template< class U > + static variant_constexpr std::size_t to_size_t( U index ) + { + return static_cast( index ); + } + + variant_constexpr type_index_t variant_npos_internal() const variant_noexcept + { + return static_cast( -1 ); + } + + variant & copy_assign( variant const & other ) + { + if ( valueless_by_exception() && other.valueless_by_exception() ) + { + // no effect + } + else if ( ! valueless_by_exception() && other.valueless_by_exception() ) + { + helper_type::destroy( type_index, ptr() ); + type_index = variant_npos_internal(); + } + else if ( index() == other.index() ) + { + type_index = helper_type::copy_assign( other.type_index, other.ptr(), ptr() ); + } + else + { + helper_type::destroy( type_index, ptr() ); + type_index = variant_npos_internal(); + type_index = helper_type::copy_construct( other.type_index, other.ptr(), ptr() ); + } + return *this; + } + +#if variant_CPP11_OR_GREATER + + variant & move_assign( variant && other ) + { + if ( valueless_by_exception() && other.valueless_by_exception() ) + { + // no effect + } + else if ( ! valueless_by_exception() && other.valueless_by_exception() ) + { + helper_type::destroy( type_index, ptr() ); + type_index = variant_npos_internal(); + } + else if ( index() == other.index() ) + { + type_index = helper_type::move_assign( other.type_index, other.ptr(), ptr() ); + } + else + { + helper_type::destroy( type_index, ptr() ); + type_index = variant_npos_internal(); + type_index = helper_type::move_construct( other.type_index, other.ptr(), ptr() ); + } + return *this; + } + + template< std::size_t K, class T > + variant & assign_value( T && value ) + { + if( index() == K ) + { + *as() = std::forward( value ); + } + else + { + helper_type::destroy( type_index, ptr() ); + type_index = variant_npos_internal(); + new( ptr() ) T( std::forward( value ) ); + type_index = K; + } + return *this; + } + +#endif // variant_CPP11_OR_GREATER + + template< std::size_t K, class T > + variant & assign_value( T const & value ) + { + if( index() == K ) + { + *as() = value; + } + else + { + helper_type::destroy( type_index, ptr() ); + type_index = variant_npos_internal(); + new( ptr() ) T( value ); + type_index = K; + } + return *this; + } + + void swap_value( type_index_t index, variant & other ) + { + using std::swap; + switch( index ) + { + case 0: swap( this->get<0>(), other.get<0>() ); break; + case 1: swap( this->get<1>(), other.get<1>() ); break; + case 2: swap( this->get<2>(), other.get<2>() ); break; + case 3: swap( this->get<3>(), other.get<3>() ); break; + case 4: swap( this->get<4>(), other.get<4>() ); break; + case 5: swap( this->get<5>(), other.get<5>() ); break; + case 6: swap( this->get<6>(), other.get<6>() ); break; + case 7: swap( this->get<7>(), other.get<7>() ); break; + case 8: swap( this->get<8>(), other.get<8>() ); break; + case 9: swap( this->get<9>(), other.get<9>() ); break; + case 10: swap( this->get<10>(), other.get<10>() ); break; + case 11: swap( this->get<11>(), other.get<11>() ); break; + case 12: swap( this->get<12>(), other.get<12>() ); break; + case 13: swap( this->get<13>(), other.get<13>() ); break; + case 14: swap( this->get<14>(), other.get<14>() ); break; + case 15: swap( this->get<15>(), other.get<15>() ); break; + + } + } + +private: + enum { data_size = detail::typelist_max< variant_types >::value }; + +#if variant_CPP11_OR_GREATER + + enum { data_align = detail::typelist_max_alignof< variant_types >::value }; + + using aligned_storage_t = typename std::aligned_storage< data_size, data_align >::type; + aligned_storage_t data; + +#elif variant_CONFIG_MAX_ALIGN_HACK + + typedef union { unsigned char data[ data_size ]; } aligned_storage_t; + + detail::max_align_t hack; + aligned_storage_t data; + +#else + typedef typename detail::typelist_max< variant_types >::type max_type; + + typedef variant_ALIGN_AS( max_type ) align_as_type; + + typedef union { align_as_type data[ 1 + ( data_size - 1 ) / sizeof(align_as_type) ]; } aligned_storage_t; + aligned_storage_t data; + +// # undef variant_ALIGN_AS + +#endif // variant_CONFIG_MAX_ALIGN_HACK + + type_index_t type_index; +}; + +// 19.7.5 Value access + +template< class T, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline bool holds_alternative( variant const & v ) variant_noexcept +{ + return v.index() == variant::template index_of(); +} + +template< class R, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline R & get( variant & v, nonstd_lite_in_place_type_t(R) = nonstd_lite_in_place_type(R) ) +{ + return v.template get(); +} + +template< class R, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline R const & get( variant const & v, nonstd_lite_in_place_type_t(R) = nonstd_lite_in_place_type(R) ) +{ + return v.template get(); +} + +template< std::size_t K, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline typename variant_alternative< K, variant >::type & +get( variant & v, nonstd_lite_in_place_index_t(K) = nonstd_lite_in_place_index(K) ) +{ +#if variant_CONFIG_NO_EXCEPTIONS + assert( K == v.index() ); +#else + if ( K != v.index() ) + { + throw bad_variant_access(); + } +#endif + return v.template get(); +} + +template< std::size_t K, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline typename variant_alternative< K, variant >::type const & +get( variant const & v, nonstd_lite_in_place_index_t(K) = nonstd_lite_in_place_index(K) ) +{ +#if variant_CONFIG_NO_EXCEPTIONS + assert( K == v.index() ); +#else + if ( K != v.index() ) + { + throw bad_variant_access(); + } +#endif + return v.template get(); +} + +#if variant_CPP11_OR_GREATER + +template< class R, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline R && get( variant && v, nonstd_lite_in_place_type_t(R) = nonstd_lite_in_place_type(R) ) +{ + return std::move(v.template get()); +} + +template< class R, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline R const && get( variant const && v, nonstd_lite_in_place_type_t(R) = nonstd_lite_in_place_type(R) ) +{ + return std::move(v.template get()); +} + +template< std::size_t K, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline typename variant_alternative< K, variant >::type && +get( variant && v, nonstd_lite_in_place_index_t(K) = nonstd_lite_in_place_index(K) ) +{ +#if variant_CONFIG_NO_EXCEPTIONS + assert( K == v.index() ); +#else + if ( K != v.index() ) + { + throw bad_variant_access(); + } +#endif + return std::move(v.template get()); +} + +template< std::size_t K, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline typename variant_alternative< K, variant >::type const && +get( variant const && v, nonstd_lite_in_place_index_t(K) = nonstd_lite_in_place_index(K) ) +{ +#if variant_CONFIG_NO_EXCEPTIONS + assert( K == v.index() ); +#else + if ( K != v.index() ) + { + throw bad_variant_access(); + } +#endif + return std::move(v.template get()); +} + +#endif // variant_CPP11_OR_GREATER + +template< class T, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline typename std11::add_pointer::type +get_if( variant * pv, nonstd_lite_in_place_type_t(T) = nonstd_lite_in_place_type(T) ) +{ + return ( pv->index() == variant::template index_of() ) ? &get( *pv ) : variant_nullptr; +} + +template< class T, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline typename std11::add_pointer::type +get_if( variant const * pv, nonstd_lite_in_place_type_t(T) = nonstd_lite_in_place_type(T)) +{ + return ( pv->index() == variant::template index_of() ) ? &get( *pv ) : variant_nullptr; +} + +template< std::size_t K, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline typename std11::add_pointer< typename variant_alternative >::type >::type +get_if( variant * pv, nonstd_lite_in_place_index_t(K) = nonstd_lite_in_place_index(K) ) +{ + return ( pv->index() == K ) ? &get( *pv ) : variant_nullptr; +} + +template< std::size_t K, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline typename std11::add_pointer< const typename variant_alternative >::type >::type +get_if( variant const * pv, nonstd_lite_in_place_index_t(K) = nonstd_lite_in_place_index(K) ) +{ + return ( pv->index() == K ) ? &get( *pv ) : variant_nullptr; +} + +// 19.7.10 Specialized algorithms + +template< class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 +#if variant_CPP11_OR_GREATER + variant_REQUIRES_T( + std::is_move_constructible::value && std17::is_swappable::value && + std::is_move_constructible::value && std17::is_swappable::value && + std::is_move_constructible::value && std17::is_swappable::value && + std::is_move_constructible::value && std17::is_swappable::value && + std::is_move_constructible::value && std17::is_swappable::value && + std::is_move_constructible::value && std17::is_swappable::value && + std::is_move_constructible::value && std17::is_swappable::value && + std::is_move_constructible::value && std17::is_swappable::value && + std::is_move_constructible::value && std17::is_swappable::value && + std::is_move_constructible::value && std17::is_swappable::value && + std::is_move_constructible::value && std17::is_swappable::value && + std::is_move_constructible::value && std17::is_swappable::value && + std::is_move_constructible::value && std17::is_swappable::value && + std::is_move_constructible::value && std17::is_swappable::value && + std::is_move_constructible::value && std17::is_swappable::value && + std::is_move_constructible::value && std17::is_swappable::value + ) +#endif +> +inline void swap( + variant & a, + variant & b ) +#if variant_CPP11_OR_GREATER + noexcept( noexcept( a.swap( b ) ) ) +#endif +{ + a.swap( b ); +} + +// 19.7.7 Visitation + +// Variant 'visitor' implementation + +namespace detail +{ + +template< typename R, typename VT > +struct VisitorApplicatorImpl +{ + template< typename Visitor, typename T > + static R apply(Visitor const& v, T const& arg) + { + return v(arg); + } +}; + +template< typename R, typename VT > +struct VisitorApplicatorImpl > +{ + template< typename Visitor, typename T > + static R apply(Visitor const&, T) + { + return R(); + } +}; + +template +struct VisitorApplicator; + +template< typename R, typename Visitor, typename V1 > +struct VisitorUnwrapper; + +#if variant_CPP11_OR_GREATER +template< size_t NumVars, typename R, typename Visitor, typename ... T > +#else +template< size_t NumVars, typename R, typename Visitor, typename T1, typename T2 = S0, typename T3 = S0, typename T4 = S0, typename T5 = S0 > +#endif +struct TypedVisitorUnwrapper; + +template< typename R, typename Visitor, typename T2 > +struct TypedVisitorUnwrapper<2, R, Visitor, T2> +{ + const Visitor& visitor; + T2 const& val2; + + TypedVisitorUnwrapper(const Visitor& visitor_, T2 const& val2_) + : visitor(visitor_) + , val2(val2_) + + { + } + + template + R operator()(const T& val1) const + { + return visitor(val1, val2); + } +}; + +template< typename R, typename Visitor, typename T2, typename T3 > +struct TypedVisitorUnwrapper<3, R, Visitor, T2, T3> +{ + const Visitor& visitor; + T2 const& val2; + T3 const& val3; + + TypedVisitorUnwrapper(const Visitor& visitor_, T2 const& val2_, T3 const& val3_) + : visitor(visitor_) + , val2(val2_) + , val3(val3_) + + { + } + + template + R operator()(const T& val1) const + { + return visitor(val1, val2, val3); + } +}; + +template< typename R, typename Visitor, typename T2, typename T3, typename T4 > +struct TypedVisitorUnwrapper<4, R, Visitor, T2, T3, T4> +{ + const Visitor& visitor; + T2 const& val2; + T3 const& val3; + T4 const& val4; + + TypedVisitorUnwrapper(const Visitor& visitor_, T2 const& val2_, T3 const& val3_, T4 const& val4_) + : visitor(visitor_) + , val2(val2_) + , val3(val3_) + , val4(val4_) + + { + } + + template + R operator()(const T& val1) const + { + return visitor(val1, val2, val3, val4); + } +}; + +template< typename R, typename Visitor, typename T2, typename T3, typename T4, typename T5 > +struct TypedVisitorUnwrapper<5, R, Visitor, T2, T3, T4, T5> +{ + const Visitor& visitor; + T2 const& val2; + T3 const& val3; + T4 const& val4; + T5 const& val5; + + TypedVisitorUnwrapper(const Visitor& visitor_, T2 const& val2_, T3 const& val3_, T4 const& val4_, T5 const& val5_) + : visitor(visitor_) + , val2(val2_) + , val3(val3_) + , val4(val4_) + , val5(val5_) + + { + } + + template + R operator()(const T& val1) const + { + return visitor(val1, val2, val3, val4, val5); + } +}; + + + +template +struct VisitorUnwrapper +{ + const Visitor& visitor; + const V2& r; + + VisitorUnwrapper(const Visitor& visitor_, const V2& r_) + : visitor(visitor_) + , r(r_) + { + } + + + template< typename T1 > + R operator()(T1 const& val1) const + { + typedef TypedVisitorUnwrapper<2, R, Visitor, T1> visitor_type; + return VisitorApplicator::apply(visitor_type(visitor, val1), r); + } + + template< typename T1, typename T2 > + R operator()(T1 const& val1, T2 const& val2) const + { + typedef TypedVisitorUnwrapper<3, R, Visitor, T1, T2> visitor_type; + return VisitorApplicator::apply(visitor_type(visitor, val1, val2), r); + } + + template< typename T1, typename T2, typename T3 > + R operator()(T1 const& val1, T2 const& val2, T3 const& val3) const + { + typedef TypedVisitorUnwrapper<4, R, Visitor, T1, T2, T3> visitor_type; + return VisitorApplicator::apply(visitor_type(visitor, val1, val2, val3), r); + } + + template< typename T1, typename T2, typename T3, typename T4 > + R operator()(T1 const& val1, T2 const& val2, T3 const& val3, T4 const& val4) const + { + typedef TypedVisitorUnwrapper<5, R, Visitor, T1, T2, T3, T4> visitor_type; + return VisitorApplicator::apply(visitor_type(visitor, val1, val2, val3, val4), r); + } + + template< typename T1, typename T2, typename T3, typename T4, typename T5 > + R operator()(T1 const& val1, T2 const& val2, T3 const& val3, T4 const& val4, T5 const& val5) const + { + typedef TypedVisitorUnwrapper<6, R, Visitor, T1, T2, T3, T4, T5> visitor_type; + return VisitorApplicator::apply(visitor_type(visitor, val1, val2, val3, val4, val5), r); + } + +}; + + +template +struct VisitorApplicator +{ + template + static R apply(const Visitor& v, const V1& arg) + { + switch( arg.index() ) + { + case 0: return apply_visitor<0>(v, arg); + case 1: return apply_visitor<1>(v, arg); + case 2: return apply_visitor<2>(v, arg); + case 3: return apply_visitor<3>(v, arg); + case 4: return apply_visitor<4>(v, arg); + case 5: return apply_visitor<5>(v, arg); + case 6: return apply_visitor<6>(v, arg); + case 7: return apply_visitor<7>(v, arg); + case 8: return apply_visitor<8>(v, arg); + case 9: return apply_visitor<9>(v, arg); + case 10: return apply_visitor<10>(v, arg); + case 11: return apply_visitor<11>(v, arg); + case 12: return apply_visitor<12>(v, arg); + case 13: return apply_visitor<13>(v, arg); + case 14: return apply_visitor<14>(v, arg); + case 15: return apply_visitor<15>(v, arg); + + default: return R(); + } + } + + template + static R apply_visitor(const Visitor& v, const V1& arg) + { + +#if variant_CPP11_OR_GREATER + typedef typename variant_alternative::type>::type value_type; +#else + typedef typename variant_alternative::type value_type; +#endif + return VisitorApplicatorImpl::apply(v, get(arg)); + } + +#if variant_CPP11_OR_GREATER + template + static R apply(const Visitor& v, const V1& arg1, const V2& arg2, const V ... args) + { + typedef VisitorUnwrapper Unwrapper; + Unwrapper unwrapper(v, arg1); + return apply(unwrapper, arg2, args ...); + } +#else + + template< typename Visitor, typename V1, typename V2 > + static R apply(const Visitor& v, V1 const& arg1, V2 const& arg2) + { + typedef VisitorUnwrapper Unwrapper; + Unwrapper unwrapper(v, arg1); + return apply(unwrapper, arg2); + } + + template< typename Visitor, typename V1, typename V2, typename V3 > + static R apply(const Visitor& v, V1 const& arg1, V2 const& arg2, V3 const& arg3) + { + typedef VisitorUnwrapper Unwrapper; + Unwrapper unwrapper(v, arg1); + return apply(unwrapper, arg2, arg3); + } + + template< typename Visitor, typename V1, typename V2, typename V3, typename V4 > + static R apply(const Visitor& v, V1 const& arg1, V2 const& arg2, V3 const& arg3, V4 const& arg4) + { + typedef VisitorUnwrapper Unwrapper; + Unwrapper unwrapper(v, arg1); + return apply(unwrapper, arg2, arg3, arg4); + } + + template< typename Visitor, typename V1, typename V2, typename V3, typename V4, typename V5 > + static R apply(const Visitor& v, V1 const& arg1, V2 const& arg2, V3 const& arg3, V4 const& arg4, V5 const& arg5) + { + typedef VisitorUnwrapper Unwrapper; + Unwrapper unwrapper(v, arg1); + return apply(unwrapper, arg2, arg3, arg4, arg5); + } + +#endif +}; + +#if variant_CPP11_OR_GREATER +template< size_t NumVars, typename Visitor, typename ... V > +struct VisitorImpl +{ + typedef decltype(std::declval()(get<0>(static_cast(std::declval()))...)) result_type; + typedef VisitorApplicator applicator_type; +}; +#endif +} // detail + +#if variant_CPP11_OR_GREATER +// No perfect forwarding here in order to simplify code +template< typename Visitor, typename ... V > +inline auto visit(Visitor const& v, V const& ... vars) -> typename detail::VisitorImpl ::result_type +{ + typedef detail::VisitorImpl impl_type; + return impl_type::applicator_type::apply(v, vars...); +} +#else + +template< typename R, typename Visitor, typename V1 > +inline R visit(const Visitor& v, V1 const& arg1) +{ + return detail::VisitorApplicator::apply(v, arg1); +} + +template< typename R, typename Visitor, typename V1, typename V2 > +inline R visit(const Visitor& v, V1 const& arg1, V2 const& arg2) +{ + return detail::VisitorApplicator::apply(v, arg1, arg2); +} + +template< typename R, typename Visitor, typename V1, typename V2, typename V3 > +inline R visit(const Visitor& v, V1 const& arg1, V2 const& arg2, V3 const& arg3) +{ + return detail::VisitorApplicator::apply(v, arg1, arg2, arg3); +} + +template< typename R, typename Visitor, typename V1, typename V2, typename V3, typename V4 > +inline R visit(const Visitor& v, V1 const& arg1, V2 const& arg2, V3 const& arg3, V4 const& arg4) +{ + return detail::VisitorApplicator::apply(v, arg1, arg2, arg3, arg4); +} + +template< typename R, typename Visitor, typename V1, typename V2, typename V3, typename V4, typename V5 > +inline R visit(const Visitor& v, V1 const& arg1, V2 const& arg2, V3 const& arg3, V4 const& arg4, V5 const& arg5) +{ + return detail::VisitorApplicator::apply(v, arg1, arg2, arg3, arg4, arg5); +} + +#endif + +// 19.7.6 Relational operators + +namespace detail { + +template< class Variant > +struct Comparator +{ + static inline bool equal( Variant const & v, Variant const & w ) + { + switch( v.index() ) + { + case 0: return get<0>( v ) == get<0>( w ); + case 1: return get<1>( v ) == get<1>( w ); + case 2: return get<2>( v ) == get<2>( w ); + case 3: return get<3>( v ) == get<3>( w ); + case 4: return get<4>( v ) == get<4>( w ); + case 5: return get<5>( v ) == get<5>( w ); + case 6: return get<6>( v ) == get<6>( w ); + case 7: return get<7>( v ) == get<7>( w ); + case 8: return get<8>( v ) == get<8>( w ); + case 9: return get<9>( v ) == get<9>( w ); + case 10: return get<10>( v ) == get<10>( w ); + case 11: return get<11>( v ) == get<11>( w ); + case 12: return get<12>( v ) == get<12>( w ); + case 13: return get<13>( v ) == get<13>( w ); + case 14: return get<14>( v ) == get<14>( w ); + case 15: return get<15>( v ) == get<15>( w ); + + default: return false; + } + } + + static inline bool less_than( Variant const & v, Variant const & w ) + { + switch( v.index() ) + { + case 0: return get<0>( v ) < get<0>( w ); + case 1: return get<1>( v ) < get<1>( w ); + case 2: return get<2>( v ) < get<2>( w ); + case 3: return get<3>( v ) < get<3>( w ); + case 4: return get<4>( v ) < get<4>( w ); + case 5: return get<5>( v ) < get<5>( w ); + case 6: return get<6>( v ) < get<6>( w ); + case 7: return get<7>( v ) < get<7>( w ); + case 8: return get<8>( v ) < get<8>( w ); + case 9: return get<9>( v ) < get<9>( w ); + case 10: return get<10>( v ) < get<10>( w ); + case 11: return get<11>( v ) < get<11>( w ); + case 12: return get<12>( v ) < get<12>( w ); + case 13: return get<13>( v ) < get<13>( w ); + case 14: return get<14>( v ) < get<14>( w ); + case 15: return get<15>( v ) < get<15>( w ); + + default: return false; + } + } +}; + +} //namespace detail + +template< class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline bool operator==( + variant const & v, + variant const & w ) +{ + if ( v.index() != w.index() ) return false; + else if ( v.valueless_by_exception() ) return true; + else return detail::Comparator< variant >::equal( v, w ); +} + +template< class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline bool operator!=( + variant const & v, + variant const & w ) +{ + return ! ( v == w ); +} + +template< class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline bool operator<( + variant const & v, + variant const & w ) +{ + if ( w.valueless_by_exception() ) return false; + else if ( v.valueless_by_exception() ) return true; + else if ( v.index() < w.index() ) return true; + else if ( v.index() > w.index() ) return false; + else return detail::Comparator< variant >::less_than( v, w ); +} + +template< class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline bool operator>( + variant const & v, + variant const & w ) +{ + return w < v; +} + +template< class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline bool operator<=( + variant const & v, + variant const & w ) +{ + return ! ( v > w ); +} + +template< class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +inline bool operator>=( + variant const & v, + variant const & w ) +{ + return ! ( v < w ); +} + +} // namespace variants + +using namespace variants; + +} // namespace nonstd + +#if variant_CPP11_OR_GREATER + +// 19.7.12 Hash support + +namespace std { + +template<> +struct hash< nonstd::monostate > +{ + std::size_t operator()( nonstd::monostate ) const variant_noexcept + { + return 42; + } +}; + +template< class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 > +struct hash< nonstd::variant > +{ + std::size_t operator()( nonstd::variant const & v ) const variant_noexcept + { + namespace nvd = nonstd::variants::detail; + + switch( v.index() ) + { + case 0: return nvd::hash( 0 ) ^ nvd::hash( get<0>( v ) ); + case 1: return nvd::hash( 1 ) ^ nvd::hash( get<1>( v ) ); + case 2: return nvd::hash( 2 ) ^ nvd::hash( get<2>( v ) ); + case 3: return nvd::hash( 3 ) ^ nvd::hash( get<3>( v ) ); + case 4: return nvd::hash( 4 ) ^ nvd::hash( get<4>( v ) ); + case 5: return nvd::hash( 5 ) ^ nvd::hash( get<5>( v ) ); + case 6: return nvd::hash( 6 ) ^ nvd::hash( get<6>( v ) ); + case 7: return nvd::hash( 7 ) ^ nvd::hash( get<7>( v ) ); + case 8: return nvd::hash( 8 ) ^ nvd::hash( get<8>( v ) ); + case 9: return nvd::hash( 9 ) ^ nvd::hash( get<9>( v ) ); + case 10: return nvd::hash( 10 ) ^ nvd::hash( get<10>( v ) ); + case 11: return nvd::hash( 11 ) ^ nvd::hash( get<11>( v ) ); + case 12: return nvd::hash( 12 ) ^ nvd::hash( get<12>( v ) ); + case 13: return nvd::hash( 13 ) ^ nvd::hash( get<13>( v ) ); + case 14: return nvd::hash( 14 ) ^ nvd::hash( get<14>( v ) ); + case 15: return nvd::hash( 15 ) ^ nvd::hash( get<15>( v ) ); + + default: return false; + } + } +}; + +} //namespace std + +#endif // variant_CPP11_OR_GREATER + +#if variant_BETWEEN( variant_COMPILER_MSVC_VER, 1300, 1900 ) +# pragma warning( pop ) +#endif + +#endif // variant_USES_STD_VARIANT + +#endif // NONSTD_VARIANT_LITE_HPP diff --git a/ndn-cxx/util/notification-stream.hpp b/ndn-cxx/util/notification-stream.hpp new file mode 100644 index 000000000..4dc5862c0 --- /dev/null +++ b/ndn-cxx/util/notification-stream.hpp @@ -0,0 +1,85 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014-2018 Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_NOTIFICATION_STREAM_HPP +#define NDN_UTIL_NOTIFICATION_STREAM_HPP + +#include "ndn-cxx/face.hpp" +#include "ndn-cxx/name.hpp" +#include "ndn-cxx/security/v2/key-chain.hpp" +#include "ndn-cxx/util/concepts.hpp" + +namespace ndn { +namespace util { + +/** \brief provides a publisher of Notification Stream + * \sa https://redmine.named-data.net/projects/nfd/wiki/Notification + */ +template +class NotificationStream : noncopyable +{ +public: + BOOST_CONCEPT_ASSERT((WireEncodable)); + + NotificationStream(Face& face, const Name& prefix, KeyChain& keyChain) + : m_face(face) + , m_prefix(prefix) + , m_keyChain(keyChain) + , m_sequenceNo(0) + { + } + + virtual + ~NotificationStream() = default; + + void + postNotification(const Notification& notification) + { + Name dataName = m_prefix; + dataName.appendSequenceNumber(m_sequenceNo); + + shared_ptr data = make_shared(dataName); + data->setContent(notification.wireEncode()); + data->setFreshnessPeriod(1_s); + + m_keyChain.sign(*data); + m_face.put(*data); + + ++m_sequenceNo; + } + +private: + Face& m_face; + const Name m_prefix; + KeyChain& m_keyChain; + uint64_t m_sequenceNo; +}; + +} // namespace util +} // namespace ndn + +#endif // NDN_UTIL_NOTIFICATION_STREAM_HPP diff --git a/ndn-cxx/util/notification-subscriber.cpp b/ndn-cxx/util/notification-subscriber.cpp new file mode 100644 index 000000000..ce9b3956a --- /dev/null +++ b/ndn-cxx/util/notification-subscriber.cpp @@ -0,0 +1,193 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014-2019 Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/notification-subscriber.hpp" +#include "ndn-cxx/util/random.hpp" + +#include + +namespace ndn { +namespace util { + +NotificationSubscriberBase::NotificationSubscriberBase(Face& face, const Name& prefix, + time::milliseconds interestLifetime) + : m_face(face) + , m_prefix(prefix) + , m_isRunning(false) + , m_lastSequenceNum(std::numeric_limits::max()) + , m_lastNackSequenceNum(std::numeric_limits::max()) + , m_attempts(1) + , m_scheduler(face.getIoService()) + , m_interestLifetime(interestLifetime) +{ +} + +NotificationSubscriberBase::~NotificationSubscriberBase() = default; + +void +NotificationSubscriberBase::start() +{ + if (m_isRunning) // already running + return; + m_isRunning = true; + + sendInitialInterest(); +} + +void +NotificationSubscriberBase::stop() +{ + if (!m_isRunning) // not running + return; + m_isRunning = false; + + m_lastInterest.cancel(); +} + +void +NotificationSubscriberBase::sendInitialInterest() +{ + if (shouldStop()) + return; + + auto interest = make_shared(m_prefix); + interest->setCanBePrefix(true); + interest->setMustBeFresh(true); + interest->setInterestLifetime(m_interestLifetime); + sendInterest(*interest); +} + +void +NotificationSubscriberBase::sendNextInterest() +{ + if (shouldStop()) + return; + + Name nextName = m_prefix; + nextName.appendSequenceNumber(m_lastSequenceNum + 1); + + auto interest = make_shared(nextName); + interest->setCanBePrefix(false); + interest->setInterestLifetime(m_interestLifetime); + sendInterest(*interest); +} + +void +NotificationSubscriberBase::sendInterest(const Interest& interest) +{ + m_lastInterest = m_face.expressInterest(interest, + [this] (const auto&, const auto& d) { this->afterReceiveData(d); }, + [this] (const auto&, const auto& n) { this->afterReceiveNack(n); }, + [this] (const auto&) { this->afterTimeout(); }); +} + +bool +NotificationSubscriberBase::shouldStop() +{ + if (!m_isRunning) + return true; + + if (!hasSubscriber() && onNack.isEmpty()) { + stop(); + return true; + } + return false; +} + +void +NotificationSubscriberBase::afterReceiveData(const Data& data) +{ + if (shouldStop()) + return; + + try { + m_lastSequenceNum = data.getName().get(-1).toSequenceNumber(); + } + catch (const tlv::Error&) { + onDecodeError(data); + sendInitialInterest(); + return; + } + + if (!decodeAndDeliver(data)) { + onDecodeError(data); + sendInitialInterest(); + return; + } + + sendNextInterest(); +} + +void +NotificationSubscriberBase::afterReceiveNack(const lp::Nack& nack) +{ + if (shouldStop()) + return; + + onNack(nack); + + time::milliseconds delay = exponentialBackoff(nack); + m_nackEvent = m_scheduler.schedule(delay, [this] { sendInitialInterest(); }); +} + +void +NotificationSubscriberBase::afterTimeout() +{ + if (shouldStop()) + return; + + onTimeout(); + + sendInitialInterest(); +} + +time::milliseconds +NotificationSubscriberBase::exponentialBackoff(lp::Nack nack) +{ + uint64_t nackSequenceNum; + try { + nackSequenceNum = nack.getInterest().getName().get(-1).toSequenceNumber(); + } + catch (const tlv::Error&) { + nackSequenceNum = 0; + } + + if (m_lastNackSequenceNum == nackSequenceNum) { + ++m_attempts; + } + else { + m_attempts = 1; + } + + m_lastNackSequenceNum = nackSequenceNum; + + return time::milliseconds(static_cast(std::pow(2, m_attempts) * 100 + + random::generateWord32() % 100)); +} + +} // namespace util +} // namespace ndn diff --git a/ndn-cxx/util/notification-subscriber.hpp b/ndn-cxx/util/notification-subscriber.hpp new file mode 100644 index 000000000..340eec723 --- /dev/null +++ b/ndn-cxx/util/notification-subscriber.hpp @@ -0,0 +1,199 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014-2019 Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_NOTIFICATION_SUBSCRIBER_HPP +#define NDN_UTIL_NOTIFICATION_SUBSCRIBER_HPP + +#include "ndn-cxx/face.hpp" +#include "ndn-cxx/util/concepts.hpp" +#include "ndn-cxx/util/scheduler.hpp" +#include "ndn-cxx/util/signal.hpp" +#include "ndn-cxx/util/time.hpp" + +namespace ndn { +namespace util { + +class NotificationSubscriberBase : noncopyable +{ +public: + virtual + ~NotificationSubscriberBase(); + + /** \return InterestLifetime of Interests to retrieve notifications + * + * This must be greater than FreshnessPeriod of Notification Data packets, + * to ensure correct operation of this subscriber implementation. + */ + time::milliseconds + getInterestLifetime() const + { + return m_interestLifetime; + } + + bool + isRunning() const + { + return m_isRunning; + } + + /** \brief start or resume receiving notifications + * \note onNotification must have at least one listener, + * otherwise this operation has no effect. + */ + void + start(); + + /** \brief stop receiving notifications + */ + void + stop(); + +protected: + /** \brief construct a NotificationSubscriber + * \note The subscriber is not started after construction. + * User should add one or more handlers to onNotification, and invoke .start(). + */ + NotificationSubscriberBase(Face& face, const Name& prefix, + time::milliseconds interestLifetime); + +private: + void + sendInitialInterest(); + + void + sendNextInterest(); + + void + sendInterest(const Interest& interest); + + virtual bool + hasSubscriber() const = 0; + + /** \brief Check if the subscriber is or should be stopped. + * \return true if the subscriber is stopped. + */ + bool + shouldStop(); + + void + afterReceiveData(const Data& data); + + /** \brief decode the Data as a notification, and deliver it to subscribers + * \return whether decode was successful + */ + virtual bool + decodeAndDeliver(const Data& data) = 0; + + void + afterReceiveNack(const lp::Nack& nack); + + void + afterTimeout(); + + time::milliseconds + exponentialBackoff(lp::Nack nack); + +public: + /** \brief fires when a NACK is received + */ + signal::Signal onNack; + + /** \brief fires when no Notification is received within .getInterestLifetime period + */ + signal::Signal onTimeout; + + /** \brief fires when a Data packet in the Notification Stream cannot be decoded as Notification + */ + signal::Signal onDecodeError; + +private: + Face& m_face; + Name m_prefix; + bool m_isRunning; + uint64_t m_lastSequenceNum; + uint64_t m_lastNackSequenceNum; + uint64_t m_attempts; + Scheduler m_scheduler; + scheduler::ScopedEventId m_nackEvent; + ScopedPendingInterestHandle m_lastInterest; + time::milliseconds m_interestLifetime; +}; + +/** \brief provides a subscriber of Notification Stream + * \sa https://redmine.named-data.net/projects/nfd/wiki/Notification + * \tparam Notification type of Notification item, appears in payload of Data packets + */ +template +class NotificationSubscriber : public NotificationSubscriberBase +{ +public: + BOOST_CONCEPT_ASSERT((boost::DefaultConstructible)); + BOOST_CONCEPT_ASSERT((WireDecodable)); + + /** \brief construct a NotificationSubscriber + * \note The subscriber is not started after construction. + * User should add one or more handlers to onNotification, and invoke .start(). + */ + NotificationSubscriber(Face& face, const Name& prefix, + time::milliseconds interestLifetime = 1_min) + : NotificationSubscriberBase(face, prefix, interestLifetime) + { + } + +public: + /** \brief fires when a Notification is received + * \note Removing all handlers will cause the subscriber to stop. + */ + signal::Signal onNotification; + +private: + bool + hasSubscriber() const override + { + return !onNotification.isEmpty(); + } + + bool + decodeAndDeliver(const Data& data) override + { + Notification notification; + try { + notification.wireDecode(data.getContent().blockFromValue()); + } + catch (const tlv::Error&) { + return false; + } + + onNotification(notification); + return true; + } +}; + +} // namespace util +} // namespace ndn + +#endif // NDN_UTIL_NOTIFICATION_SUBSCRIBER_HPP diff --git a/ndn-cxx/util/ostream-joiner.hpp b/ndn-cxx/util/ostream-joiner.hpp new file mode 100644 index 000000000..8586bd9f4 --- /dev/null +++ b/ndn-cxx/util/ostream-joiner.hpp @@ -0,0 +1,125 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +/** \file + * \brief Backport of ostream_joiner from the Library Fundamentals v2 TS + * \sa https://en.cppreference.com/w/cpp/experimental/ostream_joiner + */ + +#ifndef NDN_UTIL_OSTREAM_JOINER_HPP +#define NDN_UTIL_OSTREAM_JOINER_HPP + +#include "ndn-cxx/util/backports.hpp" + +#if NDN_CXX_HAS_INCLUDE() +# include +# if __cpp_lib_experimental_ostream_joiner >= 201411 +# define NDN_CXX_HAVE_EXPERIMENTAL_OSTREAM_JOINER +# endif +#endif + +#ifdef NDN_CXX_HAVE_EXPERIMENTAL_OSTREAM_JOINER + +namespace ndn { +using std::experimental::ostream_joiner; +using std::experimental::make_ostream_joiner; +} // namespace ndn + +#else + +#include + +namespace ndn { + +template> +class ostream_joiner +{ +public: + typedef CharT char_type; + typedef Traits traits_type; + typedef std::basic_ostream ostream_type; + typedef std::output_iterator_tag iterator_category; + typedef void value_type; + typedef void difference_type; + typedef void pointer; + typedef void reference; + + ostream_joiner(ostream_type& os, const DelimT& delimiter) + noexcept(std::is_nothrow_copy_constructible::value) + : m_os(std::addressof(os)), m_delim(delimiter) + { + } + + ostream_joiner(ostream_type& os, DelimT&& delimiter) + noexcept(std::is_nothrow_move_constructible::value) + : m_os(std::addressof(os)), m_delim(std::move(delimiter)) + { + } + + template + ostream_joiner& + operator=(const T& value) + { + if (!m_isFirst) { + *m_os << m_delim; + } + m_isFirst = false; + *m_os << value; + return *this; + } + + ostream_joiner& + operator*() noexcept + { + return *this; + } + + ostream_joiner& + operator++() noexcept + { + return *this; + } + + ostream_joiner& + operator++(int) noexcept + { + return *this; + } + +private: + ostream_type* m_os; + DelimT m_delim; + bool m_isFirst = true; +}; + +template +inline ostream_joiner, CharT, Traits> +make_ostream_joiner(std::basic_ostream& os, DelimT&& delimiter) +{ + return {os, std::forward(delimiter)}; +} + +} // namespace ndn + +#endif // NDN_CXX_HAVE_EXPERIMENTAL_OSTREAM_JOINER +#endif // NDN_UTIL_OSTREAM_JOINER_HPP diff --git a/ndn-cxx/util/overload.hpp b/ndn-cxx/util/overload.hpp new file mode 100644 index 000000000..228c684ed --- /dev/null +++ b/ndn-cxx/util/overload.hpp @@ -0,0 +1,113 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_OVERLOAD_HPP +#define NDN_UTIL_OVERLOAD_HPP + +#include +#include + +// Hana does not support GCC < 6.0.0 +#if (BOOST_VERSION >= 106100) && (!BOOST_COMP_GNUC || (BOOST_COMP_GNUC >= BOOST_VERSION_NUMBER(6,0,0))) + +#include + +namespace ndn { +constexpr boost::hana::make_overload_t overload{}; +} // namespace ndn + +#else + +#include + +namespace ndn { +namespace detail { + +// The following code is copied from the Boost.Hana library. +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See http://boost.org/LICENSE_1_0.txt) + +//! Pick one of several functions to call based on overload resolution. +//! +//! Specifically, `overload(f1, f2, ..., fn)` is a function object such +//! that +//! @code +//! overload(f1, f2, ..., fn)(x...) == fk(x...) +//! @endcode +//! +//! where `fk` is the function of `f1, ..., fn` that would be called if +//! overload resolution was performed amongst that set of functions only. +//! If more than one function `fk` would be picked by overload resolution, +//! then the call is ambiguous. +#ifndef DOXYGEN +template +struct overload_t + : overload_t::type + , overload_t::type +{ + using type = overload_t; + using overload_t::type::operator(); + using overload_t::type::operator(); + + template + constexpr explicit overload_t(F_&& f, G_&& ...g) + : overload_t::type(static_cast(f)) + , overload_t::type(static_cast(g)...) + { } +}; + +template +struct overload_t { using type = F; }; + +template +struct overload_t { + using type = overload_t; + R (*fptr_)(Args...); + + explicit constexpr overload_t(R (*fp)(Args...)) + : fptr_(fp) + { } + + constexpr R operator()(Args ...args) const + { return fptr_(static_cast(args)...); } +}; + +struct make_overload_t { + template ::type... + >::type + > + constexpr Overload operator()(F&& ...f) const { + return Overload(static_cast(f)...); + } +}; +#endif // DOXYGEN + +} // namespace detail + +constexpr detail::make_overload_t overload{}; + +} // namespace ndn + +#endif // BOOST_VERSION >= 106100 +#endif // NDN_UTIL_OVERLOAD_HPP diff --git a/ndn-cxx/util/random.cpp b/ndn-cxx/util/random.cpp new file mode 100644 index 000000000..5ff643ec3 --- /dev/null +++ b/ndn-cxx/util/random.cpp @@ -0,0 +1,80 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/random.hpp" +#include "ndn-cxx/security/impl/openssl.hpp" + +namespace ndn { +namespace random { + +uint32_t +generateSecureWord32() +{ + uint32_t random; + generateSecureBytes(reinterpret_cast(&random), sizeof(random)); + return random; +} + +uint64_t +generateSecureWord64() +{ + uint64_t random; + generateSecureBytes(reinterpret_cast(&random), sizeof(random)); + return random; +} + +void +generateSecureBytes(uint8_t* bytes, size_t size) +{ + if (RAND_bytes(bytes, size) != 1) { + NDN_THROW(std::runtime_error("Failed to generate random bytes (error code " + + to_string(ERR_get_error()) + ")")); + } +} + +RandomNumberEngine& +getRandomNumberEngine() +{ + thread_local std::mt19937 rng = [] { + std::random_device rd; + // seed with 256 bits of entropy + std::seed_seq seeds{rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()}; + return std::mt19937{seeds}; + }(); + return rng; +} + +uint32_t +generateWord32() +{ + thread_local std::uniform_int_distribution distribution; + return distribution(getRandomNumberEngine()); +} + +uint64_t +generateWord64() +{ + thread_local std::uniform_int_distribution distribution; + return distribution(getRandomNumberEngine()); +} + +} // namespace random +} // namespace ndn diff --git a/src/util/random.hpp b/ndn-cxx/util/random.hpp similarity index 84% rename from src/util/random.hpp rename to ndn-cxx/util/random.hpp index 68dbe8628..9c69bd0ab 100644 --- a/src/util/random.hpp +++ b/ndn-cxx/util/random.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,7 +22,9 @@ #ifndef NDN_UTIL_RANDOM_HPP #define NDN_UTIL_RANDOM_HPP -#include "../common.hpp" +#include "ndn-cxx/detail/common.hpp" + +#include namespace ndn { namespace random { @@ -51,6 +53,17 @@ generateSecureWord64(); void generateSecureBytes(uint8_t* bytes, size_t size); +using RandomNumberEngine = std::mt19937; + +/** + * @brief Returns a reference to a thread-local instance of a properly seeded PRNG + * + * @warning The returned RandomNumberEngine MUST NOT be used when cryptographically secure + * random numbers are needed. + */ +RandomNumberEngine& +getRandomNumberEngine(); + /** * @brief Generate a non-cryptographically-secure random integer in the range [0, 2^32) * diff --git a/src/util/regex.hpp b/ndn-cxx/util/regex.hpp similarity index 90% rename from src/util/regex.hpp rename to ndn-cxx/util/regex.hpp index dd07faa2d..4f8d7ddca 100644 --- a/src/util/regex.hpp +++ b/ndn-cxx/util/regex.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -24,7 +24,7 @@ #ifndef NDN_UTIL_REGEX_HPP #define NDN_UTIL_REGEX_HPP -#include "regex/regex-top-matcher.hpp" +#include "ndn-cxx/util/regex/regex-top-matcher.hpp" namespace ndn { diff --git a/ndn-cxx/util/regex/regex-backref-manager.cpp b/ndn-cxx/util/regex/regex-backref-manager.cpp new file mode 100644 index 000000000..ff69e217d --- /dev/null +++ b/ndn-cxx/util/regex/regex-backref-manager.cpp @@ -0,0 +1,44 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#include "ndn-cxx/util/regex/regex-backref-manager.hpp" + +namespace ndn { + +size_t +RegexBackrefManager::pushRef(const shared_ptr& matcher) +{ + auto last = m_backrefs.size(); + m_backrefs.emplace_back(matcher); + return last; +} + +shared_ptr +RegexBackrefManager::getBackref(size_t i) const +{ + auto backref = m_backrefs[i].lock(); + BOOST_ASSERT(backref != nullptr); + return backref; +} + +} // namespace ndn diff --git a/ndn-cxx/util/regex/regex-backref-manager.hpp b/ndn-cxx/util/regex/regex-backref-manager.hpp new file mode 100644 index 000000000..3d5b7176a --- /dev/null +++ b/ndn-cxx/util/regex/regex-backref-manager.hpp @@ -0,0 +1,62 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#ifndef NDN_UTIL_REGEX_REGEX_BACKREF_MANAGER_HPP +#define NDN_UTIL_REGEX_REGEX_BACKREF_MANAGER_HPP + +#include "ndn-cxx/detail/common.hpp" + +#include + +namespace ndn { + +class RegexMatcher; + +class RegexBackrefManager +{ +public: + size_t + pushRef(const shared_ptr& matcher); + + void + popRef() + { + m_backrefs.pop_back(); + } + + size_t + size() const + { + return m_backrefs.size(); + } + + shared_ptr + getBackref(size_t i) const; + +private: + std::vector> m_backrefs; +}; + +} // namespace ndn + +#endif // NDN_UTIL_REGEX_REGEX_BACKREF_MANAGER_HPP diff --git a/ndn-cxx/util/regex/regex-backref-matcher.cpp b/ndn-cxx/util/regex/regex-backref-matcher.cpp new file mode 100644 index 000000000..0b531ceed --- /dev/null +++ b/ndn-cxx/util/regex/regex-backref-matcher.cpp @@ -0,0 +1,50 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#include "ndn-cxx/util/regex/regex-backref-matcher.hpp" +#include "ndn-cxx/util/regex/regex-pattern-list-matcher.hpp" + +namespace ndn { + +RegexBackrefMatcher::RegexBackrefMatcher(const std::string& expr, + shared_ptr backrefManager) + : RegexMatcher(expr, EXPR_BACKREF, std::move(backrefManager)) +{ +} + +void +RegexBackrefMatcher::compile() +{ + if (m_expr.size() < 2) + NDN_THROW(Error("Unrecognized format: " + m_expr)); + + size_t lastIndex = m_expr.size() - 1; + if ('(' == m_expr[0] && ')' == m_expr[lastIndex]) { + m_matchers.push_back(make_shared(m_expr.substr(1, lastIndex - 1), + m_backrefManager)); + } + else + NDN_THROW(Error("Unrecognized format: " + m_expr)); +} + +} // namespace ndn diff --git a/ndn-cxx/util/regex/regex-backref-matcher.hpp b/ndn-cxx/util/regex/regex-backref-matcher.hpp new file mode 100644 index 000000000..30ededd13 --- /dev/null +++ b/ndn-cxx/util/regex/regex-backref-matcher.hpp @@ -0,0 +1,49 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#ifndef NDN_UTIL_REGEX_REGEX_BACKREF_MATCHER_HPP +#define NDN_UTIL_REGEX_REGEX_BACKREF_MATCHER_HPP + +#include "ndn-cxx/util/regex/regex-matcher.hpp" + +namespace ndn { + +class RegexBackrefMatcher : public RegexMatcher +{ +public: + RegexBackrefMatcher(const std::string& expr, shared_ptr backrefManager); + + void + lateCompile() + { + compile(); + } + +protected: + void + compile() override; +}; + +} // namespace ndn + +#endif // NDN_UTIL_REGEX_REGEX_BACKREF_MATCHER_HPP diff --git a/ndn-cxx/util/regex/regex-component-matcher.cpp b/ndn-cxx/util/regex/regex-component-matcher.cpp new file mode 100644 index 000000000..604c0eedf --- /dev/null +++ b/ndn-cxx/util/regex/regex-component-matcher.cpp @@ -0,0 +1,79 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#include "ndn-cxx/util/regex/regex-component-matcher.hpp" +#include "ndn-cxx/util/regex/regex-pseudo-matcher.hpp" + +namespace ndn { + +RegexComponentMatcher::RegexComponentMatcher(const std::string& expr, + shared_ptr backrefManager, + bool isExactMatch) + : RegexMatcher(expr, EXPR_COMPONENT, std::move(backrefManager)) + , m_isExactMatch(isExactMatch) +{ + compile(); +} + +void +RegexComponentMatcher::compile() +{ + m_componentRegex.assign(m_expr); + + m_pseudoMatchers.clear(); + m_pseudoMatchers.push_back(make_shared()); + + for (size_t i = 1; i <= m_componentRegex.mark_count(); i++) { + m_pseudoMatchers.push_back(make_shared()); + m_backrefManager->pushRef(m_pseudoMatchers.back()); + } +} + +bool +RegexComponentMatcher::match(const Name& name, size_t offset, size_t len) +{ + m_matchResult.clear(); + + if (m_expr.empty()) { + m_matchResult.push_back(name.get(offset)); + return true; + } + + if (!m_isExactMatch) + NDN_THROW(Error("Non-exact component search is not supported yet")); + + std::smatch subResult; + std::string targetStr = name.get(offset).toUri(); + if (std::regex_match(targetStr, subResult, m_componentRegex)) { + for (size_t i = 1; i <= m_componentRegex.mark_count(); i++) { + m_pseudoMatchers[i]->resetMatchResult(); + m_pseudoMatchers[i]->setMatchResult(subResult[i]); + } + m_matchResult.push_back(name.get(offset)); + return true; + } + + return false; +} + +} // namespace ndn diff --git a/ndn-cxx/util/regex/regex-component-matcher.hpp b/ndn-cxx/util/regex/regex-component-matcher.hpp new file mode 100644 index 000000000..c0b1a3e9b --- /dev/null +++ b/ndn-cxx/util/regex/regex-component-matcher.hpp @@ -0,0 +1,63 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#ifndef NDN_UTIL_REGEX_REGEX_COMPONENT_MATCHER_HPP +#define NDN_UTIL_REGEX_REGEX_COMPONENT_MATCHER_HPP + +#include "ndn-cxx/util/regex/regex-matcher.hpp" + +#include + +namespace ndn { + +class RegexPseudoMatcher; + +class RegexComponentMatcher : public RegexMatcher +{ +public: + /** + * @brief Create a RegexComponent matcher from expr + * @param expr The standard regular expression to match a component + * @param backrefManager The back reference manager + * @param isExactMatch The flag to provide exact match + */ + RegexComponentMatcher(const std::string& expr, + shared_ptr backrefManager, + bool isExactMatch = true); + + bool + match(const Name& name, size_t offset, size_t len = 1) override; + +protected: + void + compile() override; + +private: + bool m_isExactMatch; + std::regex m_componentRegex; + std::vector> m_pseudoMatchers; +}; + +} // namespace ndn + +#endif // NDN_UTIL_REGEX_REGEX_COMPONENT_MATCHER_HPP diff --git a/ndn-cxx/util/regex/regex-component-set-matcher.cpp b/ndn-cxx/util/regex/regex-component-set-matcher.cpp new file mode 100644 index 000000000..6c2eca846 --- /dev/null +++ b/ndn-cxx/util/regex/regex-component-set-matcher.cpp @@ -0,0 +1,143 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#include "ndn-cxx/util/regex/regex-component-set-matcher.hpp" +#include "ndn-cxx/util/regex/regex-component-matcher.hpp" + +namespace ndn { + +RegexComponentSetMatcher::RegexComponentSetMatcher(const std::string& expr, + shared_ptr backrefManager) + : RegexMatcher(expr, EXPR_COMPONENT_SET, std::move(backrefManager)) + , m_isInclusion(true) +{ + compile(); +} + +void +RegexComponentSetMatcher::compile() +{ + if (m_expr.size() < 2) + NDN_THROW(Error("Regexp compile error (cannot parse " + m_expr + ")")); + + switch (m_expr[0]) { + case '<': + return compileSingleComponent(); + case '[': { + size_t lastIndex = m_expr.size() - 1; + if (']' != m_expr[lastIndex]) + NDN_THROW(Error("Regexp compile error (no matching ']' in " + m_expr + ")")); + + if ('^' == m_expr[1]) { + m_isInclusion = false; + compileMultipleComponents(2, lastIndex); + } + else + compileMultipleComponents(1, lastIndex); + break; + } + default: + NDN_THROW(Error("Regexp compile error (cannot parse " + m_expr + ")")); + } +} + +void +RegexComponentSetMatcher::compileSingleComponent() +{ + size_t end = extractComponent(1); + if (m_expr.size() != end) + NDN_THROW(Error("Component expr error " + m_expr)); + + m_components.push_back(make_shared(m_expr.substr(1, end - 2), m_backrefManager)); +} + +void +RegexComponentSetMatcher::compileMultipleComponents(size_t start, size_t lastIndex) +{ + size_t index = start; + size_t tempIndex = start; + + while (index < lastIndex) { + if ('<' != m_expr[index]) + NDN_THROW(Error("Component expr error " + m_expr)); + + tempIndex = index + 1; + index = extractComponent(tempIndex); + m_components.push_back(make_shared(m_expr.substr(tempIndex, index - tempIndex - 1), + m_backrefManager)); + } + + if (index != lastIndex) + NDN_THROW(Error("Not sufficient expr to parse " + m_expr)); +} + +bool +RegexComponentSetMatcher::match(const Name& name, size_t offset, size_t len) +{ + // componentset only matches one component + if (len != 1) + return false; + + bool isMatched = false; + for (const auto& comp : m_components) { + if (comp->match(name, offset, len)) { + isMatched = true; + break; + } + } + + m_matchResult.clear(); + + if (m_isInclusion ? isMatched : !isMatched) { + m_matchResult.push_back(name.get(offset)); + return true; + } + else + return false; +} + +size_t +RegexComponentSetMatcher::extractComponent(size_t index) const +{ + size_t lcount = 1; + size_t rcount = 0; + + while (lcount > rcount) { + switch (m_expr[index]) { + case '<': + lcount++; + break; + case '>': + rcount++; + break; + case 0: + NDN_THROW(Error("Square brackets mismatch")); + break; + } + index++; + } + + return index; +} + +} // namespace ndn diff --git a/ndn-cxx/util/regex/regex-component-set-matcher.hpp b/ndn-cxx/util/regex/regex-component-set-matcher.hpp new file mode 100644 index 000000000..2aacbca4b --- /dev/null +++ b/ndn-cxx/util/regex/regex-component-set-matcher.hpp @@ -0,0 +1,72 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#ifndef NDN_UTIL_REGEX_REGEX_COMPONENT_SET_MATCHER_HPP +#define NDN_UTIL_REGEX_REGEX_COMPONENT_SET_MATCHER_HPP + +#include "ndn-cxx/util/regex/regex-matcher.hpp" + +#include + +namespace ndn { + +class RegexComponentMatcher; + +class RegexComponentSetMatcher : public RegexMatcher +{ +public: + /** + * @brief Create a RegexComponentSetMatcher matcher from expr + * @param expr The standard regular expression to match a component + * @param backrefManager Shared pointer to back-reference manager + */ + RegexComponentSetMatcher(const std::string& expr, shared_ptr backrefManager); + + bool + match(const Name& name, size_t offset, size_t len = 1) override; + +protected: + /** + * @brief Compile the regular expression to generate the more matchers when necessary + */ + void + compile() override; + +private: + void + compileSingleComponent(); + + void + compileMultipleComponents(size_t start, size_t lastIndex); + + size_t + extractComponent(size_t index) const; + +private: + std::vector> m_components; + bool m_isInclusion; +}; + +} // namespace ndn + +#endif // NDN_UTIL_REGEX_REGEX_COMPONENT_SET_MATCHER_HPP diff --git a/ndn-cxx/util/regex/regex-matcher.cpp b/ndn-cxx/util/regex/regex-matcher.cpp new file mode 100644 index 000000000..39fe7155e --- /dev/null +++ b/ndn-cxx/util/regex/regex-matcher.cpp @@ -0,0 +1,80 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#include "ndn-cxx/util/regex/regex-matcher.hpp" + +namespace ndn { + +RegexMatcher::RegexMatcher(const std::string& expr, const RegexExprType& type, + shared_ptr backrefManager) + : m_expr(expr) + , m_type(type) +{ + if (backrefManager) + m_backrefManager = std::move(backrefManager); + else + m_backrefManager = make_shared(); +} + +RegexMatcher::~RegexMatcher() = default; + +bool +RegexMatcher::match(const Name& name, size_t offset, size_t len) +{ + m_matchResult.clear(); + + if (recursiveMatch(0, name, offset, len)) { + for (size_t i = offset; i < offset + len; i++) + m_matchResult.push_back(name.get(i)); + return true; + } + + return false; +} + +bool +RegexMatcher::recursiveMatch(size_t matcherNo, const Name& name, size_t offset, size_t len) +{ + if (matcherNo >= m_matchers.size()) + return len == 0; + + ssize_t tried = len; + auto matcher = m_matchers[matcherNo]; + + while (tried >= 0) { + if (matcher->match(name, offset, tried) && + recursiveMatch(matcherNo + 1, name, offset + tried, len - tried)) + return true; + tried--; + } + + return false; +} + +std::ostream& +operator<<(std::ostream& os, const RegexMatcher& rm) +{ + return os << rm.getExpr(); +} + +} // namespace ndn diff --git a/ndn-cxx/util/regex/regex-matcher.hpp b/ndn-cxx/util/regex/regex-matcher.hpp new file mode 100644 index 000000000..6cc0dbccb --- /dev/null +++ b/ndn-cxx/util/regex/regex-matcher.hpp @@ -0,0 +1,100 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#ifndef NDN_UTIL_REGEX_REGEX_MATCHER_HPP +#define NDN_UTIL_REGEX_REGEX_MATCHER_HPP + +#include "ndn-cxx/util/regex/regex-backref-manager.hpp" +#include "ndn-cxx/name.hpp" + +namespace ndn { + +class RegexMatcher +{ +public: + class Error : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + }; + + enum RegexExprType { + EXPR_TOP, + EXPR_PATTERN_LIST, + EXPR_REPEAT_PATTERN, + EXPR_BACKREF, + EXPR_COMPONENT_SET, + EXPR_COMPONENT, + EXPR_PSEUDO + }; + + RegexMatcher(const std::string& expr, const RegexExprType& type, + shared_ptr backrefManager = nullptr); + + virtual + ~RegexMatcher(); + + virtual bool + match(const Name& name, size_t offset, size_t len); + + /** + * @brief get the matched name components + * @returns the matched name components + */ + const std::vector& + getMatchResult() const + { + return m_matchResult; + } + + const std::string& + getExpr() const + { + return m_expr; + } + +protected: + /** + * @brief Compile the regular expression to generate the more matchers when necessary + */ + virtual void + compile() = 0; + +private: + bool + recursiveMatch(size_t matcherNo, const Name& name, size_t offset, size_t len); + +protected: + const std::string m_expr; + const RegexExprType m_type; + shared_ptr m_backrefManager; + std::vector> m_matchers; + std::vector m_matchResult; +}; + +std::ostream& +operator<<(std::ostream& os, const RegexMatcher& rm); + +} // namespace ndn + +#endif // NDN_UTIL_REGEX_REGEX_MATCHER_HPP diff --git a/ndn-cxx/util/regex/regex-pattern-list-matcher.cpp b/ndn-cxx/util/regex/regex-pattern-list-matcher.cpp new file mode 100644 index 000000000..a0464c332 --- /dev/null +++ b/ndn-cxx/util/regex/regex-pattern-list-matcher.cpp @@ -0,0 +1,153 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#include "ndn-cxx/util/regex/regex-pattern-list-matcher.hpp" +#include "ndn-cxx/util/regex/regex-backref-matcher.hpp" +#include "ndn-cxx/util/regex/regex-repeat-matcher.hpp" + +namespace ndn { + +RegexPatternListMatcher::RegexPatternListMatcher(const std::string& expr, + shared_ptr backrefManager) + : RegexMatcher(expr, EXPR_PATTERN_LIST, std::move(backrefManager)) +{ + compile(); +} + +void +RegexPatternListMatcher::compile() +{ + size_t len = m_expr.size(); + size_t index = 0; + size_t subHead = index; + + while (index < len) { + subHead = index; + + if (!extractPattern(subHead, &index)) + NDN_THROW(Error("Compile error")); + } +} + +bool +RegexPatternListMatcher::extractPattern(size_t index, size_t* next) +{ + size_t start = index; + size_t end = index; + size_t indicator = index; + + switch (m_expr[index]) { + case '(': + index++; + index = extractSubPattern('(', ')', index); + indicator = index; + end = extractRepetition(index); + if (indicator == end) { + auto matcher = make_shared(m_expr.substr(start, end - start), + m_backrefManager); + m_backrefManager->pushRef(matcher); + matcher->lateCompile(); + m_matchers.push_back(std::move(matcher)); + } + else + m_matchers.push_back(make_shared(m_expr.substr(start, end - start), + m_backrefManager, indicator - start)); + break; + + case '<': + index++; + index = extractSubPattern('<', '>', index); + indicator = index; + end = extractRepetition(index); + m_matchers.push_back(make_shared(m_expr.substr(start, end - start), + m_backrefManager, indicator - start)); + break; + + case '[': + index++; + index = extractSubPattern('[', ']', index); + indicator = index; + end = extractRepetition(index); + m_matchers.push_back(make_shared(m_expr.substr(start, end - start), + m_backrefManager, indicator - start)); + break; + + default: + NDN_THROW(Error("Unexpected character "s + m_expr[index])); + } + + *next = end; + return true; +} + +size_t +RegexPatternListMatcher::extractSubPattern(const char left, const char right, size_t index) +{ + size_t lcount = 1; + size_t rcount = 0; + + while (lcount > rcount) { + if (index >= m_expr.size()) + NDN_THROW(Error("Parenthesis mismatch")); + + if (left == m_expr[index]) + lcount++; + + if (right == m_expr[index]) + rcount++; + + index++; + } + + return index; +} + +size_t +RegexPatternListMatcher::extractRepetition(size_t index) +{ + size_t exprSize = m_expr.size(); + + if (index == exprSize) + return index; + + if (('+' == m_expr[index] || '?' == m_expr[index] || '*' == m_expr[index])) { + return ++index; + } + + if ('{' == m_expr[index]) { + while ('}' != m_expr[index]) { + index++; + if (index == exprSize) + break; + } + if (index == exprSize) + NDN_THROW(Error("Missing closing brace")); + else + return ++index; + } + else { + return index; + } +} + +} // namespace ndn diff --git a/ndn-cxx/util/regex/regex-pattern-list-matcher.hpp b/ndn-cxx/util/regex/regex-pattern-list-matcher.hpp new file mode 100644 index 000000000..f814deeb0 --- /dev/null +++ b/ndn-cxx/util/regex/regex-pattern-list-matcher.hpp @@ -0,0 +1,53 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#ifndef NDN_UTIL_REGEX_REGEX_PATTERN_LIST_MATCHER_HPP +#define NDN_UTIL_REGEX_REGEX_PATTERN_LIST_MATCHER_HPP + +#include "ndn-cxx/util/regex/regex-matcher.hpp" + +namespace ndn { + +class RegexPatternListMatcher : public RegexMatcher +{ +public: + RegexPatternListMatcher(const std::string& expr, shared_ptr backrefManager); + +protected: + void + compile() override; + +private: + bool + extractPattern(size_t index, size_t* next); + + size_t + extractSubPattern(const char left, const char right, size_t index); + + size_t + extractRepetition(size_t index); +}; + +} // namespace ndn + +#endif // NDN_UTIL_REGEX_REGEX_PATTERN_LIST_MATCHER_HPP diff --git a/ndn-cxx/util/regex/regex-pseudo-matcher.cpp b/ndn-cxx/util/regex/regex-pseudo-matcher.cpp new file mode 100644 index 000000000..fc5e9510f --- /dev/null +++ b/ndn-cxx/util/regex/regex-pseudo-matcher.cpp @@ -0,0 +1,50 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#include "ndn-cxx/util/regex/regex-pseudo-matcher.hpp" + +namespace ndn { + +RegexPseudoMatcher::RegexPseudoMatcher() + : RegexMatcher("", EXPR_PSEUDO) +{ +} + +void +RegexPseudoMatcher::setMatchResult(const std::string& str) +{ + m_matchResult.push_back(name::Component(reinterpret_cast(str.data()), str.size())); +} + +void +RegexPseudoMatcher::resetMatchResult() +{ + m_matchResult.clear(); +} + +void +RegexPseudoMatcher::compile() +{ +} + +} // namespace ndn diff --git a/ndn-cxx/util/regex/regex-pseudo-matcher.hpp b/ndn-cxx/util/regex/regex-pseudo-matcher.hpp new file mode 100644 index 000000000..431702754 --- /dev/null +++ b/ndn-cxx/util/regex/regex-pseudo-matcher.hpp @@ -0,0 +1,49 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#ifndef NDN_UTIL_REGEX_REGEX_PSEUDO_MATCHER_HPP +#define NDN_UTIL_REGEX_REGEX_PSEUDO_MATCHER_HPP + +#include "ndn-cxx/util/regex/regex-matcher.hpp" + +namespace ndn { + +class RegexPseudoMatcher : public RegexMatcher +{ +public: + RegexPseudoMatcher(); + + void + setMatchResult(const std::string& str); + + void + resetMatchResult(); + +protected: + void + compile() override; +}; + +} // namespace ndn + +#endif // NDN_UTIL_REGEX_REGEX_PSEUDO_MATCHER_HPP diff --git a/ndn-cxx/util/regex/regex-repeat-matcher.cpp b/ndn-cxx/util/regex/regex-repeat-matcher.cpp new file mode 100644 index 000000000..159dc4150 --- /dev/null +++ b/ndn-cxx/util/regex/regex-repeat-matcher.cpp @@ -0,0 +1,174 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#include "ndn-cxx/util/regex/regex-repeat-matcher.hpp" +#include "ndn-cxx/util/regex/regex-backref-matcher.hpp" +#include "ndn-cxx/util/regex/regex-component-set-matcher.hpp" + +#include +#include + +namespace ndn { + +RegexRepeatMatcher::RegexRepeatMatcher(const std::string& expr, + shared_ptr backrefManager, + size_t indicator) + : RegexMatcher(expr, EXPR_REPEAT_PATTERN, std::move(backrefManager)) + , m_indicator(indicator) +{ + compile(); +} + +void +RegexRepeatMatcher::compile() +{ + if ('(' == m_expr[0]) { + auto matcher = make_shared(m_expr.substr(0, m_indicator), m_backrefManager); + m_backrefManager->pushRef(matcher); + matcher->lateCompile(); + m_matchers.push_back(std::move(matcher)); + } + else { + m_matchers.push_back(make_shared(m_expr.substr(0, m_indicator), + m_backrefManager)); + } + + parseRepetition(); +} + +bool +RegexRepeatMatcher::parseRepetition() +{ + size_t exprSize = m_expr.size(); + const size_t MAX_REPETITIONS = std::numeric_limits::max(); + + if (exprSize == m_indicator) { + m_repeatMin = 1; + m_repeatMax = 1; + return true; + } + + if (exprSize == (m_indicator + 1)) { + if ('?' == m_expr[m_indicator]) { + m_repeatMin = 0; + m_repeatMax = 1; + return true; + } + if ('+' == m_expr[m_indicator]) { + m_repeatMin = 1; + m_repeatMax = MAX_REPETITIONS; + return true; + } + if ('*' == m_expr[m_indicator]) { + m_repeatMin = 0; + m_repeatMax = MAX_REPETITIONS; + return true; + } + } + else { + std::string repeatStruct = m_expr.substr(m_indicator, exprSize - m_indicator); + size_t rsSize = repeatStruct.size(); + size_t min = 0; + size_t max = 0; + + if (std::regex_match(repeatStruct, std::regex("\\{[0-9]+,[0-9]+\\}"))) { + size_t separator = repeatStruct.find_first_of(',', 0); + min = std::atoi(repeatStruct.substr(1, separator - 1).data()); + max = std::atoi(repeatStruct.substr(separator + 1, rsSize - separator - 2).data()); + } + else if (std::regex_match(repeatStruct, std::regex("\\{,[0-9]+\\}"))) { + size_t separator = repeatStruct.find_first_of(',', 0); + min = 0; + max = std::atoi(repeatStruct.substr(separator + 1, rsSize - separator - 2).data()); + } + else if (std::regex_match(repeatStruct, std::regex("\\{[0-9]+,\\}"))) { + size_t separator = repeatStruct.find_first_of(',', 0); + min = std::atoi(repeatStruct.substr(1, separator).data()); + max = MAX_REPETITIONS; + } + else if (std::regex_match(repeatStruct, std::regex("\\{[0-9]+\\}"))) { + min = std::atoi(repeatStruct.substr(1, rsSize - 1).data()); + max = min; + } + else + NDN_THROW(Error("parseRepetition: unrecognized format " + m_expr)); + + if (min > MAX_REPETITIONS || max > MAX_REPETITIONS || min > max) + NDN_THROW(Error("parseRepetition: wrong number " + m_expr)); + + m_repeatMin = min; + m_repeatMax = max; + + return true; + } + + return false; +} + +bool +RegexRepeatMatcher::match(const Name& name, size_t offset, size_t len) +{ + m_matchResult.clear(); + + if (m_repeatMin == 0) + if (len == 0) + return true; + + if (recursiveMatch(0, name, offset, len)) { + for (size_t i = offset; i < offset + len; i++) + m_matchResult.push_back(name.get(i)); + return true; + } + + return false; +} + +bool +RegexRepeatMatcher::recursiveMatch(size_t repeat, const Name& name, size_t offset, size_t len) +{ + ssize_t tried = len; + + if (0 < len && repeat >= m_repeatMax) { + return false; + } + + if (0 == len && repeat < m_repeatMin) { + return false; + } + + if (0 == len && repeat >= m_repeatMin) { + return true; + } + + auto matcher = m_matchers[0]; + while (tried >= 0) { + if (matcher->match(name, offset, tried) && + recursiveMatch(repeat + 1, name, offset + tried, len - tried)) + return true; + tried--; + } + + return false; +} + +} // namespace ndn diff --git a/ndn-cxx/util/regex/regex-repeat-matcher.hpp b/ndn-cxx/util/regex/regex-repeat-matcher.hpp new file mode 100644 index 000000000..5e92edbbb --- /dev/null +++ b/ndn-cxx/util/regex/regex-repeat-matcher.hpp @@ -0,0 +1,60 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#ifndef NDN_UTIL_REGEX_REGEX_REPEAT_MATCHER_HPP +#define NDN_UTIL_REGEX_REGEX_REPEAT_MATCHER_HPP + +#include "ndn-cxx/util/regex/regex-matcher.hpp" + +namespace ndn { + +class RegexRepeatMatcher : public RegexMatcher +{ +public: + RegexRepeatMatcher(const std::string& expr, + shared_ptr backrefManager, + size_t indicator); + + bool + match(const Name& name, size_t offset, size_t len) override; + +protected: + void + compile() override; + +private: + bool + parseRepetition(); + + bool + recursiveMatch(size_t repeat, const Name& name, size_t offset, size_t len); + +private: + size_t m_indicator; + size_t m_repeatMin; + size_t m_repeatMax; +}; + +} // namespace ndn + +#endif // NDN_UTIL_REGEX_REGEX_REPEAT_MATCHER_HPP diff --git a/ndn-cxx/util/regex/regex-top-matcher.cpp b/ndn-cxx/util/regex/regex-top-matcher.cpp new file mode 100644 index 000000000..f326ca5ec --- /dev/null +++ b/ndn-cxx/util/regex/regex-top-matcher.cpp @@ -0,0 +1,219 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Yingdi Yu + */ + +#include "ndn-cxx/util/regex/regex-top-matcher.hpp" + +#include "ndn-cxx/util/regex/regex-backref-manager.hpp" +#include "ndn-cxx/util/regex/regex-pattern-list-matcher.hpp" + +#include + +namespace ndn { + +RegexTopMatcher::RegexTopMatcher(const std::string& expr, const std::string& expand) + : RegexMatcher(expr, EXPR_TOP) + , m_expand(expand) + , m_isSecondaryUsed(false) +{ + m_primaryBackrefManager = make_shared(); + m_secondaryBackrefManager = make_shared(); + compile(); +} + +void +RegexTopMatcher::compile() +{ + std::string expr = m_expr; + + if ('$' != expr[expr.size() - 1]) + expr = expr + "<.*>*"; + else + expr = expr.substr(0, expr.size() - 1); + + if ('^' != expr[0]) { + m_secondaryMatcher = make_shared("<.*>*" + expr, + m_secondaryBackrefManager); + } + else { + expr = expr.substr(1, expr.size() - 1); + } + + m_primaryMatcher = make_shared(expr, m_primaryBackrefManager); +} + +bool +RegexTopMatcher::match(const Name& name) +{ + m_isSecondaryUsed = false; + + m_matchResult.clear(); + + if (m_primaryMatcher->match(name, 0, name.size())) { + m_matchResult = m_primaryMatcher->getMatchResult(); + return true; + } + else { + if (m_secondaryMatcher != nullptr && m_secondaryMatcher->match(name, 0, name.size())) { + m_matchResult = m_secondaryMatcher->getMatchResult(); + m_isSecondaryUsed = true; + return true; + } + return false; + } +} + +bool +RegexTopMatcher::match(const Name& name, size_t, size_t) +{ + return match(name); +} + +Name +RegexTopMatcher::expand(const std::string& expandStr) +{ + auto backrefManager = m_isSecondaryUsed ? m_secondaryBackrefManager : m_primaryBackrefManager; + size_t backrefNo = backrefManager->size(); + + std::string expand; + if (!expandStr.empty()) + expand = expandStr; + else + expand = m_expand; + + Name result; + size_t offset = 0; + while (offset < expand.size()) { + std::string item = getItemFromExpand(expand, offset); + if (item[0] == '<') { + result.append(item.substr(1, item.size() - 2)); + } + if (item[0] == '\\') { + size_t index = boost::lexical_cast(item.substr(1, item.size() - 1)); + if (index == 0) { + for (const auto& i : m_matchResult) + result.append(i); + } + else if (index <= backrefNo) { + for (const auto& i : backrefManager->getBackref(index - 1)->getMatchResult()) + result.append(i); + } + else + NDN_THROW(Error("Exceeded the range of back reference")); + } + } + + return result; +} + +std::string +RegexTopMatcher::getItemFromExpand(const std::string& expand, size_t& offset) +{ + size_t begin = offset; + + if (expand[offset] == '\\') { + offset++; + if (offset >= expand.size()) + NDN_THROW(Error("Wrong format of expand string")); + + while (expand[offset] <= '9' and expand[offset] >= '0') { + offset++; + if (offset > expand.size()) + NDN_THROW(Error("Wrong format of expand string")); + } + if (offset > begin + 1) + return expand.substr(begin, offset - begin); + else + NDN_THROW(Error("Wrong format of expand string")); + } + else if (expand[offset] == '<') { + offset++; + if (offset >= expand.size()) + NDN_THROW(Error("Wrong format of expand string")); + + size_t left = 1; + size_t right = 0; + while (right < left) { + if (expand[offset] == '<') + left++; + if (expand[offset] == '>') + right++; + offset++; + if (offset >= expand.size()) + NDN_THROW(Error("Wrong format of expand string")); + } + return expand.substr(begin, offset - begin); + } + else + NDN_THROW(Error("Wrong format of expand string")); +} + +shared_ptr +RegexTopMatcher::fromName(const Name& name, bool hasAnchor) +{ + std::string regexStr("^"); + + for (const auto& i : name) { + regexStr.append("<"); + regexStr.append(convertSpecialChar(i.toUri())); + regexStr.append(">"); + } + + if (hasAnchor) + regexStr.append("$"); + + return make_shared(regexStr); +} + +std::string +RegexTopMatcher::convertSpecialChar(const std::string& str) +{ + std::string newStr; + + for (size_t i = 0; i < str.size(); i++) { + char c = str[i]; + switch (c) { + case '.': + case '[': + case '{': + case '}': + case '(': + case ')': + case '\\': + case '*': + case '+': + case '?': + case '|': + case '^': + case '$': + newStr.push_back('\\'); + NDN_CXX_FALLTHROUGH; + default: + newStr.push_back(c); + break; + } + } + + return newStr; +} + +} // namespace ndn diff --git a/src/util/regex/regex-top-matcher.hpp b/ndn-cxx/util/regex/regex-top-matcher.hpp similarity index 83% rename from src/util/regex/regex-top-matcher.hpp rename to ndn-cxx/util/regex/regex-top-matcher.hpp index 465f8f04e..f580a3159 100644 --- a/src/util/regex/regex-top-matcher.hpp +++ b/ndn-cxx/util/regex/regex-top-matcher.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -24,47 +24,43 @@ #ifndef NDN_UTIL_REGEX_REGEX_TOP_MATCHER_HPP #define NDN_UTIL_REGEX_REGEX_TOP_MATCHER_HPP -#include "../../common.hpp" - -#include "regex-matcher.hpp" +#include "ndn-cxx/util/regex/regex-matcher.hpp" namespace ndn { class RegexPatternListMatcher; class RegexBackrefManager; -class RegexTopMatcher: public RegexMatcher +class RegexTopMatcher : public RegexMatcher { public: + explicit RegexTopMatcher(const std::string& expr, const std::string& expand = ""); - virtual - ~RegexTopMatcher(); - bool match(const Name& name); - virtual bool - match(const Name& name, size_t offset, size_t len); + bool + match(const Name& name, size_t offset, size_t len) override; virtual Name expand(const std::string& expand = ""); static shared_ptr - fromName(const Name& name, bool hasAnchor=false); + fromName(const Name& name, bool hasAnchor = false); protected: - virtual void - compile(); + void + compile() override; private: - std::string + static std::string getItemFromExpand(const std::string& expand, size_t& offset); static std::string convertSpecialChar(const std::string& str); -private: +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: const std::string m_expand; shared_ptr m_primaryMatcher; shared_ptr m_secondaryMatcher; diff --git a/ndn-cxx/util/rtt-estimator.cpp b/ndn-cxx/util/rtt-estimator.cpp new file mode 100644 index 000000000..a0a4779f7 --- /dev/null +++ b/ndn-cxx/util/rtt-estimator.cpp @@ -0,0 +1,85 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (C) 2016-2019, Arizona Board of Regents. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Shuo Yang + * @author Weiwei Liu + * @author Chavoosh Ghasemi + * @author Davide Pesavento + */ + +#include "ndn-cxx/util/rtt-estimator.hpp" + +namespace ndn { +namespace util { + +RttEstimator::RttEstimator(shared_ptr options) + : m_options(options ? std::move(options) : make_shared()) + , m_rto(m_options->initialRto) +{ + BOOST_ASSERT(m_options->alpha >= 0 && m_options->alpha <= 1); + BOOST_ASSERT(m_options->beta >= 0 && m_options->beta <= 1); + BOOST_ASSERT(m_options->initialRto >= 0_ns); + BOOST_ASSERT(m_options->minRto >= 0_ns); + BOOST_ASSERT(m_options->maxRto >= m_options->minRto); + BOOST_ASSERT(m_options->k >= 0); + BOOST_ASSERT(m_options->rtoBackoffMultiplier >= 1); +} + +void +RttEstimator::addMeasurement(time::nanoseconds rtt, size_t nExpectedSamples) +{ + BOOST_ASSERT(rtt >= 0_ns); + BOOST_ASSERT(nExpectedSamples > 0); + + if (!hasSamples()) { // first measurement + m_sRtt = rtt; + m_rttVar = m_sRtt / 2; + } + else { + double alpha = m_options->alpha / nExpectedSamples; + double beta = m_options->beta / nExpectedSamples; + m_rttVar = time::duration_cast((1 - beta) * m_rttVar + + beta * time::abs(m_sRtt - rtt)); + m_sRtt = time::duration_cast((1 - alpha) * m_sRtt + alpha * rtt); + } + m_rto = clamp(m_sRtt + m_options->k * m_rttVar, + m_options->minRto, m_options->maxRto); +} + +void +RttEstimator::backoffRto() +{ + m_rto = clamp(m_rto * m_options->rtoBackoffMultiplier, + m_options->minRto, m_options->maxRto); +} + +void +RttEstimatorWithStats::addMeasurement(time::nanoseconds rtt, size_t nExpectedSamples) +{ + RttEstimator::addMeasurement(rtt, nExpectedSamples); + + m_rttAvg = (m_nRttSamples * m_rttAvg + rtt) / (m_nRttSamples + 1); + m_rttMax = std::max(rtt, m_rttMax); + m_rttMin = std::min(rtt, m_rttMin); + m_nRttSamples++; +} + +} // namespace util +} // namespace ndn diff --git a/ndn-cxx/util/rtt-estimator.hpp b/ndn-cxx/util/rtt-estimator.hpp new file mode 100644 index 000000000..ba3255c78 --- /dev/null +++ b/ndn-cxx/util/rtt-estimator.hpp @@ -0,0 +1,186 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (C) 2016-2019, Arizona Board of Regents. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Shuo Yang + * @author Weiwei Liu + * @author Chavoosh Ghasemi + * @author Davide Pesavento + */ + +#ifndef NDN_CXX_UTIL_RTT_ESTIMATOR_HPP +#define NDN_CXX_UTIL_RTT_ESTIMATOR_HPP + +#include "ndn-cxx/util/time.hpp" + +namespace ndn { +namespace util { + +/** + * @brief RTT/RTO estimator. + * + * This class implements the "Mean-Deviation" RTT estimator, as discussed in RFC 6298, + * with the modifications to RTO calculation described in RFC 7323 Appendix G. + */ +class RttEstimator +{ +public: + struct Options + { + double alpha = 0.125; ///< weight of exponential moving average for smoothed RTT + double beta = 0.25; ///< weight of exponential moving average for RTT variation + time::nanoseconds initialRto = 1_s; ///< initial RTO value + time::nanoseconds minRto = 200_ms; ///< lower bound of RTO + time::nanoseconds maxRto = 1_min; ///< upper bound of RTO + int k = 4; ///< RTT variation multiplier used when calculating RTO + int rtoBackoffMultiplier = 2; ///< RTO multiplier used in backoff operation + }; + + /** + * @brief Constructor. + * @param options options for the estimator; if nullptr, a default set of options is used + */ + explicit + RttEstimator(shared_ptr options = nullptr); + + /** + * @brief Records a new RTT measurement. + * @param rtt the sampled RTT + * @param nExpectedSamples number of expected samples, must be greater than 0. It should be + * set to the current number of in-flight Interests. Please refer to + * Appendix G of RFC 7323 for details. + * @note Do not call this function with RTT samples from retransmitted Interests (per Karn's algorithm). + */ + void + addMeasurement(time::nanoseconds rtt, size_t nExpectedSamples = 1); + + bool + hasSamples() const + { + return m_sRtt != -1_ns; + } + + /** + * @brief Returns the estimated RTO value. + */ + time::nanoseconds + getEstimatedRto() const + { + return m_rto; + } + + /** + * @brief Returns the smoothed RTT value (SRTT). + * @pre `hasSamples() == true` + */ + time::nanoseconds + getSmoothedRtt() const + { + return m_sRtt; + } + + /** + * @brief Returns the RTT variation (RTTVAR). + * @pre `hasSamples() == true` + */ + time::nanoseconds + getRttVariation() const + { + return m_rttVar; + } + + /** + * @brief Backoff RTO by a factor of Options::rtoBackoffMultiplier. + */ + void + backoffRto(); + +protected: + shared_ptr m_options; + +private: + time::nanoseconds m_sRtt{-1}; ///< smoothed round-trip time + time::nanoseconds m_rttVar{-1}; ///< round-trip time variation + time::nanoseconds m_rto; ///< retransmission timeout +}; + +/** + * @brief RTT/RTO estimator that also maintains min/max/average RTT statistics. + */ +class RttEstimatorWithStats : private RttEstimator +{ +public: + using RttEstimator::Options; + using RttEstimator::RttEstimator; + + using RttEstimator::hasSamples; + using RttEstimator::getEstimatedRto; + using RttEstimator::getSmoothedRtt; + using RttEstimator::getRttVariation; + using RttEstimator::backoffRto; + + /** + * @brief Records a new RTT measurement. + * @param rtt the sampled RTT + * @param nExpectedSamples number of expected samples, must be greater than 0. It should be + * set to the current number of in-flight Interests. Please refer to + * Appendix G of RFC 7323 for details. + * @note Do not call this function with RTT samples from retransmitted Interests (per Karn's algorithm). + */ + void + addMeasurement(time::nanoseconds rtt, size_t nExpectedSamples = 1); + + /** + * @brief Returns the minimum RTT observed. + */ + time::nanoseconds + getMinRtt() const + { + return m_rttMin; + } + + /** + * @brief Returns the maximum RTT observed. + */ + time::nanoseconds + getMaxRtt() const + { + return m_rttMax; + } + + /** + * @brief Returns the average RTT. + */ + time::nanoseconds + getAvgRtt() const + { + return m_rttAvg; + } + +private: + time::nanoseconds m_rttMin = time::nanoseconds::max(); + time::nanoseconds m_rttMax = time::nanoseconds::min(); + time::nanoseconds m_rttAvg = 0_ns; + int64_t m_nRttSamples = 0; +}; + +} // namespace util +} // namespace ndn + +#endif // NDN_CXX_UTIL_RTT_ESTIMATOR_HPP diff --git a/ndn-cxx/util/scheduler.cpp b/ndn-cxx/util/scheduler.cpp new file mode 100644 index 000000000..df2c4606b --- /dev/null +++ b/ndn-cxx/util/scheduler.cpp @@ -0,0 +1,184 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/scheduler.hpp" + +#include + +namespace ndn { +namespace scheduler { + +/** \brief Stores internal information about a scheduled event + */ +class EventInfo : noncopyable +{ +public: + EventInfo(time::nanoseconds after, EventCallback&& cb, uint32_t context) + : callback(std::move(cb)) + , expireTime(time::steady_clock::now() + after) + , context(context) + { + } + + NDN_CXX_NODISCARD time::nanoseconds + expiresFromNow() const + { + return std::max(expireTime - time::steady_clock::now(), 0_ns); + } + +public: + EventCallback callback; + Scheduler::EventQueue::const_iterator queueIt; + time::steady_clock::TimePoint expireTime; + bool isExpired = false; + uint32_t context = 0; +}; + +EventId::EventId(Scheduler& sched, weak_ptr info) + : CancelHandle([&sched, info] { sched.cancelImpl(info.lock()); }) + , m_info(std::move(info)) +{ +} + +EventId::operator bool() const noexcept +{ + auto sp = m_info.lock(); + return sp != nullptr && !sp->isExpired; +} + +void +EventId::reset() noexcept +{ + *this = {}; +} + +std::ostream& +operator<<(std::ostream& os, const EventId& eventId) +{ + return os << eventId.m_info.lock(); +} + +bool +Scheduler::EventQueueCompare::operator()(const shared_ptr& a, + const shared_ptr& b) const noexcept +{ + return a->expireTime < b->expireTime; +} + +Scheduler::Scheduler(DummyIoService& ioService) +{ +} + +Scheduler::~Scheduler() +{ + cancelAllEvents(); +} + +EventId +Scheduler::schedule(time::nanoseconds after, EventCallback callback) +{ + BOOST_ASSERT(callback != nullptr); + + auto i = m_queue.insert(make_shared(after, std::move(callback), ns3::Simulator::GetContext())); + (*i)->queueIt = i; + + if (!m_isEventExecuting && i == m_queue.begin()) { + // the new event is the first one to expire + this->scheduleNext(); + } + + return EventId(*this, *i); +} + +void +Scheduler::cancelImpl(const shared_ptr& info) +{ + if (info == nullptr || info->isExpired) { + return; + } + + if (m_timerEvent) { + if (!m_timerEvent->IsExpired()) { + ns3::Simulator::Remove(*m_timerEvent); + } + m_timerEvent.reset(); + } + m_queue.erase(info->queueIt); + + if (!m_isEventExecuting) { + this->scheduleNext(); + } +} + +void +Scheduler::cancelAllEvents() +{ + m_queue.clear(); + if (m_timerEvent) { + if (!m_timerEvent->IsExpired()) { + ns3::Simulator::Remove(*m_timerEvent); + } + m_timerEvent.reset(); + } +} + +void +Scheduler::scheduleNext() +{ + if (!m_queue.empty()) { + m_timerEvent = ns3::Simulator::Schedule(ns3::NanoSeconds((*m_queue.begin())->expiresFromNow().count()), + &Scheduler::executeEvent, this); + } +} + +void +Scheduler::executeEvent() +{ + m_isEventExecuting = true; + + m_timerEvent.reset(); + BOOST_SCOPE_EXIT(this_) { + this_->m_isEventExecuting = false; + this_->scheduleNext(); + } BOOST_SCOPE_EXIT_END + + // process all expired events + auto now = time::steady_clock::now(); + while (!m_queue.empty()) { + auto head = m_queue.begin(); + shared_ptr info = *head; + if (info->expireTime > now) { + break; + } + + m_queue.erase(head); + info->isExpired = true; + if (ns3::Simulator::GetContext() == info->context) { + info->callback(); + } + else { + ns3::Simulator::ScheduleWithContext(info->context, ns3::Seconds(0), ns3::MakeEvent(info->callback)); + } + } +} + +} // namespace scheduler +} // namespace ndn diff --git a/ndn-cxx/util/scheduler.hpp b/ndn-cxx/util/scheduler.hpp new file mode 100644 index 000000000..f21090507 --- /dev/null +++ b/ndn-cxx/util/scheduler.hpp @@ -0,0 +1,189 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_SCHEDULER_HPP +#define NDN_UTIL_SCHEDULER_HPP + +#include "ndn-cxx/detail/asio-fwd.hpp" +#include "ndn-cxx/detail/cancel-handle.hpp" +#include "ndn-cxx/util/time.hpp" + +#include "ns3/simulator.h" + +#include + +namespace ndn { + +namespace util { +} // namespace util + +namespace scheduler { + +class Scheduler; +class EventInfo; + +/** \brief Function to be invoked when a scheduled event expires + */ +using EventCallback = std::function; + +/** \brief A handle for a scheduled event. + * + * \code + * EventId eid = scheduler.schedule(10_ms, [] { doSomething(); }); + * eid.cancel(); // cancel the event + * \endcode + * + * \note Canceling an expired (executed) or canceled event has no effect. + * \warning Canceling an event after the scheduler has been destructed may trigger undefined + * behavior. + */ +class EventId : public detail::CancelHandle +{ +public: + /** \brief Constructs an empty EventId + */ + EventId() noexcept = default; + + /** \brief Determine whether the event is valid. + * \retval true The event is valid. + * \retval false This EventId is empty, or the event is expired or cancelled. + */ + explicit + operator bool() const noexcept; + + /** \brief Clear this EventId without canceling. + * \post !(*this) + */ + void + reset() noexcept; + +private: + // NOTE: the following "hidden friend" operators are available via + // argument-dependent lookup only and must be defined inline. + + /** \brief Determine whether this and other refer to the same event, or are both + * empty/expired/cancelled. + */ + friend bool + operator==(const EventId& lhs, const EventId& rhs) noexcept + { + return (!lhs && !rhs) || + (!lhs.m_info.owner_before(rhs.m_info) && + !rhs.m_info.owner_before(lhs.m_info)); + } + + friend bool + operator!=(const EventId& lhs, const EventId& rhs) noexcept + { + return !(lhs == rhs); + } + +private: + EventId(Scheduler& sched, weak_ptr info); + +private: + weak_ptr m_info; + + friend class Scheduler; + friend std::ostream& operator<<(std::ostream& os, const EventId& eventId); +}; + +std::ostream& +operator<<(std::ostream& os, const EventId& eventId); + +/** \brief A scoped handle for a scheduled event. + * + * Upon destruction of this handle, the event is canceled automatically. + * Most commonly, the application keeps a ScopedEventId as a class member field, so that it can + * cleanup its event when the class instance is destructed. + * + * \code + * { + * ScopedEventId eid = scheduler.schedule(10_ms, [] { doSomething(); }); + * } // eid goes out of scope, canceling the event + * \endcode + * + * \note Canceling an expired (executed) or canceled event has no effect. + * \warning Canceling an event after the scheduler has been destructed may trigger undefined + * behavior. + */ +using ScopedEventId = detail::ScopedCancelHandle; + +/** \brief Generic time-based scheduler + */ +class Scheduler : noncopyable +{ +public: + explicit + Scheduler(DummyIoService& ioService); + + ~Scheduler(); + + /** \brief Schedule a one-time event after the specified delay + * \return EventId that can be used to cancel the scheduled event + */ + EventId + schedule(time::nanoseconds after, EventCallback callback); + + /** \brief Cancel all scheduled events + */ + void + cancelAllEvents(); + +private: + void + cancelImpl(const shared_ptr& info); + + /** \brief Schedule the next event on the internal timer + */ + void + scheduleNext(); + + /** \brief Execute expired events + */ + void + executeEvent(); + +private: + class EventQueueCompare + { + public: + bool + operator()(const shared_ptr& a, const shared_ptr& b) const noexcept; + }; + + using EventQueue = std::multiset, EventQueueCompare>; + EventQueue m_queue; + + bool m_isEventExecuting = false; + ndn::optional m_timerEvent; + + friend EventId; + friend EventInfo; +}; + +} // namespace scheduler + +using scheduler::Scheduler; + +} // namespace ndn + +#endif // NDN_UTIL_SCHEDULER_HPP diff --git a/ndn-cxx/util/segment-fetcher.cpp b/ndn-cxx/util/segment-fetcher.cpp new file mode 100644 index 000000000..1daf05cc7 --- /dev/null +++ b/ndn-cxx/util/segment-fetcher.cpp @@ -0,0 +1,518 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Shuo Yang + * @author Weiwei Liu + * @author Chavoosh Ghasemi + */ + +#include "ndn-cxx/util/segment-fetcher.hpp" +#include "ndn-cxx/name-component.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/lp/nack.hpp" +#include "ndn-cxx/lp/nack-header.hpp" + +#include +#include +#include + +#include + +namespace ndn { +namespace util { + +constexpr double SegmentFetcher::MIN_SSTHRESH; + +void +SegmentFetcher::Options::validate() +{ + if (maxTimeout < 1_ms) { + NDN_THROW(std::invalid_argument("maxTimeout must be greater than or equal to 1 millisecond")); + } + + if (initCwnd < 1.0) { + NDN_THROW(std::invalid_argument("initCwnd must be greater than or equal to 1")); + } + + if (aiStep < 0.0) { + NDN_THROW(std::invalid_argument("aiStep must be greater than or equal to 0")); + } + + if (mdCoef < 0.0 || mdCoef > 1.0) { + NDN_THROW(std::invalid_argument("mdCoef must be in range [0, 1]")); + } +} + +SegmentFetcher::SegmentFetcher(Face& face, + security::v2::Validator& validator, + const SegmentFetcher::Options& options) + : m_options(options) + , m_face(face) + , m_scheduler(m_face.getIoService()) + , m_validator(validator) + , m_rttEstimator(make_shared(options.rttOptions)) + , m_timeLastSegmentReceived(time::steady_clock::now()) + , m_nextSegmentNum(0) + , m_cwnd(options.initCwnd) + , m_ssthresh(options.initSsthresh) + , m_nSegmentsInFlight(0) + , m_nSegments(0) + , m_highInterest(0) + , m_highData(0) + , m_recPoint(0) + , m_nReceived(0) + , m_nBytesReceived(0) +{ + m_options.validate(); +} + +shared_ptr +SegmentFetcher::start(Face& face, + const Interest& baseInterest, + security::v2::Validator& validator, + const SegmentFetcher::Options& options) +{ + shared_ptr fetcher(new SegmentFetcher(face, validator, options)); + fetcher->m_this = fetcher; + fetcher->fetchFirstSegment(baseInterest, false); + return fetcher; +} + +void +SegmentFetcher::stop() +{ + if (!m_this) { + return; + } + + m_pendingSegments.clear(); // cancels pending Interests and timeout events + m_scheduler.schedule(0_s, [self = std::move(m_this)] {}); +} + +bool +SegmentFetcher::shouldStop(const weak_ptr& weakSelf) +{ + auto self = weakSelf.lock(); + return self == nullptr || self->m_this == nullptr; +} + +void +SegmentFetcher::fetchFirstSegment(const Interest& baseInterest, bool isRetransmission) +{ + Interest interest(baseInterest); + interest.setCanBePrefix(true); + interest.setMustBeFresh(true); + interest.setInterestLifetime(m_options.interestLifetime); + if (isRetransmission) { + interest.refreshNonce(); + } + + sendInterest(0, interest, isRetransmission); +} + +void +SegmentFetcher::fetchSegmentsInWindow(const Interest& origInterest) +{ + if (checkAllSegmentsReceived()) { + // All segments have been retrieved + return finalizeFetch(); + } + + int64_t availableWindowSize = static_cast(m_cwnd) - m_nSegmentsInFlight; + std::vector> segmentsToRequest; // The boolean indicates whether a retx or not + + while (availableWindowSize > 0) { + if (!m_retxQueue.empty()) { + auto pendingSegmentIt = m_pendingSegments.find(m_retxQueue.front()); + m_retxQueue.pop(); + if (pendingSegmentIt == m_pendingSegments.end()) { + // Skip re-requesting this segment, since it was received after RTO timeout + continue; + } + BOOST_ASSERT(pendingSegmentIt->second.state == SegmentState::InRetxQueue); + segmentsToRequest.emplace_back(pendingSegmentIt->first, true); + } + else if (m_nSegments == 0 || m_nextSegmentNum < static_cast(m_nSegments)) { + if (m_receivedSegments.count(m_nextSegmentNum) > 0) { + // Don't request a segment a second time if received in response to first "discovery" Interest + m_nextSegmentNum++; + continue; + } + segmentsToRequest.emplace_back(m_nextSegmentNum++, false); + } + else { + break; + } + availableWindowSize--; + } + + for (const auto& segment : segmentsToRequest) { + Interest interest(origInterest); // to preserve Interest elements + interest.setName(Name(m_versionedDataName).appendSegment(segment.first)); + interest.setCanBePrefix(false); + interest.setMustBeFresh(false); + interest.setInterestLifetime(m_options.interestLifetime); + interest.refreshNonce(); + sendInterest(segment.first, interest, segment.second); + } +} + +void +SegmentFetcher::sendInterest(uint64_t segNum, const Interest& interest, bool isRetransmission) +{ + weak_ptr weakSelf = m_this; + + ++m_nSegmentsInFlight; + auto pendingInterest = m_face.expressInterest(interest, + [this, weakSelf] (const Interest& interest, const Data& data) { + afterSegmentReceivedCb(interest, data, weakSelf); + }, + [this, weakSelf] (const Interest& interest, const lp::Nack& nack) { + afterNackReceivedCb(interest, nack, weakSelf); + }, + nullptr); + + auto timeout = m_options.useConstantInterestTimeout ? m_options.maxTimeout : getEstimatedRto(); + auto timeoutEvent = m_scheduler.schedule(timeout, [this, interest, weakSelf] { + afterTimeoutCb(interest, weakSelf); + }); + + if (isRetransmission) { + updateRetransmittedSegment(segNum, pendingInterest, timeoutEvent); + return; + } + + PendingSegment pendingSegment{SegmentState::FirstInterest, time::steady_clock::now(), + pendingInterest, timeoutEvent}; + bool isNew = m_pendingSegments.emplace(segNum, std::move(pendingSegment)).second; + BOOST_VERIFY(isNew); + m_highInterest = segNum; +} + +void +SegmentFetcher::afterSegmentReceivedCb(const Interest& origInterest, const Data& data, + const weak_ptr& weakSelf) +{ + if (shouldStop(weakSelf)) + return; + + BOOST_ASSERT(m_nSegmentsInFlight > 0); + m_nSegmentsInFlight--; + + name::Component currentSegmentComponent = data.getName().get(-1); + if (!currentSegmentComponent.isSegment()) { + return signalError(DATA_HAS_NO_SEGMENT, "Data Name has no segment number"); + } + + uint64_t currentSegment = currentSegmentComponent.toSegment(); + + // The first received Interest could have any segment ID + std::map::iterator pendingSegmentIt; + if (m_receivedSegments.size() > 0) { + pendingSegmentIt = m_pendingSegments.find(currentSegment); + } + else { + pendingSegmentIt = m_pendingSegments.begin(); + } + + if (pendingSegmentIt == m_pendingSegments.end()) { + return; + } + + pendingSegmentIt->second.timeoutEvent.cancel(); + + afterSegmentReceived(data); + + m_validator.validate(data, + bind(&SegmentFetcher::afterValidationSuccess, this, _1, origInterest, + pendingSegmentIt, weakSelf), + bind(&SegmentFetcher::afterValidationFailure, this, _1, _2, weakSelf)); +} + +void +SegmentFetcher::afterValidationSuccess(const Data& data, const Interest& origInterest, + std::map::iterator pendingSegmentIt, + const weak_ptr& weakSelf) +{ + if (shouldStop(weakSelf)) + return; + + // We update the last receive time here instead of in the segment received callback so that the + // transfer will not fail to terminate if we only received invalid Data packets. + m_timeLastSegmentReceived = time::steady_clock::now(); + + m_nReceived++; + + // It was verified in afterSegmentReceivedCb that the last Data name component is a segment number + uint64_t currentSegment = data.getName().get(-1).toSegment(); + // Add measurement to RTO estimator (if not retransmission) + if (pendingSegmentIt->second.state == SegmentState::FirstInterest) { + BOOST_ASSERT(m_nSegmentsInFlight >= 0); + m_rttEstimator.addMeasurement(m_timeLastSegmentReceived - pendingSegmentIt->second.sendTime, + static_cast(m_nSegmentsInFlight) + 1); + } + + // Remove from pending segments map + m_pendingSegments.erase(pendingSegmentIt); + + // Copy data in segment to temporary buffer + auto receivedSegmentIt = m_receivedSegments.emplace(std::piecewise_construct, + std::forward_as_tuple(currentSegment), + std::forward_as_tuple(data.getContent().value_size())); + std::copy(data.getContent().value_begin(), data.getContent().value_end(), + receivedSegmentIt.first->second.begin()); + m_nBytesReceived += data.getContent().value_size(); + afterSegmentValidated(data); + + if (data.getFinalBlock()) { + if (!data.getFinalBlock()->isSegment()) { + return signalError(FINALBLOCKID_NOT_SEGMENT, + "Received FinalBlockId did not contain a segment component"); + } + + if (data.getFinalBlock()->toSegment() + 1 != static_cast(m_nSegments)) { + m_nSegments = data.getFinalBlock()->toSegment() + 1; + cancelExcessInFlightSegments(); + } + } + + if (m_receivedSegments.size() == 1) { + m_versionedDataName = data.getName().getPrefix(-1); + if (currentSegment == 0) { + // We received the first segment in response, so we can increment the next segment number + m_nextSegmentNum++; + } + } + + if (m_highData < currentSegment) { + m_highData = currentSegment; + } + + if (data.getCongestionMark() > 0 && !m_options.ignoreCongMarks) { + windowDecrease(); + } + else { + windowIncrease(); + } + + fetchSegmentsInWindow(origInterest); +} + +void +SegmentFetcher::afterValidationFailure(const Data& data, + const security::v2::ValidationError& error, + const weak_ptr& weakSelf) +{ + if (shouldStop(weakSelf)) + return; + + signalError(SEGMENT_VALIDATION_FAIL, "Segment validation failed: " + boost::lexical_cast(error)); +} + +void +SegmentFetcher::afterNackReceivedCb(const Interest& origInterest, const lp::Nack& nack, + const weak_ptr& weakSelf) +{ + if (shouldStop(weakSelf)) + return; + + afterSegmentNacked(); + + BOOST_ASSERT(m_nSegmentsInFlight > 0); + m_nSegmentsInFlight--; + + switch (nack.getReason()) { + case lp::NackReason::DUPLICATE: + case lp::NackReason::CONGESTION: + afterNackOrTimeout(origInterest); + break; + default: + signalError(NACK_ERROR, "Nack Error"); + break; + } +} + +void +SegmentFetcher::afterTimeoutCb(const Interest& origInterest, + const weak_ptr& weakSelf) +{ + if (shouldStop(weakSelf)) + return; + + afterSegmentTimedOut(); + + BOOST_ASSERT(m_nSegmentsInFlight > 0); + m_nSegmentsInFlight--; + afterNackOrTimeout(origInterest); +} + +void +SegmentFetcher::afterNackOrTimeout(const Interest& origInterest) +{ + if (time::steady_clock::now() >= m_timeLastSegmentReceived + m_options.maxTimeout) { + // Fail transfer due to exceeding the maximum timeout between the successful receipt of segments + return signalError(INTEREST_TIMEOUT, "Timeout exceeded"); + } + + name::Component lastNameComponent = origInterest.getName().get(-1); + std::map::iterator pendingSegmentIt; + BOOST_ASSERT(m_pendingSegments.size() > 0); + if (lastNameComponent.isSegment()) { + BOOST_ASSERT(m_pendingSegments.count(lastNameComponent.toSegment()) > 0); + pendingSegmentIt = m_pendingSegments.find(lastNameComponent.toSegment()); + } + else { // First Interest + BOOST_ASSERT(m_pendingSegments.size() > 0); + pendingSegmentIt = m_pendingSegments.begin(); + } + + // Cancel timeout event and set status to InRetxQueue + pendingSegmentIt->second.timeoutEvent.cancel(); + pendingSegmentIt->second.state = SegmentState::InRetxQueue; + + m_rttEstimator.backoffRto(); + + if (m_receivedSegments.size() == 0) { + // Resend first Interest (until maximum receive timeout exceeded) + fetchFirstSegment(origInterest, true); + } + else { + windowDecrease(); + m_retxQueue.push(pendingSegmentIt->first); + fetchSegmentsInWindow(origInterest); + } +} + +void +SegmentFetcher::finalizeFetch() +{ + // Combine segments into final buffer + OBufferStream buf; + // We may have received more segments than exist in the object. + BOOST_ASSERT(m_receivedSegments.size() >= static_cast(m_nSegments)); + + for (int64_t i = 0; i < m_nSegments; i++) { + buf.write(m_receivedSegments[i].get(), m_receivedSegments[i].size()); + } + + onComplete(buf.buf()); + stop(); +} + +void +SegmentFetcher::windowIncrease() +{ + if (m_options.useConstantCwnd) { + BOOST_ASSERT(m_cwnd == m_options.initCwnd); + return; + } + + if (m_cwnd < m_ssthresh) { + m_cwnd += m_options.aiStep; // additive increase + } + else { + m_cwnd += m_options.aiStep / std::floor(m_cwnd); // congestion avoidance + } +} + +void +SegmentFetcher::windowDecrease() +{ + if (m_options.disableCwa || m_highData > m_recPoint) { + m_recPoint = m_highInterest; + + if (m_options.useConstantCwnd) { + BOOST_ASSERT(m_cwnd == m_options.initCwnd); + return; + } + + // Refer to RFC 5681, Section 3.1 for the rationale behind the code below + m_ssthresh = std::max(MIN_SSTHRESH, m_cwnd * m_options.mdCoef); // multiplicative decrease + m_cwnd = m_options.resetCwndToInit ? m_options.initCwnd : m_ssthresh; + } +} + +void +SegmentFetcher::signalError(uint32_t code, const std::string& msg) +{ + onError(code, msg); + stop(); +} + +void +SegmentFetcher::updateRetransmittedSegment(uint64_t segmentNum, + const PendingInterestHandle& pendingInterest, + scheduler::EventId timeoutEvent) +{ + auto pendingSegmentIt = m_pendingSegments.find(segmentNum); + BOOST_ASSERT(pendingSegmentIt != m_pendingSegments.end()); + BOOST_ASSERT(pendingSegmentIt->second.state == SegmentState::InRetxQueue); + pendingSegmentIt->second.state = SegmentState::Retransmitted; + pendingSegmentIt->second.hdl = pendingInterest; // cancels previous pending Interest via scoped handle + pendingSegmentIt->second.timeoutEvent = timeoutEvent; +} + +void +SegmentFetcher::cancelExcessInFlightSegments() +{ + for (auto it = m_pendingSegments.begin(); it != m_pendingSegments.end();) { + if (it->first >= static_cast(m_nSegments)) { + it = m_pendingSegments.erase(it); // cancels pending Interest and timeout event + BOOST_ASSERT(m_nSegmentsInFlight > 0); + m_nSegmentsInFlight--; + } + else { + ++it; + } + } +} + +bool +SegmentFetcher::checkAllSegmentsReceived() +{ + bool haveReceivedAllSegments = false; + + if (m_nSegments != 0 && m_nReceived >= m_nSegments) { + haveReceivedAllSegments = true; + // Verify that all segments in window have been received. If not, send Interests for missing segments. + for (uint64_t i = 0; i < static_cast(m_nSegments); i++) { + if (m_receivedSegments.count(i) == 0) { + m_retxQueue.push(i); + haveReceivedAllSegments = false; + } + } + } + + return haveReceivedAllSegments; +} + +time::milliseconds +SegmentFetcher::getEstimatedRto() +{ + // We don't want an Interest timeout greater than the maximum allowed timeout between the + // succesful receipt of segments + return std::min(m_options.maxTimeout, + time::duration_cast(m_rttEstimator.getEstimatedRto())); +} + +} // namespace util +} // namespace ndn diff --git a/ndn-cxx/util/segment-fetcher.hpp b/ndn-cxx/util/segment-fetcher.hpp new file mode 100644 index 000000000..2820cf177 --- /dev/null +++ b/ndn-cxx/util/segment-fetcher.hpp @@ -0,0 +1,327 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Shuo Yang + * @author Weiwei Liu + * @author Chavoosh Ghasemi + */ + +#ifndef NDN_UTIL_SEGMENT_FETCHER_HPP +#define NDN_UTIL_SEGMENT_FETCHER_HPP + +#include "ndn-cxx/face.hpp" +#include "ndn-cxx/security/v2/validator.hpp" +#include "ndn-cxx/util/rtt-estimator.hpp" +#include "ndn-cxx/util/scheduler.hpp" +#include "ndn-cxx/util/signal.hpp" + +#include + +namespace ndn { +namespace util { + +/** + * @brief Utility class to fetch the latest version of a segmented object. + * + * SegmentFetcher assumes that segments in the object are named `///`, + * where: + * - `` is the specified prefix, + * - `` is an unknown version that needs to be discovered, and + * - `` is a segment number (the number of segments in the object is unknown until a Data + * packet containing the `FinalBlockId` field is received). + * + * SegmentFetcher implements the following logic: + * + * 1. Express an Interest to discover the latest version of the object: + * + * Interest: `/?ndn.CanBePrefix=true&ndn.MustBeFresh=true` + * + * 2. Infer the latest version of the object: ` = Data.getName().get(-2)` + * + * 3. Keep sending Interests for future segments until an error occurs or the number of segments + * indicated by the FinalBlockId in a received Data packet is reached. This retrieval will start + * at segment 1 if segment 0 was received in response to the Interest expressed in step 2; + * otherwise, retrieval will start at segment 0. By default, congestion control will be used to + * manage the Interest window size. Interests expressed in this step will follow this Name + * format: + * + * Interest: `///` + * + * 4. Signal #onComplete passing a memory buffer that combines the content of all segments in the object. + * + * If an error occurs during the fetching process, #onError is signaled with one of the error codes + * from SegmentFetcher::ErrorCode. + * + * A Validator instance must be specified to validate individual segments. Every time a segment has + * been successfully validated, #afterSegmentValidated will be signaled. + * + * Example: + * @code + * void + * afterFetchComplete(ConstBufferPtr data) + * { + * ... + * } + * + * void + * afterFetchError(uint32_t errorCode, const std::string& errorMsg) + * { + * ... + * } + * + * ... + * auto fetcher = SegmentFetcher::start(face, Interest("/data/prefix"), validator); + * fetcher->onComplete.connect(bind(&afterFetchComplete, this, _1)); + * fetcher->onError.connect(bind(&afterFetchError, this, _1, _2)); + * @endcode + */ +class SegmentFetcher : noncopyable +{ +public: + /** + * @brief Error codes passed to #onError. + */ + enum ErrorCode { + /// Retrieval timed out because the maximum timeout between the successful receipt of segments was exceeded + INTEREST_TIMEOUT = 1, + /// One of the retrieved Data packets lacked a segment number in the last Name component (excl. implicit digest) + DATA_HAS_NO_SEGMENT = 2, + /// One of the retrieved segments failed user-provided validation + SEGMENT_VALIDATION_FAIL = 3, + /// An unrecoverable Nack was received during retrieval + NACK_ERROR = 4, + /// A received FinalBlockId did not contain a segment component + FINALBLOCKID_NOT_SEGMENT = 5, + }; + + class Options + { + public: + Options() + { + } + + void + validate(); + + public: + bool useConstantCwnd = false; ///< if true, window size is kept at `initCwnd` + bool useConstantInterestTimeout = false; ///< if true, Interest timeout is kept at `maxTimeout` + time::milliseconds maxTimeout = 60_s; ///< maximum allowed time between successful receipt of segments + time::milliseconds interestLifetime = 4_s; ///< lifetime of sent Interests - independent of Interest timeout + double initCwnd = 1.0; ///< initial congestion window size + double initSsthresh = std::numeric_limits::max(); ///< initial slow start threshold + double aiStep = 1.0; ///< additive increase step (in segments) + double mdCoef = 0.5; ///< multiplicative decrease coefficient + bool disableCwa = false; ///< disable Conservative Window Adaptation + bool resetCwndToInit = false; ///< reduce cwnd to initCwnd when loss event occurs + bool ignoreCongMarks = false; ///< disable window decrease after congestion mark received + RttEstimator::Options rttOptions; ///< options for RTT estimator + }; + + /** + * @brief Initiates segment fetching. + * + * Transfer completion, failure, and progress are indicated via signals. + * + * @param face Reference to the Face that should be used to fetch data. + * @param baseInterest Interest for the initial segment of requested data. + * This interest may include a custom InterestLifetime and parameters that + * will propagate to all subsequent Interests. The only exception is that the + * initial Interest will be forced to include the "CanBePrefix=true" and + * "MustBeFresh=true" parameters, which will not be included in subsequent + * Interests. + * @param validator Reference to the Validator the fetcher will use to validate data. + * The caller must ensure the validator remains valid until either #onComplete + * or #onError has been signaled. + * @param options Options controlling the transfer. + * + * @return A shared_ptr to the constructed SegmentFetcher. + * This shared_ptr is kept internally for the lifetime of the transfer. + * Therefore, it does not need to be saved and is provided here so that the + * SegmentFetcher's signals can be connected to. + */ + static shared_ptr + start(Face& face, + const Interest& baseInterest, + security::v2::Validator& validator, + const Options& options = Options()); + + /** + * @brief Stops fetching. + * + * This cancels all interests that are still pending. + */ + void + stop(); + +private: + class PendingSegment; + + SegmentFetcher(Face& face, security::v2::Validator& validator, const Options& options); + + static bool + shouldStop(const weak_ptr& weakSelf); + + void + fetchFirstSegment(const Interest& baseInterest, bool isRetransmission); + + void + fetchSegmentsInWindow(const Interest& origInterest); + + void + sendInterest(uint64_t segNum, const Interest& interest, bool isRetransmission); + + void + afterSegmentReceivedCb(const Interest& origInterest, const Data& data, + const weak_ptr& weakSelf); + + void + afterValidationSuccess(const Data& data, const Interest& origInterest, + std::map::iterator pendingSegmentIt, + const weak_ptr& weakSelf); + + void + afterValidationFailure(const Data& data, + const security::v2::ValidationError& error, + const weak_ptr& weakSelf); + + void + afterNackReceivedCb(const Interest& origInterest, const lp::Nack& nack, + const weak_ptr& weakSelf); + + void + afterTimeoutCb(const Interest& origInterest, + const weak_ptr& weakSelf); + + void + afterNackOrTimeout(const Interest& origInterest); + + void + finalizeFetch(); + + void + windowIncrease(); + + void + windowDecrease(); + + void + signalError(uint32_t code, const std::string& msg); + + void + updateRetransmittedSegment(uint64_t segmentNum, + const PendingInterestHandle& pendingInterest, + scheduler::EventId timeoutEvent); + + void + cancelExcessInFlightSegments(); + + bool + checkAllSegmentsReceived(); + + time::milliseconds + getEstimatedRto(); + +public: + /** + * @brief Emits upon successful retrieval of the complete data. + */ + Signal onComplete; + + /** + * @brief Emits when the retrieval could not be completed due to an error. + * + * Handlers are provided with an error code and a string error message. + */ + Signal onError; + + /** + * @brief Emits whenever a data segment received. + */ + Signal afterSegmentReceived; + + /** + * @brief Emits whenever a received data segment has been successfully validated. + */ + Signal afterSegmentValidated; + + /** + * @brief Emits whenever an Interest for a data segment is nacked. + */ + Signal afterSegmentNacked; + + /** + * @brief Emits whenever an Interest for a data segment times out. + */ + Signal afterSegmentTimedOut; + +private: + enum class SegmentState { + FirstInterest, ///< the first Interest for this segment has been sent + InRetxQueue, ///< the segment is awaiting Interest retransmission + Retransmitted, ///< one or more retransmitted Interests have been sent for this segment + }; + + class PendingSegment + { + public: + SegmentState state; + time::steady_clock::TimePoint sendTime; + ScopedPendingInterestHandle hdl; + scheduler::ScopedEventId timeoutEvent; + }; + +NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: + static constexpr double MIN_SSTHRESH = 2.0; + + shared_ptr m_this; + + Options m_options; + Face& m_face; + Scheduler m_scheduler; + security::v2::Validator& m_validator; + RttEstimator m_rttEstimator; + // time::milliseconds m_timeout; + + time::steady_clock::TimePoint m_timeLastSegmentReceived; + std::queue m_retxQueue; + Name m_versionedDataName; + uint64_t m_nextSegmentNum; + double m_cwnd; + double m_ssthresh; + int64_t m_nSegmentsInFlight; + int64_t m_nSegments; + uint64_t m_highInterest; + uint64_t m_highData; + uint64_t m_recPoint; + int64_t m_nReceived; + int64_t m_nBytesReceived; + + std::map m_receivedSegments; + std::map m_pendingSegments; +}; + +} // namespace util +} // namespace ndn + +#endif // NDN_UTIL_SEGMENT_FETCHER_HPP diff --git a/ndn-cxx/util/sha256.cpp b/ndn-cxx/util/sha256.cpp new file mode 100644 index 000000000..3575884fa --- /dev/null +++ b/ndn-cxx/util/sha256.cpp @@ -0,0 +1,152 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/sha256.hpp" +#include "ndn-cxx/util/string-helper.hpp" +#include "ndn-cxx/security/impl/openssl.hpp" +#include "ndn-cxx/security/transform/digest-filter.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" +#include "ndn-cxx/security/transform/stream-source.hpp" + +namespace ndn { +namespace util { + +const size_t Sha256::DIGEST_SIZE; + +Sha256::Sha256() +{ + reset(); +} + +Sha256::Sha256(std::istream& is) + : m_output(make_unique()) + , m_isEmpty(false) + , m_isFinalized(true) +{ + namespace tr = security::transform; + + tr::streamSource(is) >> tr::digestFilter(DigestAlgorithm::SHA256) >> tr::streamSink(*m_output); +} + +void +Sha256::reset() +{ + namespace tr = security::transform; + + m_input = make_unique(); + m_output = make_unique(); + m_isEmpty = true; + m_isFinalized = false; + + *m_input >> tr::digestFilter(DigestAlgorithm::SHA256) >> tr::streamSink(*m_output); +} + +ConstBufferPtr +Sha256::computeDigest() +{ + if (!m_isFinalized) { + BOOST_ASSERT(m_input != nullptr); + m_input->end(); + m_isFinalized = true; + } + + return m_output->buf(); +} + +bool +Sha256::operator==(Sha256& digest) +{ + const Buffer& lhs = *computeDigest(); + const Buffer& rhs = *digest.computeDigest(); + + if (lhs.size() != rhs.size()) { + return false; + } + + // constant-time buffer comparison to mitigate timing attacks + return CRYPTO_memcmp(lhs.data(), rhs.data(), lhs.size()) == 0; +} + +Sha256& +Sha256::operator<<(Sha256& src) +{ + auto buf = src.computeDigest(); + update(buf->data(), buf->size()); + return *this; +} + +Sha256& +Sha256::operator<<(const std::string& str) +{ + update(reinterpret_cast(str.data()), str.size()); + return *this; +} + +Sha256& +Sha256::operator<<(const Block& block) +{ + update(block.wire(), block.size()); + return *this; +} + +Sha256& +Sha256::operator<<(uint64_t value) +{ + update(reinterpret_cast(&value), sizeof(uint64_t)); + return *this; +} + +void +Sha256::update(const uint8_t* buffer, size_t size) +{ + if (m_isFinalized) + NDN_THROW(Error("Digest has been already finalized")); + + BOOST_ASSERT(m_input != nullptr); + m_input->write(buffer, size); + m_isEmpty = false; +} + +std::string +Sha256::toString() +{ + auto buf = computeDigest(); + return toHex(*buf); +} + +ConstBufferPtr +Sha256::computeDigest(const uint8_t* buffer, size_t size) +{ + Sha256 sha256; + sha256.update(buffer, size); + return sha256.computeDigest(); +} + +std::ostream& +operator<<(std::ostream& os, Sha256& digest) +{ + auto buf = digest.computeDigest(); + printHex(os, *buf); + return os; +} + +} // namespace util +} // namespace ndn diff --git a/ndn-cxx/util/sha256.hpp b/ndn-cxx/util/sha256.hpp new file mode 100644 index 000000000..22bc25371 --- /dev/null +++ b/ndn-cxx/util/sha256.hpp @@ -0,0 +1,180 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_SHA256_HPP +#define NDN_UTIL_SHA256_HPP + +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/transform/step-source.hpp" + +namespace ndn { +namespace util { + +/** + * @brief Provides stateful SHA-256 digest calculation. + * + * Example: + * @code + * Sha256 digest; + * digest.update(buf1, size1); + * digest.update(buf2, size2); + * ... + * ConstBufferPtr result = digest.computeDigest(); + * @endcode + */ +class Sha256 +{ +public: + class Error : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + }; + + /** + * @brief Length in bytes of a SHA-256 digest. + */ + static const size_t DIGEST_SIZE = 32; + + /** + * @brief Create an empty SHA-256 digest. + */ + Sha256(); + + /** + * @brief Calculate SHA-256 digest of the input stream @p is. + */ + explicit + Sha256(std::istream& is); + + /** + * @brief Check if digest is empty. + * + * An empty digest means nothing has been taken into calculation. + */ + bool + empty() const + { + return m_isEmpty; + } + + /** + * @brief Discard the current state and start a new digest calculation. + */ + void + reset(); + + /** + * @brief Finalize and return the digest based on all previously supplied inputs. + */ + ConstBufferPtr + computeDigest(); + + /** + * @brief Check if the supplied digest is equal to this digest. + * @note This method invokes computeDigest() on both operands, finalizing the digest. + */ + bool + operator==(Sha256& digest); + + /** + * @brief Check if the supplied digest is not equal to this digest. + * @note This method invokes computeDigest() on both operands, finalizing the digest. + */ + bool + operator!=(Sha256& digest) + { + return !(*this == digest); + } + + /** + * @brief Add existing digest to the digest calculation. + * @param src digest to combine with + * + * The result of this combination is `sha256(sha256(...))` + * + * @note This method invokes computeDigest() on @p src, finalizing the digest. + * @throw Error the digest has already been finalized + */ + Sha256& + operator<<(Sha256& src); + + /** + * @brief Add a string to the digest calculation. + * @throw Error the digest has already been finalized + */ + Sha256& + operator<<(const std::string& str); + + /** + * @brief Add a block to the digest calculation. + * @throw Error the digest has already been finalized + */ + Sha256& + operator<<(const Block& block); + + /** + * @brief Add a uint64_t value to the digest calculation. + * @throw Error the digest has already been finalized + */ + Sha256& + operator<<(uint64_t value); + + /** + * @brief Add a raw buffer to the digest calculation. + * @param buffer the input buffer + * @param size the size of the input buffer + * @throw Error the digest has already been finalized + */ + void + update(const uint8_t* buffer, size_t size); + + /** + * @brief Convert digest to std::string. + * @note This method invokes computeDigest(), finalizing the digest. + */ + std::string + toString(); + + /** + * @brief Stateless SHA-256 digest calculation. + * @param buffer the input buffer + * @param size the size of the input buffer + * @return SHA-256 digest of the input buffer + */ + static ConstBufferPtr + computeDigest(const uint8_t* buffer, size_t size); + +private: + unique_ptr m_input; + unique_ptr m_output; + bool m_isEmpty; + bool m_isFinalized; +}; + +std::ostream& +operator<<(std::ostream& os, Sha256& digest); + +} // namespace util +} // namespace ndn + +#endif // NDN_UTIL_SHA256_HPP diff --git a/ndn-cxx/util/signal.hpp b/ndn-cxx/util/signal.hpp new file mode 100644 index 000000000..520b5c7e1 --- /dev/null +++ b/ndn-cxx/util/signal.hpp @@ -0,0 +1,30 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_SIGNAL_HPP +#define NDN_UTIL_SIGNAL_HPP + +#include "ndn-cxx/util/signal/signal.hpp" +#include "ndn-cxx/util/signal/emit.hpp" +#include "ndn-cxx/util/signal/connection.hpp" +#include "ndn-cxx/util/signal/scoped-connection.hpp" + +#endif // NDN_UTIL_SIGNAL_HPP diff --git a/ndn-cxx/util/signal/connection.cpp b/ndn-cxx/util/signal/connection.cpp new file mode 100644 index 000000000..1eb6a0886 --- /dev/null +++ b/ndn-cxx/util/signal/connection.cpp @@ -0,0 +1,46 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/signal/connection.hpp" + +namespace ndn { +namespace util { +namespace signal { + +BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); + +Connection::Connection(weak_ptr disconnect) noexcept + : m_disconnect(std::move(disconnect)) +{ +} + +void +Connection::disconnect() +{ + auto f = m_disconnect.lock(); + if (f != nullptr) { + (*f)(); + } +} + +} // namespace signal +} // namespace util +} // namespace ndn diff --git a/ndn-cxx/util/signal/connection.hpp b/ndn-cxx/util/signal/connection.hpp new file mode 100644 index 000000000..01bce6028 --- /dev/null +++ b/ndn-cxx/util/signal/connection.hpp @@ -0,0 +1,106 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_SIGNAL_CONNECTION_HPP +#define NDN_UTIL_SIGNAL_CONNECTION_HPP + +#include "ndn-cxx/detail/common.hpp" + +namespace ndn { +namespace util { +namespace signal { + +using DisconnectFunction = std::function; + +/** \brief represents a connection to a signal + * \note This type is copyable. Any copy can be used to disconnect. + */ +class Connection +{ +public: + constexpr + Connection() noexcept = default; + + /** \brief disconnects from the signal + * \note If the connection is already disconnected, or if the Signal has been destructed, + * this operation has no effect. + * \warning During signal emission, attempting to disconnect a connection other than + * the executing handler's own connection results in undefined behavior. + */ + void + disconnect(); + + /** \brief check if connected to the signal + */ + bool + isConnected() const noexcept + { + return !m_disconnect.expired(); + } + +private: + /** \param disconnect weak_ptr to a function that disconnects the handler + */ + explicit + Connection(weak_ptr disconnect) noexcept; + + template + friend class Signal; + +private: + // NOTE: the following "hidden friend" operators are available via + // argument-dependent lookup only and must be defined inline. + + /** \brief compare for equality + * + * Two connections are equal if they both refer to the same connection that isn't disconnected, + * or they are both disconnected. + */ + friend bool + operator==(const Connection& lhs, const Connection& rhs) noexcept + { + return (!lhs.isConnected() && !rhs.isConnected()) || + (!lhs.m_disconnect.owner_before(rhs.m_disconnect) && + !rhs.m_disconnect.owner_before(lhs.m_disconnect)); + } + + friend bool + operator!=(const Connection& lhs, const Connection& rhs) noexcept + { + return !(lhs == rhs); + } + +private: + /** \note The only shared_ptr to the disconnect function is stored in Signal<..>::Slot, + * and will be destructed if the handler is disconnected (through another Connection + * instance) or the Signal is destructed. + * Connection needs a weak_ptr instead of a shared_ptr to the disconnect function, + * because the disconnect function is bound with an iterator to the Slot, + * which is invalidated when the Slot is erased. + */ + weak_ptr m_disconnect; +}; + +} // namespace signal +} // namespace util +} // namespace ndn + +#endif // NDN_UTIL_SIGNAL_CONNECTION_HPP diff --git a/ndn-cxx/util/signal/emit.hpp b/ndn-cxx/util/signal/emit.hpp new file mode 100644 index 000000000..c073f1fd1 --- /dev/null +++ b/ndn-cxx/util/signal/emit.hpp @@ -0,0 +1,79 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +/** \file + * + * This header provides macros that allows a signal to be emitted + * from a derived class of its owner. + * + * In 'protected' section of owner class declaration, + * DECLARE_SIGNAL_EMIT(signalName) + * From a derived class of owner, + * this->emitSignal(signalName, arg1, arg2); + */ + +#ifndef NDN_UTIL_SIGNAL_EMIT_HPP +#define NDN_UTIL_SIGNAL_EMIT_HPP + +namespace ndn { +namespace util { +namespace signal { + +/** \brief (implementation detail) a filler for extra argument + */ +class DummyExtraArg +{ +}; + +} // namespace signal +} // namespace util +} // namespace ndn + +/** \brief (implementation detail) declares a 'emit_signalName' method + * \note This macro should be used in 'protected' section so that it's accessible + * by derived classes. + * \note emit_signalName method is implementation detail. + * Derived classes should use 'emitSignal' macro. + * \note The name 'emit_signalName' is an intentional violation of code-style rule 2.5. + * \note The method is declared as a template, so that the macro doesn't need argument types. + * But only argument types that are compatible with Signal declaration will work. + */ +#define DECLARE_SIGNAL_EMIT(signalName) \ + template \ + void emit_##signalName(const TArgs&... args) \ + { \ + signalName(args...); \ + } + +/** \brief (implementation detail) invokes emit_signalName method + * \note C99 requires at least one argument to be passed in __VA_ARGS__, + * thus a DummyExtraArg is expected at the end of __VA_ARGS__, + * which will be accepted but ignored by Signal::operator() overload. + */ +#define NDN_CXX_SIGNAL_EMIT(signalName, ...) \ + emit_##signalName(__VA_ARGS__) + +/** \brief (implementation detail) + */ +#define emitSignal(...) \ + NDN_CXX_SIGNAL_EMIT(__VA_ARGS__, ::ndn::util::signal::DummyExtraArg()) + +#endif // NDN_UTIL_SIGNAL_EMIT_HPP diff --git a/ndn-cxx/util/signal/scoped-connection.cpp b/ndn-cxx/util/signal/scoped-connection.cpp new file mode 100644 index 000000000..1a843b176 --- /dev/null +++ b/ndn-cxx/util/signal/scoped-connection.cpp @@ -0,0 +1,68 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/signal/scoped-connection.hpp" + +namespace ndn { +namespace util { +namespace signal { + +ScopedConnection::ScopedConnection(Connection connection) noexcept + : m_connection(std::move(connection)) +{ +} + +ScopedConnection& +ScopedConnection::operator=(Connection connection) +{ + if (m_connection != connection) { + disconnect(); + m_connection = std::move(connection); + } + return *this; +} + +ScopedConnection::~ScopedConnection() +{ + disconnect(); +} + +void +ScopedConnection::disconnect() +{ + m_connection.disconnect(); +} + +bool +ScopedConnection::isConnected() const noexcept +{ + return m_connection.isConnected(); +} + +void +ScopedConnection::release() noexcept +{ + m_connection = {}; +} + +} // namespace signal +} // namespace util +} // namespace ndn diff --git a/ndn-cxx/util/signal/scoped-connection.hpp b/ndn-cxx/util/signal/scoped-connection.hpp new file mode 100644 index 000000000..df90271ad --- /dev/null +++ b/ndn-cxx/util/signal/scoped-connection.hpp @@ -0,0 +1,102 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_SIGNAL_SCOPED_CONNECTION_HPP +#define NDN_UTIL_SIGNAL_SCOPED_CONNECTION_HPP + +#include "ndn-cxx/util/signal/connection.hpp" + +namespace ndn { +namespace util { +namespace signal { + +/** \brief Disconnects a Connection automatically upon destruction. + */ +class ScopedConnection +{ +public: + constexpr + ScopedConnection() noexcept = default; + + ScopedConnection(const ScopedConnection&) = delete; + + ScopedConnection& + operator=(const ScopedConnection&) = delete; + + /** \brief Move constructor. + */ + ScopedConnection(ScopedConnection&&) noexcept; + + /** \brief Move assignment operator. + */ + ScopedConnection& + operator=(ScopedConnection&&) noexcept; + + /** \brief Implicit constructor from Connection. + * \param connection the Connection to be disconnected upon destruction + */ + ScopedConnection(Connection connection) noexcept; + + /** \brief Assign a connection. + * + * If a different connection has been assigned to this instance previously, + * that connection will be disconnected immediately. + */ + ScopedConnection& + operator=(Connection connection); + + /** \brief Destructor, automatically disconnects the connection. + */ + ~ScopedConnection(); + + /** \brief Manually disconnect the connection. + */ + void + disconnect(); + + /** \brief Check if the connection is connected to the signal. + * \return false when a default-constructed connection is used, the connection is released, + * or the connection is disconnected + */ + bool + isConnected() const noexcept; + + /** \brief Release the connection so that it won't be disconnected + * when this ScopedConnection is destructed. + */ + void + release() noexcept; + +private: + Connection m_connection; +}; + +inline +ScopedConnection::ScopedConnection(ScopedConnection&&) noexcept = default; + +inline ScopedConnection& +ScopedConnection::operator=(ScopedConnection&&) noexcept = default; + +} // namespace signal +} // namespace util +} // namespace ndn + +#endif // NDN_UTIL_SIGNAL_SCOPED_CONNECTION_HPP diff --git a/ndn-cxx/util/signal/signal.hpp b/ndn-cxx/util/signal/signal.hpp new file mode 100644 index 000000000..fe2aee5fd --- /dev/null +++ b/ndn-cxx/util/signal/signal.hpp @@ -0,0 +1,263 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_SIGNAL_SIGNAL_HPP +#define NDN_UTIL_SIGNAL_SIGNAL_HPP + +#include "ndn-cxx/util/signal/connection.hpp" + +#include + +namespace ndn { +namespace util { +namespace signal { + +class DummyExtraArg; + +/** \brief provides a lightweight signal / event system + * + * To declare a signal: + * public: + * Signal signalName; + * To connect to a signal: + * owner->signalName.connect(f); + * Multiple functions can connect to the same signal. + * To emit a signal from owner: + * this->signalName(arg1, arg2); + * + * \tparam Owner the signal owner class; only this class can emit the signal + * \tparam TArgs types of signal arguments + * \sa signal-emit.hpp allows owner's derived classes to emit signals + */ +template +class Signal : noncopyable +{ +public: // API for anyone + /** \brief represents a function that can connect to the signal + */ + typedef function Handler; + + Signal(); + + ~Signal(); + + /** \brief connects a handler to the signal + * \note If invoked from a handler, the new handler won't receive the current emitted signal. + * \warning The handler is permitted to disconnect itself, but it must ensure its validity. + */ + Connection + connect(Handler handler); + + /** \brief connects a single-shot handler to the signal + * + * After the handler is executed once, it is automatically disconnected. + */ + Connection + connectSingleShot(Handler handler); + +private: // API for owner + /** \retval true if there is no connection + */ + bool + isEmpty() const; + + /** \brief emits a signal + * \param args arguments passed to all handlers + * \warning Emitting the signal from a handler is undefined behavior. + * \warning Destructing the Signal object during signal emission is undefined behavior. + * \note If a handler throws, the exception will be propagated to the caller + * who emits this signal, and some handlers may not be executed. + */ + void + operator()(const TArgs&... args); + + /** \brief (implementation detail) emits a signal + * \note This overload is used by signal-emit.hpp. + */ + void + operator()(const TArgs&... args, const DummyExtraArg&); + + // make Owner a friend of Signal so that API for owner can be called + friend Owner; + +private: // internal implementation + typedef Signal Self; + + /** \brief stores a handler function, and a function to disconnect this handler + */ + struct Slot + { + /** \brief the handler function who will receive emitted signals + */ + Handler handler; + + /** \brief the disconnect function which will disconnect this handler + * + * In practice this is the Signal::disconnect method bound to an iterator + * pointing at this slot. + * + * This is the only shared_ptr to this function object. + * Connection class has a weak_ptr which references the same function object. + * When the slot is erased or the signal is destructed, this function object is + * destructed, and the related Connections cannot disconnect this slot again. + */ + shared_ptr disconnect; + }; + + /** \brief stores slots + * \note std::list is used because iterators must not be invalidated + * when other slots are added or removed + */ + typedef std::list SlotList; + SlotList m_slots; + + /** \brief is a signal handler executing? + */ + bool m_isExecuting; + + /** \brief iterator to current executing slot + * \note This field is meaningful when isExecuting==true + */ + typename SlotList::iterator m_currentSlot; + + /** \brief disconnects the handler in a slot + */ + void + disconnect(typename SlotList::iterator it); +}; + +template +Signal::Signal() + : m_isExecuting(false) +{ +} + +template +Signal::~Signal() +{ + BOOST_ASSERT(!m_isExecuting); +} + +template +Connection +Signal::connect(Handler handler) +{ + auto it = m_slots.insert(m_slots.end(), {std::move(handler), nullptr}); + it->disconnect = make_shared([=] { disconnect(it); }); + + return signal::Connection(it->disconnect); +} + +template +Connection +Signal::connectSingleShot(Handler handler) +{ + auto it = m_slots.insert(m_slots.end(), {nullptr, nullptr}); + it->disconnect = make_shared([=] { disconnect(it); }); + signal::Connection conn(it->disconnect); + + it->handler = [conn, handler = std::move(handler)] (const TArgs&... args) mutable { + handler(args...); + conn.disconnect(); + }; + + return conn; +} + +template +void +Signal::disconnect(typename SlotList::iterator it) +{ + if (m_isExecuting) { + // during signal emission, only the currently executing handler can be disconnected + BOOST_ASSERT_MSG(it == m_currentSlot, "cannot disconnect another handler from a handler"); + + // this serves to indicate that the current slot needs to be erased from the list + // after it finishes executing; we cannot do it here because of bug #2333 + m_currentSlot = m_slots.end(); + + // expire all weak_ptrs, to prevent double disconnections + it->disconnect.reset(); + } + else { + m_slots.erase(it); + } +} + +template +bool +Signal::isEmpty() const +{ + return !m_isExecuting && m_slots.empty(); +} + +template +void +Signal::operator()(const TArgs&... args) +{ + BOOST_ASSERT_MSG(!m_isExecuting, "cannot emit signal from a handler"); + + if (m_slots.empty()) { + return; + } + + auto it = m_slots.begin(); + auto last = std::prev(m_slots.end()); + m_isExecuting = true; + + try { + bool isLast = false; + while (!isLast) { + m_currentSlot = it; + isLast = it == last; + + m_currentSlot->handler(args...); + + if (m_currentSlot == m_slots.end()) + it = m_slots.erase(it); + else + ++it; + } + } + catch (...) { + m_isExecuting = false; + throw; + } + + m_isExecuting = false; +} + +template +void +Signal::operator()(const TArgs&... args, const DummyExtraArg&) +{ + this->operator()(args...); +} + +} // namespace signal + +// expose as ndn::util::Signal +using signal::Signal; + +} // namespace util +} // namespace ndn + +#endif // NDN_UTIL_SIGNAL_SIGNAL_HPP diff --git a/src/util/sqlite3-statement.cpp b/ndn-cxx/util/sqlite3-statement.cpp similarity index 87% rename from src/util/sqlite3-statement.cpp rename to ndn-cxx/util/sqlite3-statement.cpp index f1871db1a..4426a020f 100644 --- a/src/util/sqlite3-statement.cpp +++ b/ndn-cxx/util/sqlite3-statement.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,7 +19,7 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "sqlite3-statement.hpp" +#include "ndn-cxx/util/sqlite3-statement.hpp" #include @@ -33,9 +33,9 @@ Sqlite3Statement::~Sqlite3Statement() Sqlite3Statement::Sqlite3Statement(sqlite3* database, const std::string& statement) { - int res = sqlite3_prepare_v2(database, statement.c_str(), -1, &m_stmt, nullptr); + int res = sqlite3_prepare_v2(database, statement.data(), -1, &m_stmt, nullptr); if (res != SQLITE_OK) - BOOST_THROW_EXCEPTION(std::domain_error("bad SQL statement: " + statement)); + NDN_THROW(std::domain_error("bad SQL statement: " + statement)); } int @@ -78,7 +78,8 @@ Sqlite3Statement::getString(int column) Block Sqlite3Statement::getBlock(int column) { - return Block(sqlite3_column_blob(m_stmt, column), sqlite3_column_bytes(m_stmt, column)); + return Block(reinterpret_cast(sqlite3_column_blob(m_stmt, column)), + sqlite3_column_bytes(m_stmt, column)); } int diff --git a/src/util/sqlite3-statement.hpp b/ndn-cxx/util/sqlite3-statement.hpp similarity index 97% rename from src/util/sqlite3-statement.hpp rename to ndn-cxx/util/sqlite3-statement.hpp index 82480d9ba..9705b052d 100644 --- a/src/util/sqlite3-statement.hpp +++ b/ndn-cxx/util/sqlite3-statement.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,8 +22,7 @@ #ifndef NDN_UTIL_SQLITE3_STATEMENT_HPP #define NDN_UTIL_SQLITE3_STATEMENT_HPP -#include "../encoding/block.hpp" -#include +#include "ndn-cxx/encoding/block.hpp" struct sqlite3; struct sqlite3_stmt; diff --git a/ndn-cxx/util/string-helper.cpp b/ndn-cxx/util/string-helper.cpp new file mode 100644 index 000000000..06b08a6de --- /dev/null +++ b/ndn-cxx/util/string-helper.cpp @@ -0,0 +1,157 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/string-helper.hpp" +#include "ndn-cxx/encoding/buffer.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/hex-decode.hpp" +#include "ndn-cxx/security/transform/hex-encode.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" + +#include + +namespace ndn { + +std::ostream& +operator<<(std::ostream& os, const AsHex& hex) +{ + printHex(os, hex.m_value, os.flags() & std::ostream::uppercase); + return os; +} + +void +printHex(std::ostream& os, uint64_t num, bool wantUpperCase) +{ + auto osFlags = os.flags(); + // std::showbase doesn't work with number 0 + os << "0x" << std::noshowbase << std::noshowpos + << (wantUpperCase ? std::uppercase : std::nouppercase) + << std::hex << num; + os.flags(osFlags); +} + +void +printHex(std::ostream& os, const uint8_t* buffer, size_t length, bool wantUpperCase) +{ + namespace tr = security::transform; + BOOST_ASSERT(buffer != nullptr || length == 0); + tr::bufferSource(buffer, length) >> tr::hexEncode(wantUpperCase) >> tr::streamSink(os); +} + +void +printHex(std::ostream& os, const Buffer& buffer, bool wantUpperCase) +{ + return printHex(os, buffer.data(), buffer.size(), wantUpperCase); +} + +std::string +toHex(const uint8_t* buffer, size_t length, bool wantUpperCase) +{ + std::ostringstream result; + printHex(result, buffer, length, wantUpperCase); + return result.str(); +} + +std::string +toHex(const Buffer& buffer, bool wantUpperCase) +{ + return toHex(buffer.data(), buffer.size(), wantUpperCase); +} + +shared_ptr +fromHex(const std::string& hexString) +{ + namespace tr = security::transform; + + OBufferStream os; + try { + tr::bufferSource(hexString) >> tr::hexDecode() >> tr::streamSink(os); + } + catch (const tr::Error& e) { + NDN_THROW_NESTED(StringHelperError("Conversion from hex failed: "s + e.what())); + } + + return os.buf(); +} + +std::string +escape(const std::string& str) +{ + std::ostringstream os; + escape(os, str.data(), str.size()); + return os.str(); +} + +void +escape(std::ostream& os, const char* str, size_t len) +{ + for (size_t i = 0; i < len; ++i) { + auto c = str[i]; + // Unreserved characters don't need to be escaped. + if ((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '-' || c == '.' || + c == '_' || c == '~') { + os << c; + } + else { + os << '%'; + os << toHexChar((c & 0xf0) >> 4); + os << toHexChar(c & 0xf); + } + } +} + +std::string +unescape(const std::string& str) +{ + std::ostringstream os; + unescape(os, str.data(), str.size()); + return os.str(); +} + +void +unescape(std::ostream& os, const char* str, size_t len) +{ + for (size_t i = 0; i < len; ++i) { + if (str[i] == '%' && i + 2 < len) { + int hi = fromHexChar(str[i + 1]); + int lo = fromHexChar(str[i + 2]); + + if (hi < 0 || lo < 0) + // Invalid hex characters, so just keep the escaped string. + os << str[i] << str[i + 1] << str[i + 2]; + else + os << static_cast((hi << 4) | lo); + + // Skip ahead past the escaped value. + i += 2; + } + else { + // Just copy through. + os << str[i]; + } + } +} + +} // namespace ndn diff --git a/ndn-cxx/util/string-helper.hpp b/ndn-cxx/util/string-helper.hpp new file mode 100644 index 000000000..97973daa8 --- /dev/null +++ b/ndn-cxx/util/string-helper.hpp @@ -0,0 +1,215 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_STRING_HELPER_HPP +#define NDN_UTIL_STRING_HELPER_HPP + +#include "ndn-cxx/detail/common.hpp" + +namespace ndn { + +class Buffer; + +class StringHelperError : public std::invalid_argument +{ +public: + using std::invalid_argument::invalid_argument; +}; + +/** + * @brief Helper class to convert a number to hexadecimal + * format, for use with stream insertion operators + * + * Example usage: + * + * @code + * std::cout << AsHex{42}; // outputs "0x2a" + * std::cout << std::uppercase << AsHex{42}; // outputs "0x2A" + * @endcode + */ +class AsHex +{ +public: + constexpr explicit + AsHex(uint64_t val) noexcept + : m_value(val) + { + } + +private: + uint64_t m_value; + + friend std::ostream& operator<<(std::ostream&, const AsHex&); +}; + +std::ostream& +operator<<(std::ostream& os, const AsHex& hex); + +/** + * @brief Output the hex representation of @p num to the output stream @p os + * + * @param os Output stream + * @param num Number to print in hexadecimal format + * @param wantUpperCase if true, print uppercase hex chars; the default is to use lowercase + * + * The output string is a continuous sequence of hex characters without any whitespace separators. + */ +void +printHex(std::ostream& os, uint64_t num, bool wantUpperCase = false); + +/** + * @brief Output the hex representation of the bytes in @p buffer to the output stream @p os + * + * @param os Output stream + * @param buffer Pointer to an array of bytes + * @param length Size of the array + * @param wantUpperCase if true (the default) print uppercase hex chars + * + * Examples: + * + * @code + * printHex(std::cout, "Hello, World!"); // outputs "48656C6C6F2C20776F726C6421" + * printHex(std::cout, "Hello, World!", false); // outputs "48656c6c6f2c20776f726c6421" + * @endcode + * + * Each octet is always represented as two hex characters ("00" for octet==0). + * + * The output string is a continuous sequence of hex characters without any whitespace separators. + */ +void +printHex(std::ostream& os, const uint8_t* buffer, size_t length, bool wantUpperCase = true); + +/** + * @brief Output the hex representation of the bytes in @p buffer to the output stream @p os + * + * @param os Output stream + * @param buffer Buffer of bytes to print in hexadecimal format + * @param wantUpperCase if true (the default) print uppercase hex chars + */ +void +printHex(std::ostream& os, const Buffer& buffer, bool wantUpperCase = true); + +/** + * @brief Return a string containing the hex representation of the bytes in @p buffer + * + * @param buffer Pointer to an array of bytes + * @param length Size of the array + * @param wantUpperCase if true (the default) use uppercase hex chars + * + * Examples: + * + * @code + * toHex("Hello, World!") == "48656C6C6F2C20776F726C6421" + * toHex("Hello, World!", false) == "48656c6c6f2c20776f726c6421" + * @endcode + * + * Each octet is always represented as two hex characters ("00" for octet==0). + * + * The output string is a continuous sequence of hex characters without any whitespace separators. + */ +NDN_CXX_NODISCARD std::string +toHex(const uint8_t* buffer, size_t length, bool wantUpperCase = true); + +/** + * @brief Return a string containing the hex representation of the bytes in @p buffer + * + * @param buffer Buffer of bytes to convert to hexadecimal format + * @param wantUpperCase if true (the default) use uppercase hex chars + */ +NDN_CXX_NODISCARD std::string +toHex(const Buffer& buffer, bool wantUpperCase = true); + +/** + * @brief Convert the hex string to buffer + * @param hexString sequence of pairs of hex numbers (lower and upper case can be mixed) + * without any whitespace separators (e.g., "48656C6C6F2C20776F726C6421") + * @throw StringHelperError if input is invalid + */ +shared_ptr +fromHex(const std::string& hexString); + +/** + * @brief Convert (the least significant nibble of) @p n to the corresponding hex character + */ +NDN_CXX_NODISCARD constexpr char +toHexChar(unsigned int n, bool wantUpperCase = true) noexcept +{ + return wantUpperCase ? + "0123456789ABCDEF"[n & 0xf] : + "0123456789abcdef"[n & 0xf]; +} + +/** + * @brief Convert the hex character @p c to an integer in [0, 15], or -1 if it's not a hex character + */ +NDN_CXX_NODISCARD constexpr int +fromHexChar(char c) noexcept +{ + return (c >= '0' && c <= '9') ? int(c - '0') : + (c >= 'A' && c <= 'F') ? int(c - 'A' + 10) : + (c >= 'a' && c <= 'f') ? int(c - 'a' + 10) : + -1; +} + +/** + * @brief Percent-encode a string + * @see RFC 3986 section 2 + * + * This function will encode all characters that are not one of the following: + * ALPHA ("a" to "z" and "A" to "Z") / DIGIT (0 to 9) / "-" / "." / "_" / "~" + * + * The hex encoding uses the numbers 0-9 and the uppercase letters A-F. + * + * Examples: + * + * @code + * escape("hello world") == "hello%20world" + * escape("100%") == "100%25" + * @endcode + */ +NDN_CXX_NODISCARD std::string +escape(const std::string& str); + +void +escape(std::ostream& os, const char* str, size_t len); + +/** + * @brief Decode a percent-encoded string + * @see RFC 3986 section 2 + * + * When % is not followed by two hex characters, the output is not transformed. + * + * Examples: + * + * @code + * unescape("hello%20world") == "hello world" + * unescape("hello%20world%FooBar") == "hello world%FooBar" + * @endcode + */ +NDN_CXX_NODISCARD std::string +unescape(const std::string& str); + +void +unescape(std::ostream& os, const char* str, size_t len); + +} // namespace ndn + +#endif // NDN_UTIL_STRING_HELPER_HPP diff --git a/src/util/time-custom-clock.hpp b/ndn-cxx/util/time-custom-clock.hpp similarity index 81% rename from src/util/time-custom-clock.hpp rename to ndn-cxx/util/time-custom-clock.hpp index 57579e545..935682f90 100644 --- a/src/util/time-custom-clock.hpp +++ b/ndn-cxx/util/time-custom-clock.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,10 +19,10 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#ifndef NDN_TIME_CUSTOM_CLOCK_HPP -#define NDN_TIME_CUSTOM_CLOCK_HPP +#ifndef NDN_UTIL_TIME_CUSTOM_CLOCK_HPP +#define NDN_UTIL_TIME_CUSTOM_CLOCK_HPP -#include "time.hpp" +#include "ndn-cxx/util/time.hpp" namespace ndn { namespace time { @@ -46,12 +46,12 @@ class CustomClock virtual std::string getSince() const = 0; - virtual boost::posix_time::time_duration - toPosixDuration(const typename BaseClock::duration& duration) const = 0; + virtual typename BaseClock::duration + toWaitDuration(typename BaseClock::duration d) const = 0; }; -typedef CustomClock CustomSystemClock; -typedef CustomClock CustomSteadyClock; +using CustomSystemClock = CustomClock; +using CustomSteadyClock = CustomClock; /** * \brief Set custom system and steady clocks @@ -66,4 +66,4 @@ setCustomClocks(shared_ptr steadyClock = nullptr, } // namespace time } // namespace ndn -#endif // NDN_TIME_CUSTOM_CLOCK_HPP +#endif // NDN_UTIL_TIME_CUSTOM_CLOCK_HPP diff --git a/ndn-cxx/util/time-unit-test-clock.cpp b/ndn-cxx/util/time-unit-test-clock.cpp new file mode 100644 index 000000000..dd08f9fc3 --- /dev/null +++ b/ndn-cxx/util/time-unit-test-clock.cpp @@ -0,0 +1,101 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/time-unit-test-clock.hpp" +#include "ndn-cxx/util/impl/steady-timer.hpp" + +#include +#include + +namespace ndn { +namespace time { + +template +UnitTestClock::UnitTestClock(nanoseconds startTime) + : m_currentTime(startTime) +{ +} + +template +std::string +UnitTestClock::getSince() const +{ + return " since unit test beginning"; +} + +template +typename BaseClock::time_point +UnitTestClock::getNow() const +{ + return typename BaseClock::time_point(duration_cast(m_currentTime)); +} + +template +typename BaseClock::duration +UnitTestClock::toWaitDuration(typename BaseClock::duration) const +{ + return typename BaseClock::duration(1); +} + +template +void +UnitTestClock::advance(nanoseconds duration) +{ + m_currentTime += duration; + + // When UnitTestClock is used with Asio timers (e.g. basic_waitable_timer), and + // an async wait operation on a timer is already in progress, Asio won't look + // at the clock again until the earliest timer has expired, so it won't know that + // the current time has changed. + // + // Therefore, in order for the clock advancement to be effective, we must sleep + // for a period greater than wait_traits::to_wait_duration(). + // + // See also http://blog.think-async.com/2007/08/time-travel.html - "Jumping Through Time" + // + std::this_thread::sleep_for(std::chrono::nanoseconds(duration_cast( + boost::asio::wait_traits::to_wait_duration(duration) + + typename BaseClock::duration(1)).count())); +} + +template +void +UnitTestClock::setNow(nanoseconds timeSinceEpoch) +{ + BOOST_ASSERT(!BaseClock::is_steady || timeSinceEpoch >= m_currentTime); + + m_currentTime = timeSinceEpoch; + + // See comment in advance() + auto delta = timeSinceEpoch - m_currentTime; + std::this_thread::sleep_for(std::chrono::nanoseconds(duration_cast( + boost::asio::wait_traits::to_wait_duration(delta) + + typename BaseClock::duration(1)).count())); +} + +template +class UnitTestClock; + +template +class UnitTestClock; + +} // namespace time +} // namespace ndn diff --git a/ndn-cxx/util/time-unit-test-clock.hpp b/ndn-cxx/util/time-unit-test-clock.hpp new file mode 100644 index 000000000..f6dd6ca1e --- /dev/null +++ b/ndn-cxx/util/time-unit-test-clock.hpp @@ -0,0 +1,114 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_TIME_UNIT_TEST_CLOCK_HPP +#define NDN_UTIL_TIME_UNIT_TEST_CLOCK_HPP + +#include "ndn-cxx/util/time-custom-clock.hpp" + +namespace ndn { +namespace time { + +/** + * @brief Traits for UnitTestClock, defining default behavior for different clocks + * + * The only behavior that is currently controlled by the traits is default start + * time. The generic implementation assumes start time to be zero. + */ +template +class UnitTestClockTraits +{ +public: + static nanoseconds + getDefaultStartTime() + { + return nanoseconds::zero(); + } +}; + +/** + * @brief Specialization of UnitTestClockTraits for system_clock + * + * This specialization sets the default start time to 1415684132 seconds + * (equivalent to Tue 11 Nov 2014 05:35:32 UTC, if Unix epoch is assumed). + */ +template<> +class UnitTestClockTraits +{ +public: + static nanoseconds + getDefaultStartTime() + { + return seconds(1415684132); + } +}; + +/** + * @brief Clock that can be used in unit tests for time-dependent tests independent of wall clock + * + * This clock should be explicitly advanced with UnitTestClock::advance() or set + * with UnitTestClock::setNow() methods. + * + * @note Default start time is determined by UnitTestClockTraits + */ +template> +class UnitTestClock : public CustomClock +{ +public: + explicit + UnitTestClock(nanoseconds startTime = ClockTraits::getDefaultStartTime()); + + /** + * @brief Advance unit test clock by @p duration + */ + void + advance(nanoseconds duration); + + /** + * @brief Explicitly set clock to @p timeSinceEpoch + */ + void + setNow(nanoseconds timeSinceEpoch); + +public: + std::string + getSince() const override; + + typename BaseClock::time_point + getNow() const override; + + typename BaseClock::duration + toWaitDuration(typename BaseClock::duration d) const override; + +private: + nanoseconds m_currentTime; +}; + +extern template class UnitTestClock; +extern template class UnitTestClock; + +using UnitTestSystemClock = UnitTestClock; +using UnitTestSteadyClock = UnitTestClock; + +} // namespace time +} // namespace ndn + +#endif // NDN_UTIL_TIME_UNIT_TEST_CLOCK_HPP diff --git a/ndn-cxx/util/time.cpp b/ndn-cxx/util/time.cpp new file mode 100644 index 000000000..170cb78f9 --- /dev/null +++ b/ndn-cxx/util/time.cpp @@ -0,0 +1,236 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/time.hpp" +#include "ndn-cxx/util/time-custom-clock.hpp" + +#include +#include + +namespace ndn { +namespace time { + +static shared_ptr g_systemClock; +static shared_ptr g_steadyClock; + +// this function is declared in time-custom-clock.hpp +void +setCustomClocks(shared_ptr steadyClock, + shared_ptr systemClock) +{ + g_systemClock = std::move(systemClock); + g_steadyClock = std::move(steadyClock); +} + +///////////////////////////////////////////////////////////////////////////////////////////// + +system_clock::time_point +system_clock::now() noexcept +{ + if (g_systemClock == nullptr) { + // optimized default version + return time_point(boost::chrono::system_clock::now().time_since_epoch()); + } + else { + return g_systemClock->getNow(); + } +} + +std::time_t +system_clock::to_time_t(const system_clock::time_point& t) noexcept +{ + return duration_cast(t.time_since_epoch()).count(); +} + +system_clock::time_point +system_clock::from_time_t(std::time_t t) noexcept +{ + return time_point(seconds(t)); +} + +///////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef __APPLE__ +// Note that on macOS platform boost::steady_clock is not truly monotonic, so we use +// system_clock instead. Refer to https://svn.boost.org/trac/boost/ticket/7719) +typedef boost::chrono::system_clock base_steady_clock; +#else +typedef boost::chrono::steady_clock base_steady_clock; +#endif + +steady_clock::time_point +steady_clock::now() noexcept +{ + if (g_steadyClock == nullptr) { + // optimized default version + return time_point(base_steady_clock::now().time_since_epoch()); + } + else { + return g_steadyClock->getNow(); + } +} + +steady_clock::duration +steady_clock::to_wait_duration(steady_clock::duration d) +{ + if (g_steadyClock == nullptr) { + // optimized default version + return d; + } + else { + return g_steadyClock->toWaitDuration(d); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// + +const system_clock::TimePoint& +getUnixEpoch() +{ + static constexpr system_clock::TimePoint epoch(seconds::zero()); + return epoch; +} + +milliseconds +toUnixTimestamp(const system_clock::TimePoint& point) +{ + return duration_cast(point - getUnixEpoch()); +} + +system_clock::TimePoint +fromUnixTimestamp(milliseconds duration) +{ + return getUnixEpoch() + duration; +} + +static boost::posix_time::ptime +convertToPosixTime(const system_clock::TimePoint& timePoint) +{ + namespace bpt = boost::posix_time; + static bpt::ptime epoch(boost::gregorian::date(1970, 1, 1)); + + using BptResolution = +#if defined(BOOST_DATE_TIME_HAS_NANOSECONDS) + nanoseconds; +#elif defined(BOOST_DATE_TIME_HAS_MICROSECONDS) + microseconds; +#else + milliseconds; +#endif + constexpr auto unitsPerHour = duration_cast(1_h).count(); + + auto sinceEpoch = duration_cast(timePoint - getUnixEpoch()).count(); + return epoch + bpt::time_duration(sinceEpoch / unitsPerHour, 0, 0, sinceEpoch % unitsPerHour); +} + +std::string +toIsoString(const system_clock::TimePoint& timePoint) +{ + return boost::posix_time::to_iso_string(convertToPosixTime(timePoint)); +} + +static system_clock::TimePoint +convertToTimePoint(const boost::posix_time::ptime& ptime) +{ + namespace bpt = boost::posix_time; + static bpt::ptime epoch(boost::gregorian::date(1970, 1, 1)); + + // .total_seconds() has an issue with large dates until Boost 1.66, see #4478. + // time_t overflows for large dates on 32-bit platforms (Y2038 problem). + auto sinceEpoch = ptime - epoch; + auto point = system_clock::TimePoint(seconds(sinceEpoch.ticks() / bpt::time_duration::ticks_per_second())); + return point + microseconds(sinceEpoch.total_microseconds() % 1000000); +} + +system_clock::TimePoint +fromIsoString(const std::string& isoString) +{ + return convertToTimePoint(boost::posix_time::from_iso_string(isoString)); +} + +std::string +toString(const system_clock::TimePoint& timePoint, + const std::string& format/* = "%Y-%m-%d %H:%M:%S"*/, + const std::locale& locale/* = std::locale("C")*/) +{ + namespace bpt = boost::posix_time; + + std::ostringstream os; + auto* facet = new bpt::time_facet(format.data()); + os.imbue(std::locale(locale, facet)); + os << convertToPosixTime(timePoint); + + return os.str(); +} + +system_clock::TimePoint +fromString(const std::string& timePointStr, + const std::string& format/* = "%Y-%m-%d %H:%M:%S"*/, + const std::locale& locale/* = std::locale("C")*/) +{ + namespace bpt = boost::posix_time; + + std::istringstream is(timePointStr); + auto* facet = new bpt::time_input_facet(format); + is.imbue(std::locale(locale, facet)); + bpt::ptime ptime; + is >> ptime; + + return convertToTimePoint(ptime); +} + +} // namespace time +} // namespace ndn + +namespace boost { +namespace chrono { + +template +std::basic_string +clock_string::since() +{ + if (ndn::time::g_systemClock == nullptr) { + // optimized default version + return clock_string::since(); + } + else { + return ndn::time::g_systemClock->getSince(); + } +} + +template +std::basic_string +clock_string::since() +{ + if (ndn::time::g_steadyClock == nullptr) { + // optimized default version + return clock_string::since(); + } + else { + return ndn::time::g_steadyClock->getSince(); + } +} + +template struct clock_string; +template struct clock_string; + +} // namespace chrono +} // namespace boost diff --git a/ndn-cxx/util/time.hpp b/ndn-cxx/util/time.hpp new file mode 100644 index 000000000..5656b2ad7 --- /dev/null +++ b/ndn-cxx/util/time.hpp @@ -0,0 +1,357 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_UTIL_TIME_HPP +#define NDN_UTIL_TIME_HPP + +#include "ndn-cxx/detail/common.hpp" + +#include +#include + +namespace ndn { +namespace time { + +using boost::chrono::duration; +using boost::chrono::duration_cast; + +using days = duration>; +using boost::chrono::hours; +using boost::chrono::minutes; +using boost::chrono::seconds; +using boost::chrono::milliseconds; +using boost::chrono::microseconds; +using boost::chrono::nanoseconds; + +/** \return the absolute value of the duration d + * \note The function does not participate in the overload resolution + * unless std::numeric_limits::is_signed is true. + */ +template::is_signed>> +constexpr duration +abs(duration d) +{ + return d >= d.zero() ? d : -d; +} + +} // namespace time + +inline namespace literals { +inline namespace time_literals { + +constexpr time::days +operator "" _day(unsigned long long days) +{ + return time::days{days}; +} + +constexpr time::duration +operator "" _day(long double days) +{ + return time::duration{days}; +} + +constexpr time::days +operator "" _days(unsigned long long days) +{ + return time::days{days}; +} + +constexpr time::duration +operator "" _days(long double days) +{ + return time::duration{days}; +} + +constexpr time::hours +operator "" _h(unsigned long long hrs) +{ + return time::hours{hrs}; +} + +constexpr time::duration +operator "" _h(long double hrs) +{ + return time::duration{hrs}; +} + +constexpr time::minutes +operator "" _min(unsigned long long mins) +{ + return time::minutes{mins}; +} + +constexpr time::duration +operator "" _min(long double mins) +{ + return time::duration{mins}; +} + +constexpr time::seconds +operator "" _s(unsigned long long secs) +{ + return time::seconds{secs}; +} + +constexpr time::duration +operator "" _s(long double secs) +{ + return time::duration{secs}; +} + +constexpr time::milliseconds +operator "" _ms(unsigned long long msecs) +{ + return time::milliseconds{msecs}; +} + +constexpr time::duration +operator "" _ms(long double msecs) +{ + return time::duration{msecs}; +} + +constexpr time::microseconds +operator "" _us(unsigned long long usecs) +{ + return time::microseconds{usecs}; +} + +constexpr time::duration +operator "" _us(long double usecs) +{ + return time::duration{usecs}; +} + +constexpr time::nanoseconds +operator "" _ns(unsigned long long nsecs) +{ + return time::nanoseconds{nsecs}; +} + +constexpr time::duration +operator "" _ns(long double nsecs) +{ + return time::duration{nsecs}; +} + +} // inline namespace time_literals +} // inline namespace literals + +namespace time { + +using namespace literals::time_literals; + +/** + * \brief System clock + * + * System clock represents the system-wide real time wall clock. + * + * It may not be monotonic: on most systems, the system time can be + * adjusted at any moment. It is the only clock that has the ability + * to be displayed and converted to/from UNIX timestamp. + * + * To get the current time: + * + * + * system_clock::TimePoint now = system_clock::now(); + * + * + * To convert a TimePoint to/from UNIX timestamp: + * + * + * system_clock::TimePoint time = ...; + * uint64_t timestampInMilliseconds = toUnixTimestamp(time).count(); + * system_clock::TimePoint time2 = fromUnixTimestamp(milliseconds(timestampInMilliseconds)); + * + */ +class system_clock +{ +public: + using duration = boost::chrono::system_clock::duration; + using rep = duration::rep; + using period = duration::period; + using time_point = boost::chrono::time_point; + static constexpr bool is_steady = boost::chrono::system_clock::is_steady; + + typedef time_point TimePoint; + typedef duration Duration; + + static time_point + now() noexcept; + + static std::time_t + to_time_t(const time_point& t) noexcept; + + static time_point + from_time_t(std::time_t t) noexcept; +}; + +/** + * \brief Steady clock + * + * Steady clock represents a monotonic clock. The time points of this + * clock cannot decrease as physical time moves forward. This clock is + * not related to wall clock time, and is best suitable for measuring + * intervals. + */ +class steady_clock +{ +public: + using duration = boost::chrono::steady_clock::duration; + using rep = duration::rep; + using period = duration::period; + using time_point = boost::chrono::time_point; + static constexpr bool is_steady = true; + + typedef time_point TimePoint; + typedef duration Duration; + + static time_point + now() noexcept; + +private: + /** + * \brief Trait function used in detail::SteadyTimer to select proper waiting time + * + * Mock time implementations should return the minimum value to ensure + * that Boost.Asio doesn't perform any waiting on mock timers. + * + * @sa http://blog.think-async.com/2007/08/time-travel.html + */ + static duration + to_wait_duration(duration d); + + friend struct boost::asio::wait_traits; // see steady-timer.hpp +}; + +/** + * \brief Get system_clock::TimePoint representing UNIX time epoch (00:00:00 on Jan 1, 1970) + */ +const system_clock::TimePoint& +getUnixEpoch(); + +/** + * \brief Convert system_clock::TimePoint to UNIX timestamp + */ +milliseconds +toUnixTimestamp(const system_clock::TimePoint& point); + +/** + * \brief Convert UNIX timestamp to system_clock::TimePoint + */ +system_clock::TimePoint +fromUnixTimestamp(milliseconds duration); + +/** + * \brief Convert to the ISO string representation of the time (YYYYMMDDTHHMMSS,fffffffff) + * + * If \p timePoint contains doesn't contain fractional seconds, + * the output format is YYYYMMDDTHHMMSS + * + * Examples: + * + * - with fractional nanoseconds: 20020131T100001,123456789 + * - with fractional microseconds: 20020131T100001,123456 + * - with fractional milliseconds: 20020131T100001,123 + * - without fractional seconds: 20020131T100001 + */ +std::string +toIsoString(const system_clock::TimePoint& timePoint); + +/** + * \brief Convert from the ISO string (YYYYMMDDTHHMMSS,fffffffff) representation + * to the internal time format + * + * Examples of accepted ISO strings: + * + * - with fractional nanoseconds: 20020131T100001,123456789 + * - with fractional microseconds: 20020131T100001,123456 + * - with fractional milliseconds: 20020131T100001,123 + * - without fractional seconds: 20020131T100001 + * + */ +system_clock::TimePoint +fromIsoString(const std::string& isoString); + +/** + * \brief Convert time point to string with specified format + * + * By default, `%Y-%m-%d %H:%M:%S` is used, producing dates like + * `2014-04-10 22:51:00` + * + * \param timePoint time point of system_clock + * \param format desired output format (default: `%Y-%m-%d %H:%M:%S`) + * \param locale desired locale (default: "C" locale) + * + * \sa https://www.boost.org/doc/libs/1_58_0/doc/html/date_time/date_time_io.html#date_time.format_flags + * describes possible formatting flags + **/ +std::string +toString(const system_clock::TimePoint& timePoint, + const std::string& format = "%Y-%m-%d %H:%M:%S", + const std::locale& locale = std::locale("C")); + +/** + * \brief Convert from string of specified format into time point + * + * By default, `%Y-%m-%d %H:%M:%S` is used, accepting dates like + * `2014-04-10 22:51:00` + * + * \param timePointStr string representing time point + * \param format input output format (default: `%Y-%m-%d %H:%M:%S`) + * \param locale input locale (default: "C" locale) + * + * \sa https://www.boost.org/doc/libs/1_58_0/doc/html/date_time/date_time_io.html#date_time.format_flags + * describes possible formatting flags + */ +system_clock::TimePoint +fromString(const std::string& timePointStr, + const std::string& format = "%Y-%m-%d %H:%M:%S", + const std::locale& locale = std::locale("C")); + +} // namespace time +} // namespace ndn + +namespace boost { +namespace chrono { + +template +struct clock_string +{ + static std::basic_string + since(); +}; + +template +struct clock_string +{ + static std::basic_string + since(); +}; + +extern template struct clock_string; +extern template struct clock_string; + +} // namespace chrono +} // namespace boost + +#endif // NDN_UTIL_TIME_HPP diff --git a/src/version.hpp.in b/ndn-cxx/version.hpp.in similarity index 97% rename from src/version.hpp.in rename to ndn-cxx/version.hpp.in index f7369f526..cbd5a6342 100644 --- a/src/version.hpp.in +++ b/ndn-cxx/version.hpp.in @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * diff --git a/src/common.hpp b/src/common.hpp deleted file mode 100644 index bc34cbd96..000000000 --- a/src/common.hpp +++ /dev/null @@ -1,130 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \brief import common constructs for ndn-cxx library internal use - * \warning This file is implementation detail of ndn-cxx library. - * Aliases imported in this file SHOULD NOT be used outside of ndn-cxx. - */ - -#ifndef NDN_COMMON_HPP -#define NDN_COMMON_HPP - -#include "ndn-cxx-config.hpp" - -// ndn-cxx specific macros declared in this and other headers must have NDN_CXX_ prefix -// to avoid conflicts with other projects that include ndn-cxx headers. -#ifdef NDN_CXX_HAVE_TESTS -#define NDN_CXX_VIRTUAL_WITH_TESTS virtual -#define NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED public -#define NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE public -#define NDN_CXX_PROTECTED_WITH_TESTS_ELSE_PRIVATE protected -#else -#define NDN_CXX_VIRTUAL_WITH_TESTS -#define NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED protected -#define NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE private -#define NDN_CXX_PROTECTED_WITH_TESTS_ELSE_PRIVATE private -#endif - -// require C++11 -#if __cplusplus < 201103L && !defined(__GXX_EXPERIMENTAL_CXX0X__) -# error "ndn-cxx applications must be compiled using the C++11 standard (-std=c++11)" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__GNUC__) || defined(__clang__) -# define DEPRECATED(func) func __attribute__ ((deprecated)) -#elif defined(_MSC_VER) -# define DEPRECATED(func) __declspec(deprecated) func -#else -# pragma message("DEPRECATED not implemented") -# define DEPRECATED(func) func -#endif - -namespace ndn { - -using std::shared_ptr; -using std::unique_ptr; -using std::weak_ptr; -using std::bad_weak_ptr; -using std::make_shared; -using std::enable_shared_from_this; - -using std::static_pointer_cast; -using std::dynamic_pointer_cast; -using std::const_pointer_cast; - -using std::function; -using std::bind; -using std::ref; -using std::cref; - -} // namespace ndn - -// Bug 2109 workaround -using namespace std::placeholders; -#define BOOST_BIND_NO_PLACEHOLDERS -#include -namespace boost { -#define NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(N) \ - template<> \ - struct is_placeholder::type> \ - { \ - enum _vt { \ - value = N \ - }; \ - }; -NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(1) -NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(2) -NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(3) -NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(4) -NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(5) -NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(6) -NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(7) -NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(8) -NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER(9) -#undef NDN_CXX_SPECIALIZE_BOOST_IS_PLACEHOLDER_FOR_STD_PLACEHOLDER -} // namespace boost - -#include -#include -#include -#include - -namespace ndn { -using boost::noncopyable; -} // namespace ndn - -#include "util/backports.hpp" - -#endif // NDN_COMMON_HPP diff --git a/src/data.cpp b/src/data.cpp deleted file mode 100644 index 8261449e5..000000000 --- a/src/data.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "data.hpp" -#include "encoding/block-helpers.hpp" -#include "util/crypto.hpp" - -namespace ndn { - -BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "Data::Error must inherit from tlv::Error"); - -Data::Data() - : m_content(tlv::Content) // empty content -{ -} - -Data::Data(const Name& name) - : m_name(name) -{ -} - -Data::Data(const Block& wire) -{ - wireDecode(wire); -} - -template -size_t -Data::wireEncode(EncodingImpl& encoder, bool unsignedPortion/* = false*/) const -{ - size_t totalLength = 0; - - // Data ::= DATA-TLV TLV-LENGTH - // Name - // MetaInfo - // Content - // Signature - - // (reverse encoding) - - if (!unsignedPortion && !m_signature) - { - BOOST_THROW_EXCEPTION(Error("Requested wire format, but data packet has not been signed yet")); - } - - if (!unsignedPortion) - { - // SignatureValue - totalLength += encoder.prependBlock(m_signature.getValue()); - } - - // SignatureInfo - totalLength += encoder.prependBlock(m_signature.getInfo()); - - // Content - totalLength += encoder.prependBlock(getContent()); - - // MetaInfo - totalLength += getMetaInfo().wireEncode(encoder); - - // Name - totalLength += getName().wireEncode(encoder); - - if (!unsignedPortion) - { - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::Data); - } - return totalLength; -} - - -template size_t -Data::wireEncode(EncodingImpl& encoder, - bool unsignedPortion) const; - -template size_t -Data::wireEncode(EncodingImpl& encoder, - bool unsignedPortion) const; - - -const Block& -Data::wireEncode(EncodingBuffer& encoder, const Block& signatureValue) const -{ - size_t totalLength = encoder.size(); - totalLength += encoder.appendBlock(signatureValue); - - encoder.prependVarNumber(totalLength); - encoder.prependVarNumber(tlv::Data); - - const_cast(this)->wireDecode(encoder.block()); - return m_wire; -} - -const Block& -Data::wireEncode() const -{ - if (m_wire.hasWire()) - return m_wire; - - EncodingEstimator estimator; - size_t estimatedSize = wireEncode(estimator); - - EncodingBuffer buffer(estimatedSize, 0); - wireEncode(buffer); - - const_cast(this)->wireDecode(buffer.block()); - return m_wire; -} - -void -Data::wireDecode(const Block& wire) -{ - m_fullName.clear(); - m_wire = wire; - m_wire.parse(); - - // Data ::= DATA-TLV TLV-LENGTH - // Name - // MetaInfo - // Content - // Signature - - // Name - m_name.wireDecode(m_wire.get(tlv::Name)); - - // MetaInfo - m_metaInfo.wireDecode(m_wire.get(tlv::MetaInfo)); - - // Content - m_content = m_wire.get(tlv::Content); - - /////////////// - // Signature // - /////////////// - - // SignatureInfo - m_signature.setInfo(m_wire.get(tlv::SignatureInfo)); - - // SignatureValue - Block::element_const_iterator val = m_wire.find(tlv::SignatureValue); - if (val != m_wire.elements_end()) - m_signature.setValue(*val); -} - -Data& -Data::setName(const Name& name) -{ - onChanged(); - m_name = name; - - return *this; -} - -const Name& -Data::getFullName() const -{ - if (m_fullName.empty()) { - if (!m_wire.hasWire()) { - BOOST_THROW_EXCEPTION(Error("Full name requested, but Data packet does not have wire format " - "(e.g., not signed)")); - } - m_fullName = m_name; - m_fullName.appendImplicitSha256Digest(crypto::computeSha256Digest(m_wire.wire(), m_wire.size())); - } - - return m_fullName; -} - -Data& -Data::setMetaInfo(const MetaInfo& metaInfo) -{ - onChanged(); - m_metaInfo = metaInfo; - - return *this; -} - -Data& -Data::setContentType(uint32_t type) -{ - onChanged(); - m_metaInfo.setType(type); - - return *this; -} - -Data& -Data::setFreshnessPeriod(const time::milliseconds& freshnessPeriod) -{ - onChanged(); - m_metaInfo.setFreshnessPeriod(freshnessPeriod); - - return *this; -} - -Data& -Data::setFinalBlockId(const name::Component& finalBlockId) -{ - onChanged(); - m_metaInfo.setFinalBlockId(finalBlockId); - - return *this; -} - -const Block& -Data::getContent() const -{ - if (m_content.empty()) - m_content = makeEmptyBlock(tlv::Content); - - if (!m_content.hasWire()) - m_content.encode(); - return m_content; -} - -Data& -Data::setContent(const uint8_t* content, size_t contentLength) -{ - onChanged(); - - m_content = makeBinaryBlock(tlv::Content, content, contentLength); - - return *this; -} - -Data& -Data::setContent(const ConstBufferPtr& contentValue) -{ - onChanged(); - - m_content = Block(tlv::Content, contentValue); // not a real wire encoding yet - - return *this; -} - -Data& -Data::setContent(const Block& content) -{ - onChanged(); - - if (content.type() == tlv::Content) - m_content = content; - else { - m_content = Block(tlv::Content, content); - } - - return *this; -} - -Data& -Data::setSignature(const Signature& signature) -{ - onChanged(); - m_signature = signature; - - return *this; -} - -Data& -Data::setSignatureValue(const Block& value) -{ - onChanged(); - m_signature.setValue(value); - - return *this; -} - -void -Data::onChanged() -{ - // The values have changed, so the wire format is invalidated - - // !!!Note!!! Signature is not invalidated and it is responsibility of - // the application to do proper re-signing if necessary - - m_wire.reset(); - m_fullName.clear(); -} - -bool -Data::operator==(const Data& other) const -{ - return getName() == other.getName() && - getMetaInfo() == other.getMetaInfo() && - getContent() == other.getContent() && - getSignature() == other.getSignature(); -} - -bool -Data::operator!=(const Data& other) const -{ - return !(*this == other); -} - -std::ostream& -operator<<(std::ostream& os, const Data& data) -{ - os << "Name: " << data.getName() << "\n"; - os << "MetaInfo: " << data.getMetaInfo() << "\n"; - os << "Content: (size: " << data.getContent().value_size() << ")\n"; - os << "Signature: (type: " << data.getSignature().getType() << - ", value_length: "<< data.getSignature().getValue().value_size() << ")"; - os << std::endl; - - return os; -} - -} // namespace ndn diff --git a/src/data.hpp b/src/data.hpp deleted file mode 100644 index b381c4ef4..000000000 --- a/src/data.hpp +++ /dev/null @@ -1,355 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_DATA_HPP -#define NDN_DATA_HPP - -#include "name.hpp" -#include "encoding/block.hpp" - -#include "signature.hpp" -#include "meta-info.hpp" -#include "key-locator.hpp" -#include "tag-host.hpp" - -namespace ndn { - -/** @brief represents a Data packet - */ -class Data : public TagHost, public enable_shared_from_this -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - - /** - * @brief Create an empty Data object - * - * Note that in certain contexts that use Data::shared_from_this(), Data must be - * created using `make_shared`: - * - * shared_ptr data = make_shared(); - * - * Otherwise, Data::shared_from_this() will throw an exception. - */ - Data(); - - /** - * @brief Create a new Data object with the given name - * - * @param name A reference to the name - * - * Note that in certain contexts that use Data::shared_from_this(), Data must be - * created using `make_shared`: - * - * shared_ptr data = make_shared(name); - * - * Otherwise, Data::shared_from_this() will throw an exception. - */ - Data(const Name& name); - - /** - * @brief Create a new Data object from wire encoding - * - * Note that in certain contexts that use Data::shared_from_this(), Data must be - * created using `make_shared`: - * - * shared_ptr data = make_shared(wire); - * - * Otherwise, Data::shared_from_this() will throw an exception. - */ - explicit - Data(const Block& wire); - - /** - * @brief Fast encoding or block size estimation - * - * @param encoder EncodingEstimator or EncodingBuffer instance - * @param wantUnsignedPortionOnly Request only unsigned portion to be encoded in block. - * If true, only Name, MetaInfo, Content, and SignatureInfo - * blocks will be encoded into the block. Note that there - * will be no outer TLV header of the Data packet. - */ - template - size_t - wireEncode(EncodingImpl& encoder, bool wantUnsignedPortionOnly = false) const; - - /** - * @brief Encode to a wire format - */ - const Block& - wireEncode() const; - - /** - * @brief Finalize Data packet encoding with the specified SignatureValue - * - * @param encoder EncodingBuffer instance, containing Name, MetaInfo, Content, and - * SignatureInfo (without outer TLV header of the Data packet). - * @param signatureValue SignatureValue block to be added to Data packet to finalize - * the wire encoding - * - * This method is intended to be used in concert with Data::wireEncode(EncodingBuffer&, true) - * method to optimize Data packet wire format creation: - * - * Data data; - * ... - * EncodingBuffer encoder; - * data.wireEncode(encoder, true); - * ... - * Block signatureValue = (encoder.buf(), encoder.size()); - * data.wireEncode(encoder, signatureValue) - */ - const Block& - wireEncode(EncodingBuffer& encoder, const Block& signatureValue) const; - - /** - * @brief Decode from the wire format - */ - void - wireDecode(const Block& wire); - - /** - * @brief Check if Data is already has wire encoding - */ - bool - hasWire() const; - - //////////////////////////////////////////////////////////////////// - - /** - * @brief Get name of the Data packet - */ - const Name& - getName() const; - - /** - * @brief Set name to a copy of the given Name - * - * @return This Data so that you can chain calls to update values - */ - Data& - setName(const Name& name); - - // - - /** - * @brief Get full name of Data packet, including the implicit digest - * - * @throws Error if Data packet doesn't have a full name yet (wire encoding has not been - * yet created) - */ - const Name& - getFullName() const; - - /** - * @brief Get MetaInfo block from Data packet - */ - const MetaInfo& - getMetaInfo() const; - - /** - * @brief Set metaInfo to a copy of the given MetaInfo - * - * @return This Data so that you can chain calls to update values. - */ - Data& - setMetaInfo(const MetaInfo& metaInfo); - - // - - /////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////// - // MetaInfo proxy methods - - uint32_t - getContentType() const; - - Data& - setContentType(uint32_t type); - - // - - const time::milliseconds& - getFreshnessPeriod() const; - - Data& - setFreshnessPeriod(const time::milliseconds& freshnessPeriod); - - // - - const name::Component& - getFinalBlockId() const; - - Data& - setFinalBlockId(const name::Component& finalBlockId); - - // - /////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////// - - /** - * @brief Get content Block - * - * To access content value, one can use value()/value_size() or - * value_begin()/value_end() methods of the Block class - */ - const Block& - getContent() const; - - /** - * @brief Set the content from the buffer (buffer will be copied) - * - * @param buffer Pointer to first byte of the buffer - * @param bufferSize Size of the buffer - * - * @return This Data so that you can chain calls to update values. - */ - Data& - setContent(const uint8_t* buffer, size_t bufferSize); - - /** - * @brief Set the content from the block - * - * Depending on type of the supplied block, there are two cases: - * - * - if block.type() == tlv::Content, then block will be used directly as Data packet's - * content (no extra copying) - * - * - if block.type() != tlv::Content, then this method will create a new Block with type - * tlv::Content and put block as a nested element in the content Block. - * - * @param block The Block containing the content to assign - * - * @return This Data so that you can chain calls to update values. - */ - Data& - setContent(const Block& block); - - /** - * @brief Set the content from the pointer to immutable buffer - * - * This method will create a Block with tlv::Content and set contentValue as a payload - * for this block. Note that this method is very different from setContent(const - * Block&), since it does not require that payload should be a valid TLV element. - * - * @param contentValue The pointer to immutable buffer containing the content to assign - * - * @return This Data so that you can chain calls to update values. - */ - Data& - setContent(const ConstBufferPtr& contentValue); - - // - - const Signature& - getSignature() const; - - /** - * @brief Set the signature to a copy of the given signature. - * @param signature The signature object which is cloned. - */ - Data& - setSignature(const Signature& signature); - - Data& - setSignatureValue(const Block& value); - -public: // EqualityComparable concept - bool - operator==(const Data& other) const; - - bool - operator!=(const Data& other) const; - -protected: - /** - * @brief Clear the wire encoding. - */ - void - onChanged(); - -private: - Name m_name; - MetaInfo m_metaInfo; - mutable Block m_content; - Signature m_signature; - - mutable Block m_wire; - mutable Name m_fullName; -}; - -std::ostream& -operator<<(std::ostream& os, const Data& data); - -inline bool -Data::hasWire() const -{ - return m_wire.hasWire(); -} - -inline const Name& -Data::getName() const -{ - return m_name; -} - -inline const MetaInfo& -Data::getMetaInfo() const -{ - return m_metaInfo; -} - -inline uint32_t -Data::getContentType() const -{ - return m_metaInfo.getType(); -} - -inline const time::milliseconds& -Data::getFreshnessPeriod() const -{ - return m_metaInfo.getFreshnessPeriod(); -} - -inline const name::Component& -Data::getFinalBlockId() const -{ - return m_metaInfo.getFinalBlockId(); -} - -inline const Signature& -Data::getSignature() const -{ - return m_signature; -} - -} // namespace ndn - -#endif diff --git a/src/detail/container-with-on-empty-signal.hpp b/src/detail/container-with-on-empty-signal.hpp deleted file mode 100644 index ef5f00412..000000000 --- a/src/detail/container-with-on-empty-signal.hpp +++ /dev/null @@ -1,108 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_DETAIL_CONTAINER_WITH_ON_EMPTY_SIGNAL_HPP -#define NDN_DETAIL_CONTAINER_WITH_ON_EMPTY_SIGNAL_HPP - -#include "../common.hpp" -#include "../util/signal.hpp" - -namespace ndn { - -/** - * @brief A container that emits onEmpty signal when it becomes empty - */ -template -class ContainerWithOnEmptySignal -{ -public: - typedef std::list Base; - typedef typename Base::value_type value_type; - typedef typename Base::iterator iterator; - - iterator - begin() - { - return m_container.begin(); - } - - iterator - end() - { - return m_container.end(); - } - - size_t - size() - { - return m_container.size(); - } - - bool - empty() - { - return m_container.empty(); - } - - iterator - erase(iterator item) - { - iterator next = m_container.erase(item); - if (empty()) { - this->onEmpty(); - } - return next; - } - - void - clear() - { - m_container.clear(); - this->onEmpty(); - } - - std::pair - insert(const value_type& value) - { - return {m_container.insert(end(), value), true}; - } - - template - void remove_if(Predicate p) - { - m_container.remove_if(p); - if (empty()) { - this->onEmpty(); - } - } - -public: - Base m_container; - - /** - * @brief Signal to be fired when container becomes empty - */ - util::Signal> onEmpty; -}; - -} // namespace ndn - -#endif // NDN_DETAIL_CONTAINER_WITH_ON_EMPTY_SIGNAL_HPP diff --git a/src/detail/face-impl.hpp b/src/detail/face-impl.hpp deleted file mode 100644 index 9ce4a69c1..000000000 --- a/src/detail/face-impl.hpp +++ /dev/null @@ -1,310 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_DETAIL_FACE_IMPL_HPP -#define NDN_DETAIL_FACE_IMPL_HPP - -#include "../common.hpp" -#include "../face.hpp" - -#include "registered-prefix.hpp" -#include "pending-interest.hpp" -#include "container-with-on-empty-signal.hpp" - -#include "../util/scheduler.hpp" -#include "../util/config-file.hpp" -#include "../util/signal.hpp" - -#include "../transport/transport.hpp" -#include "../transport/unix-transport.hpp" -#include "../transport/tcp-transport.hpp" - -#include "../mgmt/nfd/controller.hpp" -#include "../mgmt/nfd/command-options.hpp" - -#include "../lp/packet.hpp" -#include "../lp/tags.hpp" - -namespace ndn { - -/** - * @brief implementation detail of Face - */ -class Face::Impl : noncopyable -{ -public: - typedef ContainerWithOnEmptySignal> PendingInterestTable; - typedef std::list> InterestFilterTable; - typedef ContainerWithOnEmptySignal> RegisteredPrefixTable; - - explicit - Impl(Face& face) - : m_face(face) - , m_scheduler(m_face.getIoService()) - , m_processEventsTimeoutEvent(m_scheduler) - { - auto postOnEmptyPitOrNoRegisteredPrefixes = [this] { - this->m_face.getIoService().post([this] { this->onEmptyPitOrNoRegisteredPrefixes(); }); - // without this extra "post", transport can get paused (-async_read) and then resumed - // (+async_read) from within onInterest/onData callback. After onInterest/onData - // finishes, there is another +async_read with the same memory block. A few of such - // async_read duplications can cause various effects and result in segfault. - }; - - m_pendingInterestTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes); - m_registeredPrefixTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes); - } - -public: // consumer - void - asyncExpressInterest(shared_ptr interest, - const DataCallback& afterSatisfied, - const NackCallback& afterNacked, - const TimeoutCallback& afterTimeout) - { - this->ensureConnected(true); - - auto entry = m_pendingInterestTable.insert(make_shared( - interest, afterSatisfied, afterNacked, afterTimeout, ref(m_scheduler))).first; - (*entry)->setDeleter([this, entry] { m_pendingInterestTable.erase(entry); }); - - lp::Packet packet; - - shared_ptr nextHopFaceIdTag = interest->getTag(); - if (nextHopFaceIdTag != nullptr) { - packet.add(*nextHopFaceIdTag); - } - - shared_ptr congestionMarkTag = interest->getTag(); - if (congestionMarkTag != nullptr) { - packet.add(*congestionMarkTag); - } - - packet.add(std::make_pair(interest->wireEncode().begin(), - interest->wireEncode().end())); - - m_face.m_transport->send(packet.wireEncode()); - } - - void - asyncRemovePendingInterest(const PendingInterestId* pendingInterestId) - { - m_pendingInterestTable.remove_if(MatchPendingInterestId(pendingInterestId)); - } - - void - asyncRemoveAllPendingInterests() - { - m_pendingInterestTable.clear(); - } - - void - satisfyPendingInterests(const Data& data) - { - for (auto entry = m_pendingInterestTable.begin(); entry != m_pendingInterestTable.end(); ) { - if ((*entry)->getInterest()->matchesData(data)) { - shared_ptr matchedEntry = *entry; - entry = m_pendingInterestTable.erase(entry); - matchedEntry->invokeDataCallback(data); - } - else { - ++entry; - } - } - } - - void - nackPendingInterests(const lp::Nack& nack) - { - for (auto entry = m_pendingInterestTable.begin(); entry != m_pendingInterestTable.end(); ) { - const Interest& pendingInterest = *(*entry)->getInterest(); - if (pendingInterest == nack.getInterest()) { - shared_ptr matchedEntry = *entry; - entry = m_pendingInterestTable.erase(entry); - matchedEntry->invokeNackCallback(nack); - } - else { - ++entry; - } - } - } - -public: // producer - void - asyncSetInterestFilter(shared_ptr interestFilterRecord) - { - m_interestFilterTable.push_back(interestFilterRecord); - } - - void - asyncUnsetInterestFilter(const InterestFilterId* interestFilterId) - { - InterestFilterTable::iterator i = std::find_if(m_interestFilterTable.begin(), - m_interestFilterTable.end(), - MatchInterestFilterId(interestFilterId)); - if (i != m_interestFilterTable.end()) { - m_interestFilterTable.erase(i); - } - } - - void - processInterestFilters(Interest& interest) - { - for (const auto& filter : m_interestFilterTable) { - if (filter->doesMatch(interest.getName())) { - filter->invokeInterestCallback(interest); - } - } - } - - void - asyncSend(const Block& wire) - { - this->ensureConnected(true); - m_face.m_transport->send(wire); - } - -public: // prefix registration - const RegisteredPrefixId* - registerPrefix(const Name& prefix, - shared_ptr filter, - const RegisterPrefixSuccessCallback& onSuccess, - const RegisterPrefixFailureCallback& onFailure, - uint64_t flags, - const nfd::CommandOptions& options) - { - nfd::ControlParameters params; - params.setName(prefix); - params.setFlags(flags); - - auto prefixToRegister = make_shared(prefix, filter, options); - - m_face.m_nfdController->start( - params, - [=] (const nfd::ControlParameters&) { this->afterPrefixRegistered(prefixToRegister, onSuccess); }, - [=] (const nfd::ControlResponse& resp) { onFailure(prefixToRegister->getPrefix(), resp.getText()); }, - options); - - return reinterpret_cast(prefixToRegister.get()); - } - - void - afterPrefixRegistered(shared_ptr registeredPrefix, - const RegisterPrefixSuccessCallback& onSuccess) - { - m_registeredPrefixTable.insert(registeredPrefix); - - if (registeredPrefix->getFilter() != nullptr) { - // it was a combined operation - m_interestFilterTable.push_back(registeredPrefix->getFilter()); - } - - if (onSuccess != nullptr) { - onSuccess(registeredPrefix->getPrefix()); - } - } - - void - asyncUnregisterPrefix(const RegisteredPrefixId* registeredPrefixId, - const UnregisterPrefixSuccessCallback& onSuccess, - const UnregisterPrefixFailureCallback& onFailure) - { - auto i = std::find_if(m_registeredPrefixTable.begin(), - m_registeredPrefixTable.end(), - MatchRegisteredPrefixId(registeredPrefixId)); - if (i != m_registeredPrefixTable.end()) { - RegisteredPrefix& record = **i; - const shared_ptr& filter = record.getFilter(); - - if (filter != nullptr) { - // it was a combined operation - m_interestFilterTable.remove(filter); - } - - nfd::ControlParameters params; - params.setName(record.getPrefix()); - m_face.m_nfdController->start( - params, - [=] (const nfd::ControlParameters&) { this->finalizeUnregisterPrefix(i, onSuccess); }, - [=] (const nfd::ControlResponse& resp) { onFailure(resp.getText()); }, - record.getCommandOptions()); - } - else { - if (onFailure != nullptr) { - onFailure("Unrecognized PrefixId"); - } - } - - // there cannot be two registered prefixes with the same id - } - - void - finalizeUnregisterPrefix(RegisteredPrefixTable::iterator item, - const UnregisterPrefixSuccessCallback& onSuccess) - { - m_registeredPrefixTable.erase(item); - - if (onSuccess != nullptr) { - onSuccess(); - } - } - -public: // IO routine - void - ensureConnected(bool wantResume) - { - if (!m_face.m_transport->isConnected()) - m_face.m_transport->connect(m_face.m_ioService, - [=] (const Block& wire) { m_face.onReceiveElement(wire); }); - - if (wantResume && !m_face.m_transport->isReceiving()) { - m_face.m_transport->resume(); - } - } - - void - onEmptyPitOrNoRegisteredPrefixes() - { - if (m_pendingInterestTable.empty() && m_registeredPrefixTable.empty()) { - m_face.m_transport->pause(); - if (!m_ioServiceWork) { - m_processEventsTimeoutEvent.cancel(); - } - } - } - -private: - Face& m_face; - util::Scheduler m_scheduler; - util::scheduler::ScopedEventId m_processEventsTimeoutEvent; - - PendingInterestTable m_pendingInterestTable; - InterestFilterTable m_interestFilterTable; - RegisteredPrefixTable m_registeredPrefixTable; - - unique_ptr m_ioServiceWork; // if thread needs to be preserved - - friend class Face; -}; - -} // namespace ndn - -#endif // NDN_DETAIL_FACE_IMPL_HPP diff --git a/src/detail/interest-filter-record.hpp b/src/detail/interest-filter-record.hpp deleted file mode 100644 index f771d16d3..000000000 --- a/src/detail/interest-filter-record.hpp +++ /dev/null @@ -1,114 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_DETAIL_INTEREST_FILTER_RECORD_HPP -#define NDN_DETAIL_INTEREST_FILTER_RECORD_HPP - -#include "../name.hpp" -#include "../interest.hpp" - -namespace ndn { - -/** - * @brief associates an InterestFilter with Interest callback - */ -class InterestFilterRecord : noncopyable -{ -public: - /** - * @brief Construct an Interest filter record - * - * @param filter an InterestFilter that represents what Interest should invoke the callback - * @param interestCallback invoked when matching Interest is received - */ - InterestFilterRecord(const InterestFilter& filter, - const InterestCallback& interestCallback) - : m_filter(filter) - , m_interestCallback(interestCallback) - { - } - - /** - * @return the filter - */ - const InterestFilter& - getFilter() const - { - return m_filter; - } - - /** - * @brief Check if Interest name matches the filter - * @param name Interest Name - */ - bool - doesMatch(const Name& name) const - { - return m_filter.doesMatch(name); - } - - /** - * @brief invokes the InterestCallback - * @note This method does nothing if the Interest callback is empty - */ - void - invokeInterestCallback(const Interest& interest) const - { - if (m_interestCallback != nullptr) { - m_interestCallback(m_filter, interest); - } - } - -private: - InterestFilter m_filter; - InterestCallback m_interestCallback; -}; - -/** - * @brief Opaque type to identify an InterestFilterRecord - */ -class InterestFilterId; - -/** - * @brief Functor to match InterestFilterId - */ -class MatchInterestFilterId -{ -public: - explicit - MatchInterestFilterId(const InterestFilterId* interestFilterId) - : m_id(interestFilterId) - { - } - - bool - operator()(const shared_ptr& interestFilterId) const - { - return reinterpret_cast(interestFilterId.get()) == m_id; - } - -private: - const InterestFilterId* m_id; -}; - -} // namespace ndn - -#endif // NDN_DETAIL_INTEREST_FILTER_RECORD_HPP diff --git a/src/detail/pending-interest.hpp b/src/detail/pending-interest.hpp deleted file mode 100644 index 735db8051..000000000 --- a/src/detail/pending-interest.hpp +++ /dev/null @@ -1,163 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_DETAIL_PENDING_INTEREST_HPP -#define NDN_DETAIL_PENDING_INTEREST_HPP - -#include "../interest.hpp" -#include "../data.hpp" -#include "../lp/nack.hpp" -#include "../util/scheduler-scoped-event-id.hpp" - -namespace ndn { - -/** - * @brief stores a pending Interest and associated callbacks - */ -class PendingInterest : noncopyable -{ -public: - /** - * @brief Construct a pending Interest record - * - * The timeout is set based on the current time and the Interest lifetime. - * This class will invoke the timeout callback unless the record is deleted before timeout. - * - * @param interest the Interest - * @param dataCallback invoked when matching Data packet is received - * @param nackCallback invoked when Nack matching Interest is received - * @param timeoutCallback invoked when Interest times out - * @param scheduler Scheduler for scheduling the timeout event - */ - PendingInterest(shared_ptr interest, - const DataCallback& dataCallback, - const NackCallback& nackCallback, - const TimeoutCallback& timeoutCallback, - Scheduler& scheduler) - : m_interest(interest) - , m_dataCallback(dataCallback) - , m_nackCallback(nackCallback) - , m_timeoutCallback(timeoutCallback) - , m_timeoutEvent(scheduler) - { - m_timeoutEvent = - scheduler.scheduleEvent(m_interest->getInterestLifetime() > time::milliseconds::zero() ? - m_interest->getInterestLifetime() : - DEFAULT_INTEREST_LIFETIME, - [=] { this->invokeTimeoutCallback(); }); - } - - /** - * @return the Interest - */ - shared_ptr - getInterest() const - { - return m_interest; - } - - /** - * @brief invokes the Data callback - * @note This method does nothing if the Data callback is empty - */ - void - invokeDataCallback(const Data& data) - { - if (m_dataCallback != nullptr) { - m_dataCallback(*m_interest, data); - } - } - - /** - * @brief invokes the Nack callback - * @note This method does nothing if the Nack callback is empty - */ - void - invokeNackCallback(const lp::Nack& nack) - { - if (m_nackCallback != nullptr) { - m_nackCallback(*m_interest, nack); - } - } - - /** - * @brief Set cleanup function to be invoked when Interest times out - */ - void - setDeleter(const std::function& deleter) - { - m_deleter = deleter; - } - -private: - /** - * @brief invokes the timeout callback (if non-empty) and the deleter - */ - void - invokeTimeoutCallback() - { - if (m_timeoutCallback) { - m_timeoutCallback(*m_interest); - } - - BOOST_ASSERT(m_deleter); - m_deleter(); - } - -private: - shared_ptr m_interest; - DataCallback m_dataCallback; - NackCallback m_nackCallback; - TimeoutCallback m_timeoutCallback; - util::scheduler::ScopedEventId m_timeoutEvent; - std::function m_deleter; -}; - -/** - * @brief Opaque type to identify a PendingInterest - */ -class PendingInterestId; - -/** - * @brief Functor to match PendingInterestId - */ -class MatchPendingInterestId -{ -public: - explicit - MatchPendingInterestId(const PendingInterestId* pendingInterestId) - : m_id(pendingInterestId) - { - } - - bool - operator()(const shared_ptr& pendingInterest) const - { - return reinterpret_cast(pendingInterest->getInterest().get()) == m_id; - } - -private: - const PendingInterestId* m_id; -}; - -} // namespace ndn - -#endif // NDN_DETAIL_PENDING_INTEREST_HPP diff --git a/src/detail/registered-prefix.hpp b/src/detail/registered-prefix.hpp deleted file mode 100644 index 5b08167d0..000000000 --- a/src/detail/registered-prefix.hpp +++ /dev/null @@ -1,103 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_DETAIL_REGISTERED_PREFIX_HPP -#define NDN_DETAIL_REGISTERED_PREFIX_HPP - -#include "../common.hpp" -#include "../name.hpp" -#include "../interest.hpp" - -#include "interest-filter-record.hpp" -#include "mgmt/nfd/command-options.hpp" -#include "mgmt/nfd/control-parameters.hpp" - -namespace ndn { - -/** - * @brief stores information about a prefix registered in NDN forwarder - */ -class RegisteredPrefix : noncopyable -{ -public: - RegisteredPrefix(const Name& prefix, - shared_ptr filter, - const nfd::CommandOptions& options) - : m_prefix(prefix) - , m_filter(filter) - , m_options(options) - { - } - - const Name& - getPrefix() const - { - return m_prefix; - } - - const shared_ptr& - getFilter() const - { - return m_filter; - } - - const nfd::CommandOptions& - getCommandOptions() const - { - return m_options; - } - -private: - Name m_prefix; - shared_ptr m_filter; - nfd::CommandOptions m_options; -}; - -/** - * @brief Opaque type to identify a RegisteredPrefix - */ -class RegisteredPrefixId; - -/** - * @brief Functor to match RegisteredPrefixId - */ -class MatchRegisteredPrefixId -{ -public: - explicit - MatchRegisteredPrefixId(const RegisteredPrefixId* registeredPrefixId) - : m_id(registeredPrefixId) - { - } - - bool - operator()(const shared_ptr& registeredPrefix) const - { - return reinterpret_cast(registeredPrefix.get()) == m_id; - } - -private: - const RegisteredPrefixId* m_id; -}; - -} // namespace ndn - -#endif // NDN_DETAIL_REGISTERED_PREFIX_HPP diff --git a/src/encoding/block-helpers.cpp b/src/encoding/block-helpers.cpp deleted file mode 100644 index 594fc5cfb..000000000 --- a/src/encoding/block-helpers.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "block-helpers.hpp" - -namespace ndn { -namespace encoding { - -template -size_t -prependNonNegativeIntegerBlock(EncodingImpl& encoder, uint32_t type, uint64_t value) -{ - size_t valueLength = encoder.prependNonNegativeInteger(value); - size_t totalLength = valueLength; - totalLength += encoder.prependVarNumber(valueLength); - totalLength += encoder.prependVarNumber(type); - - return totalLength; -} - -template size_t -prependNonNegativeIntegerBlock(EncodingImpl& encoder, - uint32_t type, uint64_t value); - -template size_t -prependNonNegativeIntegerBlock(EncodingImpl& encoder, - uint32_t type, uint64_t value); - - -Block -makeNonNegativeIntegerBlock(uint32_t type, uint64_t value) -{ - EncodingEstimator estimator; - size_t totalLength = prependNonNegativeIntegerBlock(estimator, type, value); - - EncodingBuffer encoder(totalLength, 0); - prependNonNegativeIntegerBlock(encoder, type, value); - - return encoder.block(); -} - -uint64_t -readNonNegativeInteger(const Block& block) -{ - Buffer::const_iterator begin = block.value_begin(); - return tlv::readNonNegativeInteger(block.value_size(), begin, block.value_end()); -} - -//////// - -template -size_t -prependEmptyBlock(EncodingImpl& encoder, uint32_t type) -{ - size_t totalLength = encoder.prependVarNumber(0); - totalLength += encoder.prependVarNumber(type); - - return totalLength; -} - -template size_t -prependEmptyBlock(EncodingImpl& encoder, uint32_t type); - -template size_t -prependEmptyBlock(EncodingImpl& encoder, uint32_t type); - - -Block -makeEmptyBlock(uint32_t type) -{ - EncodingEstimator estimator; - size_t totalLength = prependEmptyBlock(estimator, type); - - EncodingBuffer encoder(totalLength, 0); - prependEmptyBlock(encoder, type); - - return encoder.block(); -} - -//////// - -template -size_t -prependStringBlock(EncodingImpl& encoder, uint32_t type, const std::string& value) -{ - size_t valueLength = encoder.prependByteArray(reinterpret_cast(value.data()), - value.size()); - size_t totalLength = valueLength; - totalLength += encoder.prependVarNumber(valueLength); - totalLength += encoder.prependVarNumber(type); - - return totalLength; -} - -template size_t -prependStringBlock(EncodingImpl& encoder, - uint32_t type, const std::string& value); - -template size_t -prependStringBlock(EncodingImpl& encoder, - uint32_t type, const std::string& value); - - -Block -makeStringBlock(uint32_t type, const std::string& value) -{ - EncodingEstimator estimator; - size_t totalLength = prependStringBlock(estimator, type, value); - - EncodingBuffer encoder(totalLength, 0); - prependStringBlock(encoder, type, value); - - return encoder.block(); -} - -std::string -readString(const Block& block) -{ - return std::string(reinterpret_cast(block.value()), block.value_size()); -} - -//////// - -Block -makeBinaryBlock(uint32_t type, const uint8_t* value, size_t length) -{ - EncodingEstimator estimator; - size_t totalLength = estimator.prependByteArrayBlock(type, value, length); - - EncodingBuffer encoder(totalLength, 0); - encoder.prependByteArrayBlock(type, value, length); - - return encoder.block(); -} - -Block -makeBinaryBlock(uint32_t type, const char* value, size_t length) -{ - return makeBinaryBlock(type, reinterpret_cast(value), length); -} - -} // namespace encoding -} // namespace ndn diff --git a/src/encoding/block-helpers.hpp b/src/encoding/block-helpers.hpp deleted file mode 100644 index d207938cc..000000000 --- a/src/encoding/block-helpers.hpp +++ /dev/null @@ -1,235 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_ENCODING_BLOCK_HELPERS_HPP -#define NDN_ENCODING_BLOCK_HELPERS_HPP - -#include "block.hpp" -#include "encoding-buffer.hpp" -#include "../util/concepts.hpp" - -#include - -namespace ndn { -namespace encoding { - -/** - * @brief Helper to prepend TLV block type @p type containing non-negative integer @p value - * @see makeNonNegativeIntegerBlock, readNonNegativeInteger - */ -template -size_t -prependNonNegativeIntegerBlock(EncodingImpl& encoder, uint32_t type, uint64_t value); - -/** - * @brief Create a TLV block type @p type containing non-negative integer @p value - * @see prependNonNegativeIntegerBlock, readNonNegativeInteger - */ -Block -makeNonNegativeIntegerBlock(uint32_t type, uint64_t value); - -/** - * @brief Helper to read a non-negative integer from a block - * @see prependNonNegativeIntegerBlock, makeNonNegativeIntegerBlock - * @throw tlv::Error if block does not contain a valid nonNegativeInteger - */ -uint64_t -readNonNegativeInteger(const Block& block); - -//////// - -/** - * @brief Helper to prepend TLV block type @p type containing no value (i.e., a boolean block) - * @see makeEmptyBlock - */ -template -size_t -prependEmptyBlock(EncodingImpl& encoder, uint32_t type); - -/** - * @brief Create a TLV block type @p type containing no value (i.e., a boolean block) - * @see prependEmptyBlock - */ -Block -makeEmptyBlock(uint32_t type); - -//////// - -/** - * @brief Helper to prepend TLV block type @p type with value from a string @p value - * @see makeStringBlock, readString - */ -template -size_t -prependStringBlock(EncodingImpl& encoder, uint32_t type, const std::string& value); - -/** - * @brief Create a TLV block type @p type with value from a string @p value - * @see prependStringBlock, readString - */ -Block -makeStringBlock(uint32_t type, const std::string& value); - -/** - * @brief Helper to read a string value from a block - * @see prependStringBlock, makeStringBlock - */ -std::string -readString(const Block& block); - -//////// - -/** - * @brief Create a TLV block type @p type with value from a buffer @p value of size @p length - */ -Block -makeBinaryBlock(uint32_t type, const uint8_t* value, size_t length); - -/** - * @brief Create a TLV block type @p type with value from a buffer @p value of size @p length - */ -Block -makeBinaryBlock(uint32_t type, const char* value, size_t length); - -/** - * @brief Helper class template to create a data block when RandomAccessIterator is used - */ -template -class DataBlockFast -{ -public: - BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator)); - - static Block - makeBlock(uint32_t type, Iterator first, Iterator last) - { - EncodingEstimator estimator; - size_t valueLength = last - first; - size_t totalLength = valueLength; - totalLength += estimator.prependVarNumber(valueLength); - totalLength += estimator.prependVarNumber(type); - - EncodingBuffer encoder(totalLength, 0); - encoder.prependRange(first, last); - encoder.prependVarNumber(valueLength); - encoder.prependVarNumber(type); - - return encoder.block(); - } -}; - -/** - * @brief Helper class template to create a data block when generic InputIterator is used - */ -template -class DataBlockSlow -{ -public: - BOOST_CONCEPT_ASSERT((boost::InputIterator)); - - static Block - makeBlock(uint32_t type, Iterator first, Iterator last) - { - // reserve 4 bytes in front (common for 1(type)-3(length) encoding - // Actual size will be adjusted as necessary by the encoder - EncodingBuffer encoder(4, 4); - size_t valueLength = encoder.appendRange(first, last); - encoder.prependVarNumber(valueLength); - encoder.prependVarNumber(type); - - return encoder.block(); - } -}; - -/** - * @brief Free function to create a block given @p type and range [@p first, @p last) of bytes - * @tparam Iterator iterator type satisfying at least InputIterator concept. Implementation - * is more optimal when the iterator type satisfies RandomAccessIterator concept - * It is required that sizeof(std::iterator_traits::value_type) == 1. - */ -template -inline Block -makeBinaryBlock(uint32_t type, Iterator first, Iterator last) -{ - static_assert(sizeof(typename std::iterator_traits::value_type) == 1, - "Iterator should point only to char or unsigned char"); - - typedef typename boost::mpl::if_< - std::is_base_of::iterator_category>, - DataBlockFast, - DataBlockSlow>::type DataBlock; - - return DataBlock::makeBlock(type, first, last); -} - -//////// - -/** - * @brief Prepend a TLV block of type @p type with WireEncodable @p value as a value - * @tparam U type that satisfies WireEncodableWithEncodingBuffer concept - * @see makeNestedBlock - */ -template -inline size_t -prependNestedBlock(EncodingImpl& encoder, uint32_t type, const U& value) -{ - BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); - - size_t valueLength = value.wireEncode(encoder); - size_t totalLength = valueLength; - totalLength += encoder.prependVarNumber(valueLength); - totalLength += encoder.prependVarNumber(type); - - return totalLength; -} - -/** - * @brief Create a TLV block of type @p type with WireEncodable @p value as a value - * @tparam U type that satisfies WireEncodableWithEncodingBuffer concept - * @see prependNestedBlock - */ -template -inline Block -makeNestedBlock(uint32_t type, const U& value) -{ - EncodingEstimator estimator; - size_t totalLength = prependNestedBlock(estimator, type, value); - - EncodingBuffer encoder(totalLength, 0); - prependNestedBlock(encoder, type, value); - - return encoder.block(); -} - -} // namespace encoding - -using encoding::makeNonNegativeIntegerBlock; -using encoding::readNonNegativeInteger; -using encoding::makeEmptyBlock; -using encoding::makeStringBlock; -using encoding::readString; -using encoding::makeBinaryBlock; -using encoding::makeNestedBlock; - -} // namespace ndn - -#endif // NDN_ENCODING_BLOCK_HELPERS_HPP diff --git a/src/encoding/block.cpp b/src/encoding/block.cpp deleted file mode 100644 index 16c05c5fc..000000000 --- a/src/encoding/block.cpp +++ /dev/null @@ -1,619 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Alexander Afanasyev - */ - -#include "block.hpp" -#include "block-helpers.hpp" - -#include "tlv.hpp" -#include "encoding-buffer.hpp" -#include "buffer-stream.hpp" - -#include -#include - -namespace ndn { - -#if NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE -static_assert(std::is_nothrow_move_constructible::value, - "Block must be MoveConstructible with noexcept"); -#endif // NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE - -#if NDN_CXX_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE -static_assert(std::is_nothrow_move_assignable::value, - "Block must be MoveAssignable with noexcept"); -#endif // NDN_CXX_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE - -const size_t MAX_SIZE_OF_BLOCK_FROM_STREAM = MAX_NDN_PACKET_SIZE; - -Block::Block() - : m_type(std::numeric_limits::max()) -{ -} - -Block::Block(const EncodingBuffer& buffer) - : m_buffer(const_cast(buffer).getBuffer()) - , m_begin(buffer.begin()) - , m_end(buffer.end()) - , m_size(m_end - m_begin) -{ - m_value_begin = m_begin; - m_value_end = m_end; - - m_type = tlv::readType(m_value_begin, m_value_end); - uint64_t length = tlv::readVarNumber(m_value_begin, m_value_end); - if (length != static_cast(m_value_end - m_value_begin)) - { - BOOST_THROW_EXCEPTION(tlv::Error("TLV length doesn't match buffer length")); - } -} - -Block::Block(const ConstBufferPtr& wire, - uint32_t type, - const Buffer::const_iterator& begin, const Buffer::const_iterator& end, - const Buffer::const_iterator& valueBegin, const Buffer::const_iterator& valueEnd) - : m_buffer(wire) - , m_type(type) - , m_begin(begin) - , m_end(end) - , m_size(m_end - m_begin) - , m_value_begin(valueBegin) - , m_value_end(valueEnd) -{ -} - -Block::Block(const ConstBufferPtr& buffer) - : m_buffer(buffer) - , m_begin(m_buffer->begin()) - , m_end(m_buffer->end()) - , m_size(m_end - m_begin) -{ - m_value_begin = m_begin; - m_value_end = m_end; - - m_type = tlv::readType(m_value_begin, m_value_end); - - uint64_t length = tlv::readVarNumber(m_value_begin, m_value_end); - if (length != static_cast(m_value_end - m_value_begin)) - { - BOOST_THROW_EXCEPTION(tlv::Error("TLV length doesn't match buffer length")); - } -} - -Block::Block(const ConstBufferPtr& buffer, - const Buffer::const_iterator& begin, const Buffer::const_iterator& end, - bool verifyLength/* = true*/) - : m_buffer(buffer) - , m_begin(begin) - , m_end(end) - , m_size(m_end - m_begin) -{ - m_value_begin = m_begin; - m_value_end = m_end; - - m_type = tlv::readType(m_value_begin, m_value_end); - uint64_t length = tlv::readVarNumber(m_value_begin, m_value_end); - if (verifyLength) { - if (length != static_cast(std::distance(m_value_begin, m_value_end))) { - BOOST_THROW_EXCEPTION(tlv::Error("TLV length doesn't match buffer length")); - } - } -} - -Block::Block(const Block& block, - const Buffer::const_iterator& begin, const Buffer::const_iterator& end, - bool verifyLength/* = true*/) - : m_buffer(block.m_buffer) - , m_begin(begin) - , m_end(end) - , m_size(m_end - m_begin) -{ - if (!(m_buffer->begin() <= begin && begin <= m_buffer->end()) || - !(m_buffer->begin() <= end && end <= m_buffer->end())) { - BOOST_THROW_EXCEPTION(Error("begin/end iterators do not point to the underlying buffer of the block")); - } - - m_value_begin = m_begin; - m_value_end = m_end; - - m_type = tlv::readType(m_value_begin, m_value_end); - uint64_t length = tlv::readVarNumber(m_value_begin, m_value_end); - if (verifyLength) { - if (length != static_cast(std::distance(m_value_begin, m_value_end))) { - BOOST_THROW_EXCEPTION(tlv::Error("TLV length doesn't match buffer length")); - } - } -} - -Block::Block(const uint8_t* buffer, size_t maxlength) -{ - const uint8_t* tmp_begin = buffer; - const uint8_t* tmp_end = buffer + maxlength; - - m_type = tlv::readType(tmp_begin, tmp_end); - uint64_t length = tlv::readVarNumber(tmp_begin, tmp_end); - - if (length > static_cast(tmp_end - tmp_begin)) - { - BOOST_THROW_EXCEPTION(tlv::Error("Not enough data in the buffer to fully parse TLV")); - } - - m_buffer = make_shared(buffer, (tmp_begin - buffer) + length); - - m_begin = m_buffer->begin(); - m_end = m_buffer->end(); - m_size = m_end - m_begin; - - m_value_begin = m_buffer->begin() + (tmp_begin - buffer); - m_value_end = m_buffer->end(); -} - -Block::Block(const void* bufferX, size_t maxlength) -{ - const uint8_t* buffer = reinterpret_cast(bufferX); - - const uint8_t* tmp_begin = buffer; - const uint8_t* tmp_end = buffer + maxlength; - - m_type = tlv::readType(tmp_begin, tmp_end); - uint64_t length = tlv::readVarNumber(tmp_begin, tmp_end); - - if (length > static_cast(tmp_end - tmp_begin)) - { - BOOST_THROW_EXCEPTION(tlv::Error("Not enough data in the buffer to fully parse TLV")); - } - - m_buffer = make_shared(buffer, (tmp_begin - buffer) + length); - - m_begin = m_buffer->begin(); - m_end = m_buffer->end(); - m_size = m_end - m_begin; - - m_value_begin = m_buffer->begin() + (tmp_begin - buffer); - m_value_end = m_buffer->end(); -} - -Block::Block(uint32_t type) - : m_type(type) -{ -} - -Block::Block(uint32_t type, const ConstBufferPtr& value) - : m_buffer(value) - , m_type(type) - , m_begin(m_buffer->end()) - , m_end(m_buffer->end()) - , m_value_begin(m_buffer->begin()) - , m_value_end(m_buffer->end()) -{ - m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size(); -} - -Block::Block(uint32_t type, const Block& value) - : m_buffer(value.m_buffer) - , m_type(type) - , m_begin(m_buffer->end()) - , m_end(m_buffer->end()) - , m_value_begin(value.begin()) - , m_value_end(value.end()) -{ - m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size(); -} - -Block -Block::fromStream(std::istream& is) -{ - std::istream_iterator begin(is >> std::noskipws); - std::istream_iterator end; - - uint32_t type = tlv::readType(begin, end); - uint64_t length = tlv::readVarNumber(begin, end); - - if (length == 0) { - return makeEmptyBlock(type); - } - - if (length > MAX_SIZE_OF_BLOCK_FROM_STREAM) - BOOST_THROW_EXCEPTION(tlv::Error("Length of block from stream is too large")); - - // We may still have some problem here, if some exception happens, - // we may completely lose all the bytes extracted from the stream. - - char buf[MAX_SIZE_OF_BLOCK_FROM_STREAM]; - buf[0] = *begin; - is.read(buf + 1, length - 1); - - if (length != static_cast(is.gcount()) + 1) { - BOOST_THROW_EXCEPTION(tlv::Error("Not enough data in the buffer to fully parse TLV")); - } - - return makeBinaryBlock(type, buf, length); -} - -std::tuple -Block::fromBuffer(ConstBufferPtr buffer, size_t offset) -{ - Buffer::const_iterator tempBegin = buffer->begin() + offset; - - uint32_t type; - bool isOk = tlv::readType(tempBegin, buffer->end(), type); - if (!isOk) - return std::make_tuple(false, Block()); - - uint64_t length; - isOk = tlv::readVarNumber(tempBegin, buffer->end(), length); - if (!isOk) - return std::make_tuple(false, Block()); - - if (length > static_cast(buffer->end() - tempBegin)) - return std::make_tuple(false, Block()); - - return std::make_tuple(true, Block(buffer, type, - buffer->begin() + offset, tempBegin + length, - tempBegin, tempBegin + length)); -} - -std::tuple -Block::fromBuffer(const uint8_t* buffer, size_t maxSize) -{ - const uint8_t* tempBegin = buffer; - const uint8_t* tempEnd = buffer + maxSize; - - uint32_t type = 0; - bool isOk = tlv::readType(tempBegin, tempEnd, type); - if (!isOk) - return std::make_tuple(false, Block()); - - uint64_t length; - isOk = tlv::readVarNumber(tempBegin, tempEnd, length); - if (!isOk) - return std::make_tuple(false, Block()); - - if (length > static_cast(tempEnd - tempBegin)) - return std::make_tuple(false, Block()); - - BufferPtr sharedBuffer = make_shared(buffer, tempBegin + length); - return std::make_tuple(true, - Block(sharedBuffer, type, - sharedBuffer->begin(), sharedBuffer->end(), - sharedBuffer->begin() + (tempBegin - buffer), sharedBuffer->end())); -} - -void -Block::reset() -{ - m_buffer.reset(); // reset of the shared_ptr - m_subBlocks.clear(); // remove all parsed subelements - - m_type = std::numeric_limits::max(); - m_begin = m_end = m_value_begin = m_value_end = Buffer::const_iterator(); -} - -void -Block::resetWire() -{ - m_buffer.reset(); // reset of the shared_ptr - // keep subblocks - - // keep type - m_begin = m_end = m_value_begin = m_value_end = Buffer::const_iterator(); -} - -void -Block::parse() const -{ - if (!m_subBlocks.empty() || value_size() == 0) - return; - - Buffer::const_iterator begin = value_begin(); - Buffer::const_iterator end = value_end(); - - while (begin != end) - { - Buffer::const_iterator element_begin = begin; - - uint32_t type = tlv::readType(begin, end); - uint64_t length = tlv::readVarNumber(begin, end); - - if (length > static_cast(end - begin)) - { - m_subBlocks.clear(); - BOOST_THROW_EXCEPTION(tlv::Error("TLV length exceeds buffer length")); - } - Buffer::const_iterator element_end = begin + length; - - m_subBlocks.push_back(Block(m_buffer, - type, - element_begin, element_end, - begin, element_end)); - - begin = element_end; - // don't do recursive parsing, just the top level - } -} - -void -Block::encode() -{ - if (hasWire()) - return; - - OBufferStream os; - tlv::writeVarNumber(os, type()); - - if (hasValue()) - { - tlv::writeVarNumber(os, value_size()); - os.write(reinterpret_cast(value()), value_size()); - } - else if (m_subBlocks.size() == 0) - { - tlv::writeVarNumber(os, 0); - } - else - { - size_t valueSize = 0; - for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) { - valueSize += i->size(); - } - - tlv::writeVarNumber(os, valueSize); - - for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) { - if (i->hasWire()) - os.write(reinterpret_cast(i->wire()), i->size()); - else if (i->hasValue()) { - tlv::writeVarNumber(os, i->type()); - tlv::writeVarNumber(os, i->value_size()); - os.write(reinterpret_cast(i->value()), i->value_size()); - } - else - BOOST_THROW_EXCEPTION(Error("Underlying value buffer is empty")); - } - } - - // now assign correct block - - m_buffer = os.buf(); - m_begin = m_buffer->begin(); - m_end = m_buffer->end(); - m_size = m_end - m_begin; - - m_value_begin = m_buffer->begin(); - m_value_end = m_buffer->end(); - - tlv::readType(m_value_begin, m_value_end); - tlv::readVarNumber(m_value_begin, m_value_end); -} - -const Block& -Block::get(uint32_t type) const -{ - element_const_iterator it = this->find(type); - if (it != m_subBlocks.end()) - return *it; - - BOOST_THROW_EXCEPTION(Error("(Block::get) Requested a non-existed type [" + - boost::lexical_cast(type) + "] from Block")); -} - -Block::element_const_iterator -Block::find(uint32_t type) const -{ - return std::find_if(m_subBlocks.begin(), m_subBlocks.end(), - [type] (const Block& subBlock) { return subBlock.type() == type; }); -} - -void -Block::remove(uint32_t type) -{ - resetWire(); - - auto it = std::remove_if(m_subBlocks.begin(), m_subBlocks.end(), - [type] (const Block& subBlock) { return subBlock.type() == type; }); - m_subBlocks.resize(it - m_subBlocks.begin()); -} - -Block -Block::blockFromValue() const -{ - if (value_size() == 0) - BOOST_THROW_EXCEPTION(Error("Underlying value buffer is empty")); - - Buffer::const_iterator begin = value_begin(), - end = value_end(); - - Buffer::const_iterator element_begin = begin; - - uint32_t type = tlv::readType(begin, end); - uint64_t length = tlv::readVarNumber(begin, end); - - if (length != static_cast(end - begin)) - BOOST_THROW_EXCEPTION(tlv::Error("TLV length mismatches buffer length")); - - return Block(m_buffer, - type, - element_begin, end, - begin, end); -} - -Block::operator boost::asio::const_buffer() const -{ - return boost::asio::const_buffer(wire(), size()); -} - -bool -Block::empty() const -{ - return m_type == std::numeric_limits::max(); -} - -bool -Block::hasWire() const -{ - return m_buffer && (m_begin != m_end); -} - -Buffer::const_iterator -Block::begin() const -{ - if (!hasWire()) - BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty")); - - return m_begin; -} - -Buffer::const_iterator -Block::end() const -{ - if (!hasWire()) - BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty")); - - return m_end; -} - -const uint8_t* -Block::wire() const -{ - if (!hasWire()) - BOOST_THROW_EXCEPTION(Error("(Block::wire) Underlying wire buffer is empty")); - - return &*m_begin; -} - -size_t -Block::size() const -{ - if (hasWire() || hasValue()) { - return m_size; - } - else - BOOST_THROW_EXCEPTION(Error("Block size cannot be determined (undefined block size)")); -} - -bool -Block::hasValue() const -{ - return static_cast(m_buffer); -} - -const uint8_t* -Block::value() const -{ - if (!hasValue()) - return 0; - - return &*m_value_begin; -} - -size_t -Block::value_size() const -{ - if (!hasValue()) - return 0; - - return m_value_end - m_value_begin; -} - -Block::element_iterator -Block::erase(Block::element_const_iterator position) -{ - resetWire(); - -#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR - return m_subBlocks.erase(position); -#else - element_iterator it = m_subBlocks.begin(); - std::advance(it, std::distance(m_subBlocks.cbegin(), position)); - return m_subBlocks.erase(it); -#endif -} - -Block::element_iterator -Block::erase(Block::element_const_iterator first, Block::element_const_iterator last) -{ - resetWire(); - -#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR - return m_subBlocks.erase(first, last); -#else - element_iterator itStart = m_subBlocks.begin(); - element_iterator itEnd = m_subBlocks.begin(); - std::advance(itStart, std::distance(m_subBlocks.cbegin(), first)); - std::advance(itEnd, std::distance(m_subBlocks.cbegin(), last)); - return m_subBlocks.erase(itStart, itEnd); -#endif -} - -void -Block::push_back(const Block& element) -{ - resetWire(); - m_subBlocks.push_back(element); -} - -Block::element_iterator -Block::insert(Block::element_const_iterator pos, const Block& element) -{ - resetWire(); - -#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR - return m_subBlocks.insert(pos, element); -#else - element_iterator it = m_subBlocks.begin(); - std::advance(it, std::distance(m_subBlocks.cbegin(), pos)); - return m_subBlocks.insert(it, element); -#endif -} - -Block::element_const_iterator -Block::elements_begin() const -{ - return m_subBlocks.begin(); -} - -Block::element_const_iterator -Block::elements_end() const -{ - return m_subBlocks.end(); -} - -size_t -Block::elements_size() const -{ - return m_subBlocks.size(); -} - -bool -Block::operator!=(const Block& other) const -{ - return !this->operator==(other); -} - -bool -Block::operator==(const Block& other) const -{ - return this->size() == other.size() && - std::equal(this->begin(), this->end(), other.begin()); -} - -} // namespace ndn diff --git a/src/encoding/block.hpp b/src/encoding/block.hpp deleted file mode 100644 index 7ade6e30d..000000000 --- a/src/encoding/block.hpp +++ /dev/null @@ -1,349 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Alexander Afanasyev - */ - -#ifndef NDN_ENCODING_BLOCK_HPP -#define NDN_ENCODING_BLOCK_HPP - -#include "../common.hpp" - -#include "buffer.hpp" -#include "tlv.hpp" -#include "encoding-buffer-fwd.hpp" - -namespace boost { -namespace asio { -class const_buffer; -} // namespace asio -} // namespace boost - -namespace ndn { - -/** @brief Class representing a wire element of NDN-TLV packet format - */ -class Block -{ -public: - typedef std::vector element_container; - typedef element_container::iterator element_iterator; - typedef element_container::const_iterator element_const_iterator; - - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - -public: // constructor, creation, assignment - /** @brief Create an empty Block - */ - Block(); - - /** @brief Create a Block based on EncodingBuffer object - */ - explicit - Block(const EncodingBuffer& buffer); - - /** @brief Create a Block from the raw buffer with Type-Length parsing - */ - explicit - Block(const ConstBufferPtr& buffer); - - /** @brief Create a Block from a buffer, directly specifying boundaries - * of the block within the buffer - * - * This overload will automatically detect type and position of the value within the block - */ - Block(const ConstBufferPtr& buffer, - const Buffer::const_iterator& begin, const Buffer::const_iterator& end, - bool verifyLength = true); - - /** @brief Create a Block from existing block (reusing the underlying buffer), directly - * specifying boundaries of the block within the buffer - * - * This overload will automatically detect type and position of the value within the block - */ - Block(const Block& block, - const Buffer::const_iterator& begin, const Buffer::const_iterator& end, - bool verifyLength = true); - - /** @brief Create a Block from the raw buffer with Type-Length parsing - */ - Block(const uint8_t* buffer, size_t maxlength); - - /** @brief Create a Block from the raw buffer with Type-Length parsing - */ - Block(const void* buffer, size_t maxlength); - - /** @brief Create a Block from the wire buffer (no parsing) - * - * This overload does not do any parsing - */ - Block(const ConstBufferPtr& wire, - uint32_t type, - const Buffer::const_iterator& begin, const Buffer::const_iterator& end, - const Buffer::const_iterator& valueBegin, const Buffer::const_iterator& valueEnd); - - /** @brief Create Block of a specific type with empty wire buffer - */ - explicit - Block(uint32_t type); - - /** @brief Create a Block of a specific type with the specified value - * - * The underlying buffer holds only value Additional operations are needed - * to construct wire encoding, one need to prepend the wire buffer with type - * and value-length VAR-NUMBERs - */ - Block(uint32_t type, const ConstBufferPtr& value); - - /** @brief Create a nested Block of a specific type with the specified value - * - * The underlying buffer holds only value. Additional operations are needed - * to construct wire encoding, one need to prepend the wire buffer with type - * and value-length VAR-NUMBERs - */ - Block(uint32_t type, const Block& value); - - /** @brief Create a Block from an input stream - */ - static Block - fromStream(std::istream& is); - - /** @brief Try to construct block from Buffer - * @param buffer the buffer to construct block from - * @note buffer is passed by value because the constructed block - * takes shared ownership of the buffer - * @param offset offset from beginning of \p buffer to construct Block from - * - * This method does not throw upon decoding error. - * This method does not copy the bytes. - * - * @return true and the Block, if Block is successfully created; otherwise false - */ - static std::tuple - fromBuffer(ConstBufferPtr buffer, size_t offset); - - /** @brief Try to construct block from raw buffer - * @param buffer the raw buffer to copy bytes from - * @param maxSize the maximum size of constructed block; - * @p buffer must have a size of at least @p maxSize - * - * This method does not throw upon decoding error. - * This method copies the bytes into a new Buffer. - * - * @return true and the Block, if Block is successfully created; otherwise false - */ - static std::tuple - fromBuffer(const uint8_t* buffer, size_t maxSize); - -public: // wire format - /** @brief Check if the Block is empty - */ - bool - empty() const; - - /** @brief Check if the Block has fully encoded wire - */ - bool - hasWire() const; - - /** @brief Reset wire buffer of the element - */ - void - reset(); - - /** @brief Reset wire buffer but keep sub elements (if any) - */ - void - resetWire(); - - Buffer::const_iterator - begin() const; - - Buffer::const_iterator - end() const; - - const uint8_t* - wire() const; - - size_t - size() const; - -public: // type and value - uint32_t - type() const; - - /** @brief Check if the Block has value block (no type and length are encoded) - */ - bool - hasValue() const; - - Buffer::const_iterator - value_begin() const; - - Buffer::const_iterator - value_end() const; - - const uint8_t* - value() const; - - size_t - value_size() const; - -public: // sub elements - /** @brief Parse wire buffer into subblocks - * - * This method is not really const, but it does not modify any data. It simply - * parses contents of the buffer into subblocks - */ - void - parse() const; - - /** @brief Encode subblocks into wire buffer - */ - void - encode(); - - /** @brief Get the first subelement of the requested type - */ - const Block& - get(uint32_t type) const; - - element_const_iterator - find(uint32_t type) const; - - /** - * @brief remove all subelements of \p type - * @param type TLV-TYPE of subelements to remove - * @pre parse() has been invoked - */ - void - remove(uint32_t type); - - element_iterator - erase(element_const_iterator position); - - element_iterator - erase(element_const_iterator first, element_const_iterator last); - - void - push_back(const Block& element); - - /** - * @brief insert Insert a new element in a specific position - * @param pos Position to insert the new element - * @param element Element to be inserted - * @return An iterator that points to the first of the newly inserted elements. - */ - element_iterator - insert(element_const_iterator pos, const Block& element); - - /** @brief Get all subelements - */ - const element_container& - elements() const; - - element_const_iterator - elements_begin() const; - - element_const_iterator - elements_end() const; - - size_t - elements_size() const; - - Block - blockFromValue() const; - - /** - * @brief Get underlying buffer - */ - shared_ptr - getBuffer() const; - -public: // EqualityComparable concept - bool - operator==(const Block& other) const; - - bool - operator!=(const Block& other) const; - -public: // ConvertibleToConstBuffer - operator boost::asio::const_buffer() const; - -protected: - shared_ptr m_buffer; - - uint32_t m_type; - - Buffer::const_iterator m_begin; - Buffer::const_iterator m_end; - uint32_t m_size; - - Buffer::const_iterator m_value_begin; - Buffer::const_iterator m_value_end; - - mutable element_container m_subBlocks; -}; - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -inline shared_ptr -Block::getBuffer() const -{ - return m_buffer; -} - -inline uint32_t -Block::type() const -{ - return m_type; -} - -inline Buffer::const_iterator -Block::value_begin() const -{ - return m_value_begin; -} - -inline Buffer::const_iterator -Block::value_end() const -{ - return m_value_end; -} - -inline const Block::element_container& -Block::elements() const -{ - return m_subBlocks; -} - -} // namespace ndn - -#endif // NDN_ENCODING_BLOCK_HPP diff --git a/src/encoding/buffer.cpp b/src/encoding/buffer.cpp deleted file mode 100644 index 0d9550bcc..000000000 --- a/src/encoding/buffer.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Alexander Afanasyev - */ - -#include "buffer.hpp" - -namespace ndn { - -#if NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE -static_assert(std::is_nothrow_move_constructible::value, - "Buffer must be MoveConstructible with noexcept"); -#endif // NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE - -#if NDN_CXX_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE -static_assert(std::is_nothrow_move_assignable::value, - "Buffer must be MoveAssignable with noexcept"); -#endif // NDN_CXX_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE - -Buffer::Buffer() -{ -} - -Buffer::Buffer(size_t size) - : std::vector(size, 0) -{ -} - -Buffer::Buffer(const void* buf, size_t length) - : std::vector(reinterpret_cast(buf), - reinterpret_cast(buf) + length) -{ -} - -} // namespace ndn diff --git a/src/encoding/buffer.hpp b/src/encoding/buffer.hpp deleted file mode 100644 index 994fbf899..000000000 --- a/src/encoding/buffer.hpp +++ /dev/null @@ -1,133 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Alexander Afanasyev - */ - -#ifndef NDN_ENCODING_BUFFER_HPP -#define NDN_ENCODING_BUFFER_HPP - -#include "../common.hpp" - -#include - -namespace ndn { - -class Buffer; -typedef shared_ptr ConstBufferPtr; -typedef shared_ptr BufferPtr; - -/** - * @brief Class representing a general-use automatically managed/resized buffer - * - * In most respect, Buffer class is equivalent to std::vector and is in fact - * uses it as a base class. In addition to that, it provides buf() and buf() helper - * method for easier access to the underlying data (buf() casts pointer to the requested class) - */ -class Buffer : public std::vector -{ -public: - /** @brief Creates an empty buffer - */ - Buffer(); - - /** @brief Creates a buffer with pre-allocated size - * @param size size of the buffer to be allocated - */ - explicit - Buffer(size_t size); - - /** @brief Create a buffer by copying contents from a buffer - * @param buf const pointer to buffer - * @param length length of the buffer to copy - */ - Buffer(const void* buf, size_t length); - - /** @brief Create a buffer by copying contents of the range [first, last) - * @tparam InputIterator an InputIterator compatible with std::vector constructor - * @param first iterator to the first element to copy - * @param last iterator to the element immediately following the last element to copy - */ - template - Buffer(InputIterator first, InputIterator last) - : std::vector(first, last) - { - } - - /** @return pointer to the first byte of the buffer - */ - uint8_t* - get() - { - return &front(); - } - - /** @return pointer to the first byte of the buffer - * - * This is same as \p .get() - */ - uint8_t* - buf() - { - return &front(); - } - - /** @return pointer to the first byte of the buffer and reinterpret_cast - * it to the requested type T - */ - template - T* - get() - { - return reinterpret_cast(&front()); - } - - /** @return pointer to the first byte of the buffer - * - * This is same as \p .get() - */ - const uint8_t* - buf() const - { - return &front(); - } - - /** @return pointer to the first byte of the buffer - */ - const uint8_t* - get() const - { - return &front(); - } - - /** @return const pointer to the first byte of the buffer and reinterpret_cast - * it to the requested type T - */ - template - const T* - get() const - { - return reinterpret_cast(&front()); - } -}; - -} // namespace ndn - -#endif // NDN_ENCODING_BUFFER_HPP diff --git a/src/encoding/cryptopp/asn_ext.cpp b/src/encoding/cryptopp/asn_ext.cpp deleted file mode 100644 index 96010c410..000000000 --- a/src/encoding/cryptopp/asn_ext.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Alexander Afanasyev - * @author Yingdi Yu - */ - -#include "asn_ext.hpp" -#include "../../util/time.hpp" - -#include -#include - -using namespace CryptoPP; - -namespace ndn { - -size_t -DEREncodeGeneralTime(CryptoPP::BufferedTransformation& bt, - const time::system_clock::TimePoint& time) -{ - std::string str = time::toIsoString(time); - // For example, 20131226T232254 - // 20131226T232254.100000 - BOOST_ASSERT(str.size() >= 15); - std::string asn1time = str.substr(0, 8) + str.substr(9,6) + "Z"; - - bt.Put(GENERALIZED_TIME); - size_t lengthBytes = DERLengthEncode(bt, asn1time.size()); - bt.Put(reinterpret_cast(asn1time.c_str()), asn1time.size()); - return 1+lengthBytes+asn1time.size(); -} - -void -BERDecodeTime(CryptoPP::BufferedTransformation& bt, - time::system_clock::TimePoint& time) -{ - byte b; - if (!bt.Get(b) || (b != GENERALIZED_TIME && b != UTC_TIME)) - BERDecodeError(); - - size_t bc; - if (!BERLengthDecode(bt, bc)) - BERDecodeError(); - - SecByteBlock time_str(bc); - if (bc != bt.Get(time_str, bc)) - BERDecodeError(); - - std::string str; - str.assign (time_str.begin(), time_str.end()); - - if (b == UTC_TIME) { - if (boost::lexical_cast(str.substr(0,2)) < 50) - str = "20" + str; - else - str = "19" + str; - } - - time = time::fromIsoString(str.substr(0, 8) + "T" + str.substr(8, 6)); -} - -} // namespace ndn diff --git a/src/encoding/cryptopp/asn_ext.hpp b/src/encoding/cryptopp/asn_ext.hpp deleted file mode 100644 index 359aa8b24..000000000 --- a/src/encoding/cryptopp/asn_ext.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author: Alexander Afanasyev - * @author: Yingdi Yu - */ - -#ifndef NDN_ASN_EXT_HPP -#define NDN_ASN_EXT_HPP - -#include "../../common.hpp" -#include "../../security/v1/cryptopp.hpp" - -#include "../../util/time.hpp" - -namespace ndn { - -size_t -DEREncodeGeneralTime(CryptoPP::BufferedTransformation& bt, - const time::system_clock::TimePoint& time); - -void -BERDecodeTime(CryptoPP::BufferedTransformation& bt, - time::system_clock::TimePoint& time); - -} // namespace ndn - -#endif // NDN_ASN_EXT_HPP diff --git a/src/encoding/encoding-buffer-fwd.hpp b/src/encoding/encoding-buffer-fwd.hpp deleted file mode 100644 index 359864fd9..000000000 --- a/src/encoding/encoding-buffer-fwd.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_ENCODING_ENCODING_BUFFER_FWD_HPP -#define NDN_ENCODING_ENCODING_BUFFER_FWD_HPP - -namespace ndn { -namespace encoding { - -typedef bool Tag; - -/** - * @brief Tag for EncodingImpl to indicate that Encoder is requested - * Implementation of the tag may change to class. Use of true directly - * as a template parameter is discouraged. - */ -static const Tag EncoderTag = true; - -/** - * @brief Tag for EncodingImpl to indicate that Estimator is requested - * Implementation of the tag may change to class. Use of false directly - * as a template parameter is discouraged. - */ -static const Tag EstimatorTag = false; - -template -class EncodingImpl; - -typedef EncodingImpl EncodingBuffer; -typedef EncodingImpl EncodingEstimator; - -} // namespace encoding - -using encoding::EncodingImpl; -using encoding::EncodingBuffer; -using encoding::EncodingEstimator; - -} // namespace ndn - -#endif // NDN_ENCODING_ENCODING_BUFFER_FWD_HPP diff --git a/src/encoding/endian.hpp b/src/encoding/endian.hpp deleted file mode 100644 index e37fa98f7..000000000 --- a/src/encoding/endian.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Junxiao Shi - */ - -#ifndef NDN_ENCODING_ENDIAN_HPP -#define NDN_ENCODING_ENDIAN_HPP - -#ifdef __linux__ - -#include - -#endif // __linux__ - -#ifdef __FreeBSD__ - -#include - -#endif // __FreeBSD__ - -#ifdef __APPLE__ - -#include -#define htobe16(x) OSSwapHostToBigInt16(x) -#define htole16(x) OSSwapHostToLittleInt16(x) -#define be16toh(x) OSSwapBigToHostInt16(x) -#define le16toh(x) OSSwapLittleToHostInt16(x) -#define htobe32(x) OSSwapHostToBigInt32(x) -#define htole32(x) OSSwapHostToLittleInt32(x) -#define be32toh(x) OSSwapBigToHostInt32(x) -#define le32toh(x) OSSwapLittleToHostInt32(x) -#define htobe64(x) OSSwapHostToBigInt64(x) -#define htole64(x) OSSwapHostToLittleInt64(x) -#define be64toh(x) OSSwapBigToHostInt64(x) -#define le64toh(x) OSSwapLittleToHostInt64(x) - -#endif // __APPLE__ - -#endif // NDN_ENCODING_ENDIAN_HPP diff --git a/src/encoding/estimator.cpp b/src/encoding/estimator.cpp deleted file mode 100644 index 9ec23360e..000000000 --- a/src/encoding/estimator.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "estimator.hpp" - -namespace ndn { -namespace encoding { - -Estimator::Estimator(size_t totalReserve, size_t reserveFromBack) -{ -} - -size_t -Estimator::prependByte(uint8_t value) -{ - return 1; -} - -size_t -Estimator::appendByte(uint8_t value) -{ - return 1; -} - - -size_t -Estimator::prependByteArray(const uint8_t* array, size_t length) -{ - return length; -} - -size_t -Estimator::appendByteArray(const uint8_t* array, size_t length) -{ - return prependByteArray(array, length); -} - -size_t -Estimator::prependVarNumber(uint64_t varNumber) -{ - if (varNumber < 253) { - return 1; - } - else if (varNumber <= std::numeric_limits::max()) { - return 3; - } - else if (varNumber <= std::numeric_limits::max()) { - return 5; - } - else { - return 9; - } -} - -size_t -Estimator::appendVarNumber(uint64_t varNumber) -{ - return prependVarNumber(varNumber); -} - - -size_t -Estimator::prependNonNegativeInteger(uint64_t varNumber) -{ - if (varNumber <= std::numeric_limits::max()) { - return 1; - } - else if (varNumber <= std::numeric_limits::max()) { - return 2; - } - else if (varNumber <= std::numeric_limits::max()) { - return 4; - } - else { - return 8; - } -} - -size_t -Estimator::appendNonNegativeInteger(uint64_t varNumber) -{ - return prependNonNegativeInteger(varNumber); -} - - -size_t -Estimator::prependByteArrayBlock(uint32_t type, const uint8_t* array, size_t arraySize) -{ - size_t totalLength = arraySize; - totalLength += prependVarNumber(arraySize); - totalLength += prependVarNumber(type); - - return totalLength; -} - -size_t -Estimator::appendByteArrayBlock(uint32_t type, const uint8_t* array, size_t arraySize) -{ - return prependByteArrayBlock(type, array, arraySize); -} - - -size_t -Estimator::prependBlock(const Block& block) -{ - if (block.hasWire()) { - return block.size(); - } - else { - return prependByteArrayBlock(block.type(), block.value(), block.value_size()); - } -} - -size_t -Estimator::appendBlock(const Block& block) -{ - return prependBlock(block); -} - - -} // namespace encoding -} // namespace ndn diff --git a/src/encoding/estimator.hpp b/src/encoding/estimator.hpp deleted file mode 100644 index 364f9534a..000000000 --- a/src/encoding/estimator.hpp +++ /dev/null @@ -1,162 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_ENCODING_ESTIMATOR_HPP -#define NDN_ENCODING_ESTIMATOR_HPP - -#include "../common.hpp" -#include "block.hpp" - -namespace ndn { -namespace encoding { - -/** - * @brief Helper class to estimate size of TLV encoding - * Interface of this class (mostly) matches interface of Encoder class - * @sa Encoder - */ -class Estimator -{ -public: // common interface between Encoder and Estimator - /** - * @brief Create instance of the estimator - * @param totalReserve not used (for compatibility with the Encoder) - * @param reserveFromBack not used (for compatibility with the Encoder) - */ - explicit - Estimator(size_t totalReserve = 0, size_t reserveFromBack = 0); - - Estimator(const Estimator&) = delete; - - Estimator& - operator=(const Estimator&) = delete; - - /** - * @brief Prepend a byte - */ - size_t - prependByte(uint8_t value); - - /** - * @brief Append a byte - */ - size_t - appendByte(uint8_t value); - - /** - * @brief Prepend a byte array @p array of length @p length - */ - size_t - prependByteArray(const uint8_t* array, size_t length); - - /** - * @brief Append a byte array @p array of length @p length - */ - size_t - appendByteArray(const uint8_t* array, size_t length); - - /** - * @brief Prepend range of bytes from the range [@p first, @p last) - */ - template - size_t - prependRange(Iterator first, Iterator last); - - /** - * @brief Append range of bytes from the range [@p first, @p last) - */ - template - size_t - appendRange(Iterator first, Iterator last); - - /** - * @brief Prepend VarNumber @p varNumber of NDN TLV encoding - * @sa http://named-data.net/doc/ndn-tlv/ - */ - size_t - prependVarNumber(uint64_t varNumber); - - /** - * @brief Prepend VarNumber @p varNumber of NDN TLV encoding - * @sa http://named-data.net/doc/ndn-tlv/ - */ - size_t - appendVarNumber(uint64_t varNumber); - - /** - * @brief Prepend non-negative integer @p integer of NDN TLV encoding - * @sa http://named-data.net/doc/ndn-tlv/ - */ - size_t - prependNonNegativeInteger(uint64_t integer); - - /** - * @brief Append non-negative integer @p integer of NDN TLV encoding - * @sa http://named-data.net/doc/ndn-tlv/ - */ - size_t - appendNonNegativeInteger(uint64_t integer); - - /** - * @brief Prepend TLV block of type @p type and value from buffer @p array of size @p arraySize - */ - size_t - prependByteArrayBlock(uint32_t type, const uint8_t* array, size_t arraySize); - - /** - * @brief Append TLV block of type @p type and value from buffer @p array of size @p arraySize - */ - size_t - appendByteArrayBlock(uint32_t type, const uint8_t* array, size_t arraySize); - - /** - * @brief Prepend TLV block @p block - */ - size_t - prependBlock(const Block& block); - - /** - * @brief Append TLV block @p block - */ - size_t - appendBlock(const Block& block); -}; - - -template -inline size_t -Estimator::prependRange(Iterator first, Iterator last) -{ - return std::distance(first, last); -} - - -template -inline size_t -Estimator::appendRange(Iterator first, Iterator last) -{ - return prependRange(first, last); -} - -} // namespace encoding -} // namespace ndn - -#endif // NDN_ENCODING_ESTIMATOR_HPP diff --git a/src/encoding/nfd-constants.cpp b/src/encoding/nfd-constants.cpp deleted file mode 100644 index 2b18d4da4..000000000 --- a/src/encoding/nfd-constants.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "nfd-constants.hpp" -#include -#include - -namespace ndn { -namespace nfd { - -std::ostream& -operator<<(std::ostream& os, FaceScope faceScope) -{ - switch (faceScope) { - case FACE_SCOPE_NONE: - return os << "none"; - case FACE_SCOPE_NON_LOCAL: - return os << "non-local"; - case FACE_SCOPE_LOCAL: - return os << "local"; - default: - return os << static_cast(faceScope); - } -} - -std::ostream& -operator<<(std::ostream& os, FacePersistency facePersistency) -{ - switch (facePersistency) { - case FACE_PERSISTENCY_NONE: - return os << "none"; - case FACE_PERSISTENCY_PERSISTENT: - return os << "persistent"; - case FACE_PERSISTENCY_ON_DEMAND: - return os << "on-demand"; - case FACE_PERSISTENCY_PERMANENT: - return os << "permanent"; - default: - return os << static_cast(facePersistency); - } -} - -std::ostream& -operator<<(std::ostream& os, LinkType linkType) -{ - switch (linkType) { - case LINK_TYPE_NONE: - return os << "none"; - case LINK_TYPE_POINT_TO_POINT: - return os << "point-to-point"; - case LINK_TYPE_MULTI_ACCESS: - return os << "multi-access"; - default: - return os << static_cast(linkType); - } -} - -std::ostream& -operator<<(std::ostream& os, RouteOrigin routeOrigin) -{ - switch (routeOrigin) { - case ROUTE_ORIGIN_NONE: - return os << "none"; - case ROUTE_ORIGIN_APP: - return os << "app"; - case ROUTE_ORIGIN_AUTOREG: - return os << "autoreg"; - case ROUTE_ORIGIN_CLIENT: - return os << "client"; - case ROUTE_ORIGIN_AUTOCONF: - return os << "autoconf"; - case ROUTE_ORIGIN_NLSR: - return os << "nlsr"; - case ROUTE_ORIGIN_STATIC: - return os << "static"; - default: - return os << static_cast(routeOrigin); - } -} - -std::ostream& -operator<<(std::ostream& os, RouteFlags routeFlags) -{ - if (routeFlags == ROUTE_FLAGS_NONE) { - return os << "none"; - } - - bool isFirst = true; - auto printToken = [&os, &isFirst] (const std::string& token) { - if (isFirst) { - isFirst = false; - } - else { - os << '|'; - } - os << token; - }; - - static const std::map knownBits = { - {ROUTE_FLAG_CHILD_INHERIT, "child-inherit"}, - {ROUTE_FLAG_CAPTURE, "capture"}}; - for (const auto& pair : knownBits) { - RouteFlags bit = ROUTE_FLAGS_NONE; - std::string token; - std::tie(bit, token) = pair; - - if ((routeFlags & bit) == 0) { - continue; - } - - printToken(token); - routeFlags = static_cast(routeFlags & ~bit); - } - - if (routeFlags != 0) { - printToken("0x"); - std::ios_base::fmtflags oldFmt = os.flags(); - os << std::hex << std::nouppercase - << static_cast(routeFlags); - os.flags(oldFmt); - } - - return os; -} - -} // namespace nfd -} // namespace ndn diff --git a/src/encoding/nfd-constants.hpp b/src/encoding/nfd-constants.hpp deleted file mode 100644 index 4c38bd9f4..000000000 --- a/src/encoding/nfd-constants.hpp +++ /dev/null @@ -1,117 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_ENCODING_NFD_CONSTANTS_HPP -#define NDN_ENCODING_NFD_CONSTANTS_HPP - -#include "../common.hpp" - -namespace ndn { -namespace nfd { - -static const uint64_t INVALID_FACE_ID = std::numeric_limits::max(); - -/** \ingroup management - */ -enum FaceScope : uint8_t { - FACE_SCOPE_NONE = std::numeric_limits::max(), - /** \brief face is non-local - */ - FACE_SCOPE_NON_LOCAL = 0, - /** \brief face is local - */ - FACE_SCOPE_LOCAL = 1 -}; - -std::ostream& -operator<<(std::ostream& os, FaceScope faceScope); - -/** \ingroup management - */ -enum FacePersistency : uint8_t { - FACE_PERSISTENCY_NONE = std::numeric_limits::max(), - /** \brief face is persistent - */ - FACE_PERSISTENCY_PERSISTENT = 0, - /** \brief face is on-demand - */ - FACE_PERSISTENCY_ON_DEMAND = 1, - /** \brief face is permanent - */ - FACE_PERSISTENCY_PERMANENT = 2 -}; - -std::ostream& -operator<<(std::ostream& os, FacePersistency facePersistency); - -/** \ingroup management - */ -enum FaceFlagBit { - /** \brief bit that controls whether local fields are enabled on a face - */ - BIT_LOCAL_FIELDS_ENABLED = 0 -}; - -/** \ingroup management - */ -enum LinkType : uint8_t { - LINK_TYPE_NONE = std::numeric_limits::max(), - /** \brief link is point-to-point - */ - LINK_TYPE_POINT_TO_POINT = 0, - /** \brief link is multi-access - */ - LINK_TYPE_MULTI_ACCESS = 1 -}; - -std::ostream& -operator<<(std::ostream& os, LinkType linkType); - -/** \ingroup management - */ -enum RouteOrigin : uint16_t { - ROUTE_ORIGIN_NONE = std::numeric_limits::max(), - ROUTE_ORIGIN_APP = 0, - ROUTE_ORIGIN_AUTOREG = 64, - ROUTE_ORIGIN_CLIENT = 65, - ROUTE_ORIGIN_AUTOCONF = 66, - ROUTE_ORIGIN_NLSR = 128, - ROUTE_ORIGIN_STATIC = 255 -}; - -std::ostream& -operator<<(std::ostream& os, RouteOrigin routeOrigin); - -/** \ingroup management - */ -enum RouteFlags { - ROUTE_FLAGS_NONE = 0, - ROUTE_FLAG_CHILD_INHERIT = 1, - ROUTE_FLAG_CAPTURE = 2 -}; - -std::ostream& -operator<<(std::ostream& os, RouteFlags routeFlags); - -} // namespace nfd -} // namespace ndn - -#endif // NDN_ENCODING_NFD_CONSTANTS_HPP diff --git a/src/encoding/oid.cpp b/src/encoding/oid.cpp deleted file mode 100644 index da5ee5c60..000000000 --- a/src/encoding/oid.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "oid.hpp" - -#include "../security/v1/cryptopp.hpp" - -#include - -namespace ndn { - -static const int OID_MAGIC_NUMBER = 40; - -Oid::Oid(const char* oid) - : Oid(std::string(oid)) -{ -} - -Oid::Oid(const std::string& oid) -{ - std::string str = oid + "."; - - size_t pos = 0; - size_t ppos = 0; - - while (std::string::npos != pos) { - ppos = pos; - - pos = str.find_first_of('.', pos); - if (pos == std::string::npos) - break; - - m_oid.push_back(atoi(str.substr(ppos, pos - ppos).c_str())); - - pos++; - } -} - -std::string -Oid::toString() const -{ - std::ostringstream convert; - - for (std::vector::const_iterator it = m_oid.begin(); it != m_oid.end(); ++it) { - if (it != m_oid.begin()) - convert << "."; - convert << *it; - } - - return convert.str(); -} - -bool -Oid::equal(const Oid& oid) const -{ - std::vector::const_iterator i = m_oid.begin(); - std::vector::const_iterator j = oid.m_oid.begin(); - - for (; i != m_oid.end() && j != oid.m_oid.end(); i++, j++) { - if (*i != *j) - return false; - } - - return (i == m_oid.end() && j == oid.m_oid.end()); // keep parenthesis for readability. -} - -inline void -encodeValue(CryptoPP::BufferedTransformation& bt, CryptoPP::word32 v) -{ - using namespace CryptoPP; - - for (unsigned int i = RoundUpToMultipleOf(STDMAX(7U, BitPrecision(v)), 7U) - 7; i != 0; i -= 7) - bt.Put(static_cast(0x80 | ((v >> i) & 0x7f))); - bt.Put(static_cast(v & 0x7f)); -} - -inline size_t -decodeValue(CryptoPP::BufferedTransformation& bt, CryptoPP::word32& v) -{ - using namespace CryptoPP; - - v = 0; - size_t i = 0; - while (true) - { - byte b; - if (!bt.Get(b)) - BERDecodeError(); - i++; - if (v >> (8 * sizeof(v) - 7)) // v about to overflow - BERDecodeError(); - v <<= 7; - v += b & 0x7f; - if ((b & 0x80) == 0) - return i; - } -} - -void -Oid::encode(CryptoPP::BufferedTransformation& out) const -{ - using namespace CryptoPP; - - BOOST_ASSERT(m_oid.size() >= 2); - - ByteQueue temp; - temp.Put(byte(m_oid[0] * OID_MAGIC_NUMBER + m_oid[1])); - for (size_t i = 2; i < m_oid.size(); i++) - encodeValue(temp, m_oid[i]); - - out.Put(OBJECT_IDENTIFIER); - DERLengthEncode(out, temp.CurrentSize()); - temp.TransferTo(out); -} - -void -Oid::decode(CryptoPP::BufferedTransformation& in) -{ - using namespace CryptoPP; - - byte b; - if (!in.Get(b) || b != OBJECT_IDENTIFIER) - BERDecodeError(); - - size_t length; - if (!BERLengthDecode(in, length) || length < 1) - BERDecodeError(); - - if (!in.Get(b)) - BERDecodeError(); - - length--; - m_oid.resize(2); - m_oid[0] = b / OID_MAGIC_NUMBER; - m_oid[1] = b % OID_MAGIC_NUMBER; - - while (length > 0) - { - word32 v; - size_t valueLen = decodeValue(in, v); - if (valueLen > length) - BERDecodeError(); - m_oid.push_back(v); - length -= valueLen; - } -} - -namespace oid { -const Oid RSA("1.2.840.113549.1.1.1"); -const Oid ECDSA("1.2.840.10045.2.1"); - -const Oid ATTRIBUTE_NAME("2.5.4.41"); -} // namespace oid - -} // namespace ndn diff --git a/src/encoding/oid.hpp b/src/encoding/oid.hpp deleted file mode 100644 index 2f8948459..000000000 --- a/src/encoding/oid.hpp +++ /dev/null @@ -1,110 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_ENCODING_OID_HPP -#define NDN_ENCODING_OID_HPP - -#include "../common.hpp" - -#include - -namespace CryptoPP { -class BufferedTransformation; -} // namespace CryptoPP - -namespace ndn { - -class Oid -{ -public: - Oid() = default; - - explicit - Oid(const char* oid); - - explicit - Oid(const std::string& oid); - - explicit - Oid(const std::vector& oid) - : m_oid(oid) - { - } - - const std::vector& - getIntegerList() const - { - return m_oid; - } - - void - setIntegerList(const std::vector& value) - { - m_oid = value; - } - - std::string - toString() const; - - bool - operator==(const Oid& oid) const - { - return equal(oid); - } - - bool - operator!=(const Oid& oid) const - { - return !equal(oid); - } - - void - encode(CryptoPP::BufferedTransformation& out) const; - - void - decode(CryptoPP::BufferedTransformation& in); - - -private: - bool - equal(const Oid& oid) const; - -private: - std::vector m_oid; -}; - -/** - * @deprecated Use Oid type instead - */ -typedef Oid OID; - -namespace oid { -// crypto algorithm -extern const Oid RSA; -extern const Oid ECDSA; - -// certificate entries -extern const Oid ATTRIBUTE_NAME; -} // namespace oid - -} // namespace ndn - -#endif // NDN_ENCODING_OID_HPP diff --git a/src/encoding/tlv-nfd.hpp b/src/encoding/tlv-nfd.hpp deleted file mode 100644 index 0033f229e..000000000 --- a/src/encoding/tlv-nfd.hpp +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_ENCODING_TLV_NFD_HPP -#define NDN_ENCODING_TLV_NFD_HPP - -#include "tlv.hpp" -#include "nfd-constants.hpp" - -namespace ndn { -namespace tlv { -namespace nfd { - -// NFD Management protocol -enum { - // ControlParameters - ControlParameters = 104, - FaceId = 105, - Uri = 114, - LocalControlFeature = 110, - Origin = 111, - Cost = 106, - Flags = 108, - Mask = 112, - Strategy = 107, - ExpirationPeriod = 109, - - // ControlResponse - ControlResponse = 101, - StatusCode = 102, - StatusText = 103, - - // ForwarderStatus - NfdVersion = 128, - StartTimestamp = 129, - CurrentTimestamp = 130, - NNameTreeEntries = 131, - NFibEntries = 132, - NPitEntries = 133, - NMeasurementsEntries = 134, - NCsEntries = 135, - - // Face Management - FaceStatus = 128, - LocalUri = 129, - ChannelStatus = 130, - UriScheme = 131, - FaceScope = 132, - FacePersistency = 133, - LinkType = 134, - FaceQueryFilter = 150, - FaceEventNotification = 192, - FaceEventKind = 193, - - // ForwarderStatus and FaceStatus counters - NInInterests = 144, - NInDatas = 145, - NInNacks = 151, - NOutInterests = 146, - NOutDatas = 147, - NOutNacks = 152, - NInBytes = 148, - NOutBytes = 149, - - // FIB Management - FibEntry = 128, - NextHopRecord = 129, - - // Strategy Choice Management - StrategyChoice = 128, - - // RIB Management - RibEntry = 128, - Route = 129 - -}; - -enum { - // Local Control Header - LocalControlHeader = 80, - IncomingFaceId = 81, - NextHopFaceId = 82, - CachingPolicy = 83, - NoCache = 96 -}; - -} // namespace nfd -} // namespace tlv -} // namespace ndn - -#endif // NDN_ENCODING_TLV_NFD_HPP diff --git a/src/encoding/tlv.hpp b/src/encoding/tlv.hpp deleted file mode 100644 index ad964e2f3..000000000 --- a/src/encoding/tlv.hpp +++ /dev/null @@ -1,587 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_ENCODING_TLV_HPP -#define NDN_ENCODING_TLV_HPP - -#include -#include -#include -#include - -#include "buffer.hpp" -#include "endian.hpp" - -namespace ndn { - -/** @brief practical limit of network layer packet size - * - * If a packet is longer than this size, library and application MAY drop it. - */ -const size_t MAX_NDN_PACKET_SIZE = 8800; - -/** - * @brief Namespace defining NDN-TLV related constants and procedures - */ -namespace tlv { - -/** @brief represents an error in TLV encoding or decoding - * - * Element::Error SHOULD inherit from this Error class. - */ -class Error : public std::runtime_error -{ -public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } -}; - -enum { - Interest = 5, - Data = 6, - Name = 7, - ImplicitSha256DigestComponent = 1, - NameComponent = 8, - Selectors = 9, - Nonce = 10, - // = 11, - InterestLifetime = 12, - MinSuffixComponents = 13, - MaxSuffixComponents = 14, - PublisherPublicKeyLocator = 15, - Exclude = 16, - ChildSelector = 17, - MustBeFresh = 18, - Any = 19, - MetaInfo = 20, - Content = 21, - SignatureInfo = 22, - SignatureValue = 23, - ContentType = 24, - FreshnessPeriod = 25, - FinalBlockId = 26, - SignatureType = 27, - KeyLocator = 28, - KeyDigest = 29, - LinkPreference = 30, - LinkDelegation = 31, - SelectedDelegation = 32, - - AppPrivateBlock1 = 128, - AppPrivateBlock2 = 32767 -}; - -enum SignatureTypeValue { - DigestSha256 = 0, - SignatureSha256WithRsa = 1, - // = 2, - SignatureSha256WithEcdsa = 3 -}; - -/** @brief TLV codes for SignatureInfo features - * @sa docs/tutorials/certificate-format.rst - */ -enum { - // SignatureInfo TLVs - ValidityPeriod = 253, - NotBefore = 254, - NotAfter = 255, - - AdditionalDescription = 258, - DescriptionEntry = 512, - DescriptionKey = 513, - DescriptionValue = 514 -}; - -/** @brief indicates a possible value of ContentType field - */ -enum ContentTypeValue { - /** @brief indicates content is the actual data bits - */ - ContentType_Blob = 0, - - /** @brief indicates content is another name which identifies actual data content - */ - ContentType_Link = 1, - - /** @brief indicates content is a public key - */ - ContentType_Key = 2, - - /** @brief indicates a producer generated NACK - * @warning Experimental. Not defined in NDN-TLV spec. - */ - ContentType_Nack = 3 -}; - -/** - * @brief Read VAR-NUMBER in NDN-TLV encoding - * - * @param [in] begin Begin (pointer or iterator) of the buffer - * @param [in] end End (pointer or iterator) of the buffer - * @param [out] number Read number - * - * @throws This call never throws exception - * - * @return true if number successfully read from input, false otherwise - */ -template -inline bool -readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number); - -/** - * @brief Read TLV Type - * - * @param [in] begin Begin (pointer or iterator) of the buffer - * @param [in] end End (pointer or iterator) of the buffer - * @param [out] type Read type number - * - * @throws This call never throws exception - * - * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type - * is larger than 2^32-1 (type in this library is implemented as uint32_t) - */ -template -inline bool -readType(InputIterator& begin, const InputIterator& end, uint32_t& type); - - -/** - * @brief Read VAR-NUMBER in NDN-TLV encoding - * - * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read - * - * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER - */ -template -inline uint64_t -readVarNumber(InputIterator& begin, const InputIterator& end); - -/** - * @brief Read TLV Type - * - * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read - * - * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type - * is larger than 2^32-1 (type in this library is implemented as uint32_t) - */ -template -inline uint32_t -readType(InputIterator& begin, const InputIterator& end); - -/** - * @brief Get number of bytes necessary to hold value of VAR-NUMBER - */ -inline size_t -sizeOfVarNumber(uint64_t varNumber); - -/** - * @brief Write VAR-NUMBER to the specified stream - */ -inline size_t -writeVarNumber(std::ostream& os, uint64_t varNumber); - -/** - * @brief Read nonNegativeInteger in NDN-TLV encoding - * - * This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read - * - * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER - * - * How many bytes will be read is directly controlled by the size parameter, which can be either - * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown. - */ -template -inline uint64_t -readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end); - -/** - * @brief Get number of bytes necessary to hold value of nonNegativeInteger - */ -inline size_t -sizeOfNonNegativeInteger(uint64_t varNumber); - -/** - * @brief Write nonNegativeInteger to the specified stream - */ -inline size_t -writeNonNegativeInteger(std::ostream& os, uint64_t varNumber); - -///////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////// - -// Inline implementations - -///////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////// - -template -inline bool -readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number) -{ - if (begin == end) - return false; - - uint8_t firstOctet = *begin; - ++begin; - if (firstOctet < 253) - { - number = firstOctet; - } - else if (firstOctet == 253) - { - if (end - begin < 2) - return false; - - uint16_t value = *reinterpret_cast(&*begin); - begin += 2; - number = be16toh(value); - } - else if (firstOctet == 254) - { - if (end - begin < 4) - return false; - - uint32_t value = *reinterpret_cast(&*begin); - begin += 4; - number = be32toh(value); - } - else // if (firstOctet == 255) - { - if (end - begin < 8) - return false; - - uint64_t value = *reinterpret_cast(&*begin); - begin += 8; - - number = be64toh(value); - } - - return true; -} - -template -inline bool -readType(InputIterator& begin, const InputIterator& end, uint32_t& type) -{ - uint64_t number = 0; - bool isOk = readVarNumber(begin, end, number); - if (!isOk || number > std::numeric_limits::max()) - { - return false; - } - - type = static_cast(number); - return true; -} - -template -inline uint64_t -readVarNumber(InputIterator& begin, const InputIterator& end) -{ - if (begin == end) - BOOST_THROW_EXCEPTION(Error("Empty buffer during TLV processing")); - - uint64_t value; - bool isOk = readVarNumber(begin, end, value); - if (!isOk) - BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing")); - - return value; -} - -template<> -inline bool -readVarNumber>(std::istream_iterator& begin, - const std::istream_iterator& end, - uint64_t& value) -{ - if (begin == end) - return false; - - uint8_t firstOctet = *begin; - ++begin; - if (firstOctet < 253) - { - value = firstOctet; - } - else if (firstOctet == 253) - { - value = 0; - size_t count = 0; - for (; begin != end && count < 2; ++count) - { - value = ((value << 8) | *begin); - begin++; - } - - if (count != 2) - return false; - } - else if (firstOctet == 254) - { - value = 0; - size_t count = 0; - for (; begin != end && count < 4; ++count) - { - value = ((value << 8) | *begin); - begin++; - } - - if (count != 4) - return false; - } - else // if (firstOctet == 255) - { - value = 0; - size_t count = 0; - for (; begin != end && count < 8; ++count) - { - value = ((value << 8) | *begin); - begin++; - } - - if (count != 8) - return false; - } - - return true; -} - -template -inline uint32_t -readType(InputIterator& begin, const InputIterator& end) -{ - uint64_t type = readVarNumber(begin, end); - if (type > std::numeric_limits::max()) - { - BOOST_THROW_EXCEPTION(Error("TLV type code exceeds allowed maximum")); - } - - return static_cast(type); -} - -size_t -sizeOfVarNumber(uint64_t varNumber) -{ - if (varNumber < 253) { - return 1; - } - else if (varNumber <= std::numeric_limits::max()) { - return 3; - } - else if (varNumber <= std::numeric_limits::max()) { - return 5; - } - else { - return 9; - } -} - -inline size_t -writeVarNumber(std::ostream& os, uint64_t varNumber) -{ - if (varNumber < 253) { - os.put(static_cast(varNumber)); - return 1; - } - else if (varNumber <= std::numeric_limits::max()) { - os.put(static_cast(253)); - uint16_t value = htobe16(static_cast(varNumber)); - os.write(reinterpret_cast(&value), 2); - return 3; - } - else if (varNumber <= std::numeric_limits::max()) { - os.put(static_cast(254)); - uint32_t value = htobe32(static_cast(varNumber)); - os.write(reinterpret_cast(&value), 4); - return 5; - } - else { - os.put(static_cast(255)); - uint64_t value = htobe64(varNumber); - os.write(reinterpret_cast(&value), 8); - return 9; - } -} - -template -inline uint64_t -readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end) -{ - switch (size) { - case 1: - { - if (end - begin < 1) - BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing")); - - uint8_t value = *begin; - begin++; - return value; - } - case 2: - { - if (end - begin < 2) - BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing")); - - uint16_t value = *reinterpret_cast(&*begin); - begin += 2; - return be16toh(value); - } - case 4: - { - if (end - begin < 4) - BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing")); - - uint32_t value = *reinterpret_cast(&*begin); - begin += 4; - return be32toh(value); - } - case 8: - { - if (end - begin < 8) - BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing")); - - uint64_t value = *reinterpret_cast(&*begin); - begin += 8; - return be64toh(value); - } - } - BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)")); -} - -template<> -inline uint64_t -readNonNegativeInteger >(size_t size, - std::istream_iterator& begin, - const std::istream_iterator& end) -{ - switch (size) { - case 1: - { - if (begin == end) - BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing")); - - uint64_t value = *begin; - begin++; - return value; - } - case 2: - { - uint64_t value = 0; - size_t count = 0; - for (; begin != end && count < 2; ++count) - { - value = ((value << 8) | *begin); - begin++; - } - - if (count != 2) - BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing")); - - return value; - } - case 4: - { - uint64_t value = 0; - size_t count = 0; - for (; begin != end && count < 4; ++count) - { - value = ((value << 8) | *begin); - begin++; - } - - if (count != 4) - BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing")); - - return value; - } - case 8: - { - uint64_t value = 0; - size_t count = 0; - for (; begin != end && count < 8; ++count) - { - value = ((value << 8) | *begin); - begin++; - } - - if (count != 8) - BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing")); - - return value; - } - } - BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)")); -} - -inline size_t -sizeOfNonNegativeInteger(uint64_t varNumber) -{ - if (varNumber < 253) { - return 1; - } - else if (varNumber <= std::numeric_limits::max()) { - return 2; - } - else if (varNumber <= std::numeric_limits::max()) { - return 4; - } - else { - return 8; - } -} - - -inline size_t -writeNonNegativeInteger(std::ostream& os, uint64_t varNumber) -{ - if (varNumber < 253) { - os.put(static_cast(varNumber)); - return 1; - } - else if (varNumber <= std::numeric_limits::max()) { - uint16_t value = htobe16(static_cast(varNumber)); - os.write(reinterpret_cast(&value), 2); - return 2; - } - else if (varNumber <= std::numeric_limits::max()) { - uint32_t value = htobe32(static_cast(varNumber)); - os.write(reinterpret_cast(&value), 4); - return 4; - } - else { - uint64_t value = htobe64(varNumber); - os.write(reinterpret_cast(&value), 8); - return 8; - } -} - - -} // namespace tlv -} // namespace ndn - -#endif // NDN_ENCODING_TLV_HPP diff --git a/src/exclude.cpp b/src/exclude.cpp deleted file mode 100644 index 7007daf1f..000000000 --- a/src/exclude.cpp +++ /dev/null @@ -1,426 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Alexander Afanasyev - */ - -#include "exclude.hpp" -#include "encoding/block-helpers.hpp" - -#include - -namespace ndn { - -Exclude::ExcludeComponent::ExcludeComponent(const name::Component& component1) - : isNegInf(false) - , component(component1) -{ -} - -Exclude::ExcludeComponent::ExcludeComponent(bool isNegInf1) - : isNegInf(true) -{ - BOOST_ASSERT(isNegInf1 == true); -} - -bool -operator==(const Exclude::ExcludeComponent& a, const Exclude::ExcludeComponent& b) -{ - return (a.isNegInf && b.isNegInf) || - (a.isNegInf == b.isNegInf && a.component == b.component); -} - -bool -operator>(const Exclude::ExcludeComponent& a, const Exclude::ExcludeComponent& b) -{ - return a.isNegInf < b.isNegInf || - (a.isNegInf == b.isNegInf && a.component > b.component); -} - -bool -Exclude::Range::operator==(const Exclude::Range& other) const -{ - return this->fromInfinity == other.fromInfinity && this->toInfinity == other.toInfinity && - (this->fromInfinity || this->from == other.from) && - (this->toInfinity || this->to == other.to); -} - -std::ostream& -operator<<(std::ostream& os, const Exclude::Range& range) -{ - if (range.isSingular()) { - return os << '{' << range.from << '}'; - } - - if (range.fromInfinity) { - os << "(-∞"; - } - else { - os << '[' << range.from; - } - - os << ","; - - if (range.toInfinity) { - os << "+∞)"; - } - else { - os << range.to << ']'; - } - - return os; -} - -BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "Exclude::Error must inherit from tlv::Error"); - -Exclude::Exclude() = default; - -Exclude::Exclude(const Block& wire) -{ - wireDecode(wire); -} - -template -size_t -Exclude::wireEncode(EncodingImpl& encoder) const -{ - if (m_entries.empty()) { - BOOST_THROW_EXCEPTION(Error("cannot encode empty Exclude selector")); - } - - size_t totalLength = 0; - - // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+ - // Any ::= ANY-TYPE TLV-LENGTH(=0) - - for (const Entry& entry : m_entries) { - if (entry.second) { - totalLength += prependEmptyBlock(encoder, tlv::Any); - } - if (!entry.first.isNegInf) { - totalLength += entry.first.component.wireEncode(encoder); - } - } - - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::Exclude); - return totalLength; -} - -template size_t -Exclude::wireEncode(EncodingImpl& encoder) const; - -template size_t -Exclude::wireEncode(EncodingImpl& encoder) const; - -const Block& -Exclude::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 -Exclude::wireDecode(const Block& wire) -{ - clear(); - - if (wire.type() != tlv::Exclude) - BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding Exclude")); - - m_wire = wire; - m_wire.parse(); - - if (m_wire.elements_size() == 0) { - BOOST_THROW_EXCEPTION(Error("Exclude element cannot be empty")); - } - - // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+ - // Any ::= ANY-TYPE TLV-LENGTH(=0) - - Block::element_const_iterator i = m_wire.elements_begin(); - if (i->type() == tlv::Any) { - this->appendEntry(true, true); - ++i; - } - - while (i != m_wire.elements_end()) { - name::Component component; - try { - component = name::Component(*i); - } - catch (const name::Component::Error&) { - BOOST_THROW_EXCEPTION(Error("Incorrect format of Exclude filter")); - } - ++i; - - if (i != m_wire.elements_end() && i->type() == tlv::Any) { - this->appendEntry(component, true); - ++i; - } - else { - this->appendEntry(component, false); - } - } -} - -template -void -Exclude::appendEntry(const T& component, bool hasAny) -{ - m_entries.emplace_hint(m_entries.begin(), std::piecewise_construct, - std::forward_as_tuple(component), - std::forward_as_tuple(hasAny)); -} - -// example: ANY "b" "d" ANY "f" -// ordered in map as: "f" (false); "d" (true); "b" (false); -Inf (true) -// -// lower_bound("") -> -Inf (true) <-- excluded (ANY) -// lower_bound("a") -> -Inf (true) <-- excluded (ANY) -// lower_bound("b") -> "b" (false) <--- excluded (equal) -// lower_bound("c") -> "b" (false) <--- not excluded (not equal and no ANY) -// lower_bound("d") -> "d" (true) <- excluded -// lower_bound("e") -> "d" (true) <- excluded -bool -Exclude::isExcluded(const name::Component& comp) const -{ - ExcludeMap::const_iterator lb = m_entries.lower_bound(comp); - return lb != m_entries.end() && // if false, comp is less than the first excluded component - (lb->second || // comp matches an ANY range - (!lb->first.isNegInf && lb->first.component == comp)); // comp equals an exact excluded component -} - -Exclude& -Exclude::excludeOne(const name::Component& comp) -{ - if (!isExcluded(comp)) { - this->appendEntry(comp, false); - m_wire.reset(); - } - return *this; -} - -Exclude& -Exclude::excludeBefore(const name::Component& to) -{ - return excludeRange(ExcludeComponent(true), to); -} - -Exclude& -Exclude::excludeRange(const name::Component& from, const name::Component& to) -{ - return excludeRange(ExcludeComponent(from), to); -} - -// example: ANY "b" "d" ANY "g" -// ordered in map as: "f" (false); "d" (true); "b" (false); -Inf (true) -// possible sequence of operations: -// excludeBefore("a") -> excludeRange(-Inf, "a") -> ANY "a" -// "a" (false); -Inf (true) -// excludeBefore("b") -> excludeRange(-Inf, "b") -> ANY "b" -// "b" (false); -Inf (true) -// excludeRange("e", "g") -> ANY "b" "e" ANY "g" -// "g" (false); "e" (true); "b" (false); -Inf (true) -// excludeRange("d", "f") -> ANY "b" "d" ANY "g" -// "g" (false); "d" (true); "b" (false); -Inf (true) - -Exclude& -Exclude::excludeRange(const ExcludeComponent& from, const name::Component& to) -{ - if (!from.isNegInf && from.component >= to) { - BOOST_THROW_EXCEPTION(Error("Invalid exclude range [" + from.component.toUri() + ", " + to.toUri() + "] " - "(for single name exclude use Exclude::excludeOne)")); - } - - ExcludeMap::iterator newFrom = m_entries.lower_bound(from); - if (newFrom == m_entries.end() || !newFrom->second /*without ANY*/) { - bool isNewEntry = false; - std::tie(newFrom, isNewEntry) = m_entries.emplace(from, true); - if (!isNewEntry) { - // this means that the lower bound is equal to the item itself. So, just update ANY flag - newFrom->second = true; - } - } - // else - // nothing special if start of the range already exists with ANY flag set - - ExcludeMap::iterator newTo = m_entries.lower_bound(to); - BOOST_ASSERT(newTo != m_entries.end()); - if (newTo == newFrom || !newTo->second) { - newTo = m_entries.emplace_hint(newTo, to, false); - ++newTo; - } - // else - // nothing to do really - - // remove any intermediate entries, since all of the are excluded - m_entries.erase(newTo, newFrom); - - m_wire.reset(); - return *this; -} - -Exclude& -Exclude::excludeAfter(const name::Component& from) -{ - ExcludeMap::iterator newFrom = m_entries.lower_bound(from); - if (newFrom == m_entries.end() || !newFrom->second /*without ANY*/) { - bool isNewEntry = false; - std::tie(newFrom, isNewEntry) = m_entries.emplace(from, true); - if (!isNewEntry) { - // this means that the lower bound is equal to the item itself. So, just update ANY flag - newFrom->second = true; - } - } - // else - // nothing special if start of the range already exists with ANY flag set - - // remove any intermediate node, since all of the are excluded - m_entries.erase(m_entries.begin(), newFrom); - - m_wire.reset(); - return *this; -} - -std::ostream& -operator<<(std::ostream& os, const Exclude& exclude) -{ - bool isFirst = true; - for (const Exclude::Entry& entry : exclude.m_entries | boost::adaptors::reversed) { - if (!entry.first.isNegInf) { - if (!isFirst) - os << ","; - entry.first.component.toUri(os); - isFirst = false; - } - if (entry.second) { - if (!isFirst) - os << ","; - os << "*"; - isFirst = false; - } - } - return os; -} - -std::string -Exclude::toUri() const -{ - std::ostringstream os; - os << *this; - return os.str(); -} - -bool -Exclude::operator==(const Exclude& other) const -{ - return m_entries == other.m_entries; -} - -size_t -Exclude::size() const -{ - return std::distance(begin(), end()); -} - -void -Exclude::clear() -{ - m_entries.clear(); - m_wire.reset(); -} - -Exclude::const_iterator::const_iterator(ExcludeMap::const_reverse_iterator it, - ExcludeMap::const_reverse_iterator rend) - : m_it(it) - , m_rend(rend) -{ - this->update(); -} - -Exclude::const_iterator& -Exclude::const_iterator::operator++() -{ - bool wasInRange = m_it->second; - ++m_it; - if (wasInRange && m_it != m_rend) { - BOOST_ASSERT(m_it->second == false); // consecutive ranges should have been combined - ++m_it; // skip over range high limit - } - this->update(); - return *this; -} - -Exclude::const_iterator -Exclude::const_iterator::operator++(int) -{ - const_iterator i = *this; - this->operator++(); - return i; -} - -void -Exclude::const_iterator::update() -{ - if (m_it == m_rend) { - return; - } - - if (m_it->second) { // range - if (m_it->first.isNegInf) { - m_range.fromInfinity = true; - } - else { - m_range.fromInfinity = false; - m_range.from = m_it->first.component; - } - - auto next = std::next(m_it); - if (next == m_rend) { - m_range.toInfinity = true; - } - else { - m_range.toInfinity = false; - m_range.to = next->first.component; - } - } - else { // single - BOOST_ASSERT(!m_it->first.isNegInf); - m_range.fromInfinity = m_range.toInfinity = false; - m_range.from = m_range.to = m_it->first.component; - } -} - -} // namespace ndn diff --git a/src/exclude.hpp b/src/exclude.hpp deleted file mode 100644 index 595f143d7..000000000 --- a/src/exclude.hpp +++ /dev/null @@ -1,368 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Alexander Afanasyev - */ - -#ifndef NDN_EXCLUDE_H -#define NDN_EXCLUDE_H - -#include "name-component.hpp" -#include "encoding/encoding-buffer.hpp" - -#include -#include - -namespace ndn { - -/** - * @brief Represents Exclude selector in NDN Interest - */ -class Exclude -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - - /** - * @brief Constructs an empty Exclude - */ - Exclude(); - - /** - * @brief Create from wire encoding - */ - explicit - Exclude(const Block& wire); - - /** - * @brief Fast encoding or block size estimation - */ - template - size_t - wireEncode(EncodingImpl& encoder) const; - - /** - * @brief Encode to a wire format - */ - const Block& - wireEncode() const; - - /** - * @brief Decode from the wire format - */ - void - wireDecode(const Block& wire); - - /** - * @brief Get escaped string representation (e.g., for use in URI) of the exclude filter - */ - std::string - toUri() const; - -public: // high-level API - /** - * @brief Check if name component is excluded - * @param comp Name component to check against exclude filter - */ - bool - isExcluded(const name::Component& comp) const; - - /** - * @brief Exclude specific name component - * @param comp component to exclude - * @returns *this to allow chaining - */ - Exclude& - excludeOne(const name::Component& comp); - - /** - * @brief Exclude components in range [from, to] - * @param from first element of the range - * @param to last element of the range - * @throw Error \p from equals or comes after \p to in canonical ordering - * @returns *this to allow chaining - */ - Exclude& - excludeRange(const name::Component& from, const name::Component& to); - - /** - * @brief Exclude all components in range (-Inf, to] - * @param to last element of the range - * @returns *this to allow chaining - */ - Exclude& - excludeBefore(const name::Component& to); - - /** - * @brief Exclude all components in range [from, +Inf) - * @param from the first element of the range - * @returns *this to allow chaining - */ - Exclude& - excludeAfter(const name::Component& from); - -public: // EqualityComparable concept - bool - operator==(const Exclude& other) const; - - bool - operator!=(const Exclude& other) const; - -public: // interal storage - /** - * @brief either a name::Component or "negative infinity" - */ - class ExcludeComponent - { - public: - /** - * @brief implicitly construct a regular infinity ExcludeComponent - * @param component a name component which is excluded - */ - ExcludeComponent(const name::Component& component); - - /** - * @brief construct a negative infinity ExcludeComponent - * @param isNegInf must be true - */ - explicit - ExcludeComponent(bool isNegInf); - - public: - bool isNegInf; - name::Component component; - }; - - /** - * @brief a map of exclude entries - * - * Each key, except "negative infinity", is a name component that is excluded. - * The mapped boolean indicates whether the range between a key and the next greater key - * is also excluded. If true, the wire encoding shall have an ANY element. - * - * The map is ordered in descending order to simplify \p isExcluded. - */ - typedef std::map> ExcludeMap; - typedef ExcludeMap::value_type Entry; - -public: // enumeration API - /** - * @brief represent an excluded component or range - */ - class Range - { - public: - /** - * @retval true A single component is excluded - * @retval false A range of more than one components are excluded - */ - bool - isSingular() const; - - bool - operator==(const Exclude::Range& other) const; - - bool - operator!=(const Exclude::Range& other) const; - - public: - /** - * @brief from negative infinity? - */ - bool fromInfinity; - - /** - * @brief from component (inclusive) - * @pre valid only if !fromInfinity - */ - name::Component from; - - /** - * @brief to positive infinity? - */ - bool toInfinity; - - /** - * @brief to component (inclusive) - * @pre valid only if !toInfinity - */ - name::Component to; - }; - - class const_iterator : public std::iterator - { - public: - const_iterator() = default; - - const_iterator(ExcludeMap::const_reverse_iterator it, ExcludeMap::const_reverse_iterator rend); - - const Range& - operator*() const; - - const Range* - operator->() const; - - const_iterator& - operator++(); - - const_iterator - operator++(int); - - bool - operator==(const const_iterator& other) const; - - bool - operator!=(const const_iterator& other) const; - - private: - void - update(); - - private: - ExcludeMap::const_reverse_iterator m_it; - ExcludeMap::const_reverse_iterator m_rend; - Range m_range; - friend class Exclude; - }; - - const_iterator - begin() const; - - const_iterator - end() const; - - bool - empty() const; - - size_t - size() const; - - /// \todo const_iterator erase(const_iterator i); - - void - clear(); - -private: - /** - * @brief directly append exclude element - * @tparam T either name::Component or bool - * - * This method is used during conversion from wire format of exclude filter - */ - template - void - appendEntry(const T& component, bool hasAny); - - Exclude& - excludeRange(const ExcludeComponent& from, const name::Component& to); - -private: - ExcludeMap m_entries; - mutable Block m_wire; - - friend std::ostream& - operator<<(std::ostream& os, const Exclude& name); -}; - -std::ostream& -operator<<(std::ostream& os, const Exclude& name); - -bool -operator==(const Exclude::ExcludeComponent& a, const Exclude::ExcludeComponent& b); - -bool -operator>(const Exclude::ExcludeComponent& a, const Exclude::ExcludeComponent& b); - -std::ostream& -operator<<(std::ostream& os, const Exclude::Range& range); - -inline Exclude::const_iterator -Exclude::begin() const -{ - return const_iterator(m_entries.rbegin(), m_entries.rend()); -} - -inline Exclude::const_iterator -Exclude::end() const -{ - return const_iterator(m_entries.rend(), m_entries.rend()); -} - -inline bool -Exclude::empty() const -{ - return m_entries.empty(); -} - -inline bool -Exclude::operator!=(const Exclude& other) const -{ - return !(*this == other); -} - -inline bool -Exclude::Range::isSingular() const -{ - return !this->fromInfinity && !this->toInfinity && this->from == this->to; -} - -inline bool -Exclude::Range::operator!=(const Exclude::Range& other) const -{ - return !this->operator==(other); -} - -inline const Exclude::Range& -Exclude::const_iterator::operator*() const -{ - BOOST_ASSERT(m_it != m_rend); - return m_range; -} - -inline const Exclude::Range* -Exclude::const_iterator::operator->() const -{ - BOOST_ASSERT(m_it != m_rend); - return &m_range; -} - -inline bool -Exclude::const_iterator::operator==(const const_iterator& other) const -{ - return m_it == other.m_it; -} - -inline bool -Exclude::const_iterator::operator!=(const const_iterator& other) const -{ - return !this->operator==(other); -} - -} // namespace ndn - -#endif // NDN_EXCLUDE_H diff --git a/src/face.cpp b/src/face.cpp deleted file mode 100644 index 430f65e1e..000000000 --- a/src/face.cpp +++ /dev/null @@ -1,566 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "face.hpp" -#include "detail/face-impl.hpp" - -#include "encoding/tlv.hpp" -#include "security/key-chain.hpp" -#include "security/signing-helpers.hpp" -#include "util/time.hpp" -#include "util/random.hpp" -#include "util/face-uri.hpp" - -// A callback scheduled through io.post and io.dispatch may be invoked after the face -// is destructed. To prevent this situation, these macros captures Face::m_impl as weak_ptr, -// and skips callback execution if the face has been destructed. -#define IO_CAPTURE_WEAK_IMPL(OP) \ - { \ - weak_ptr implWeak(m_impl); \ - m_ioService.OP([=] { \ - auto impl = implWeak.lock(); \ - if (impl != nullptr) { -#define IO_CAPTURE_WEAK_IMPL_END \ - } \ - }); \ - } - -namespace ndn { - -Face::Face(shared_ptr transport) - : m_internalIoService(new boost::asio::io_service()) - , m_ioService(*m_internalIoService) - , m_internalKeyChain(new KeyChain()) - , m_impl(make_shared(*this)) -{ - construct(transport, *m_internalKeyChain); -} - -Face::Face(boost::asio::io_service& ioService) - : m_ioService(ioService) - , m_internalKeyChain(new KeyChain()) - , m_impl(make_shared(*this)) -{ - construct(nullptr, *m_internalKeyChain); -} - -Face::Face(const std::string& host, const std::string& port) - : m_internalIoService(new boost::asio::io_service()) - , m_ioService(*m_internalIoService) - , m_internalKeyChain(new KeyChain()) - , m_impl(make_shared(*this)) -{ - construct(make_shared(host, port), *m_internalKeyChain); -} - -Face::Face(shared_ptr transport, KeyChain& keyChain) - : m_internalIoService(new boost::asio::io_service()) - , m_ioService(*m_internalIoService) - , m_impl(make_shared(*this)) -{ - construct(transport, keyChain); -} - -Face::Face(shared_ptr transport, boost::asio::io_service& ioService) - : m_ioService(ioService) - , m_internalKeyChain(new KeyChain()) - , m_impl(make_shared(*this)) -{ - construct(transport, *m_internalKeyChain); -} - -Face::Face(shared_ptr transport, boost::asio::io_service& ioService, KeyChain& keyChain) - : m_ioService(ioService) - , m_impl(make_shared(*this)) -{ - construct(transport, keyChain); -} - -shared_ptr -Face::makeDefaultTransport() -{ - // transport=unix:///var/run/nfd.sock - // transport=tcp://localhost:6363 - - std::string transportUri; - - const char* transportEnviron = getenv("NDN_CLIENT_TRANSPORT"); - if (transportEnviron != nullptr) { - transportUri = transportEnviron; - } - else { - ConfigFile config; - transportUri = config.getParsedConfiguration().get("transport", ""); - } - - if (transportUri.empty()) { - // transport not specified, use default Unix transport. - return UnixTransport::create(""); - } - - std::string protocol; - try { - util::FaceUri uri(transportUri); - protocol = uri.getScheme(); - - if (protocol == "unix") { - return UnixTransport::create(transportUri); - } - else if (protocol == "tcp" || protocol == "tcp4" || protocol == "tcp6") { - return TcpTransport::create(transportUri); - } - else { - BOOST_THROW_EXCEPTION(ConfigFile::Error("Unsupported transport protocol \"" + protocol + "\"")); - } - } - catch (const Transport::Error& error) { - BOOST_THROW_EXCEPTION(ConfigFile::Error(error.what())); - } - catch (const util::FaceUri::Error& error) { - BOOST_THROW_EXCEPTION(ConfigFile::Error(error.what())); - } -} - -void -Face::construct(shared_ptr transport, KeyChain& keyChain) -{ - if (transport == nullptr) { - transport = makeDefaultTransport(); - } - BOOST_ASSERT(transport != nullptr); - m_transport = transport; - - m_nfdController.reset(new nfd::Controller(*this, keyChain)); - - IO_CAPTURE_WEAK_IMPL(post) { - impl->ensureConnected(false); - } IO_CAPTURE_WEAK_IMPL_END -} - -Face::~Face() = default; - -shared_ptr -Face::getTransport() -{ - return m_transport; -} - -const PendingInterestId* -Face::expressInterest(const Interest& interest, - const DataCallback& afterSatisfied, - const NackCallback& afterNacked, - const TimeoutCallback& afterTimeout) -{ - shared_ptr interestToExpress = make_shared(interest); - - // Use `interestToExpress` to avoid wire format creation for the original Interest - if (interestToExpress->wireEncode().size() > MAX_NDN_PACKET_SIZE) { - BOOST_THROW_EXCEPTION(Error("Interest size exceeds maximum limit")); - } - - // If the same ioService thread, dispatch directly calls the method - IO_CAPTURE_WEAK_IMPL(dispatch) { - impl->asyncExpressInterest(interestToExpress, afterSatisfied, afterNacked, afterTimeout); - } IO_CAPTURE_WEAK_IMPL_END - - return reinterpret_cast(interestToExpress.get()); -} - -const PendingInterestId* -Face::expressInterest(const Interest& interest, - const OnData& onData, - const OnTimeout& onTimeout) -{ - return this->expressInterest( - interest, - [onData] (const Interest& interest, const Data& data) { - if (onData != nullptr) { - onData(interest, const_cast(data)); - } - }, - [onTimeout] (const Interest& interest, const lp::Nack& nack) { - if (onTimeout != nullptr) { - onTimeout(interest); - } - }, - onTimeout - ); -} - -const PendingInterestId* -Face::expressInterest(const Name& name, const Interest& tmpl, - const OnData& onData, const OnTimeout& onTimeout) -{ - return expressInterest(Interest(tmpl).setName(name).setNonce(0), - onData, onTimeout); -} - -void -Face::removePendingInterest(const PendingInterestId* pendingInterestId) -{ - IO_CAPTURE_WEAK_IMPL(post) { - impl->asyncRemovePendingInterest(pendingInterestId); - } IO_CAPTURE_WEAK_IMPL_END -} - -void -Face::removeAllPendingInterests() -{ - IO_CAPTURE_WEAK_IMPL(post) { - impl->asyncRemoveAllPendingInterests(); - } IO_CAPTURE_WEAK_IMPL_END -} - -size_t -Face::getNPendingInterests() const -{ - return m_impl->m_pendingInterestTable.size(); -} - -void -Face::put(const Data& data) -{ - Block wire = data.wireEncode(); - - lp::Packet packet; - bool hasLpFields = false; - - shared_ptr cachePolicyTag = data.getTag(); - if (cachePolicyTag != nullptr) { - packet.add(*cachePolicyTag); - hasLpFields = true; - } - - shared_ptr congestionMarkTag = data.getTag(); - if (congestionMarkTag != nullptr) { - packet.add(*congestionMarkTag); - hasLpFields = true; - } - - if (hasLpFields) { - packet.add(std::make_pair(wire.begin(), wire.end())); - wire = packet.wireEncode(); - } - - if (wire.size() > MAX_NDN_PACKET_SIZE) - BOOST_THROW_EXCEPTION(Error("Data size exceeds maximum limit")); - - IO_CAPTURE_WEAK_IMPL(dispatch) { - impl->asyncSend(wire); - } IO_CAPTURE_WEAK_IMPL_END -} - -void -Face::put(const lp::Nack& nack) -{ - lp::Packet packet; - packet.add(nack.getHeader()); - const Block& interestWire = nack.getInterest().wireEncode(); - packet.add(std::make_pair(interestWire.begin(), interestWire.end())); - - shared_ptr congestionMarkTag = nack.getTag(); - if (congestionMarkTag != nullptr) { - packet.add(*congestionMarkTag); - } - - Block wire = packet.wireEncode(); - - if (wire.size() > MAX_NDN_PACKET_SIZE) - BOOST_THROW_EXCEPTION(Error("Nack size exceeds maximum limit")); - - IO_CAPTURE_WEAK_IMPL(dispatch) { - impl->asyncSend(wire); - } IO_CAPTURE_WEAK_IMPL_END -} - -const RegisteredPrefixId* -Face::setInterestFilter(const InterestFilter& interestFilter, - const InterestCallback& onInterest, - const RegisterPrefixFailureCallback& onFailure, - const security::SigningInfo& signingInfo, - uint64_t flags) -{ - return setInterestFilter(interestFilter, onInterest, nullptr, onFailure, signingInfo, flags); -} - -const RegisteredPrefixId* -Face::setInterestFilter(const InterestFilter& interestFilter, - const InterestCallback& onInterest, - const RegisterPrefixSuccessCallback& onSuccess, - const RegisterPrefixFailureCallback& onFailure, - const security::SigningInfo& signingInfo, - uint64_t flags) -{ - auto filter = make_shared(interestFilter, onInterest); - - nfd::CommandOptions options; - options.setSigningInfo(signingInfo); - - return m_impl->registerPrefix(interestFilter.getPrefix(), filter, - onSuccess, onFailure, flags, options); -} - -const InterestFilterId* -Face::setInterestFilter(const InterestFilter& interestFilter, - const InterestCallback& onInterest) -{ - auto filter = make_shared(interestFilter, onInterest); - - IO_CAPTURE_WEAK_IMPL(post) { - impl->asyncSetInterestFilter(filter); - } IO_CAPTURE_WEAK_IMPL_END - - return reinterpret_cast(filter.get()); -} - -#ifdef NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING - -const RegisteredPrefixId* -Face::setInterestFilter(const InterestFilter& interestFilter, - const OnInterest& onInterest, - const RegisterPrefixSuccessCallback& onSuccess, - const RegisterPrefixFailureCallback& onFailure, - const security::v1::IdentityCertificate& certificate, - uint64_t flags) -{ - security::SigningInfo signingInfo; - if (!certificate.getName().empty()) { - signingInfo = signingByCertificate(certificate.getName()); - } - return setInterestFilter(interestFilter, onInterest, onSuccess, onFailure, signingInfo, flags); -} - -const RegisteredPrefixId* -Face::setInterestFilter(const InterestFilter& interestFilter, - const OnInterest& onInterest, - const RegisterPrefixFailureCallback& onFailure, - const security::v1::IdentityCertificate& certificate, - uint64_t flags) -{ - security::SigningInfo signingInfo; - if (!certificate.getName().empty()) { - signingInfo = signingByCertificate(certificate.getName()); - } - return setInterestFilter(interestFilter, onInterest, onFailure, signingInfo, flags); -} - -const RegisteredPrefixId* -Face::setInterestFilter(const InterestFilter& interestFilter, - const OnInterest& onInterest, - const RegisterPrefixSuccessCallback& onSuccess, - const RegisterPrefixFailureCallback& onFailure, - const Name& identity, - uint64_t flags) -{ - security::SigningInfo signingInfo = signingByIdentity(identity); - return setInterestFilter(interestFilter, onInterest, - onSuccess, onFailure, - signingInfo, flags); -} - -const RegisteredPrefixId* -Face::setInterestFilter(const InterestFilter& interestFilter, - const OnInterest& onInterest, - const RegisterPrefixFailureCallback& onFailure, - const Name& identity, - uint64_t flags) -{ - security::SigningInfo signingInfo = signingByIdentity(identity); - return setInterestFilter(interestFilter, onInterest, onFailure, signingInfo, flags); -} - -#endif // NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING - -const RegisteredPrefixId* -Face::registerPrefix(const Name& prefix, - const RegisterPrefixSuccessCallback& onSuccess, - const RegisterPrefixFailureCallback& onFailure, - const security::SigningInfo& signingInfo, - uint64_t flags) -{ - nfd::CommandOptions options; - options.setSigningInfo(signingInfo); - - return m_impl->registerPrefix(prefix, nullptr, onSuccess, onFailure, flags, options); -} - -#ifdef NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING -const RegisteredPrefixId* -Face::registerPrefix(const Name& prefix, - const RegisterPrefixSuccessCallback& onSuccess, - const RegisterPrefixFailureCallback& onFailure, - const security::v1::IdentityCertificate& certificate, - uint64_t flags) -{ - security::SigningInfo signingInfo; - if (!certificate.getName().empty()) { - signingInfo = signingByCertificate(certificate.getName()); - } - return registerPrefix(prefix, onSuccess, onFailure, signingInfo, flags); -} - -const RegisteredPrefixId* -Face::registerPrefix(const Name& prefix, - const RegisterPrefixSuccessCallback& onSuccess, - const RegisterPrefixFailureCallback& onFailure, - const Name& identity, - uint64_t flags) -{ - security::SigningInfo signingInfo = signingByIdentity(identity); - return registerPrefix(prefix, onSuccess, onFailure, signingInfo, flags); -} -#endif // NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING - -void -Face::unsetInterestFilter(const RegisteredPrefixId* registeredPrefixId) -{ - IO_CAPTURE_WEAK_IMPL(post) { - impl->asyncUnregisterPrefix(registeredPrefixId, nullptr, nullptr); - } IO_CAPTURE_WEAK_IMPL_END -} - -void -Face::unsetInterestFilter(const InterestFilterId* interestFilterId) -{ - IO_CAPTURE_WEAK_IMPL(post) { - impl->asyncUnsetInterestFilter(interestFilterId); - } IO_CAPTURE_WEAK_IMPL_END -} - -void -Face::unregisterPrefix(const RegisteredPrefixId* registeredPrefixId, - const UnregisterPrefixSuccessCallback& onSuccess, - const UnregisterPrefixFailureCallback& onFailure) -{ - IO_CAPTURE_WEAK_IMPL(post) { - impl->asyncUnregisterPrefix(registeredPrefixId, onSuccess, onFailure); - } IO_CAPTURE_WEAK_IMPL_END -} - -void -Face::doProcessEvents(const time::milliseconds& timeout, bool keepThread) -{ - if (m_ioService.stopped()) { - m_ioService.reset(); // ensure that run()/poll() will do some work - } - - try { - if (timeout < time::milliseconds::zero()) { - // do not block if timeout is negative, but process pending events - m_ioService.poll(); - return; - } - - if (timeout > time::milliseconds::zero()) { - boost::asio::io_service& ioService = m_ioService; - unique_ptr& work = m_impl->m_ioServiceWork; - m_impl->m_processEventsTimeoutEvent = m_impl->m_scheduler.scheduleEvent(timeout, - [&ioService, &work] { - ioService.stop(); - work.reset(); - }); - } - - if (keepThread) { - // work will ensure that m_ioService is running until work object exists - m_impl->m_ioServiceWork.reset(new boost::asio::io_service::work(m_ioService)); - } - - m_ioService.run(); - } - catch (...) { - m_impl->m_ioServiceWork.reset(); - m_impl->m_pendingInterestTable.clear(); - m_impl->m_registeredPrefixTable.clear(); - throw; - } -} - -void -Face::shutdown() -{ - IO_CAPTURE_WEAK_IMPL(post) { - this->asyncShutdown(); - } IO_CAPTURE_WEAK_IMPL_END -} - -void -Face::asyncShutdown() -{ - m_impl->m_pendingInterestTable.clear(); - m_impl->m_registeredPrefixTable.clear(); - - if (m_transport->isConnected()) - m_transport->close(); - - m_impl->m_ioServiceWork.reset(); -} - -/** - * @brief extract local fields from NDNLPv2 packet and tag onto a network layer packet - */ -template -static void -extractLpLocalFields(NetPkt& netPacket, const lp::Packet& lpPacket) -{ - if (lpPacket.has()) { - netPacket.setTag(make_shared(lpPacket.get())); - } - - if (lpPacket.has()) { - netPacket.setTag(make_shared(lpPacket.get())); - } -} - -void -Face::onReceiveElement(const Block& blockFromDaemon) -{ - lp::Packet lpPacket(blockFromDaemon); // bare Interest/Data is a valid lp::Packet, - // no need to distinguish - - Buffer::const_iterator begin, end; - std::tie(begin, end) = lpPacket.get(); - Block netPacket(&*begin, std::distance(begin, end)); - switch (netPacket.type()) { - case tlv::Interest: { - auto interest = make_shared(netPacket); - if (lpPacket.has()) { - auto nack = make_shared(std::move(*interest)); - nack->setHeader(lpPacket.get()); - extractLpLocalFields(*nack, lpPacket); - m_impl->nackPendingInterests(*nack); - } - else { - extractLpLocalFields(*interest, lpPacket); - m_impl->processInterestFilters(*interest); - } - break; - } - case tlv::Data: { - auto data = make_shared(netPacket); - extractLpLocalFields(*data, lpPacket); - m_impl->satisfyPendingInterests(*data); - break; - } - } -} - -} // namespace ndn diff --git a/src/face.hpp b/src/face.hpp deleted file mode 100644 index 6c6c9572f..000000000 --- a/src/face.hpp +++ /dev/null @@ -1,760 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_FACE_HPP -#define NDN_FACE_HPP - -#include "common.hpp" - -#include "name.hpp" -#include "interest.hpp" -#include "interest-filter.hpp" -#include "data.hpp" -#include "encoding/nfd-constants.hpp" -#include "lp/nack.hpp" -#include "security/signing-info.hpp" - -#define NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING - -#ifdef NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING -#include "security/v1/identity-certificate.hpp" -#endif // NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING - -namespace boost { -namespace asio { -class io_service; -} // namespace asio -} // namespace boost - -namespace ndn { - -class Transport; - -class PendingInterestId; -class RegisteredPrefixId; -class InterestFilterId; - -namespace security { -class KeyChain; -} // namespace security -using security::KeyChain; - -namespace nfd { -class Controller; -} // namespace nfd - -/** - * @brief Callback invoked when expressed Interest gets satisfied with a Data packet - */ -typedef function DataCallback; - -/** - * @brief Callback invoked when Nack is sent in response to expressed Interest - */ -typedef function NackCallback; - -/** - * @brief Callback invoked when expressed Interest times out - */ -typedef function TimeoutCallback; - -/** - * @brief Callback invoked when expressed Interest gets satisfied with Data packet - * @deprecated use DataCallback - */ -typedef function OnData; - -/** - * @brief Callback invoked when expressed Interest times out - * @deprecated use TimeoutCallback - */ -typedef function OnTimeout; - -/** - * @brief Callback invoked when incoming Interest matches the specified InterestFilter - */ -typedef function InterestCallback; - -/** - * @brief Callback invoked when incoming Interest matches the specified InterestFilter - * @deprecated use InterestCallback - */ -typedef function OnInterest; - -/** - * @brief Callback invoked when registerPrefix or setInterestFilter command succeeds - */ -typedef function RegisterPrefixSuccessCallback; - -/** - * @brief Callback invoked when registerPrefix or setInterestFilter command fails - */ -typedef function RegisterPrefixFailureCallback; - -/** - * @brief Callback invoked when unregisterPrefix or unsetInterestFilter command succeeds - */ -typedef function UnregisterPrefixSuccessCallback; - -/** - * @brief Callback invoked when unregisterPrefix or unsetInterestFilter command fails - */ -typedef function UnregisterPrefixFailureCallback; - -/** - * @brief Provide a communication channel with local or remote NDN forwarder - */ -class Face : noncopyable -{ -public: - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - -public: // constructors - /** - * @brief Create Face using given transport (or default transport if omitted) - * @param transport the transport for lower layer communication. If nullptr, - * a default transport will be used. The default transport is - * determined from a FaceUri in NDN_CLIENT_TRANSPORT environ, - * a FaceUri in configuration file 'transport' key, or UnixTransport. - * - * @throw ConfigFile::Error if @p transport is nullptr, and the configuration file cannot be - * parsed or specifies an unsupported protocol - * @note shared_ptr is passed by value because ownership is shared with this class - */ - explicit - Face(shared_ptr transport = nullptr); - - /** - * @brief Create Face using default transport and given io_service - * - * Usage examples: - * - * @code - * Face face1; - * Face face2(face1.getIoService()); - * - * // Now the following ensures that events on both faces are processed - * face1.processEvents(); - * // or face1.getIoService().run(); - * @endcode - * - * or - * - * @code - * boost::asio::io_service ioService; - * Face face1(ioService); - * Face face2(ioService); - * - * ioService.run(); - * @endcode - * - * @param ioService A reference to boost::io_service object that should control all - * IO operations. - * @throw ConfigFile::Error the configuration file cannot be parsed or specifies an unsupported protocol - */ - explicit - Face(boost::asio::io_service& ioService); - - /** - * @brief Create Face using TcpTransport - * - * @param host IP address or hostname of the NDN forwarder - * @param port port number or service name of the NDN forwarder (**default**: "6363") - */ - explicit - Face(const std::string& host, const std::string& port = "6363"); - - /** - * @brief Create Face using given transport and KeyChain - * @param transport the transport for lower layer communication. If nullptr, - * a default transport will be used. - * @param keyChain the KeyChain to sign commands - * - * @sa Face(shared_ptr) - * - * @throw ConfigFile::Error if @p transport is nullptr, and the configuration file cannot be - * parsed or specifies an unsupported protocol - * @note shared_ptr is passed by value because ownership is shared with this class - */ - Face(shared_ptr transport, KeyChain& keyChain); - - /** - * @brief Create Face using given transport and IO service - * @param transport the transport for lower layer communication. If nullptr, - * a default transport will be used. - * @param ioService the io_service that controls all IO operations - * - * @sa Face(boost::asio::io_service&) - * @sa Face(shared_ptr) - * - * @throw ConfigFile::Error if @p transport is nullptr, and the configuration file cannot be - * parsed or specifies an unsupported protocol - * @note shared_ptr is passed by value because ownership is shared with this class - */ - Face(shared_ptr transport, boost::asio::io_service& ioService); - - /** - * @brief Create a new Face using given Transport and IO service - * @param transport the transport for lower layer communication. If nullptr, - * a default transport will be used. - * @param ioService the io_service that controls all IO operations - * @param keyChain the KeyChain to sign commands - * - * @sa Face(boost::asio::io_service&) - * @sa Face(shared_ptr, KeyChain&) - * - * @throw ConfigFile::Error if @p transport is nullptr, and the configuration file cannot be - * parsed or specifies an unsupported protocol - * @note shared_ptr is passed by value because ownership is shared with this class - */ - Face(shared_ptr transport, boost::asio::io_service& ioService, KeyChain& keyChain); - - ~Face(); - -public: // consumer - /** - * @brief Express Interest - * @param interest the Interest; a copy will be made, so that the caller is not - * required to maintain the argument unchanged - * @param afterSatisfied function to be invoked if Data is returned - * @param afterNacked function to be invoked if Network NACK is returned - * @param afterTimeout function to be invoked if neither Data nor Network NACK - * is returned within InterestLifetime - */ - const PendingInterestId* - expressInterest(const Interest& interest, - const DataCallback& afterSatisfied, - const NackCallback& afterNacked, - const TimeoutCallback& afterTimeout); - - /** - * @brief Express Interest - * - * @param interest An Interest to be expressed - * @param onData Callback to be called when a matching data packet is received - * @param onTimeout (optional) A function object to call if the interest times out or is Nacked - * - * @return The pending interest ID which can be used with removePendingInterest - * - * @throw Error when Interest size exceeds maximum limit (MAX_NDN_PACKET_SIZE) - * - * @deprecated use expressInterest(Interest, DataCallback, NackCallback, TimeoutCallback) - */ - const PendingInterestId* - expressInterest(const Interest& interest, - const OnData& onData, - const OnTimeout& onTimeout = nullptr); - - /** - * @brief Express Interest using name and Interest template - * - * @param name Name of the Interest - * @param tmpl Interest template to fill parameters - * @param onData Callback to be called when a matching data packet is received - * @param onTimeout (optional) A function object to call if the interest times out or is Nacked - * - * @return Opaque pending interest ID which can be used with removePendingInterest - * - * @throw Error when Interest size exceeds maximum limit (MAX_NDN_PACKET_SIZE) - * - * @deprecated use expressInterest(Interest, DataCallback, NackCallback, TimeoutCallback) - */ - const PendingInterestId* - expressInterest(const Name& name, - const Interest& tmpl, - const OnData& onData, - const OnTimeout& onTimeout = nullptr); - - /** - * @brief Cancel previously expressed Interest - * - * @param pendingInterestId The ID returned from expressInterest. - */ - void - removePendingInterest(const PendingInterestId* pendingInterestId); - - /** - * @brief Cancel all previously expressed Interests - */ - void - removeAllPendingInterests(); - - /** - * @brief Get number of pending Interests - */ - size_t - getNPendingInterests() const; - -public: // producer - /** - * @brief Set InterestFilter to dispatch incoming matching interest to onInterest - * callback and register the filtered prefix with the connected NDN forwarder - * - * This version of setInterestFilter combines setInterestFilter and registerPrefix - * operations and is intended to be used when only one filter for the same prefix needed - * to be set. When multiple names sharing the same prefix should be dispatched to - * different callbacks, use one registerPrefix call, followed (in onSuccess callback) by - * a series of setInterestFilter calls. - * - * @param interestFilter Interest filter (prefix part will be registered with the forwarder) - * @param onInterest A callback to be called when a matching interest is received - * @param onFailure A callback to be called when prefixRegister command fails - * @param flags (optional) RIB flags - * @param signingInfo (optional) Signing parameters. When omitted, a default parameters - * used in the signature will be used. - * - * @return Opaque registered prefix ID which can be used with unsetInterestFilter or - * removeRegisteredPrefix - */ - const RegisteredPrefixId* - setInterestFilter(const InterestFilter& interestFilter, - const InterestCallback& onInterest, - const RegisterPrefixFailureCallback& onFailure, - const security::SigningInfo& signingInfo = security::SigningInfo(), - uint64_t flags = nfd::ROUTE_FLAG_CHILD_INHERIT); - - /** - * @brief Set InterestFilter to dispatch incoming matching interest to onInterest - * callback and register the filtered prefix with the connected NDN forwarder - * - * This version of setInterestFilter combines setInterestFilter and registerPrefix - * operations and is intended to be used when only one filter for the same prefix needed - * to be set. When multiple names sharing the same prefix should be dispatched to - * different callbacks, use one registerPrefix call, followed (in onSuccess callback) by - * a series of setInterestFilter calls. - * - * @param interestFilter Interest filter (prefix part will be registered with the forwarder) - * @param onInterest A callback to be called when a matching interest is received - * @param onSuccess A callback to be called when prefixRegister command succeeds - * @param onFailure A callback to be called when prefixRegister command fails - * @param flags (optional) RIB flags - * @param signingInfo (optional) Signing parameters. When omitted, a default parameters - * used in the signature will be used. - * - * @return Opaque registered prefix ID which can be used with unsetInterestFilter or - * removeRegisteredPrefix - */ - const RegisteredPrefixId* - setInterestFilter(const InterestFilter& interestFilter, - const InterestCallback& onInterest, - const RegisterPrefixSuccessCallback& onSuccess, - const RegisterPrefixFailureCallback& onFailure, - const security::SigningInfo& signingInfo = security::SigningInfo(), - uint64_t flags = nfd::ROUTE_FLAG_CHILD_INHERIT); - - /** - * @brief Set InterestFilter to dispatch incoming matching interest to onInterest callback - * - * @param interestFilter Interest - * @param onInterest A callback to be called when a matching interest is received - * - * This method modifies library's FIB only, and does not register the prefix with the - * forwarder. It will always succeed. To register prefix with the forwarder, use - * registerPrefix, or use the setInterestFilter overload taking two callbacks. - * - * @return Opaque interest filter ID which can be used with unsetInterestFilter - */ - const InterestFilterId* - setInterestFilter(const InterestFilter& interestFilter, - const InterestCallback& onInterest); - -#ifdef NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING - /** - * @deprecated Use override with SigningInfo instead of this function - * @brief Set InterestFilter to dispatch incoming matching interest to onInterest - * callback and register the filtered prefix with the connected NDN forwarder - * - * This version of setInterestFilter combines setInterestFilter and registerPrefix - * operations and is intended to be used when only one filter for the same prefix needed - * to be set. When multiple names sharing the same prefix should be dispatched to - * different callbacks, use one registerPrefix call, followed (in onSuccess callback) by - * a series of setInterestFilter calls. - * - * @param interestFilter Interest filter (prefix part will be registered with the forwarder) - * @param onInterest A callback to be called when a matching interest is received - * @param onSuccess A callback to be called when prefixRegister command succeeds - * @param onFailure A callback to be called when prefixRegister command fails - * @param flags (optional) RIB flags - * @param certificate (optional) A certificate under which the prefix registration - * command is signed. When omitted, a default certificate of - * the default identity is used to sign the registration command - * - * @return Opaque registered prefix ID which can be used with unsetInterestFilter or - * removeRegisteredPrefix - */ - DEPRECATED( - const RegisteredPrefixId* - setInterestFilter(const InterestFilter& interestFilter, - const OnInterest& onInterest, - const RegisterPrefixSuccessCallback& onSuccess, - const RegisterPrefixFailureCallback& onFailure, - const security::v1::IdentityCertificate& certificate, - uint64_t flags = nfd::ROUTE_FLAG_CHILD_INHERIT)); - - /** - * @deprecated Use override with SigningInfo instead of this function - * @brief Set InterestFilter to dispatch incoming matching interest to onInterest - * callback and register the filtered prefix with the connected NDN forwarder - * - * This version of setInterestFilter combines setInterestFilter and registerPrefix - * operations and is intended to be used when only one filter for the same prefix needed - * to be set. When multiple names sharing the same prefix should be dispatched to - * different callbacks, use one registerPrefix call, followed (in onSuccess callback) by - * a series of setInterestFilter calls. - * - * @param interestFilter Interest filter (prefix part will be registered with the forwarder) - * @param onInterest A callback to be called when a matching interest is received - * @param onFailure A callback to be called when prefixRegister command fails - * @param flags (optional) RIB flags - * @param certificate (optional) A certificate under which the prefix registration - * command is signed. When omitted, a default certificate of - * the default identity is used to sign the registration command - * - * @return Opaque registered prefix ID which can be used with unsetInterestFilter or - * removeRegisteredPrefix - */ - DEPRECATED( - const RegisteredPrefixId* - setInterestFilter(const InterestFilter& interestFilter, - const OnInterest& onInterest, - const RegisterPrefixFailureCallback& onFailure, - const security::v1::IdentityCertificate& certificate, - uint64_t flags = nfd::ROUTE_FLAG_CHILD_INHERIT)); - - /** - * @deprecated Use override with SigningInfo instead of this function - * @brief Set InterestFilter to dispatch incoming matching interest to onInterest - * callback and register the filtered prefix with the connected NDN forwarder - * - * This version of setInterestFilter combines setInterestFilter and registerPrefix - * operations and is intended to be used when only one filter for the same prefix needed - * to be set. When multiple names sharing the same prefix should be dispatched to - * different callbacks, use one registerPrefix call, followed (in onSuccess callback) by - * a series of setInterestFilter calls. - * - * @param interestFilter Interest filter (prefix part will be registered with the forwarder) - * @param onInterest A callback to be called when a matching interest is received - * @param onSuccess A callback to be called when prefixRegister command succeeds - * @param onFailure A callback to be called when prefixRegister command fails - * @param identity A signing identity. A prefix registration command is signed - * under the default certificate of this identity - * @param flags (optional) RIB flags - * - * @return Opaque registered prefix ID which can be used with removeRegisteredPrefix - */ - DEPRECATED( - const RegisteredPrefixId* - setInterestFilter(const InterestFilter& interestFilter, - const OnInterest& onInterest, - const RegisterPrefixSuccessCallback& onSuccess, - const RegisterPrefixFailureCallback& onFailure, - const Name& identity, - uint64_t flags = nfd::ROUTE_FLAG_CHILD_INHERIT)); - - /** - * @deprecated Use override with SigningInfo instead of this function - * @brief Set InterestFilter to dispatch incoming matching interest to onInterest - * callback and register the filtered prefix with the connected NDN forwarder - * - * This version of setInterestFilter combines setInterestFilter and registerPrefix - * operations and is intended to be used when only one filter for the same prefix needed - * to be set. When multiple names sharing the same prefix should be dispatched to - * different callbacks, use one registerPrefix call, followed (in onSuccess callback) by - * a series of setInterestFilter calls. - * - * @param interestFilter Interest filter (prefix part will be registered with the forwarder) - * @param onInterest A callback to be called when a matching interest is received - * @param onFailure A callback to be called when prefixRegister command fails - * @param identity A signing identity. A prefix registration command is signed - * under the default certificate of this identity - * @param flags (optional) RIB flags - * - * @return Opaque registered prefix ID which can be used with removeRegisteredPrefix - */ - DEPRECATED( - const RegisteredPrefixId* - setInterestFilter(const InterestFilter& interestFilter, - const OnInterest& onInterest, - const RegisterPrefixFailureCallback& onFailure, - const Name& identity, - uint64_t flags = nfd::ROUTE_FLAG_CHILD_INHERIT)); -#endif // NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING - - /** - * @brief Register prefix with the connected NDN forwarder - * - * This method only modifies forwarder's RIB and does not associate any - * onInterest callbacks. Use setInterestFilter method to dispatch incoming Interests to - * the right callbacks. - * - * @param prefix A prefix to register with the connected NDN forwarder - * @param onSuccess A callback to be called when prefixRegister command succeeds - * @param onFailure A callback to be called when prefixRegister command fails - * @param signingInfo (optional) Signing parameters. When omitted, a default parameters - * used in the signature will be used. - * @param flags Prefix registration flags - * - * @return The registered prefix ID which can be used with unregisterPrefix - * @see nfd::RouteFlags - */ - const RegisteredPrefixId* - registerPrefix(const Name& prefix, - const RegisterPrefixSuccessCallback& onSuccess, - const RegisterPrefixFailureCallback& onFailure, - const security::SigningInfo& signingInfo = security::SigningInfo(), - uint64_t flags = nfd::ROUTE_FLAG_CHILD_INHERIT); - -#ifdef NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING - /** - * @deprecated Use override with SigningInfo instead of this function - * @brief Register prefix with the connected NDN forwarder - * - * This method only modifies forwarder's RIB and does not associate any - * onInterest callbacks. Use setInterestFilter method to dispatch incoming Interests to - * the right callbacks. - * - * @param prefix A prefix to register with the connected NDN forwarder - * @param onSuccess A callback to be called when prefixRegister command succeeds - * @param onFailure A callback to be called when prefixRegister command fails - * @param certificate (optional) A certificate under which the prefix registration - * command is signed. When omitted, a default certificate of - * the default identity is used to sign the registration command - * @param flags (optional) RIB flags - * - * @return The registered prefix ID which can be used with unregisterPrefix - */ - DEPRECATED( - const RegisteredPrefixId* - registerPrefix(const Name& prefix, - const RegisterPrefixSuccessCallback& onSuccess, - const RegisterPrefixFailureCallback& onFailure, - const security::v1::IdentityCertificate& certificate, - uint64_t flags = nfd::ROUTE_FLAG_CHILD_INHERIT)); - - /** - * @deprecated Use override with SigningInfo instead of this function - * @brief Register prefix with the connected NDN forwarder and call onInterest when a matching - * interest is received. - * - * This method only modifies forwarder's RIB and does not associate any - * onInterest callbacks. Use setInterestFilter method to dispatch incoming Interests to - * the right callbacks. - * - * @param prefix A prefix to register with the connected NDN forwarder - * @param onSuccess A callback to be called when prefixRegister command succeeds - * @param onFailure A callback to be called when prefixRegister command fails - * @param identity A signing identity. A prefix registration command is signed - * under the default certificate of this identity - * @param flags (optional) RIB flags - * - * @return The registered prefix ID which can be used with unregisterPrefix - */ - DEPRECATED( - const RegisteredPrefixId* - registerPrefix(const Name& prefix, - const RegisterPrefixSuccessCallback& onSuccess, - const RegisterPrefixFailureCallback& onFailure, - const Name& identity, - uint64_t flags = nfd::ROUTE_FLAG_CHILD_INHERIT)); -#endif // NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING - - /** - * @brief Remove the registered prefix entry with the registeredPrefixId - * - * This does not affect another registered prefix with a different registeredPrefixId, - * even it if has the same prefix name. If there is no entry with the - * registeredPrefixId, do nothing. - * - * unsetInterestFilter will use the same credentials as original - * setInterestFilter/registerPrefix command - * - * @param registeredPrefixId The ID returned from registerPrefix - */ - void - unsetInterestFilter(const RegisteredPrefixId* registeredPrefixId); - - /** - * @brief Remove previously set InterestFilter from library's FIB - * - * This method always succeeds and will **NOT** send any request to the connected - * forwarder. - * - * @param interestFilterId The ID returned from setInterestFilter. - */ - void - unsetInterestFilter(const InterestFilterId* interestFilterId); - - /** - * @brief Unregister prefix from RIB - * - * unregisterPrefix will use the same credentials as original - * setInterestFilter/registerPrefix command - * - * If registeredPrefixId was obtained using setInterestFilter, the corresponding - * InterestFilter will be unset too. - * - * @param registeredPrefixId The ID returned from registerPrefix - * @param onSuccess Callback to be called when operation succeeds - * @param onFailure Callback to be called when operation fails - */ - void - unregisterPrefix(const RegisteredPrefixId* registeredPrefixId, - const UnregisterPrefixSuccessCallback& onSuccess, - const UnregisterPrefixFailureCallback& onFailure); - - /** - * @brief Publish data packet - * - * This method can be called to satisfy the incoming Interest or to put Data packet into - * the cache of the local NDN forwarder. - * - * @param data Data packet to publish. It is highly recommended to use Data packet that - * was created using make_shared(...). Otherwise, put() will make an - * extra copy of the Data packet to ensure validity of published Data until - * asynchronous put() operation finishes. - * - * @throw Error when Data size exceeds maximum limit (MAX_NDN_PACKET_SIZE) - */ - void - put(const Data& data); - - /** - * @brief sends a Network NACK - * @param nack the Nack; a copy will be made, so that the caller is not required to - * maintain the argument unchanged - */ - void - put(const lp::Nack& nack); - -public: // IO routine - /** - * @brief Process any data to receive or call timeout callbacks. - * - * This call will block forever (default timeout == 0) to process IO on the face. - * To exit, one expected to call face.shutdown() from one of the callback methods. - * - * If positive timeout is specified, then processEvents will exit after this timeout, if - * not stopped earlier with face.shutdown() or when all active events finish. The call - * can be called repeatedly, if desired. - * - * If negative timeout is specified, then processEvents will not block and process only - * pending events. - * - * @param timeout maximum time to block the thread - * @param keepThread Keep thread in a blocked state (in event processing), even when - * there are no outstanding events (e.g., no Interest/Data is expected) - * - * @throw This may throw an exception for reading data or in the callback for processing - * the data. If you call this from an main event loop, you may want to catch and - * log/disregard all exceptions. - */ - void - processEvents(const time::milliseconds& timeout = time::milliseconds::zero(), - bool keepThread = false) - { - this->doProcessEvents(timeout, keepThread); - } - - /** - * @brief Shutdown face operations - * - * This method cancels all pending operations and closes connection to NDN Forwarder. - * - * Note that this method does not stop IO service and if the same IO service is shared - * between multiple Faces or with other IO objects (e.g., Scheduler). - */ - void - shutdown(); - - /** - * @return reference to IO service object - */ - boost::asio::io_service& - getIoService() - { - return m_ioService; - } - -NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED: - /** - * @return underlying transport - */ - shared_ptr - getTransport(); - -protected: - virtual void - doProcessEvents(const time::milliseconds& timeout, bool keepThread); - -private: - /** - * @throw ConfigFile::Error on parse error and unsupported protocols - */ - shared_ptr - makeDefaultTransport(); - - /** - * @throw Face::Error on unsupported protocol - * @note shared_ptr is passed by value because ownership is transferred to this function - */ - void - construct(shared_ptr transport, KeyChain& keyChain); - - void - onReceiveElement(const Block& blockFromDaemon); - - void - asyncShutdown(); - -private: - /// the IO service owned by this Face, could be null - unique_ptr m_internalIoService; - /// the IO service used by this Face - boost::asio::io_service& m_ioService; - - shared_ptr m_transport; - - /** - * @brief if not null, a pointer to an internal KeyChain owned by Face - * @note if a KeyChain is supplied to constructor, this pointer will be null, - * and the passed KeyChain is given to nfdController; - * currently Face does not keep the KeyChain passed in constructor - * because it's not needed, but this may change in the future - */ - unique_ptr m_internalKeyChain; - - unique_ptr m_nfdController; - - class Impl; - shared_ptr m_impl; -}; - -} // namespace ndn - -#endif // NDN_FACE_HPP diff --git a/src/interest.cpp b/src/interest.cpp deleted file mode 100644 index 7f4579f4e..000000000 --- a/src/interest.cpp +++ /dev/null @@ -1,488 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "interest.hpp" -#include "util/random.hpp" -#include "util/crypto.hpp" -#include "data.hpp" - -namespace ndn { - -BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "Interest::Error must inherit from tlv::Error"); - -Interest::Interest() - : m_interestLifetime(time::milliseconds::min()) - , m_selectedDelegationIndex(INVALID_SELECTED_DELEGATION_INDEX) -{ -} - -Interest::Interest(const Name& name) - : m_name(name) - , m_interestLifetime(time::milliseconds::min()) - , m_selectedDelegationIndex(INVALID_SELECTED_DELEGATION_INDEX) -{ -} - -Interest::Interest(const Name& name, const time::milliseconds& interestLifetime) - : m_name(name) - , m_interestLifetime(interestLifetime) - , m_selectedDelegationIndex(INVALID_SELECTED_DELEGATION_INDEX) -{ -} - -Interest::Interest(const Block& wire) -{ - wireDecode(wire); -} - -uint32_t -Interest::getNonce() const -{ - if (!m_nonce.hasWire()) - const_cast(this)->setNonce(random::generateWord32()); - - if (m_nonce.value_size() == sizeof(uint32_t)) - return *reinterpret_cast(m_nonce.value()); - else { - // for compatibility reasons. Should be removed eventually - return readNonNegativeInteger(m_nonce); - } -} - -Interest& -Interest::setNonce(uint32_t nonce) -{ - if (m_wire.hasWire() && m_nonce.value_size() == sizeof(uint32_t)) { - std::memcpy(const_cast(m_nonce.value()), &nonce, sizeof(nonce)); - } - else { - m_nonce = makeBinaryBlock(tlv::Nonce, - reinterpret_cast(&nonce), - sizeof(nonce)); - m_wire.reset(); - } - return *this; -} - -void -Interest::refreshNonce() -{ - if (!hasNonce()) - return; - - uint32_t oldNonce = getNonce(); - uint32_t newNonce = oldNonce; - while (newNonce == oldNonce) - newNonce = random::generateWord32(); - - setNonce(newNonce); -} - -bool -Interest::matchesName(const Name& name) const -{ - if (name.size() < m_name.size()) - return false; - - if (!m_name.isPrefixOf(name)) - return false; - - if (getMinSuffixComponents() >= 0 && - // name must include implicit digest - !(name.size() - m_name.size() >= static_cast(getMinSuffixComponents()))) - return false; - - if (getMaxSuffixComponents() >= 0 && - // name must include implicit digest - !(name.size() - m_name.size() <= static_cast(getMaxSuffixComponents()))) - return false; - - if (!getExclude().empty() && - name.size() > m_name.size() && - getExclude().isExcluded(name[m_name.size()])) - return false; - - return true; -} - -bool -Interest::matchesData(const Data& data) const -{ - size_t interestNameLength = m_name.size(); - const Name& dataName = data.getName(); - size_t fullNameLength = dataName.size() + 1; - - // check MinSuffixComponents - bool hasMinSuffixComponents = getMinSuffixComponents() >= 0; - size_t minSuffixComponents = hasMinSuffixComponents ? - static_cast(getMinSuffixComponents()) : 0; - if (!(interestNameLength + minSuffixComponents <= fullNameLength)) - return false; - - // check MaxSuffixComponents - bool hasMaxSuffixComponents = getMaxSuffixComponents() >= 0; - if (hasMaxSuffixComponents && - !(interestNameLength + getMaxSuffixComponents() >= fullNameLength)) - return false; - - // check prefix - if (interestNameLength == fullNameLength) { - if (m_name.get(-1).isImplicitSha256Digest()) { - if (m_name != data.getFullName()) - return false; - } - else { - // Interest Name is same length as Data full Name, but last component isn't digest - // so there's no possibility of matching - return false; - } - } - else { - // Interest Name is a strict prefix of Data full Name - if (!m_name.isPrefixOf(dataName)) - return false; - } - - // check Exclude - // Exclude won't be violated if Interest Name is same as Data full Name - if (!getExclude().empty() && fullNameLength > interestNameLength) { - if (interestNameLength == fullNameLength - 1) { - // component to exclude is the digest - if (getExclude().isExcluded(data.getFullName().get(interestNameLength))) - return false; - // There's opportunity to inspect the Exclude filter and determine whether - // the digest would make a difference. - // eg. "AA" doesn't exclude any digest - - // fullName not needed; - // "AA" and - // "ffffffffffffffffffffffffffffffff - // " - // excludes all digests - fullName not needed; - // "80000000000000000000000000000000 - // " - // excludes some digests - fullName required - // But Interests that contain the exact Data Name before digest and also - // contain Exclude filter is too rare to optimize for, so we request - // fullName no mater what's in the Exclude filter. - } - else { - // component to exclude is not the digest - if (getExclude().isExcluded(dataName.get(interestNameLength))) - return false; - } - } - - // check PublisherPublicKeyLocator - const KeyLocator& publisherPublicKeyLocator = this->getPublisherPublicKeyLocator(); - if (!publisherPublicKeyLocator.empty()) { - const Signature& signature = data.getSignature(); - const Block& signatureInfo = signature.getInfo(); - Block::element_const_iterator it = signatureInfo.find(tlv::KeyLocator); - if (it == signatureInfo.elements_end()) { - return false; - } - if (publisherPublicKeyLocator.wireEncode() != *it) { - return false; - } - } - - return true; -} - -template -size_t -Interest::wireEncode(EncodingImpl& encoder) const -{ - size_t totalLength = 0; - - // Interest ::= INTEREST-TYPE TLV-LENGTH - // Name - // Selectors? - // Nonce - // InterestLifetime? - // Link? - // SelectedDelegation? - - // (reverse encoding) - - if (hasLink()) { - if (hasSelectedDelegation()) { - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::SelectedDelegation, - m_selectedDelegationIndex); - } - totalLength += encoder.prependBlock(m_link); - } - else { - BOOST_ASSERT(!hasSelectedDelegation()); - } - - // InterestLifetime - if (getInterestLifetime() >= time::milliseconds::zero() && - getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) - { - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::InterestLifetime, - getInterestLifetime().count()); - } - - // Nonce - getNonce(); // to ensure that Nonce is properly set - totalLength += encoder.prependBlock(m_nonce); - - // Selectors - if (hasSelectors()) - { - totalLength += getSelectors().wireEncode(encoder); - } - - // Name - totalLength += getName().wireEncode(encoder); - - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::Interest); - return totalLength; -} - -template size_t -Interest::wireEncode(EncodingImpl& encoder) const; - -template size_t -Interest::wireEncode(EncodingImpl& encoder) const; - -const Block& -Interest::wireEncode() const -{ - if (m_wire.hasWire()) - return m_wire; - - EncodingEstimator estimator; - size_t estimatedSize = wireEncode(estimator); - - EncodingBuffer buffer(estimatedSize, 0); - wireEncode(buffer); - - // to ensure that Nonce block points to the right memory location - const_cast(this)->wireDecode(buffer.block()); - - return m_wire; -} - -void -Interest::wireDecode(const Block& wire) -{ - m_wire = wire; - m_wire.parse(); - - // Interest ::= INTEREST-TYPE TLV-LENGTH - // Name - // Selectors? - // Nonce - // InterestLifetime? - // Link? - // SelectedDelegation? - - if (m_wire.type() != tlv::Interest) - BOOST_THROW_EXCEPTION(Error("Unexpected TLV number when decoding Interest")); - - // Name - m_name.wireDecode(m_wire.get(tlv::Name)); - - // Selectors - Block::element_const_iterator val = m_wire.find(tlv::Selectors); - if (val != m_wire.elements_end()) { - m_selectors.wireDecode(*val); - } - else - m_selectors = Selectors(); - - // Nonce - m_nonce = m_wire.get(tlv::Nonce); - - // InterestLifetime - val = m_wire.find(tlv::InterestLifetime); - if (val != m_wire.elements_end()) { - m_interestLifetime = time::milliseconds(readNonNegativeInteger(*val)); - } - else { - m_interestLifetime = DEFAULT_INTEREST_LIFETIME; - } - - // Link object - m_linkCached.reset(); - val = m_wire.find(tlv::Data); - if (val != m_wire.elements_end()) { - m_link = (*val); - } - else { - m_link = Block(); - } - - // SelectedDelegation - val = m_wire.find(tlv::SelectedDelegation); - if (val != m_wire.elements_end()) { - if (!this->hasLink()) { - BOOST_THROW_EXCEPTION(Error("Interest contains SelectedDelegation, but no LINK object")); - } - uint64_t selectedDelegation = readNonNegativeInteger(*val); - if (selectedDelegation < uint64_t(Link::countDelegationsFromWire(m_link))) { - m_selectedDelegationIndex = static_cast(selectedDelegation); - } - else { - BOOST_THROW_EXCEPTION(Error("Invalid selected delegation index when decoding Interest")); - } - } - else { - m_selectedDelegationIndex = INVALID_SELECTED_DELEGATION_INDEX; - } -} - -bool -Interest::hasLink() const -{ - return m_link.hasWire(); -} - -const Link& -Interest::getLink() const -{ - if (hasLink()) { - if (!m_linkCached) { - m_linkCached = make_shared(m_link); - } - return *m_linkCached; - } - BOOST_THROW_EXCEPTION(Error("There is no encapsulated link object")); -} - -void -Interest::setLink(const Block& link) -{ - m_link = link; - if (!link.hasWire()) { - BOOST_THROW_EXCEPTION(Error("The given link does not have a wire format")); - } - m_wire.reset(); - m_linkCached.reset(); - this->unsetSelectedDelegation(); -} - -void -Interest::unsetLink() -{ - m_link.reset(); - m_wire.reset(); - m_linkCached.reset(); - this->unsetSelectedDelegation(); -} - -bool -Interest::hasSelectedDelegation() const -{ - return m_selectedDelegationIndex != INVALID_SELECTED_DELEGATION_INDEX; -} - -Name -Interest::getSelectedDelegation() const -{ - if (!hasSelectedDelegation()) { - BOOST_THROW_EXCEPTION(Error("There is no encapsulated selected delegation")); - } - return std::get<1>(Link::getDelegationFromWire(m_link, m_selectedDelegationIndex)); -} - -void -Interest::setSelectedDelegation(const Name& delegationName) -{ - size_t delegationIndex = Link::findDelegationFromWire(m_link, delegationName); - if (delegationIndex != INVALID_SELECTED_DELEGATION_INDEX) { - m_selectedDelegationIndex = delegationIndex; - } - else { - BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid selected delegation name")); - } - m_wire.reset(); -} - -void -Interest::setSelectedDelegation(size_t delegationIndex) -{ - if (delegationIndex >= Link(m_link).getDelegations().size()) { - BOOST_THROW_EXCEPTION(Error("Invalid selected delegation index")); - } - m_selectedDelegationIndex = delegationIndex; - m_wire.reset(); -} - -void -Interest::unsetSelectedDelegation() -{ - m_selectedDelegationIndex = INVALID_SELECTED_DELEGATION_INDEX; - m_wire.reset(); -} - -std::ostream& -operator<<(std::ostream& os, const Interest& interest) -{ - os << interest.getName(); - - char delim = '?'; - - if (interest.getMinSuffixComponents() >= 0) { - os << delim << "ndn.MinSuffixComponents=" << interest.getMinSuffixComponents(); - delim = '&'; - } - if (interest.getMaxSuffixComponents() >= 0) { - os << delim << "ndn.MaxSuffixComponents=" << interest.getMaxSuffixComponents(); - delim = '&'; - } - if (interest.getChildSelector() >= 0) { - os << delim << "ndn.ChildSelector=" << interest.getChildSelector(); - delim = '&'; - } - if (interest.getMustBeFresh()) { - os << delim << "ndn.MustBeFresh=" << interest.getMustBeFresh(); - delim = '&'; - } - if (interest.getInterestLifetime() >= time::milliseconds::zero() - && interest.getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) { - os << delim << "ndn.InterestLifetime=" << interest.getInterestLifetime().count(); - delim = '&'; - } - - if (interest.hasNonce()) { - os << delim << "ndn.Nonce=" << interest.getNonce(); - delim = '&'; - } - if (!interest.getExclude().empty()) { - os << delim << "ndn.Exclude=" << interest.getExclude(); - delim = '&'; - } - - return os; -} - -} // namespace ndn diff --git a/src/interest.hpp b/src/interest.hpp deleted file mode 100644 index 14ba33e4a..000000000 --- a/src/interest.hpp +++ /dev/null @@ -1,421 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_INTEREST_HPP -#define NDN_INTEREST_HPP - -#include "name.hpp" -#include "selectors.hpp" -#include "util/time.hpp" -#include "tag-host.hpp" -#include "link.hpp" - -namespace ndn { - -class Data; - -/** @var const unspecified_duration_type DEFAULT_INTEREST_LIFETIME; - * @brief default value for InterestLifetime - */ -const time::milliseconds DEFAULT_INTEREST_LIFETIME = time::milliseconds(4000); - -/** @brief represents an Interest packet - */ -class Interest : public TagHost, public enable_shared_from_this -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - - /** @brief Create a new Interest with an empty name (`ndn:/`) - * @warning In certain contexts that use Interest::shared_from_this(), Interest must be created - * using `make_shared`. Otherwise, .shared_from_this() will throw an exception. - */ - Interest(); - - /** @brief Create a new Interest with the given name - * @param name The name for the interest. - * @note This constructor allows implicit conversion from Name. - * @warning In certain contexts that use Interest::shared_from_this(), Interest must be created - * using `make_shared`. Otherwise, .shared_from_this() will throw an exception. - */ - Interest(const Name& name); - - /** @brief Create a new Interest with the given name and interest lifetime - * @param name The name for the interest. - * @param interestLifetime The interest lifetime in time::milliseconds, or -1 for none. - * @warning In certain contexts that use Interest::shared_from_this(), Interest must be created - * using `make_shared`. Otherwise, .shared_from_this() will throw an exception. - */ - Interest(const Name& name, const time::milliseconds& interestLifetime); - - /** @brief Create from wire encoding - * @warning In certain contexts that use Interest::shared_from_this(), Interest must be created - * using `make_shared`. Otherwise, .shared_from_this() will throw an exception. - */ - explicit - Interest(const Block& wire); - - /** - * @brief Fast encoding or block size estimation - */ - template - size_t - wireEncode(EncodingImpl& encoder) const; - - /** - * @brief Encode to a wire format - */ - const Block& - wireEncode() const; - - /** - * @brief Decode from the wire format - */ - void - wireDecode(const Block& wire); - - /** - * @brief Check if already has wire - */ - bool - hasWire() const - { - return m_wire.hasWire(); - } - - /** - * @brief Encode the name according to the NDN URI Scheme - * - * If there are interest selectors, this method will append "?" and add the selectors as - * a query string. For example, "/test/name?ndn.ChildSelector=1" - */ - std::string - toUri() const; - -public: // Link and forwarding hint - - /** - * @brief Check whether the Interest contains a Link object - * @return True if there is a link object, otherwise false - */ - bool - hasLink() const; - - /** - * @brief Get the link object for this interest - * @return The link object if there is one contained in this interest - * @throws Interest::Error if there is no link object contained in the interest - * @throws tlv::Error if the incorporated link object is malformed - */ - const Link& - getLink() const; - - /** - * @brief Set the link object for this interest - * @param link The link object that will be included in this interest (in wire format) - * @post !hasSelectedDelegation() - */ - void - setLink(const Block& link); - - /** - * @brief Delete the link object for this interest - * @post !hasLink() - */ - void - unsetLink(); - - /** - * @brief Check whether the Interest includes a selected delegation - * @return True if there is a selected delegation, otherwise false - */ - bool - hasSelectedDelegation() const; - - /** - * @brief Get the name of the selected delegation - * @return The name of the selected delegation - * @throw Error SelectedDelegation is not set. - */ - Name - getSelectedDelegation() const; - - /** - * @brief Set the selected delegation - * @param delegationName The name of the selected delegation - * @throw Error Link is not set. - * @throw std::invalid_argument @p delegationName does not exist in Link. - */ - void - setSelectedDelegation(const Name& delegationName); - - /** - * @brief Set the selected delegation - * @param delegationIndex The index of the selected delegation - * @throw Error Link is not set. - * @throw std::out_of_range @p delegationIndex is out of bound in Link. - */ - void - setSelectedDelegation(size_t delegationIndex); - - /** - * @brief Unset the selected delegation - */ - void - unsetSelectedDelegation(); - -public: // matching - /** @brief Check if Interest, including selectors, matches the given @p name - * @param name The name to be matched. If this is a Data name, it shall contain the - * implicit digest component - */ - bool - matchesName(const Name& name) const; - - /** - * @brief Check if Interest can be satisfied by @p data. - * - * This method considers Name, MinSuffixComponents, MaxSuffixComponents, - * PublisherPublicKeyLocator, and Exclude. - * This method does not consider ChildSelector and MustBeFresh. - * - * @todo recognize implicit digest component - */ - bool - matchesData(const Data& data) const; - -public: // Name and guiders - const Name& - getName() const - { - return m_name; - } - - Interest& - setName(const Name& name) - { - m_name = name; - m_wire.reset(); - return *this; - } - - const time::milliseconds& - getInterestLifetime() const - { - return m_interestLifetime; - } - - Interest& - setInterestLifetime(const time::milliseconds& interestLifetime) - { - m_interestLifetime = interestLifetime; - m_wire.reset(); - return *this; - } - - /** @brief Check if Nonce set - */ - bool - hasNonce() const - { - return m_nonce.hasWire(); - } - - /** @brief Get Interest's nonce - * - * If nonce was not set before this call, it will be automatically assigned to a random value - */ - uint32_t - getNonce() const; - - /** @brief Set Interest's nonce - * - * If wire format already exists, this call simply replaces nonce in the - * existing wire format, without resetting and recreating it. - */ - Interest& - setNonce(uint32_t nonce); - - /** @brief Refresh nonce - * - * It's guaranteed that new nonce value differs from the existing one. - * - * If nonce is already set, it will be updated to a different random value. - * If nonce is not set, this method does nothing. - */ - void - refreshNonce(); - -public: // Selectors - /** - * @return true if Interest has any selector present - */ - bool - hasSelectors() const - { - return !m_selectors.empty(); - } - - const Selectors& - getSelectors() const - { - return m_selectors; - } - - Interest& - setSelectors(const Selectors& selectors) - { - m_selectors = selectors; - m_wire.reset(); - return *this; - } - - int - getMinSuffixComponents() const - { - return m_selectors.getMinSuffixComponents(); - } - - Interest& - setMinSuffixComponents(int minSuffixComponents) - { - m_selectors.setMinSuffixComponents(minSuffixComponents); - m_wire.reset(); - return *this; - } - - int - getMaxSuffixComponents() const - { - return m_selectors.getMaxSuffixComponents(); - } - - Interest& - setMaxSuffixComponents(int maxSuffixComponents) - { - m_selectors.setMaxSuffixComponents(maxSuffixComponents); - m_wire.reset(); - return *this; - } - - const KeyLocator& - getPublisherPublicKeyLocator() const - { - return m_selectors.getPublisherPublicKeyLocator(); - } - - Interest& - setPublisherPublicKeyLocator(const KeyLocator& keyLocator) - { - m_selectors.setPublisherPublicKeyLocator(keyLocator); - m_wire.reset(); - return *this; - } - - const Exclude& - getExclude() const - { - return m_selectors.getExclude(); - } - - Interest& - setExclude(const Exclude& exclude) - { - m_selectors.setExclude(exclude); - m_wire.reset(); - return *this; - } - - int - getChildSelector() const - { - return m_selectors.getChildSelector(); - } - - Interest& - setChildSelector(int childSelector) - { - m_selectors.setChildSelector(childSelector); - m_wire.reset(); - return *this; - } - - int - getMustBeFresh() const - { - return m_selectors.getMustBeFresh(); - } - - Interest& - setMustBeFresh(bool mustBeFresh) - { - m_selectors.setMustBeFresh(mustBeFresh); - m_wire.reset(); - return *this; - } - -public: // EqualityComparable concept - bool - operator==(const Interest& other) const - { - return wireEncode() == other.wireEncode(); - } - - bool - operator!=(const Interest& other) const - { - return !(*this == other); - } - -private: - Name m_name; - Selectors m_selectors; - mutable Block m_nonce; - time::milliseconds m_interestLifetime; - - mutable Block m_link; - mutable shared_ptr m_linkCached; - size_t m_selectedDelegationIndex; - mutable Block m_wire; -}; - -std::ostream& -operator<<(std::ostream& os, const Interest& interest); - -inline std::string -Interest::toUri() const -{ - std::ostringstream os; - os << *this; - return os.str(); -} - -} // namespace ndn - -#endif // NDN_INTEREST_HPP diff --git a/src/key-locator.cpp b/src/key-locator.cpp deleted file mode 100644 index 151a70479..000000000 --- a/src/key-locator.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "key-locator.hpp" -#include "encoding/block-helpers.hpp" - -namespace ndn { - -BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "KeyLocator::Error must inherit from tlv::Error"); - -KeyLocator::KeyLocator() - : m_type(KeyLocator_None) -{ -} - -KeyLocator::KeyLocator(const Block& wire) -{ - wireDecode(wire); -} - -KeyLocator::KeyLocator(const Name& name) -{ - setName(name); -} - -template -size_t -KeyLocator::wireEncode(EncodingImpl& encoder) const -{ - // KeyLocator ::= KEY-LOCATOR-TYPE TLV-LENGTH (Name | KeyDigest) - // KeyDigest ::= KEY-DIGEST-TYPE TLV-LENGTH BYTE+ - - size_t totalLength = 0; - - switch (m_type) { - case KeyLocator_None: - break; - case KeyLocator_Name: - totalLength += m_name.wireEncode(encoder); - break; - case KeyLocator_KeyDigest: - totalLength += encoder.prependBlock(m_keyDigest); - break; - default: - BOOST_THROW_EXCEPTION(Error("Unsupported KeyLocator type")); - } - - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::KeyLocator); - return totalLength; -} - -template size_t -KeyLocator::wireEncode(EncodingImpl& encoder) const; - -template size_t -KeyLocator::wireEncode(EncodingImpl& encoder) const; - -const Block& -KeyLocator::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 -KeyLocator::wireDecode(const Block& wire) -{ - if (wire.type() != tlv::KeyLocator) - BOOST_THROW_EXCEPTION(Error("Unexpected TLV type during KeyLocator decoding")); - - m_wire = wire; - m_wire.parse(); - - if (m_wire.elements().empty()) { - m_type = KeyLocator_None; - return; - } - - switch (m_wire.elements_begin()->type()) { - case tlv::Name: - m_type = KeyLocator_Name; - m_name.wireDecode(*m_wire.elements_begin()); - break; - case tlv::KeyDigest: - m_type = KeyLocator_KeyDigest; - m_keyDigest = *m_wire.elements_begin(); - break; - default: - m_type = KeyLocator_Unknown; - break; - } -} - -KeyLocator& -KeyLocator::clear() -{ - m_wire.reset(); - m_type = KeyLocator_None; - m_name.clear(); - m_keyDigest.reset(); - return *this; -} - -const Name& -KeyLocator::getName() const -{ - if (m_type != KeyLocator_Name) - BOOST_THROW_EXCEPTION(Error("KeyLocator type is not Name")); - - return m_name; -} - -KeyLocator& -KeyLocator::setName(const Name& name) -{ - this->clear(); - m_type = KeyLocator_Name; - m_name = name; - return *this; -} - -const Block& -KeyLocator::getKeyDigest() const -{ - if (m_type != KeyLocator_KeyDigest) - BOOST_THROW_EXCEPTION(Error("KeyLocator type is not KeyDigest")); - - return m_keyDigest; -} - -KeyLocator& -KeyLocator::setKeyDigest(const Block& keyDigest) -{ - if (keyDigest.type() != tlv::KeyDigest) - BOOST_THROW_EXCEPTION(Error("expecting KeyDigest block")); - - this->clear(); - m_type = KeyLocator_KeyDigest; - m_keyDigest = keyDigest; - return *this; -} - -KeyLocator& -KeyLocator::setKeyDigest(const ConstBufferPtr& keyDigest) -{ - // WARNING: ConstBufferPtr is shared_ptr - // This function takes a constant reference of a shared pointer. - // It MUST NOT change the reference count of that shared pointer. - - return this->setKeyDigest(makeBinaryBlock(tlv::KeyDigest, keyDigest->get(), keyDigest->size())); -} - -bool -KeyLocator::operator==(const KeyLocator& other) const -{ - return wireEncode() == other.wireEncode(); -} - -} // namespace ndn diff --git a/src/key-locator.hpp b/src/key-locator.hpp deleted file mode 100644 index 8c206e422..000000000 --- a/src/key-locator.hpp +++ /dev/null @@ -1,167 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_KEY_LOCATOR_HPP -#define NDN_KEY_LOCATOR_HPP - -#include "encoding/encoding-buffer.hpp" -#include "name.hpp" - -namespace ndn { - -class KeyLocator -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - - enum Type { - /** \brief indicates KeyLocator is empty (internal use only) - */ - KeyLocator_None = 65535, - /** \brief indicates KeyLocator contains a Name - */ - KeyLocator_Name = 0, - /** \brief indicates KeyLocator contains a KeyDigest - */ - KeyLocator_KeyDigest = 1, - /** \brief indicates KeyLocator contains an unknown element - */ - KeyLocator_Unknown = 255 - }; - -public: // constructors - /** \brief construct an empty KeyLocator - */ - KeyLocator(); - - /** \brief construct from wire encoding - */ - explicit - KeyLocator(const Block& wire); - - /** \brief construct from Name - * \note implicit conversion is permitted - */ - KeyLocator(const Name& name); - -public: // encode and decode - /** \brief prepend wire encoding - * \param encoder EncodingBuffer or Estimator - */ - template - size_t - wireEncode(EncodingImpl& encoder) const; - - /** \return wire encoding - */ - const Block& - wireEncode() const; - - /** \brief decode from wire encoding - * \throw Error outer TLV type is not KeyLocator - * \note No error is thrown for unrecognized inner TLV, but type becomes KeyLocator_Unknown. - */ - void - wireDecode(const Block& wire); - -public: // attributes - bool - empty() const - { - return m_type == KeyLocator_None; - } - - Type - getType() const - { - return m_type; - } - - /** \brief clear KeyLocator - * \details type becomes KeyLocator_None - * \return self - */ - KeyLocator& - clear(); - - /** \brief get Name element - * \throw Error if type is not KeyLocator_Name - */ - const Name& - getName() const; - - /** \brief set Name element - * \details type becomes KeyLocator_Name - * \return self - */ - KeyLocator& - setName(const Name& name); - - /** \brief get KeyDigest element - * \throw Error if type is not KeyLocator_KeyDigest - */ - const Block& - getKeyDigest() const; - - /** \brief set KeyDigest element - * \details type becomes KeyLocator_KeyDigest - * \throw Error if Block type is not KeyDigest - * \return self - */ - KeyLocator& - setKeyDigest(const Block& keyDigest); - - /** \brief set KeyDigest value - * \details type becomes KeyLocator_KeyDigest - * \return self - */ - KeyLocator& - setKeyDigest(const ConstBufferPtr& keyDigest); - -public: // EqualityComparable concept - bool - operator==(const KeyLocator& other) const; - - bool - operator!=(const KeyLocator& other) const - { - return !this->operator==(other); - } - -private: - Type m_type; - Name m_name; - Block m_keyDigest; - - mutable Block m_wire; -}; - -} // namespace ndn - -#endif // NDN_KEY_LOCATOR_HPP diff --git a/src/link.cpp b/src/link.cpp deleted file mode 100644 index 587f480c4..000000000 --- a/src/link.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "link.hpp" -#include "interest.hpp" -#include "encoding/block-helpers.hpp" -#include "util/crypto.hpp" -#include "security/key-chain.hpp" - -#include - -#include - -namespace ndn { - -BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "Link::Error should inherit from Data::Error"); - -Link::Link(const Block& block) -{ - wireDecode(block); -} - -Link::Link(const Name& name) - : Data(name) -{ -} - -Link::Link(const Name& name, std::initializer_list> links) - : Data(name) -{ - m_delegations.insert(links); - encodeContent(); -} - -void -Link::addDelegation(uint32_t preference, const Name& name) -{ - this->removeDelegationNoEncode(name); - m_delegations.insert({preference, name}); - encodeContent(); -} - -bool -Link::removeDelegation(const Name& name) -{ - bool hasRemovedDelegation = this->removeDelegationNoEncode(name); - if (hasRemovedDelegation) { - encodeContent(); - } - return hasRemovedDelegation; -} - -const Link::DelegationSet& -Link::getDelegations() const -{ - return m_delegations; -} - -template -size_t -Link::encodeContent(EncodingImpl& encoder) const -{ - // LinkContent ::= CONTENT-TYPE TLV-LENGTH - // Delegation+ - - // Delegation ::= LINK-DELEGATION-TYPE TLV-LENGTH - // Preference - // Name - - // Preference ::= LINK-PREFERENCE-TYPE TLV-LENGTH - // nonNegativeInteger - - size_t totalLength = 0; - for (const auto& delegation : m_delegations | boost::adaptors::reversed) { - size_t delegationLength = 0; - delegationLength += std::get<1>(delegation).wireEncode(encoder); - delegationLength += prependNonNegativeIntegerBlock(encoder, tlv::LinkPreference, - std::get<0>(delegation)); - delegationLength += encoder.prependVarNumber(delegationLength); - delegationLength += encoder.prependVarNumber(tlv::LinkDelegation); - totalLength += delegationLength; - } - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::Content); - return totalLength; -} - -template size_t -Link::encodeContent(EncodingImpl& encoder) const; - -template size_t -Link::encodeContent(EncodingImpl& encoder) const; - -void -Link::encodeContent() -{ - onChanged(); - - EncodingEstimator estimator; - size_t estimatedSize = encodeContent(estimator); - - EncodingBuffer buffer(estimatedSize, 0); - encodeContent(buffer); - - setContentType(tlv::ContentType_Link); - setContent(buffer.block()); -} - -void -Link::decodeContent() -{ - // LinkContent ::= CONTENT-TYPE TLV-LENGTH - // Delegation+ - - // Delegation ::= LINK-DELEGATION-TYPE TLV-LENGTH - // Preference - // Name - - // Preference ::= LINK-PREFERENCE-TYPE TLV-LENGTH - // nonNegativeInteger - - if (getContentType() != tlv::ContentType_Link) - { - BOOST_THROW_EXCEPTION(Error("Expected Content Type Link")); - } - - const Block& content = getContent(); - content.parse(); - - for (auto& delegation : content.elements()) { - delegation.parse(); - Block::element_const_iterator val = delegation.elements_begin(); - if (val == delegation.elements_end()) { - BOOST_THROW_EXCEPTION(Error("Unexpected Link Encoding")); - } - uint32_t preference; - try { - preference = static_cast(readNonNegativeInteger(*val)); - } - catch (tlv::Error&) { - BOOST_THROW_EXCEPTION(Error("Missing Preference field in Link Encoding")); - } - ++val; - if (val == delegation.elements_end()) { - BOOST_THROW_EXCEPTION(Error("Missing Name field in Link Encoding")); - } - Name name(*val); - m_delegations.insert({preference, name}); - } -} - -void -Link::wireDecode(const Block& wire) -{ - Data::wireDecode(wire); - decodeContent(); -} - -std::tuple -Link::getDelegationFromWire(const Block& block, size_t index) -{ - block.parse(); - const Block& contentBlock = block.get(tlv::Content); - contentBlock.parse(); - const Block& delegationBlock = contentBlock.elements().at(index); - delegationBlock.parse(); - if (delegationBlock.type() != tlv::LinkDelegation) { - BOOST_THROW_EXCEPTION(Error("Unexpected TLV-TYPE, expecting LinkDelegation")); - } - return std::make_tuple( - static_cast( - readNonNegativeInteger(delegationBlock.get(tlv::LinkPreference))), - Name(delegationBlock.get(tlv::Name))); -} - -ssize_t -Link::findDelegationFromWire(const Block& block, const Name& delegationName) -{ - block.parse(); - const Block& contentBlock = block.get(tlv::Content); - contentBlock.parse(); - size_t counter = 0; - for (auto&& delegationBlock : contentBlock.elements()) { - delegationBlock.parse(); - if (delegationBlock.type() != tlv::LinkDelegation) { - BOOST_THROW_EXCEPTION(Error("Unexpected TLV-TYPE, expecting LinkDelegation")); - } - Name name(delegationBlock.get(tlv::Name)); - if (name == delegationName) { - return counter; - } - ++counter; - } - return INVALID_SELECTED_DELEGATION_INDEX; -} - -ssize_t -Link::countDelegationsFromWire(const Block& block) -{ - block.parse(); - const Block& contentBlock = block.get(tlv::Content); - contentBlock.parse(); - return contentBlock.elements_size(); -} - -bool -Link::removeDelegationNoEncode(const Name& name) -{ - bool hasRemoved = false; - auto i = m_delegations.begin(); - while (i != m_delegations.end()) { - if (i->second == name) { - hasRemoved = true; - i = m_delegations.erase(i); - } - else { - ++i; - } - } - return hasRemoved; -} - -} // namespace ndn diff --git a/src/link.hpp b/src/link.hpp deleted file mode 100644 index 03b83a6ec..000000000 --- a/src/link.hpp +++ /dev/null @@ -1,184 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_LINK_HPP -#define NDN_LINK_HPP - -#include "data.hpp" -#include - -namespace ndn { - -const size_t INVALID_SELECTED_DELEGATION_INDEX = std::numeric_limits::max(); - -/** @brief represents a Link instance - */ -class Link : public Data -{ -public: - class Error : public Data::Error - { - public: - explicit - Error(const std::string& what) - : Data::Error(what) - { - } - }; - - // The ordering is based on the preference number and needs to be preserved - typedef std::set> DelegationSet; - - /** - * @brief Create an empty Link object - * - * Note that in certain contexts that use Link::shared_from_this(), Link must be - * created using `make_shared`: - * - * shared_ptr linkObject = make_shared(); - * - * Otherwise, Link::shared_from_this() will throw std::bad_weak_ptr. - */ - Link() = default; - - /** - * @brief Create a Link object from a Block - * - * Note that in certain contexts that use Link::shared_from_this(), Link must be - * created using `make_shared`: - * - * shared_ptr linkObject = make_shared(block); - * - * Otherwise, Link::shared_from_this() will throw std::bad_weak_ptr. - */ - explicit - Link(const Block& block); - - /** - * @brief Create a Link object with the given name - * - * @param name A reference to the name of the redirected namespace - * - * Note that in certain contexts that use Link::shared_from_this(), Link must be - * created using `make_shared`: - * - * shared_ptr link = make_shared(name); - * - * Otherwise, Link::shared_from_this() will throw std::bad_weak_ptr. - */ - explicit - Link(const Name& name); - - /** - * @brief Create a Link object with the given name and pairs of - * - * @param name A reference to the name of the redirected namespace - * @param links A reference to the list of pairs of the redirected namespace - * along with its priority - * - * Note that in certain contexts that use Link::shared_from_this(), Link must be - * created using `make_shared`: - * - * shared_ptr link = make_shared(name, links); - * - * Otherwise, Link::shared_from_this() will throw std::bad_weak_ptr. - */ - Link(const Name& name, std::initializer_list> links); - - /** - * @brief Add a delegation in the format of - * @param preference The preference of the delegation to be added - * @param name The name of the delegation to be added - * @note If a delegation with @p name exists, its preference will be updated - */ - void - addDelegation(uint32_t preference, const Name& name); - - /** - * @brief Remove a delegation whose name is @p name - * @param name The name of the delegation to be removed - * @return true if delegation is removed, otherwise false - */ - bool - removeDelegation(const Name& name); - - /** - * @brief Get the pairs of - * @return a set of delegations - */ - const DelegationSet& - getDelegations() const; - - /** - * @brief Decode from the wire format - * @warning This method does not preserve the relative order between delegations. - * To get a delegation by index, use @p getDelegationFromWire method. - */ - void - wireDecode(const Block& wire); - - /** @brief gets the delegation at @p index from @p block - * @param block wire format of a Link object - * @param index 0-based index of a delegation in the Link object - * @return delegation preference and name - * @throw std::out_of_range index is out of range - */ - static std::tuple - getDelegationFromWire(const Block& block, size_t index); - - /** @brief finds index of a delegation with @p delegationName from @p block - * @param block wire format of a Link object - * @param delegationName delegation name in the Link object - * @return 0-based index of the first delegation with @p delegationName , - * or -1 if no such delegation exists - */ - static ssize_t - findDelegationFromWire(const Block& block, const Name& delegationName); - - static ssize_t - countDelegationsFromWire(const Block& block); - -protected: - /** @brief prepend Link object as a Content block to the encoder - * - * The outermost Content element is not part of Link object structure. - */ - template - size_t - encodeContent(EncodingImpl& encoder) const; - - void - encodeContent(); - - void - decodeContent(); - -private: - bool - removeDelegationNoEncode(const Name& name); - -private: - DelegationSet m_delegations; -}; - -} // namespace ndn - -#endif // NDN_LINK_HPP diff --git a/src/lp/cache-policy.cpp b/src/lp/cache-policy.cpp deleted file mode 100644 index 2802b9664..000000000 --- a/src/lp/cache-policy.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Eric Newberry - */ - -#include "cache-policy.hpp" - -namespace ndn { -namespace lp { - -std::ostream& -operator<<(std::ostream& os, CachePolicyType policy) -{ - switch (policy) { - case CachePolicyType::NO_CACHE: - os << "NoCache"; - break; - default: - os << "None"; - break; - } - - return os; -} - -CachePolicy::CachePolicy() - : m_policy(CachePolicyType::NONE) -{ -} - -CachePolicy::CachePolicy(const Block& block) -{ - wireDecode(block); -} - -template -size_t -CachePolicy::wireEncode(EncodingImpl& encoder) const -{ - if (m_policy == CachePolicyType::NONE) { - BOOST_THROW_EXCEPTION(Error("CachePolicyType must be set")); - } - size_t length = 0; - length += prependNonNegativeIntegerBlock(encoder, tlv::CachePolicyType, - static_cast(m_policy)); - length += encoder.prependVarNumber(length); - length += encoder.prependVarNumber(tlv::CachePolicy); - return length; -} - -template size_t -CachePolicy::wireEncode(EncodingImpl& encoder) const; - -template size_t -CachePolicy::wireEncode(EncodingImpl& encoder) const; - -const Block& -CachePolicy::wireEncode() const -{ - if (m_policy == CachePolicyType::NONE) { - BOOST_THROW_EXCEPTION(Error("CachePolicyType must be set")); - } - - 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 -CachePolicy::wireDecode(const Block& wire) -{ - if (wire.type() != tlv::CachePolicy) { - BOOST_THROW_EXCEPTION(Error("expecting CachePolicy block")); - } - - m_wire = wire; - m_wire.parse(); - - Block::element_const_iterator it = m_wire.elements_begin(); - if (it != m_wire.elements_end() && it->type() == tlv::CachePolicyType) { - m_policy = static_cast(readNonNegativeInteger(*it)); - if (this->getPolicy() == CachePolicyType::NONE) { - BOOST_THROW_EXCEPTION(Error("unknown CachePolicyType")); - } - } - else { - BOOST_THROW_EXCEPTION(Error("expecting CachePolicyType block")); - } -} - -CachePolicyType -CachePolicy::getPolicy() const -{ - switch (m_policy) { - case CachePolicyType::NO_CACHE: - return m_policy; - default: - return CachePolicyType::NONE; - } -} - -CachePolicy& -CachePolicy::setPolicy(CachePolicyType policy) -{ - m_policy = policy; - m_wire.reset(); - return *this; -} - -} // namespace lp -} // namespace ndn diff --git a/src/lp/detail/field-decl.hpp b/src/lp/detail/field-decl.hpp deleted file mode 100644 index 792a3405c..000000000 --- a/src/lp/detail/field-decl.hpp +++ /dev/null @@ -1,147 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_CXX_LP_DETAIL_FIELD_DECL_HPP -#define NDN_CXX_LP_DETAIL_FIELD_DECL_HPP - -#include "../field.hpp" -#include "../tlv.hpp" - -#include "../../encoding/block-helpers.hpp" -#include "../../util/concepts.hpp" -#include - -namespace ndn { -namespace lp { -namespace detail { - -template -struct DecodeHelper -{ - static - BOOST_CONCEPT_REQUIRES(((WireDecodable)), (T)) - decode(const Block& wire) - { - T type; - type.wireDecode(wire); - return type; - } -}; - -template -struct DecodeHelper -{ - static uint64_t - decode(const Block& wire) - { - return readNonNegativeInteger(wire); - } -}; - -template -struct DecodeHelper> -{ - static std::pair - decode(const Block& wire) - { - if (wire.value_size() == 0) { - BOOST_THROW_EXCEPTION(ndn::tlv::Error(to_string(wire.type()) + " must not be empty")); - } - - return std::make_pair(wire.value_begin(), wire.value_end()); - } -}; - -template -struct EncodeHelper -{ - static - BOOST_CONCEPT_REQUIRES(((WireEncodable)), (size_t)) - encode(EncodingImpl& encoder, const T& value) - { - return value.wireEncode(encoder); - } -}; - -template -struct EncodeHelper -{ - static size_t - encode(EncodingImpl& encoder, const uint64_t value) - { - return prependNonNegativeIntegerBlock(encoder, TlvType::value, value); - } -}; - -template -struct EncodeHelper> -{ - static size_t - encode(EncodingImpl& encoder, const std::pair& value) - { - size_t length = 0; - length += encoder.prependRange(value.first, value.second); - length += encoder.prependVarNumber(length); - length += encoder.prependVarNumber(TlvType::value); - return length; - } -}; - -template -class FieldDecl -{ -public: - typedef LOCATION FieldLocation; - typedef VALUE ValueType; - typedef std::integral_constant TlvType; - typedef std::integral_constant IsRepeatable; - - /** \brief decodes a field - * \param wire a Block with top-level type \p TYPE - * \return value of the field - */ - static ValueType - decode(const Block& wire) - { - if (wire.type() != TlvType::value) { - BOOST_THROW_EXCEPTION(ndn::tlv::Error("Unexpected TLV type " + to_string(wire.type()))); - } - - return DecodeHelper::decode(wire); - } - - /** \brief encodes a field and prepends to \p encoder its Block with top-level type \p TYPE - * \param encoder Instance of the buffer encoder or buffer estimator - * \param value value of the field - */ - template - static size_t - encode(EncodingImpl& encoder, const T& value) - { - return EncodeHelper::encode(encoder, value); - } -}; - -} // namespace detail -} // namespace lp -} // namespace ndn - -#endif // NDN_CXX_LP_DETAIL_FIELD_DECL_HPP diff --git a/src/lp/detail/field-info.cpp b/src/lp/detail/field-info.cpp deleted file mode 100644 index fadd85801..000000000 --- a/src/lp/detail/field-info.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "field-info.hpp" - -#include -#include - -namespace ndn { -namespace lp { -namespace detail { - -struct ExtractFieldInfo -{ - typedef void result_type; - - template - void - operator()(FieldInfo* info, T) - { - if (T::TlvType::value != info->tlvType) { - return; - } - info->isRecognized = true; - info->canIgnore = false; - info->isRepeatable = T::IsRepeatable::value; - info->locationSortOrder = getLocationSortOrder(); - } -}; - -FieldInfo::FieldInfo() - : tlvType(0) - , isRecognized(false) - , canIgnore(false) - , isRepeatable(false) - , locationSortOrder(getLocationSortOrder()) -{ -} - -FieldInfo::FieldInfo(uint64_t tlv) - : tlvType(tlv) - , isRecognized(false) - , canIgnore(false) - , isRepeatable(false) - , locationSortOrder(getLocationSortOrder()) -{ - boost::mpl::for_each
(boost::bind(ExtractFieldInfo(), this, _1)); - if (!isRecognized) { - canIgnore = tlv::HEADER3_MIN <= tlvType && tlvType <= tlv::HEADER3_MAX && - (tlvType & 0x01) == 0x01; - } -} - -} // namespace detail -} // namespace lp -} // namespace ndn \ No newline at end of file diff --git a/src/lp/detail/field-info.hpp b/src/lp/detail/field-info.hpp deleted file mode 100644 index 2ee0e1089..000000000 --- a/src/lp/detail/field-info.hpp +++ /dev/null @@ -1,97 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_CXX_LP_DETAIL_FIELD_INFO_HPP -#define NDN_CXX_LP_DETAIL_FIELD_INFO_HPP - -#include "../../common.hpp" - -#include "../fields.hpp" - -namespace ndn { -namespace lp { -namespace detail { - -class FieldInfo -{ -public: - FieldInfo(); - - explicit - FieldInfo(uint64_t tlv); - -public: - /** - * \brief TLV-TYPE of the field; 0 if field does not exist - */ - uint64_t tlvType; - - /** - * \brief is this field known - */ - bool isRecognized; - - /** - * \brief can this unknown field be ignored - */ - bool canIgnore; - - /** - * \brief is the field repeatable - */ - bool isRepeatable; - - /** - * \brief sort order of field_location_tag - */ - int locationSortOrder; -}; - -template -inline int -getLocationSortOrder(); - -template<> -inline int -getLocationSortOrder() -{ - return 1; -} - -template<> -inline int -getLocationSortOrder() -{ - return 2; -} - -inline bool -compareFieldSortOrder(const FieldInfo& first, const FieldInfo& second) -{ - return (first.locationSortOrder < second.locationSortOrder) || - (first.locationSortOrder == second.locationSortOrder && first.tlvType < second.tlvType); -} - -} // namespace detail -} // namespace lp -} // namespace ndn - -#endif // NDN_CXX_LP_DETAIL_FIELD_INFO_HPP \ No newline at end of file diff --git a/src/lp/field.hpp b/src/lp/field.hpp deleted file mode 100644 index 712bd86f5..000000000 --- a/src/lp/field.hpp +++ /dev/null @@ -1,84 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_CXX_LP_FIELD_HPP -#define NDN_CXX_LP_FIELD_HPP - -#include "../common.hpp" -#include "../encoding/encoding-buffer.hpp" - -#include -#include -#include - -namespace ndn { -namespace lp { - -/** - * \brief indicates where a field may occur - */ -namespace field_location_tags { - -class Base -{ -}; - -/** - * \brief a header field - */ -class Header : public Base -{ -}; - -/** - * \brief the Fragment field - */ -class Fragment : public Base -{ -}; - -} // namespace field_location_tags - -/** - * \brief concept check for fields - */ -template -struct Field -{ - BOOST_CONCEPT_ASSERT((boost::is_base_of)); - BOOST_CONCEPT_ASSERT((boost::DefaultConstructible)); - BOOST_CONCEPT_ASSERT((boost::CopyConstructible)); - BOOST_CONCEPT_ASSERT((boost::is_same)); - BOOST_CONCEPT_ASSERT((boost::is_same)); - BOOST_CONCEPT_USAGE(Field) - { - Block wire; - X j; - typename X::ValueType decoded = j.decode(wire); - EncodingBuffer enc; - j.encode(enc, decoded); - } -}; - -} // namespace lp -} // namespace ndn - -#endif // NDN_CXX_LP_FIELD_HPP diff --git a/src/lp/fields.hpp b/src/lp/fields.hpp deleted file mode 100644 index 7d898d07e..000000000 --- a/src/lp/fields.hpp +++ /dev/null @@ -1,103 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_CXX_LP_FIELDS_HPP -#define NDN_CXX_LP_FIELDS_HPP - -#include "detail/field-decl.hpp" - -#include "sequence.hpp" -#include "cache-policy.hpp" -#include "nack-header.hpp" - -#include - -namespace ndn { -namespace lp { - -typedef detail::FieldDecl SequenceField; -BOOST_CONCEPT_ASSERT((Field)); - -typedef detail::FieldDecl FragIndexField; -BOOST_CONCEPT_ASSERT((Field)); - -typedef detail::FieldDecl FragCountField; -BOOST_CONCEPT_ASSERT((Field)); - -typedef detail::FieldDecl NackField; -BOOST_CONCEPT_ASSERT((Field)); - -typedef detail::FieldDecl NextHopFaceIdField; -BOOST_CONCEPT_ASSERT((Field)); - -typedef detail::FieldDecl CachePolicyField; -BOOST_CONCEPT_ASSERT((Field)); - -typedef detail::FieldDecl IncomingFaceIdField; -BOOST_CONCEPT_ASSERT((Field)); - -typedef detail::FieldDecl CongestionMarkField; -BOOST_CONCEPT_ASSERT((Field)); - -/** - * The value of the wire encoded field is the data between the provided iterators. During - * encoding, the data is copied from the Buffer into the wire buffer. - */ -typedef detail::FieldDecl, - tlv::Fragment> FragmentField; -BOOST_CONCEPT_ASSERT((Field)); - -/** - * \brief set of all field declarations - */ -typedef boost::mpl::set< - FragmentField, - SequenceField, - FragIndexField, - FragCountField, - NackField, - NextHopFaceIdField, - CachePolicyField, - IncomingFaceIdField, - CongestionMarkField - > FieldSet; - -} // namespace lp -} // namespace ndn - -#endif // NDN_CXX_LP_FIELDS_HPP diff --git a/src/lp/packet.cpp b/src/lp/packet.cpp deleted file mode 100644 index 8d62ed93d..000000000 --- a/src/lp/packet.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "packet.hpp" -#include "detail/field-info.hpp" - -#include - -namespace ndn { -namespace lp { - -Packet::Packet() - : m_wire(Block(tlv::LpPacket)) -{ -} - -Packet::Packet(const Block& wire) -{ - wireDecode(wire); -} - -template -size_t -Packet::wireEncode(EncodingImpl& encoder) const -{ - if (m_wire.hasWire()) { - return m_wire.size(); - } - - size_t length = 0; - - for (const Block& element : boost::adaptors::reverse(m_wire.elements())) { - length += encoder.prependBlock(element); - } - - length += encoder.prependVarNumber(length); - length += encoder.prependVarNumber(tlv::LpPacket); - - return length; -} - -template size_t -Packet::wireEncode(EncodingImpl& encoder) const; - -template size_t -Packet::wireEncode(EncodingImpl& encoder) const; - -Block -Packet::wireEncode() const -{ - if (m_wire.hasWire()) { - return m_wire; - } - - // If no header or trailer, return bare network packet - Block::element_container elements = m_wire.elements(); - if (elements.size() == 1 && elements.front().type() == FragmentField::TlvType::value) { - elements.front().parse(); - elements.front().elements().front().parse(); - return elements.front().elements().front(); - } - - EncodingEstimator estimator; - size_t estimatedSize = wireEncode(estimator); - - EncodingBuffer buffer(estimatedSize, 0); - wireEncode(buffer); - - m_wire = buffer.block(); - return m_wire; -} - -void -Packet::wireDecode(const Block& wire) -{ - if (wire.type() == ndn::tlv::Interest || wire.type() == ndn::tlv::Data) { - m_wire = Block(tlv::LpPacket); - add(make_pair(wire.begin(), wire.end())); - return; - } - - if (wire.type() != tlv::LpPacket) { - BOOST_THROW_EXCEPTION(Error("unrecognized TLV-TYPE " + to_string(wire.type()))); - } - - wire.parse(); - - bool isFirst = true; - detail::FieldInfo prev; - for (const Block& element : wire.elements()) { - detail::FieldInfo info(element.type()); - - if (!info.isRecognized && !info.canIgnore) { - BOOST_THROW_EXCEPTION(Error("unrecognized field cannot be ignored")); - } - - if (!isFirst) { - if (info.tlvType == prev.tlvType && !info.isRepeatable) { - BOOST_THROW_EXCEPTION(Error("non-repeatable field cannot be repeated")); - } - - else if (info.tlvType != prev.tlvType && !detail::compareFieldSortOrder(prev, info)) { - BOOST_THROW_EXCEPTION(Error("fields are not in correct sort order")); - } - } - - isFirst = false; - prev = info; - } - - m_wire = wire; -} - -bool -Packet::comparePos(const Block& first, const uint64_t second) -{ - detail::FieldInfo firstInfo(first.type()); - detail::FieldInfo secondInfo(second); - return detail::compareFieldSortOrder(firstInfo, secondInfo); -} - -} // namespace lp -} // namespace ndn diff --git a/src/lp/tags.hpp b/src/lp/tags.hpp deleted file mode 100644 index 5e2b3d696..000000000 --- a/src/lp/tags.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_CXX_LP_TAGS_HPP -#define NDN_CXX_LP_TAGS_HPP - -#include "cache-policy.hpp" -#include "../tag-host.hpp" - -namespace ndn { -namespace lp { - -/** \class IncomingFaceIdTag - * \brief a packet tag for IncomingFaceId field - * - * This tag can be attached to Interest, Data, Nack. - */ -typedef SimpleTag IncomingFaceIdTag; - -/** \class NextHopFaceIdTag - * \brief a packet tag for NextHopFaceId field - * - * This tag can be attached to Interest. - */ -typedef SimpleTag NextHopFaceIdTag; - -/** \class CachePolicyTag - * \brief a packet tag for CachePolicy field - * - * This tag can be attached to Data. - */ -typedef SimpleTag CachePolicyTag; - -/** \class CongestionMarkTag - * \brief a packet tag for CongestionMark field - * - * This tag can be attached to Interest, Data, Nack. - */ -typedef SimpleTag CongestionMarkTag; - -} // namespace lp -} // namespace ndn - -#endif // NDN_CXX_LP_TAGS_HPP diff --git a/src/lp/tlv.hpp b/src/lp/tlv.hpp deleted file mode 100644 index e7a5ccad3..000000000 --- a/src/lp/tlv.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_CXX_LP_TLV_HPP -#define NDN_CXX_LP_TLV_HPP - -namespace ndn { -namespace lp { -namespace tlv { - -/** - * \brief TLV-TYPE code assignments for NDNLPv2 - */ -enum { - LpPacket = 100, - Fragment = 80, - Sequence = 81, - FragIndex = 82, - FragCount = 83, - Nack = 800, - NackReason = 801, - NextHopFaceId = 816, - CachePolicy = 820, - CachePolicyType = 821, - IncomingFaceId = 817, - CongestionMark = 832 -}; - -enum { - /** - * \brief lower bound of 1-octet header field - */ - HEADER1_MIN = 81, - - /** - * \brief upper bound of 1-octet header field - */ - HEADER1_MAX = 99, - - /** - * \brief lower bound of 3-octet header field - */ - HEADER3_MIN = 800, - - /** - * \brief upper bound of 3-octet header field - */ - HEADER3_MAX = 959 -}; - -} // namespace tlv -} // namespace lp -} // namespace ndn - -#endif // NDN_CXX_LP_TLV_HPP diff --git a/src/management/nfd-channel-status.hpp b/src/management/nfd-channel-status.hpp deleted file mode 100644 index 524d9f9e1..000000000 --- a/src/management/nfd-channel-status.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/channel-status.hpp - */ -#include "../mgmt/nfd/channel-status.hpp" diff --git a/src/management/nfd-command-options.hpp b/src/management/nfd-command-options.hpp deleted file mode 100644 index 7cf8c7785..000000000 --- a/src/management/nfd-command-options.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/command-options.hpp - */ -#include "../mgmt/nfd/command-options.hpp" diff --git a/src/management/nfd-control-command.hpp b/src/management/nfd-control-command.hpp deleted file mode 100644 index 393e174ad..000000000 --- a/src/management/nfd-control-command.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/control-command.hpp - */ -#include "../mgmt/nfd/control-command.hpp" diff --git a/src/management/nfd-control-parameters.hpp b/src/management/nfd-control-parameters.hpp deleted file mode 100644 index a22bc6f07..000000000 --- a/src/management/nfd-control-parameters.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/control-parameters.hpp - */ -#include "../mgmt/nfd/control-parameters.hpp" diff --git a/src/management/nfd-control-response.hpp b/src/management/nfd-control-response.hpp deleted file mode 100644 index 74e38f314..000000000 --- a/src/management/nfd-control-response.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/control-response.hpp - */ -#include "../mgmt/nfd/control-response.hpp" diff --git a/src/management/nfd-controller.hpp b/src/management/nfd-controller.hpp deleted file mode 100644 index b127d5723..000000000 --- a/src/management/nfd-controller.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/controller.hpp - */ -#include "../mgmt/nfd/controller.hpp" diff --git a/src/management/nfd-face-event-notification.hpp b/src/management/nfd-face-event-notification.hpp deleted file mode 100644 index 3749390dd..000000000 --- a/src/management/nfd-face-event-notification.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/face-event-notification.hpp - */ -#include "../mgmt/nfd/face-event-notification.hpp" diff --git a/src/management/nfd-face-monitor.hpp b/src/management/nfd-face-monitor.hpp deleted file mode 100644 index f6bc9438e..000000000 --- a/src/management/nfd-face-monitor.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/face-monitor.hpp - */ -#include "../mgmt/nfd/face-monitor.hpp" diff --git a/src/management/nfd-face-query-filter.hpp b/src/management/nfd-face-query-filter.hpp deleted file mode 100644 index 345af3ebe..000000000 --- a/src/management/nfd-face-query-filter.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/face-query-filter.hpp - */ -#include "../mgmt/nfd/face-query-filter.hpp" diff --git a/src/management/nfd-face-status.hpp b/src/management/nfd-face-status.hpp deleted file mode 100644 index 13e491951..000000000 --- a/src/management/nfd-face-status.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/face-status.hpp - */ -#include "../mgmt/nfd/face-status.hpp" diff --git a/src/management/nfd-face-traits.hpp b/src/management/nfd-face-traits.hpp deleted file mode 100644 index 914c4d51a..000000000 --- a/src/management/nfd-face-traits.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/face-traits.hpp - */ -#include "../mgmt/nfd/face-traits.hpp" diff --git a/src/management/nfd-fib-entry.hpp b/src/management/nfd-fib-entry.hpp deleted file mode 100644 index 5f3a4c347..000000000 --- a/src/management/nfd-fib-entry.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/fib-entry.hpp - */ -#include "../mgmt/nfd/fib-entry.hpp" diff --git a/src/management/nfd-forwarder-status.hpp b/src/management/nfd-forwarder-status.hpp deleted file mode 100644 index ca9a9440b..000000000 --- a/src/management/nfd-forwarder-status.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/forwarder-status.hpp - */ -#include "../mgmt/nfd/forwarder-status.hpp" diff --git a/src/management/nfd-rib-entry.hpp b/src/management/nfd-rib-entry.hpp deleted file mode 100644 index 2673e6cb6..000000000 --- a/src/management/nfd-rib-entry.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/rib-entry.hpp - */ -#include "../mgmt/nfd/rib-entry.hpp" diff --git a/src/management/nfd-rib-flags.hpp b/src/management/nfd-rib-flags.hpp deleted file mode 100644 index 8a15a3430..000000000 --- a/src/management/nfd-rib-flags.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/rib-flags.hpp - */ -#include "../mgmt/nfd/rib-flags.hpp" diff --git a/src/management/nfd-status-dataset.hpp b/src/management/nfd-status-dataset.hpp deleted file mode 100644 index 0f2d72a99..000000000 --- a/src/management/nfd-status-dataset.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/status-dataset.hpp - */ -#include "../mgmt/nfd/status-dataset.hpp" diff --git a/src/management/nfd-strategy-choice.hpp b/src/management/nfd-strategy-choice.hpp deleted file mode 100644 index 1b31c0da4..000000000 --- a/src/management/nfd-strategy-choice.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \deprecated Use mgmt/nfd/strategy-choice.hpp - */ -#include "../mgmt/nfd/strategy-choice.hpp" diff --git a/src/meta-info.cpp b/src/meta-info.cpp deleted file mode 100644 index 0fd69237f..000000000 --- a/src/meta-info.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "meta-info.hpp" -#include "encoding/block-helpers.hpp" -#include "encoding/encoding-buffer.hpp" - -namespace ndn { - -BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "MetaInfo::Error must inherit from tlv::Error"); - -MetaInfo::MetaInfo() - : m_type(tlv::ContentType_Blob) - , m_freshnessPeriod(-1) -{ -} - -MetaInfo::MetaInfo(const Block& block) -{ - wireDecode(block); -} - -MetaInfo& -MetaInfo::setType(uint32_t type) -{ - m_wire.reset(); - m_type = type; - return *this; -} - -MetaInfo& -MetaInfo::setFreshnessPeriod(const time::milliseconds& freshnessPeriod) -{ - m_wire.reset(); - m_freshnessPeriod = freshnessPeriod; - return *this; -} - -MetaInfo& -MetaInfo::setFinalBlockId(const name::Component& finalBlockId) -{ - m_wire.reset(); - m_finalBlockId = finalBlockId; - return *this; -} - -const std::list& -MetaInfo::getAppMetaInfo() const -{ - return m_appMetaInfo; -} - -MetaInfo& -MetaInfo::setAppMetaInfo(const std::list& info) -{ - for (std::list::const_iterator i = info.begin(); i != info.end(); ++i) { - if (!(128 <= i->type() && i->type() <= 252)) - BOOST_THROW_EXCEPTION(Error("AppMetaInfo block has type outside the application range " - "[128, 252]")); - } - - m_wire.reset(); - m_appMetaInfo = info; - return *this; -} - -MetaInfo& -MetaInfo::addAppMetaInfo(const Block& block) -{ - if (!(128 <= block.type() && block.type() <= 252)) - BOOST_THROW_EXCEPTION(Error("AppMetaInfo block has type outside the application range " - "[128, 252]")); - - m_wire.reset(); - m_appMetaInfo.push_back(block); - return *this; -} - -bool -MetaInfo::removeAppMetaInfo(uint32_t tlvType) -{ - for (std::list::iterator iter = m_appMetaInfo.begin(); - iter != m_appMetaInfo.end(); ++iter) { - if (iter->type() == tlvType) { - m_wire.reset(); - m_appMetaInfo.erase(iter); - return true; - } - } - return false; -} - -const Block* -MetaInfo::findAppMetaInfo(uint32_t tlvType) const -{ - for (std::list::const_iterator iter = m_appMetaInfo.begin(); - iter != m_appMetaInfo.end(); ++iter) { - if (iter->type() == tlvType) { - return &*iter; - } - } - return 0; -} - -template -size_t -MetaInfo::wireEncode(EncodingImpl& encoder) const -{ - // MetaInfo ::= META-INFO-TYPE TLV-LENGTH - // ContentType? - // FreshnessPeriod? - // FinalBlockId? - // AppMetaInfo* - - size_t totalLength = 0; - - for (std::list::const_reverse_iterator appMetaInfoItem = m_appMetaInfo.rbegin(); - appMetaInfoItem != m_appMetaInfo.rend(); ++appMetaInfoItem) { - totalLength += encoder.prependBlock(*appMetaInfoItem); - } - - // FinalBlockId - if (!m_finalBlockId.empty()) - { - totalLength += prependNestedBlock(encoder, tlv::FinalBlockId, m_finalBlockId); - } - - // FreshnessPeriod - if (m_freshnessPeriod >= time::milliseconds::zero()) - { - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::FreshnessPeriod, - m_freshnessPeriod.count()); - } - - // ContentType - if (m_type != tlv::ContentType_Blob) - { - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::ContentType, m_type); - } - - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::MetaInfo); - return totalLength; -} - -template size_t -MetaInfo::wireEncode(EncodingImpl& encoder) const; - -template size_t -MetaInfo::wireEncode(EncodingImpl& encoder) const; - -const Block& -MetaInfo::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 -MetaInfo::wireDecode(const Block& wire) -{ - m_wire = wire; - m_wire.parse(); - - // MetaInfo ::= META-INFO-TYPE TLV-LENGTH - // ContentType? - // FreshnessPeriod? - // FinalBlockId? - // AppMetaInfo* - - - Block::element_const_iterator val = m_wire.elements_begin(); - - // ContentType - if (val != m_wire.elements_end() && val->type() == tlv::ContentType) { - m_type = readNonNegativeInteger(*val); - ++val; - } - else { - m_type = tlv::ContentType_Blob; - } - - // FreshnessPeriod - if (val != m_wire.elements_end() && val->type() == tlv::FreshnessPeriod) { - m_freshnessPeriod = time::milliseconds(readNonNegativeInteger(*val)); - ++val; - } - else { - m_freshnessPeriod = time::milliseconds::min(); - } - - // FinalBlockId - if (val != m_wire.elements_end() && val->type() == tlv::FinalBlockId) { - m_finalBlockId = val->blockFromValue(); - if (m_finalBlockId.type() != tlv::NameComponent) - { - /// @todo May or may not throw exception later... - m_finalBlockId = name::Component(); - } - ++val; - } - else { - m_finalBlockId = name::Component(); - } - - // AppMetaInfo (if any) - for (; val != m_wire.elements().end(); ++val) { - m_appMetaInfo.push_back(*val); - } -} - -std::ostream& -operator<<(std::ostream& os, const MetaInfo& info) -{ - // ContentType - os << "ContentType: " << info.getType(); - - // FreshnessPeriod - if (info.getFreshnessPeriod() >= time::milliseconds::zero()) { - os << ", FreshnessPeriod: " << info.getFreshnessPeriod(); - } - - // FinalBlockId - if (!info.getFinalBlockId().empty()) { - os << ", FinalBlockId: "; - info.getFinalBlockId().toUri(os); - } - - // App-defined MetaInfo items - for (std::list::const_iterator iter = info.getAppMetaInfo().begin(); - iter != info.getAppMetaInfo().end(); ++iter) { - os << ", AppMetaInfoTlvType: " << iter->type(); - } - - return os; -} - -} // namespace ndn diff --git a/src/mgmt/control-parameters.hpp b/src/mgmt/control-parameters.hpp deleted file mode 100644 index f4360561c..000000000 --- a/src/mgmt/control-parameters.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_MGMT_CONTROL_PARAMETERS_HPP -#define NDN_MGMT_CONTROL_PARAMETERS_HPP - -#include "../encoding/block.hpp" - -namespace ndn { -namespace mgmt { - -/** \brief base class for a struct that contains ControlCommand parameters - */ -class ControlParameters -{ -public: - virtual void - wireDecode(const Block& wire) = 0; - - virtual Block - wireEncode() const = 0; -}; - -} // namespace mgmt -} // namespace ndn - -#endif // NDN_MGMT_CONTROL_PARAMETERS_HPP diff --git a/src/mgmt/control-response.hpp b/src/mgmt/control-response.hpp deleted file mode 100644 index 266b21b65..000000000 --- a/src/mgmt/control-response.hpp +++ /dev/null @@ -1,133 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_MGMT_CONTROL_RESPONSE_HPP -#define NDN_MGMT_CONTROL_RESPONSE_HPP - -#include "../encoding/block.hpp" - -namespace ndn { -namespace mgmt { - -/** \brief ControlCommand response - */ -class ControlResponse -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - - ControlResponse(); - - ControlResponse(uint32_t code, const std::string& text); - - explicit - ControlResponse(const Block& block); - - uint32_t - getCode() const; - - ControlResponse& - setCode(uint32_t code); - - const std::string& - getText() const; - - ControlResponse& - setText(const std::string& text); - - const Block& - getBody() const; - - ControlResponse& - setBody(const Block& body); - - const Block& - wireEncode() const; - - void - wireDecode(const Block& block); - -protected: - uint32_t m_code; - std::string m_text; - Block m_body; - - mutable Block m_wire; -}; - -inline uint32_t -ControlResponse::getCode() const -{ - return m_code; -} - -inline ControlResponse& -ControlResponse::setCode(uint32_t code) -{ - m_code = code; - m_wire.reset(); - return *this; -} - -inline const std::string& -ControlResponse::getText() const -{ - return m_text; -} - -inline ControlResponse& -ControlResponse::setText(const std::string& text) -{ - m_text = text; - m_wire.reset(); - return *this; -} - -inline const Block& -ControlResponse::getBody() const -{ - return m_body; -} - -inline ControlResponse& -ControlResponse::setBody(const Block& body) -{ - m_body = body; - m_body.encode(); // will do nothing if already encoded - m_wire.reset(); - return *this; -} - -std::ostream& -operator<<(std::ostream& os, const ControlResponse& response); - -} // namespace mgmt -} // namespace ndn - -#endif // NDN_MGMT_CONTRO_RESPONSE_HPP diff --git a/src/mgmt/dispatcher.cpp b/src/mgmt/dispatcher.cpp deleted file mode 100644 index a7f4a067a..000000000 --- a/src/mgmt/dispatcher.cpp +++ /dev/null @@ -1,372 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "dispatcher.hpp" -#include "../lp/tags.hpp" -#include "../util/logger.hpp" - -#include - -NDN_LOG_INIT(ndn.mgmt.Dispatcher); - -namespace ndn { -namespace mgmt { - -const time::milliseconds DEFAULT_FRESHNESS_PERIOD = time::milliseconds(1000); - -Authorization -makeAcceptAllAuthorization() -{ - return [] (const Name& prefix, - const Interest& interest, - const ControlParameters* params, - const AcceptContinuation& accept, - const RejectContinuation& reject) { - accept(""); - }; -} - -Dispatcher::Dispatcher(Face& face, security::KeyChain& keyChain, - const security::SigningInfo& signingInfo, - size_t imsCapacity) - : m_face(face) - , m_keyChain(keyChain) - , m_signingInfo(signingInfo) - , m_storage(m_face.getIoService(), imsCapacity) -{ -} - -Dispatcher::~Dispatcher() -{ - std::vector topPrefixNames; - - std::transform(m_topLevelPrefixes.begin(), - m_topLevelPrefixes.end(), - std::back_inserter(topPrefixNames), - [] (const std::unordered_map::value_type& entry) { - return entry.second.topPrefix; - }); - - for (auto&& name : topPrefixNames) { - removeTopPrefix(name); - } -} - -void -Dispatcher::addTopPrefix(const Name& prefix, - bool wantRegister, - const security::SigningInfo& signingInfo) -{ - bool hasOverlap = std::any_of(m_topLevelPrefixes.begin(), - m_topLevelPrefixes.end(), - [&] (const std::unordered_map::value_type& x) { - return x.first.isPrefixOf(prefix) || prefix.isPrefixOf(x.first); - }); - if (hasOverlap) { - BOOST_THROW_EXCEPTION(std::out_of_range("Top-level Prefixes overlapped")); - } - - TopPrefixEntry& topPrefixEntry = m_topLevelPrefixes[prefix];; - topPrefixEntry.topPrefix = prefix; - topPrefixEntry.wantRegister = wantRegister; - - if (wantRegister) { - RegisterPrefixFailureCallback failure = [] (const Name& name, const std::string& reason) { - BOOST_THROW_EXCEPTION(std::runtime_error(reason)); - }; - topPrefixEntry.registerPrefixId = - m_face.registerPrefix(prefix, bind([]{}), failure, signingInfo); - } - - for (auto&& entry : m_handlers) { - Name fullPrefix = prefix; - fullPrefix.append(entry.first); - - const InterestFilterId* interestFilterId = - m_face.setInterestFilter(fullPrefix, std::bind(entry.second, prefix, _2)); - - topPrefixEntry.interestFilters.push_back(interestFilterId); - } -} - -void -Dispatcher::removeTopPrefix(const Name& prefix) -{ - auto it = m_topLevelPrefixes.find(prefix); - if (it == m_topLevelPrefixes.end()) { - return; - } - - const TopPrefixEntry& topPrefixEntry = it->second; - if (topPrefixEntry.wantRegister) { - m_face.unregisterPrefix(topPrefixEntry.registerPrefixId, bind([]{}), bind([]{})); - } - - for (auto&& filter : topPrefixEntry.interestFilters) { - m_face.unsetInterestFilter(filter); - } - - m_topLevelPrefixes.erase(it); -} - -bool -Dispatcher::isOverlappedWithOthers(const PartialName& relPrefix) -{ - bool hasOverlapWithHandlers = - std::any_of(m_handlers.begin(), m_handlers.end(), - [&] (const HandlerMap::value_type& entry) { - return entry.first.isPrefixOf(relPrefix) || relPrefix.isPrefixOf(entry.first); - }); - bool hasOverlapWithStreams = - std::any_of(m_streams.begin(), m_streams.end(), - [&] (const std::unordered_map::value_type& entry) { - return entry.first.isPrefixOf(relPrefix) || relPrefix.isPrefixOf(entry.first); - }); - - return hasOverlapWithHandlers || hasOverlapWithStreams; -} - -void -Dispatcher::afterAuthorizationRejected(RejectReply act, const Interest& interest) -{ - if (act == RejectReply::STATUS403) { - sendControlResponse(ControlResponse(403, "authorization rejected"), interest); - } -} - -void -Dispatcher::queryStorage(const Name& prefix, const Interest& interest, - const InterestHandler& missContinuation) -{ - auto data = m_storage.find(interest); - if (data == nullptr) { - // invoke missContinuation to process this Interest if the query fails. - missContinuation(prefix, interest); - } - else { - // send the fetched data through face if query succeeds. - sendOnFace(*data); - } -} - -void -Dispatcher::sendData(const Name& dataName, const Block& content, const MetaInfo& metaInfo, - SendDestination option, time::milliseconds imsFresh) -{ - shared_ptr data = make_shared(dataName); - data->setContent(content).setMetaInfo(metaInfo).setFreshnessPeriod(DEFAULT_FRESHNESS_PERIOD); - - m_keyChain.sign(*data, m_signingInfo); - - if (option == SendDestination::IMS || option == SendDestination::FACE_AND_IMS) { - lp::CachePolicy policy; - policy.setPolicy(lp::CachePolicyType::NO_CACHE); - data->setTag(make_shared(policy)); - m_storage.insert(*data, imsFresh); - } - - if (option == SendDestination::FACE || option == SendDestination::FACE_AND_IMS) { - sendOnFace(*data); - } -} - -void -Dispatcher::sendOnFace(const Data& data) -{ - try { - m_face.put(data); - } - catch (const Face::Error& e) { - NDN_LOG_ERROR("sendOnFace: " << e.what()); - } -} - -void -Dispatcher::processControlCommandInterest(const Name& prefix, - const Name& relPrefix, - const Interest& interest, - const ControlParametersParser& parser, - const Authorization& authorization, - const AuthorizationAcceptedCallback& accepted, - const AuthorizationRejectedCallback& rejected) -{ - // /// - size_t parametersLoc = prefix.size() + relPrefix.size(); - const name::Component& pc = interest.getName().get(parametersLoc); - - shared_ptr parameters; - try { - parameters = parser(pc); - } - catch (const tlv::Error&) { - return; - } - - AcceptContinuation accept = bind(accepted, _1, prefix, interest, parameters.get()); - RejectContinuation reject = bind(rejected, _1, interest); - authorization(prefix, interest, parameters.get(), accept, reject); -} - -void -Dispatcher::processAuthorizedControlCommandInterest(const std::string& requester, - const Name& prefix, - const Interest& interest, - const ControlParameters* parameters, - const ValidateParameters& validateParams, - const ControlCommandHandler& handler) -{ - if (validateParams(*parameters)) { - handler(prefix, interest, *parameters, - bind(&Dispatcher::sendControlResponse, this, _1, interest, false)); - } - else { - sendControlResponse(ControlResponse(400, "failed in validating parameters"), interest); - } -} - -void -Dispatcher::sendControlResponse(const ControlResponse& resp, const Interest& interest, - bool isNack) -{ - MetaInfo metaInfo; - if (isNack) { - metaInfo.setType(tlv::ContentType_Nack); - } - // control response is always sent out through the face - sendData(interest.getName(), resp.wireEncode(), metaInfo, SendDestination::FACE, - DEFAULT_FRESHNESS_PERIOD); -} - -void -Dispatcher::addStatusDataset(const PartialName& relPrefix, - const Authorization& authorization, - const StatusDatasetHandler& handler) -{ - if (!m_topLevelPrefixes.empty()) { - BOOST_THROW_EXCEPTION(std::domain_error("one or more top-level prefix has been added")); - } - - if (isOverlappedWithOthers(relPrefix)) { - BOOST_THROW_EXCEPTION(std::out_of_range("relPrefix overlapped")); - } - - AuthorizationAcceptedCallback accepted = - bind(&Dispatcher::processAuthorizedStatusDatasetInterest, this, - _1, _2, _3, handler); - AuthorizationRejectedCallback rejected = - bind(&Dispatcher::afterAuthorizationRejected, this, _1, _2); - - // follow the general path if storage is a miss - InterestHandler missContinuation = bind(&Dispatcher::processStatusDatasetInterest, this, - _1, _2, authorization, accepted, rejected); - m_handlers[relPrefix] = bind(&Dispatcher::queryStorage, this, _1, _2, missContinuation); -} - -void -Dispatcher::processStatusDatasetInterest(const Name& prefix, - const Interest& interest, - const Authorization& authorization, - const AuthorizationAcceptedCallback& accepted, - const AuthorizationRejectedCallback& rejected) -{ - const Name& interestName = interest.getName(); - bool endsWithVersionOrSegment = interestName.size() >= 1 && - (interestName[-1].isVersion() || interestName[-1].isSegment()); - if (endsWithVersionOrSegment) { - return; - } - - AcceptContinuation accept = bind(accepted, _1, prefix, interest, nullptr); - RejectContinuation reject = bind(rejected, _1, interest); - authorization(prefix, interest, nullptr, accept, reject); -} - -void -Dispatcher::processAuthorizedStatusDatasetInterest(const std::string& requester, - const Name& prefix, - const Interest& interest, - const StatusDatasetHandler& handler) -{ - StatusDatasetContext context(interest, - bind(&Dispatcher::sendStatusDatasetSegment, this, _1, _2, _3, _4), - bind(&Dispatcher::sendControlResponse, this, _1, interest, true)); - handler(prefix, interest, context); -} - -void -Dispatcher::sendStatusDatasetSegment(const Name& dataName, const Block& content, - time::milliseconds imsFresh, bool isFinalBlock) -{ - // the first segment will be sent to both places (the face and the in-memory storage) - // other segments will be inserted to the in-memory storage only - auto destination = SendDestination::IMS; - if (dataName[-1].toSegment() == 0) { - destination = SendDestination::FACE_AND_IMS; - } - - MetaInfo metaInfo; - if (isFinalBlock) { - metaInfo.setFinalBlockId(dataName[-1]); - } - - sendData(dataName, content, metaInfo, destination, imsFresh); -} - -PostNotification -Dispatcher::addNotificationStream(const PartialName& relPrefix) -{ - if (!m_topLevelPrefixes.empty()) { - BOOST_THROW_EXCEPTION(std::domain_error("one or more top-level prefix has been added")); - } - - if (isOverlappedWithOthers(relPrefix)) { - BOOST_THROW_EXCEPTION(std::out_of_range("relPrefix overlaps with another relPrefix")); - } - - // keep silent if Interest does not match a stored notification - InterestHandler missContinuation = bind([]{}); - - // register a handler for the subscriber of this notification stream - m_handlers[relPrefix] = bind(&Dispatcher::queryStorage, this, _1, _2, missContinuation); - m_streams[relPrefix] = 0; - return bind(&Dispatcher::postNotification, this, _1, relPrefix); -} - -void -Dispatcher::postNotification(const Block& notification, const PartialName& relPrefix) -{ - if (m_topLevelPrefixes.empty() || m_topLevelPrefixes.size() > 1) { - NDN_LOG_WARN("postNotification: no top-level prefix or too many top-level prefixes"); - return; - } - - Name streamName(m_topLevelPrefixes.begin()->second.topPrefix); - streamName.append(relPrefix); - streamName.appendSequenceNumber(m_streams[streamName]++); - - // notification is sent out by the face after inserting into the in-memory storage, - // because a request may be pending in the PIT - sendData(streamName, notification, MetaInfo(), SendDestination::FACE_AND_IMS, - DEFAULT_FRESHNESS_PERIOD); -} - -} // namespace mgmt -} // namespace ndn diff --git a/src/mgmt/nfd/channel-status.cpp b/src/mgmt/nfd/channel-status.cpp deleted file mode 100644 index bbbfdf417..000000000 --- a/src/mgmt/nfd/channel-status.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "channel-status.hpp" -#include "encoding/tlv-nfd.hpp" -#include "encoding/block-helpers.hpp" -#include "util/concepts.hpp" - -namespace ndn { -namespace nfd { - -//BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "ChannelStatus::Error must inherit from tlv::Error"); - -ChannelStatus::ChannelStatus() -{ -} - -ChannelStatus::ChannelStatus(const Block& payload) -{ - this->wireDecode(payload); -} - -template -size_t -ChannelStatus::wireEncode(EncodingImpl& encoder) const -{ - size_t totalLength = 0; - - totalLength += encoder.prependByteArrayBlock(tlv::nfd::LocalUri, - reinterpret_cast(m_localUri.c_str()), m_localUri.size()); - - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::nfd::ChannelStatus); - return totalLength; -} - -template size_t -ChannelStatus::wireEncode(EncodingImpl&) const; - -template size_t -ChannelStatus::wireEncode(EncodingImpl&) const; - -const Block& -ChannelStatus::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 -ChannelStatus::wireDecode(const Block& block) -{ - if (block.type() != tlv::nfd::ChannelStatus) { - BOOST_THROW_EXCEPTION(Error("Expecting ChannelStatus block")); - } - m_wire = block; - m_wire.parse(); - Block::element_const_iterator val = m_wire.elements_begin(); - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::LocalUri) { - m_localUri.assign(reinterpret_cast(val->value()), val->value_size()); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("Missing required LocalUri field")); - } -} - -ChannelStatus& -ChannelStatus::setLocalUri(const std::string localUri) -{ - m_wire.reset(); - m_localUri = localUri; - return *this; -} - -} // namespace nfd -} // namespace ndn diff --git a/src/mgmt/nfd/channel-status.hpp b/src/mgmt/nfd/channel-status.hpp deleted file mode 100644 index 5a2aae832..000000000 --- a/src/mgmt/nfd/channel-status.hpp +++ /dev/null @@ -1,82 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_MGMT_NFD_CHANNEL_STATUS_HPP -#define NDN_MGMT_NFD_CHANNEL_STATUS_HPP - -#include "../../encoding/block.hpp" - -namespace ndn { -namespace nfd { - -/** - * @ingroup management - * @brief represents NFD Channel Status dataset - * @sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Channel-Dataset - */ -class ChannelStatus -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - - ChannelStatus(); - - explicit - ChannelStatus(const Block& payload); - - template - size_t - wireEncode(EncodingImpl& encoder) const; - - const Block& - wireEncode() const; - - void - wireDecode(const Block& wire); - -public: // getters & setters - const std::string& - getLocalUri() const - { - return m_localUri; - } - - ChannelStatus& - setLocalUri(const std::string localUri); - -private: - std::string m_localUri; - - mutable Block m_wire; -}; - -} // namespace nfd -} // namespace ndn - -#endif // NDN_MGMT_NFD_CHANNEL_STATUS_HPP diff --git a/src/mgmt/nfd/command-options.cpp b/src/mgmt/nfd/command-options.cpp deleted file mode 100644 index 557cce34b..000000000 --- a/src/mgmt/nfd/command-options.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "command-options.hpp" - -#ifdef NDN_MANAGEMENT_NFD_COMMAND_OPTIONS_KEEP_DEPRECATED_SIGNING_PARAMS -#include "../../security/v1/identity-certificate.hpp" -#include "../../security/signing-helpers.hpp" -#endif // NDN_MANAGEMENT_NFD_COMMAND_OPTIONS_KEEP_DEPRECATED_SIGNING_PARAMS - -namespace ndn { -namespace nfd { - -const time::milliseconds CommandOptions::DEFAULT_TIMEOUT(10000); -const Name CommandOptions::DEFAULT_PREFIX("ndn:/localhost/nfd"); - -CommandOptions::CommandOptions() - : m_timeout(DEFAULT_TIMEOUT) - , m_prefix(DEFAULT_PREFIX) -{ -} - -CommandOptions& -CommandOptions::setTimeout(const time::milliseconds& timeout) -{ - if (timeout <= time::milliseconds::zero()) { - BOOST_THROW_EXCEPTION(std::out_of_range("Timeout must be positive")); - } - - m_timeout = timeout; - return *this; -} - -CommandOptions& -CommandOptions::setPrefix(const Name& prefix) -{ - m_prefix = prefix; - return *this; -} - -CommandOptions& -CommandOptions::setSigningInfo(const security::SigningInfo& signingInfo) -{ - m_signingInfo = signingInfo; - return *this; -} - -#ifdef NDN_MANAGEMENT_NFD_COMMAND_OPTIONS_KEEP_DEPRECATED_SIGNING_PARAMS - -CommandOptions::SigningParamsKind -CommandOptions::getSigningParamsKind() const -{ - switch (m_signingInfo.getSignerType()) { - case security::SigningInfo::SIGNER_TYPE_NULL: - return SIGNING_PARAMS_DEFAULT; - case security::SigningInfo::SIGNER_TYPE_ID: - return SIGNING_PARAMS_IDENTITY; - case security::SigningInfo::SIGNER_TYPE_CERT: - return SIGNING_PARAMS_CERTIFICATE; - default: - BOOST_THROW_EXCEPTION(std::out_of_range("SigningInfo::SignerType is not convertible to " - "CommandOptions::SigningParamsKind")); - } -} - -const Name& -CommandOptions::getSigningIdentity() const -{ - BOOST_ASSERT(m_signingInfo.getSignerType() == security::SigningInfo::SIGNER_TYPE_ID); - return m_signingInfo.getSignerName(); -} - -const Name& -CommandOptions::getSigningCertificate() const -{ - BOOST_ASSERT(m_signingInfo.getSignerType() == security::SigningInfo::SIGNER_TYPE_CERT); - return m_signingInfo.getSignerName(); -} - -CommandOptions& -CommandOptions::setSigningDefault() -{ - m_signingInfo = security::SigningInfo(); - return *this; -} - -CommandOptions& -CommandOptions::setSigningIdentity(const Name& identityName) -{ - m_signingInfo = security::signingByIdentity(identityName); - return *this; -} - -static security::SigningInfo -makeSigningInfoFromIdentityCertificate(const Name& certificateName) -{ - // A valid IdentityCertificate has at least 4 name components, - // as it follows `<...>/KEY/<...>//ID-CERT/` naming model. - if (certificateName.size() < 4) { - BOOST_THROW_EXCEPTION(std::invalid_argument("Certificate is invalid")); - } - - return security::signingByCertificate(certificateName); -} - -CommandOptions& -CommandOptions::setSigningCertificate(const Name& certificateName) -{ - m_signingInfo = makeSigningInfoFromIdentityCertificate(certificateName); - return *this; -} - -CommandOptions& -CommandOptions::setSigningCertificate(const security::v1::IdentityCertificate& certificate) -{ - m_signingInfo = makeSigningInfoFromIdentityCertificate(certificate.getName()); - return *this; -} - -#endif // NDN_MANAGEMENT_NFD_COMMAND_OPTIONS_KEEP_DEPRECATED_SIGNING_PARAMS - -} // namespace nfd -} // namespace ndn diff --git a/src/mgmt/nfd/command-options.hpp b/src/mgmt/nfd/command-options.hpp deleted file mode 100644 index efde928c4..000000000 --- a/src/mgmt/nfd/command-options.hpp +++ /dev/null @@ -1,196 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_MGMT_NFD_COMMAND_OPTIONS_HPP -#define NDN_MGMT_NFD_COMMAND_OPTIONS_HPP - -#include "../../security/signing-info.hpp" - -#define NDN_MGMT_NFD_COMMAND_OPTIONS_KEEP_DEPRECATED_SIGNING_PARAMS - -namespace ndn { - -namespace security { -namespace v1 { -class IdentityCertificate; -} // namespace v1 -} // namespace security - -namespace nfd { - -/** \ingroup management - * \brief contains options for ControlCommand execution - * \note This type is intentionally copyable - */ -class CommandOptions -{ -public: - /** \brief constructs CommandOptions - * \post getTimeout() == DEFAULT_TIMEOUT - * \post getPrefix() == DEFAULT_PREFIX - * \post getSigningInfo().getSignerType() == SIGNER_TYPE_NULL - */ - CommandOptions(); - - /** \return command timeout - */ - const time::milliseconds& - getTimeout() const - { - return m_timeout; - } - - /** \brief sets command timeout - * \param timeout the new command timeout, must be positive - * \throw std::out_of_range if timeout is non-positive - * \return self - */ - CommandOptions& - setTimeout(const time::milliseconds& timeout); - - /** \return command prefix - */ - const Name& - getPrefix() const - { - return m_prefix; - } - - /** \brief sets command prefix - * \return self - */ - CommandOptions& - setPrefix(const Name& prefix); - - /** \return signing parameters - */ - const security::SigningInfo& - getSigningInfo() const - { - return m_signingInfo; - } - - /** \brief sets signing parameters - * \return self - */ - CommandOptions& - setSigningInfo(const security::SigningInfo& signingInfo); - -#ifdef NDN_MGMT_NFD_COMMAND_OPTIONS_KEEP_DEPRECATED_SIGNING_PARAMS -public: // signing parameters - /** \deprecated use getSigningInfo and setSigningInfo - * \brief indicates the selection of signing parameters - */ - enum SigningParamsKind { - /** \brief picks the default signing identity and certificate - */ - SIGNING_PARAMS_DEFAULT, - /** \brief picks the default certificate of a specific identity Name - */ - SIGNING_PARAMS_IDENTITY, - /** \brief picks a specific identity certificate - */ - SIGNING_PARAMS_CERTIFICATE - }; - - /** \deprecated use getSigningInfo and setSigningInfo - * \return selection of signing parameters - */ - DEPRECATED( - SigningParamsKind - getSigningParamsKind() const); - - /** \deprecated use getSigningInfo and setSigningInfo - * \return identity Name - * \pre getSigningParamsKind() == SIGNING_PARAMS_IDENTITY - */ - DEPRECATED( - const Name& - getSigningIdentity() const); - - /** \deprecated use getSigningInfo and setSigningInfo - * \return certificate Name - * \pre getSigningParamsKind() == SIGNING_PARAMS_CERTIFICATE - */ - DEPRECATED( - const Name& - getSigningCertificate() const); - - /** \deprecated use getSigningInfo and setSigningInfo - * \brief chooses to use default identity and certificate - * \post getSigningParamsKind() == SIGNING_PARAMS_DEFAULT - * \return self - */ - DEPRECATED( - CommandOptions& - setSigningDefault()); - - /** \deprecated use getSigningInfo and setSigningInfo - * \brief chooses to use a specific identity and its default certificate - * \post getSigningParamsKind() == SIGNING_PARAMS_IDENTITY - * \post getIdentityName() == identityName - * \return self - */ - DEPRECATED( - CommandOptions& - setSigningIdentity(const Name& identityName)); - - /** \deprecated use getSigningInfo and setSigningInfo - * \brief chooses to use a specific identity certificate - * \param certificateName identity certificate Name - * \throw std::invalid_argument if certificateName is invalid - * \post getSigningParamsKind() == SIGNING_PARAMS_CERTIFICATE - * \post getSigningCertificate() == certificateName - * \return self - */ - DEPRECATED( - CommandOptions& - setSigningCertificate(const Name& certificateName)); - - /** \deprecated use getSigningInfo and setSigningInfo - * \brief chooses to use a specific identity certificate - * \details This is equivalent to .setIdentityCertificate(certificate.getName()) - */ - DEPRECATED( - CommandOptions& - setSigningCertificate(const security::v1::IdentityCertificate& certificate)); - -#endif // NDN_MGMT_NFD_COMMAND_OPTIONS_KEEP_DEPRECATED_SIGNING_PARAMS - -public: - /** \brief gives the default command timeout: 10000ms - */ - static const time::milliseconds DEFAULT_TIMEOUT; - - /** \brief gives the default command prefix: ndn:/localhost/nfd - */ - static const Name DEFAULT_PREFIX; - -private: - time::milliseconds m_timeout; - Name m_prefix; - security::SigningInfo m_signingInfo; -}; - -} // namespace nfd -} // namespace ndn - -#endif // NDN_MGMT_NFD_COMMAND_OPTIONS_HPP diff --git a/src/mgmt/nfd/control-command.cpp b/src/mgmt/nfd/control-command.cpp deleted file mode 100644 index 2a6eda7f8..000000000 --- a/src/mgmt/nfd/control-command.cpp +++ /dev/null @@ -1,422 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "control-command.hpp" -#include "command-options.hpp" // only used in deprecated functions - -namespace ndn { -namespace nfd { - -ControlCommand::ControlCommand(const std::string& module, const std::string& verb) - : m_module(module) - , m_verb(verb) -{ -} - -ControlCommand::~ControlCommand() = default; - -void -ControlCommand::validateRequest(const ControlParameters& parameters) const -{ - m_requestValidator.validate(parameters); -} - -void -ControlCommand::applyDefaultsToRequest(ControlParameters& parameters) const -{ -} - -void -ControlCommand::validateResponse(const ControlParameters& parameters) const -{ - m_responseValidator.validate(parameters); -} - -void -ControlCommand::applyDefaultsToResponse(ControlParameters& parameters) const -{ -} - -Name -ControlCommand::getRequestName(const Name& commandPrefix, - const ControlParameters& parameters) const -{ - this->validateRequest(parameters); - - Name name = commandPrefix; - name.append(m_module).append(m_verb); - name.append(parameters.wireEncode()); - return name; -} - -ControlCommand::FieldValidator::FieldValidator() - : m_required(CONTROL_PARAMETER_UBOUND) - , m_optional(CONTROL_PARAMETER_UBOUND) -{ -} - -void -ControlCommand::FieldValidator::validate(const ControlParameters& parameters) const -{ - const std::vector& presentFields = parameters.getPresentFields(); - - for (size_t i = 0; i < CONTROL_PARAMETER_UBOUND; ++i) { - bool isPresent = presentFields[i]; - if (m_required[i]) { - if (!isPresent) { - BOOST_THROW_EXCEPTION(ArgumentError(CONTROL_PARAMETER_FIELD[i] + " is required but " - "missing")); - } - } - else if (isPresent && !m_optional[i]) { - BOOST_THROW_EXCEPTION(ArgumentError(CONTROL_PARAMETER_FIELD[i] + " is forbidden but " - "present")); - } - } -} - -FaceCreateCommand::FaceCreateCommand() - : ControlCommand("faces", "create") -{ - m_requestValidator - .required(CONTROL_PARAMETER_URI) - .optional(CONTROL_PARAMETER_FACE_PERSISTENCY) - .optional(CONTROL_PARAMETER_FLAGS) - .optional(CONTROL_PARAMETER_MASK); - m_responseValidator - .required(CONTROL_PARAMETER_FACE_ID) - .required(CONTROL_PARAMETER_FACE_PERSISTENCY) - .optional(CONTROL_PARAMETER_FLAGS) - .optional(CONTROL_PARAMETER_URI); -} - -void -FaceCreateCommand::applyDefaultsToRequest(ControlParameters& parameters) const -{ - parameters.setFaceId(0); - - if (!parameters.hasFacePersistency()) { - parameters.setFacePersistency(FacePersistency::FACE_PERSISTENCY_PERSISTENT); - } -} - -void -FaceCreateCommand::validateRequest(const ControlParameters& parameters) const -{ - this->ControlCommand::validateRequest(parameters); - - if (parameters.hasFlags() != parameters.hasMask()) { - BOOST_THROW_EXCEPTION(ArgumentError("Flags must be accompanied by Mask")); - } -} - -void -FaceCreateCommand::validateResponse(const ControlParameters& parameters) const -{ - this->ControlCommand::validateResponse(parameters); - - if (parameters.getFaceId() == 0) { - BOOST_THROW_EXCEPTION(ArgumentError("FaceId must not be zero")); - } -} - -FaceUpdateCommand::FaceUpdateCommand() - : ControlCommand("faces", "update") -{ - m_requestValidator - .optional(CONTROL_PARAMETER_FACE_ID) - .optional(CONTROL_PARAMETER_FACE_PERSISTENCY) - .optional(CONTROL_PARAMETER_FLAGS) - .optional(CONTROL_PARAMETER_MASK); - m_responseValidator - .required(CONTROL_PARAMETER_FACE_ID) - .required(CONTROL_PARAMETER_FACE_PERSISTENCY) - .required(CONTROL_PARAMETER_FLAGS); -} - -void -FaceUpdateCommand::applyDefaultsToRequest(ControlParameters& parameters) const -{ - if (!parameters.hasFaceId()) { - parameters.setFaceId(0); - } -} - -void -FaceUpdateCommand::validateRequest(const ControlParameters& parameters) const -{ - this->ControlCommand::validateRequest(parameters); - - if (parameters.hasFlags() != parameters.hasMask()) { - BOOST_THROW_EXCEPTION(ArgumentError("Flags must be accompanied by Mask")); - } -} - -void -FaceUpdateCommand::validateResponse(const ControlParameters& parameters) const -{ - this->ControlCommand::validateResponse(parameters); - - if (parameters.getFaceId() == 0) { - BOOST_THROW_EXCEPTION(ArgumentError("FaceId must not be zero")); - } -} - -FaceDestroyCommand::FaceDestroyCommand() - : ControlCommand("faces", "destroy") -{ - m_requestValidator - .required(CONTROL_PARAMETER_FACE_ID); - m_responseValidator = m_requestValidator; -} - -void -FaceDestroyCommand::validateRequest(const ControlParameters& parameters) const -{ - this->ControlCommand::validateRequest(parameters); - - if (parameters.getFaceId() == 0) { - BOOST_THROW_EXCEPTION(ArgumentError("FaceId must not be zero")); - } -} - -void -FaceDestroyCommand::validateResponse(const ControlParameters& parameters) const -{ - this->validateRequest(parameters); -} - -FaceLocalControlCommand::FaceLocalControlCommand(const std::string& verb) - : ControlCommand("faces", verb) -{ - m_requestValidator - .required(CONTROL_PARAMETER_LOCAL_CONTROL_FEATURE); - m_responseValidator = m_requestValidator; -} - -void -FaceLocalControlCommand::validateRequest(const ControlParameters& parameters) const -{ - this->ControlCommand::validateRequest(parameters); - - switch (parameters.getLocalControlFeature()) { - case LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID: - case LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID: - break; - default: - BOOST_THROW_EXCEPTION(ArgumentError("LocalControlFeature is invalid")); - } -} - -void -FaceLocalControlCommand::validateResponse(const ControlParameters& parameters) const -{ - this->validateRequest(parameters); -} - -FaceEnableLocalControlCommand::FaceEnableLocalControlCommand() - : FaceLocalControlCommand("enable-local-control") -{ -} - -FaceDisableLocalControlCommand::FaceDisableLocalControlCommand() - : FaceLocalControlCommand("disable-local-control") -{ -} - -FibAddNextHopCommand::FibAddNextHopCommand() - : ControlCommand("fib", "add-nexthop") -{ - m_requestValidator - .required(CONTROL_PARAMETER_NAME) - .optional(CONTROL_PARAMETER_FACE_ID) - .optional(CONTROL_PARAMETER_COST); - m_responseValidator - .required(CONTROL_PARAMETER_NAME) - .required(CONTROL_PARAMETER_FACE_ID) - .required(CONTROL_PARAMETER_COST); -} - -void -FibAddNextHopCommand::applyDefaultsToRequest(ControlParameters& parameters) const -{ - if (!parameters.hasFaceId()) { - parameters.setFaceId(0); - } - if (!parameters.hasCost()) { - parameters.setCost(0); - } -} - -void -FibAddNextHopCommand::validateResponse(const ControlParameters& parameters) const -{ - this->ControlCommand::validateResponse(parameters); - - if (parameters.getFaceId() == 0) { - BOOST_THROW_EXCEPTION(ArgumentError("FaceId must not be zero")); - } -} - -FibRemoveNextHopCommand::FibRemoveNextHopCommand() - : ControlCommand("fib", "remove-nexthop") -{ - m_requestValidator - .required(CONTROL_PARAMETER_NAME) - .optional(CONTROL_PARAMETER_FACE_ID); - m_responseValidator - .required(CONTROL_PARAMETER_NAME) - .required(CONTROL_PARAMETER_FACE_ID); -} - -void -FibRemoveNextHopCommand::applyDefaultsToRequest(ControlParameters& parameters) const -{ - if (!parameters.hasFaceId()) { - parameters.setFaceId(0); - } -} - -void -FibRemoveNextHopCommand::validateResponse(const ControlParameters& parameters) const -{ - this->ControlCommand::validateResponse(parameters); - - if (parameters.getFaceId() == 0) { - BOOST_THROW_EXCEPTION(ArgumentError("FaceId must not be zero")); - } -} - -StrategyChoiceSetCommand::StrategyChoiceSetCommand() - : ControlCommand("strategy-choice", "set") -{ - m_requestValidator - .required(CONTROL_PARAMETER_NAME) - .required(CONTROL_PARAMETER_STRATEGY); - m_responseValidator = m_requestValidator; -} - -StrategyChoiceUnsetCommand::StrategyChoiceUnsetCommand() - : ControlCommand("strategy-choice", "unset") -{ - m_requestValidator - .required(CONTROL_PARAMETER_NAME); - m_responseValidator = m_requestValidator; -} - -void -StrategyChoiceUnsetCommand::validateRequest(const ControlParameters& parameters) const -{ - this->ControlCommand::validateRequest(parameters); - - if (parameters.getName().size() == 0) { - BOOST_THROW_EXCEPTION(ArgumentError("Name must not be ndn:/")); - } -} - -void -StrategyChoiceUnsetCommand::validateResponse(const ControlParameters& parameters) const -{ - this->validateRequest(parameters); -} - -RibRegisterCommand::RibRegisterCommand() - : ControlCommand("rib", "register") -{ - m_requestValidator - .required(CONTROL_PARAMETER_NAME) - .optional(CONTROL_PARAMETER_FACE_ID) - .optional(CONTROL_PARAMETER_ORIGIN) - .optional(CONTROL_PARAMETER_COST) - .optional(CONTROL_PARAMETER_FLAGS) - .optional(CONTROL_PARAMETER_EXPIRATION_PERIOD); - m_responseValidator - .required(CONTROL_PARAMETER_NAME) - .required(CONTROL_PARAMETER_FACE_ID) - .required(CONTROL_PARAMETER_ORIGIN) - .required(CONTROL_PARAMETER_COST) - .required(CONTROL_PARAMETER_FLAGS) - .optional(CONTROL_PARAMETER_EXPIRATION_PERIOD); -} - -void -RibRegisterCommand::applyDefaultsToRequest(ControlParameters& parameters) const -{ - if (!parameters.hasFaceId()) { - parameters.setFaceId(0); - } - if (!parameters.hasOrigin()) { - parameters.setOrigin(ROUTE_ORIGIN_APP); - } - if (!parameters.hasCost()) { - parameters.setCost(0); - } - if (!parameters.hasFlags()) { - parameters.setFlags(ROUTE_FLAG_CHILD_INHERIT); - } -} - -void -RibRegisterCommand::validateResponse(const ControlParameters& parameters) const -{ - this->ControlCommand::validateResponse(parameters); - - if (parameters.getFaceId() == 0) { - BOOST_THROW_EXCEPTION(ArgumentError("FaceId must not be zero")); - } -} - -RibUnregisterCommand::RibUnregisterCommand() - : ControlCommand("rib", "unregister") -{ - m_requestValidator - .required(CONTROL_PARAMETER_NAME) - .optional(CONTROL_PARAMETER_FACE_ID) - .optional(CONTROL_PARAMETER_ORIGIN); - m_responseValidator - .required(CONTROL_PARAMETER_NAME) - .required(CONTROL_PARAMETER_FACE_ID) - .required(CONTROL_PARAMETER_ORIGIN); -} - -void -RibUnregisterCommand::applyDefaultsToRequest(ControlParameters& parameters) const -{ - if (!parameters.hasFaceId()) { - parameters.setFaceId(0); - } - if (!parameters.hasOrigin()) { - parameters.setOrigin(ROUTE_ORIGIN_APP); - } -} - -void -RibUnregisterCommand::validateResponse(const ControlParameters& parameters) const -{ - this->ControlCommand::validateResponse(parameters); - - if (parameters.getFaceId() == 0) { - BOOST_THROW_EXCEPTION(ArgumentError("FaceId must not be zero")); - } -} - -} // namespace nfd -} // namespace ndn diff --git a/src/mgmt/nfd/control-parameters.cpp b/src/mgmt/nfd/control-parameters.cpp deleted file mode 100644 index 30f8fe94f..000000000 --- a/src/mgmt/nfd/control-parameters.cpp +++ /dev/null @@ -1,335 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "control-parameters.hpp" -#include "encoding/tlv-nfd.hpp" -#include "encoding/block-helpers.hpp" -#include "util/concepts.hpp" - -namespace ndn { -namespace nfd { - -//BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "ControlParameters::Error must inherit from tlv::Error"); - -ControlParameters::ControlParameters() - : m_hasFields(CONTROL_PARAMETER_UBOUND) -{ -} - -ControlParameters::ControlParameters(const Block& block) - : m_hasFields(CONTROL_PARAMETER_UBOUND) -{ - wireDecode(block); -} - -template -size_t -ControlParameters::wireEncode(EncodingImpl& encoder) const -{ - size_t totalLength = 0; - - if (this->hasFacePersistency()) { - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::FacePersistency, m_facePersistency); - } - if (this->hasExpirationPeriod()) { - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::ExpirationPeriod, m_expirationPeriod.count()); - } - if (this->hasStrategy()) { - totalLength += prependNestedBlock(encoder, tlv::nfd::Strategy, m_strategy); - } - if (this->hasMask()) { - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Mask, m_mask); - } - if (this->hasFlags()) { - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Flags, m_flags); - } - if (this->hasCost()) { - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Cost, m_cost); - } - if (this->hasOrigin()) { - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Origin, m_origin); - } - if (this->hasLocalControlFeature()) { - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::LocalControlFeature, m_localControlFeature); - } - if (this->hasUri()) { - size_t valLength = encoder.prependByteArray( - reinterpret_cast(m_uri.c_str()), m_uri.size()); - totalLength += valLength; - totalLength += encoder.prependVarNumber(valLength); - totalLength += encoder.prependVarNumber(tlv::nfd::Uri); - } - if (this->hasFaceId()) { - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::FaceId, m_faceId); - } - if (this->hasName()) { - totalLength += m_name.wireEncode(encoder); - } - - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::nfd::ControlParameters); - return totalLength; -} - -template size_t -ControlParameters::wireEncode(EncodingImpl&) const; - -template size_t -ControlParameters::wireEncode(EncodingImpl&) const; - -Block -ControlParameters::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 -ControlParameters::wireDecode(const Block& block) -{ - if (block.type() != tlv::nfd::ControlParameters) { - BOOST_THROW_EXCEPTION(Error("Expecting TLV-TYPE ControlParameters")); - } - m_wire = block; - m_wire.parse(); - Block::element_const_iterator val; - - val = m_wire.find(tlv::Name); - m_hasFields[CONTROL_PARAMETER_NAME] = val != m_wire.elements_end(); - if (this->hasName()) { - m_name.wireDecode(*val); - } - - val = m_wire.find(tlv::nfd::FaceId); - m_hasFields[CONTROL_PARAMETER_FACE_ID] = val != m_wire.elements_end(); - if (this->hasFaceId()) { - m_faceId = static_cast(readNonNegativeInteger(*val)); - } - - val = m_wire.find(tlv::nfd::Uri); - m_hasFields[CONTROL_PARAMETER_URI] = val != m_wire.elements_end(); - if (this->hasUri()) { - m_uri.assign(reinterpret_cast(val->value()), val->value_size()); - } - - val = m_wire.find(tlv::nfd::LocalControlFeature); - m_hasFields[CONTROL_PARAMETER_LOCAL_CONTROL_FEATURE] = val != m_wire.elements_end(); - if (this->hasLocalControlFeature()) { - m_localControlFeature = static_cast(readNonNegativeInteger(*val)); - } - - val = m_wire.find(tlv::nfd::Origin); - m_hasFields[CONTROL_PARAMETER_ORIGIN] = val != m_wire.elements_end(); - if (this->hasOrigin()) { - m_origin = static_cast(readNonNegativeInteger(*val)); - } - - val = m_wire.find(tlv::nfd::Cost); - m_hasFields[CONTROL_PARAMETER_COST] = val != m_wire.elements_end(); - if (this->hasCost()) { - m_cost = static_cast(readNonNegativeInteger(*val)); - } - - val = m_wire.find(tlv::nfd::Flags); - m_hasFields[CONTROL_PARAMETER_FLAGS] = val != m_wire.elements_end(); - if (this->hasFlags()) { - m_flags = static_cast(readNonNegativeInteger(*val)); - } - - val = m_wire.find(tlv::nfd::Mask); - m_hasFields[CONTROL_PARAMETER_MASK] = val != m_wire.elements_end(); - if (this->hasMask()) { - m_mask = static_cast(readNonNegativeInteger(*val)); - } - - val = m_wire.find(tlv::nfd::Strategy); - m_hasFields[CONTROL_PARAMETER_STRATEGY] = val != m_wire.elements_end(); - if (this->hasStrategy()) { - val->parse(); - if (val->elements().empty()) { - BOOST_THROW_EXCEPTION(Error("Expecting Strategy/Name")); - } - else { - m_strategy.wireDecode(*val->elements_begin()); - } - } - - val = m_wire.find(tlv::nfd::ExpirationPeriod); - m_hasFields[CONTROL_PARAMETER_EXPIRATION_PERIOD] = val != m_wire.elements_end(); - if (this->hasExpirationPeriod()) { - m_expirationPeriod = time::milliseconds(readNonNegativeInteger(*val)); - } - - val = m_wire.find(tlv::nfd::FacePersistency); - m_hasFields[CONTROL_PARAMETER_FACE_PERSISTENCY] = val != m_wire.elements_end(); - if (this->hasFacePersistency()) { - m_facePersistency = static_cast(readNonNegativeInteger(*val)); - } -} - -bool -ControlParameters::hasFlagBit(size_t bit) const -{ - if (bit >= 64) { - BOOST_THROW_EXCEPTION(std::out_of_range("bit must be within range [0, 64)")); - } - - if (!hasMask()) { - return false; - } - - return getMask() & (1 << bit); -} - -bool -ControlParameters::getFlagBit(size_t bit) const -{ - if (bit >= 64) { - BOOST_THROW_EXCEPTION(std::out_of_range("bit must be within range [0, 64)")); - } - - if (!hasFlags()) { - return false; - } - - return getFlags() & (1 << bit); -} - -ControlParameters& -ControlParameters::setFlagBit(size_t bit, bool value, bool wantMask/* = true*/) -{ - if (bit >= 64) { - BOOST_THROW_EXCEPTION(std::out_of_range("bit must be within range [0, 64)")); - } - - uint64_t flags = hasFlags() ? getFlags() : 0; - if (value) { - flags |= (1 << bit); - } - else { - flags &= ~(1 << bit); - } - setFlags(flags); - - if (wantMask) { - uint64_t mask = hasMask() ? getMask() : 0; - mask |= (1 << bit); - setMask(mask); - } - - return *this; -} - -ControlParameters& -ControlParameters::unsetFlagBit(size_t bit) -{ - if (bit >= 64) { - BOOST_THROW_EXCEPTION(std::out_of_range("bit must be within range [0, 64)")); - } - - uint64_t mask = hasMask() ? getMask() : 0; - mask &= ~(1 << bit); - if (mask == 0) { - unsetMask(); - unsetFlags(); - } - else { - setMask(mask); - } - - return *this; -} - -std::ostream& -operator<<(std::ostream& os, const ControlParameters& parameters) -{ - os << "ControlParameters("; - - if (parameters.hasName()) { - os << "Name: " << parameters.getName() << ", "; - } - - if (parameters.hasFaceId()) { - os << "FaceId: " << parameters.getFaceId() << ", "; - } - - if (parameters.hasUri()) { - os << "Uri: " << parameters.getUri() << ", "; - } - - if (parameters.hasLocalControlFeature()) { - os << "LocalControlFeature: " << parameters.getLocalControlFeature() << ", "; - } - - if (parameters.hasOrigin()) { - os << "Origin: " << parameters.getOrigin() << ", "; - } - - if (parameters.hasCost()) { - os << "Cost: " << parameters.getCost() << ", "; - } - - if (parameters.hasFlags()) { - std::ios_base::fmtflags osFlags = os.flags(); - os << "Flags: " << std::showbase << std::hex << parameters.getFlags() << ", "; - os.flags(osFlags); - } - - if (parameters.hasMask()) { - std::ios_base::fmtflags osFlags = os.flags(); - os << "Mask: " << std::showbase << std::hex << parameters.getMask() << ", "; - os.flags(osFlags); - } - - if (parameters.hasStrategy()) { - os << "Strategy: " << parameters.getStrategy() << ", "; - } - - if (parameters.hasExpirationPeriod()) { - os << "ExpirationPeriod: " << parameters.getExpirationPeriod() << ", "; - } - - if (parameters.hasFacePersistency()) { - os << "FacePersistency: " << parameters.getFacePersistency() << ", "; - } - - os << ")"; - return os; -} - -} // namespace nfd -} // namespace ndn diff --git a/src/mgmt/nfd/control-parameters.hpp b/src/mgmt/nfd/control-parameters.hpp deleted file mode 100644 index d57c75d65..000000000 --- a/src/mgmt/nfd/control-parameters.hpp +++ /dev/null @@ -1,514 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_MGMT_NFD_CONTROL_PARAMETERS_HPP -#define NDN_MGMT_NFD_CONTROL_PARAMETERS_HPP - -#include "../../encoding/nfd-constants.hpp" -#include "../../name.hpp" -#include "../../util/time.hpp" -#include "../control-parameters.hpp" - -namespace ndn { -namespace nfd { - -/** - * \ingroup management - */ -enum ControlParameterField { - CONTROL_PARAMETER_NAME, - CONTROL_PARAMETER_FACE_ID, - CONTROL_PARAMETER_URI, - CONTROL_PARAMETER_LOCAL_CONTROL_FEATURE, - CONTROL_PARAMETER_ORIGIN, - CONTROL_PARAMETER_COST, - CONTROL_PARAMETER_FLAGS, - CONTROL_PARAMETER_MASK, - CONTROL_PARAMETER_STRATEGY, - CONTROL_PARAMETER_EXPIRATION_PERIOD, - CONTROL_PARAMETER_FACE_PERSISTENCY, - CONTROL_PARAMETER_UBOUND -}; - -const std::string CONTROL_PARAMETER_FIELD[CONTROL_PARAMETER_UBOUND] = { - "Name", - "FaceId", - "Uri", - "LocalControlFeature", - "Origin", - "Cost", - "Flags", - "Mask", - "Strategy", - "ExpirationPeriod", - "FacePersistency" -}; - -/** - * \ingroup management - * \deprecated use Flags+Mask fields instead - */ -enum LocalControlFeature { - LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID = 1, - LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID = 2 -}; - -/** - * \ingroup management - * \brief represents parameters in a ControlCommand request or response - * \sa http://redmine.named-data.net/projects/nfd/wiki/ControlCommand#ControlParameters - * \details This type is copyable because it's an abstraction of a TLV type. - */ -class ControlParameters : public ndn::mgmt::ControlParameters -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - - ControlParameters(); - - explicit - ControlParameters(const Block& block); - - template - size_t - wireEncode(EncodingImpl& encoder) const; - - virtual Block - wireEncode() const final; - - virtual void - wireDecode(const Block& wire) final; - -public: // getters & setters - bool - hasName() const - { - return m_hasFields[CONTROL_PARAMETER_NAME]; - } - - const Name& - getName() const - { - BOOST_ASSERT(this->hasName()); - return m_name; - } - - ControlParameters& - setName(const Name& name) - { - m_wire.reset(); - m_name = name; - m_hasFields[CONTROL_PARAMETER_NAME] = true; - return *this; - } - - ControlParameters& - unsetName() - { - m_wire.reset(); - m_hasFields[CONTROL_PARAMETER_NAME] = false; - return *this; - } - - bool - hasFaceId() const - { - return m_hasFields[CONTROL_PARAMETER_FACE_ID]; - } - - uint64_t - getFaceId() const - { - BOOST_ASSERT(this->hasFaceId()); - return m_faceId; - } - - ControlParameters& - setFaceId(uint64_t faceId) - { - m_wire.reset(); - m_faceId = faceId; - m_hasFields[CONTROL_PARAMETER_FACE_ID] = true; - return *this; - } - - ControlParameters& - unsetFaceId() - { - m_wire.reset(); - m_hasFields[CONTROL_PARAMETER_FACE_ID] = false; - return *this; - } - - bool - hasUri() const - { - return m_hasFields[CONTROL_PARAMETER_URI]; - } - - const std::string& - getUri() const - { - BOOST_ASSERT(this->hasUri()); - return m_uri; - } - - ControlParameters& - setUri(const std::string& uri) - { - m_wire.reset(); - m_uri = uri; - m_hasFields[CONTROL_PARAMETER_URI] = true; - return *this; - } - - ControlParameters& - unsetUri() - { - m_wire.reset(); - m_hasFields[CONTROL_PARAMETER_URI] = false; - return *this; - } - - /** - * \deprecated use Flags+Mask fields instead - */ - bool - hasLocalControlFeature() const - { - return m_hasFields[CONTROL_PARAMETER_LOCAL_CONTROL_FEATURE]; - } - - /** - * \deprecated use Flags+Mask fields instead - */ - LocalControlFeature - getLocalControlFeature() const - { - BOOST_ASSERT(this->hasLocalControlFeature()); - return m_localControlFeature; - } - - /** - * \deprecated use Flags+Mask fields instead - */ - ControlParameters& - setLocalControlFeature(LocalControlFeature localControlFeature) - { - m_wire.reset(); - m_localControlFeature = localControlFeature; - m_hasFields[CONTROL_PARAMETER_LOCAL_CONTROL_FEATURE] = true; - return *this; - } - - /** - * \deprecated use Flags+Mask fields instead - */ - ControlParameters& - unsetLocalControlFeature() - { - m_wire.reset(); - m_hasFields[CONTROL_PARAMETER_LOCAL_CONTROL_FEATURE] = false; - return *this; - } - - bool - hasOrigin() const - { - return m_hasFields[CONTROL_PARAMETER_ORIGIN]; - } - - uint64_t - getOrigin() const - { - BOOST_ASSERT(this->hasOrigin()); - return m_origin; - } - - ControlParameters& - setOrigin(uint64_t origin) - { - m_wire.reset(); - m_origin = origin; - m_hasFields[CONTROL_PARAMETER_ORIGIN] = true; - return *this; - } - - ControlParameters& - unsetOrigin() - { - m_wire.reset(); - m_hasFields[CONTROL_PARAMETER_ORIGIN] = false; - return *this; - } - - bool - hasCost() const - { - return m_hasFields[CONTROL_PARAMETER_COST]; - } - - uint64_t - getCost() const - { - BOOST_ASSERT(this->hasCost()); - return m_cost; - } - - ControlParameters& - setCost(uint64_t cost) - { - m_wire.reset(); - m_cost = cost; - m_hasFields[CONTROL_PARAMETER_COST] = true; - return *this; - } - - ControlParameters& - unsetCost() - { - m_wire.reset(); - m_hasFields[CONTROL_PARAMETER_COST] = false; - return *this; - } - - bool - hasFlags() const - { - return m_hasFields[CONTROL_PARAMETER_FLAGS]; - } - - uint64_t - getFlags() const - { - BOOST_ASSERT(this->hasFlags()); - return m_flags; - } - - ControlParameters& - setFlags(uint64_t flags) - { - m_wire.reset(); - m_flags = flags; - m_hasFields[CONTROL_PARAMETER_FLAGS] = true; - return *this; - } - - ControlParameters& - unsetFlags() - { - m_wire.reset(); - m_hasFields[CONTROL_PARAMETER_FLAGS] = false; - return *this; - } - - bool - hasMask() const - { - return m_hasFields[CONTROL_PARAMETER_MASK]; - } - - uint64_t - getMask() const - { - BOOST_ASSERT(this->hasMask()); - return m_mask; - } - - ControlParameters& - setMask(uint64_t mask) - { - m_wire.reset(); - m_mask = mask; - m_hasFields[CONTROL_PARAMETER_MASK] = true; - return *this; - } - - ControlParameters& - unsetMask() - { - m_wire.reset(); - m_hasFields[CONTROL_PARAMETER_MASK] = false; - return *this; - } - - bool - hasStrategy() const - { - return m_hasFields[CONTROL_PARAMETER_STRATEGY]; - } - - const Name& - getStrategy() const - { - BOOST_ASSERT(this->hasStrategy()); - return m_strategy; - } - - ControlParameters& - setStrategy(const Name& strategy) - { - m_wire.reset(); - m_strategy = strategy; - m_hasFields[CONTROL_PARAMETER_STRATEGY] = true; - return *this; - } - - ControlParameters& - unsetStrategy() - { - m_wire.reset(); - m_hasFields[CONTROL_PARAMETER_STRATEGY] = false; - return *this; - } - - bool - hasExpirationPeriod() const - { - return m_hasFields[CONTROL_PARAMETER_EXPIRATION_PERIOD]; - } - - const time::milliseconds& - getExpirationPeriod() const - { - BOOST_ASSERT(this->hasExpirationPeriod()); - return m_expirationPeriod; - } - - ControlParameters& - setExpirationPeriod(const time::milliseconds& expirationPeriod) - { - m_wire.reset(); - m_expirationPeriod = expirationPeriod; - m_hasFields[CONTROL_PARAMETER_EXPIRATION_PERIOD] = true; - return *this; - } - - ControlParameters& - unsetExpirationPeriod() - { - m_wire.reset(); - m_hasFields[CONTROL_PARAMETER_EXPIRATION_PERIOD] = false; - return *this; - } - - bool - hasFacePersistency() const - { - return m_hasFields[CONTROL_PARAMETER_FACE_PERSISTENCY]; - } - - FacePersistency - getFacePersistency() const - { - BOOST_ASSERT(this->hasFacePersistency()); - return m_facePersistency; - } - - ControlParameters& - setFacePersistency(FacePersistency persistency) - { - m_wire.reset(); - m_facePersistency = persistency; - m_hasFields[CONTROL_PARAMETER_FACE_PERSISTENCY] = true; - return *this; - } - - ControlParameters& - unsetFacePersistency() - { - m_wire.reset(); - m_hasFields[CONTROL_PARAMETER_FACE_PERSISTENCY] = false; - return *this; - } - - const std::vector& - getPresentFields() const - { - return m_hasFields; - } - -public: // Flags and Mask helpers - /** - * \return whether bit is enabled in Mask - * \param bit bit position within range [0, 64) (least significant bit is 0) - */ - bool - hasFlagBit(size_t bit) const; - - /** - * \return bit at a position in Flags - * \param bit bit position within range [0, 64) (least significant bit is 0) - */ - bool - getFlagBit(size_t bit) const; - - /** - * \brief set a bit in Flags - * \param bit bit position within range [0, 64) (least significant bit is 0) - * \param value new value in Flags - * \param wantMask if true, enable the bit in Mask - */ - ControlParameters& - setFlagBit(size_t bit, bool value, bool wantMask = true); - - /** - * \brief disable a bit in Mask - * \param bit bit position within range [0, 64) (least significant bit is 0) - * \post If all bits are disabled, Flags and Mask fields are deleted. - */ - ControlParameters& - unsetFlagBit(size_t bit); - -private: // fields - std::vector m_hasFields; - - Name m_name; - uint64_t m_faceId; - std::string m_uri; - LocalControlFeature m_localControlFeature; - uint64_t m_origin; - uint64_t m_cost; - uint64_t m_flags; - uint64_t m_mask; - Name m_strategy; - time::milliseconds m_expirationPeriod; - FacePersistency m_facePersistency; - -private: - mutable Block m_wire; -}; - -std::ostream& -operator<<(std::ostream& os, const ControlParameters& parameters); - -} // namespace nfd -} // namespace ndn - -#endif // NDN_MGMT_NFD_CONTROL_PARAMETERS_HPP diff --git a/src/mgmt/nfd/control-response.hpp b/src/mgmt/nfd/control-response.hpp deleted file mode 100644 index 8234e2d7a..000000000 --- a/src/mgmt/nfd/control-response.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_MANAGEMENT_CONTROL_RESPONSE_HPP -#define NDN_MANAGEMENT_CONTROL_RESPONSE_HPP - -#include "../dispatcher.hpp" - -namespace ndn { -namespace nfd { - -typedef ndn::mgmt::ControlResponse ControlResponse; - -} // namespace nfd -} // namespace ndn - -#endif // NDN_MANAGEMENT_CONTROL_RESPONSE_HPP diff --git a/src/mgmt/nfd/controller.cpp b/src/mgmt/nfd/controller.cpp deleted file mode 100644 index cfb7956f2..000000000 --- a/src/mgmt/nfd/controller.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "controller.hpp" -#include "../../face.hpp" -#include "../../security/key-chain.hpp" -#include "../../util/segment-fetcher.hpp" - -namespace ndn { -namespace nfd { - -using ndn::util::SegmentFetcher; - -const uint32_t Controller::ERROR_TIMEOUT = 10060; // WinSock ESAETIMEDOUT -const uint32_t Controller::ERROR_NACK = 10800; // 10000 + TLV-TYPE of Nack header -const uint32_t Controller::ERROR_VALIDATION = 10021; // 10000 + TLS1_ALERT_DECRYPTION_FAILED -const uint32_t Controller::ERROR_SERVER = 500; -const uint32_t Controller::ERROR_LBOUND = 400; -ValidatorNull Controller::s_validatorNull; - -Controller::Controller(Face& face, KeyChain& keyChain, Validator& validator) - : m_face(face) - , m_keyChain(keyChain) - , m_validator(validator) -{ -} - -void -Controller::startCommand(const shared_ptr& command, - const ControlParameters& parameters, - const CommandSucceedCallback& onSuccess1, - const CommandFailCallback& onFailure1, - const CommandOptions& options) -{ - const CommandSucceedCallback& onSuccess = onSuccess1 ? - onSuccess1 : [] (const ControlParameters&) {}; - const CommandFailCallback& onFailure = onFailure1 ? - onFailure1 : [] (const ControlResponse&) {}; - - Name requestName = command->getRequestName(options.getPrefix(), parameters); - Interest interest(requestName); - interest.setInterestLifetime(options.getTimeout()); - m_keyChain.sign(interest, options.getSigningInfo()); - - m_face.expressInterest(interest, - [=] (const Interest&, const Data& data) { - this->processCommandResponse(data, command, onSuccess, onFailure); - }, - [=] (const Interest&, const lp::Nack&) { - onFailure(ControlResponse(Controller::ERROR_NACK, "network Nack received")); - }, - [=] (const Interest&) { - onFailure(ControlResponse(Controller::ERROR_TIMEOUT, "request timed out")); - }); -} - -void -Controller::processCommandResponse(const Data& data, - const shared_ptr& command, - const CommandSucceedCallback& onSuccess, - const CommandFailCallback& onFailure) -{ - m_validator.validate(data, - [=] (const shared_ptr& data) { - this->processValidatedCommandResponse(*data, command, onSuccess, onFailure); - }, - [=] (const shared_ptr&, const std::string& msg) { - onFailure(ControlResponse(ERROR_VALIDATION, msg)); - } - ); -} - -void -Controller::processValidatedCommandResponse(const Data& data, - const shared_ptr& command, - const CommandSucceedCallback& onSuccess, - const CommandFailCallback& onFailure) -{ - ControlResponse response; - try { - response.wireDecode(data.getContent().blockFromValue()); - } - catch (const tlv::Error& e) { - onFailure(ControlResponse(ERROR_SERVER, e.what())); - return; - } - - uint32_t code = response.getCode(); - if (code >= ERROR_LBOUND) { - onFailure(response); - return; - } - - ControlParameters parameters; - try { - parameters.wireDecode(response.getBody()); - } - catch (const tlv::Error& e) { - onFailure(ControlResponse(ERROR_SERVER, e.what())); - return; - } - - try { - command->validateResponse(parameters); - } - catch (const ControlCommand::ArgumentError& e) { - onFailure(ControlResponse(ERROR_SERVER, e.what())); - return; - } - - onSuccess(parameters); -} - -void -Controller::fetchDataset(const Name& prefix, - const std::function& processResponse, - const DatasetFailCallback& onFailure, - const CommandOptions& options) -{ - Interest baseInterest(prefix); - baseInterest.setInterestLifetime(options.getTimeout()); - - SegmentFetcher::fetch(m_face, baseInterest, m_validator, processResponse, - bind(&Controller::processDatasetFetchError, this, onFailure, _1, _2)); -} - -void -Controller::processDatasetFetchError(const DatasetFailCallback& onFailure, - uint32_t code, std::string msg) -{ - switch (static_cast(code)) { - // It's intentional to cast as SegmentFetcher::ErrorCode, and to not have a 'default' clause. - // This forces the switch statement to handle every defined SegmentFetcher::ErrorCode, - // and breaks compilation if it does not. - case SegmentFetcher::ErrorCode::INTEREST_TIMEOUT: - onFailure(ERROR_TIMEOUT, msg); - break; - case SegmentFetcher::ErrorCode::DATA_HAS_NO_SEGMENT: - onFailure(ERROR_SERVER, msg); - break; - case SegmentFetcher::ErrorCode::SEGMENT_VALIDATION_FAIL: - /// \todo When SegmentFetcher exposes validator error code, Controller::ERROR_VALIDATION - /// should be replaced with a range that corresponds to validator error codes. - onFailure(ERROR_VALIDATION, msg); - break; - case SegmentFetcher::ErrorCode::NACK_ERROR: - onFailure(ERROR_NACK, msg); - break; - } -} - -} // namespace nfd -} // namespace ndn diff --git a/src/mgmt/nfd/controller.hpp b/src/mgmt/nfd/controller.hpp deleted file mode 100644 index 3d3808c03..000000000 --- a/src/mgmt/nfd/controller.hpp +++ /dev/null @@ -1,221 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_MGMT_NFD_CONTROLLER_HPP -#define NDN_MGMT_NFD_CONTROLLER_HPP - -#include "control-command.hpp" -#include "control-response.hpp" -#include "status-dataset.hpp" -#include "command-options.hpp" -#include "../../security/validator-null.hpp" - -namespace ndn { - -namespace security { -class KeyChain; -class Validator; -} // namespace security -class Face; - -namespace nfd { - -/** - * \defgroup management Management - * \brief Classes and data structures to manage NDN forwarder - */ - -/** - * \ingroup management - * \brief NFD Management protocol client - * \sa https://redmine.named-data.net/projects/nfd/wiki/Management - */ -class Controller : noncopyable -{ -public: - /** \brief a callback on command success - */ - typedef function CommandSucceedCallback; - - /** \brief a callback on command failure - */ - typedef function CommandFailCallback; - - /** \brief a callback on dataset retrieval failure - */ - typedef function DatasetFailCallback; - - /** \brief construct a Controller that uses face for transport, - * and uses the passed KeyChain to sign commands - */ - Controller(Face& face, security::KeyChain& keyChain, security::Validator& validator = s_validatorNull); - - /** \brief start command execution - */ - template - void - start(const ControlParameters& parameters, - const CommandSucceedCallback& onSuccess, - const CommandFailCallback& onFailure, - const CommandOptions& options = CommandOptions()) - { - shared_ptr command = make_shared(); - this->startCommand(command, parameters, onSuccess, onFailure, options); - } - - /** \brief start dataset fetching - */ - template - typename std::enable_if::value>::type - fetch(const std::function& onSuccess, - const DatasetFailCallback& onFailure, - const CommandOptions& options = CommandOptions()) - { - this->fetchDataset(make_shared(), onSuccess, onFailure, options); - } - - /** \brief start dataset fetching - */ - template - void - fetch(const ParamType& param, - const std::function& onSuccess, - const DatasetFailCallback& onFailure, - const CommandOptions& options = CommandOptions()) - { - this->fetchDataset(make_shared(param), onSuccess, onFailure, options); - } - -private: - void - startCommand(const shared_ptr& command, - const ControlParameters& parameters, - const CommandSucceedCallback& onSuccess, - const CommandFailCallback& onFailure, - const CommandOptions& options); - - void - processCommandResponse(const Data& data, - const shared_ptr& command, - const CommandSucceedCallback& onSuccess, - const CommandFailCallback& onFailure); - - void - processValidatedCommandResponse(const Data& data, - const shared_ptr& command, - const CommandSucceedCallback& onSuccess, - const CommandFailCallback& onFailure); - - template - void - fetchDataset(shared_ptr dataset, - const std::function& onSuccess, - const DatasetFailCallback& onFailure, - const CommandOptions& options); - - void - fetchDataset(const Name& prefix, - const std::function& processResponse, - const DatasetFailCallback& onFailure, - const CommandOptions& options); - - template - void - processDatasetResponse(shared_ptr dataset, - const std::function& onSuccess, - const DatasetFailCallback& onFailure, - ConstBufferPtr payload); - - void - processDatasetFetchError(const DatasetFailCallback& onFailure, uint32_t code, std::string msg); - -public: - /** \brief error code for timeout - */ - static const uint32_t ERROR_TIMEOUT; - - /** \brief error code for network Nack - */ - static const uint32_t ERROR_NACK; - - /** \brief error code for response validation failure - */ - static const uint32_t ERROR_VALIDATION; - - /** \brief error code for server error - */ - static const uint32_t ERROR_SERVER; - - /** \brief inclusive lower bound of error codes - */ - static const uint32_t ERROR_LBOUND; - -protected: - Face& m_face; - security::KeyChain& m_keyChain; - security::Validator& m_validator; - -private: - static ValidatorNull s_validatorNull; -}; - -template -inline void -Controller::fetchDataset(shared_ptr dataset, - const std::function& onSuccess1, - const DatasetFailCallback& onFailure1, - const CommandOptions& options) -{ - const std::function& onSuccess = onSuccess1 ? - onSuccess1 : [] (const typename Dataset::ResultType&) {}; - const DatasetFailCallback& onFailure = onFailure1 ? - onFailure1 : [] (uint32_t, const std::string&) {}; - - Name prefix = dataset->getDatasetPrefix(options.getPrefix()); - this->fetchDataset(prefix, - bind(&Controller::processDatasetResponse, this, dataset, onSuccess, onFailure, _1), - onFailure, - options); -} - -template -inline void -Controller::processDatasetResponse(shared_ptr dataset, - const std::function& onSuccess, - const DatasetFailCallback& onFailure, - ConstBufferPtr payload) -{ - typename Dataset::ResultType result; - try { - result = dataset->parseResult(payload); - } - catch (const tlv::Error& e) { - onFailure(ERROR_SERVER, e.what()); - return; - } - - onSuccess(result); -} - -} // namespace nfd -} // namespace ndn - -#endif // NDN_MGMT_NFD_CONTROLLER_HPP diff --git a/src/mgmt/nfd/face-event-notification.cpp b/src/mgmt/nfd/face-event-notification.cpp deleted file mode 100644 index a322ae997..000000000 --- a/src/mgmt/nfd/face-event-notification.cpp +++ /dev/null @@ -1,215 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "face-event-notification.hpp" -#include "encoding/tlv-nfd.hpp" -#include "encoding/block-helpers.hpp" -#include "util/concepts.hpp" - -namespace ndn { -namespace nfd { - -//BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "FaceEventNotification::Error must inherit from tlv::Error"); - -FaceEventNotification::FaceEventNotification() - : m_kind(static_cast(0)) -{ -} - -FaceEventNotification::FaceEventNotification(const Block& block) -{ - this->wireDecode(block); -} - -template -size_t -FaceEventNotification::wireEncode(EncodingImpl& encoder) const -{ - size_t totalLength = 0; - - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::Flags, m_flags); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::LinkType, m_linkType); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::FacePersistency, m_facePersistency); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::FaceScope, m_faceScope); - totalLength += encoder.prependByteArrayBlock(tlv::nfd::LocalUri, - reinterpret_cast(m_localUri.c_str()), m_localUri.size()); - totalLength += encoder.prependByteArrayBlock(tlv::nfd::Uri, - reinterpret_cast(m_remoteUri.c_str()), m_remoteUri.size()); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::FaceId, m_faceId); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::FaceEventKind, m_kind); - - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::nfd::FaceEventNotification); - return totalLength; -} - -const Block& -FaceEventNotification::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 -FaceEventNotification::wireDecode(const Block& block) -{ - if (block.type() != tlv::nfd::FaceEventNotification) { - BOOST_THROW_EXCEPTION(Error("expecting FaceEventNotification block")); - } - m_wire = block; - m_wire.parse(); - Block::element_const_iterator val = m_wire.elements_begin(); - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceEventKind) { - m_kind = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required FaceEventKind field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceId) { - m_faceId = readNonNegativeInteger(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required FaceId field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::Uri) { - m_remoteUri.assign(reinterpret_cast(val->value()), val->value_size()); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required Uri field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::LocalUri) { - m_localUri.assign(reinterpret_cast(val->value()), val->value_size()); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required LocalUri field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceScope) { - m_faceScope = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required FaceScope field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::FacePersistency) { - m_facePersistency = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required FacePersistency field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::LinkType) { - m_linkType = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required LinkType field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::Flags) { - m_flags = readNonNegativeInteger(*val); - } - else { - BOOST_THROW_EXCEPTION(Error("missing required Flags field")); - } -} - -FaceEventNotification& -FaceEventNotification::setKind(FaceEventKind kind) -{ - m_wire.reset(); - m_kind = kind; - return *this; -} - -void -FaceEventNotification::wireReset() const -{ - m_wire.reset(); -} - -std::ostream& -operator<<(std::ostream& os, const FaceEventNotification& notification) -{ - os << "FaceEventNotification("; - - switch (notification.getKind()) - { - case FACE_EVENT_CREATED: - os << "Kind: created, "; - break; - case FACE_EVENT_DESTROYED: - os << "Kind: destroyed, "; - break; - case FACE_EVENT_UP: - os << "Kind: up, "; - break; - case FACE_EVENT_DOWN: - os << "Kind: down, "; - break; - } - - os << "FaceID: " << notification.getFaceId() << ", " - << "RemoteUri: " << notification.getRemoteUri() << ", " - << "LocalUri: " << notification.getLocalUri() << ", " - << "FaceScope: " << notification.getFaceScope() << ", " - << "FacePersistency: " << notification.getFacePersistency() << ", " - << "LinkType: " << notification.getLinkType() << ", "; - - auto osFlags = os.flags(); - os << "Flags: " << std::showbase << std::hex << notification.getFlags(); - os.flags(osFlags); - - os << ")"; - return os; -} - -} // namespace nfd -} // namespace ndn diff --git a/src/mgmt/nfd/face-monitor.hpp b/src/mgmt/nfd/face-monitor.hpp deleted file mode 100644 index 5429ea12e..000000000 --- a/src/mgmt/nfd/face-monitor.hpp +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** - * Original copyright notice from NFD: - * - * Copyright (c) 2014, Regents of the University of California, - * Arizona Board of Regents, - * Colorado State University, - * University Pierre & Marie Curie, Sorbonne University, - * Washington University in St. Louis, - * Beijing Institute of Technology, - * The University of Memphis - * - * This file is part of NFD (Named Data Networking Forwarding Daemon). - * See AUTHORS.md for complete list of NFD authors and contributors. - * - * NFD 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. - * - * NFD 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 - * NFD, e.g., in COPYING.md file. If not, see . - */ - -#ifndef NDN_MGMT_NFD_FACE_MONITOR_HPP -#define NDN_MGMT_NFD_FACE_MONITOR_HPP - -#include "../../util/notification-subscriber.hpp" -#include "face-event-notification.hpp" - -namespace ndn { -namespace nfd { - -/** \brief A subscriber for Face status change notification stream - * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Face-Status-Change-Notification - */ -class FaceMonitor : public util::NotificationSubscriber -{ -public: - FaceMonitor(Face& face) - : NotificationSubscriber(face, "ndn:/localhost/nfd/faces/events") - { - } -}; - -} // namespace nfd -} // namespace ndn - -#endif // NDN_MGMT_NFD_FACE_MONITOR_HPP diff --git a/src/mgmt/nfd/face-query-filter.cpp b/src/mgmt/nfd/face-query-filter.cpp deleted file mode 100644 index ffaae903b..000000000 --- a/src/mgmt/nfd/face-query-filter.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "face-query-filter.hpp" -#include "encoding/tlv-nfd.hpp" -#include "encoding/block-helpers.hpp" -#include "util/concepts.hpp" - -namespace ndn { -namespace nfd { - -//BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "FaceQueryFilter::Error must inherit from tlv::Error"); - -FaceQueryFilter::FaceQueryFilter() - : m_hasFaceId(false) - , m_hasUriScheme(false) - , m_hasRemoteUri(false) - , m_hasLocalUri(false) - , m_hasFaceScope(false) - , m_hasFacePersistency(false) - , m_hasLinkType(false) -{ -} - -FaceQueryFilter::FaceQueryFilter(const Block& block) -{ - this->wireDecode(block); -} - -template -size_t -FaceQueryFilter::wireEncode(EncodingImpl& encoder) const -{ - size_t totalLength = 0; - - if (m_hasLinkType) { - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::LinkType, m_linkType); - } - - if (m_hasFacePersistency) { - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::FacePersistency, m_facePersistency); - } - - if (m_hasFaceScope) { - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::FaceScope, m_faceScope); - } - - if (m_hasLocalUri) { - totalLength += encoder.prependByteArrayBlock(tlv::nfd::LocalUri, - reinterpret_cast(m_localUri.c_str()), m_localUri.size()); - } - - if (m_hasRemoteUri) { - totalLength += encoder.prependByteArrayBlock(tlv::nfd::Uri, - reinterpret_cast(m_remoteUri.c_str()), m_remoteUri.size()); - } - - if (m_hasUriScheme) { - totalLength += encoder.prependByteArrayBlock(tlv::nfd::UriScheme, - reinterpret_cast(m_uriScheme.c_str()), m_uriScheme.size()); - } - - if (m_hasFaceId) { - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::FaceId, m_faceId); - } - - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::nfd::FaceQueryFilter); - return totalLength; -} - -template size_t -FaceQueryFilter::wireEncode(EncodingImpl&) const; - -template size_t -FaceQueryFilter::wireEncode(EncodingImpl&) const; - -const Block& -FaceQueryFilter::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 -FaceQueryFilter::wireDecode(const Block& block) -{ - //all fields are optional - if (block.type() != tlv::nfd::FaceQueryFilter) { - BOOST_THROW_EXCEPTION(Error("expecting FaceQueryFilter block")); - } - - m_wire = block; - m_wire.parse(); - Block::element_const_iterator val = m_wire.elements_begin(); - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceId) { - m_faceId = readNonNegativeInteger(*val); - m_hasFaceId = true; - ++val; - } - else { - m_hasFaceId = false; - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::UriScheme) { - m_uriScheme.assign(reinterpret_cast(val->value()), val->value_size()); - m_hasUriScheme = true; - ++val; - } - else { - m_hasUriScheme = false; - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::Uri) { - m_remoteUri.assign(reinterpret_cast(val->value()), val->value_size()); - m_hasRemoteUri = true; - ++val; - } - else { - m_hasRemoteUri = false; - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::LocalUri) { - m_localUri.assign(reinterpret_cast(val->value()), val->value_size()); - m_hasLocalUri = true; - ++val; - } - else { - m_hasLocalUri = false; - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceScope) { - m_faceScope = static_cast(readNonNegativeInteger(*val)); - m_hasFaceScope = true; - ++val; - } - else { - m_hasFaceScope = false; - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::FacePersistency) { - m_facePersistency = static_cast(readNonNegativeInteger(*val)); - m_hasFacePersistency = true; - ++val; - } - else { - m_hasFacePersistency = false; - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::LinkType) { - m_linkType = static_cast(readNonNegativeInteger(*val)); - m_hasLinkType = true; - ++val; - } - else { - m_hasLinkType = false; - } - -} - -FaceQueryFilter& -FaceQueryFilter::setFaceId(uint64_t faceId) -{ - m_wire.reset(); - m_faceId = faceId; - m_hasFaceId = true; - return *this; -} - -FaceQueryFilter& -FaceQueryFilter::unsetFaceId() -{ - m_wire.reset(); - m_hasFaceId = false; - return *this; -} - -FaceQueryFilter& -FaceQueryFilter::setUriScheme(const std::string& uriScheme) -{ - m_wire.reset(); - m_uriScheme = uriScheme; - m_hasUriScheme = true; - return *this; -} - -FaceQueryFilter& -FaceQueryFilter::unsetUriScheme() -{ - m_wire.reset(); - m_hasUriScheme = false; - return *this; -} - -FaceQueryFilter& -FaceQueryFilter::setRemoteUri(const std::string& remoteUri) -{ - m_wire.reset(); - m_remoteUri = remoteUri; - m_hasRemoteUri = true; - return *this; -} - -FaceQueryFilter& -FaceQueryFilter::unsetRemoteUri() -{ - m_wire.reset(); - m_hasRemoteUri = false; - return *this; -} - -FaceQueryFilter& -FaceQueryFilter::setLocalUri(const std::string& localUri) -{ - m_wire.reset(); - m_localUri = localUri; - m_hasLocalUri = true; - return *this; -} - -FaceQueryFilter& -FaceQueryFilter::unsetLocalUri() -{ - m_wire.reset(); - m_hasLocalUri = false; - return *this; -} - -FaceQueryFilter& -FaceQueryFilter::setFaceScope(FaceScope faceScope) -{ - m_wire.reset(); - m_faceScope = faceScope; - m_hasFaceScope = true; - return *this; -} - -FaceQueryFilter& -FaceQueryFilter::unsetFaceScope() -{ - m_wire.reset(); - m_hasFaceScope = false; - return *this; -} - -FaceQueryFilter& -FaceQueryFilter::setFacePersistency(FacePersistency facePersistency) -{ - m_wire.reset(); - m_facePersistency = facePersistency; - m_hasFacePersistency = true; - return *this; -} - -FaceQueryFilter& -FaceQueryFilter::unsetFacePersistency() -{ - m_wire.reset(); - m_hasFacePersistency = false; - return *this; -} - -FaceQueryFilter& -FaceQueryFilter::setLinkType(LinkType linkType) -{ - m_wire.reset(); - m_linkType = linkType; - m_hasLinkType = true; - return *this; -} - -FaceQueryFilter& -FaceQueryFilter::unsetLinkType() -{ - m_wire.reset(); - m_hasLinkType = false; - return *this; -} - -std::ostream& -operator<<(std::ostream& os, const FaceQueryFilter& filter) -{ - os << "FaceQueryFilter("; - if (filter.hasFaceId()) { - os << "FaceID: " << filter.getFaceId() << ",\n"; - } - - if (filter.hasUriScheme()) { - os << "UriScheme: " << filter.getUriScheme() << ",\n"; - } - - if (filter.hasRemoteUri()) { - os << "RemoteUri: " << filter.getRemoteUri() << ",\n"; - } - - if (filter.hasLocalUri()) { - os << "LocalUri: " << filter.getLocalUri() << ",\n"; - } - - if (filter.hasFaceScope()) { - os << "FaceScope: " << filter.getFaceScope() << ",\n"; - } - - if (filter.hasFacePersistency()) { - os << "FacePersistency: " << filter.getFacePersistency() << ",\n"; - } - - if (filter.hasLinkType()) { - os << "LinkType: " << filter.getLinkType() << ",\n"; - } - os << ")"; - return os; -} - -} // namespace nfd -} // namespace ndn diff --git a/src/mgmt/nfd/face-status.cpp b/src/mgmt/nfd/face-status.cpp deleted file mode 100644 index d54f0725d..000000000 --- a/src/mgmt/nfd/face-status.cpp +++ /dev/null @@ -1,378 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "face-status.hpp" -#include "encoding/tlv-nfd.hpp" -#include "encoding/block-helpers.hpp" -#include "util/concepts.hpp" - -namespace ndn { -namespace nfd { - -//BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "FaceStatus::Error must inherit from tlv::Error"); - -FaceStatus::FaceStatus() - : m_hasExpirationPeriod(false) - , m_nInInterests(0) - , m_nInDatas(0) - , m_nInNacks(0) - , m_nOutInterests(0) - , m_nOutDatas(0) - , m_nOutNacks(0) - , m_nInBytes(0) - , m_nOutBytes(0) -{ -} - -FaceStatus::FaceStatus(const Block& block) -{ - this->wireDecode(block); -} - -template -size_t -FaceStatus::wireEncode(EncodingImpl& encoder) const -{ - size_t totalLength = 0; - - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::Flags, m_flags); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::NOutBytes, m_nOutBytes); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::NInBytes, m_nInBytes); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::NOutNacks, m_nOutNacks); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::NOutDatas, m_nOutDatas); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::NOutInterests, m_nOutInterests); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::NInNacks, m_nInNacks); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::NInDatas, m_nInDatas); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::NInInterests, m_nInInterests); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::LinkType, m_linkType); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::FacePersistency, m_facePersistency); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::FaceScope, m_faceScope); - if (m_hasExpirationPeriod) { - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::ExpirationPeriod, m_expirationPeriod.count()); - } - totalLength += encoder.prependByteArrayBlock(tlv::nfd::LocalUri, - reinterpret_cast(m_localUri.c_str()), m_localUri.size()); - totalLength += encoder.prependByteArrayBlock(tlv::nfd::Uri, - reinterpret_cast(m_remoteUri.c_str()), m_remoteUri.size()); - totalLength += prependNonNegativeIntegerBlock(encoder, - tlv::nfd::FaceId, m_faceId); - - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::nfd::FaceStatus); - return totalLength; -} - -template size_t -FaceStatus::wireEncode(EncodingImpl& block) const; - -template size_t -FaceStatus::wireEncode(EncodingImpl& block) const; - -const Block& -FaceStatus::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 -FaceStatus::wireDecode(const Block& block) -{ - if (block.type() != tlv::nfd::FaceStatus) { - BOOST_THROW_EXCEPTION(Error("expecting FaceStatus block")); - } - m_wire = block; - m_wire.parse(); - Block::element_const_iterator val = m_wire.elements_begin(); - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceId) { - m_faceId = readNonNegativeInteger(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required FaceId field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::Uri) { - m_remoteUri.assign(reinterpret_cast(val->value()), val->value_size()); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required Uri field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::LocalUri) { - m_localUri.assign(reinterpret_cast(val->value()), val->value_size()); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required LocalUri field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::ExpirationPeriod) { - m_expirationPeriod = time::milliseconds(readNonNegativeInteger(*val)); - m_hasExpirationPeriod = true; - ++val; - } - else { - m_hasExpirationPeriod = false; - // ExpirationPeriod is optional - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceScope) { - m_faceScope = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required FaceScope field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::FacePersistency) { - m_facePersistency = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required FacePersistency field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::LinkType) { - m_linkType = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required LinkType field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInInterests) { - m_nInInterests = readNonNegativeInteger(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NInInterests field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInDatas) { - m_nInDatas = readNonNegativeInteger(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NInDatas field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInNacks) { - m_nInNacks = readNonNegativeInteger(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NInNacks field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutInterests) { - m_nOutInterests = readNonNegativeInteger(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NOutInterests field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutDatas) { - m_nOutDatas = readNonNegativeInteger(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NOutDatas field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutNacks) { - m_nOutNacks = readNonNegativeInteger(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NOutNacks field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInBytes) { - m_nInBytes = readNonNegativeInteger(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NInBytes field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutBytes) { - m_nOutBytes = readNonNegativeInteger(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NOutBytes field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::Flags) { - m_flags = readNonNegativeInteger(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required Flags field")); - } -} - -FaceStatus& -FaceStatus::setExpirationPeriod(const time::milliseconds& expirationPeriod) -{ - m_wire.reset(); - m_expirationPeriod = expirationPeriod; - m_hasExpirationPeriod = true; - return *this; -} - -FaceStatus& -FaceStatus::setNInInterests(uint64_t nInInterests) -{ - m_wire.reset(); - m_nInInterests = nInInterests; - return *this; -} - -FaceStatus& -FaceStatus::setNInDatas(uint64_t nInDatas) -{ - m_wire.reset(); - m_nInDatas = nInDatas; - return *this; -} - -FaceStatus& -FaceStatus::setNInNacks(uint64_t nInNacks) -{ - m_wire.reset(); - m_nInNacks = nInNacks; - return *this; -} - -FaceStatus& -FaceStatus::setNOutInterests(uint64_t nOutInterests) -{ - m_wire.reset(); - m_nOutInterests = nOutInterests; - return *this; -} - -FaceStatus& -FaceStatus::setNOutDatas(uint64_t nOutDatas) -{ - m_wire.reset(); - m_nOutDatas = nOutDatas; - return *this; -} - -FaceStatus& -FaceStatus::setNOutNacks(uint64_t nOutNacks) -{ - m_wire.reset(); - m_nOutNacks = nOutNacks; - return *this; -} - -FaceStatus& -FaceStatus::setNInBytes(uint64_t nInBytes) -{ - m_wire.reset(); - m_nInBytes = nInBytes; - return *this; -} - -FaceStatus& -FaceStatus::setNOutBytes(uint64_t nOutBytes) -{ - m_wire.reset(); - m_nOutBytes = nOutBytes; - return *this; -} - -void -FaceStatus::wireReset() const -{ - m_wire.reset(); -} - -std::ostream& -operator<<(std::ostream& os, const FaceStatus& status) -{ - os << "FaceStatus(" - << "FaceID: " << status.getFaceId() << ",\n" - << "RemoteUri: " << status.getRemoteUri() << ",\n" - << "LocalUri: " << status.getLocalUri() << ",\n"; - - if (status.hasExpirationPeriod()) { - os << "ExpirationPeriod: " << status.getExpirationPeriod() << ",\n"; - } - else { - os << "ExpirationPeriod: infinite,\n"; - } - - os << "FaceScope: " << status.getFaceScope() << ",\n" - << "FacePersistency: " << status.getFacePersistency() << ",\n" - << "LinkType: " << status.getLinkType() << ",\n"; - - auto osFlags = os.flags(); - os << "Flags: " << std::showbase << std::hex << status.getFlags() << ",\n"; - os.flags(osFlags); - - os << "Counters: { Interests: {in: " << status.getNInInterests() << ", " - << "out: " << status.getNOutInterests() << "},\n" - << " Data: {in: " << status.getNInDatas() << ", " - << "out: " << status.getNOutDatas() << "},\n" - << " Nack: {in: " << status.getNInNacks() << ", " - << "out: " << status.getNOutNacks() << "},\n" - << " bytes: {in: " << status.getNInBytes() << ", " - << "out: " << status.getNOutBytes() << "} }\n" - << ")"; - return os; -} - -} // namespace nfd -} // namespace ndn diff --git a/src/mgmt/nfd/face-status.hpp b/src/mgmt/nfd/face-status.hpp deleted file mode 100644 index 4f20e531b..000000000 --- a/src/mgmt/nfd/face-status.hpp +++ /dev/null @@ -1,175 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_MGMT_NFD_FACE_STATUS_HPP -#define NDN_MGMT_NFD_FACE_STATUS_HPP - -#include "face-traits.hpp" // include this first, to ensure it compiles on its own. -#include "../../encoding/block.hpp" -#include "../../util/time.hpp" - -namespace ndn { -namespace nfd { - -/** - * \ingroup management - * \brief represents Face status - * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Face-Dataset - */ -class FaceStatus : public FaceTraits -{ -public: - FaceStatus(); - - explicit - FaceStatus(const Block& block); - - /** \brief prepend FaceStatus to the encoder - */ - template - size_t - wireEncode(EncodingImpl& encoder) const; - - /** \brief encode FaceStatus - */ - const Block& - wireEncode() const; - - /** \brief decode FaceStatus - */ - void - wireDecode(const Block& wire); - -public: // getters & setters - bool - hasExpirationPeriod() const - { - return m_hasExpirationPeriod; - } - - const time::milliseconds& - getExpirationPeriod() const - { - BOOST_ASSERT(m_hasExpirationPeriod); - return m_expirationPeriod; - } - - FaceStatus& - setExpirationPeriod(const time::milliseconds& expirationPeriod); - - uint64_t - getNInInterests() const - { - return m_nInInterests; - } - - FaceStatus& - setNInInterests(uint64_t nInInterests); - - uint64_t - getNInDatas() const - { - return m_nInDatas; - } - - FaceStatus& - setNInDatas(uint64_t nInDatas); - - uint64_t - getNInNacks() const - { - return m_nInNacks; - } - - FaceStatus& - setNInNacks(uint64_t nInNacks); - - uint64_t - getNOutInterests() const - { - return m_nOutInterests; - } - - FaceStatus& - setNOutInterests(uint64_t nOutInterests); - - uint64_t - getNOutDatas() const - { - return m_nOutDatas; - } - - FaceStatus& - setNOutDatas(uint64_t nOutDatas); - - uint64_t - getNOutNacks() const - { - return m_nOutNacks; - } - - FaceStatus& - setNOutNacks(uint64_t nOutNacks); - - uint64_t - getNInBytes() const - { - return m_nInBytes; - } - - FaceStatus& - setNInBytes(uint64_t nInBytes); - - uint64_t - getNOutBytes() const - { - return m_nOutBytes; - } - - FaceStatus& - setNOutBytes(uint64_t nOutBytes); - -protected: - void - wireReset() const; - -private: - time::milliseconds m_expirationPeriod; - bool m_hasExpirationPeriod; - uint64_t m_nInInterests; - uint64_t m_nInDatas; - uint64_t m_nInNacks; - uint64_t m_nOutInterests; - uint64_t m_nOutDatas; - uint64_t m_nOutNacks; - uint64_t m_nInBytes; - uint64_t m_nOutBytes; - - mutable Block m_wire; -}; - -std::ostream& -operator<<(std::ostream& os, const FaceStatus& status); - -} // namespace nfd -} // namespace ndn - -#endif // NDN_MGMT_NFD_FACE_STATUS_HPP diff --git a/src/mgmt/nfd/fib-entry.cpp b/src/mgmt/nfd/fib-entry.cpp deleted file mode 100644 index dd1092f46..000000000 --- a/src/mgmt/nfd/fib-entry.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "fib-entry.hpp" -#include -#include "encoding/tlv-nfd.hpp" -#include "encoding/block-helpers.hpp" -#include "util/concepts.hpp" - -namespace ndn { -namespace nfd { - -//BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "NextHopRecord::Error must inherit from tlv::Error"); - -//BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "FibEntry::Error must inherit from tlv::Error"); - -// NextHopRecord := NEXT-HOP-RECORD TLV-LENGTH -// FaceId -// Cost - -NextHopRecord::NextHopRecord() - : m_faceId(std::numeric_limits::max()) - , m_cost(0) -{ -} - -NextHopRecord::NextHopRecord(const Block& block) -{ - this->wireDecode(block); -} - -NextHopRecord& -NextHopRecord::setFaceId(uint64_t faceId) -{ - m_faceId = faceId; - m_wire.reset(); - return *this; -} - -NextHopRecord& -NextHopRecord::setCost(uint64_t cost) -{ - m_cost = cost; - m_wire.reset(); - return *this; -} - -template -size_t -NextHopRecord::wireEncode(EncodingImpl& block) const -{ - size_t totalLength = 0; - totalLength += prependNonNegativeIntegerBlock(block, - ndn::tlv::nfd::Cost, - m_cost); - - totalLength += prependNonNegativeIntegerBlock(block, - ndn::tlv::nfd::FaceId, - m_faceId); - - totalLength += block.prependVarNumber(totalLength); - totalLength += block.prependVarNumber(ndn::tlv::nfd::NextHopRecord); - return totalLength; -} - -template size_t -NextHopRecord::wireEncode(EncodingImpl& block) const; - -template size_t -NextHopRecord::wireEncode(EncodingImpl& block) const; - -const Block& -NextHopRecord::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 -NextHopRecord::wireDecode(const Block& wire) -{ - m_faceId = std::numeric_limits::max(); - m_cost = 0; - - m_wire = wire; - - if (m_wire.type() != tlv::nfd::NextHopRecord) { - std::stringstream error; - error << "Requested decoding of NextHopRecord, but Block is of a different type: #" - << m_wire.type(); - BOOST_THROW_EXCEPTION(Error(error.str())); - } - m_wire.parse(); - - Block::element_const_iterator val = m_wire.elements_begin(); - if (val == m_wire.elements_end()) { - BOOST_THROW_EXCEPTION(Error("Unexpected end of NextHopRecord")); - } - else if (val->type() != tlv::nfd::FaceId) { - std::stringstream error; - error << "Expected FaceId, but Block is of a different type: #" - << val->type(); - BOOST_THROW_EXCEPTION(Error(error.str())); - } - m_faceId = readNonNegativeInteger(*val); - ++val; - - if (val == m_wire.elements_end()) { - BOOST_THROW_EXCEPTION(Error("Unexpected end of NextHopRecord")); - } - else if (val->type() != tlv::nfd::Cost) { - std::stringstream error; - error << "Expected Cost, but Block is of a different type: #" - << m_wire.type(); - BOOST_THROW_EXCEPTION(Error(error.str())); - } - m_cost = readNonNegativeInteger(*val); -} - -// FibEntry := FIB-ENTRY-TYPE TLV-LENGTH -// Name -// NextHopRecord* - -FibEntry::FibEntry() -{ -} - -FibEntry::FibEntry(const Block& block) -{ - this->wireDecode(block); -} - -FibEntry& -FibEntry::setPrefix(const Name& prefix) -{ - m_prefix = prefix; - m_wire.reset(); - return *this; -} - -FibEntry& -FibEntry::addNextHopRecord(const NextHopRecord& nextHopRecord) -{ - m_nextHopRecords.push_back(nextHopRecord); - m_wire.reset(); - return *this; -} - -template -size_t -FibEntry::wireEncode(EncodingImpl& block) const -{ - size_t totalLength = 0; - - for (auto i = m_nextHopRecords.rbegin(); i != m_nextHopRecords.rend(); ++i) { - totalLength += i->wireEncode(block); - } - - totalLength += m_prefix.wireEncode(block); - totalLength += block.prependVarNumber(totalLength); - totalLength += block.prependVarNumber(tlv::nfd::FibEntry); - - return totalLength; -} - -template size_t -FibEntry::wireEncode(EncodingImpl& block) const; - -template size_t -FibEntry::wireEncode(EncodingImpl& block) const; - -const Block& -FibEntry::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 -FibEntry::wireDecode(const Block& wire) -{ - m_prefix.clear(); - m_nextHopRecords.clear(); - - m_wire = wire; - - if (m_wire.type() != tlv::nfd::FibEntry) { - std::stringstream error; - error << "Requested decoding of FibEntry, but Block is of a different type: #" - << m_wire.type(); - BOOST_THROW_EXCEPTION(Error(error.str())); - } - - m_wire.parse(); - - Block::element_const_iterator val = m_wire.elements_begin(); - if (val == m_wire.elements_end()) { - BOOST_THROW_EXCEPTION(Error("Unexpected end of FibEntry")); - } - else if (val->type() != tlv::Name) { - std::stringstream error; - error << "Expected Name, but Block is of a different type: #" - << val->type(); - BOOST_THROW_EXCEPTION(Error(error.str())); - } - m_prefix.wireDecode(*val); - ++val; - - for (; val != m_wire.elements_end(); ++val) { - if (val->type() != tlv::nfd::NextHopRecord) { - std::stringstream error; - error << "Expected NextHopRecords, but Block is of a different type: #" - << val->type(); - BOOST_THROW_EXCEPTION(Error(error.str())); - } - m_nextHopRecords.push_back(NextHopRecord(*val)); - } -} - -} // namespace nfd -} // namespace ndn diff --git a/src/mgmt/nfd/fib-entry.hpp b/src/mgmt/nfd/fib-entry.hpp deleted file mode 100644 index 6a7304cfd..000000000 --- a/src/mgmt/nfd/fib-entry.hpp +++ /dev/null @@ -1,155 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_MGMT_NFD_FIB_ENTRY_HPP -#define NDN_MGMT_NFD_FIB_ENTRY_HPP - -#include "../../encoding/block.hpp" -#include "../../name.hpp" -#include - -namespace ndn { -namespace nfd { - -/** @ingroup management - */ -class NextHopRecord -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - - NextHopRecord(); - - explicit - NextHopRecord(const Block& block); - - uint64_t - getFaceId() const - { - return m_faceId; - } - - NextHopRecord& - setFaceId(uint64_t faceId); - - uint64_t - getCost() const - { - return m_cost; - } - - NextHopRecord& - setCost(uint64_t cost); - - template - size_t - wireEncode(EncodingImpl& block) const; - - const Block& - wireEncode() const; - - void - wireDecode(const Block& wire); - -private: - uint64_t m_faceId; - uint64_t m_cost; - - mutable Block m_wire; -}; - -/** @ingroup management - */ -class FibEntry -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - - FibEntry(); - - explicit - FibEntry(const Block& block); - - const Name& - getPrefix() const - { - return m_prefix; - } - - FibEntry& - setPrefix(const Name& prefix); - - const std::list& - getNextHopRecords() const - { - return m_nextHopRecords; - } - - FibEntry& - addNextHopRecord(const NextHopRecord& nextHopRecord); - - template - FibEntry& - setNextHopRecords(const T& begin, const T& end) - { - m_nextHopRecords.clear(); - m_nextHopRecords.assign(begin, end); - m_wire.reset(); - return *this; - } - - template - size_t - wireEncode(EncodingImpl& block) const; - - const Block& - wireEncode() const; - - void - wireDecode(const Block& wire); - -private: - Name m_prefix; - std::list m_nextHopRecords; - - mutable Block m_wire; -}; - -} // namespace nfd -} // namespace ndn - -#endif // NDN_MGMT_NFD_FIB_ENTRY_HPP diff --git a/src/mgmt/nfd/forwarder-status.cpp b/src/mgmt/nfd/forwarder-status.cpp deleted file mode 100644 index 21fee5611..000000000 --- a/src/mgmt/nfd/forwarder-status.cpp +++ /dev/null @@ -1,357 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "forwarder-status.hpp" -#include "encoding/tlv-nfd.hpp" -#include "encoding/block-helpers.hpp" -#include "util/concepts.hpp" - -namespace ndn { -namespace nfd { - -//BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "ForwarderStatus::Error must inherit from tlv::Error"); - -ForwarderStatus::ForwarderStatus() - : m_startTimestamp(time::system_clock::TimePoint::min()) - , m_currentTimestamp(time::system_clock::TimePoint::min()) - , m_nNameTreeEntries(0) - , m_nFibEntries(0) - , m_nPitEntries(0) - , m_nMeasurementsEntries(0) - , m_nCsEntries(0) - , m_nInInterests(0) - , m_nInDatas(0) - , m_nInNacks(0) - , m_nOutInterests(0) - , m_nOutDatas(0) - , m_nOutNacks(0) -{ -} - -ForwarderStatus::ForwarderStatus(const Block& payload) -{ - this->wireDecode(payload); -} - -template -size_t -ForwarderStatus::wireEncode(EncodingImpl& encoder) const -{ - size_t totalLength = 0; - - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NOutNacks, - m_nOutNacks); - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NOutDatas, - m_nOutDatas); - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NOutInterests, - m_nOutInterests); - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NInNacks, - m_nInNacks); - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NInDatas, - m_nInDatas); - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NInInterests, - m_nInInterests); - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NCsEntries, - m_nCsEntries); - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NMeasurementsEntries, - m_nMeasurementsEntries); - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NPitEntries, - m_nPitEntries); - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NFibEntries, - m_nFibEntries); - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NNameTreeEntries, - m_nNameTreeEntries); - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::CurrentTimestamp, - time::toUnixTimestamp(m_currentTimestamp).count()); - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::StartTimestamp, - time::toUnixTimestamp(m_startTimestamp).count()); - totalLength += encoder.prependByteArrayBlock(tlv::nfd::NfdVersion, - reinterpret_cast(m_nfdVersion.c_str()), - m_nfdVersion.size()); - - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::Content); - return totalLength; -} - -template size_t -ForwarderStatus::wireEncode(EncodingImpl&) const; - -template size_t -ForwarderStatus::wireEncode(EncodingImpl&) const; - -const Block& -ForwarderStatus::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 -ForwarderStatus::wireDecode(const Block& block) -{ - if (block.type() != tlv::Content) { - BOOST_THROW_EXCEPTION(Error("expecting Content block for Status payload")); - } - m_wire = block; - m_wire.parse(); - Block::element_const_iterator val = m_wire.elements_begin(); - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NfdVersion) { - m_nfdVersion.assign(reinterpret_cast(val->value()), val->value_size()); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NfdVersion field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::StartTimestamp) { - m_startTimestamp = time::fromUnixTimestamp(time::milliseconds(readNonNegativeInteger(*val))); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required StartTimestamp field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::CurrentTimestamp) { - m_currentTimestamp = time::fromUnixTimestamp(time::milliseconds(readNonNegativeInteger(*val))); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required CurrentTimestamp field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NNameTreeEntries) { - m_nNameTreeEntries = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NNameTreeEntries field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NFibEntries) { - m_nFibEntries = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NFibEntries field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NPitEntries) { - m_nPitEntries = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NPitEntries field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NMeasurementsEntries) { - m_nMeasurementsEntries = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NMeasurementsEntries field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NCsEntries) { - m_nCsEntries = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NCsEntries field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInInterests) { - m_nInInterests = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NInInterests field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInDatas) { - m_nInDatas = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NInDatas field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInNacks) { - m_nInNacks = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NInNacks field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutInterests) { - m_nOutInterests = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NOutInterests field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutDatas) { - m_nOutDatas = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NOutDatas field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutNacks) { - m_nOutNacks = static_cast(readNonNegativeInteger(*val)); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required NInNacks field")); - } -} - -ForwarderStatus& -ForwarderStatus::setNfdVersion(const std::string& nfdVersion) -{ - m_wire.reset(); - m_nfdVersion = nfdVersion; - return *this; -} - -ForwarderStatus& -ForwarderStatus::setStartTimestamp(const time::system_clock::TimePoint& startTimestamp) -{ - m_wire.reset(); - m_startTimestamp = startTimestamp; - return *this; -} - -ForwarderStatus& -ForwarderStatus::setCurrentTimestamp(const time::system_clock::TimePoint& currentTimestamp) -{ - m_wire.reset(); - m_currentTimestamp = currentTimestamp; - return *this; -} - -ForwarderStatus& -ForwarderStatus::setNNameTreeEntries(size_t nNameTreeEntries) -{ - m_wire.reset(); - m_nNameTreeEntries = nNameTreeEntries; - return *this; -} - -ForwarderStatus& -ForwarderStatus::setNFibEntries(size_t nFibEntries) -{ - m_wire.reset(); - m_nFibEntries = nFibEntries; - return *this; -} - -ForwarderStatus& -ForwarderStatus::setNPitEntries(size_t nPitEntries) -{ - m_wire.reset(); - m_nPitEntries = nPitEntries; - return *this; -} - -ForwarderStatus& -ForwarderStatus::setNMeasurementsEntries(size_t nMeasurementsEntries) -{ - m_wire.reset(); - m_nMeasurementsEntries = nMeasurementsEntries; - return *this; -} - -ForwarderStatus& -ForwarderStatus::setNCsEntries(size_t nCsEntries) -{ - m_wire.reset(); - m_nCsEntries = nCsEntries; - return *this; -} - -ForwarderStatus& -ForwarderStatus::setNInInterests(uint64_t nInInterests) -{ - m_wire.reset(); - m_nInInterests = nInInterests; - return *this; -} - -ForwarderStatus& -ForwarderStatus::setNInDatas(uint64_t nInDatas) -{ - m_wire.reset(); - m_nInDatas = nInDatas; - return *this; -} - -ForwarderStatus& -ForwarderStatus::setNInNacks(uint64_t nInNacks) -{ - m_wire.reset(); - m_nInNacks = nInNacks; - return *this; -} - -ForwarderStatus& -ForwarderStatus::setNOutInterests(uint64_t nOutInterests) -{ - m_wire.reset(); - m_nOutInterests = nOutInterests; - return *this; -} - -ForwarderStatus& -ForwarderStatus::setNOutDatas(uint64_t nOutDatas) -{ - m_wire.reset(); - m_nOutDatas = nOutDatas; - return *this; -} - -ForwarderStatus& -ForwarderStatus::setNOutNacks(uint64_t nOutNacks) -{ - m_wire.reset(); - m_nOutNacks = nOutNacks; - return *this; -} - -} // namespace nfd -} // namespace ndn diff --git a/src/mgmt/nfd/forwarder-status.hpp b/src/mgmt/nfd/forwarder-status.hpp deleted file mode 100644 index 460161080..000000000 --- a/src/mgmt/nfd/forwarder-status.hpp +++ /dev/null @@ -1,225 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_MGMT_NFD_FORWARDER_STATUS_HPP -#define NDN_MGMT_NFD_FORWARDER_STATUS_HPP - -#include "../../encoding/block.hpp" -#include "../../util/time.hpp" - -namespace ndn { -namespace nfd { - -/** - * \ingroup management - * \brief represents NFD Forwarder Status - * \sa http://redmine.named-data.net/projects/nfd/wiki/ForwarderStatus - */ -class ForwarderStatus -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - - ForwarderStatus(); - - explicit - ForwarderStatus(const Block& payload); - - /** \brief prepend ForwarderStatus as a Content block to the encoder - * - * The outermost Content element isn't part of ForwardStatus structure. - */ - template - size_t - wireEncode(EncodingImpl& encoder) const; - - /** \brief encode ForwarderStatus as a Content block - * - * The outermost Content element isn't part of ForwardStatus structure. - */ - const Block& - wireEncode() const; - - /** \brief decode ForwarderStatus from a Content block - * - * The outermost Content element isn't part of ForwardStatus structure. - */ - void - wireDecode(const Block& wire); - -public: // getters & setters - const std::string& - getNfdVersion() const - { - return m_nfdVersion; - } - - ForwarderStatus& - setNfdVersion(const std::string& nfdVersion); - - const time::system_clock::TimePoint& - getStartTimestamp() const - { - return m_startTimestamp; - } - - ForwarderStatus& - setStartTimestamp(const time::system_clock::TimePoint& startTimestamp); - - const time::system_clock::TimePoint& - getCurrentTimestamp() const - { - return m_currentTimestamp; - } - - ForwarderStatus& - setCurrentTimestamp(const time::system_clock::TimePoint& currentTimestamp); - - size_t - getNNameTreeEntries() const - { - return m_nNameTreeEntries; - } - - ForwarderStatus& - setNNameTreeEntries(size_t nNameTreeEntries); - - size_t - getNFibEntries() const - { - return m_nFibEntries; - } - - ForwarderStatus& - setNFibEntries(size_t nFibEntries); - - size_t - getNPitEntries() const - { - return m_nPitEntries; - } - - ForwarderStatus& - setNPitEntries(size_t nPitEntries); - - size_t - getNMeasurementsEntries() const - { - return m_nMeasurementsEntries; - } - - ForwarderStatus& - setNMeasurementsEntries(size_t nMeasurementsEntries); - - size_t - getNCsEntries() const - { - return m_nCsEntries; - } - - ForwarderStatus& - setNCsEntries(size_t nCsEntries); - - uint64_t - getNInInterests() const - { - return m_nInInterests; - } - - ForwarderStatus& - setNInInterests(uint64_t nInInterests); - - uint64_t - getNInDatas() const - { - return m_nInDatas; - } - - ForwarderStatus& - setNInDatas(uint64_t nInDatas); - - uint64_t - getNInNacks() const - { - return m_nInNacks; - } - - ForwarderStatus& - setNInNacks(uint64_t nInNacks); - - uint64_t - getNOutInterests() const - { - return m_nOutInterests; - } - - ForwarderStatus& - setNOutInterests(uint64_t nOutInterests); - - uint64_t - getNOutDatas() const - { - return m_nOutDatas; - } - - ForwarderStatus& - setNOutDatas(uint64_t nOutDatas); - - uint64_t - getNOutNacks() const - { - return m_nOutNacks; - } - - ForwarderStatus& - setNOutNacks(uint64_t nOutNacks); - -private: - std::string m_nfdVersion; - time::system_clock::TimePoint m_startTimestamp; - time::system_clock::TimePoint m_currentTimestamp; - size_t m_nNameTreeEntries; - size_t m_nFibEntries; - size_t m_nPitEntries; - size_t m_nMeasurementsEntries; - size_t m_nCsEntries; - uint64_t m_nInInterests; - uint64_t m_nInDatas; - uint64_t m_nInNacks; - uint64_t m_nOutInterests; - uint64_t m_nOutDatas; - uint64_t m_nOutNacks; - - mutable Block m_wire; -}; - -} // namespace nfd -} // namespace ndn - -#endif // NDN_MGMT_NFD_FORWARDER_STATUS_HPP diff --git a/src/mgmt/nfd/rib-entry.cpp b/src/mgmt/nfd/rib-entry.cpp deleted file mode 100644 index d47d3165a..000000000 --- a/src/mgmt/nfd/rib-entry.cpp +++ /dev/null @@ -1,320 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "rib-entry.hpp" -#include "encoding/tlv-nfd.hpp" -#include "encoding/block-helpers.hpp" -#include "util/concepts.hpp" - -namespace ndn { -namespace nfd { - -//BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "Route::Error must inherit from tlv::Error"); - -//BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "RibEntry::Error must inherit from tlv::Error"); - -const time::milliseconds Route::INFINITE_EXPIRATION_PERIOD(time::milliseconds::max()); - -Route::Route() - : m_faceId(0) - , m_origin(0) - , m_cost(0) - , m_flags(ROUTE_FLAG_CHILD_INHERIT) - , m_expirationPeriod(INFINITE_EXPIRATION_PERIOD) - , m_hasInfiniteExpirationPeriod(true) -{ -} - -Route::Route(const Block& block) -{ - wireDecode(block); -} - -template -size_t -Route::wireEncode(EncodingImpl& block) const -{ - size_t totalLength = 0; - - // Absence of an ExpirationPeriod signifies non-expiration - if (!m_hasInfiniteExpirationPeriod) { - totalLength += prependNonNegativeIntegerBlock(block, - ndn::tlv::nfd::ExpirationPeriod, - m_expirationPeriod.count()); - } - - totalLength += prependNonNegativeIntegerBlock(block, - ndn::tlv::nfd::Flags, - m_flags); - - totalLength += prependNonNegativeIntegerBlock(block, - ndn::tlv::nfd::Cost, - m_cost); - - totalLength += prependNonNegativeIntegerBlock(block, - ndn::tlv::nfd::Origin, - m_origin); - - totalLength += prependNonNegativeIntegerBlock(block, - ndn::tlv::nfd::FaceId, - m_faceId); - - totalLength += block.prependVarNumber(totalLength); - totalLength += block.prependVarNumber(ndn::tlv::nfd::Route); - - return totalLength; -} - -template size_t -Route::wireEncode(EncodingImpl& block) const; - -template size_t -Route::wireEncode(EncodingImpl& block) const; - -const Block& -Route::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 -Route::wireDecode(const Block& wire) -{ - m_faceId = 0; - m_origin = 0; - m_cost = 0; - m_flags = 0; - m_expirationPeriod = time::milliseconds::min(); - - m_wire = wire; - - if (m_wire.type() != tlv::nfd::Route) { - std::stringstream error; - error << "Expected Route Block, but Block is of a different type: #" - << m_wire.type(); - BOOST_THROW_EXCEPTION(Error(error.str())); - } - - m_wire.parse(); - - Block::element_const_iterator val = m_wire.elements_begin(); - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceId) { - m_faceId = readNonNegativeInteger(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("Missing required FaceId field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::Origin) { - m_origin = readNonNegativeInteger(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("Missing required Origin field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::Cost) { - m_cost = readNonNegativeInteger(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("Missing required Cost field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::Flags) { - m_flags = readNonNegativeInteger(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("Missing required Flags field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::ExpirationPeriod) { - m_expirationPeriod = time::milliseconds(readNonNegativeInteger(*val)); - m_hasInfiniteExpirationPeriod = false; - } - else { - m_expirationPeriod = INFINITE_EXPIRATION_PERIOD; - m_hasInfiniteExpirationPeriod = true; - } -} - -std::ostream& -operator<<(std::ostream& os, const Route& route) -{ - os << "Route(" - << "FaceId: " << route.getFaceId() << ", " - << "Origin: " << route.getOrigin() << ", " - << "Cost: " << route.getCost() << ", " - << "Flags: " << route.getFlags() << ", "; - - if (!route.hasInfiniteExpirationPeriod()) { - os << "ExpirationPeriod: " << route.getExpirationPeriod(); - } - else { - os << "ExpirationPeriod: Infinity"; - } - - os << ")"; - - return os; -} - - -////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// - - -RibEntry::RibEntry() -{ -} - -RibEntry::RibEntry(const Block& block) -{ - wireDecode(block); -} - - -template -size_t -RibEntry::wireEncode(EncodingImpl& block) const -{ - size_t totalLength = 0; - - for (std::list::const_reverse_iterator it = m_routes.rbegin(); - it != m_routes.rend(); ++it) - { - totalLength += it->wireEncode(block); - } - - totalLength += m_prefix.wireEncode(block); - - totalLength += block.prependVarNumber(totalLength); - totalLength += block.prependVarNumber(tlv::nfd::RibEntry); - - return totalLength; -} - -template size_t -RibEntry::wireEncode(EncodingImpl& block) const; - -template size_t -RibEntry::wireEncode(EncodingImpl& block) const; - -const Block& -RibEntry::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 -RibEntry::wireDecode(const Block& wire) -{ - m_prefix.clear(); - m_routes.clear(); - - m_wire = wire; - - if (m_wire.type() != tlv::nfd::RibEntry) { - std::stringstream error; - error << "Expected RibEntry Block, but Block is of a different type: #" - << m_wire.type(); - BOOST_THROW_EXCEPTION(Error(error.str())); - } - - m_wire.parse(); - - Block::element_const_iterator val = m_wire.elements_begin(); - - if (val != m_wire.elements_end() && val->type() == tlv::Name) { - m_prefix.wireDecode(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("Missing required Name field")); - } - - for (; val != m_wire.elements_end(); ++val) { - - if (val->type() == tlv::nfd::Route) { - m_routes.push_back(Route(*val)); - } - else { - std::stringstream error; - error << "Expected Route Block, but Block is of a different type: #" - << m_wire.type(); - BOOST_THROW_EXCEPTION(Error(error.str())); - } - } -} - -std::ostream& -operator<<(std::ostream& os, const RibEntry& entry) -{ - os << "RibEntry{\n" - << " Name: " << entry.getName() << "\n"; - - for (RibEntry::iterator it = entry.begin(); it != entry.end(); ++it) { - os << " " << *it << "\n"; - } - - os << "}"; - - return os; -} - -} // namespace nfd -} // namespace ndn diff --git a/src/mgmt/nfd/rib-entry.hpp b/src/mgmt/nfd/rib-entry.hpp deleted file mode 100644 index 6c1c5a28c..000000000 --- a/src/mgmt/nfd/rib-entry.hpp +++ /dev/null @@ -1,287 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_MGMT_NFD_RIB_ENTRY_HPP -#define NDN_MGMT_NFD_RIB_ENTRY_HPP - -#include "rib-flags.hpp" // include this first, to ensure it compiles on its own. -#include "../../name.hpp" -#include "../../util/time.hpp" - -#include - -namespace ndn { -namespace nfd { - -/** - * @ingroup management - * - * @brief Data abstraction for Route - * - * A route indicates the availability of content via a certain face and - * provides meta-information about the face. - * - * Route := ROUTE-TYPE TLV-LENGTH - * FaceId - * Origin - * Cost - * Flags - * ExpirationPeriod? - * - * @sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt - */ -class Route : public RibFlagsTraits -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) : tlv::Error(what) - { - } - }; - - Route(); - - explicit - Route(const Block& block); - - uint64_t - getFaceId() const - { - return m_faceId; - } - - Route& - setFaceId(uint64_t faceId) - { - m_faceId = faceId; - m_wire.reset(); - return *this; - } - - uint64_t - getOrigin() const - { - return m_origin; - } - - /** @brief set Origin - * @param origin a code defined in ndn::nfd::RouteOrigin - */ - Route& - setOrigin(uint64_t origin) - { - m_origin = origin; - m_wire.reset(); - return *this; - } - - uint64_t - getCost() const - { - return m_cost; - } - - Route& - setCost(uint64_t cost) - { - m_cost = cost; - m_wire.reset(); - return *this; - } - - uint64_t - getFlags() const - { - return m_flags; - } - - /** @brief set route inheritance flags - * @param flags a bitwise OR'ed code from ndn::nfd::RouteFlags - */ - Route& - setFlags(uint64_t flags) - { - m_flags = flags; - m_wire.reset(); - return *this; - } - - static const time::milliseconds INFINITE_EXPIRATION_PERIOD; - - const time::milliseconds& - getExpirationPeriod() const - { - return m_expirationPeriod; - } - - Route& - setExpirationPeriod(const time::milliseconds& expirationPeriod) - { - m_expirationPeriod = expirationPeriod; - - m_hasInfiniteExpirationPeriod = m_expirationPeriod == INFINITE_EXPIRATION_PERIOD; - - m_wire.reset(); - return *this; - } - - bool - hasInfiniteExpirationPeriod() const - { - return m_hasInfiniteExpirationPeriod; - } - - template - size_t - wireEncode(EncodingImpl& block) const; - - const Block& - wireEncode() const; - - void - wireDecode(const Block& wire); - -private: - uint64_t m_faceId; - uint64_t m_origin; - uint64_t m_cost; - uint64_t m_flags; - time::milliseconds m_expirationPeriod; - bool m_hasInfiniteExpirationPeriod; - - mutable Block m_wire; -}; - -std::ostream& -operator<<(std::ostream& os, const Route& route); - -/** - * @ingroup management - * - * @brief Data abstraction for RIB entry - * - * A RIB entry contains one or more routes for the name prefix - * - * RibEntry := RIB-ENTRY-TYPE TLV-LENGTH - * Name - * Route+ - * - * @sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt - */ -class RibEntry -{ -public: - class Error : public tlv::Error - { - public: - Error(const std::string& what) : tlv::Error(what) - { - } - }; - - typedef std::list RouteList; - typedef RouteList::const_iterator iterator; - - RibEntry(); - - explicit - RibEntry(const Block& block); - - const Name& - getName() const - { - return m_prefix; - } - - RibEntry& - setName(const Name& prefix) - { - m_prefix = prefix; - m_wire.reset(); - return *this; - } - - const std::list& - getRoutes() const - { - return m_routes; - } - - RibEntry& - addRoute(const Route& route) - { - m_routes.push_back(route); - m_wire.reset(); - return *this; - } - - RibEntry& - clearRoutes() - { - m_routes.clear(); - return *this; - } - - template - size_t - wireEncode(EncodingImpl& block) const; - - const Block& - wireEncode() const; - - void - wireDecode(const Block& wire); - - iterator - begin() const; - - iterator - end() const; - -private: - Name m_prefix; - RouteList m_routes; - - mutable Block m_wire; -}; - -inline RibEntry::iterator -RibEntry::begin() const -{ - return m_routes.begin(); -} - -inline RibEntry::iterator -RibEntry::end() const -{ - return m_routes.end(); -} - -std::ostream& -operator<<(std::ostream& os, const RibEntry& entry); - -} // namespace nfd -} // namespace ndn - -#endif // NDN_MGMT_NFD_RIB_ENTRY_HPP diff --git a/src/mgmt/nfd/rib-flags.hpp b/src/mgmt/nfd/rib-flags.hpp deleted file mode 100644 index 158048f68..000000000 --- a/src/mgmt/nfd/rib-flags.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_MGMT_NFD_RIB_FLAGS_HPP -#define NDN_MGMT_NFD_RIB_FLAGS_HPP - -#include "../../encoding/nfd-constants.hpp" - -namespace ndn { -namespace nfd { - -/** - * \ingroup management - * \brief implements getters to each RIB flag - * - * \tparam T class containing a RibFlags field and implements - * `RibFlags getFlags() const` method - */ -template -class RibFlagsTraits -{ -public: - bool - isChildInherit() const - { - return static_cast(this)->getFlags() & ROUTE_FLAG_CHILD_INHERIT; - } - - bool - isRibCapture() const - { - return static_cast(this)->getFlags() & ROUTE_FLAG_CAPTURE; - } -}; - -} // namespace nfd -} // namespace ndn - -#endif // NDN_MGMT_NFD_RIB_FLAGS_HPP diff --git a/src/mgmt/nfd/status-dataset.hpp b/src/mgmt/nfd/status-dataset.hpp deleted file mode 100644 index 9eb43d44a..000000000 --- a/src/mgmt/nfd/status-dataset.hpp +++ /dev/null @@ -1,252 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_MGMT_NFD_STATUS_DATASET_HPP -#define NDN_MGMT_NFD_STATUS_DATASET_HPP - -#include "../../name.hpp" -#include "forwarder-status.hpp" -#include "face-status.hpp" -#include "face-query-filter.hpp" -#include "channel-status.hpp" -#include "fib-entry.hpp" -#include "strategy-choice.hpp" -#include "rib-entry.hpp" - -namespace ndn { -namespace nfd { - -/** - * \ingroup management - * \brief base class of NFD StatusDataset - * \sa http://redmine.named-data.net/projects/nfd/wiki/StatusDataset - */ -class StatusDataset : noncopyable -{ -public: -#ifdef DOXYGEN - /** - * \brief if defined, specifies constructor argument type; - * otherwise, constructor has no argument - */ - typedef int ParamType; -#endif - - /** - * \brief constructs a name prefix for the dataset - * \param prefix top-level prefix, such as ndn:/localhost/nfd - * \return name prefix without version and segment components - */ - Name - getDatasetPrefix(const Name& prefix) const; - -#ifdef DOXYGEN - /** - * \brief provides the result type, usually a vector - */ - typedef std::vector ResultType; -#endif - - /** - * \brief indicates reassembled payload cannot be parsed as ResultType - */ - class ParseResultError : public tlv::Error - { - public: - explicit - ParseResultError(const std::string& what) - : tlv::Error(what) - { - } - }; - -#ifdef DOXYGEN - /** - * \brief parses a result from reassembled payload - * \param payload reassembled payload - * \throw tlv::Error cannot parse payload - */ - ResultType - parseResult(ConstBufferPtr payload) const; -#endif - -protected: - /** - * \brief constructs a StatusDataset instance with given sub-prefix - * \param datasetName dataset name after top-level prefix, such as faces/list - */ - explicit - StatusDataset(const PartialName& datasetName); - -private: - /** - * \brief appends parameters to the dataset name prefix - * \param[in,out] the dataset name prefix onto which parameter components can be appended - */ - virtual void - addParameters(Name& name) const; - -private: - PartialName m_datasetName; -}; - - -/** - * \ingroup management - * \brief represents a status/general dataset - * \sa http://redmine.named-data.net/projects/nfd/wiki/ForwarderStatus#General-Status-Dataset - */ -class ForwarderGeneralStatusDataset : public StatusDataset -{ -public: - ForwarderGeneralStatusDataset(); - - typedef ForwarderStatus ResultType; - - ResultType - parseResult(ConstBufferPtr payload) const; -}; - - -/** - * \ingroup management - * \brief provides common functionality among FaceDataset and FaceQueryDataset - */ -class FaceDatasetBase : public StatusDataset -{ -public: - typedef std::vector ResultType; - - ResultType - parseResult(ConstBufferPtr payload) const; - -protected: - explicit - FaceDatasetBase(const PartialName& datasetName); -}; - - -/** - * \ingroup management - * \brief represents a faces/list dataset - * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Face-Dataset - */ -class FaceDataset : public FaceDatasetBase -{ -public: - FaceDataset(); -}; - - -/** - * \ingroup management - * \brief represents a faces/query dataset - * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Query-Operation - */ -class FaceQueryDataset : public FaceDatasetBase -{ -public: - typedef FaceQueryFilter ParamType; - - explicit - FaceQueryDataset(const FaceQueryFilter& filter); - -private: - virtual void - addParameters(Name& name) const override; - -private: - FaceQueryFilter m_filter; -}; - - -/** - * \ingroup management - * \brief represents a faces/channels dataset - * \sa https://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Channel-Dataset - */ -class ChannelDataset : public StatusDataset -{ -public: - ChannelDataset(); - - typedef std::vector ResultType; - - ResultType - parseResult(ConstBufferPtr payload) const; -}; - - -/** - * \ingroup management - * \brief represents a fib/list dataset - * \sa http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#FIB-Dataset - */ -class FibDataset : public StatusDataset -{ -public: - FibDataset(); - - typedef std::vector ResultType; - - ResultType - parseResult(ConstBufferPtr payload) const; -}; - - -/** - * \ingroup management - * \brief represents a strategy-choice/list dataset - * \sa http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Strategy-Choice-Dataset - */ -class StrategyChoiceDataset : public StatusDataset -{ -public: - StrategyChoiceDataset(); - - typedef std::vector ResultType; - - ResultType - parseResult(ConstBufferPtr payload) const; -}; - - -/** - * \ingroup management - * \brief represents a rib/list dataset - * \sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#RIB-Dataset - */ -class RibDataset : public StatusDataset -{ -public: - RibDataset(); - - typedef std::vector ResultType; - - ResultType - parseResult(ConstBufferPtr payload) const; -}; - - -} // namespace nfd -} // namespace ndn - -#endif // NDN_MGMT_NFD_STATUS_DATASET_HPP diff --git a/src/mgmt/nfd/strategy-choice.cpp b/src/mgmt/nfd/strategy-choice.cpp deleted file mode 100644 index 2e294d728..000000000 --- a/src/mgmt/nfd/strategy-choice.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "strategy-choice.hpp" -#include "encoding/tlv-nfd.hpp" -#include "encoding/block-helpers.hpp" -#include "util/concepts.hpp" - -namespace ndn { -namespace nfd { - -//BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "StrategyChoice::Error must inherit from tlv::Error"); - -StrategyChoice::StrategyChoice() -{ -} - -StrategyChoice::StrategyChoice(const Block& payload) -{ - this->wireDecode(payload); -} - -template -size_t -StrategyChoice::wireEncode(EncodingImpl& encoder) const -{ - size_t totalLength = 0; - - totalLength += prependNestedBlock(encoder, tlv::nfd::Strategy, m_strategy); - totalLength += m_name.wireEncode(encoder); - - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::nfd::StrategyChoice); - return totalLength; -} - -template size_t -StrategyChoice::wireEncode(EncodingImpl&) const; - -template size_t -StrategyChoice::wireEncode(EncodingImpl&) const; - -const Block& -StrategyChoice::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 -StrategyChoice::wireDecode(const Block& block) -{ - if (block.type() != tlv::nfd::StrategyChoice) { - BOOST_THROW_EXCEPTION(Error("expecting StrategyChoice block")); - } - m_wire = block; - m_wire.parse(); - Block::element_const_iterator val = m_wire.elements_begin(); - - if (val != m_wire.elements_end() && val->type() == tlv::Name) { - m_name.wireDecode(*val); - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required Name field")); - } - - if (val != m_wire.elements_end() && val->type() == tlv::nfd::Strategy) { - val->parse(); - if (val->elements().empty()) { - BOOST_THROW_EXCEPTION(Error("expecting Strategy/Name")); - } - else { - m_strategy.wireDecode(*val->elements_begin()); - } - ++val; - } - else { - BOOST_THROW_EXCEPTION(Error("missing required Strategy field")); - } -} - -StrategyChoice& -StrategyChoice::setName(const Name& name) -{ - m_wire.reset(); - m_name = name; - return *this; -} - -StrategyChoice& -StrategyChoice::setStrategy(const Name& strategy) -{ - m_wire.reset(); - m_strategy = strategy; - return *this; -} - -} // namespace nfd -} // namespace ndn diff --git a/src/mgmt/nfd/strategy-choice.hpp b/src/mgmt/nfd/strategy-choice.hpp deleted file mode 100644 index 8cdaa59e8..000000000 --- a/src/mgmt/nfd/strategy-choice.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_MGMT_NFD_STRATEGY_CHOICE_HPP -#define NDN_MGMT_NFD_STRATEGY_CHOICE_HPP - -#include "../../encoding/block.hpp" -#include "../../name.hpp" - -namespace ndn { -namespace nfd { - -/** - * @ingroup management - * @brief represents NFD StrategyChoice dataset - * @sa http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Strategy-Choice-Dataset - */ -class StrategyChoice -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - - StrategyChoice(); - - explicit - StrategyChoice(const Block& payload); - - template - size_t - wireEncode(EncodingImpl& encoder) const; - - const Block& - wireEncode() const; - - void - wireDecode(const Block& wire); - -public: // getters & setters - const Name& - getName() const - { - return m_name; - } - - StrategyChoice& - setName(const Name& name); - - const Name& - getStrategy() const - { - return m_strategy; - } - - StrategyChoice& - setStrategy(const Name& strategy); - -private: - Name m_name; // namespace - Name m_strategy; // strategy for the namespace - - mutable Block m_wire; -}; - -} // namespace nfd -} // namespace ndn - -#endif // NDN_MGMT_NFD_STRATEGY_CHOICE_HPP diff --git a/src/name-component.cpp b/src/name-component.cpp deleted file mode 100644 index b491f2eea..000000000 --- a/src/name-component.cpp +++ /dev/null @@ -1,490 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Jeff Thompson - * @author Alexander Afanasyev - * @author Zhenkai Zhu - */ - -#include "name-component.hpp" - -#include "encoding/block-helpers.hpp" -#include "encoding/encoding-buffer.hpp" -#include "util/string-helper.hpp" -#include "util/crypto.hpp" - -#include - -namespace ndn { -namespace name { - -BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "name::Component::Error must inherit from tlv::Error"); - -static const std::string& -getSha256DigestUriPrefix() -{ - static const std::string prefix{"sha256digest="}; - return prefix; -} - -Component::Component() - : Block(tlv::NameComponent) -{ -} - -Component::Component(const Block& wire) - : Block(wire) -{ - if (!isGeneric() && !isImplicitSha256Digest()) - BOOST_THROW_EXCEPTION(Error("Cannot construct name::Component from not a NameComponent " - "or ImplicitSha256DigestComponent TLV wire block")); -} - -Component::Component(const ConstBufferPtr& buffer) - : Block(tlv::NameComponent, buffer) -{ -} - -Component::Component(const Buffer& value) - : Block(makeBinaryBlock(tlv::NameComponent, value.buf(), value.size())) -{ -} - -Component::Component(const uint8_t* value, size_t valueLen) - : Block(makeBinaryBlock(tlv::NameComponent, value, valueLen)) -{ -} - -Component::Component(const char* str) - : Block(makeBinaryBlock(tlv::NameComponent, str, std::char_traits::length(str))) -{ -} - -Component::Component(const std::string& str) - : Block(makeStringBlock(tlv::NameComponent, str)) -{ -} - - -Component -Component::fromEscapedString(const char* escapedString, size_t beginOffset, size_t endOffset) -{ - std::string trimmedString(escapedString + beginOffset, escapedString + endOffset); - trim(trimmedString); - - if (trimmedString.compare(0, getSha256DigestUriPrefix().size(), - getSha256DigestUriPrefix()) == 0) { - if (trimmedString.size() != getSha256DigestUriPrefix().size() + crypto::SHA256_DIGEST_SIZE * 2) - BOOST_THROW_EXCEPTION(Error("Cannot convert to ImplicitSha256DigestComponent" - "(expected sha256 in hex encoding)")); - - try { - trimmedString.erase(0, getSha256DigestUriPrefix().size()); - return fromImplicitSha256Digest(fromHex(trimmedString)); - } - catch (StringHelperError& e) { - BOOST_THROW_EXCEPTION(Error("Cannot convert to a ImplicitSha256DigestComponent (invalid hex " - "encoding)")); - } - } - else { - std::string value = unescape(trimmedString); - - if (value.find_first_not_of(".") == std::string::npos) { - // Special case for component of only periods. - if (value.size() <= 2) - // Zero, one or two periods is illegal. Ignore this component. - BOOST_THROW_EXCEPTION(Error("Illegal URI (name component cannot be . or ..)")); - else - // Remove 3 periods. - return Component(reinterpret_cast(&value[3]), value.size() - 3); - } - else - return Component(reinterpret_cast(&value[0]), value.size()); - } -} - - -void -Component::toUri(std::ostream& result) const -{ - if (type() == tlv::ImplicitSha256DigestComponent) { - result << getSha256DigestUriPrefix(); - - printHex(result, value(), value_size(), false); - } - else { - const uint8_t* value = this->value(); - size_t valueSize = value_size(); - - bool gotNonDot = false; - for (size_t i = 0; i < valueSize; ++i) { - if (value[i] != 0x2e) { - gotNonDot = true; - break; - } - } - if (!gotNonDot) { - // Special case for component of zero or more periods. Add 3 periods. - result << "..."; - for (size_t i = 0; i < valueSize; ++i) - result << '.'; - } - else { - // In case we need to escape, set to upper case hex and save the previous flags. - std::ios::fmtflags saveFlags = result.flags(std::ios::hex | std::ios::uppercase); - - for (size_t i = 0; i < valueSize; ++i) { - uint8_t x = value[i]; - // Check for 0-9, A-Z, a-z, (+), (-), (.), (_) - if ((x >= 0x30 && x <= 0x39) || (x >= 0x41 && x <= 0x5a) || - (x >= 0x61 && x <= 0x7a) || x == 0x2b || x == 0x2d || - x == 0x2e || x == 0x5f) - result << x; - else { - result << '%'; - if (x < 16) - result << '0'; - result << static_cast(x); - } - } - - // Restore. - result.flags(saveFlags); - } - } -} - -std::string -Component::toUri() const -{ - std::ostringstream os; - toUri(os); - return os.str(); -} - -//////////////////////////////////////////////////////////////////////////////// - -bool -Component::isNumber() const -{ - return (value_size() == 1 || value_size() == 2 || - value_size() == 4 || value_size() == 8); -} - -bool -Component::isNumberWithMarker(uint8_t marker) const -{ - return (!empty() && value()[0] == marker && - (value_size() == 2 || value_size() == 3 || - value_size() == 5 || value_size() == 9)); -} - -bool -Component::isVersion() const -{ - return isNumberWithMarker(VERSION_MARKER); -} - -bool -Component::isSegment() const -{ - return isNumberWithMarker(SEGMENT_MARKER); -} - -bool -Component::isSegmentOffset() const -{ - return isNumberWithMarker(SEGMENT_OFFSET_MARKER); -} - -bool -Component::isTimestamp() const -{ - return isNumberWithMarker(TIMESTAMP_MARKER); -} - -bool -Component::isSequenceNumber() const -{ - return isNumberWithMarker(SEQUENCE_NUMBER_MARKER); -} - -//////////////////////////////////////////////////////////////////////////////// - -uint64_t -Component::toNumber() const -{ - if (!isNumber()) - BOOST_THROW_EXCEPTION(Error("Name component does not have nonNegativeInteger value")); - - return readNonNegativeInteger(*this); -} - -uint64_t -Component::toNumberWithMarker(uint8_t marker) const -{ - if (!isNumberWithMarker(marker)) - BOOST_THROW_EXCEPTION(Error("Name component does not have the requested marker " - "or the value is not a nonNegativeInteger")); - - Buffer::const_iterator valueBegin = value_begin() + 1; - return tlv::readNonNegativeInteger(value_size() - 1, valueBegin, value_end()); -} - -uint64_t -Component::toVersion() const -{ - return toNumberWithMarker(VERSION_MARKER); -} - -uint64_t -Component::toSegment() const -{ - return toNumberWithMarker(SEGMENT_MARKER); -} - -uint64_t -Component::toSegmentOffset() const -{ - return toNumberWithMarker(SEGMENT_OFFSET_MARKER); -} - -time::system_clock::TimePoint -Component::toTimestamp() const -{ - uint64_t value = toNumberWithMarker(TIMESTAMP_MARKER); - return time::getUnixEpoch() + time::microseconds(value); -} - -uint64_t -Component::toSequenceNumber() const -{ - return toNumberWithMarker(SEQUENCE_NUMBER_MARKER); -} - -//////////////////////////////////////////////////////////////////////////////// - -Component -Component::fromNumber(uint64_t number) -{ - return makeNonNegativeIntegerBlock(tlv::NameComponent, number); -} - -Component -Component::fromNumberWithMarker(uint8_t marker, uint64_t number) -{ - EncodingEstimator estimator; - - size_t valueLength = estimator.prependNonNegativeInteger(number); - valueLength += estimator.prependByteArray(&marker, 1); - size_t totalLength = valueLength; - totalLength += estimator.prependVarNumber(valueLength); - totalLength += estimator.prependVarNumber(tlv::NameComponent); - - EncodingBuffer encoder(totalLength, 0); - encoder.prependNonNegativeInteger(number); - encoder.prependByteArray(&marker, 1); - encoder.prependVarNumber(valueLength); - encoder.prependVarNumber(tlv::NameComponent); - - return encoder.block(); -} - -Component -Component::fromVersion(uint64_t version) -{ - return fromNumberWithMarker(VERSION_MARKER, version); -} - -Component -Component::fromSegment(uint64_t segmentNo) -{ - return fromNumberWithMarker(SEGMENT_MARKER, segmentNo); -} - -Component -Component::fromSegmentOffset(uint64_t offset) -{ - return fromNumberWithMarker(SEGMENT_OFFSET_MARKER, offset); -} - -Component -Component::fromTimestamp(const time::system_clock::TimePoint& timePoint) -{ - using namespace time; - uint64_t value = duration_cast(timePoint - getUnixEpoch()).count(); - return fromNumberWithMarker(TIMESTAMP_MARKER, value); -} - -Component -Component::fromSequenceNumber(uint64_t seqNo) -{ - return fromNumberWithMarker(SEQUENCE_NUMBER_MARKER, seqNo); -} - -//////////////////////////////////////////////////////////////////////////////// - -bool -Component::isGeneric() const -{ - return (type() == tlv::NameComponent); -} - -bool -Component::isImplicitSha256Digest() const -{ - return (type() == tlv::ImplicitSha256DigestComponent && - value_size() == crypto::SHA256_DIGEST_SIZE); -} - -Component -Component::fromImplicitSha256Digest(const ConstBufferPtr& digest) -{ - if (digest->size() != crypto::SHA256_DIGEST_SIZE) - BOOST_THROW_EXCEPTION(Error("Cannot create ImplicitSha256DigestComponent (input digest must be " + - to_string(crypto::SHA256_DIGEST_SIZE) + " octets)")); - - return Block(tlv::ImplicitSha256DigestComponent, digest); -} - -Component -Component::fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize) -{ - if (digestSize != crypto::SHA256_DIGEST_SIZE) - BOOST_THROW_EXCEPTION(Error("Cannot create ImplicitSha256DigestComponent (input digest must be " + - to_string(crypto::SHA256_DIGEST_SIZE) + " octets)")); - - return makeBinaryBlock(tlv::ImplicitSha256DigestComponent, digest, digestSize); -} - -//////////////////////////////////////////////////////////////////////////////// - -bool -Component::equals(const Component& other) const -{ - return type() == other.type() && - value_size() == other.value_size() && - (empty() || // needed on OSX 10.9 due to STL bug - std::equal(value_begin(), value_end(), other.value_begin())); -} - -int -Component::compare(const Component& other) const -{ - if (this->hasWire() && other.hasWire()) { - // In the common case where both components have wire encoding, - // it's more efficient to simply compare the wire encoding. - // This works because lexical order of TLV encoding happens to be - // the same as canonical order of the value. - return std::memcmp(wire(), other.wire(), std::min(size(), other.size())); - } - - int cmpType = type() - other.type(); - if (cmpType != 0) - return cmpType; - - int cmpSize = value_size() - other.value_size(); - if (cmpSize != 0) - return cmpSize; - - if (empty()) // needed on OSX 10.9 due to STL bug - return 0; - - return std::memcmp(value(), other.value(), value_size()); -} - -Component -Component::getSuccessor() const -{ - size_t totalLength = 0; - EncodingBuffer encoder(size() + 1, 1); // + 1 in case there is an overflow - // in unlikely case TLV length increases, - // EncodingBuffer will take care of that - - bool isOverflow = true; - size_t i = value_size(); - for (; isOverflow && i > 0; i--) { - uint8_t newValue = static_cast((value()[i - 1] + 1) & 0xFF); - totalLength += encoder.prependByte(newValue); - isOverflow = (newValue == 0); - } - totalLength += encoder.prependByteArray(value(), i); - - if (isOverflow) { - // new name components has to be extended - totalLength += encoder.appendByte(0); - } - - encoder.prependVarNumber(totalLength); - encoder.prependVarNumber(type()); - - return encoder.block(); -} - - -template -size_t -Component::wireEncode(EncodingImpl& encoder) const -{ - size_t totalLength = 0; - if (value_size() > 0) - totalLength += encoder.prependByteArray(value(), value_size()); - totalLength += encoder.prependVarNumber(value_size()); - totalLength += encoder.prependVarNumber(type()); - return totalLength; -} - -template size_t -Component::wireEncode(EncodingImpl& encoder) const; - -template size_t -Component::wireEncode(EncodingImpl& encoder) const; - -const Block& -Component::wireEncode() const -{ - if (this->hasWire()) - return *this; - - EncodingEstimator estimator; - size_t estimatedSize = wireEncode(estimator); - - EncodingBuffer buffer(estimatedSize, 0); - wireEncode(buffer); - - const_cast(*this) = buffer.block(); - return *this; -} - -void -Component::wireDecode(const Block& wire) -{ - *this = wire; - // validity check is done within Component(const Block& wire) -} - -} // namespace name -} // namespace ndn diff --git a/src/name-component.hpp b/src/name-component.hpp deleted file mode 100644 index 7b4391019..000000000 --- a/src/name-component.hpp +++ /dev/null @@ -1,619 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_NAME_COMPONENT_HPP -#define NDN_NAME_COMPONENT_HPP - -#include "common.hpp" -#include "encoding/block.hpp" -#include "encoding/block-helpers.hpp" -#include "util/time.hpp" - -namespace ndn { -namespace name { - -/// @brief Segment marker for NDN naming conventions -static const uint8_t SEGMENT_MARKER = 0x00; -/// @brief Segment offset marker for NDN naming conventions -static const uint8_t SEGMENT_OFFSET_MARKER = 0xFB; -/// @brief Version marker for NDN naming conventions -static const uint8_t VERSION_MARKER = 0xFD; -/// @brief Timestamp marker for NDN naming conventions -static const uint8_t TIMESTAMP_MARKER = 0xFC; -/// @brief Sequence number marker for NDN naming conventions -static const uint8_t SEQUENCE_NUMBER_MARKER = 0xFE; - -/** - * @brief Component holds a read-only name component value. - */ -class Component : public Block -{ -public: - /** - * @brief Error that can be thrown from name::Component - */ - class Error : public Block::Error - { - public: - explicit - Error(const std::string& what) - : Block::Error(what) - { - } - }; - - /** - * Create a new name::Component with an empty value - */ - Component(); - - /** - * @brief Create name::Component from a wire block - * - * @param wire tlv::NameComponent Block from which to create name::Component - * @throws Error if wire.type() is not tlv::NameComponent - * - * Any block can be implicitly converted to name::Component - */ - Component(const Block& wire); - - /** - * @brief Create a new name::Component from the buffer pointer (buffer pointer will be copied) - * - * @param buffer A pointer to an immutable buffer - * - * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload. - * Note that this method **will not** allocate new memory for and copy the payload until - * toWire() method is called. - */ - explicit - Component(const ConstBufferPtr& buffer); - - /** - * @brief Create a new name::Component from the buffer (data from buffer will be copied) - * @param buffer A reference to the buffer - * - * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload. - * Note that this method **will** allocate new memory for and copy the payload. - */ - explicit - Component(const Buffer& buffer); - - /** - * @brief Create a new name::Component from the buffer (data from buffer will be copied) - * @param buffer A pointer to the first byte of the buffer - * @param bufferSize Size of the buffer - * - * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload. - * Note that this method **will** allocate new memory for and copy the payload. - */ - Component(const uint8_t* buffer, size_t bufferSize); - - /** - * @brief Create a new name::Component frome the range [@p first, @p last) of bytes - * @param first Iterator pointing to the beginning of the buffer - * @param last Iterator pointing to the ending of the buffer - * @tparam Iterator iterator type satisfying at least InputIterator concept. Implementation - * is more optimal when the iterator type satisfies RandomAccessIterator concept. - * It is required that sizeof(std::iterator_traits::value_type) == 1. - * - * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload. - * Note that this method **will** allocate new memory for and copy the payload. - */ - template - Component(Iterator first, Iterator last); - - /** - * @brief Create a new name::Component from the C string (data from string will be copied) - * - * @param str Zero-ended string. Note that this string will be interpreted as is (i.e., - * it will not be interpreted as URI) - * - * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload. - * Note that this method **will** allocate new memory for and copy the payload. - */ - explicit - Component(const char* str); - - /** - * @brief Create a new name::Component from the STL string (data from string will be copied) - * - * @param str Const reference to STL string. Note that this string will be interpreted - * as is (i.e., it will not be interpreted as URI) - * - * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload. - * Note that this method **will** allocate new memory for and copy the payload. - */ - explicit - Component(const std::string& str); - - /** - * @brief Fast encoding or block size estimation - */ - template - size_t - wireEncode(EncodingImpl& encoder) const; - - /** - * @brief Encode to a wire format - */ - const Block& - wireEncode() const; - - /** - * @brief Decode from the wire format - */ - void - wireDecode(const Block& wire); - - /** - * @brief Create name::Component by decoding the escapedString between beginOffset and - * endOffset according to the NDN URI Scheme. - * - * If the escaped string is "", "." or ".." then return an empty name::Component. Note - * that an empty name::Component should not be added to Name and if attempted, an - * exception will be thrown. - * - * @param escapedString String containing NDN URI-encoded name - * component. [escapedString+beginOffset, beginOffset+endOffset) - * must be a valid memory buffer. - * @param beginOffset The offset in escapedString of the beginning of the portion to decode. - * @param endOffset The offset in escapedString of the end of the portion to decode. - */ - static Component - fromEscapedString(const char* escapedString, size_t beginOffset, size_t endOffset); - - /** - * @brief Create name::Component by decoding the escapedString according to the NDN URI Scheme - * - * This overload is a convenience wrapper for fromEscapedString(char*,size_t,size) - */ - static Component - fromEscapedString(const char* escapedString) - { - return fromEscapedString(escapedString, 0, std::char_traits::length(escapedString)); - } - - /** - * @brief Create name::Component by decoding the escapedString according to the NDN URI Scheme - * - * This overload is a convenience wrapper for fromEscapedString(char*,size_t,size) - */ - static Component - fromEscapedString(const std::string& escapedString) - { - return fromEscapedString(escapedString.c_str(), 0, escapedString.size()); - } - - /** - * @brief Write *this to the output stream, escaping characters according to the NDN URI Scheme - * - * @deprecated Use toUri(std::ostream&) instead - * - * This also adds "..." to a value with zero or more "." - * - * @param os The output stream to where write the URI escaped version *this - */ - DEPRECATED( - void - toEscapedString(std::ostream& os) const) - { - return toUri(os); - } - - /** - * @brief Convert *this by escaping characters according to the NDN URI Scheme - * - * @deprecated Use toUri() instead - * - * This also adds "..." to a value with zero or more "." - * - * @return The escaped string - */ - DEPRECATED( - std::string - toEscapedString() const) - { - return toUri(); - } - - /** - * @brief Write *this to the output stream, escaping characters according to the NDN URI Scheme - * - * This also adds "..." to a value with zero or more "." - * - * @param os The output stream to where write the URI escaped version *this - */ - void - toUri(std::ostream& os) const; - - /** - * @brief Convert *this by escaping characters according to the NDN URI Scheme - * - * This also adds "..." to a value with zero or more "." - * - * @return The escaped string - */ - std::string - toUri() const; - - //////////////////////////////////////////////////////////////////////////////// - - /** - * @brief Check if the component is nonNegativeInteger - * @see http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding - */ - bool - isNumber() const; - - /** - * @brief Check if the component is NameComponentWithMarker per NDN naming conventions - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - bool - isNumberWithMarker(uint8_t marker) const; - - /** - * @brief Check if the component is version per NDN naming conventions - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - bool - isVersion() const; - - /** - * @brief Check if the component is segment number per NDN naming conventions - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - bool - isSegment() const; - - /** - * @brief Check if the component is segment offset per NDN naming conventions - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - bool - isSegmentOffset() const; - - /** - * @brief Check if the component is timestamp per NDN naming conventions - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - bool - isTimestamp() const; - - /** - * @brief Check if the component is sequence number per NDN naming conventions - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - bool - isSequenceNumber() const; - - //////////////////////////////////////////////////////////////////////////////// - - /** - * @brief Interpret this name component as nonNegativeInteger - * - * @see http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding - * - * @return The integer number. - */ - uint64_t - toNumber() const; - - /** - * @brief Interpret this name component as NameComponentWithMarker - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - * - * @param marker 1-byte octet of the marker - * @return The integer number. - * @throws Error if name component does not have the specified marker. - * tlv::Error if format does not follow NameComponentWithMarker specification. - */ - uint64_t - toNumberWithMarker(uint8_t marker) const; - - /** - * @brief Interpret as version component using NDN naming conventions - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - * - * @throws Error if name component does not have the specified marker. - * tlv::Error if format does not follow NameComponentWithMarker specification. - */ - uint64_t - toVersion() const; - - /** - * @brief Interpret as segment number component using NDN naming conventions - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - * - * @throws Error if name component does not have the specified marker. - * tlv::Error if format does not follow NameComponentWithMarker specification. - */ - uint64_t - toSegment() const; - - /** - * @brief Interpret as segment offset component using NDN naming conventions - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - * - * @throws Error if name component does not have the specified marker. - * tlv::Error if format does not follow NameComponentWithMarker specification. - */ - uint64_t - toSegmentOffset() const; - - /** - * @brief Interpret as timestamp component using NDN naming conventions - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - * - * @throws Error if name component does not have the specified marker. - * tlv::Error if format does not follow NameComponentWithMarker specification. - */ - time::system_clock::TimePoint - toTimestamp() const; - - /** - * @brief Interpret as sequence number component using NDN naming conventions - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - * - * @throws Error if name component does not have the specified marker. - * tlv::Error if format does not follow NameComponentWithMarker specification. - */ - uint64_t - toSequenceNumber() const; - - //////////////////////////////////////////////////////////////////////////////// - - /** - * @brief Create a component encoded as nonNegativeInteger - * - * @see http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding - * - * @param number The non-negative number - * @return The component value. - */ - static Component - fromNumber(uint64_t number); - - /** - * @brief Create a component encoded as NameComponentWithMarker - * - * NameComponentWithMarker is defined as: - * - * NameComponentWithMarker ::= NAME-COMPONENT-TYPE TLV-LEGTH - * Marker - * includedNonNegativeInteger - * Marker ::= BYTE - * includedNonNegativeInteger ::= BYTE{1,2,4,8} - * NDN-TLV := TLV-TYPE TLV-LENGTH TLV-VALUE? - * TLV-TYPE := VAR-NUMBER - * TLV-LENGTH := VAR-NUMBER - * TLV-VALUE := BYTE+ - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - * - * @param marker 1-byte marker octet - * @param number The non-negative number - * @return The component value. - */ - static Component - fromNumberWithMarker(uint8_t marker, uint64_t number); - - /** - * @brief Create version component using NDN naming conventions - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - static Component - fromVersion(uint64_t version); - - /** - * @brief Create segment number component using NDN naming conventions - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - static Component - fromSegment(uint64_t segmentNo); - - /** - * @brief Create segment offset component using NDN naming conventions - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - static Component - fromSegmentOffset(uint64_t offset); - - /** - * @brief Create sequence number component using NDN naming conventions - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - static Component - fromTimestamp(const time::system_clock::TimePoint& timePoint); - - /** - * @brief Create sequence number component using NDN naming conventions - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - static Component - fromSequenceNumber(uint64_t seqNo); - - //////////////////////////////////////////////////////////////////////////////// - - /** - * @brief Check if the component is GenericComponent - */ - bool - isGeneric() const; - - /** - * @brief Check if the component is ImplicitSha256DigestComponent - */ - bool - isImplicitSha256Digest() const; - - /** - * @brief Create ImplicitSha256DigestComponent component - */ - static Component - fromImplicitSha256Digest(const ConstBufferPtr& digest); - - /** - * @brief Create ImplicitSha256DigestComponent component - */ - static Component - fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize); - - //////////////////////////////////////////////////////////////////////////////// - - bool - empty() const - { - return value_size() == 0; - } - - /** - * @brief Check if this is the same component as other - * - * @param other The other Component to compare with - * @return true if the components are equal, otherwise false. - */ - bool - equals(const Component& other) const; - - /** - * @brief Compare this to the other Component using NDN canonical ordering - * - * @param other The other Component to compare with. - * @retval negative this comes before other in canonical ordering - * @retval zero this equals other - * @retval positive this comes after other in canonical ordering - * - * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order - */ - int - compare(const Component& other) const; - - /** - * @brief Check if this is the same component as other - * - * @param other The other Component to compare with. - * @return true if the components are equal, otherwise false. - */ - bool - operator==(const Component& other) const - { - return equals(other); - } - - /** - * @brief Check if this is not the same component as other - * @param other The other Component to compare with - * @return true if the components are not equal, otherwise false - */ - bool - operator!=(const Component& other) const - { - return !equals(other); - } - - /** - * @brief Check if the *this is less than or equal to the other in NDN canonical ordering - * @param other The other Component to compare with - * - * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order - */ - bool - operator<=(const Component& other) const - { - return compare(other) <= 0; - } - - /** - * @brief Check if the *this is less than the other in NDN canonical ordering - * @param other The other Component to compare with - * - * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order - */ - bool - operator<(const Component& other) const - { - return compare(other) < 0; - } - - /** - * @brief Check if the *this is greater or equal than the other in NDN canonical ordering - * @param other The other Component to compare with - * - * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order - */ - bool - operator>=(const Component& other) const - { - return compare(other) >= 0; - } - - /** - * @brief Check if the *this is greater than the other in NDN canonical ordering - * @param other The other Component to compare with - * - * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order - */ - bool - operator>(const Component& other) const - { - return compare(other) > 0; - } - - Component - getSuccessor() const; - - // !!! NOTE TO IMPLEMENTOR !!! - // - // This class MUST NOT contain any data fields. - // Block can be reinterpret_cast'ed as Component type. -}; - -inline std::ostream& -operator<<(std::ostream& os, const Component& component) -{ - component.toUri(os); - return os; -} - -template -inline -Component::Component(Iterator first, Iterator last) - : Block(makeBinaryBlock(tlv::NameComponent, first, last)) -{ -} - -} // namespace name -} // namespace ndn - -#endif // NDN_NAME_COMPONENT_HPP diff --git a/src/name.cpp b/src/name.cpp deleted file mode 100644 index f8b9a8c85..000000000 --- a/src/name.cpp +++ /dev/null @@ -1,377 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Jeff Thompson - * @author Alexander Afanasyev - * @author Zhenkai Zhu - */ - -#include "name.hpp" - -#include "util/time.hpp" -#include "util/string-helper.hpp" -#include "encoding/block.hpp" -#include "encoding/encoding-buffer.hpp" - -#include - -namespace ndn { - -BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "Name::Error must inherit from tlv::Error"); - -const size_t Name::npos = std::numeric_limits::max(); - -Name::Name() - : m_nameBlock(tlv::Name) -{ -} - -Name::Name(const Block& wire) -{ - m_nameBlock = wire; - m_nameBlock.parse(); -} - -Name::Name(const char* uri) - : Name(std::string(uri)) -{ -} - -Name::Name(std::string uri) -{ - trim(uri); - if (uri.empty()) - return; - - size_t iColon = uri.find(':'); - if (iColon != std::string::npos) { - // Make sure the colon came before a '/'. - size_t iFirstSlash = uri.find('/'); - if (iFirstSlash == std::string::npos || iColon < iFirstSlash) { - // Omit the leading protocol such as ndn: - uri.erase(0, iColon + 1); - trim(uri); - } - } - - // Trim the leading slash and possibly the authority. - if (uri[0] == '/') { - if (uri.size() >= 2 && uri[1] == '/') { - // Strip the authority following "//". - size_t iAfterAuthority = uri.find('/', 2); - if (iAfterAuthority == std::string::npos) - // Unusual case: there was only an authority. - return; - else { - uri.erase(0, iAfterAuthority + 1); - trim(uri); - } - } - else { - uri.erase(0, 1); - trim(uri); - } - } - - size_t iComponentStart = 0; - - // Unescape the components. - while (iComponentStart < uri.size()) { - size_t iComponentEnd = uri.find("/", iComponentStart); - if (iComponentEnd == std::string::npos) - iComponentEnd = uri.size(); - - append(Component::fromEscapedString(&uri[0], iComponentStart, iComponentEnd)); - iComponentStart = iComponentEnd + 1; - } -} - -Name -Name::deepCopy() const -{ - Name copiedName(*this); - copiedName.m_nameBlock.resetWire(); - copiedName.wireEncode(); // "compress" the underlying buffer - return copiedName; -} - -template -size_t -Name::wireEncode(EncodingImpl& encoder) const -{ - size_t totalLength = 0; - - for (const_reverse_iterator i = rbegin(); i != rend(); ++i) - { - totalLength += i->wireEncode(encoder); - } - - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::Name); - return totalLength; -} - -template size_t -Name::wireEncode(EncodingImpl& encoder) const; - -template size_t -Name::wireEncode(EncodingImpl& encoder) const; - -const Block& -Name::wireEncode() const -{ - if (m_nameBlock.hasWire()) - return m_nameBlock; - - EncodingEstimator estimator; - size_t estimatedSize = wireEncode(estimator); - - EncodingBuffer buffer(estimatedSize, 0); - wireEncode(buffer); - - m_nameBlock = buffer.block(); - m_nameBlock.parse(); - - return m_nameBlock; -} - -void -Name::wireDecode(const Block& wire) -{ - if (wire.type() != tlv::Name) - BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding Name")); - - m_nameBlock = wire; - m_nameBlock.parse(); -} - -std::string -Name::toUri() const -{ - std::ostringstream os; - os << *this; - return os.str(); -} - -Name& -Name::append(const PartialName& name) -{ - if (&name == this) - // Copying from this name, so need to make a copy first. - return append(PartialName(name)); - - for (size_t i = 0; i < name.size(); ++i) - append(name.at(i)); - - return *this; -} - -Name& -Name::appendNumber(uint64_t number) -{ - m_nameBlock.push_back(Component::fromNumber(number)); - return *this; -} - -Name& -Name::appendNumberWithMarker(uint8_t marker, uint64_t number) -{ - m_nameBlock.push_back(Component::fromNumberWithMarker(marker, number)); - return *this; -} - -Name& -Name::appendVersion(uint64_t version) -{ - m_nameBlock.push_back(Component::fromVersion(version)); - return *this; -} - -Name& -Name::appendVersion() -{ - appendVersion(time::toUnixTimestamp(time::system_clock::now()).count()); - return *this; -} - -Name& -Name::appendSegment(uint64_t segmentNo) -{ - m_nameBlock.push_back(Component::fromSegment(segmentNo)); - return *this; -} - -Name& -Name::appendSegmentOffset(uint64_t offset) -{ - m_nameBlock.push_back(Component::fromSegmentOffset(offset)); - return *this; -} - -Name& -Name::appendTimestamp(const time::system_clock::TimePoint& timePoint) -{ - m_nameBlock.push_back(Component::fromTimestamp(timePoint)); - return *this; -} - -Name& -Name::appendSequenceNumber(uint64_t seqNo) -{ - m_nameBlock.push_back(Component::fromSequenceNumber(seqNo)); - return *this; -} - -Name& -Name::appendImplicitSha256Digest(const ConstBufferPtr& digest) -{ - m_nameBlock.push_back(Component::fromImplicitSha256Digest(digest)); - return *this; -} - -Name& -Name::appendImplicitSha256Digest(const uint8_t* digest, size_t digestSize) -{ - m_nameBlock.push_back(Component::fromImplicitSha256Digest(digest, digestSize)); - return *this; -} - -PartialName -Name::getSubName(ssize_t iStartComponent, size_t nComponents) const -{ - PartialName result; - - ssize_t iStart = iStartComponent < 0 ? this->size() + iStartComponent : iStartComponent; - size_t iEnd = this->size(); - - iStart = std::max(iStart, static_cast(0)); - - if (nComponents != npos) - iEnd = std::min(this->size(), iStart + nComponents); - - for (size_t i = iStart; i < iEnd; ++i) - result.append(at(i)); - - return result; -} - -Name -Name::getSuccessor() const -{ - if (empty()) { - static uint8_t firstValue[] = { 0 }; - Name firstName; - firstName.append(firstValue, 1); - return firstName; - } - - return getPrefix(-1).append(get(-1).getSuccessor()); -} - -bool -Name::equals(const Name& name) const -{ - if (size() != name.size()) - return false; - - for (size_t i = 0; i < size(); ++i) { - if (at(i) != name.at(i)) - return false; - } - - return true; -} - -bool -Name::isPrefixOf(const Name& name) const -{ - // This name is longer than the name we are checking against. - if (size() > name.size()) - return false; - - // Check if at least one of given components doesn't match. - for (size_t i = 0; i < size(); ++i) { - if (at(i) != name.at(i)) - return false; - } - - return true; -} - -int -Name::compare(size_t pos1, size_t count1, const Name& other, size_t pos2, size_t count2) const -{ - count1 = std::min(count1, this->size() - pos1); - count2 = std::min(count2, other.size() - pos2); - size_t count = std::min(count1, count2); - - for (size_t i = 0; i < count; ++i) { - int comp = this->at(pos1 + i).compare(other.at(pos2 + i)); - if (comp != 0) { // i-th component differs - return comp; - } - } - // [pos1, pos1+count) of this Name equals [pos2, pos2+count) of other Name - return count1 - count2; -} - -std::ostream& -operator<<(std::ostream& os, const Name& name) -{ - if (name.empty()) - { - os << "/"; - } - else - { - for (Name::const_iterator i = name.begin(); i != name.end(); i++) { - os << "/"; - i->toUri(os); - } - } - return os; -} - -std::istream& -operator>>(std::istream& is, Name& name) -{ - std::string inputString; - is >> inputString; - name = Name(inputString); - - return is; -} - -} // namespace ndn - -namespace std { -size_t -hash::operator()(const ndn::Name& name) const -{ - return boost::hash_range(name.wireEncode().wire(), - name.wireEncode().wire() + name.wireEncode().size()); -} - -} // namespace std diff --git a/src/name.hpp b/src/name.hpp deleted file mode 100644 index 381794704..000000000 --- a/src/name.hpp +++ /dev/null @@ -1,635 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Jeff Thompson - * @author Alexander Afanasyev - * @author Zhenkai Zhu - */ - -#ifndef NDN_NAME_HPP -#define NDN_NAME_HPP - -#include "common.hpp" -#include "name-component.hpp" - -#include - -namespace ndn { - -class Name; - -/** - * @brief Partial name abstraction to represent an arbitrary sequence of name components - */ -typedef Name PartialName; - -/** - * @brief Name abstraction to represent an absolute name - */ -class Name : public enable_shared_from_this -{ -public: - /** - * @brief Error that can be thrown from Name - */ - class Error : public name::Component::Error - { - public: - explicit - Error(const std::string& what) - : name::Component::Error(what) - { - } - }; - - typedef name::Component Component; - - typedef std::vector component_container; - - typedef Component value_type; - typedef void allocator_type; - typedef Component& reference; - typedef const Component const_reference; - typedef Component* pointer; - typedef const Component* const_pointer; - typedef Component* iterator; - typedef const Component* const_iterator; - - typedef boost::reverse_iterator reverse_iterator; - typedef boost::reverse_iterator const_reverse_iterator; - - typedef component_container::difference_type difference_type; - typedef component_container::size_type size_type; - - /** - * @brief Create a new Name with no components. - */ - Name(); - - /** - * @brief Create Name object from wire block - * - * This is a more efficient equivalent for - * @code - * Name name; - * name.wireDecode(wire); - * @endcode - */ - explicit - Name(const Block& wire); - - /** - * @brief Create name from @p uri (NDN URI scheme) - * @param uri The null-terminated URI string - */ - Name(const char* uri); - - /** - * @brief Create name from @p uri (NDN URI scheme) - * @param uri The URI string - */ - Name(std::string uri); - - /** - * @brief Make a deep copy of the name, reallocating the underlying memory buffer - */ - Name - deepCopy() const; - - /** - * @brief Fast encoding or block size estimation - */ - template - size_t - wireEncode(EncodingImpl& encoder) const; - - const Block& - wireEncode() const; - - void - wireDecode(const Block& wire); - - /** - * @brief Check if already has wire - */ - bool - hasWire() const; - - /** - * @brief Append a new component, copying from value of length valueLength. - * @return This name so that you can chain calls to append. - */ - Name& - append(const uint8_t* value, size_t valueLength) - { - m_nameBlock.push_back(Component(value, valueLength)); - return *this; - } - - /** - * @brief Append a new component, copying from value frome the range [@p first, @p last) of bytes - * @param first Iterator pointing to the beginning of the buffer - * @param last Iterator pointing to the ending of the buffer - * @tparam Iterator iterator type satisfying at least InputIterator concept. Implementation - * is more optimal when the iterator type satisfies RandomAccessIterator concept. - * It is required that sizeof(std::iterator_traits::value_type) == 1. - * @return This name so that you can chain calls to append. - */ - template - Name& - append(Iterator first, Iterator last) - { - m_nameBlock.push_back(Component(first, last)); - return *this; - } - - /** - * @brief Append component @p value - */ - Name& - append(const Component& value) - { - m_nameBlock.push_back(value); - return *this; - } - - /** - * @brief Append name component that represented as a string - * - * Note that this method is necessary to ensure correctness and unambiguity of - * ``append("string")`` operations (both Component and Name can be implicitly - * converted from string, each having different outcomes - */ - Name& - append(const char* value) - { - m_nameBlock.push_back(Component(value)); - return *this; - } - - Name& - append(const Block& value) - { - if (value.type() == tlv::NameComponent) - m_nameBlock.push_back(value); - else - m_nameBlock.push_back(Block(tlv::NameComponent, value)); - - return *this; - } - - /** - * @brief append a PartialName to this Name. - * @param name the components to append - * @return this name - */ - Name& - append(const PartialName& name); - - /** - * Clear all the components. - */ - void - clear() - { - m_nameBlock = Block(tlv::Name); - } - - /** - * @brief Extract a sub-name (PartialName) of @p nComponents components starting - * from @p iStartComponent - * @param iStartComponent index of the first component; - * if iStartComponent is negative, size()+iStartComponent is used instead - * @param nComponents The number of components starting at iStartComponent. - * Use npos to get the Partial Name until the end of this Name. - * @details If iStartComponent is out of bounds and is negative, returns the components - * starting from the beginning of the Name. - * If iStartComponent is out of bounds and is positive, returns the component "/". - * If nComponents is out of bounds, returns the components until the end of - * this Name - * @return A new partial name - */ - PartialName - getSubName(ssize_t iStartComponent, size_t nComponents = npos) const; - - /** - * @brief Extract a prefix (PartialName) of the name, containing first @p nComponents components - * - * @param nComponents The number of prefix components. If nComponents is -N then return - * the prefix up to name.size() - N. For example getPrefix(-1) - * returns the name without the final component. - * @return A new partial name - */ - PartialName - getPrefix(ssize_t nComponents) const - { - if (nComponents < 0) - return getSubName(0, m_nameBlock.elements_size() + nComponents); - else - return getSubName(0, nComponents); - } - - /** - * Encode this name as a URI. - * @return The encoded URI. - */ - std::string - toUri() const; - - /** - * @brief Append a component with the number encoded as nonNegativeInteger - * - * @see http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding - * - * @param number The non-negative number - * @return This name so that you can chain calls to append. - */ - Name& - appendNumber(uint64_t number); - - /** - * @brief Create a component encoded as NameComponentWithMarker - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - * - * @param marker 1-byte marker octet - * @param number The non-negative number - */ - Name& - appendNumberWithMarker(uint8_t marker, uint64_t number); - - /** - * @brief Append version using NDN naming conventions - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - Name& - appendVersion(uint64_t version); - - /** - * @brief Append version using NDN naming conventions based on current UNIX timestamp - * in milliseconds - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - Name& - appendVersion(); - - /** - * @brief Append segment number (sequential) using NDN naming conventions - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - Name& - appendSegment(uint64_t segmentNo); - - /** - * @brief Append segment byte offset using NDN naming conventions - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - Name& - appendSegmentOffset(uint64_t offset); - - /** - * @brief Append timestamp using NDN naming conventions - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - Name& - appendTimestamp(const time::system_clock::TimePoint& timePoint = time::system_clock::now()); - - /** - * @brief Append sequence number using NDN naming conventions - * - * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf - */ - Name& - appendSequenceNumber(uint64_t seqNo); - - /** - * @brief Append ImplicitSha256Digest - */ - Name& - appendImplicitSha256Digest(const ConstBufferPtr& digest); - - /** - * @brief Append ImplicitSha256Digest - */ - Name& - appendImplicitSha256Digest(const uint8_t* digest, size_t digestSize); - - /** - * @brief Get the successor of a name - * - * The successor of a name is defined as follows: - * - * N represents the set of NDN Names, and X,Y ∈ N. - * Operator < is defined by canonical order on N. - * Y is the successor of X, if (a) X < Y, and (b) ∄ Z ∈ N s.t. X < Z < Y. - * - * In plain words, successor of a name is the same name, but with its last component - * advanced to a next possible value. - * - * Examples: - * - * - successor for / is /%00 - * - successor for /%00%01/%01%02 is /%00%01/%01%03 - * - successor for /%00%01/%01%FF is /%00%01/%02%00 - * - successor for /%00%01/%FF%FF is /%00%01/%00%00%00 - * - * @return a new name - */ - Name - getSuccessor() const; - - /** - * Check if this name has the same component count and components as the given name. - * @param name The Name to check. - * @return true if the names are equal, otherwise false. - */ - bool - equals(const Name& name) const; - - /** - * @brief Check if the N components of this name are the same as the first N components - * of the given name. - * - * @param name The Name to check. - * @return true if this matches the given name, otherwise false. This always returns - * true if this name is empty. - */ - bool - isPrefixOf(const Name& name) const; - - // - // vector equivalent interface. - // - - /** - * @brief Check if name is emtpy - */ - bool - empty() const - { - return m_nameBlock.elements().empty(); - } - - /** - * Get the number of components. - * @return The number of components. - */ - size_t - size() const - { - return m_nameBlock.elements_size(); - } - - /** - * Get the component at the given index. - * @param i The index of the component, starting from 0. - * @return The name component at the index. - */ - const Component& - get(ssize_t i) const - { - if (i >= 0) - return reinterpret_cast(m_nameBlock.elements()[i]); - else - return reinterpret_cast(m_nameBlock.elements()[size() + i]); - } - - const Component& - operator[](ssize_t i) const - { - return get(i); - } - - /** - * @brief Get component at the specified index - * - * Unlike get() and operator[] methods, at() checks for out of bounds - * and will throw Name::Error when it happens - * - * @throws Name::Error if index out of bounds - */ - const Component& - at(ssize_t i) const - { - if ((i >= 0 && static_cast(i) >= size()) || - (i < 0 && static_cast(-i) > size())) - BOOST_THROW_EXCEPTION(Error("Requested component does not exist (out of bounds)")); - - return get(i); - } - - /** - * @brief Compare this to the other Name using NDN canonical ordering. - * - * If the first components of each name are not equal, this returns a negative value if - * the first comes before the second using the NDN canonical ordering for name - * components, or a positive value if it comes after. If they are equal, this compares - * the second components of each name, etc. If both names are the same up to the size - * of the shorter name, this returns a negative value if the first name is shorter than - * the second or a positive value if it is longer. For example, if you std::sort gives: - * /a/b/d /a/b/cc /c /c/a /bb . - * This is intuitive because all names with the prefix /a are next to each other. - * But it may be also be counter-intuitive because /c comes before /bb according - * to NDN canonical ordering since it is shorter. - * - * @param other The other Name to compare with. - * - * @retval negative this comes before other in canonical ordering - * @retval zero this equals other - * @retval positive this comes after other in canonical ordering - * - * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order - */ - int - compare(const Name& other) const - { - return this->compare(0, npos, other); - } - - /** \brief compares [pos1, pos1+count1) components in this Name - * to [pos2, pos2+count2) components in \p other - * - * This is equivalent to this->getSubName(pos1, count1).compare(other.getSubName(pos2, count2)); - */ - int - compare(size_t pos1, size_t count1, - const Name& other, size_t pos2 = 0, size_t count2 = npos) const; - - /** - * Append the component - * @param component The component of type T. - */ - template void - push_back(const T& component) - { - append(component); - } - - /** - * Check if this name has the same component count and components as the given name. - * @param name The Name to check. - * @return true if the names are equal, otherwise false. - */ - bool - operator==(const Name& name) const - { - return equals(name); - } - - /** - * Check if this name has the same component count and components as the given name. - * @param name The Name to check. - * @return true if the names are not equal, otherwise false. - */ - bool - operator!=(const Name& name) const - { - return !equals(name); - } - - /** - * Return true if this is less than or equal to the other Name in the NDN canonical ordering. - * @param other The other Name to compare with. - * - * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order - */ - bool - operator<=(const Name& other) const - { - return compare(other) <= 0; - } - - /** - * Return true if this is less than the other Name in the NDN canonical ordering. - * @param other The other Name to compare with. - * - * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order - */ - bool - operator<(const Name& other) const - { - return compare(other) < 0; - } - - /** - * Return true if this is less than or equal to the other Name in the NDN canonical ordering. - * @param other The other Name to compare with. - * - * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order - */ - bool - operator>=(const Name& other) const - { - return compare(other) >= 0; - } - - /** - * Return true if this is greater than the other Name in the NDN canonical ordering. - * @param other The other Name to compare with. - * - * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order - */ - bool - operator>(const Name& other) const - { - return compare(other) > 0; - } - - // - // Iterator interface to name components. - // - - /** - * Begin iterator (const). - */ - const_iterator - begin() const - { - return reinterpret_cast(&*m_nameBlock.elements().begin()); - } - - /** - * End iterator (const). - * - * @todo Check if this crash when there are no elements in the buffer - */ - const_iterator - end() const - { - return reinterpret_cast(&*m_nameBlock.elements().end()); - } - - /** - * Reverse begin iterator (const). - */ - const_reverse_iterator - rbegin() const - { - return const_reverse_iterator(end()); - } - - /** - * Reverse end iterator (const). - */ - const_reverse_iterator - rend() const - { - return const_reverse_iterator(begin()); - } - -public: - /** \brief indicates "until the end" in getSubName and compare - */ - static const size_t npos; - -private: - mutable Block m_nameBlock; -}; - -std::ostream& -operator<<(std::ostream& os, const Name& name); - -std::istream& -operator>>(std::istream& is, Name& name); - -inline bool -Name::hasWire() const -{ - return m_nameBlock.hasWire(); -} - -} // namespace ndn - -namespace std { -template<> -struct hash -{ - size_t - operator()(const ndn::Name& name) const; -}; - -} // namespace std - -#endif diff --git a/src/security/certificate-cache-ttl.cpp b/src/security/certificate-cache-ttl.cpp deleted file mode 100644 index c1ad631bf..000000000 --- a/src/security/certificate-cache-ttl.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#include "certificate-cache-ttl.hpp" - -namespace ndn { -namespace security { - -CertificateCacheTtl::CertificateCacheTtl(boost::asio::io_service& io, - const time::seconds& defaultTtl/* = time::seconds(3600)*/) - : m_defaultTtl(defaultTtl) - , m_io(io) - , m_scheduler(m_io) -{ -} - -CertificateCacheTtl::~CertificateCacheTtl() -{ -} - -void -CertificateCacheTtl::insertCertificate(shared_ptr certificate) -{ - m_io.dispatch([this, certificate] { this->insert(certificate); }); -} - -shared_ptr -CertificateCacheTtl::getCertificate(const Name& certificateName) -{ - Cache::iterator it = m_cache.find(certificateName); - if (it != m_cache.end()) - return it->second.first; - else - return shared_ptr(); -} - -void -CertificateCacheTtl::reset() -{ - m_io.dispatch([this] { this->removeAll(); }); -} - -size_t -CertificateCacheTtl::getSize() -{ - return m_cache.size(); -} - -void -CertificateCacheTtl::insert(shared_ptr certificate) -{ - time::milliseconds expire = (certificate->getFreshnessPeriod() >= time::seconds::zero() ? - certificate->getFreshnessPeriod() : m_defaultTtl); - - Name index = certificate->getName().getPrefix(-1); - - Cache::iterator it = m_cache.find(index); - if (it != m_cache.end()) - m_scheduler.cancelEvent(it->second.second); - - EventId eventId = m_scheduler.scheduleEvent(expire, - bind(&CertificateCacheTtl::remove, - this, certificate->getName())); - - m_cache[index] = std::make_pair(certificate, eventId); -} - -void -CertificateCacheTtl::remove(const Name& certificateName) -{ - Name name = certificateName.getPrefix(-1); - Cache::iterator it = m_cache.find(name); - if (it != m_cache.end()) - m_cache.erase(it); -} - -void -CertificateCacheTtl::removeAll() -{ - for(Cache::iterator it = m_cache.begin(); it != m_cache.end(); it++) - m_scheduler.cancelEvent(it->second.second); - - m_cache.clear(); -} - -} // namespace security -} // namespace ndn diff --git a/src/security/certificate-cache-ttl.hpp b/src/security/certificate-cache-ttl.hpp deleted file mode 100644 index e0ef8374b..000000000 --- a/src/security/certificate-cache-ttl.hpp +++ /dev/null @@ -1,87 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_SECURITY_CERTIFICATE_CACHE_TTL_HPP -#define NDN_SECURITY_CERTIFICATE_CACHE_TTL_HPP - -#include "../common.hpp" -#include "certificate-cache.hpp" -#include "../util/scheduler.hpp" - -namespace ndn { -namespace security { - -/** - * @brief Cache of validated certificates with freshness-based eviction policy - * - * Validated certificates will stay in cache for the duration of their freshness period. - * The lifetime of the certificate in cache can be extended by "re-inserting" it in the cache. - */ -class CertificateCacheTtl : public CertificateCache -{ -public: - explicit - CertificateCacheTtl(boost::asio::io_service& io, - const time::seconds& defaultTtl = time::seconds(3600)); - - virtual - ~CertificateCacheTtl(); - - virtual void - insertCertificate(shared_ptr certificate); - - virtual shared_ptr - getCertificate(const Name& certificateNameWithoutVersion); - - virtual void - reset(); - - virtual size_t - getSize(); - -private: - void - insert(shared_ptr certificate); - - void - remove(const Name& certificateName); - - void - removeAll(); - -protected: - typedef std::map, EventId> > Cache; - - time::seconds m_defaultTtl; - Cache m_cache; - boost::asio::io_service& m_io; - Scheduler m_scheduler; -}; - -} // namespace security - -using security::CertificateCacheTtl; - -} // namespace ndn - -#endif // NDN_SECURITY_CERTIFICATE_CACHE_TTL_HPP diff --git a/src/security/certificate-cache.hpp b/src/security/certificate-cache.hpp deleted file mode 100644 index fa6cb79d9..000000000 --- a/src/security/certificate-cache.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_SECURITY_CERTIFICATE_CACHE_HPP -#define NDN_SECURITY_CERTIFICATE_CACHE_HPP - -#include "../name.hpp" -#include "v1/identity-certificate.hpp" - -namespace ndn { -namespace security { - -/** - * @brief Interface for the cache of validated certificates - */ -class CertificateCache : noncopyable -{ -public: - virtual - ~CertificateCache() - { - } - - virtual void - insertCertificate(shared_ptr certificate) = 0; - - virtual shared_ptr - getCertificate(const Name& certificateNameWithoutVersion) = 0; - - virtual void - reset() = 0; - - virtual size_t - getSize() = 0; - - bool - isEmpty() - { - return (getSize() == 0); - } -}; - -} // namespace security - -using security::CertificateCache; - -} // namespace ndn - -#endif // NDN_SECURITY_CERTIFICATE_CACHE_HPP diff --git a/src/security/certificate-container.cpp b/src/security/certificate-container.cpp deleted file mode 100644 index a05dd5272..000000000 --- a/src/security/certificate-container.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "certificate-container.hpp" -#include "pib-impl.hpp" - -namespace ndn { -namespace security { - -CertificateContainer::const_iterator::const_iterator(std::set::const_iterator it, - shared_ptr impl) - : m_it(it) - , m_impl(impl) -{ -} - -v1::IdentityCertificate -CertificateContainer::const_iterator::operator*() -{ - return m_impl->getCertificate(*m_it); -} - -CertificateContainer::const_iterator& -CertificateContainer::const_iterator::operator++() -{ - ++m_it; - return *this; -} - -CertificateContainer::const_iterator -CertificateContainer::const_iterator::operator++(int) -{ - const_iterator it(m_it, m_impl); - ++m_it; - return it; -} - -bool -CertificateContainer::const_iterator::operator==(const const_iterator& other) -{ - return (m_impl == other.m_impl && m_it == other.m_it); -} - -bool -CertificateContainer::const_iterator::operator!=(const const_iterator& other) -{ - return !(*this == other); -} - -CertificateContainer::CertificateContainer() -{ -} - -CertificateContainer::CertificateContainer(std::set&& certNames, - shared_ptr impl) - : m_certNames(certNames) - , m_impl(impl) -{ -} - -CertificateContainer::const_iterator -CertificateContainer::begin() const -{ - return const_iterator(m_certNames.begin(), m_impl); -} - -CertificateContainer::const_iterator -CertificateContainer::end() const -{ - return const_iterator(m_certNames.end(), m_impl); -} - -CertificateContainer::const_iterator -CertificateContainer::find(const Name& certName) const -{ - return const_iterator(m_certNames.find(certName), m_impl); -} - -size_t -CertificateContainer::size() const -{ - return m_certNames.size(); -} - -} // namespace security -} // namespace ndn diff --git a/src/security/certificate-container.hpp b/src/security/certificate-container.hpp deleted file mode 100644 index f0cc4081c..000000000 --- a/src/security/certificate-container.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_CERTIFICATE_CONTAINER_HPP -#define NDN_SECURITY_CERTIFICATE_CONTAINER_HPP - -#include -#include "v1/identity-certificate.hpp" - -namespace ndn { -namespace security { - -class PibImpl; - -/// @brief A handler to search or enumerate certificates of a key. -class CertificateContainer -{ -public: - class const_iterator - { - public: - friend class CertificateContainer; - - public: - v1::IdentityCertificate - operator*(); - - const_iterator& - operator++(); - - const_iterator - operator++(int); - - bool - operator==(const const_iterator& other); - - bool - operator!=(const const_iterator& other); - - private: - const_iterator(std::set::const_iterator it, shared_ptr impl); - - private: - std::set::const_iterator m_it; - shared_ptr m_impl; - }; - - typedef const_iterator iterator; - -public: - CertificateContainer(); - - CertificateContainer(std::set&& certNames, shared_ptr impl); - - const_iterator - begin() const; - - const_iterator - end() const; - - const_iterator - find(const Name& certName) const; - - size_t - size() const; - -private: - std::set m_certNames; - shared_ptr m_impl; -}; - -} // namespace security -} // namespace ndn - -#endif // NDN_SECURITY_CERTIFICATE_CONTAINER_HPP diff --git a/src/security/command-interest-validator.cpp b/src/security/command-interest-validator.cpp deleted file mode 100644 index f877f4170..000000000 --- a/src/security/command-interest-validator.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "command-interest-validator.hpp" -#include "v1/identity-certificate.hpp" -#include - -namespace ndn { -namespace security { - -std::ostream& -operator<<(std::ostream& os, CommandInterestValidator::ErrorCode error) -{ - switch (error) { - case CommandInterestValidator::ErrorCode::NONE: - return os << "OK"; - case CommandInterestValidator::ErrorCode::NAME_TOO_SHORT: - return os << "command Interest name is too short"; - case CommandInterestValidator::ErrorCode::BAD_TIMESTAMP: - return os << "cannot parse timestamp"; - case CommandInterestValidator::ErrorCode::BAD_SIG_INFO: - return os << "cannot parse SignatureInfo"; - case CommandInterestValidator::ErrorCode::MISSING_KEY_LOCATOR: - return os << "KeyLocator is missing"; - case CommandInterestValidator::ErrorCode::BAD_KEY_LOCATOR_TYPE: - return os << "KeyLocator type is not Name"; - case CommandInterestValidator::ErrorCode::BAD_CERT_NAME: - return os << "cannot parse certificate name"; - case CommandInterestValidator::ErrorCode::TIMESTAMP_OUT_OF_GRACE: - return os << "timestamp is out of grace period"; - case CommandInterestValidator::ErrorCode::TIMESTAMP_REORDER: - return os << "timestamp is less than or equal to last timestamp"; - } - return os; -} - -static void -invokeReject(const OnInterestValidationFailed& reject, const Interest& interest, - CommandInterestValidator::ErrorCode error) -{ - reject(interest.shared_from_this(), boost::lexical_cast(error)); -} - -CommandInterestValidator::CommandInterestValidator(unique_ptr inner, - const Options& options) - : m_inner(std::move(inner)) - , m_options(options) - , m_index(m_container.get<0>()) - , m_queue(m_container.get<1>()) -{ - if (m_inner == nullptr) { - BOOST_THROW_EXCEPTION(std::invalid_argument("inner validator is nullptr")); - } - - m_options.gracePeriod = std::max(m_options.gracePeriod, time::nanoseconds::zero()); -} - -void -CommandInterestValidator::checkPolicy(const Interest& interest, int nSteps, - const OnInterestValidated& accept, - const OnInterestValidationFailed& reject, - std::vector>& nextSteps) -{ - BOOST_ASSERT(nSteps == 0); - this->cleanup(); - - Name keyName; - uint64_t timestamp; - ErrorCode res = this->parseCommandInterest(interest, keyName, timestamp); - if (res != ErrorCode::NONE) { - return invokeReject(reject, interest, res); - } - - time::system_clock::TimePoint receiveTime = time::system_clock::now(); - - m_inner->validate(interest, - [=] (const shared_ptr& interest) { - ErrorCode res = this->checkTimestamp(keyName, timestamp, receiveTime); - if (res != ErrorCode::NONE) { - return invokeReject(reject, *interest, res); - } - accept(interest); - }, reject); -} - -void -CommandInterestValidator::cleanup() -{ - time::steady_clock::TimePoint expiring = time::steady_clock::now() - m_options.timestampTtl; - - while ((!m_queue.empty() && m_queue.front().lastRefreshed <= expiring) || - (m_options.maxTimestamps >= 0 && - m_queue.size() > static_cast(m_options.maxTimestamps))) { - m_queue.pop_front(); - } -} - -CommandInterestValidator::ErrorCode -CommandInterestValidator::parseCommandInterest(const Interest& interest, Name& keyName, - uint64_t& timestamp) const -{ - const Name& name = interest.getName(); - if (name.size() < signed_interest::MIN_LENGTH) { - return ErrorCode::NAME_TOO_SHORT; - } - - const name::Component& timestampComp = name[signed_interest::POS_TIMESTAMP]; - if (!timestampComp.isNumber()) { - return ErrorCode::BAD_TIMESTAMP; - } - timestamp = timestampComp.toNumber(); - - SignatureInfo sig; - try { - sig.wireDecode(name[signed_interest::POS_SIG_INFO].blockFromValue()); - } - catch (const tlv::Error&) { - return ErrorCode::BAD_SIG_INFO; - } - - if (!sig.hasKeyLocator()) { - return ErrorCode::MISSING_KEY_LOCATOR; - } - - const KeyLocator& keyLocator = sig.getKeyLocator(); - if (keyLocator.getType() != KeyLocator::KeyLocator_Name) { - return ErrorCode::BAD_KEY_LOCATOR_TYPE; - } - - try { - keyName = v1::IdentityCertificate::certificateNameToPublicKeyName(keyLocator.getName()); - } - catch (const v1::IdentityCertificate::Error&) { - return ErrorCode::BAD_CERT_NAME; - } - - return ErrorCode::NONE; -} - -CommandInterestValidator::ErrorCode -CommandInterestValidator::checkTimestamp(const Name& keyName, uint64_t timestamp, - time::system_clock::TimePoint receiveTime) -{ - time::steady_clock::TimePoint now = time::steady_clock::now(); - - // try to insert new record - Queue::iterator i = m_queue.end(); - bool isNew = false; - std::tie(i, isNew) = m_queue.push_back({keyName, timestamp, now}); - - if (isNew) { - // check grace period - time::system_clock::TimePoint sigTime = time::fromUnixTimestamp(time::milliseconds(timestamp)); - if (time::abs(sigTime - receiveTime) > m_options.gracePeriod) { - // out of grace period, delete new record - m_queue.erase(i); - return ErrorCode::TIMESTAMP_OUT_OF_GRACE; - } - } - else { - BOOST_ASSERT(i->keyName == keyName); - - // compare timestamp with last timestamp - if (timestamp <= i->timestamp) { - return ErrorCode::TIMESTAMP_REORDER; - } - - // set lastRefreshed field, and move to queue tail - m_queue.erase(i); - isNew = m_queue.push_back({keyName, timestamp, now}).second; - BOOST_ASSERT(isNew); - } - - return ErrorCode::NONE; -} - -void -CommandInterestValidator::checkPolicy(const Data& data, int nSteps, - const OnDataValidated& accept, - const OnDataValidationFailed& reject, - std::vector>& nextSteps) -{ - BOOST_ASSERT(nSteps == 0); - m_inner->validate(data, accept, reject); -} - -} // namespace security -} // namespace ndn diff --git a/src/security/command-interest-validator.hpp b/src/security/command-interest-validator.hpp deleted file mode 100644 index e789f09e3..000000000 --- a/src/security/command-interest-validator.hpp +++ /dev/null @@ -1,194 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_COMMAND_INTEREST_VALIDATOR_HPP -#define NDN_SECURITY_COMMAND_INTEREST_VALIDATOR_HPP - -#include "validator.hpp" -#include -#include -#include -#include - -namespace ndn { -namespace security { - -/** \brief a validator for stop-and-wait command Interests - * \sa https://redmine.named-data.net/projects/ndn-cxx/wiki/CommandInterest - * - * This validator checks timestamp field of a stop-and-wait command Interest. - * Signed Interest validation and Data validation requests are delegated to an inner validator. - */ -class CommandInterestValidator : public Validator -{ -public: - class Options - { - public: - Options() - { - } - - public: - /** \brief tolerance of initial timestamp - * - * A stop-and-wait command Interest is considered "initial" if the validator - * has not recorded the last timestamp from the same public key, or when - * such knowledge has been erased. - * For an initial command Interest, its timestamp is compared to the current - * system clock, and the command Interest is rejected if the absolute difference - * is greater than the grace interval. - * - * This should be positive. - * Setting this option to 0 or negative causes the validator to require exactly same - * timestamp as the system clock, which most likely rejects all command Interests. - */ - time::nanoseconds gracePeriod = time::seconds(120); - - /** \brief max number of distinct public keys to record last timestamp - * - * The validator records last timestamps for every public key. - * For a subsequent command Interest using the same public key, - * its timestamp is compared to the last timestamp from that public key, - * and the command Interest is rejected if its timestamp is - * less than or equal to the recorded timestamp. - * - * This option limits the number of distinct public keys being tracked. - * If the limit is exceeded, the oldest record is deleted. - * - * Setting this option to -1 allows tracking unlimited public keys. - * Setting this option to 0 disables last timestamp records and causes - * every command Interest to be processed as initial. - */ - ssize_t maxTimestamps = 1000; - - /** \brief max lifetime of a last timestamp record - * - * A last timestamp record expires and can be deleted if it has not been refreshed - * within this duration. - * Setting this option to 0 or negative makes last timestamp records expire immediately - * and causes every command Interest to be processed as initial. - */ - time::nanoseconds timestampTtl = time::hours(1); - - }; - - /** \brief error codes - * \todo #1872 assign numeric codes to these errors - */ - enum class ErrorCode { - NONE = 0, - NAME_TOO_SHORT, - BAD_TIMESTAMP, - BAD_SIG_INFO, - MISSING_KEY_LOCATOR, - BAD_KEY_LOCATOR_TYPE, - BAD_CERT_NAME, - TIMESTAMP_OUT_OF_GRACE, - TIMESTAMP_REORDER - }; - - /** \brief constructor - * \param inner a Validator for signed Interest signature validation and Data validation; - * this must not be nullptr - * \param options stop-and-wait command Interest validation options - * \throw std::invalid inner is nullptr - */ - explicit - CommandInterestValidator(unique_ptr inner, - const Options& options = Options()); - -protected: - /** \brief validate command Interest - * - * This function executes the following validation procedure: - * - * 1. parse the Interest as a command Interest, and extract the public key name - * 2. invoke inner validation to verify the signed Interest - * 3. classify the command Interest as either initial or subsequent, - * and check the timestamp accordingly - * 4. record the timestamp as last timestamp of the public key name - * - * The validation request is rejected if any step in this procedure fails. - */ - virtual void - checkPolicy(const Interest& interest, int nSteps, - const OnInterestValidated& accept, - const OnInterestValidationFailed& reject, - std::vector>& nextSteps) override; - - /** \brief validate Data - * - * The validation request is redirected to the inner validator. - */ - virtual void - checkPolicy(const Data& data, int nSteps, - const OnDataValidated& accept, - const OnDataValidationFailed& reject, - std::vector>& nextSteps) override; - -private: - void - cleanup(); - - ErrorCode - parseCommandInterest(const Interest& interest, Name& keyName, uint64_t& timestamp) const; - - ErrorCode - checkTimestamp(const Name& keyName, uint64_t timestamp, - time::system_clock::TimePoint receiveTime); - -private: - unique_ptr m_inner; - Options m_options; - - struct LastTimestampRecord - { - Name keyName; - uint64_t timestamp; - time::steady_clock::TimePoint lastRefreshed; - }; - - typedef boost::multi_index_container< - LastTimestampRecord, - boost::multi_index::indexed_by< - boost::multi_index::ordered_unique< - boost::multi_index::member - >, - boost::multi_index::sequenced<> - > - > Container; - typedef Container::nth_index<0>::type Index; - typedef Container::nth_index<1>::type Queue; - - Container m_container; - Index& m_index; - Queue& m_queue; -}; - -std::ostream& -operator<<(std::ostream& os, CommandInterestValidator::ErrorCode error); - -} // namespace security -} // namespace ndn - - -#endif // NDN_SECURITY_COMMAND_INTEREST_VALIDATOR_HPP diff --git a/src/security/conf/checker.hpp b/src/security/conf/checker.hpp deleted file mode 100644 index c4ec3cafb..000000000 --- a/src/security/conf/checker.hpp +++ /dev/null @@ -1,489 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_SECURITY_CONF_CHECKER_HPP -#define NDN_SECURITY_CONF_CHECKER_HPP - -#include "common.hpp" - -#include "key-locator-checker.hpp" -#include "../../util/io.hpp" -#include "../validator.hpp" -#include "../v1/identity-certificate.hpp" - -#include -#include -#include - -namespace ndn { -namespace security { -namespace conf { - -class Checker -{ -public: - typedef function&)> OnInterestChecked; - typedef function&, - const std::string&)> OnInterestCheckFailed; - typedef function&)> OnDataChecked; - typedef function&, const std::string&)> OnDataCheckFailed; - - enum { - INTEREST_SIG_VALUE = -1, - INTEREST_SIG_INFO = -2 - }; - - - virtual - ~Checker() - { - } - - /** - * @brief check if data satisfies condition defined in the specific checker implementation - * - * @param data Data packet - * @retval -1 if data is immediately invalid - * @retval 1 if data is immediately valid - * @retval 0 if further signature verification is needed. - */ - virtual int8_t - check(const Data& data) = 0; - - /** - * @brief check if interest satisfies condition defined in the specific checker implementation - * - * @param interest Interest packet - * @retval -1 if interest is immediately invalid - * @retval 1 if interest is immediately valid - * @retval 0 if further signature verification is needed. - */ - virtual int8_t - check(const Interest& interest) = 0; -}; - -class CustomizedChecker : public Checker -{ -public: - CustomizedChecker(uint32_t sigType, - shared_ptr keyLocatorChecker) - : m_sigType(sigType) - , m_keyLocatorChecker(keyLocatorChecker) - { - switch (sigType) { - case tlv::SignatureSha256WithRsa: - case tlv::SignatureSha256WithEcdsa: { - if (!static_cast(m_keyLocatorChecker)) - BOOST_THROW_EXCEPTION(Error("Strong signature requires KeyLocatorChecker")); - return; - } - case tlv::DigestSha256: - return; - default: - BOOST_THROW_EXCEPTION(Error("Unsupported signature type")); - } - } - - virtual int8_t - check(const Data& data) override - { - return check(data, data.getSignature()); - } - - virtual int8_t - check(const Interest& interest) override - { - try { - const Name& interestName = interest.getName(); - Signature signature(interestName[Checker::INTEREST_SIG_INFO].blockFromValue(), - interestName[Checker::INTEREST_SIG_VALUE].blockFromValue()); - return check(interest, signature); - } - catch (const Signature::Error& e) { - // Invalid signature - return -1; - } - catch (const tlv::Error& e) { - // Cannot decode signature related TLVs - return -1; - } - } - -private: - template - int8_t - check(const Packet& packet, const Signature& signature) - { - if (m_sigType != signature.getType()) { - // Signature type does not match - return -1; - } - - if (signature.getType() == tlv::DigestSha256) - return 0; - - try { - switch (signature.getType()) { - case tlv::SignatureSha256WithRsa: - case tlv::SignatureSha256WithEcdsa: { - if (!signature.hasKeyLocator()) { - // Missing KeyLocator in SignatureInfo - return -1; - } - break; - } - default: { - // Unsupported signature type - return -1; - } - } - } - catch (const KeyLocator::Error& e) { - // Cannot decode KeyLocator - return -1; - } - catch (const tlv::Error& e) { - // Cannot decode signature - return -1; - } - - std::string failInfo; - if (m_keyLocatorChecker->check(packet, signature.getKeyLocator(), failInfo)) - return 0; - else { - return -1; - } - } - -private: - uint32_t m_sigType; - shared_ptr m_keyLocatorChecker; -}; - -class HierarchicalChecker : public CustomizedChecker -{ -public: - explicit - HierarchicalChecker(uint32_t sigType) - : CustomizedChecker(sigType, - make_shared("^(<>*)$", "\\1", - "^([^]*)(<>*)$", - "\\1\\2", - KeyLocatorChecker::RELATION_IS_PREFIX_OF)) - { - } -}; - -class FixedSignerChecker : public Checker -{ -public: - FixedSignerChecker(uint32_t sigType, - const std::vector>& signers) - : m_sigType(sigType) - { - for (std::vector>::const_iterator it = signers.begin(); - it != signers.end(); it++) - m_signers[(*it)->getName().getPrefix(-1)] = (*it); - - if (sigType != tlv::SignatureSha256WithRsa && - sigType != tlv::SignatureSha256WithEcdsa) { - BOOST_THROW_EXCEPTION(Error("FixedSigner is only meaningful for strong signature type")); - } - } - - virtual int8_t - check(const Data& data) override - { - return check(data, data.getSignature()); - } - - virtual int8_t - check(const Interest& interest) override - { - try { - const Name& interestName = interest.getName(); - Signature signature(interestName[Checker::INTEREST_SIG_INFO].blockFromValue(), - interestName[Checker::INTEREST_SIG_VALUE].blockFromValue()); - return check(interest, signature); - } - catch (const Signature::Error& e) { - // Invalid signature - return -1; - } - catch (const tlv::Error& e) { - // Cannot decode signature related TLVs - return -1; - } - } - -private: - template - int8_t - check(const Packet& packet, const Signature& signature) - { - if (m_sigType != signature.getType()) { - // Signature type does not match - return -1; - } - - if (signature.getType() == tlv::DigestSha256) { - // FixedSigner does not allow Sha256 signature type - return -1; - } - - try { - switch (signature.getType()) { - case tlv::SignatureSha256WithRsa: - case tlv::SignatureSha256WithEcdsa: { - if (!signature.hasKeyLocator()) { - // Missing KeyLocator in SignatureInfo - return -1; - } - break; - } - - default: { - // Unsupported signature type - return -1; - } - } - - const Name& keyLocatorName = signature.getKeyLocator().getName(); - - if (m_signers.find(keyLocatorName) == m_signers.end()) { - // Signer is not in the fixed signer list - return -1; - } - - if (Validator::verifySignature(packet, signature, - m_signers[keyLocatorName]->getPublicKeyInfo())) { - return 1; - } - else { - // Signature cannot be validated - return -1; - } - } - catch (const KeyLocator::Error& e) { - // KeyLocator does not have name - return -1; - } - catch (const tlv::Error& e) { - // Cannot decode signature - return -1; - } - } - -private: - typedef std::map> SignerList; - uint32_t m_sigType; - SignerList m_signers; -}; - -class CheckerFactory -{ -public: - /** - * @brief create a checker from configuration file. - * - * @param configSection The section containing the definition of checker. - * @param configFilename The configuration file name. - * @return a shared pointer to the created checker. - */ - static shared_ptr - create(const ConfigSection& configSection, const std::string& configFilename) - { - ConfigSection::const_iterator propertyIt = configSection.begin(); - - // Get checker.type - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) - BOOST_THROW_EXCEPTION(Error("Expect ")); - - std::string type = propertyIt->second.data(); - - if (boost::iequals(type, "customized")) - return createCustomizedChecker(configSection, configFilename); - else if (boost::iequals(type, "hierarchical")) - return createHierarchicalChecker(configSection, configFilename); - else if (boost::iequals(type, "fixed-signer")) - return createFixedSignerChecker(configSection, configFilename); - else - BOOST_THROW_EXCEPTION(Error("Unsupported checker type: " + type)); - } - -private: - static shared_ptr - createCustomizedChecker(const ConfigSection& configSection, - const std::string& configFilename) - { - ConfigSection::const_iterator propertyIt = configSection.begin(); - propertyIt++; - - // Get checker.sig-type - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "sig-type")) - BOOST_THROW_EXCEPTION(Error("Expect ")); - - std::string sigType = propertyIt->second.data(); - propertyIt++; - - // Get checker.key-locator - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "key-locator")) - BOOST_THROW_EXCEPTION(Error("Expect ")); - - shared_ptr keyLocatorChecker = - KeyLocatorCheckerFactory::create(propertyIt->second, configFilename); - propertyIt++; - - if (propertyIt != configSection.end()) - BOOST_THROW_EXCEPTION(Error("Expect the end of checker")); - - return make_shared(getSigType(sigType), keyLocatorChecker); - } - - static shared_ptr - createHierarchicalChecker(const ConfigSection& configSection, - const std::string& configFilename) - { - ConfigSection::const_iterator propertyIt = configSection.begin(); - propertyIt++; - - // Get checker.sig-type - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "sig-type")) - BOOST_THROW_EXCEPTION(Error("Expect ")); - - std::string sigType = propertyIt->second.data(); - propertyIt++; - - if (propertyIt != configSection.end()) - BOOST_THROW_EXCEPTION(Error("Expect the end of checker")); - - return make_shared(getSigType(sigType)); - } - - static shared_ptr - createFixedSignerChecker(const ConfigSection& configSection, - const std::string& configFilename) - { - ConfigSection::const_iterator propertyIt = configSection.begin(); - propertyIt++; - - // Get checker.sig-type - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "sig-type")) - BOOST_THROW_EXCEPTION(Error("Expect ")); - - std::string sigType = propertyIt->second.data(); - propertyIt++; - - std::vector> signers; - for (; propertyIt != configSection.end(); propertyIt++) { - if (!boost::iequals(propertyIt->first, "signer")) - BOOST_THROW_EXCEPTION(Error("Expect but get first + ">")); - - signers.push_back(getSigner(propertyIt->second, configFilename)); - } - - if (propertyIt != configSection.end()) - BOOST_THROW_EXCEPTION(Error("Expect the end of checker")); - - return shared_ptr(new FixedSignerChecker(getSigType(sigType), - signers)); - } - - static shared_ptr - getSigner(const ConfigSection& configSection, const std::string& configFilename) - { - using namespace boost::filesystem; - - ConfigSection::const_iterator propertyIt = configSection.begin(); - - // Get checker.signer.type - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) - BOOST_THROW_EXCEPTION(Error("Expect ")); - - std::string type = propertyIt->second.data(); - propertyIt++; - - if (boost::iequals(type, "file")) { - // Get checker.signer.file-name - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "file-name")) - BOOST_THROW_EXCEPTION(Error("Expect ")); - - path certfilePath = absolute(propertyIt->second.data(), - path(configFilename).parent_path()); - propertyIt++; - - if (propertyIt != configSection.end()) - BOOST_THROW_EXCEPTION(Error("Expect the end of checker.signer")); - - shared_ptr idCert - = io::load(certfilePath.c_str()); - - if (static_cast(idCert)) - return idCert; - else - BOOST_THROW_EXCEPTION(Error("Cannot read certificate from file: " + - certfilePath.native())); - } - else if (boost::iequals(type, "base64")) { - // Get checker.signer.base64-string - if (propertyIt == configSection.end() || - !boost::iequals(propertyIt->first, "base64-string")) - BOOST_THROW_EXCEPTION(Error("Expect ")); - - std::stringstream ss(propertyIt->second.data()); - propertyIt++; - - if (propertyIt != configSection.end()) - BOOST_THROW_EXCEPTION(Error("Expect the end of checker.signer")); - - shared_ptr idCert = io::load(ss); - - if (static_cast(idCert)) - return idCert; - else - BOOST_THROW_EXCEPTION(Error("Cannot decode certificate from string")); - } - else - BOOST_THROW_EXCEPTION(Error("Unsupported checker.signer type: " + type)); - } - - static uint32_t - getSigType(const std::string& sigType) - { - if (boost::iequals(sigType, "rsa-sha256")) - return tlv::SignatureSha256WithRsa; - else if (boost::iequals(sigType, "ecdsa-sha256")) - return tlv::SignatureSha256WithEcdsa; - else if (boost::iequals(sigType, "sha256")) - return tlv::DigestSha256; - else - BOOST_THROW_EXCEPTION(Error("Unsupported signature type")); - } -}; - -} // namespace conf -} // namespace security -} // namespace ndn - -#endif // NDN_SECURITY_CONF_CHECKER_HPP diff --git a/src/security/conf/common.hpp b/src/security/conf/common.hpp deleted file mode 100644 index 3c79b7ba7..000000000 --- a/src/security/conf/common.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_SECURITY_CONF_COMMON_HPP -#define NDN_SECURITY_CONF_COMMON_HPP - -#include "../../common.hpp" -#include -#include - -namespace ndn { -namespace security { -namespace conf { - -typedef boost::property_tree::ptree ConfigSection; - -class Error : public std::runtime_error -{ -public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } -}; - -} // namespace conf -} // namespace security -} // namespace ndn - -#endif // NDN_SECURITY_CONF_COMMON_HPP diff --git a/src/security/conf/filter.hpp b/src/security/conf/filter.hpp deleted file mode 100644 index d191b1bb8..000000000 --- a/src/security/conf/filter.hpp +++ /dev/null @@ -1,238 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_SECURITY_CONF_FILTER_HPP -#define NDN_SECURITY_CONF_FILTER_HPP - -#include "../../common.hpp" -#include "../../data.hpp" -#include "../../interest.hpp" -#include "../../util/regex.hpp" -#include "../security-common.hpp" -#include - -#include "common.hpp" - -namespace ndn { -namespace security { -namespace conf { - -/** - * @brief Filter is one of the classes used by ValidatorConfig. - * - * The ValidatorConfig class consists of a set of rules. - * The Filter class is a part of a rule and is used to match packet. - * Matched packets will be checked against the checkers defined in the rule. - */ - -class Filter -{ -public: - - virtual - ~Filter() - { - } - - bool - match(const Data& data) - { - return matchName(data.getName()); - } - - bool - match(const Interest& interest) - { - if (interest.getName().size() < signed_interest::MIN_LENGTH) - return false; - - Name unsignedName = interest.getName().getPrefix(-signed_interest::MIN_LENGTH); - return matchName(unsignedName); - } - -protected: - virtual bool - matchName(const Name& name) = 0; -}; - -class RelationNameFilter : public Filter -{ -public: - enum Relation - { - RELATION_EQUAL, - RELATION_IS_PREFIX_OF, - RELATION_IS_STRICT_PREFIX_OF - }; - - RelationNameFilter(const Name& name, Relation relation) - : m_name(name) - , m_relation(relation) - { - } - - virtual - ~RelationNameFilter() - { - } - -protected: - virtual bool - matchName(const Name& name) - { - switch (m_relation) - { - case RELATION_EQUAL: - return (name == m_name); - case RELATION_IS_PREFIX_OF: - return m_name.isPrefixOf(name); - case RELATION_IS_STRICT_PREFIX_OF: - return (m_name.isPrefixOf(name) && m_name.size() < name.size()); - default: - return false; - } - } - -private: - Name m_name; - Relation m_relation; -}; - -class RegexNameFilter : public Filter -{ -public: - explicit - RegexNameFilter(const Regex& regex) - : m_regex(regex) - { - } - - virtual - ~RegexNameFilter() - { - } - -protected: - virtual bool - matchName(const Name& name) - { - return m_regex.match(name); - } - -private: - Regex m_regex; -}; - -class FilterFactory -{ -public: - static shared_ptr - create(const ConfigSection& configSection) - { - ConfigSection::const_iterator propertyIt = configSection.begin(); - - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) - BOOST_THROW_EXCEPTION(Error("Expect !")); - - std::string type = propertyIt->second.data(); - - if (boost::iequals(type, "name")) - return createNameFilter(configSection); - else - BOOST_THROW_EXCEPTION(Error("Unsupported filter.type: " + type)); - } -private: - static shared_ptr - createNameFilter(const ConfigSection& configSection) - { - ConfigSection::const_iterator propertyIt = configSection.begin(); - propertyIt++; - - if (propertyIt == configSection.end()) - BOOST_THROW_EXCEPTION(Error("Expect more properties for filter(name)")); - - if (boost::iequals(propertyIt->first, "name")) - { - // Get filter.name - Name name; - try - { - name = Name(propertyIt->second.data()); - } - catch (Name::Error& e) - { - BOOST_THROW_EXCEPTION(Error("Wrong filter.name: " + propertyIt->second.data())); - } - - propertyIt++; - - // Get filter.relation - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation")) - BOOST_THROW_EXCEPTION(Error("Expect !")); - - std::string relationString = propertyIt->second.data(); - propertyIt++; - - RelationNameFilter::Relation relation; - if (boost::iequals(relationString, "equal")) - relation = RelationNameFilter::RELATION_EQUAL; - else if (boost::iequals(relationString, "is-prefix-of")) - relation = RelationNameFilter::RELATION_IS_PREFIX_OF; - else if (boost::iequals(relationString, "is-strict-prefix-of")) - relation = RelationNameFilter::RELATION_IS_STRICT_PREFIX_OF; - else - BOOST_THROW_EXCEPTION(Error("Unsupported relation: " + relationString)); - - - if (propertyIt != configSection.end()) - BOOST_THROW_EXCEPTION(Error("Expect the end of filter!")); - - return make_shared(name, relation); - } - else if (boost::iequals(propertyIt->first, "regex")) - { - std::string regexString = propertyIt->second.data(); - propertyIt++; - - if (propertyIt != configSection.end()) - BOOST_THROW_EXCEPTION(Error("Expect the end of filter!")); - - try - { - return shared_ptr(new RegexNameFilter(regexString)); - } - catch (Regex::Error& e) - { - BOOST_THROW_EXCEPTION(Error("Wrong filter.regex: " + regexString)); - } - } - else - BOOST_THROW_EXCEPTION(Error("Wrong filter(name) properties")); - } -}; - -} // namespace conf -} // namespace security -} // namespace ndn - -#endif // NDN_SECURITY_CONF_FILTER_HPP diff --git a/src/security/conf/key-locator-checker.hpp b/src/security/conf/key-locator-checker.hpp deleted file mode 100644 index 7a9ff0b77..000000000 --- a/src/security/conf/key-locator-checker.hpp +++ /dev/null @@ -1,389 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_SECURITY_CONF_KEY_LOCATOR_CHECKER_HPP -#define NDN_SECURITY_CONF_KEY_LOCATOR_CHECKER_HPP - -#include "../../common.hpp" -#include "../../data.hpp" -#include "../../interest.hpp" -#include "../../util/regex.hpp" -#include "../security-common.hpp" -#include - -#include "common.hpp" - -namespace ndn { -namespace security { -namespace conf { - -class KeyLocatorCheckerFactory; - -/** - * @brief KeyLocatorChecker is one of the classes used by ValidatorConfig. - * - * The ValidatorConfig class consists of a set of rules. - * The KeyLocatorChecker class is part of a rule and is used to check if the KeyLocator field of a - * packet satisfy the requirements. - */ - - -class KeyLocatorChecker -{ -public: - enum Relation { - RELATION_EQUAL, - RELATION_IS_PREFIX_OF, - RELATION_IS_STRICT_PREFIX_OF - }; - - virtual - ~KeyLocatorChecker() - { - } - - bool - check(const Data& data, - const KeyLocator& keyLocator, - std::string& failInfo) - { - return check(data.getName(), keyLocator, failInfo); - } - - bool - check(const Interest& interest, - const KeyLocator& keyLocator, - std::string& failInfo) - { - if (interest.getName().size() < signed_interest::MIN_LENGTH) - { - failInfo = "No Signature"; - return false; - } - - Name signedName = interest.getName().getPrefix(-signed_interest::MIN_LENGTH); - return check(signedName, keyLocator, failInfo); - } - -protected: - - virtual bool - check(const Name& packetName, - const KeyLocator& keyLocator, - std::string& failInfo) = 0; - - bool - checkRelation(const Relation& relation, const Name& name1, const Name& name2) - { - switch (relation) - { - case RELATION_EQUAL: - return (name1 == name2); - case RELATION_IS_PREFIX_OF: - return name1.isPrefixOf(name2); - case RELATION_IS_STRICT_PREFIX_OF: - return (name1.isPrefixOf(name2) && name1 != name2); - default: - return false; - } - } -}; - -class RelationKeyLocatorNameChecker : public KeyLocatorChecker -{ -public: - RelationKeyLocatorNameChecker(const Name& name, - const KeyLocatorChecker::Relation& relation) - : m_name(name) - , m_relation(relation) - { - } - -protected: - virtual bool - check(const Name& packetName, - const KeyLocator& keyLocator, - std::string& failInfo) - { - try - { - if (checkRelation(m_relation, m_name, keyLocator.getName())) - return true; - - failInfo = "KeyLocatorChecker failed!"; - return false; - } - catch (KeyLocator::Error& e) - { - failInfo = "KeyLocator does not have name"; - return false; - } - } - -private: - Name m_name; - KeyLocatorChecker::Relation m_relation; -}; - -class RegexKeyLocatorNameChecker : public KeyLocatorChecker -{ -public: - explicit - RegexKeyLocatorNameChecker(const Regex& regex) - : m_regex(regex) - { - } - -protected: - virtual bool - check(const Name& packetName, - const KeyLocator& keyLocator, - std::string& failInfo) - { - try - { - if (m_regex.match(keyLocator.getName())) - return true; - - failInfo = "KeyLocatorChecker failed!"; - return false; - } - catch (KeyLocator::Error& e) - { - failInfo = "KeyLocator does not have name"; - return false; - } - } - -private: - Regex m_regex; -}; - -class HyperKeyLocatorNameChecker : public KeyLocatorChecker -{ -public: - HyperKeyLocatorNameChecker(const std::string& pExpr, const std::string pExpand, - const std::string& kExpr, const std::string kExpand, - const Relation& hyperRelation) - : m_hyperPRegex(new Regex(pExpr, pExpand)) - , m_hyperKRegex(new Regex(kExpr, kExpand)) - , m_hyperRelation(hyperRelation) - { - } - -protected: - virtual bool - check(const Name& packetName, - const KeyLocator& keyLocator, - std::string& failInfo) - { - try - { - if (m_hyperPRegex->match(packetName) && - m_hyperKRegex->match(keyLocator.getName()) && - checkRelation(m_hyperRelation, - m_hyperKRegex->expand(), - m_hyperPRegex->expand())) - return true; - - failInfo = "KeyLocatorChecker failed!"; - return false; - } - catch (KeyLocator::Error& e) - { - failInfo = "KeyLocator does not have name"; - return false; - } - - } - -private: - shared_ptr m_hyperPRegex; - shared_ptr m_hyperKRegex; - Relation m_hyperRelation; -}; - - -class KeyLocatorCheckerFactory -{ -public: - static shared_ptr - create(const ConfigSection& configSection, const std::string& filename) - { - ConfigSection::const_iterator propertyIt = configSection.begin(); - - // Get checker.key-locator.type - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) - BOOST_THROW_EXCEPTION(Error("Expect !")); - - std::string type = propertyIt->second.data(); - - if (boost::iequals(type, "name")) - return createKeyLocatorNameChecker(configSection, filename); - else - BOOST_THROW_EXCEPTION(Error("Unsupported checker.key-locator.type: " + type)); - } - -private: - static shared_ptr - createKeyLocatorNameChecker(const ConfigSection& configSection, - const std::string& filename) - { - ConfigSection::const_iterator propertyIt = configSection.begin(); - propertyIt++; - - if (propertyIt == configSection.end()) - BOOST_THROW_EXCEPTION(Error("Expect more checker.key-locator properties")); - - if (boost::iequals(propertyIt->first, "name")) - { - Name name; - try - { - name = Name(propertyIt->second.data()); - } - catch (Name::Error& e) - { - BOOST_THROW_EXCEPTION(Error("Invalid checker.key-locator.name: " + - propertyIt->second.data())); - } - propertyIt++; - - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "relation")) - BOOST_THROW_EXCEPTION(Error("Expect !")); - - std::string relationString = propertyIt->second.data(); - propertyIt++; - - KeyLocatorChecker::Relation relation; - if (boost::iequals(relationString, "equal")) - relation = KeyLocatorChecker::RELATION_EQUAL; - else if (boost::iequals(relationString, "is-prefix-of")) - relation = KeyLocatorChecker::RELATION_IS_PREFIX_OF; - else if (boost::iequals(relationString, "is-strict-prefix-of")) - relation = KeyLocatorChecker::RELATION_IS_STRICT_PREFIX_OF; - else - BOOST_THROW_EXCEPTION(Error("Unsupported relation: " + relationString)); - - if (propertyIt != configSection.end()) - BOOST_THROW_EXCEPTION(Error("Expect the end of checker.key-locator!")); - - return shared_ptr - (new RelationKeyLocatorNameChecker(name, relation)); - } - else if (boost::iequals(propertyIt->first, "regex")) - { - std::string regexString = propertyIt->second.data(); - propertyIt++; - - if (propertyIt != configSection.end()) - BOOST_THROW_EXCEPTION(Error("Expect the end of checker.key-locator!")); - - try - { - return shared_ptr - (new RegexKeyLocatorNameChecker(regexString)); - } - catch (Regex::Error& e) - { - BOOST_THROW_EXCEPTION(Error("Invalid checker.key-locator.regex: " + regexString)); - } - } - else if (boost::iequals(propertyIt->first, "hyper-relation")) - { - const ConfigSection& hSection = propertyIt->second; - - ConfigSection::const_iterator hPropertyIt = hSection.begin(); - - // Get k-regex - if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-regex")) - BOOST_THROW_EXCEPTION(Error("Expect !")); - - std::string kRegex = hPropertyIt->second.data(); - hPropertyIt++; - - // Get k-expand - if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "k-expand")) - BOOST_THROW_EXCEPTION(Error("Expect !")); - - std::string kExpand = hPropertyIt->second.data(); - hPropertyIt++; - - // Get h-relation - if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "h-relation")) - BOOST_THROW_EXCEPTION(Error("Expect !")); - - std::string hRelation = hPropertyIt->second.data(); - hPropertyIt++; - - // Get p-regex - if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-regex")) - BOOST_THROW_EXCEPTION(Error("Expect !")); - - std::string pRegex = hPropertyIt->second.data(); - hPropertyIt++; - - // Get p-expand - if (hPropertyIt == hSection.end() || !boost::iequals(hPropertyIt->first, "p-expand")) - BOOST_THROW_EXCEPTION(Error("Expect !")); - - std::string pExpand = hPropertyIt->second.data(); - hPropertyIt++; - - if (hPropertyIt != hSection.end()) - BOOST_THROW_EXCEPTION(Error("Expect the end of checker.key-locator.hyper-relation!")); - - KeyLocatorChecker::Relation relation; - if (boost::iequals(hRelation, "equal")) - relation = KeyLocatorChecker::RELATION_EQUAL; - else if (boost::iequals(hRelation, "is-prefix-of")) - relation = KeyLocatorChecker::RELATION_IS_PREFIX_OF; - else if (boost::iequals(hRelation, "is-strict-prefix-of")) - relation = KeyLocatorChecker::RELATION_IS_STRICT_PREFIX_OF; - else - BOOST_THROW_EXCEPTION(Error("Unsupported checker.key-locator.hyper-relation.h-relation: " - + hRelation)); - - try - { - return shared_ptr - (new HyperKeyLocatorNameChecker(pRegex, pExpand, - kRegex, kExpand, - relation)); - } - catch (Regex::Error& e) - { - BOOST_THROW_EXCEPTION(Error("Invalid regex for key-locator.hyper-relation")); - } - } - else - BOOST_THROW_EXCEPTION(Error("Unsupported checker.key-locator")); - } -}; - - -} // namespace conf -} // namespace security -} // namespace ndn - -#endif // NDN_SECURITY_CONF_KEY_LOCATOR_CHECKER_HPP diff --git a/src/security/conf/rule.hpp b/src/security/conf/rule.hpp deleted file mode 100644 index 03af661f4..000000000 --- a/src/security/conf/rule.hpp +++ /dev/null @@ -1,133 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - * @author Zhiyi Zhang - */ - -#ifndef NDN_SECURITY_CONF_RULE_HPP -#define NDN_SECURITY_CONF_RULE_HPP - -#include "filter.hpp" -#include "checker.hpp" - - -namespace ndn { -namespace security { -namespace conf { - -template -class Rule -{ -public: - explicit - Rule(const std::string& id) - : m_id(id) - { - } - - virtual - ~Rule() - { - } - - const std::string& - getId() - { - return m_id; - } - - void - addFilter(const shared_ptr& filter) - { - m_filters.push_back(filter); - } - - void - addChecker(const shared_ptr& checker) - { - m_checkers.push_back(checker); - } - - bool - match(const Packet& packet) - { - if (m_filters.empty()) - return true; - - for (FilterList::iterator it = m_filters.begin(); - it != m_filters.end(); it++) - { - if (!(*it)->match(packet)) - return false; - } - - return true; - } - - /** - * @brief check if packet satisfies certain condition - * - * @param packet The packet - * @param onValidated Callback function which is called when packet is immediately valid - * @param onValidationFailed Call function which is called when packet is immediately invalid - * @return -1 if packet is immediately invalid (onValidationFailed has been called) - * 1 if packet is immediately valid (onValidated has been called) - * 0 if further signature verification is needed. - */ - template - int8_t - check(const Packet& packet, - const ValidatedCallback& onValidated, - const ValidationFailureCallback& onValidationFailed) - { - bool hasPendingResult = false; - for (CheckerList::iterator it = m_checkers.begin(); it != m_checkers.end(); it++) { - int8_t result = (*it)->check(packet); - if (result > 0) { - onValidated(packet.shared_from_this()); - return result; - } - else if (result == 0) - hasPendingResult = true; - } - if (hasPendingResult) { - return 0; - } - else { - onValidationFailed(packet.shared_from_this(), "Packet cannot pass any checkers."); - return -1; - } - } - -NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: - typedef std::vector> FilterList; - typedef std::vector> CheckerList; - - std::string m_id; - FilterList m_filters; - CheckerList m_checkers; -}; - -} // namespace conf -} // namespace security -} // namespace ndn - -#endif // NDN_SECURITY_CONF_RULE_HPP diff --git a/src/security/cryptopp.hpp b/src/security/cryptopp.hpp deleted file mode 100644 index 4c9e95953..000000000 --- a/src/security/cryptopp.hpp +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** - * @file security/cryptopp.hpp - * @deprecated Use security/v1/cryptopp.hpp - */ - -#include "security-common.hpp" - -#ifdef NDN_CXX_KEEP_SECURITY_V1_ALIASES -#include "v1/cryptopp.hpp" -#else -#error "Deprecated. Use v1/cryptopp.hpp instead." -#endif // NDN_CXX_KEEP_SECURITY_V1_ALIASES diff --git a/src/security/detail/openssl-helper.cpp b/src/security/detail/openssl-helper.cpp deleted file mode 100644 index 8f8422a5d..000000000 --- a/src/security/detail/openssl-helper.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "openssl-helper.hpp" - -namespace ndn { -namespace security { -namespace detail { - -const EVP_MD* -toDigestEvpMd(DigestAlgorithm algo) -{ - switch (algo) { - case DigestAlgorithm::SHA256: - return EVP_sha256(); - default: - return nullptr; - } -} - -EvpPkey::EvpPkey() - : m_key(nullptr) -{ -} - -EvpPkey::~EvpPkey() -{ - EVP_PKEY_free(m_key); -} - -EvpPkeyCtx::EvpPkeyCtx(EVP_PKEY* key) - : m_ctx(EVP_PKEY_CTX_new(key, nullptr)) -{ - BOOST_ASSERT(m_ctx != nullptr); -} - -EvpPkeyCtx::EvpPkeyCtx(int id) - : m_ctx(EVP_PKEY_CTX_new_id(id, nullptr)) -{ - BOOST_ASSERT(m_ctx != nullptr); -} - -EvpPkeyCtx::~EvpPkeyCtx() -{ - EVP_PKEY_CTX_free(m_ctx); -} - -#if OPENSSL_VERSION_NUMBER < 0x1010000fL -Bio::Bio(BIO_METHOD* method) -#else -Bio::Bio(const BIO_METHOD* method) -#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL - : m_bio(BIO_new(method)) -{ - BOOST_ASSERT(m_bio != nullptr); -} - -Bio::~Bio() -{ - BIO_free_all(m_bio); -} - -} // namespace detail -} // namespace security -} // namespace ndn diff --git a/src/security/detail/openssl-helper.hpp b/src/security/detail/openssl-helper.hpp deleted file mode 100644 index 50f21bcad..000000000 --- a/src/security/detail/openssl-helper.hpp +++ /dev/null @@ -1,105 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_CXX_SECURITY_DETAIL_OPENSSL_HELPER_HPP -#define NDN_CXX_SECURITY_DETAIL_OPENSSL_HELPER_HPP - -#include "../security-common.hpp" -#include "openssl.hpp" - -namespace ndn { -namespace security { -namespace detail { - -const EVP_MD* -toDigestEvpMd(DigestAlgorithm algo); - -class EvpPkey -{ -public: - EvpPkey(); - - ~EvpPkey(); - - EVP_PKEY* - get() const - { - return m_key; - } - - EVP_PKEY** - operator&() - { - return &m_key; - } - -private: - EVP_PKEY* m_key; -}; - -class EvpPkeyCtx -{ -public: - explicit - EvpPkeyCtx(EVP_PKEY* key); - - explicit - EvpPkeyCtx(int id); - - ~EvpPkeyCtx(); - - EVP_PKEY_CTX* - get() const - { - return m_ctx; - } - -private: - EVP_PKEY_CTX* m_ctx; -}; - -class Bio -{ -public: - explicit -#if OPENSSL_VERSION_NUMBER < 0x1010000fL - Bio(BIO_METHOD* method); -#else - Bio(const BIO_METHOD* method); -#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL - - ~Bio(); - - BIO* - get() const - { - return m_bio; - } - -private: - BIO* m_bio; -}; - -} // namespace detail -} // namespace security -} // namespace ndn - -#endif // NDN_CXX_SECURITY_DETAIL_OPENSSL_HELPER_HPP diff --git a/src/security/detail/openssl.hpp b/src/security/detail/openssl.hpp deleted file mode 100644 index d3ab59287..000000000 --- a/src/security/detail/openssl.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_DETAIL_OPENSSL_HPP -#define NDN_SECURITY_DETAIL_OPENSSL_HPP - -// suppress deprecation warnings in OSX >= 10.7 - -#if defined(__APPLE__) - -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif // __clang__ - -#endif // __APPLE__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif // NDN_SECURITY_DETAIL_OPENSSL_HPP diff --git a/src/security/digest-sha256.hpp b/src/security/digest-sha256.hpp deleted file mode 100644 index d3a15de92..000000000 --- a/src/security/digest-sha256.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_DIGEST_SHA256_HPP -#define NDN_SECURITY_DIGEST_SHA256_HPP - -#include "../data.hpp" -#include "../encoding/tlv.hpp" - -namespace ndn { - -/** - * Represent a SHA256 digest. - */ -class DigestSha256 : public Signature -{ -public: - class Error : public Signature::Error - { - public: - explicit - Error(const std::string& what) - : Signature::Error(what) - { - } - }; - - DigestSha256(); - - explicit - DigestSha256(const Signature& signature); - -}; - -} // namespace ndn - -#endif //NDN_SECURITY_DIGEST_SHA256_HPP diff --git a/src/security/identity-certificate.hpp b/src/security/identity-certificate.hpp deleted file mode 100644 index 42553a6f4..000000000 --- a/src/security/identity-certificate.hpp +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** - * @file security/identity-certificate.hpp - * @deprecated Use security/v1/identity-certificate.hpp - */ - -#include "security-common.hpp" - -#ifdef NDN_CXX_KEEP_SECURITY_V1_ALIASES -#include "v1/identity-certificate.hpp" -#else -#error "Deprecated. Use `v1/identity-certificate.hpp` instead." -#endif // NDN_CXX_KEEP_SECURITY_V1_ALIASES diff --git a/src/security/identity-container.cpp b/src/security/identity-container.cpp deleted file mode 100644 index 756a75a12..000000000 --- a/src/security/identity-container.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "identity-container.hpp" -#include "pib-impl.hpp" - -namespace ndn { -namespace security { - -IdentityContainer::const_iterator::const_iterator(std::set::const_iterator it, - shared_ptr impl) - : m_it(it) - , m_impl(impl) -{ -} - -Identity -IdentityContainer::const_iterator::operator*() -{ - return Identity(*m_it, m_impl); -} - -IdentityContainer::const_iterator& -IdentityContainer::const_iterator::operator++() -{ - ++m_it; - return *this; -} - -IdentityContainer::const_iterator -IdentityContainer::const_iterator::operator++(int) -{ - const_iterator it(*this); - ++m_it; - return it; -} - -bool -IdentityContainer::const_iterator::operator==(const const_iterator& other) -{ - return (m_impl == other.m_impl && m_it == other.m_it); -} - -bool -IdentityContainer::const_iterator::operator!=(const const_iterator& other) -{ - return !(*this == other); -} - -IdentityContainer::IdentityContainer() -{ -} - -IdentityContainer::IdentityContainer(std::set&& identities, - shared_ptr impl) - : m_identities(identities) - , m_impl(impl) -{ -} - -IdentityContainer::const_iterator -IdentityContainer::begin() const -{ - return const_iterator(m_identities.begin(), m_impl); -} - -IdentityContainer::const_iterator -IdentityContainer::end() const -{ - return const_iterator(m_identities.end(), m_impl); -} - -IdentityContainer::const_iterator -IdentityContainer::find(const Name& identity) const -{ - return const_iterator(m_identities.find(identity), m_impl); -} - -size_t -IdentityContainer::size() const -{ - return m_identities.size(); -} - -} // namespace security -} // namespace ndn diff --git a/src/security/identity-container.hpp b/src/security/identity-container.hpp deleted file mode 100644 index dee80dd9b..000000000 --- a/src/security/identity-container.hpp +++ /dev/null @@ -1,94 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_IDENTITY_CONTAINER_HPP -#define NDN_SECURITY_IDENTITY_CONTAINER_HPP - -#include -#include "identity.hpp" - -namespace ndn { -namespace security { - -class PibImpl; - -/// @brief A handler to search or enumerate identities in PIB. -class IdentityContainer -{ -public: - class const_iterator - { - public: - friend class IdentityContainer; - - public: - Identity - operator*(); - - const_iterator& - operator++(); - - const_iterator - operator++(int); - - bool - operator==(const const_iterator& other); - - bool - operator!=(const const_iterator& other); - - private: - const_iterator(std::set::const_iterator it, shared_ptr impl); - - private: - Name m_identity; - std::set::const_iterator m_it; - shared_ptr m_impl; - }; - - typedef const_iterator iterator; - -public: - IdentityContainer(); - - IdentityContainer(std::set&& identities, shared_ptr impl); - - const_iterator - begin() const; - - const_iterator - end() const; - - const_iterator - find(const Name& keyId) const; - - size_t - size() const; - -private: - std::set m_identities; - shared_ptr m_impl; -}; - -} // namespace security -} // namespace ndn - -#endif // NDN_SECURITY_IDENTITY_CONTAINER_HPP diff --git a/src/security/identity.cpp b/src/security/identity.cpp deleted file mode 100644 index 176814cf3..000000000 --- a/src/security/identity.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "identity.hpp" -#include "pib-impl.hpp" -#include "pib.hpp" - -namespace ndn { -namespace security { - -const name::Component Identity::EMPTY_KEY_ID; - -Identity::Identity() - : m_hasDefaultKey(false) - , m_needRefreshKeys(false) - , m_impl(nullptr) -{ -} - -Identity::Identity(const Name& identityName, shared_ptr impl, bool needInit) - : m_name(identityName) - , m_hasDefaultKey(false) - , m_needRefreshKeys(true) - , m_impl(impl) -{ - validityCheck(); - - if (needInit) - m_impl->addIdentity(m_name); - else if (!m_impl->hasIdentity(m_name)) - BOOST_THROW_EXCEPTION(Pib::Error("Identity: " + m_name.toUri() + " does not exist")); -} - -const Name& -Identity::getName() const -{ - validityCheck(); - - return m_name; -} - -Key -Identity::addKey(const v1::PublicKey& publicKey, const name::Component& keyId) -{ - validityCheck(); - - name::Component actualKeyId = keyId; - if (actualKeyId == EMPTY_KEY_ID) { - const Block& digest = publicKey.computeDigest(); - actualKeyId = name::Component(digest.wire(), digest.size()); - } - - if (!m_needRefreshKeys && m_keys.find(actualKeyId) == m_keys.end()) { - // if we have already loaded all the keys, but the new key is not one of them - // the KeyContainer should be refreshed - m_needRefreshKeys = true; - } - - return Key(m_name, actualKeyId, publicKey, m_impl); -} - -void -Identity::removeKey(const name::Component& keyId) -{ - validityCheck(); - - if (m_hasDefaultKey && m_defaultKey.getKeyId() == keyId) - m_hasDefaultKey = false; - - m_impl->removeKey(m_name, keyId); - m_needRefreshKeys = true; -} - -Key -Identity::getKey(const name::Component& keyId) const -{ - validityCheck(); - - return Key(m_name, keyId, m_impl); -} - -const KeyContainer& -Identity::getKeys() const -{ - validityCheck(); - - if (m_needRefreshKeys) { - m_keys = KeyContainer(m_name, m_impl->getKeysOfIdentity(m_name), m_impl); - m_needRefreshKeys = false; - } - - return m_keys; -} - -Key& -Identity::setDefaultKey(const name::Component& keyId) -{ - validityCheck(); - - m_defaultKey = Key(m_name, keyId, m_impl); - m_hasDefaultKey = true; - - m_impl->setDefaultKeyOfIdentity(m_name, keyId); - return m_defaultKey; -} - -Key& -Identity::setDefaultKey(const v1::PublicKey& publicKey, const name::Component& keyId) -{ - const Key& keyEntry = addKey(publicKey, keyId); - return setDefaultKey(keyEntry.getKeyId()); -} - -Key& -Identity::getDefaultKey() const -{ - validityCheck(); - - if (!m_hasDefaultKey) { - m_defaultKey = Key(m_name, m_impl->getDefaultKeyOfIdentity(m_name), m_impl); - m_hasDefaultKey = true; - } - - return m_defaultKey; -} - -Identity::operator bool() const -{ - return !(this->operator!()); -} - -bool -Identity::operator!() const -{ - return (m_impl == nullptr); -} - -void -Identity::validityCheck() const -{ - if (m_impl == nullptr) - BOOST_THROW_EXCEPTION(std::domain_error("Invalid Identity instance")); -} - -} // namespace security -} // namespace ndn diff --git a/src/security/identity.hpp b/src/security/identity.hpp deleted file mode 100644 index 1e4bd2cb9..000000000 --- a/src/security/identity.hpp +++ /dev/null @@ -1,194 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_IDENTITY_HPP -#define NDN_SECURITY_IDENTITY_HPP - -#include "key-container.hpp" - -namespace ndn { -namespace security { - -class PibImpl; -class Pib; -class IdentityContainer; - -/** - * @brief represents an identity - * - * Identity is at the top level in PIB's Identity-Key-Certificate hierarchy. - * An identity has a Name, and contains one or more keys, one of which is set - * as the default key of this identity. Properties of a key can be accessed - * after obtaining a Key object. - * - * @throw PibImpl::Error when underlying implementation has non-semantic error. - */ -class Identity -{ -public: - friend class Pib; - friend class IdentityContainer; - friend class KeyChain; - -public: - /** - * @brief Default Constructor - * - * Identity created using this default constructor is just a place holder. - * It must obtain an actual instance from Pib::getIdentity(...). A typical - * usage would be for exception handling: - * - * Identity id; - * try { - * id = pib.getIdentity(...); - * } - * catch (Pib::Error&) { - * ... - * } - * - * An Identity instance created using the constructor is invalid. Calling a - * member method on an invalid Identity instance may cause an std::domain_error. - */ - Identity(); - - /// @brief Get the name of the identity. - const Name& - getName() const; - - /** - * @brief Get a key with id @p keyId. - * - * @param keyId The id of the key to get. - * @throw Pib::Error if the key does not exist. - */ - Key - getKey(const name::Component& keyId) const; - - /// @brief Get all the keys for this Identity. - const KeyContainer& - getKeys() const; - - /** - * @brief Get the default key for this Identity. - * - * @throws Pib::Error if the default key does not exist. - */ - Key& - getDefaultKey() const; - - /// @brief Check if the Identity instance is valid - operator bool() const; - - /// @brief Check if the Identity instance is invalid - bool - operator!() const; - -NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: // write operations should be private - - /** - * @brief Add a key. - * - * If the key already exists, do nothing. - * - * If no default key is set before, the new key will be set as the default key of the identity. - * - * @param publicKey The public key to add. - * @param keyId The key id component of the new key to add. - * By default, the keyId will be set to the hash of the public key bits. - * @return the added key or existing key with the same key id. - */ - Key - addKey(const v1::PublicKey& publicKey, const name::Component& keyId = EMPTY_KEY_ID); - - /** - * @brief Remove a key. - * - * @param keyId The key id component of the key to delete. - */ - void - removeKey(const name::Component& keyId); - - /** - * @brief Set the key with id @p keyId as the default key. - * - * @param keyId The key id component of the default key. - * @return The default key - * @throws Pib::Error if the key does not exist. - */ - Key& - setDefaultKey(const name::Component& keyId); - - /** - * @brief Set the default key. - * - * If the key does not exist, add the key and set it as the default of the Identity. - * If the key exists, simply set it as the default key of the Identity. - * - * @param publicKey The public key to add. - * @param keyId The key id component of the default key. - * @return the default key - */ - Key& - setDefaultKey(const v1::PublicKey& publicKey, const name::Component& keyId = EMPTY_KEY_ID); - -NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: - /** - * @brief Create an Identity with @p identityName. - * - * @param identityName The name of the Identity. - * @param impl The backend implementation. - * @param needInit If true, create the identity in backend when the identity does not exist. - * Otherwise, throw Pib::Error when the identity does not exist. - */ - Identity(const Name& identityName, shared_ptr impl, bool needInit = false); - - /** - * @brief Check the validity of this instance - * - * @throws std::domain_error if the instance is invalid - */ - void - validityCheck() const; - -public: - /** - * @brief The default value of keyId when add a new key. - * - * An empty keyId implies that the key digest should be used as the actual keyId. - */ - static const name::Component EMPTY_KEY_ID; - -private: - Name m_name; - - mutable bool m_hasDefaultKey; - mutable Key m_defaultKey; - - mutable bool m_needRefreshKeys; - mutable KeyContainer m_keys; - - shared_ptr m_impl; -}; - -} // namespace security -} // namespace ndn - -#endif // NDN_SECURITY_IDENTITY_HPP diff --git a/src/security/key-chain.cpp b/src/security/key-chain.cpp deleted file mode 100644 index 827f9df1e..000000000 --- a/src/security/key-chain.cpp +++ /dev/null @@ -1,846 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#include "key-chain.hpp" -#include "signing-helpers.hpp" - -#include "../util/random.hpp" -#include "../util/config-file.hpp" - -#include "sec-public-info-sqlite3.hpp" - -#ifdef NDN_CXX_HAVE_OSX_SECURITY -#include "sec-tpm-osx.hpp" -#endif // NDN_CXX_HAVE_OSX_SECURITY - -#include "sec-tpm-file.hpp" - -namespace ndn { -namespace security { - -// Use a GUID as a magic number of KeyChain::DEFAULT_PREFIX identifier -const Name KeyChain::DEFAULT_PREFIX("/723821fd-f534-44b3-80d9-44bf5f58bbbb"); -const Name KeyChain::DIGEST_SHA256_IDENTITY("/localhost/identity/digest-sha256"); - -// Note: cannot use default constructor, as it depends on static variables which may or may not be -// initialized at this point -const SigningInfo KeyChain::DEFAULT_SIGNING_INFO(SigningInfo::SIGNER_TYPE_NULL, Name(), SignatureInfo()); - -const RsaKeyParams KeyChain::DEFAULT_KEY_PARAMS; - -const std::string DEFAULT_PIB_SCHEME = "pib-sqlite3"; - -#if defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN) -const std::string DEFAULT_TPM_SCHEME = "tpm-osxkeychain"; -#else -const std::string DEFAULT_TPM_SCHEME = "tpm-file"; -#endif // defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN) - -// When static library is used, not everything is compiled into the resulting binary. -// Therefore, the following standard PIB and TPMs need to be registered here. -// http://stackoverflow.com/q/9459980/2150331 -// -// Also, cannot use Type::SCHEME, as its value may be uninitialized -NDN_CXX_KEYCHAIN_REGISTER_PIB(SecPublicInfoSqlite3, "pib-sqlite3", "sqlite3"); - -#ifdef NDN_CXX_HAVE_OSX_SECURITY -NDN_CXX_KEYCHAIN_REGISTER_TPM(SecTpmOsx, "tpm-osxkeychain", "osx-keychain"); -#endif // NDN_CXX_HAVE_OSX_SECURITY - -NDN_CXX_KEYCHAIN_REGISTER_TPM(SecTpmFile, "tpm-file", "file"); - -template -struct Factory -{ - Factory(const std::string& canonicalName, const T& create) - : canonicalName(canonicalName) - , create(create) - { - } - - std::string canonicalName; - T create; -}; -typedef Factory PibFactory; -typedef Factory TpmFactory; - -static std::map& -getPibFactories() -{ - static std::map pibFactories; - return pibFactories; -} - -static std::map& -getTpmFactories() -{ - static std::map tpmFactories; - return tpmFactories; -} - -void -KeyChain::registerPibImpl(const std::string& canonicalName, - std::initializer_list aliases, - KeyChain::PibCreateFunc createFunc) -{ - for (const std::string& alias : aliases) { - getPibFactories().insert(make_pair(alias, PibFactory(canonicalName, createFunc))); - } -} - -void -KeyChain::registerTpmImpl(const std::string& canonicalName, - std::initializer_list aliases, - KeyChain::TpmCreateFunc createFunc) -{ - for (const std::string& alias : aliases) { - getTpmFactories().insert(make_pair(alias, TpmFactory(canonicalName, createFunc))); - } -} - -KeyChain::KeyChain() - : m_pib(nullptr) - , m_tpm(nullptr) - , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now())) -{ - std::string pibLocator; - std::string tpmLocator; - - if (getenv("NDN_CLIENT_PIB") != nullptr) { - pibLocator = getenv("NDN_CLIENT_PIB"); - } - - if (getenv("NDN_CLIENT_TPM") != nullptr) { - tpmLocator = getenv("NDN_CLIENT_TPM"); - } - - if (pibLocator.empty() || tpmLocator.empty()) { - ConfigFile config; - const ConfigFile::Parsed& parsed = config.getParsedConfiguration(); - - if (pibLocator.empty()) { - pibLocator = parsed.get("pib", ""); - } - - if (tpmLocator.empty()) { - tpmLocator = parsed.get("tpm", ""); - } - } - - initialize(pibLocator, tpmLocator, false); -} - -KeyChain::KeyChain(const std::string& pibName, - const std::string& tpmName, - bool allowReset) - : m_pib(nullptr) - , m_tpm(nullptr) - , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now())) -{ - initialize(pibName, tpmName, allowReset); -} - -KeyChain::~KeyChain() -{ -} - -static inline std::tuple -parseUri(const std::string& uri) -{ - size_t pos = uri.find(':'); - if (pos != std::string::npos) { - return std::make_tuple(uri.substr(0, pos), - uri.substr(pos + 1)); - } - else { - return std::make_tuple(uri, ""); - } -} - -std::string -KeyChain::getDefaultPibLocator() -{ - std::string defaultPibLocator = DEFAULT_PIB_SCHEME + ":"; - return defaultPibLocator; -} - -static inline std::tuple -getCanonicalPibLocator(const std::string& pibLocator) -{ - std::string pibScheme, pibLocation; - std::tie(pibScheme, pibLocation) = parseUri(pibLocator); - - if (pibScheme.empty()) { - pibScheme = DEFAULT_PIB_SCHEME; - } - - auto pibFactory = getPibFactories().find(pibScheme); - if (pibFactory == getPibFactories().end()) { - BOOST_THROW_EXCEPTION(KeyChain::Error("PIB scheme '" + pibScheme + "' is not supported")); - } - pibScheme = pibFactory->second.canonicalName; - - return std::make_tuple(pibScheme, pibLocation); -} - -unique_ptr -KeyChain::createPib(const std::string& pibLocator) -{ - BOOST_ASSERT(!getPibFactories().empty()); - - std::string pibScheme, pibLocation; - std::tie(pibScheme, pibLocation) = getCanonicalPibLocator(pibLocator); - auto pibFactory = getPibFactories().find(pibScheme); - BOOST_ASSERT(pibFactory != getPibFactories().end()); - return pibFactory->second.create(pibLocation); -} - -std::string -KeyChain::getDefaultTpmLocator() -{ - std::string defaultTpmLocator = DEFAULT_TPM_SCHEME + ":"; - return defaultTpmLocator; -} - -static inline std::tuple -getCanonicalTpmLocator(const std::string& tpmLocator) -{ - std::string tpmScheme, tpmLocation; - std::tie(tpmScheme, tpmLocation) = parseUri(tpmLocator); - - if (tpmScheme.empty()) { - tpmScheme = DEFAULT_TPM_SCHEME; - } - auto tpmFactory = getTpmFactories().find(tpmScheme); - if (tpmFactory == getTpmFactories().end()) { - BOOST_THROW_EXCEPTION(KeyChain::Error("TPM scheme '" + tpmScheme + "' is not supported")); - } - tpmScheme = tpmFactory->second.canonicalName; - - return std::make_tuple(tpmScheme, tpmLocation); -} - -unique_ptr -KeyChain::createTpm(const std::string& tpmLocator) -{ - BOOST_ASSERT(!getTpmFactories().empty()); - - std::string tpmScheme, tpmLocation; - std::tie(tpmScheme, tpmLocation) = getCanonicalTpmLocator(tpmLocator); - auto tpmFactory = getTpmFactories().find(tpmScheme); - BOOST_ASSERT(tpmFactory != getTpmFactories().end()); - return tpmFactory->second.create(tpmLocation); -} - -void -KeyChain::initialize(const std::string& pibLocator, - const std::string& tpmLocator, - bool allowReset) -{ - // PIB Locator - std::string pibScheme, pibLocation; - std::tie(pibScheme, pibLocation) = getCanonicalPibLocator(pibLocator); - std::string canonicalPibLocator = pibScheme + ":" + pibLocation; - - // Create PIB - m_pib = createPib(canonicalPibLocator); - - // TPM Locator - std::string tpmScheme, tpmLocation; - std::tie(tpmScheme, tpmLocation) = getCanonicalTpmLocator(tpmLocator); - std::string canonicalTpmLocator = tpmScheme + ":" + tpmLocation; - - // Create TPM, checking that it matches to the previously associated one - try { - if (!allowReset && - !m_pib->getTpmLocator().empty() && m_pib->getTpmLocator() != canonicalTpmLocator) - // Tpm mismatch, but we do not want to reset PIB - BOOST_THROW_EXCEPTION(MismatchError("TPM locator supplied does not match TPM locator in PIB: " - + m_pib->getTpmLocator() + " != " + canonicalTpmLocator)); - } - catch (const SecPublicInfo::Error&) { - // TPM locator is not set in PIB yet. - } - - // note that key mismatch may still happen if the TPM locator is initially set to a - // wrong one or if the PIB was shared by more than one TPMs before. This is due to the - // old PIB does not have TPM info, new pib should not have this problem. - m_tpm = createTpm(canonicalTpmLocator); - m_pib->setTpmLocator(canonicalTpmLocator); -} - -Name -KeyChain::createIdentity(const Name& identityName, const KeyParams& params) -{ - m_pib->addIdentity(identityName); - - Name keyName; - try { - keyName = m_pib->getDefaultKeyNameForIdentity(identityName); - - shared_ptr key = m_pib->getPublicKey(keyName); - - if (key->getKeyType() != params.getKeyType()) { - keyName = generateKeyPair(identityName, true, params); - m_pib->setDefaultKeyNameForIdentity(keyName); - } - } - catch (const SecPublicInfo::Error& e) { - keyName = generateKeyPair(identityName, true, params); - m_pib->setDefaultKeyNameForIdentity(keyName); - } - - Name certName; - try { - certName = m_pib->getDefaultCertificateNameForKey(keyName); - } - catch (const SecPublicInfo::Error& e) { - shared_ptr selfCert = selfSign(keyName); - m_pib->addCertificateAsIdentityDefault(*selfCert); - certName = selfCert->getName(); - } - - return certName; -} - -Name -KeyChain::generateRsaKeyPair(const Name& identityName, bool isKsk, uint32_t keySize) -{ - RsaKeyParams params(keySize); - return generateKeyPair(identityName, isKsk, params); -} - -Name -KeyChain::generateEcdsaKeyPair(const Name& identityName, bool isKsk, uint32_t keySize) -{ - EcdsaKeyParams params(keySize); - return generateKeyPair(identityName, isKsk, params); -} - -Name -KeyChain::generateRsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize) -{ - RsaKeyParams params(keySize); - - Name keyName = generateKeyPair(identityName, isKsk, params); - - m_pib->setDefaultKeyNameForIdentity(keyName); - - return keyName; -} - -Name -KeyChain::generateEcdsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize) -{ - EcdsaKeyParams params(keySize); - - Name keyName = generateKeyPair(identityName, isKsk, params); - - m_pib->setDefaultKeyNameForIdentity(keyName); - - return keyName; -} - - -shared_ptr -KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName, - const Name& signingIdentity, - const time::system_clock::TimePoint& notBefore, - const time::system_clock::TimePoint& notAfter, - const std::vector& subjectDescription, - const Name& certPrefix) -{ - shared_ptr publicKey; - try { - publicKey = m_pib->getPublicKey(keyName); - } - catch (const SecPublicInfo::Error& e) { - return nullptr; - } - - return prepareUnsignedIdentityCertificate(keyName, *publicKey, signingIdentity, - notBefore, notAfter, - subjectDescription, certPrefix); -} - -shared_ptr -KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName, - const v1::PublicKey& publicKey, - const Name& signingIdentity, - const time::system_clock::TimePoint& notBefore, - const time::system_clock::TimePoint& notAfter, - const std::vector& subjectDescription, - const Name& certPrefix) -{ - if (keyName.size() < 1) - return nullptr; - - std::string keyIdPrefix = keyName.get(-1).toUri().substr(0, 4); - if (keyIdPrefix != "ksk-" && keyIdPrefix != "dsk-") - return nullptr; - - Name certName; - - if (certPrefix == KeyChain::DEFAULT_PREFIX) { - // No certificate prefix hint, infer the prefix - if (signingIdentity.isPrefixOf(keyName)) - certName.append(signingIdentity) - .append("KEY") - .append(keyName.getSubName(signingIdentity.size())) - .append("ID-CERT") - .appendVersion(); - else - certName.append(keyName.getPrefix(-1)) - .append("KEY") - .append(keyName.get(-1)) - .append("ID-CERT") - .appendVersion(); - } - else { - // cert prefix hint is supplied, determine the cert name. - if (certPrefix.isPrefixOf(keyName) && certPrefix != keyName) - certName.append(certPrefix) - .append("KEY") - .append(keyName.getSubName(certPrefix.size())) - .append("ID-CERT") - .appendVersion(); - else - return nullptr; - } - - auto certificate = make_shared(); - certificate->setName(certName); - certificate->setNotBefore(notBefore); - certificate->setNotAfter(notAfter); - certificate->setPublicKeyInfo(publicKey); - - if (subjectDescription.empty()) { - v1::CertificateSubjectDescription subjectName(oid::ATTRIBUTE_NAME, keyName.getPrefix(-1).toUri()); - certificate->addSubjectDescription(subjectName); - } - else { - std::vector::const_iterator sdIt = subjectDescription.begin(); - std::vector::const_iterator sdEnd = subjectDescription.end(); - for(; sdIt != sdEnd; sdIt++) - certificate->addSubjectDescription(*sdIt); - } - - certificate->encode(); - - return certificate; -} - -std::tuple -KeyChain::prepareSignatureInfo(const SigningInfo& params) -{ - SignatureInfo sigInfo = params.getSignatureInfo(); - - shared_ptr signingCert; - - switch (params.getSignerType()) { - case SigningInfo::SIGNER_TYPE_NULL: { - if (m_pib->getDefaultCertificate() == nullptr) - setDefaultCertificateInternal(); - - signingCert = m_pib->getDefaultCertificate(); - break; - } - case SigningInfo::SIGNER_TYPE_ID: { - Name signingCertName; - try { - signingCertName = m_pib->getDefaultCertificateNameForIdentity(params.getSignerName()); - } - catch (const SecPublicInfo::Error&) { - signingCertName = createIdentity(params.getSignerName(), getDefaultKeyParamsForIdentity(params.getSignerName())); - } - - signingCert = m_pib->getCertificate(signingCertName); - - break; - } - case SigningInfo::SIGNER_TYPE_KEY: { - Name signingCertName; - try { - signingCertName = m_pib->getDefaultCertificateNameForKey(params.getSignerName()); - } - catch (const SecPublicInfo::Error&) { - BOOST_THROW_EXCEPTION(Error("signing certificate does not exist")); - } - - signingCert = m_pib->getCertificate(signingCertName); - - break; - } - case SigningInfo::SIGNER_TYPE_CERT: { - signingCert = m_pib->getCertificate(params.getSignerName()); - if (signingCert == nullptr) - BOOST_THROW_EXCEPTION(Error("signing certificate does not exist")); - - break; - } - case SigningInfo::SIGNER_TYPE_SHA256: { - sigInfo.setSignatureType(tlv::DigestSha256); - return std::make_tuple(DIGEST_SHA256_IDENTITY, sigInfo); - } - default: - BOOST_THROW_EXCEPTION(Error("Unrecognized signer type")); - } - - sigInfo.setSignatureType(getSignatureType(signingCert->getPublicKeyInfo().getKeyType(), - params.getDigestAlgorithm())); - sigInfo.setKeyLocator(KeyLocator(signingCert->getName().getPrefix(-1))); - - return std::make_tuple(signingCert->getPublicKeyName(), sigInfo); -} - -void -KeyChain::sign(Data& data, const SigningInfo& params) -{ - signImpl(data, params); -} - -void -KeyChain::sign(Interest& interest, const SigningInfo& params) -{ - signImpl(interest, params); -} - -Block -KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const SigningInfo& params) -{ - Name keyName; - SignatureInfo sigInfo; - std::tie(keyName, sigInfo) = prepareSignatureInfo(params); - return pureSign(buffer, bufferLength, keyName, DigestAlgorithm::SHA256); -} - -Signature -KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName) -{ - shared_ptr certificate = m_pib->getCertificate(certificateName); - - if (certificate == nullptr) { - BOOST_THROW_EXCEPTION(SecPublicInfo::Error("certificate does not exist")); - } - - Signature sig; - - // For temporary usage, we support SHA256 only, but will support more. - sig.setValue(m_tpm->signInTpm(buffer, bufferLength, - certificate->getPublicKeyName(), - DigestAlgorithm::SHA256)); - - return sig; -} - -shared_ptr -KeyChain::selfSign(const Name& keyName) -{ - shared_ptr pubKey; - try { - pubKey = m_pib->getPublicKey(keyName); // may throw an exception. - } - catch (const SecPublicInfo::Error&) { - return nullptr; - } - - auto certificate = make_shared(); - - Name certificateName = keyName.getPrefix(-1); - certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion(); - - certificate->setName(certificateName); - certificate->setNotBefore(time::system_clock::now()); - certificate->setNotAfter(time::system_clock::now() + time::days(7300)); // ~20 years - certificate->setPublicKeyInfo(*pubKey); - certificate->addSubjectDescription(v1::CertificateSubjectDescription(oid::ATTRIBUTE_NAME, - keyName.toUri())); - certificate->encode(); - - certificate->setSignature(Signature(SignatureInfo())); - - selfSign(*certificate); - return certificate; -} - -void -KeyChain::selfSign(v1::IdentityCertificate& cert) -{ - Name keyName = cert.getPublicKeyName(); - - if (!m_tpm->doesKeyExistInTpm(keyName, KeyClass::PRIVATE)) - BOOST_THROW_EXCEPTION(SecTpm::Error("Private key does not exist")); - - SignatureInfo sigInfo(cert.getSignature().getInfo()); - sigInfo.setKeyLocator(KeyLocator(cert.getName().getPrefix(-1))); - sigInfo.setSignatureType(getSignatureType(cert.getPublicKeyInfo().getKeyType(), - DigestAlgorithm::SHA256)); - - signPacketWrapper(cert, Signature(sigInfo), keyName, DigestAlgorithm::SHA256); -} - -shared_ptr -KeyChain::exportIdentity(const Name& identity, const std::string& passwordStr) -{ - if (!m_pib->doesIdentityExist(identity)) - BOOST_THROW_EXCEPTION(SecPublicInfo::Error("Identity does not exist")); - - Name keyName = m_pib->getDefaultKeyNameForIdentity(identity); - - ConstBufferPtr pkcs5; - try { - pkcs5 = m_tpm->exportPrivateKeyPkcs5FromTpm(keyName, passwordStr); - } - catch (const SecTpm::Error& e) { - BOOST_THROW_EXCEPTION(SecPublicInfo::Error("Fail to export PKCS5 of private key")); - } - - shared_ptr cert; - try { - cert = m_pib->getCertificate(m_pib->getDefaultCertificateNameForKey(keyName)); - } - catch (const SecPublicInfo::Error& e) { - cert = selfSign(keyName); - m_pib->addCertificateAsIdentityDefault(*cert); - } - - // make_shared on OSX 10.9 has some strange problem here - return shared_ptr(new SecuredBag(*cert, pkcs5)); -} - -void -KeyChain::importIdentity(const SecuredBag& securedBag, const std::string& passwordStr) -{ - Name certificateName = securedBag.getCertificate().getName(); - Name keyName = v1::IdentityCertificate::certificateNameToPublicKeyName(certificateName); - Name identity = keyName.getPrefix(-1); - - // Add identity - m_pib->addIdentity(identity); - - // Add key - m_tpm->importPrivateKeyPkcs5IntoTpm(keyName, - securedBag.getKey()->buf(), - securedBag.getKey()->size(), - passwordStr); - - shared_ptr pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri()); - // HACK! We should set key type according to the pkcs8 info. - m_pib->addKey(keyName, *pubKey); - m_pib->setDefaultKeyNameForIdentity(keyName); - - // Add cert - m_pib->addCertificateAsIdentityDefault(securedBag.getCertificate()); -} - -const KeyParams& -KeyChain::getDefaultKeyParamsForIdentity(const Name &identityName) const -{ - KeyType keyType = KeyType::NONE; - try { - keyType = m_pib->getPublicKeyType(m_pib->getDefaultKeyNameForIdentity(identityName)); - } - catch (const SecPublicInfo::Error& e) { // @TODO Switch to Pib::Error - return DEFAULT_KEY_PARAMS; - } - - switch (keyType) { - case KeyType::RSA: { - static RsaKeyParams defaultRsaParams; - return defaultRsaParams; - } - case KeyType::EC: { - static EcdsaKeyParams defaultEcdsaParams; - return defaultEcdsaParams; - } - case KeyType::NONE: { - return DEFAULT_KEY_PARAMS; - } - default: - BOOST_THROW_EXCEPTION(Error("Unsupported key type")); - } -} - -void -KeyChain::setDefaultCertificateInternal() -{ - m_pib->refreshDefaultCertificate(); - - if (m_pib->getDefaultCertificate() == nullptr) { - Name defaultIdentity; - try { - defaultIdentity = m_pib->getDefaultIdentity(); - } - catch (const SecPublicInfo::Error& e) { - uint32_t random = random::generateWord32(); - defaultIdentity.append("tmp-identity") - .append(reinterpret_cast(&random), 4); - } - createIdentity(defaultIdentity); - m_pib->setDefaultIdentity(defaultIdentity); - m_pib->refreshDefaultCertificate(); - } -} - -Name -KeyChain::generateKeyPair(const Name& identityName, bool isKsk, const KeyParams& params) -{ - Name keyName = m_pib->getNewKeyName(identityName, isKsk); - - m_tpm->generateKeyPairInTpm(keyName.toUri(), params); - - shared_ptr pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri()); - m_pib->addKey(keyName, *pubKey); - - return keyName; -} - -void -KeyChain::signPacketWrapper(Data& data, const Signature& signature, - const Name& keyName, DigestAlgorithm digestAlgorithm) -{ - data.setSignature(signature); - - EncodingBuffer encoder; - data.wireEncode(encoder, true); - - Block sigValue = pureSign(encoder.buf(), encoder.size(), keyName, digestAlgorithm); - - data.wireEncode(encoder, sigValue); -} - -void -KeyChain::signPacketWrapper(Interest& interest, const Signature& signature, - const Name& keyName, DigestAlgorithm digestAlgorithm) -{ - time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now()); - if (timestamp <= m_lastTimestamp) { - timestamp = m_lastTimestamp + time::milliseconds(1); - } - - Name signedName = interest.getName(); - signedName - .append(name::Component::fromNumber(timestamp.count())) // timestamp - .append(name::Component::fromNumber(random::generateWord64())) // nonce - .append(signature.getInfo()); // signatureInfo - - Block sigValue = pureSign(signedName.wireEncode().value(), - signedName.wireEncode().value_size(), - keyName, - digestAlgorithm); - - sigValue.encode(); - signedName.append(sigValue); // signatureValue - interest.setName(signedName); -} - -Block -KeyChain::pureSign(const uint8_t* buf, size_t size, - const Name& keyName, DigestAlgorithm digestAlgorithm) const -{ - if (keyName == DIGEST_SHA256_IDENTITY) - return Block(tlv::SignatureValue, crypto::computeSha256Digest(buf, size)); - - return m_tpm->signInTpm(buf, size, keyName, digestAlgorithm); -} - -Signature -KeyChain::signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName) -{ - Signature sig; - sig.setValue(sign(buffer, bufferLength, signingByIdentity(identityName))); - return sig; -} - -void -KeyChain::signWithSha256(Data& data) -{ - return sign(data, signingWithSha256()); -} - -void -KeyChain::signWithSha256(Interest& interest) -{ - DigestSha256 sig; - - time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now()); - if (timestamp <= m_lastTimestamp) - timestamp = m_lastTimestamp + time::milliseconds(1); - - Name signedName = interest.getName(); - signedName - .append(name::Component::fromNumber(timestamp.count())) // timestamp - .append(name::Component::fromNumber(random::generateWord64())) // nonce - .append(sig.getInfo()); // signatureInfo - - Block sigValue(tlv::SignatureValue, - crypto::computeSha256Digest(signedName.wireEncode().value(), - signedName.wireEncode().value_size())); - - sigValue.encode(); - signedName.append(sigValue); // signatureValue - interest.setName(signedName); -} - -void -KeyChain::deleteCertificate(const Name& certificateName) -{ - m_pib->deleteCertificateInfo(certificateName); -} - -void -KeyChain::deleteKey(const Name& keyName) -{ - m_pib->deletePublicKeyInfo(keyName); - m_tpm->deleteKeyPairInTpm(keyName); -} - -void -KeyChain::deleteIdentity(const Name& identity) -{ - std::vector keyNames; - m_pib->getAllKeyNamesOfIdentity(identity, keyNames, true); - m_pib->getAllKeyNamesOfIdentity(identity, keyNames, false); - - m_pib->deleteIdentityInfo(identity); - - for (const auto& keyName : keyNames) - m_tpm->deleteKeyPairInTpm(keyName); -} - -tlv::SignatureTypeValue -KeyChain::getSignatureType(KeyType keyType, DigestAlgorithm digestAlgorithm) -{ - switch (keyType) { - case KeyType::RSA: - return tlv::SignatureSha256WithRsa; - case KeyType::EC: - return tlv::SignatureSha256WithEcdsa; - default: - BOOST_THROW_EXCEPTION(Error("Unsupported key types")); - } - -} - -} // namespace security -} // namespace ndn diff --git a/src/security/key-chain.hpp b/src/security/key-chain.hpp deleted file mode 100644 index 796aa33fd..000000000 --- a/src/security/key-chain.hpp +++ /dev/null @@ -1,973 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_SECURITY_KEY_CHAIN_HPP -#define NDN_SECURITY_KEY_CHAIN_HPP - -#include "sec-public-info.hpp" -#include "sec-tpm.hpp" -#include "key-params.hpp" -#include "secured-bag.hpp" -#include "signature-sha256-with-rsa.hpp" -#include "signature-sha256-with-ecdsa.hpp" -#include "digest-sha256.hpp" -#include "signing-info.hpp" - -#include "../interest.hpp" -#include "../util/crypto.hpp" -#include "../util/random.hpp" -#include - -namespace ndn { -namespace security { - -/** - * @brief The packet signing interface. - */ -class KeyChain : noncopyable -{ -public: - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - - /** - * @brief Error thrown when the supplied TPM locator to KeyChain constructor does not match - * the locator stored in PIB - */ - class MismatchError : public Error - { - public: - explicit - MismatchError(const std::string& what) - : Error(what) - { - } - }; - - typedef function (const std::string&)> PibCreateFunc; - typedef function(const std::string&)> TpmCreateFunc; - - /** - * @brief Register a new PIB - * @param aliases List of schemes with which this PIB will be associated. - * The first alias in the list is considered a canonical name of the PIB instance. - */ - template - static void - registerPib(std::initializer_list aliases); - - /** - * @brief Register a new TPM - * @param aliases List of schemes with which this TPM will be associated - * The first alias in the list is considered a canonical name of the TPM instance. - */ - template - static void - registerTpm(std::initializer_list aliases); - - /** - * @brief Get default PIB locator - */ - static std::string - getDefaultPibLocator(); - - /** - * @brief Create a PIB according to @p pibLocator - */ - static unique_ptr - createPib(const std::string& pibLocator); - - /** - * @brief Get default TPM locator - */ - static std::string - getDefaultTpmLocator(); - - /** - * @brief Create a TPM according to @p tpmLocator - */ - static unique_ptr - createTpm(const std::string& tpmLocator); - - /** - * @brief Constructor to create KeyChain with default PIB and TPM - * - * Default PIB and TPM are platform-dependent and can be overriden system-wide or on - * per-use basis. - * - * @todo Add detailed description about config file behavior here - */ - KeyChain(); - - /** - * @brief KeyChain constructor - * - * @sa http://redmine.named-data.net/issues/2260 - * - * @param pibLocator PIB locator - * @param tpmLocator TPM locator - * @param allowReset if true, the PIB will be reset when the supplied tpmLocator - * mismatches the one in PIB - */ - KeyChain(const std::string& pibLocator, - const std::string& tpmLocator, - bool allowReset = false); - - virtual - ~KeyChain(); - - /** - * @brief Create an identity by creating a pair of Key-Signing-Key (KSK) for this identity and a - * self-signed certificate of the KSK. - * - * @param identityName The name of the identity. - * @param params The key parameter if a key needs to be generated for the identity. - * @return The name of the default certificate of the identity. - */ - Name - createIdentity(const Name& identityName, const KeyParams& params = DEFAULT_KEY_PARAMS); - - /** - * @brief Generate a pair of RSA keys for the specified identity. - * - * @param identityName The name of the identity. - * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK). - * @param keySize The size of the key. - * @return The generated key name. - * @see generateEcdsaKeyPair - */ - Name - generateRsaKeyPair(const Name& identityName, bool isKsk = false, uint32_t keySize = 2048); - - /** - * @brief Generate a pair of ECDSA keys for the specified identity. - * - * @param identityName The name of the identity. - * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK). - * @param keySize The size of the key. - * @return The generated key name. - * @see generateRsaKeyPair - */ - Name - generateEcdsaKeyPair(const Name& identityName, bool isKsk = false, uint32_t keySize = 256); - - /** - * @brief Generate a pair of RSA keys for the specified identity and set it as default key for - * the identity. - * - * @param identityName The name of the identity. - * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK). - * @param keySize The size of the key. - * @return The generated key name. - * @see generateRsaKeyPair, generateEcdsaKeyPair, generateEcdsaKeyPairAsDefault - */ - Name - generateRsaKeyPairAsDefault(const Name& identityName, bool isKsk = false, uint32_t keySize = 2048); - - /** - * @brief Generate a pair of ECDSA keys for the specified identity and set it as default key for - * the identity. - * - * @param identityName The name of the identity. - * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK). - * @param keySize The size of the key. - * @return The generated key name. - * @see generateRsaKeyPair, generateEcdsaKeyPair, generateRsaKeyPairAsDefault - */ - Name - generateEcdsaKeyPairAsDefault(const Name& identityName, bool isKsk = false, uint32_t keySize = 256); - - /** - * @brief prepare an unsigned identity certificate - * - * @param keyName Key name, e.g., `//ksk-123456`. - * @param signingIdentity The signing identity. - * @param notBefore Refer to v1::IdentityCertificate. - * @param notAfter Refer to v1::IdentityCertificate. - * @param subjectDescription Refer to v1::IdentityCertificate. - * @param certPrefix Prefix before `KEY` component. By default, KeyChain will infer the - * certificate name according to the relation between the signingIdentity and - * the subject identity. If signingIdentity is a prefix of the subject identity, - * `KEY` will be inserted after the signingIdentity, otherwise `KEY` is inserted - * after subject identity (i.e., before `ksk-....`). - * @return v1::IdentityCertificate. - */ - shared_ptr - prepareUnsignedIdentityCertificate(const Name& keyName, - const Name& signingIdentity, - const time::system_clock::TimePoint& notBefore, - const time::system_clock::TimePoint& notAfter, - const std::vector& subjectDescription, - const Name& certPrefix = DEFAULT_PREFIX); - - /** - * @brief prepare an unsigned identity certificate - * - * @param keyName Key name, e.g., `//ksk-123456`. - * @param publicKey Public key to sign. - * @param signingIdentity The signing identity. - * @param notBefore Refer to v1::IdentityCertificate. - * @param notAfter Refer to v1::IdentityCertificate. - * @param subjectDescription Refer to v1::IdentityCertificate. - * @param certPrefix Prefix before `KEY` component. By default, KeyChain will infer the - * certificate name according to the relation between the signingIdentity and - * the subject identity. If signingIdentity is a prefix of the subject identity, - * `KEY` will be inserted after the signingIdentity, otherwise `KEY` is inserted - * after subject identity (i.e., before `ksk-....`). - * @return v1::IdentityCertificate. - */ - shared_ptr - prepareUnsignedIdentityCertificate(const Name& keyName, - const v1::PublicKey& publicKey, - const Name& signingIdentity, - const time::system_clock::TimePoint& notBefore, - const time::system_clock::TimePoint& notAfter, - const std::vector& subjectDescription, - const Name& certPrefix = DEFAULT_PREFIX); - - /** - * @brief Sign data according to the supplied signing information - * - * This method uses the supplied signing information @p params to create the SignatureInfo block: - * - it selects a private key and its certificate to sign the packet - * - sets the KeyLocator field with the certificate name, and - * - adds other requested information to the SignatureInfo block). - * - * After that, the method assigns the created SignatureInfo to the data packets, generate a - * signature and sets as part of the SignatureValue block. - * - * @param data The data to sign - * @param params The signing parameters. - * @throws Error if signing fails. - * @see SigningInfo - */ - void - sign(Data& data, const SigningInfo& params = DEFAULT_SIGNING_INFO); - - /** - * @brief Sign interest according to the supplied signing information - * - * This method uses the supplied signing information @p params to create the SignatureInfo block: - * - it selects a private key and its certificate to sign the packet - * - sets the KeyLocator field with the certificate name, and - * - adds other requested information to the SignatureInfo block). - * - * After that, the method appends the created SignatureInfo to the interest name, generate a - * signature and appends it as part of the SignatureValue block to the interest name. - * - * @param interest The interest to sign - * @param params The signing parameters. - * @throws Error if signing fails. - * @see SigningInfo - */ - void - sign(Interest& interest, const SigningInfo& params = DEFAULT_SIGNING_INFO); - - /** - * @brief Sign buffer according to the supplied signing information - * - * @param buffer The buffer to sign - * @param bufferLength The buffer size - * @param params The signing parameters. - * @return a SignatureValue TLV block - * @throws Error if signing fails. - * @see SigningInfo - */ - Block - sign(const uint8_t* buffer, size_t bufferLength, const SigningInfo& params); - - /** - * @deprecated use sign sign(T&, const SigningInfo&) - * @brief Sign packet with a particular certificate. - * - * @param packet The packet to be signed. - * @param certificateName The certificate name of the key to use for signing. - * @throws SecPublicInfo::Error if certificate does not exist. - */ - template - void - sign(T& packet, const Name& certificateName); - - /** - * @deprecated Use sign(const uint8_t*, size_t, const SigningInfo&) instead - * @brief Sign the byte array using a particular certificate. - * - * @param buffer The byte array to be signed. - * @param bufferLength the length of buffer. - * @param certificateName The certificate name of the signing key. - * @return The Signature. - * @throws SecPublicInfo::Error if certificate does not exist. - */ - Signature - sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName); - - /** - * @deprecated use sign sign(T&, const SigningInfo&) - * @brief Sign packet using the default certificate of a particular identity. - * - * If there is no default certificate of that identity, this method will create a self-signed - * certificate. - * - * @param packet The packet to be signed. - * @param identityName The signing identity name. - */ - template - void - signByIdentity(T& packet, const Name& identityName); - - /** - * @deprecated use sign(const uint8_t*, size_t, const SigningInfo&) instead - * @brief Sign the byte array using the default certificate of a particular identity. - * - * @param buffer The byte array to be signed. - * @param bufferLength the length of buffer. - * @param identityName The identity name. - * @return The Signature. - */ - Signature - signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName); - - /** - * @deprecated use sign(Data&, SigningInfo(SigningInfo::SIGNER_TYPE_SHA256)) - * @brief Set Sha256 weak signature for @p data - */ - void - signWithSha256(Data& data); - - /** - * @deprecated use sign(Interest&, SigningInfo(SigningInfo::SIGNER_TYPE_SHA256)) - * @brief Set Sha256 weak signature for @p interest - */ - void - signWithSha256(Interest& interest); - - /** - * @brief Generate a self-signed certificate for a public key. - * - * @param keyName The name of the public key - * @return The generated certificate, shared_ptr() if selfSign fails - */ - shared_ptr - selfSign(const Name& keyName); - - /** - * @brief Self-sign the supplied identity certificate. - * - * @param cert The supplied cert. - * @throws SecTpm::Error if the private key does not exist. - */ - void - selfSign(v1::IdentityCertificate& cert); - - /** - * @brief delete a certificate. - * - * @param certificateName The certificate to be deleted. - * @throws KeyChain::Error if certificate cannot be deleted. - */ - void - deleteCertificate(const Name& certificateName); - - /** - * @brief delete a key. - * - * @param keyName The key to be deleted. - * @throws KeyChain::Error if key cannot be deleted. - */ - void - deleteKey(const Name& keyName); - - /** - * @brief delete an identity. - * - * @param identity The identity to be deleted. - * @throws KeyChain::Error if identity cannot be deleted. - */ - void - deleteIdentity(const Name& identity); - - /** - * @brief export an identity. - * - * @param identity The identity to export. - * @param passwordStr The password to secure the private key. - * @return The encoded export data. - * @throws SecPublicInfo::Error if anything goes wrong in exporting. - */ - shared_ptr - exportIdentity(const Name& identity, const std::string& passwordStr); - - /** - * @brief import an identity. - * - * @param securedBag The encoded import data. - * @param passwordStr The password to secure the private key. - */ - void - importIdentity(const SecuredBag& securedBag, const std::string& passwordStr); - - SecPublicInfo& - getPib() - { - return *m_pib; - } - - const SecPublicInfo& - getPib() const - { - return *m_pib; - } - - SecTpm& - getTpm() - { - return *m_tpm; - } - - const SecTpm& - getTpm() const - { - return *m_tpm; - } - - /******************************* - * Wrapper of SecPublicInfo * - *******************************/ - bool - doesIdentityExist(const Name& identityName) const - { - return m_pib->doesIdentityExist(identityName); - } - - void - addIdentity(const Name& identityName) - { - return m_pib->addIdentity(identityName); - } - - bool - doesPublicKeyExist(const Name& keyName) const - { - return m_pib->doesPublicKeyExist(keyName); - } - - void - addPublicKey(const Name& keyName, KeyType keyType, const v1::PublicKey& publicKeyDer) - { - return m_pib->addKey(keyName, publicKeyDer); - } - - void - addKey(const Name& keyName, const v1::PublicKey& publicKeyDer) - { - return m_pib->addKey(keyName, publicKeyDer); - } - - shared_ptr - getPublicKey(const Name& keyName) const - { - return m_pib->getPublicKey(keyName); - } - - bool - doesCertificateExist(const Name& certificateName) const - { - return m_pib->doesCertificateExist(certificateName); - } - - void - addCertificate(const v1::IdentityCertificate& certificate) - { - return m_pib->addCertificate(certificate); - } - - shared_ptr - getCertificate(const Name& certificateName) const - { - return m_pib->getCertificate(certificateName); - } - - Name - getDefaultIdentity() const - { - return m_pib->getDefaultIdentity(); - } - - Name - getDefaultKeyNameForIdentity(const Name& identityName) const - { - return m_pib->getDefaultKeyNameForIdentity(identityName); - } - - /** - * @brief Get default key parameters for the specified identity - * - * If identity has a previously generated key, the returned parameters - * will include the same type of the key. If there are no existing - * keys, DEFAULT_KEY_PARAMS is used. - */ - const KeyParams& - getDefaultKeyParamsForIdentity(const Name& identityName) const; - - Name - getDefaultCertificateNameForKey(const Name& keyName) const - { - return m_pib->getDefaultCertificateNameForKey(keyName); - } - - void - getAllIdentities(std::vector& nameList, bool isDefault) const - { - return m_pib->getAllIdentities(nameList, isDefault); - } - - void - getAllKeyNames(std::vector& nameList, bool isDefault) const - { - return m_pib->getAllKeyNames(nameList, isDefault); - } - - void - getAllKeyNamesOfIdentity(const Name& identity, std::vector& nameList, bool isDefault) const - { - return m_pib->getAllKeyNamesOfIdentity(identity, nameList, isDefault); - } - - void - getAllCertificateNames(std::vector& nameList, bool isDefault) const - { - return m_pib->getAllCertificateNames(nameList, isDefault); - } - - void - getAllCertificateNamesOfKey(const Name& keyName, - std::vector& nameList, - bool isDefault) const - { - return m_pib->getAllCertificateNamesOfKey(keyName, nameList, isDefault); - } - - void - deleteCertificateInfo(const Name& certificateName) - { - return m_pib->deleteCertificateInfo(certificateName); - } - - void - deletePublicKeyInfo(const Name& keyName) - { - return m_pib->deletePublicKeyInfo(keyName); - } - - void - deleteIdentityInfo(const Name& identity) - { - return m_pib->deleteIdentityInfo(identity); - } - - void - setDefaultIdentity(const Name& identityName) - { - return m_pib->setDefaultIdentity(identityName); - } - - void - setDefaultKeyNameForIdentity(const Name& keyName) - { - return m_pib->setDefaultKeyNameForIdentity(keyName); - } - - void - setDefaultCertificateNameForKey(const Name& certificateName) - { - return m_pib->setDefaultCertificateNameForKey(certificateName); - } - - Name - getNewKeyName(const Name& identityName, bool useKsk) - { - return m_pib->getNewKeyName(identityName, useKsk); - } - - Name - getDefaultCertificateNameForIdentity(const Name& identityName) const - { - return m_pib->getDefaultCertificateNameForIdentity(identityName); - } - - Name - getDefaultCertificateName() const - { - return m_pib->getDefaultCertificateName(); - } - - void - addCertificateAsKeyDefault(const v1::IdentityCertificate& certificate) - { - return m_pib->addCertificateAsKeyDefault(certificate); - } - - void - addCertificateAsIdentityDefault(const v1::IdentityCertificate& certificate) - { - return m_pib->addCertificateAsIdentityDefault(certificate); - } - - void - addCertificateAsSystemDefault(const v1::IdentityCertificate& certificate) - { - return m_pib->addCertificateAsSystemDefault(certificate); - } - - shared_ptr - getDefaultCertificate() const - { - if (!static_cast(m_pib->getDefaultCertificate())) - const_cast(this)->setDefaultCertificateInternal(); - - return m_pib->getDefaultCertificate(); - } - - void - refreshDefaultCertificate() - { - return m_pib->refreshDefaultCertificate(); - } - - /******************************* - * Wrapper of SecTpm * - *******************************/ - - void - setTpmPassword(const uint8_t* password, size_t passwordLength) - { - return m_tpm->setTpmPassword(password, passwordLength); - } - - void - resetTpmPassword() - { - return m_tpm->resetTpmPassword(); - } - - void - setInTerminal(bool inTerminal) - { - return m_tpm->setInTerminal(inTerminal); - } - - bool - getInTerminal() const - { - return m_tpm->getInTerminal(); - } - - bool - isLocked() const - { - return m_tpm->isLocked(); - } - - bool - unlockTpm(const char* password, size_t passwordLength, bool usePassword) - { - return m_tpm->unlockTpm(password, passwordLength, usePassword); - } - - void - generateKeyPairInTpm(const Name& keyName, const KeyParams& params) - { - return m_tpm->generateKeyPairInTpm(keyName, params); - } - - void - deleteKeyPairInTpm(const Name& keyName) - { - return m_tpm->deleteKeyPairInTpm(keyName); - } - - shared_ptr - getPublicKeyFromTpm(const Name& keyName) const - { - return m_tpm->getPublicKeyFromTpm(keyName); - } - - Block - signInTpm(const uint8_t* data, size_t dataLength, - const Name& keyName, - DigestAlgorithm digestAlgorithm) - { - return m_tpm->signInTpm(data, dataLength, keyName, digestAlgorithm); - } - - ConstBufferPtr - decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric) - { - return m_tpm->decryptInTpm(data, dataLength, keyName, isSymmetric); - } - - ConstBufferPtr - encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric) - { - return m_tpm->encryptInTpm(data, dataLength, keyName, isSymmetric); - } - - void - generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params) - { - return m_tpm->generateSymmetricKeyInTpm(keyName, params); - } - - bool - doesKeyExistInTpm(const Name& keyName, KeyClass keyClass) const - { - return m_tpm->doesKeyExistInTpm(keyName, keyClass); - } - - bool - generateRandomBlock(uint8_t* res, size_t size) const - { - return m_tpm->generateRandomBlock(res, size); - } - - void - addAppToAcl(const Name& keyName, KeyClass keyClass, const std::string& appPath, AclType acl) - { - return m_tpm->addAppToAcl(keyName, keyClass, appPath, acl); - } - - ConstBufferPtr - exportPrivateKeyPkcs5FromTpm(const Name& keyName, const std::string& password) - { - return m_tpm->exportPrivateKeyPkcs5FromTpm(keyName, password); - } - - bool - importPrivateKeyPkcs5IntoTpm(const Name& keyName, - const uint8_t* buf, size_t size, - const std::string& password) - { - return m_tpm->importPrivateKeyPkcs5IntoTpm(keyName, buf, size, password); - } - -private: - void - initialize(const std::string& pibLocatorUri, - const std::string& tpmLocatorUri, - bool needReset); - - /** - * @brief Prepare a SignatureInfo TLV according to signing information and return the signing key name - * - * @param params The signing parameters. - * @return The signing key name and prepared SignatureInfo. - * @throw Error when the requested signing method cannot be satisfied. - */ - std::tuple - prepareSignatureInfo(const SigningInfo& params); - - /** - * @brief Internal abstraction of packet signing. - * - * @param packet The packet to sign - * @param params The signing parameters. - * @throw Error when the signing fails. - */ - template - void - signImpl(T& packet, const SigningInfo& params); - - /** - * @brief Set default certificate if it is not initialized - */ - void - setDefaultCertificateInternal(); - - /** - * @brief Generate a key pair for the specified identity. - * - * @param identityName The name of the specified identity. - * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK). - * @param params The parameter of the key. - * @return The name of the generated key. - */ - Name - generateKeyPair(const Name& identityName, bool isKsk = false, - const KeyParams& params = DEFAULT_KEY_PARAMS); - - /** - * @brief Sign the data using a particular key. - * - * @param data Reference to the data packet. - * @param signature Signature to be added. - * @param keyName The name of the signing key. - * @param digestAlgorithm the digest algorithm. - * @throws Tpm::Error - */ - void - signPacketWrapper(Data& data, const Signature& signature, - const Name& keyName, DigestAlgorithm digestAlgorithm); - - /** - * @brief Sign the interest using a particular key. - * - * @param interest Reference to the interest packet. - * @param signature Signature to be added. - * @param keyName The name of the signing key. - * @param digestAlgorithm the digest algorithm. - * @throws Tpm::Error - */ - void - signPacketWrapper(Interest& interest, const Signature& signature, - const Name& keyName, DigestAlgorithm digestAlgorithm); - - /** - * @brief Generate a SignatureValue block for a buffer @p buf with size @p size using - * a key with name @p keyName and digest algorithm @p digestAlgorithm. - */ - Block - pureSign(const uint8_t* buf, size_t size, const Name& keyName, DigestAlgorithm digestAlgorithm) const; - - static void - registerPibImpl(const std::string& canonicalName, - std::initializer_list aliases, PibCreateFunc createFunc); - - static void - registerTpmImpl(const std::string& canonicalName, - std::initializer_list aliases, TpmCreateFunc createFunc); - -public: - static tlv::SignatureTypeValue - getSignatureType(KeyType keyType, DigestAlgorithm digestAlgorithm); - -public: - static const Name DEFAULT_PREFIX; - static const SigningInfo DEFAULT_SIGNING_INFO; - - /** - * @brief A localhost identity which indicates that signature is generated using SHA-256. - * @todo Passing this as identity is not implemented. - */ - static const Name DIGEST_SHA256_IDENTITY; - - // RsaKeyParams is set to be default for backward compatibility. - static const RsaKeyParams DEFAULT_KEY_PARAMS; - - typedef std::map SignParams; - -private: - std::unique_ptr m_pib; - std::unique_ptr m_tpm; - time::milliseconds m_lastTimestamp; -}; - -template -void -KeyChain::signImpl(T& packet, const SigningInfo& params) -{ - Name keyName; - SignatureInfo sigInfo; - std::tie(keyName, sigInfo) = prepareSignatureInfo(params); - - signPacketWrapper(packet, Signature(sigInfo), - keyName, params.getDigestAlgorithm()); -} - -template -void -KeyChain::sign(T& packet, const Name& certificateName) -{ - signImpl(packet, SigningInfo(SigningInfo::SIGNER_TYPE_CERT, certificateName)); -} - -template -void -KeyChain::signByIdentity(T& packet, const Name& identityName) -{ - signImpl(packet, SigningInfo(SigningInfo::SIGNER_TYPE_ID, identityName)); -} - -template -inline void -KeyChain::registerPib(std::initializer_list aliases) -{ - registerPibImpl(*aliases.begin(), aliases, [] (const std::string& locator) { - return make_unique(locator); - }); -} - -template -inline void -KeyChain::registerTpm(std::initializer_list aliases) -{ - registerTpmImpl(*aliases.begin(), aliases, [] (const std::string& locator) { - return make_unique(locator); - }); -} - -/** - * \brief Register SecPib class in ndn-cxx KeyChain - * - * This macro should be placed once in the implementation file of the - * SecPib type within the namespace where the type is declared. - */ -#define NDN_CXX_KEYCHAIN_REGISTER_PIB(PibType, ...) \ -static class NdnCxxAuto ## PibType ## PibRegistrationClass \ -{ \ -public: \ - NdnCxxAuto ## PibType ## PibRegistrationClass() \ - { \ - ::ndn::KeyChain::registerPib({__VA_ARGS__}); \ - } \ -} ndnCxxAuto ## PibType ## PibRegistrationVariable - -/** - * \brief Register SecTpm class in ndn-cxx KeyChain - * - * This macro should be placed once in the implementation file of the - * SecTpm type within the namespace where the type is declared. - */ -#define NDN_CXX_KEYCHAIN_REGISTER_TPM(TpmType, ...) \ -static class NdnCxxAuto ## TpmType ## TpmRegistrationClass \ -{ \ -public: \ - NdnCxxAuto ## TpmType ## TpmRegistrationClass() \ - { \ - ::ndn::KeyChain::registerTpm({__VA_ARGS__}); \ - } \ -} ndnCxxAuto ## TpmType ## TpmRegistrationVariable - -} // namespace security - -using security::KeyChain; - -} // namespace ndn - -#endif // NDN_SECURITY_KEY_CHAIN_HPP diff --git a/src/security/key-container.cpp b/src/security/key-container.cpp deleted file mode 100644 index 51ffac588..000000000 --- a/src/security/key-container.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "key-container.hpp" -#include "pib-impl.hpp" - -namespace ndn { -namespace security { - -KeyContainer::const_iterator::const_iterator(const Name& identity, - std::set::const_iterator it, - shared_ptr impl) - : m_identity(identity) - , m_it(it) - , m_impl(impl) -{ -} - -Key -KeyContainer::const_iterator::operator*() -{ - return Key(m_identity, *m_it, m_impl); -} - -KeyContainer::const_iterator& -KeyContainer::const_iterator::operator++() -{ - ++m_it; - return *this; -} - -KeyContainer::const_iterator -KeyContainer::const_iterator::operator++(int) -{ - const_iterator it(*this); - ++m_it; - return it; -} - -bool -KeyContainer::const_iterator::operator==(const const_iterator& other) -{ - return (m_impl == other.m_impl && m_identity == other.m_identity && m_it == other.m_it); -} - -bool -KeyContainer::const_iterator::operator!=(const const_iterator& other) -{ - return !(*this == other); -} - -KeyContainer::KeyContainer() -{ -} - -KeyContainer::KeyContainer(const Name& identity, - std::set&& keyIds, - shared_ptr impl) - : m_identity(identity) - , m_keyIds(keyIds) - , m_impl(impl) -{ -} - -KeyContainer::const_iterator -KeyContainer::begin() const -{ - return const_iterator(m_identity, m_keyIds.begin(), m_impl); -} - -KeyContainer::const_iterator -KeyContainer::end() const -{ - return const_iterator(m_identity, m_keyIds.end(), m_impl); -} - -KeyContainer::const_iterator -KeyContainer::find(const name::Component& keyId) const -{ - return const_iterator(m_identity, m_keyIds.find(keyId), m_impl); -} - -size_t -KeyContainer::size() const -{ - return m_keyIds.size(); -} - -} // namespace security -} // namespace ndn diff --git a/src/security/key-container.hpp b/src/security/key-container.hpp deleted file mode 100644 index 9799d0321..000000000 --- a/src/security/key-container.hpp +++ /dev/null @@ -1,99 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_KEY_CONTAINER_HPP -#define NDN_SECURITY_KEY_CONTAINER_HPP - -#include -#include "key.hpp" - -namespace ndn { -namespace security { - -class PibImpl; - -/// @brief A handler to search or enumerate keys of an identity. -class KeyContainer -{ -public: - class const_iterator - { - public: - friend class KeyContainer; - - public: - Key - operator*(); - - const_iterator& - operator++(); - - const_iterator - operator++(int); - - bool - operator==(const const_iterator& other); - - bool - operator!=(const const_iterator& other); - - private: - const_iterator(const Name& identity, - std::set::const_iterator it, - shared_ptr impl); - - private: - Name m_identity; - std::set::const_iterator m_it; - shared_ptr m_impl; - }; - - typedef const_iterator iterator; - -public: - KeyContainer(); - - KeyContainer(const Name& identity, - std::set&& keyIds, - shared_ptr impl); - - const_iterator - begin() const; - - const_iterator - end() const; - - const_iterator - find(const name::Component& keyId) const; - - size_t - size() const; - -private: - Name m_identity; - std::set m_keyIds; - shared_ptr m_impl; -}; - -} // namespace security -} // namespace ndn - -#endif // NDN_SECURITY_KEY_CONTAINER_HPP diff --git a/src/security/key-params.cpp b/src/security/key-params.cpp deleted file mode 100644 index 7ee2e1e58..000000000 --- a/src/security/key-params.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "key-params.hpp" - -namespace ndn { - -static const uint32_t RSA_KEY_SIZES[] = {2048, 1024}; -static const uint32_t ECDSA_KEY_SIZES[] = {256, 384}; -static const uint32_t AES_KEY_SIZES[] = {64, 128, 256}; - -uint32_t -RsaKeyParamsInfo::checkKeySize(uint32_t size) -{ - for (size_t i = 0; i < (sizeof(RSA_KEY_SIZES) / sizeof(uint32_t)); i++) - { - if (RSA_KEY_SIZES[i] == size) - return size; - } - return getDefaultSize(); -} - -uint32_t -RsaKeyParamsInfo::getDefaultSize() -{ - return RSA_KEY_SIZES[0]; -} - -uint32_t -EcdsaKeyParamsInfo::checkKeySize(uint32_t size) -{ - - for (size_t i = 0; i < (sizeof(ECDSA_KEY_SIZES) / sizeof(uint32_t)); i++) - { - if (ECDSA_KEY_SIZES[i] == size) - return size; - } - return getDefaultSize(); -} - -uint32_t -EcdsaKeyParamsInfo::getDefaultSize() -{ - return ECDSA_KEY_SIZES[0]; -} - - -uint32_t -AesKeyParamsInfo::checkKeySize(uint32_t size) -{ - for (size_t i = 0; i < (sizeof(AES_KEY_SIZES) / sizeof(uint32_t)); i++) - { - if (AES_KEY_SIZES[i] == size) - return size; - } - return getDefaultSize(); -} - -uint32_t -AesKeyParamsInfo::getDefaultSize() -{ - return AES_KEY_SIZES[0]; -} - -} // namespace ndn diff --git a/src/security/key-params.hpp b/src/security/key-params.hpp deleted file mode 100644 index 976927059..000000000 --- a/src/security/key-params.hpp +++ /dev/null @@ -1,236 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_KEY_PARAMS_HPP -#define NDN_SECURITY_KEY_PARAMS_HPP - -#include "../common.hpp" -#include "security-common.hpp" - -namespace ndn { - -/** - * @brief Base class of key parameters. - * - * Its subclasses are used to store parameters for key generation. - */ -class KeyParams -{ -public: - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - - virtual - ~KeyParams() - { - } - - KeyType - getKeyType() const - { - return m_keyType; - } - -protected: - explicit - KeyParams(KeyType keyType) - : m_keyType(keyType) - { - } - -private: - KeyType m_keyType; -}; - - -/// @brief RsaKeyParamInfo is used to initialize a SimplePublicKeyParams template for RSA key. -class RsaKeyParamsInfo -{ -public: - static KeyType - getType() - { - return KeyType::RSA; - } - - /// @brief check if size is qualified, otherwise return the default key size. - static uint32_t - checkKeySize(uint32_t size); - - static uint32_t - getDefaultSize(); -}; - -/// @brief EcdsaKeyParamInfo is used to initialize a SimplePublicKeyParams template for ECDSA key. -class EcdsaKeyParamsInfo -{ -public: - static KeyType - getType() - { - return KeyType::EC; - } - - /// @brief check if size is qualified, otherwise return the default key size. - static uint32_t - checkKeySize(uint32_t size); - - static uint32_t - getDefaultSize(); -}; - - -/// @brief SimplePublicKeyParams is a template for public keys with only one parameter: size. -template -class SimplePublicKeyParams : public KeyParams -{ -public: - explicit - SimplePublicKeyParams(uint32_t size = KeyParamsInfo::getDefaultSize()) - : KeyParams(KeyParamsInfo::getType()) - { - setKeySize(size); - } - - explicit - SimplePublicKeyParams(const SimplePublicKeyParams& params) - : KeyParams(params) - , m_size(params.m_size) - { - } - - explicit - SimplePublicKeyParams(const KeyParams& params) - : KeyParams(params.getKeyType()) - { - BOOST_THROW_EXCEPTION(KeyParams::Error("Incorrect key parameters (incompatible key type)")); - } - - uint32_t - getKeySize() const - { - return m_size; - } - -private: - void - setKeySize(uint32_t size) - { - m_size = KeyParamsInfo::checkKeySize(size); - } - - uint32_t - getDefaultKeySize() const - { - return KeyParamsInfo::getDefaultSize(); - } - -private: - uint32_t m_size; -}; - -/// @brief RsaKeyParams carries parameters for RSA key. -typedef SimplePublicKeyParams RsaKeyParams; - -/// @brief EcdsaKeyParams carries parameters for ECDSA key. -typedef SimplePublicKeyParams EcdsaKeyParams; - - -/// @brief AesKeyParamsInfo is used to initialize a SimpleSymmetricKeyParams template for AES key. -class AesKeyParamsInfo -{ -public: - static KeyType - getType() - { - return KeyType::AES; - } - - /// @brief check if size is qualified, otherwise return the default key size. - static uint32_t - checkKeySize(uint32_t size); - - static uint32_t - getDefaultSize(); -}; - - -/// @brief SimpleSymmetricKeyParams is a template for symmetric keys with only one parameter: size. -template -class SimpleSymmetricKeyParams : public KeyParams -{ -public: - explicit - SimpleSymmetricKeyParams(uint32_t size = KeyParamsInfo::getDefaultSize()) - : KeyParams(KeyParamsInfo::getType()) - { - setKeySize(size); - } - - explicit - SimpleSymmetricKeyParams(const SimpleSymmetricKeyParams& params) - : KeyParams(params) - , m_size(params.m_size) - { - } - - explicit - SimpleSymmetricKeyParams(const KeyParams& params) - { - BOOST_THROW_EXCEPTION(KeyParams::Error("Incorrect key parameters (incompatible key type)")); - } - - uint32_t - getKeySize() const - { - return m_size; - } - -private: - void - setKeySize(uint32_t size) - { - m_size = KeyParamsInfo::checkKeySize(size); - } - - uint32_t - getDefaultKeySize() const - { - return KeyParamsInfo::getDefaultSize(); - } - -private: - uint32_t m_size; - -}; - -typedef SimpleSymmetricKeyParams AesKeyParams; - -} // namespace ndn - -#endif // NDN_SECURITY_KEY_PARAMS_HPP diff --git a/src/security/key.cpp b/src/security/key.cpp deleted file mode 100644 index c59a39dfb..000000000 --- a/src/security/key.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "key.hpp" -#include "pib-impl.hpp" -#include "pib.hpp" - -namespace ndn { -namespace security { - -Key::Key() - : m_hasDefaultCertificate(false) - , m_needRefreshCerts(false) - , m_impl(nullptr) -{ -} - -Key::Key(const Name& identityName, const name::Component& keyId, - const v1::PublicKey& publicKey, shared_ptr impl) - : m_id(identityName) - , m_keyId(keyId) - , m_key(publicKey) - , m_hasDefaultCertificate(false) - , m_needRefreshCerts(true) - , m_impl(impl) -{ - validityCheck(); - - m_keyName = m_id; - m_keyName.append(m_keyId); - - m_impl->addIdentity(m_id); - m_impl->addKey(m_id, m_keyId, publicKey); -} - -Key::Key(const Name& identityName, const name::Component& keyId, - shared_ptr impl) - : m_id(identityName) - , m_keyId(keyId) - , m_hasDefaultCertificate(false) - , m_needRefreshCerts(true) - , m_impl(impl) -{ - validityCheck(); - - m_keyName = m_id; - m_keyName.append(m_keyId); - - m_key = m_impl->getKeyBits(m_id, m_keyId); -} - -const Name& -Key::getName() const -{ - validityCheck(); - - return m_keyName; -} - -const Name& -Key::getIdentity() const -{ - validityCheck(); - - return m_id; -} - -const name::Component& -Key::getKeyId() const -{ - validityCheck(); - - return m_keyId; -} - -const v1::PublicKey& -Key::getPublicKey() const -{ - validityCheck(); - - return m_key; -} - -void -Key::addCertificate(const v1::IdentityCertificate& certificate) -{ - validityCheck(); - - if (!m_needRefreshCerts && - m_certificates.find(certificate.getName()) == m_certificates.end()) { - // if we have already loaded all the certificate, but the new certificate is not one of them - // the CertificateContainer should be refreshed - m_needRefreshCerts = true; - } - - m_impl->addCertificate(certificate); -} - -void -Key::removeCertificate(const Name& certName) -{ - validityCheck(); - - if (m_hasDefaultCertificate && m_defaultCertificate.getName() == certName) - m_hasDefaultCertificate = false; - - m_impl->removeCertificate(certName); - m_needRefreshCerts = true; -} - -v1::IdentityCertificate -Key::getCertificate(const Name& certName) const -{ - validityCheck(); - - return m_impl->getCertificate(certName); -} - -const CertificateContainer& -Key::getCertificates() const -{ - validityCheck(); - - if (m_needRefreshCerts) { - m_certificates = CertificateContainer(m_impl->getCertificatesOfKey(m_id, m_keyId), m_impl); - m_needRefreshCerts = false; - } - - return m_certificates; -} - -const v1::IdentityCertificate& -Key::setDefaultCertificate(const Name& certName) -{ - validityCheck(); - - m_defaultCertificate = m_impl->getCertificate(certName); - m_impl->setDefaultCertificateOfKey(m_id, m_keyId, certName); - m_hasDefaultCertificate = true; - return m_defaultCertificate; -} - -const v1::IdentityCertificate& -Key::setDefaultCertificate(const v1::IdentityCertificate& certificate) -{ - addCertificate(certificate); - return setDefaultCertificate(certificate.getName()); -} - -const v1::IdentityCertificate& -Key::getDefaultCertificate() const -{ - validityCheck(); - - if (!m_hasDefaultCertificate) { - m_defaultCertificate = m_impl->getDefaultCertificateOfKey(m_id, m_keyId); - m_hasDefaultCertificate = true; - } - - return m_defaultCertificate; -} - -Key::operator bool() const -{ - return !(this->operator!()); -} - -bool -Key::operator!() const -{ - return (m_impl == nullptr); -} - -void -Key::validityCheck() const -{ - if (m_impl == nullptr) - BOOST_THROW_EXCEPTION(std::domain_error("Invalid Key instance")); -} - -} // namespace security -} // namespace ndn diff --git a/src/security/key.hpp b/src/security/key.hpp deleted file mode 100644 index a237a38fe..000000000 --- a/src/security/key.hpp +++ /dev/null @@ -1,207 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_KEY_HPP -#define NDN_SECURITY_KEY_HPP - -#include "v1/identity-certificate.hpp" -#include "certificate-container.hpp" - -namespace ndn { -namespace security { - -class PibImpl; -class Identity; -class KeyContainer; - -/** - * @brief represents a key - * - * Key is at the second level in PIB's Identity-Key-Certificate hierarchy. - * An Key has a Name (identity + keyId), and contains one or more certificates, - * one of which is set as the default certificate of this key. A certificate - * can be directly accessed from a Key object. - * - * @throw PibImpl::Error when underlying implementation has non-semantic error. - */ -class Key -{ -public: - friend class Identity; - friend class KeyContainer; - friend class KeyChain; - -public: - /** - * @brief Default Constructor - * - * Key created using this default constructor is just a place holder. - * It must obtain an actual instance from Identity::getKey(...). A typical - * usage would be for exception handling: - * - * Key key; - * try { - * key = Identity.getKey(...); - * } - * catch (Pib::Error&) { - * ... - * } - * - * A Key instance created using the constructor is invalid. Calling a - * member method on an invalid Key instance may cause an std::domain_error. - */ - Key(); - - /// @brief Get the name of the key. - const Name& - getName() const; - - /// @brief Get the name of the belonging identity. - const Name& - getIdentity() const; - - /// @brief Get the key id of the key. - const name::Component& - getKeyId() const; - - /// @brief Get public key - const v1::PublicKey& - getPublicKey() const; - - /** - * @brief Get a certificate. - * - * @return the certificate - * @throws Pib::Error if the certificate does not exist. - */ - v1::IdentityCertificate - getCertificate(const Name& certName) const; - - /// @brief Get all the certificates for this key. - const CertificateContainer& - getCertificates() const; - - /** - * @brief Get the default certificate for this Key. - * - * @throws Pib::Error if the default certificate does not exist. - */ - const v1::IdentityCertificate& - getDefaultCertificate() const; - - /// @brief Check if the Key instance is valid - operator bool() const; - - /// @brief Check if the Key instance is invalid - bool - operator!() const; - -NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: // write operations should be private - - /** - * @brief Add a certificate. - * - * @param certificate The certificate to add. - */ - void - addCertificate(const v1::IdentityCertificate& certificate); - - /** - * @brief Remove a certificate. - * - * @param certName The name of the certificate to delete. - */ - void - removeCertificate(const Name& certName); - - /** - * @brief Set the default certificate. - * - * @param certName The name of the default certificate of the key. - * @return the default certificate - * @throws Pib::Error if the certificate does not exist. - */ - const v1::IdentityCertificate& - setDefaultCertificate(const Name& certName); - - /** - * @brief Set the default certificate. - * - * If the certificate does not exist, add it and set it as the default certificate of the key. - * If the certificate exists, simply set it as the default certificate of the key. - * - * @param certificate The certificate to add. - * @return the default certificate - */ - const v1::IdentityCertificate& - setDefaultCertificate(const v1::IdentityCertificate& certificate); - -NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: - /** - * @brief Create a Key with @p identityName and @p keyId. - * - * If the key/identity does not exist in the backend, create it in backend. - * - * @param identityName The name of the Identity. - * @param keyId The key id of the key. - * @param publicKey The public key to add. - * @param impl The actual backend implementation. - */ - Key(const Name& identityName, const name::Component& keyId, - const v1::PublicKey& publicKey, shared_ptr impl); - - /** - * @brief Create an KeyEntry with @p identityName and @p keyId. - * - * @param identityName The name of the Identity. - * @param keyId The key id of the key. - * @param impl The actual backend implementation. - * @throws Pib::Error if the key does not exist. - */ - Key(const Name& identityName, const name::Component& keyId, shared_ptr impl); - - /** - * @brief Check the validity of this instance - * - * @throws std::domain_error if the instance is invalid - */ - void - validityCheck() const; - -private: - Name m_id; - name::Component m_keyId; - Name m_keyName; - v1::PublicKey m_key; - - mutable bool m_hasDefaultCertificate; - mutable v1::IdentityCertificate m_defaultCertificate; - - mutable bool m_needRefreshCerts; - mutable CertificateContainer m_certificates; - - shared_ptr m_impl; -}; - -} // namespace security -} // namespace ndn - -#endif // NDN_SECURITY_PIB_HPP diff --git a/src/security/pib-impl.hpp b/src/security/pib-impl.hpp deleted file mode 100644 index d2b232475..000000000 --- a/src/security/pib-impl.hpp +++ /dev/null @@ -1,304 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_PIB_IMPL_HPP -#define NDN_SECURITY_PIB_IMPL_HPP - -#include -#include "v1/identity-certificate.hpp" - -namespace ndn { -namespace security { - -/** - * @brief Abstract class of PIB implementation - * - * This class defines the interface that an actual PIB (e.g., one based on sqlite3) - * implementation should provide. - */ -class PibImpl -{ -public: - /** - * @brief represents a non-semantic error - * - * A subclass of PibImpl may throw a subclass of this type when - * there's a non-semantic error, such as a storage problem. - */ - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - -public: - - virtual - ~PibImpl() - { - } - -public: // TpmLocator management - - /** - * @brief Set the corresponding TPM information to @p tpmLocator. - * - * If the provided @p tpmLocator is different from the existing one, the - * content in PIB will be cleaned up, otherwise nothing will be changed. - * - * @param tpmLocator The name for the new TPM locator - */ - virtual void - setTpmLocator(const std::string& tpmLocator) = 0; - - /** - * @brief Get TPM Locator - */ - virtual std::string - getTpmLocator() const = 0; - -public: // Identity management - - /** - * @brief Check the existence of an identity. - * - * @param identity The name of the identity. - * @return true if the identity exists, otherwise false. - */ - virtual bool - hasIdentity(const Name& identity) const = 0; - - /** - * @brief Add an identity. - * - * If the identity already exists, do nothing. - * If no default identity has been set, set the added one as default identity. - * - * @param identity The name of the identity to add. - */ - virtual void - addIdentity(const Name& identity) = 0; - - /** - * @brief Remove an identity - * - * If the identity does not exist, do nothing. - * Remove related keys and certificates as well. - * - * @param identity The name of the identity to remove. - */ - virtual void - removeIdentity(const Name& identity) = 0; - - /// @brief Get the name of all the identities - virtual std::set - getIdentities() const = 0; - - /** - * @brief Set an identity with name @p identityName as the default identity. - * - * Since adding an identity only requires the identity name, create the - * identity if it does not exist. - * - * @param identityName The name for the default identity. - */ - virtual void - setDefaultIdentity(const Name& identityName) = 0; - - /** - * @brief Get the default identity. - * - * @return The name for the default identity. - * @throws Pib::Error if no default identity. - */ - virtual Name - getDefaultIdentity() const = 0; - -public: // Key management - - /** - * @brief Check the existence of a key. - * - * @param identity The name of the belonged identity. - * @param keyId The key id component. - * @return true if the key exists, otherwise false. Return false if the identity does not exist - */ - virtual bool - hasKey(const Name& identity, const name::Component& keyId) const = 0; - - /** - * @brief Add a key. - * - * If the key already exists, do nothing. - * If the identity does not exist, add the identity as well. - * If no default key of the identity has been set, set the added one as default - * key of the identity. - * - * @param identity The name of the belonged identity. - * @param keyId The key id component. - * @param publicKey The public key bits. - */ - virtual void - addKey(const Name& identity, const name::Component& keyId, const v1::PublicKey& publicKey) = 0; - - /** - * @brief Remove a key. - * - * If the key does not exist, do nothing. - * Remove related certificates as well. - * - * @param identity The name of the belonged identity. - * @param keyId The key id component. - */ - virtual void - removeKey(const Name& identity, const name::Component& keyId) = 0; - - /** - * @brief Get the key bits of a key. - * - * @param identity The name of the belonged identity. - * @param keyId The key id component. - * @return key bits - * @throws Pib::Error if the key does not exist. - */ - virtual v1::PublicKey - getKeyBits(const Name& identity, const name::Component& keyId) const = 0; - - /** - * @brief Get all the key ids of an identity with name @p identity - * - * The returned key ids can be used to create a KeyContainer. - * With key id, identity name, backend implementation, one can create a Key frontend instance. - * - * @return the key id name component set. If the identity does not exist, return an empty set. - */ - virtual std::set - getKeysOfIdentity(const Name& identity) const = 0; - - /** - * @brief Set an key with id @p keyId as the default key of an identity with name @p identity. - * - * @param identity The name of the belonged identity. - * @param keyId The key id component. - * @throws Pib::Error if the key does not exist. - */ - virtual void - setDefaultKeyOfIdentity(const Name& identity, const name::Component& keyId) = 0; - - /** - * @brief Get the id of the default key of an identity with name @p identity. - * - * @param identity The name of the belonged identity. - * @throws Pib::Error if no default key or the identity does not exist. - */ - virtual name::Component - getDefaultKeyOfIdentity(const Name& identity) const = 0; - -public: // Certificate Management - - /** - * @brief Check the existence of a certificate with name @p certName. - * - * @param certName The name of the certificate. - * @return true if the certificate exists, otherwise false. - */ - virtual bool - hasCertificate(const Name& certName) const = 0; - - /** - * @brief Add a certificate. - * - * If the certificate already exists, do nothing. - * If the key or identity do not exist, add them as well. - * If no default certificate of the key has been set, set the added one as - * default certificate of the key. - * - * @param certificate The certificate to add. - */ - virtual void - addCertificate(const v1::IdentityCertificate& certificate) = 0; - - /** - * @brief Remove a certificate with name @p certName. - * - * If the certificate does not exist, do nothing. - * - * @param certName The name of the certificate. - */ - virtual void - removeCertificate(const Name& certName) = 0; - - /** - * @brief Get a certificate with name @p certName. - * - * @param certName The name of the certificate. - * @return the certificate. - * @throws Pib::Error if the certificate does not exist. - */ - virtual v1::IdentityCertificate - getCertificate(const Name& certName) const = 0; - - /** - * @brief Get a list of certificate names of a key with id @p keyId of @p identity. - * - * The returned certificate names can be used to create a CertificateContainer. - * With certificate name and backend implementation, one can obtain the certificate directly. - * - * @param identity The name of the belonging identity. - * @param keyId The key id. - * @return The certificate name set. If the key does not exist, return an empty set. - */ - virtual std::set - getCertificatesOfKey(const Name& identity, const name::Component& keyId) const = 0; - - /** - * @brief Set a cert with name @p certName as the default of a key with id @p keyId of @p identity. - * - * @param identity The name of the belonging identity. - * @param keyId The key id. - * @param certName The name of the certificate. - * @throws Pib::Error if the certificate with name @p certName does not exist. - */ - virtual void - setDefaultCertificateOfKey(const Name& identity, const name::Component& keyId, - const Name& certName) = 0; - - /** - * @brief Get the default certificate of a key with id @p keyId of @p identity. - * - * @param identity The name of the belonging identity. - * @param keyId The key id. - * @return a pointer to the certificate, null if no default certificate for the key. - * @throws Pib::Error if the default certificate does not exist. - */ - virtual v1::IdentityCertificate - getDefaultCertificateOfKey(const Name& identity, const name::Component& keyId) const = 0; - -}; - -} // namespace security -} // namespace ndn - -#endif // NDN_SECURITY_PIB_IMPL_HPP diff --git a/src/security/pib-memory.cpp b/src/security/pib-memory.cpp deleted file mode 100644 index c47286305..000000000 --- a/src/security/pib-memory.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "pib-memory.hpp" -#include "pib.hpp" - -namespace ndn { -namespace security { - -PibMemory::PibMemory() - : m_hasDefaultIdentity(false) -{ -} - -void -PibMemory::setTpmLocator(const std::string& tpmLocator) -{ - BOOST_THROW_EXCEPTION(Error("PibMemory does not need a locator")); -} - -std::string -PibMemory::getTpmLocator() const -{ - return "tpm-memory:"; -} - -bool -PibMemory::hasIdentity(const Name& identity) const -{ - return (m_identities.count(identity) > 0); -} - -void -PibMemory::addIdentity(const Name& identity) -{ - m_identities.insert(identity); - - if (!m_hasDefaultIdentity) { - m_defaultIdentity = identity; - m_hasDefaultIdentity = true; - } -} - -void -PibMemory::removeIdentity(const Name& identity) -{ - m_identities.erase(identity); - if (identity == m_defaultIdentity) - m_hasDefaultIdentity = false; - - auto keyIds = this->getKeysOfIdentity(identity); - for (const name::Component& keyId : keyIds) { - this->removeKey(identity, keyId); - } -} - -std::set -PibMemory::getIdentities() const -{ - return m_identities; -} - -void -PibMemory::setDefaultIdentity(const Name& identityName) -{ - addIdentity(identityName); - m_defaultIdentity = identityName; - m_hasDefaultIdentity = true; -} - -Name -PibMemory::getDefaultIdentity() const -{ - if (m_hasDefaultIdentity) - return m_defaultIdentity; - - BOOST_THROW_EXCEPTION(Pib::Error("No default identity")); -} - -bool -PibMemory::hasKey(const Name& identity, const name::Component& keyId) const -{ - return (m_keys.count(getKeyName(identity, keyId)) > 0); -} - -void -PibMemory::addKey(const Name& identity, const name::Component& keyId, const v1::PublicKey& publicKey) -{ - this->addIdentity(identity); - - Name keyName = getKeyName(identity, keyId); - m_keys[keyName] = publicKey; - - if (m_defaultKey.find(identity) == m_defaultKey.end()) - m_defaultKey[identity] = keyName; -} - -void -PibMemory::removeKey(const Name& identity, const name::Component& keyId) -{ - Name keyName = getKeyName(identity, keyId); - m_keys.erase(keyName); - m_defaultKey.erase(identity); - - - auto certNames = this->getCertificatesOfKey(identity, keyId); - for (const auto& certName : certNames) { - this->removeCertificate(certName); - } -} - -v1::PublicKey -PibMemory::getKeyBits(const Name& identity, const name::Component& keyId) const -{ - if (!hasKey(identity, keyId)) - BOOST_THROW_EXCEPTION(Pib::Error("No key")); - - auto it = m_keys.find(getKeyName(identity, keyId)); - return it->second; -} - -std::set -PibMemory::getKeysOfIdentity(const Name& identity) const -{ - std::set ids; - for (const auto& it : m_keys) { - if (identity == it.first.getPrefix(-1)) - ids.insert(it.first.get(-1)); - } - return ids; -} - -void -PibMemory::setDefaultKeyOfIdentity(const Name& identity, const name::Component& keyId) -{ - Name keyName = getKeyName(identity, keyId); - - if (!hasKey(identity, keyId)) - BOOST_THROW_EXCEPTION(Pib::Error("No key")); - - m_defaultKey[identity] = keyName; -} - -name::Component -PibMemory::getDefaultKeyOfIdentity(const Name& identity) const -{ - auto it = m_defaultKey.find(identity); - if (it == m_defaultKey.end()) - BOOST_THROW_EXCEPTION(Pib::Error("No default key")); - - return it->second.get(-1); -} - -Name -PibMemory::getKeyName(const Name& identity, const name::Component& keyId) const -{ - Name keyName = identity; - keyName.append(keyId); - return keyName; -} - -bool -PibMemory::hasCertificate(const Name& certName) const -{ - return (m_certs.count(certName) > 0); -} - -void -PibMemory::addCertificate(const v1::IdentityCertificate& certificate) -{ - this->addKey(certificate.getPublicKeyName().getPrefix(-1), - certificate.getPublicKeyName().get(-1), - certificate.getPublicKeyInfo()); - - m_certs[certificate.getName()] = certificate; - - const Name& keyName = certificate.getPublicKeyName(); - if (m_defaultCert.find(keyName) == m_defaultCert.end()) - m_defaultCert[keyName] = certificate.getName(); -} - -void -PibMemory::removeCertificate(const Name& certName) -{ - m_certs.erase(certName); - m_defaultCert.erase(v1::IdentityCertificate::certificateNameToPublicKeyName(certName)); -} - -v1::IdentityCertificate -PibMemory::getCertificate(const Name& certName) const -{ - if (!hasCertificate(certName)) - BOOST_THROW_EXCEPTION(Pib::Error("No cert")); - - auto it = m_certs.find(certName); - return it->second; -} - -std::set -PibMemory::getCertificatesOfKey(const Name& identity, const name::Component& keyId) const -{ - Name keyName = getKeyName(identity, keyId); - - std::set certNames; - for (const auto& it : m_certs) { - if (it.second.getPublicKeyName() == keyName) - certNames.insert(it.first); - } - return certNames; -} - -void -PibMemory::setDefaultCertificateOfKey(const Name& identity, const name::Component& keyId, const Name& certName) -{ - if (!hasCertificate(certName)) - BOOST_THROW_EXCEPTION(Pib::Error("No cert")); - - Name keyName = getKeyName(identity, keyId); - m_defaultCert[keyName] = certName; -} - -v1::IdentityCertificate -PibMemory::getDefaultCertificateOfKey(const Name& identity, const name::Component& keyId) const -{ - Name keyName = getKeyName(identity, keyId); - - auto it = m_defaultCert.find(keyName); - if (it == m_defaultCert.end()) - BOOST_THROW_EXCEPTION(Pib::Error("No default certificate")); - - auto certIt = m_certs.find(it->second); - if (certIt == m_certs.end()) - BOOST_THROW_EXCEPTION(Pib::Error("No default certificate")); - else - return certIt->second; -} - -} // namespace security -} // namespace ndn diff --git a/src/security/pib-memory.hpp b/src/security/pib-memory.hpp deleted file mode 100644 index 1a859ce16..000000000 --- a/src/security/pib-memory.hpp +++ /dev/null @@ -1,153 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_PIB_MEMORY_HPP -#define NDN_SECURITY_PIB_MEMORY_HPP - -#include "pib-impl.hpp" - -namespace ndn { -namespace security { - -/** - * @brief An in-memory implementation of Pib - * - * All the contents in Pib are stored in memory - * and have the same lifetime as the implementation instance. - */ -class PibMemory : public PibImpl -{ -public: - class Error : public PibImpl::Error - { - public: - explicit - Error(const std::string& what) - : PibImpl::Error(what) - { - } - }; - -public: - PibMemory(); - -public: // TpmLocator management - - virtual void - setTpmLocator(const std::string& tpmLocator) override; - - virtual std::string - getTpmLocator() const override; - -public: // Identity management - - virtual bool - hasIdentity(const Name& identity) const override; - - virtual void - addIdentity(const Name& identity) override; - - virtual void - removeIdentity(const Name& identity) override; - - virtual std::set - getIdentities() const override; - - virtual void - setDefaultIdentity(const Name& identityName) override; - - virtual Name - getDefaultIdentity() const override; - -public: // Key management - - virtual bool - hasKey(const Name& identity, const name::Component& keyId) const override; - - virtual void - addKey(const Name& identity, const name::Component& keyId, const v1::PublicKey& publicKey) override; - - virtual void - removeKey(const Name& identity, const name::Component& keyId) override; - - virtual v1::PublicKey - getKeyBits(const Name& identity, const name::Component& keyId) const override; - - virtual std::set - getKeysOfIdentity(const Name& identity) const override; - - virtual void - setDefaultKeyOfIdentity(const Name& identity, const name::Component& keyId) override; - - virtual name::Component - getDefaultKeyOfIdentity(const Name& identity) const override; - -public: // Certificate management - - virtual bool - hasCertificate(const Name& certName) const override; - - virtual void - addCertificate(const v1::IdentityCertificate& certificate) override; - - virtual void - removeCertificate(const Name& certName) override; - - virtual v1::IdentityCertificate - getCertificate(const Name& certName) const override; - - virtual std::set - getCertificatesOfKey(const Name& identity, const name::Component& keyId) const override; - - virtual void - setDefaultCertificateOfKey(const Name& identity, const name::Component& keyId, const Name& certName) override; - - virtual v1::IdentityCertificate - getDefaultCertificateOfKey(const Name& identity, const name::Component& keyId) const override; - -private: // Key management - - Name - getKeyName(const Name& identity, const name::Component& keyId) const; - -private: - - std::set m_identities; - bool m_hasDefaultIdentity; - Name m_defaultIdentity; - - /// @brief keyName => keyBits - std::map m_keys; - - /// @brief identity => default key Name - std::map m_defaultKey; - - /// @brief certificate Name => certificate - std::map m_certs; - - /// @brief keyName => default certificate Name - std::map m_defaultCert; -}; - -} // namespace security -} // namespace ndn - -#endif // NDN_SECURITY_PIB_MEMORY_HPP diff --git a/src/security/pib-sqlite3.cpp b/src/security/pib-sqlite3.cpp deleted file mode 100644 index dc21610ae..000000000 --- a/src/security/pib-sqlite3.cpp +++ /dev/null @@ -1,565 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "pib-sqlite3.hpp" - -#include "common.hpp" -#include "pib.hpp" -#include "util/sqlite3-statement.hpp" - -#include -#include -#include - -namespace ndn { -namespace security { - -using std::string; -using util::Sqlite3Statement; - -static const string INITIALIZATION = - "CREATE TABLE IF NOT EXISTS \n" - " tpmInfo( \n" - " tpm_locator BLOB \n" - " ); \n" - " \n" - "CREATE TRIGGER IF NOT EXISTS \n" - " tpm_update_trigger \n" - " BEFORE UPDATE ON tpmInfo \n" - " WHEN NEW.tpm_locator!=OLD.tpm_locator \n" - " BEGIN \n" - " DELETE FROM certificates; \n" - " DELETE FROM keys; \n" - " DELETE FROM identities; \n" - " END; \n" - " \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" - " \n" - "CREATE UNIQUE INDEX IF NOT EXISTS \n" - " identityIndex ON identities(identity); \n" - " \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" - " \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" - " \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" - " \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" - " \n" - "CREATE UNIQUE INDEX IF NOT EXISTS \n" - " keyIndex ON keys(key_name); \n" - " \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" - " \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" - " \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" - " \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" - " \n" - "CREATE UNIQUE INDEX IF NOT EXISTS \n" - " certIndex ON certificates(certificate_name);\n" - " \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" - " \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" - " \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"; - -static Name -getKeyName(const Name& identity, const name::Component& keyId) -{ - Name keyName = identity; - keyName.append(keyId); - return keyName; -} - -PibSqlite3::PibSqlite3(const string& dir) -{ - // Determine the path of PIB DB - boost::filesystem::path actualDir; - if (dir == "") { -#ifdef NDN_CXX_HAVE_TESTS - if (getenv("TEST_HOME") != nullptr) { - actualDir = boost::filesystem::path(getenv("TEST_HOME")) / ".ndn"; - } - else -#endif // NDN_CXX_HAVE_TESTS - if (getenv("HOME") != nullptr) { - actualDir = boost::filesystem::path(getenv("HOME")) / ".ndn"; - } - else { - actualDir = boost::filesystem::path(".") / ".ndn"; - } - } - else { - actualDir = boost::filesystem::path(dir); - } - boost::filesystem::create_directories(actualDir); - - // Open PIB - int result = sqlite3_open_v2((actualDir / "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) - BOOST_THROW_EXCEPTION(PibImpl::Error("PIB DB cannot be opened/created: " + dir)); - - - // enable foreign key - sqlite3_exec(m_database, "PRAGMA foreign_keys=ON", nullptr, nullptr, nullptr); - - // initialize PIB tables - char* errorMessage = nullptr; - result = sqlite3_exec(m_database, INITIALIZATION.c_str(), nullptr, nullptr, &errorMessage); - if (result != SQLITE_OK && errorMessage != nullptr) { - sqlite3_free(errorMessage); - BOOST_THROW_EXCEPTION(PibImpl::Error("PIB DB cannot be initialized")); - } -} - -PibSqlite3::~PibSqlite3() -{ - sqlite3_close(m_database); -} - -void -PibSqlite3::setTpmLocator(const std::string& tpmLocator) -{ - Sqlite3Statement statement(m_database, "UPDATE tpmInfo SET tpm_locator=?"); - statement.bind(1, tpmLocator, SQLITE_TRANSIENT); - statement.step(); - - // no row is updated, tpm_locator does not exist, insert it directly - if (0 == sqlite3_changes(m_database)) { - Sqlite3Statement insertStatement(m_database, "INSERT INTO tpmInfo (tpm_locator) values (?)"); - insertStatement.bind(1, tpmLocator, SQLITE_TRANSIENT); - insertStatement.step(); - } -} - -std::string -PibSqlite3::getTpmLocator() const -{ - Sqlite3Statement statement(m_database, "SELECT tpm_locator FROM tpmInfo"); - int res = statement.step(); - - string tpmLocator; - if (res == SQLITE_ROW) - return statement.getString(0); - else - BOOST_THROW_EXCEPTION(Pib::Error("TPM info does not exist")); -} - -bool -PibSqlite3::hasIdentity(const Name& identity) const -{ - Sqlite3Statement statement(m_database, "SELECT id FROM identities WHERE identity=?"); - statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT); - return (statement.step() == SQLITE_ROW); -} - -void -PibSqlite3::addIdentity(const Name& identity) -{ - Sqlite3Statement statement(m_database, "INSERT INTO identities (identity) values (?)"); - statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT); - statement.step(); -} - -void -PibSqlite3::removeIdentity(const Name& identity) -{ - Sqlite3Statement statement(m_database, "DELETE FROM identities WHERE identity=?"); - statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT); - statement.step(); -} - -std::set -PibSqlite3::getIdentities() const -{ - std::set identities; - Sqlite3Statement statement(m_database, "SELECT identity FROM identities"); - - while (statement.step() == SQLITE_ROW) - identities.insert(Name(statement.getBlock(0))); - - return identities; -} - -void -PibSqlite3::setDefaultIdentity(const Name& identityName) -{ - Sqlite3Statement statement(m_database, "UPDATE identities SET is_default=1 WHERE identity=?"); - statement.bind(1, identityName.wireEncode(), SQLITE_TRANSIENT); - statement.step(); -} - -Name -PibSqlite3::getDefaultIdentity() const -{ - Sqlite3Statement statement(m_database, "SELECT identity FROM identities WHERE is_default=1"); - - if (statement.step() == SQLITE_ROW) - return Name(statement.getBlock(0)); - else - BOOST_THROW_EXCEPTION(Pib::Error("No default identity")); -} - -bool -PibSqlite3::hasKey(const Name& identity, const name::Component& keyId) const -{ - Name keyName = getKeyName(identity, keyId); - - Sqlite3Statement statement(m_database, "SELECT id FROM keys WHERE key_name=?"); - statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT); - - return (statement.step() == SQLITE_ROW); -} - -void -PibSqlite3::addKey(const Name& identity, const name::Component& keyId, const v1::PublicKey& publicKey) -{ - if (hasKey(identity, keyId)) { - return; - } - - // ensure identity exists - addIdentity(identity); - - // add key - Name keyName = getKeyName(identity, keyId); - - Sqlite3Statement statement(m_database, - "INSERT INTO keys (identity_id, key_name, key_type, key_bits) " - "VALUES ((SELECT id FROM identities WHERE identity=?), ?, ?, ?)"); - statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT); - statement.bind(2, keyName.wireEncode(), SQLITE_TRANSIENT); - statement.bind(3, static_cast(publicKey.getKeyType())); - statement.bind(4, publicKey.get().buf(), publicKey.get().size(), SQLITE_STATIC); - statement.step(); -} - -void -PibSqlite3::removeKey(const Name& identity, const name::Component& keyId) -{ - Name keyName = getKeyName(identity, keyId); - - Sqlite3Statement statement(m_database, "DELETE FROM keys WHERE key_name=?"); - statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT); - statement.step(); -} - -v1::PublicKey -PibSqlite3::getKeyBits(const Name& identity, const name::Component& keyId) const -{ - Name keyName = getKeyName(identity, keyId); - - Sqlite3Statement statement(m_database, "SELECT key_bits FROM keys WHERE key_name=?"); - statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT); - - if (statement.step() == SQLITE_ROW) - return v1::PublicKey(statement.getBlob(0), statement.getSize(0)); - else - BOOST_THROW_EXCEPTION(Pib::Error("Key does not exist")); -} - -std::set -PibSqlite3::getKeysOfIdentity(const Name& identity) const -{ - std::set keyNames; - - Sqlite3Statement statement(m_database, - "SELECT key_name " - "FROM keys JOIN identities ON keys.identity_id=identities.id " - "WHERE identities.identity=?"); - statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT); - - while (statement.step() == SQLITE_ROW) { - Name keyName(statement.getBlock(0)); - keyNames.insert(keyName.get(-1)); - } - - return keyNames; -} - -void -PibSqlite3::setDefaultKeyOfIdentity(const Name& identity, const name::Component& keyId) -{ - Name keyName = getKeyName(identity, keyId); - - if (!hasKey(identity, keyId)) { - BOOST_THROW_EXCEPTION(Pib::Error("No such key")); - } - - Sqlite3Statement statement(m_database, "UPDATE keys SET is_default=1 WHERE key_name=?"); - statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT); - statement.step(); -} - -name::Component -PibSqlite3::getDefaultKeyOfIdentity(const Name& identity) const -{ - if (!hasIdentity(identity)) { - BOOST_THROW_EXCEPTION(Pib::Error("Identity does not exist")); - } - - Sqlite3Statement statement(m_database, - "SELECT key_name " - "FROM keys JOIN identities ON keys.identity_id=identities.id " - "WHERE identities.identity=? AND keys.is_default=1"); - statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT); - - if (statement.step() == SQLITE_ROW) { - Name keyName(statement.getBlock(0)); - return keyName.get(-1); - } - else - BOOST_THROW_EXCEPTION(Pib::Error("No default key")); -} - -bool -PibSqlite3::hasCertificate(const Name& certName) const -{ - Sqlite3Statement statement(m_database, "SELECT id FROM certificates WHERE certificate_name=?"); - statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT); - return (statement.step() == SQLITE_ROW); -} - -void -PibSqlite3::addCertificate(const v1::IdentityCertificate& certificate) -{ - const Name& certName = certificate.getName(); - const Name& keyName = certificate.getPublicKeyName(); - - name::Component keyId = keyName.get(-1); - Name identityName = keyName.getPrefix(-1); - - // ensure key exists - addKey(identityName, keyId, certificate.getPublicKeyInfo()); - - Sqlite3Statement statement(m_database, - "INSERT INTO certificates " - "(key_id, certificate_name, certificate_data) " - "VALUES ((SELECT id FROM keys WHERE key_name=?), ?, ?)"); - statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT); - statement.bind(2, certName.wireEncode(), SQLITE_TRANSIENT); - statement.bind(3, certificate.wireEncode(), SQLITE_STATIC); - statement.step(); -} - -void -PibSqlite3::removeCertificate(const Name& certName) -{ - Sqlite3Statement statement(m_database, "DELETE FROM certificates WHERE certificate_name=?"); - statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT); - statement.step(); -} - -v1::IdentityCertificate -PibSqlite3::getCertificate(const Name& certName) const -{ - Sqlite3Statement statement(m_database, - "SELECT certificate_data FROM certificates WHERE certificate_name=?"); - statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT); - - if (statement.step() == SQLITE_ROW) - return v1::IdentityCertificate(statement.getBlock(0)); - else - BOOST_THROW_EXCEPTION(Pib::Error("Certificate does not exit")); -} - -std::set -PibSqlite3::getCertificatesOfKey(const Name& identity, const name::Component& keyId) const -{ - std::set certNames; - - Name keyName = getKeyName(identity, keyId); - - Sqlite3Statement statement(m_database, - "SELECT certificate_name " - "FROM certificates JOIN keys ON certificates.key_id=keys.id " - "WHERE keys.key_name=?"); - statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT); - - while (statement.step() == SQLITE_ROW) - certNames.insert(Name(statement.getBlock(0))); - - return certNames; -} - -void -PibSqlite3::setDefaultCertificateOfKey(const Name& identity, const name::Component& keyId, - const Name& certName) -{ - if (!hasCertificate(certName)) { - BOOST_THROW_EXCEPTION(Pib::Error("Certificate does not exist")); - } - - Sqlite3Statement statement(m_database, - "UPDATE certificates SET is_default=1 WHERE certificate_name=?"); - statement.bind(1, certName.wireEncode(), SQLITE_TRANSIENT); - statement.step(); -} - -v1::IdentityCertificate -PibSqlite3::getDefaultCertificateOfKey(const Name& identity, const name::Component& keyId) const -{ - Name keyName = getKeyName(identity, keyId); - - Sqlite3Statement statement(m_database, - "SELECT certificate_data " - "FROM certificates JOIN keys ON certificates.key_id=keys.id " - "WHERE certificates.is_default=1 AND keys.key_name=?"); - statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT); - - if (statement.step() == SQLITE_ROW) - return v1::IdentityCertificate(statement.getBlock(0)); - else - BOOST_THROW_EXCEPTION(Pib::Error("Certificate does not exit")); -} - -} // namespace security -} // namespace ndn diff --git a/src/security/pib-sqlite3.hpp b/src/security/pib-sqlite3.hpp deleted file mode 100644 index f8665c50f..000000000 --- a/src/security/pib-sqlite3.hpp +++ /dev/null @@ -1,143 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITTY_PIB_SQLITE3_HPP -#define NDN_SECURITTY_PIB_SQLITE3_HPP - -#include "pib-impl.hpp" - -struct sqlite3; - -namespace ndn { -namespace security { - -/** - * @brief Pib backend implementation based on SQLite3 database - * - * All the contents in Pib are stored in a SQLite3 database file. - * This backend provides more persistent storage than PibMemory. - */ -class PibSqlite3 : public PibImpl -{ -public: - /** - * @brief Constructor of PibSqlite3 - * - * This method will create a SQLite3 database file under the directory @p dir. - * If the directory does not exist, it will be created automatically. - * It assumes that the directory does not contain a PIB database of an older version, - * It is user's responsibility to update the older version database or remove the database. - * - * @param dir The directory where the database file is located. By default, it points to the - * $HOME/.ndn directory. - * @throws PibImpl::Error when initialization fails. - */ - explicit - PibSqlite3(const std::string& dir = ""); - - /** - * @brief Destruct and cleanup internal state - */ - ~PibSqlite3(); - -public: // TpmLocator management - - virtual void - setTpmLocator(const std::string& tpmLocator) final; - - virtual std::string - getTpmLocator() const final; - -public: // Identity management - - virtual bool - hasIdentity(const Name& identity) const final; - - virtual void - addIdentity(const Name& identity) final; - - virtual void - removeIdentity(const Name& identity) final; - - virtual std::set - getIdentities() const final; - - virtual void - setDefaultIdentity(const Name& identityName) final; - - virtual Name - getDefaultIdentity() const final; - -public: // Key management - - virtual bool - hasKey(const Name& identity, const name::Component& keyId) const final; - - virtual void - addKey(const Name& identity, const name::Component& keyId, const v1::PublicKey& publicKey) final; - - virtual void - removeKey(const Name& identity, const name::Component& keyId) final; - - virtual v1::PublicKey - getKeyBits(const Name& identity, const name::Component& keyId) const final; - - virtual std::set - getKeysOfIdentity(const Name& identity) const final; - - virtual void - setDefaultKeyOfIdentity(const Name& identity, const name::Component& keyId) final; - - virtual name::Component - getDefaultKeyOfIdentity(const Name& identity) const final; - -public: // Certificate Management - - virtual bool - hasCertificate(const Name& certName) const final; - - virtual void - addCertificate(const v1::IdentityCertificate& certificate) final; - - virtual void - removeCertificate(const Name& certName) final; - - virtual v1::IdentityCertificate - getCertificate(const Name& certName) const final; - - virtual std::set - getCertificatesOfKey(const Name& identity, const name::Component& keyId) const final; - - virtual void - setDefaultCertificateOfKey(const Name& identity, const name::Component& keyId, - const Name& certName) final; - - virtual v1::IdentityCertificate - getDefaultCertificateOfKey(const Name& identity, const name::Component& keyId) const final; - -private: - sqlite3* m_database; -}; - -} // namespace security -} // namespace ndn - -#endif // NDN_SECURITTY_PIB_SQLITE3_HPP diff --git a/src/security/pib.cpp b/src/security/pib.cpp deleted file mode 100644 index df366c986..000000000 --- a/src/security/pib.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "pib.hpp" -#include "pib-impl.hpp" - -namespace ndn { -namespace security { - -Pib::Pib(const std::string scheme, const std::string& location, shared_ptr impl) - : m_scheme(scheme) - , m_location(location) - , m_hasDefaultIdentity(false) - , m_needRefreshIdentities(true) - , m_impl(impl) -{ -} - -Pib::~Pib() -{ -} - -std::string -Pib::getPibLocator() const -{ - return m_scheme + ":" + m_location; -} - -void -Pib::setTpmLocator(const std::string& tpmLocator) -{ - m_impl->setTpmLocator(tpmLocator); -} - -std::string -Pib::getTpmLocator() const -{ - return m_impl->getTpmLocator(); -} - -Identity -Pib::addIdentity(const Name& identity) -{ - if (!m_needRefreshIdentities && m_identities.find(identity) == m_identities.end()) { - // if we have already loaded all the identities, but the new identity is not one of them - // the IdentityContainer should be refreshed - m_needRefreshIdentities = true; - } - return Identity(identity, m_impl, true); -} - -void -Pib::removeIdentity(const Name& identity) -{ - if (m_hasDefaultIdentity && m_defaultIdentity.getName() == identity) - m_hasDefaultIdentity = false; - - m_impl->removeIdentity(identity); - m_needRefreshIdentities = true; -} - -Identity -Pib::getIdentity(const Name& identity) const -{ - return Identity(identity, m_impl, false); -} - -const IdentityContainer& -Pib::getIdentities() const -{ - if (m_needRefreshIdentities) { - m_identities = IdentityContainer(m_impl->getIdentities(), m_impl); - m_needRefreshIdentities = false; - } - - return m_identities; -} - -Identity& -Pib::setDefaultIdentity(const Name& identityName) -{ - m_defaultIdentity = addIdentity(identityName); - m_hasDefaultIdentity = true; - - m_impl->setDefaultIdentity(identityName); - return m_defaultIdentity; -} - -Identity& -Pib::getDefaultIdentity() const -{ - if (!m_hasDefaultIdentity) { - m_defaultIdentity = Identity(m_impl->getDefaultIdentity(), m_impl, false); - m_hasDefaultIdentity = true; - } - - return m_defaultIdentity; -} - - -} // namespace security -} // namespace ndn diff --git a/src/security/pib.hpp b/src/security/pib.hpp deleted file mode 100644 index 1fd200612..000000000 --- a/src/security/pib.hpp +++ /dev/null @@ -1,187 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_PIB_HPP -#define NDN_SECURITY_PIB_HPP - -#include "identity-container.hpp" - -namespace ndn { -namespace security { - -class KeyChain; -class PibImpl; - -/** - * @brief represents the PIB - * - * The PIB (Public Information Base) stores the public portion of a user's cryptography keys. - * The format and location of stored information is indicated by the PibLocator. - * The PIB is designed to work with a TPM (Trusted Platform Module) which stores private keys. - * There is a one-to-one association between PIB and TPM, and therefore the TpmLocator is recorded - * by the PIB to enforce this association and prevent one from operating on mismatched PIB and TPM. - * - * Information in the PIB is organized in a hierarchy of Identity-Key-Certificate. At the top level, - * the Pib class provides access to identities, and allows setting a default identity. Properties of - * an identity can be accessed after obtaining an Identity object. - * - * @throw PibImpl::Error when underlying implementation has non-semantic error. - */ -class Pib : noncopyable -{ -public: - friend class KeyChain; - -public: - /// @brief represents a semantic error - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - -public: - - ~Pib(); - - /** - * @brief return the scheme of the PibLocator - */ - std::string - getScheme() const - { - return m_scheme; - } - - /** - * @brief Get PIB Locator - */ - std::string - getPibLocator() const; - - /** - * @brief Set the corresponding TPM information to @p tpmLocator. - * - * If the provided @p tpmLocator is different from the existing one, the - * PIB will be reset, otherwise nothing will be changed. - * - * @param tpmLocator The name for the new TPM locator - */ - void - setTpmLocator(const std::string& tpmLocator); - - /** - * @brief Get TPM Locator - */ - std::string - getTpmLocator() const; - - /** - * @brief Get an identity with name @p identityName. - * - * @param identityName The name for the identity to get. - * @throw Pib::Error if the identity does not exist. - */ - Identity - getIdentity(const Name& identityName) const; - - /// @brief Get all the identities - const IdentityContainer& - getIdentities() const; - - /** - * @brief Get the default identity. - * - * @return the default identity. - * @throws Pib::Error if no default identity. - */ - Identity& - getDefaultIdentity() const; - -NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: // write operations should be private - - /* - * @brief Create an identity with name @p identityName and return a reference to it. - * - * If there already exists an identity for the name @p identityName, then it is returned. - * If no default identity is set, the newly created identity will be set as the default. - * - * @param identityName The name for the identity to be added - */ - Identity - addIdentity(const Name& identityName); - - /* - * @brief Remove an identity with name @p identityName. - * - * @param identityName The name for the identity to be deleted - */ - void - removeIdentity(const Name& identityName); - - /** - * @brief Set an identity with name @p identityName as the default identity. - * - * Also create the identity if it does not exist. - * - * @param identityName The name for the default identity. - * @return the default identity - */ - Identity& - setDefaultIdentity(const Name& identityName); - -NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: - /* - * @brief Create a new Pib with the specified @p location - * - * @param scheme The scheme for the Pib - * @param location The location for the Pib - * @param impl The backend implementation - */ - Pib(const std::string scheme, const std::string& location, shared_ptr impl); - - shared_ptr - getImpl() - { - return m_impl; - } - -protected: - std::string m_scheme; - std::string m_location; - - mutable bool m_hasDefaultIdentity; - mutable Identity m_defaultIdentity; - - mutable bool m_needRefreshIdentities; - mutable IdentityContainer m_identities; - - shared_ptr m_impl; -}; - -} // namespace security -} // namespace ndn - -#endif // NDN_SECURITY_PIB_HPP diff --git a/src/security/public-key.hpp b/src/security/public-key.hpp deleted file mode 100644 index 8e1a09b8f..000000000 --- a/src/security/public-key.hpp +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** - * @file security/public-key.hpp - * @deprecated Use security/v1/public-key.hpp - */ - -#include "security-common.hpp" - -#ifdef NDN_CXX_KEEP_SECURITY_V1_ALIASES -#include "v1/public-key.hpp" -#else -#error "Deprecated. Use `v1/public-key.hpp` instead." -#endif // NDN_CXX_KEEP_SECURITY_V1_ALIASES diff --git a/src/security/safe-bag.cpp b/src/security/safe-bag.cpp deleted file mode 100644 index 448847a02..000000000 --- a/src/security/safe-bag.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Zhiyi Zhang - */ -#include "safe-bag.hpp" -#include "encoding/tlv-security.hpp" -#include "util/concepts.hpp" - -namespace ndn { -namespace security { - -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireDecodable)); - -SafeBag::SafeBag() = default; - -SafeBag::SafeBag(const Block& wire) -{ - this->wireDecode(wire); -} - -SafeBag::SafeBag(const Data& certificate, - const Buffer& encryptedKeyBag) - : m_certificate(certificate) - , m_encryptedKeyBag(encryptedKeyBag) -{ -} - -SafeBag::SafeBag(const Data& certificate, - const uint8_t* encryptedKey, - size_t encryptedKeyLen) - : m_certificate(certificate) - , m_encryptedKeyBag(encryptedKey, encryptedKeyLen) -{ -} - -///////////////////////////////////////////////////// encode & decode - -template -size_t -SafeBag::wireEncode(EncodingImpl& encoder) const -{ - size_t totalLength = 0; - - // EncryptedKeyBag - totalLength += encoder.prependByteArrayBlock(tlv::security::EncryptedKeyBag, - m_encryptedKeyBag.get(), - m_encryptedKeyBag.size()); - - // Certificate - totalLength += this->m_certificate.wireEncode(encoder); - - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::security::SafeBag); - - return totalLength; -} - -template size_t -SafeBag::wireEncode(EncodingImpl& encoder) const; - -template size_t -SafeBag::wireEncode(EncodingImpl& encoder) const; - -const Block& -SafeBag::wireEncode() const -{ - EncodingEstimator estimator; - size_t estimatedSize = wireEncode(estimator); - - EncodingBuffer buffer(estimatedSize, 0); - wireEncode(buffer); - - this->m_wire = buffer.block(); - return m_wire; -} - -void -SafeBag::wireDecode(const Block& wire) -{ - if (wire.type() != tlv::security::SafeBag) - BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding safebag")); - - this->m_wire = wire; - m_wire.parse(); - - Block::element_const_iterator it = m_wire.elements_begin(); - - // Certificate must be the first part - if (it != m_wire.elements_end()) { - this->m_certificate.wireDecode(*it); - it++; - } - else - BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV structure when decoding certificate")); - - // EncryptedKeyBag - if (it != m_wire.elements_end() && it->type() == tlv::security::EncryptedKeyBag) { - this->m_encryptedKeyBag = Buffer(it->value(), it->value_size()); - it++; - } - else - BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV structure when decoding encryptedkeybag")); - - // Check if end - if (it != m_wire.elements_end()) - BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV structure after decoding the block")); -} - -} // namespace security -} // namespace ndn diff --git a/src/security/sec-public-info-sqlite3.cpp b/src/security/sec-public-info-sqlite3.cpp deleted file mode 100644 index b392ba11d..000000000 --- a/src/security/sec-public-info-sqlite3.cpp +++ /dev/null @@ -1,956 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - * @author Jeff Thompson - */ - -#include "sec-public-info-sqlite3.hpp" -#include "v1/identity-certificate.hpp" -#include "signature-sha256-with-rsa.hpp" -#include "signature-sha256-with-ecdsa.hpp" -#include "../data.hpp" - -#include -#include -#include -#include -#include -#include - -namespace ndn { -namespace security { - -using std::string; -using std::vector; - -const std::string SecPublicInfoSqlite3::SCHEME("pib-sqlite3"); - -static const string INIT_TPM_INFO_TABLE = - "CREATE TABLE IF NOT EXISTS " - " TpmInfo( " - " tpm_locator BLOB NOT NULL," - " PRIMARY KEY (tpm_locator) " - " ); "; - -static const string INIT_ID_TABLE = - "CREATE TABLE IF NOT EXISTS " - " Identity( " - " identity_name BLOB NOT NULL, " - " default_identity INTEGER DEFAULT 0, " - " PRIMARY KEY (identity_name) " - " ); " - "CREATE INDEX identity_index ON Identity(identity_name);"; - -static const string INIT_KEY_TABLE = - "CREATE TABLE IF NOT EXISTS " - " Key( " - " identity_name BLOB NOT NULL, " - " key_identifier BLOB NOT NULL, " - " key_type INTEGER, " - " public_key BLOB, " - " default_key INTEGER DEFAULT 0, " - " active INTEGER DEFAULT 0, " - " PRIMARY KEY (identity_name, key_identifier)" - " ); " - "CREATE INDEX key_index ON Key(identity_name); "; - - -static const string INIT_CERT_TABLE = - "CREATE TABLE IF NOT EXISTS " - " Certificate( " - " cert_name BLOB NOT NULL, " - " cert_issuer BLOB NOT NULL, " - " identity_name BLOB NOT NULL, " - " key_identifier BLOB NOT NULL, " - " not_before TIMESTAMP, " - " not_after TIMESTAMP, " - " certificate_data BLOB NOT NULL, " - " valid_flag INTEGER DEFAULT 1, " - " default_cert INTEGER DEFAULT 0, " - " PRIMARY KEY (cert_name) " - " ); " - "CREATE INDEX cert_index ON Certificate(cert_name); " - "CREATE INDEX subject ON Certificate(identity_name);"; - -/** - * 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); -} - -static string -sqlite3_column_string(sqlite3_stmt* statement, int column) -{ - return string(reinterpret_cast(sqlite3_column_text(statement, column)), - sqlite3_column_bytes(statement, column)); -} - -SecPublicInfoSqlite3::SecPublicInfoSqlite3(const std::string& dir) - : SecPublicInfo(dir) - , m_database(nullptr) -{ - boost::filesystem::path identityDir; - if (dir == "") { -#ifdef NDN_CXX_HAVE_TESTS - if (getenv("TEST_HOME") != nullptr) { - identityDir = boost::filesystem::path(getenv("TEST_HOME")) / ".ndn"; - } - else -#endif // NDN_CXX_HAVE_TESTS - if (getenv("HOME") != nullptr) { - identityDir = boost::filesystem::path(getenv("HOME")) / ".ndn"; - } - else { - identityDir = boost::filesystem::path(".") / ".ndn"; - } - } - else { - identityDir = boost::filesystem::path(dir); - } - boost::filesystem::create_directories(identityDir); - - /// @todo Add define for windows/unix in wscript. The following may completely fail on windows - int res = sqlite3_open_v2((identityDir / "ndnsec-public-info.db").c_str(), &m_database, - SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, -#ifdef NDN_CXX_DISABLE_SQLITE3_FS_LOCKING - "unix-dotfile" -#else - 0 -#endif - ); - if (res != SQLITE_OK) - BOOST_THROW_EXCEPTION(Error("identity DB cannot be opened/created")); - - - BOOST_ASSERT(m_database != nullptr); - - initializeTable("TpmInfo", INIT_TPM_INFO_TABLE); // Check if TpmInfo table exists; - initializeTable("Identity", INIT_ID_TABLE); // Check if Identity table exists; - initializeTable("Key", INIT_KEY_TABLE); // Check if Key table exists; - initializeTable("Certificate", INIT_CERT_TABLE); // Check if Certificate table exists; -} - -SecPublicInfoSqlite3::~SecPublicInfoSqlite3() -{ - sqlite3_close(m_database); - m_database = nullptr; -} - -bool -SecPublicInfoSqlite3::doesTableExist(const string& tableName) -{ - // Check if the table exists; - bool doesTableExist = false; - string checkingString = - "SELECT name FROM sqlite_master WHERE type='table' AND name='" + tableName + "'"; - - sqlite3_stmt* statement = nullptr; - sqlite3_prepare_v2(m_database, checkingString.c_str(), -1, &statement, 0); - - int result = sqlite3_step(statement); - if (result == SQLITE_ROW) - doesTableExist = true; - sqlite3_finalize(statement); - - return doesTableExist; -} - -bool -SecPublicInfoSqlite3::initializeTable(const string& tableName, const string& initCommand) -{ - // Create the table if it does not exist - if (!doesTableExist(tableName)) { - char* errorMessage = 0; - int result = sqlite3_exec(m_database, initCommand.c_str(), NULL, NULL, &errorMessage); - - if (result != SQLITE_OK && errorMessage != 0) { - sqlite3_free(errorMessage); - return false; - } - } - - return true; -} - -void -SecPublicInfoSqlite3::deleteTable(const string& tableName) -{ - string query = "DROP TABLE IF EXISTS " + tableName; - - sqlite3_stmt* statement = nullptr; - sqlite3_prepare_v2(m_database, query.c_str(), -1, &statement, 0); - - sqlite3_step(statement); - sqlite3_finalize(statement); -} - -void -SecPublicInfoSqlite3::setTpmLocator(const string& tpmLocator) -{ - string currentTpm; - try { - currentTpm = getTpmLocator(); - } - catch (SecPublicInfo::Error&) { - setTpmLocatorInternal(tpmLocator, false); // set tpmInfo without resetting - return; - } - - if (currentTpm == tpmLocator) - return; // if the same, nothing will be changed - - setTpmLocatorInternal(tpmLocator, true); // set tpmInfo and reset pib -} - -string -SecPublicInfoSqlite3::getTpmLocator() -{ - sqlite3_stmt* statement = nullptr; - sqlite3_prepare_v2(m_database, "SELECT tpm_locator FROM TpmInfo", -1, &statement, 0); - - int res = sqlite3_step(statement); - - if (res == SQLITE_ROW) { - string tpmLocator = sqlite3_column_string(statement, 0); - sqlite3_finalize(statement); - return tpmLocator; - } - else { - sqlite3_finalize(statement); - BOOST_THROW_EXCEPTION(SecPublicInfo::Error("TPM info does not exist")); - } -} - -void -SecPublicInfoSqlite3::setTpmLocatorInternal(const string& tpmLocator, bool needReset) -{ - sqlite3_stmt* statement = nullptr; - - if (needReset) { - deleteTable("Identity"); - deleteTable("Key"); - deleteTable("Certificate"); - - initializeTable("Identity", INIT_ID_TABLE); - initializeTable("Key", INIT_KEY_TABLE); - initializeTable("Certificate", INIT_CERT_TABLE); - - sqlite3_prepare_v2(m_database, "UPDATE TpmInfo SET tpm_locator = ?", - -1, &statement, 0); - sqlite3_bind_string(statement, 1, tpmLocator, SQLITE_TRANSIENT); - } - else { - // no reset implies there is no tpmLocator record, insert one - sqlite3_prepare_v2(m_database, "INSERT INTO TpmInfo (tpm_locator) VALUES (?)", - -1, &statement, 0); - sqlite3_bind_string(statement, 1, tpmLocator, SQLITE_TRANSIENT); - } - - sqlite3_step(statement); - sqlite3_finalize(statement); -} - -std::string -SecPublicInfoSqlite3::getPibLocator() -{ - return string("pib-sqlite3:").append(m_location); -} - -bool -SecPublicInfoSqlite3::doesIdentityExist(const Name& identityName) -{ - bool result = false; - - sqlite3_stmt* statement = nullptr; - sqlite3_prepare_v2(m_database, - "SELECT count(*) FROM Identity WHERE identity_name=?", - -1, &statement, 0); - - sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT); - int res = sqlite3_step(statement); - - if (res == SQLITE_ROW) { - int countAll = sqlite3_column_int(statement, 0); - if (countAll > 0) - result = true; - } - - sqlite3_finalize(statement); - - return result; -} - -void -SecPublicInfoSqlite3::addIdentity(const Name& identityName) -{ - if (doesIdentityExist(identityName)) - return; - - sqlite3_stmt* statement = nullptr; - - sqlite3_prepare_v2(m_database, - "INSERT OR REPLACE INTO Identity (identity_name) values (?)", - -1, &statement, 0); - - sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT); - - sqlite3_step(statement); - - sqlite3_finalize(statement); -} - -bool -SecPublicInfoSqlite3::revokeIdentity() -{ - //TODO: - return false; -} - -bool -SecPublicInfoSqlite3::doesPublicKeyExist(const Name& keyName) -{ - if (keyName.empty()) - BOOST_THROW_EXCEPTION(Error("Incorrect key name " + keyName.toUri())); - - string keyId = keyName.get(-1).toUri(); - Name identityName = keyName.getPrefix(-1); - - sqlite3_stmt* statement = nullptr; - sqlite3_prepare_v2(m_database, - "SELECT count(*) FROM Key WHERE identity_name=? AND key_identifier=?", - -1, &statement, 0); - - sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT); - sqlite3_bind_string(statement, 2, keyId, SQLITE_TRANSIENT); - - int res = sqlite3_step(statement); - - bool keyIdExist = false; - if (res == SQLITE_ROW) { - int countAll = sqlite3_column_int(statement, 0); - if (countAll > 0) - keyIdExist = true; - } - - sqlite3_finalize(statement); - - return keyIdExist; -} - -void -SecPublicInfoSqlite3::addKey(const Name& keyName, - const v1::PublicKey& publicKeyDer) -{ - if (keyName.empty()) - return; - - if (doesPublicKeyExist(keyName)) - return; - - string keyId = keyName.get(-1).toUri(); - Name identityName = keyName.getPrefix(-1); - - addIdentity(identityName); - - sqlite3_stmt* statement = nullptr; - sqlite3_prepare_v2(m_database, - "INSERT OR REPLACE INTO Key \ - (identity_name, key_identifier, key_type, public_key) \ - values (?, ?, ?, ?)", - -1, &statement, 0); - - sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT); - sqlite3_bind_string(statement, 2, keyId, SQLITE_TRANSIENT); - sqlite3_bind_int(statement, 3, static_cast(publicKeyDer.getKeyType())); - sqlite3_bind_blob(statement, 4, - publicKeyDer.get().buf(), - publicKeyDer.get().size(), - SQLITE_STATIC); - - sqlite3_step(statement); - - sqlite3_finalize(statement); -} - -shared_ptr -SecPublicInfoSqlite3::getPublicKey(const Name& keyName) -{ - if (keyName.empty()) - BOOST_THROW_EXCEPTION(Error("SecPublicInfoSqlite3::getPublicKey Empty keyName")); - - string keyId = keyName.get(-1).toUri(); - Name identityName = keyName.getPrefix(-1); - - sqlite3_stmt* statement = nullptr; - sqlite3_prepare_v2(m_database, - "SELECT public_key FROM Key WHERE identity_name=? AND key_identifier=?", - -1, &statement, 0); - - sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT); - sqlite3_bind_string(statement, 2, keyId, SQLITE_TRANSIENT); - - int res = sqlite3_step(statement); - - shared_ptr result; - if (res == SQLITE_ROW) { - result = make_shared(static_cast(sqlite3_column_blob(statement, 0)), - sqlite3_column_bytes(statement, 0)); - sqlite3_finalize(statement); - return result; - } - else { - sqlite3_finalize(statement); - BOOST_THROW_EXCEPTION(Error("SecPublicInfoSqlite3::getPublicKey public key does not exist")); - } -} - -KeyType -SecPublicInfoSqlite3::getPublicKeyType(const Name& keyName) -{ - if (keyName.empty()) - return KeyType::NONE; - - string keyId = keyName.get(-1).toUri(); - Name identityName = keyName.getPrefix(-1); - - sqlite3_stmt* statement = nullptr; - sqlite3_prepare_v2(m_database, - "SELECT key_type FROM Key WHERE identity_name=? AND key_identifier=?", - -1, &statement, 0); - - sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT); - sqlite3_bind_string(statement, 2, keyId, SQLITE_TRANSIENT); - - int res = sqlite3_step(statement); - - if (res == SQLITE_ROW) { - int typeValue = sqlite3_column_int(statement, 0); - sqlite3_finalize(statement); - return static_cast(typeValue); - } - else { - sqlite3_finalize(statement); - return KeyType::NONE; - } -} - -bool -SecPublicInfoSqlite3::doesCertificateExist(const Name& certificateName) -{ - sqlite3_stmt* statement = nullptr; - sqlite3_prepare_v2(m_database, - "SELECT count(*) FROM Certificate WHERE cert_name=?", - -1, &statement, 0); - - sqlite3_bind_string(statement, 1, certificateName.toUri(), SQLITE_TRANSIENT); - - int res = sqlite3_step(statement); - - bool certExist = false; - if (res == SQLITE_ROW) { - int countAll = sqlite3_column_int(statement, 0); - if (countAll > 0) - certExist = true; - } - - sqlite3_finalize(statement); - - return certExist; -} - -void -SecPublicInfoSqlite3::addCertificate(const v1::IdentityCertificate& certificate) -{ - const Name& certificateName = certificate.getName(); - // KeyName is from v1::IdentityCertificate name, so should be qualified. - Name keyName = - v1::IdentityCertificate::certificateNameToPublicKeyName(certificate.getName()); - - addKey(keyName, certificate.getPublicKeyInfo()); - - if (doesCertificateExist(certificateName)) - return; - - string keyId = keyName.get(-1).toUri(); - Name identity = keyName.getPrefix(-1); - - // Insert the certificate - sqlite3_stmt* statement = nullptr; - sqlite3_prepare_v2(m_database, - "INSERT OR REPLACE INTO Certificate \ - (cert_name, cert_issuer, identity_name, key_identifier, \ - not_before, not_after, certificate_data) \ - values (?, ?, ?, ?, datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), ?)", - -1, &statement, 0); - - sqlite3_bind_string(statement, 1, certificateName.toUri(), SQLITE_TRANSIENT); - - try { - // this will throw an exception if the signature is not the standard one - // or there is no key locator present - std::string signerName = certificate.getSignature().getKeyLocator().getName().toUri(); - sqlite3_bind_string(statement, 2, signerName, SQLITE_TRANSIENT); - } - catch (tlv::Error&) { - return; - } - - sqlite3_bind_string(statement, 3, identity.toUri(), SQLITE_TRANSIENT); - sqlite3_bind_string(statement, 4, keyId, SQLITE_STATIC); - - sqlite3_bind_int64(statement, 5, - static_cast(time::toUnixTimestamp(certificate.getNotBefore()).count())); - sqlite3_bind_int64(statement, 6, - static_cast(time::toUnixTimestamp(certificate.getNotAfter()).count())); - - sqlite3_bind_blob(statement, 7, - certificate.wireEncode().wire(), - certificate.wireEncode().size(), - SQLITE_TRANSIENT); - - sqlite3_step(statement); - - sqlite3_finalize(statement); -} - -shared_ptr -SecPublicInfoSqlite3::getCertificate(const Name& certificateName) -{ - sqlite3_stmt* statement = nullptr; - - sqlite3_prepare_v2(m_database, - "SELECT certificate_data FROM Certificate WHERE cert_name=?", - -1, &statement, 0); - - sqlite3_bind_string(statement, 1, certificateName.toUri(), SQLITE_TRANSIENT); - - int res = sqlite3_step(statement); - - if (res == SQLITE_ROW) { - shared_ptr certificate = make_shared(); - try { - certificate->wireDecode(Block(static_cast(sqlite3_column_blob(statement, 0)), - sqlite3_column_bytes(statement, 0))); - } - catch (tlv::Error&) { - sqlite3_finalize(statement); - BOOST_THROW_EXCEPTION(Error("SecPublicInfoSqlite3::getCertificate certificate cannot be " - "decoded")); - } - - sqlite3_finalize(statement); - return certificate; - } - else { - sqlite3_finalize(statement); - BOOST_THROW_EXCEPTION(Error("SecPublicInfoSqlite3::getCertificate certificate does not " - "exist")); - } -} - - -Name -SecPublicInfoSqlite3::getDefaultIdentity() -{ - sqlite3_stmt* statement = nullptr; - sqlite3_prepare_v2(m_database, - "SELECT identity_name FROM Identity WHERE default_identity=1", - -1, &statement, 0); - - int res = sqlite3_step(statement); - - if (res == SQLITE_ROW) { - Name identity(sqlite3_column_string(statement, 0)); - sqlite3_finalize(statement); - return identity; - } - else { - sqlite3_finalize(statement); - BOOST_THROW_EXCEPTION(Error("SecPublicInfoSqlite3::getDefaultIdentity no default identity")); - } -} - -void -SecPublicInfoSqlite3::setDefaultIdentityInternal(const Name& identityName) -{ - addIdentity(identityName); - - sqlite3_stmt* statement = nullptr; - - //Reset previous default identity - sqlite3_prepare_v2(m_database, - "UPDATE Identity SET default_identity=0 WHERE default_identity=1", - -1, &statement, 0); - - while (sqlite3_step(statement) == SQLITE_ROW) - ; - - sqlite3_finalize(statement); - - //Set current default identity - sqlite3_prepare_v2(m_database, - "UPDATE Identity SET default_identity=1 WHERE identity_name=?", - -1, &statement, 0); - - sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT); - - sqlite3_step(statement); - - sqlite3_finalize(statement); -} - -Name -SecPublicInfoSqlite3::getDefaultKeyNameForIdentity(const Name& identityName) -{ - sqlite3_stmt* statement = nullptr; - sqlite3_prepare_v2(m_database, - "SELECT key_identifier FROM Key WHERE identity_name=? AND default_key=1", - -1, &statement, 0); - - sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT); - - int res = sqlite3_step(statement); - - if (res == SQLITE_ROW) { - Name keyName = identityName; - keyName.append(string(reinterpret_cast(sqlite3_column_text(statement, 0)), - sqlite3_column_bytes(statement, 0))); - sqlite3_finalize(statement); - return keyName; - } - else { - sqlite3_finalize(statement); - BOOST_THROW_EXCEPTION(Error("SecPublicInfoSqlite3::getDefaultKeyNameForIdentity key not " - "found")); - } -} - -void -SecPublicInfoSqlite3::setDefaultKeyNameForIdentityInternal(const Name& keyName) -{ - if (!doesPublicKeyExist(keyName)) - BOOST_THROW_EXCEPTION(Error("Key does not exist:" + keyName.toUri())); - - string keyId = keyName.get(-1).toUri(); - Name identityName = keyName.getPrefix(-1); - - sqlite3_stmt* statement = nullptr; - - //Reset previous default Key - sqlite3_prepare_v2(m_database, - "UPDATE Key SET default_key=0 WHERE default_key=1 and identity_name=?", - -1, &statement, 0); - - sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT); - - while (sqlite3_step(statement) == SQLITE_ROW) - ; - - sqlite3_finalize(statement); - - //Set current default Key - sqlite3_prepare_v2(m_database, - "UPDATE Key SET default_key=1 WHERE identity_name=? AND key_identifier=?", - -1, &statement, 0); - - sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT); - sqlite3_bind_string(statement, 2, keyId, SQLITE_TRANSIENT); - - sqlite3_step(statement); - - sqlite3_finalize(statement); -} - -Name -SecPublicInfoSqlite3::getDefaultCertificateNameForKey(const Name& keyName) -{ - if (keyName.empty()) - BOOST_THROW_EXCEPTION(Error("SecPublicInfoSqlite3::getDefaultCertificateNameForKey wrong key")); - - string keyId = keyName.get(-1).toUri(); - Name identityName = keyName.getPrefix(-1); - - sqlite3_stmt* statement = nullptr; - sqlite3_prepare_v2(m_database, - "SELECT cert_name FROM Certificate \ - WHERE identity_name=? AND key_identifier=? AND default_cert=1", - -1, &statement, 0); - - sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT); - sqlite3_bind_string(statement, 2, keyId, SQLITE_TRANSIENT); - - int res = sqlite3_step(statement); - - if (res == SQLITE_ROW) { - Name certName(string(reinterpret_cast(sqlite3_column_text(statement, 0)), - sqlite3_column_bytes(statement, 0))); - sqlite3_finalize(statement); - return certName; - } - else { - sqlite3_finalize(statement); - BOOST_THROW_EXCEPTION(Error("certificate not found")); - } -} - -void -SecPublicInfoSqlite3::setDefaultCertificateNameForKeyInternal(const Name& certificateName) -{ - if (!doesCertificateExist(certificateName)) - BOOST_THROW_EXCEPTION(Error("certificate does not exist:" + certificateName.toUri())); - - Name keyName = v1::IdentityCertificate::certificateNameToPublicKeyName(certificateName); - string keyId = keyName.get(-1).toUri(); - Name identityName = keyName.getPrefix(-1); - - sqlite3_stmt* statement = nullptr; - - //Reset previous default Key - sqlite3_prepare_v2(m_database, - "UPDATE Certificate SET default_cert=0 \ - WHERE default_cert=1 AND identity_name=? AND key_identifier=?", - -1, &statement, 0); - - sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT); - sqlite3_bind_string(statement, 2, keyId, SQLITE_TRANSIENT); - - while (sqlite3_step(statement) == SQLITE_ROW) - ; - - sqlite3_finalize(statement); - - //Set current default Key - sqlite3_prepare_v2(m_database, - "UPDATE Certificate SET default_cert=1 \ - WHERE identity_name=? AND key_identifier=? AND cert_name=?", - -1, &statement, 0); - - sqlite3_bind_string(statement, 1, identityName.toUri(), SQLITE_TRANSIENT); - sqlite3_bind_string(statement, 2, keyId, SQLITE_TRANSIENT); - sqlite3_bind_string(statement, 3, certificateName.toUri(), SQLITE_TRANSIENT); - - sqlite3_step(statement); - - sqlite3_finalize(statement); -} - -void -SecPublicInfoSqlite3::getAllIdentities(vector& nameList, bool isDefault) -{ - sqlite3_stmt* stmt; - if (isDefault) - sqlite3_prepare_v2(m_database, - "SELECT identity_name FROM Identity WHERE default_identity=1", - -1, &stmt, 0); - else - sqlite3_prepare_v2(m_database, - "SELECT identity_name FROM Identity WHERE default_identity=0", - -1, &stmt, 0); - - while (sqlite3_step(stmt) == SQLITE_ROW) - nameList.push_back(Name(string(reinterpret_cast(sqlite3_column_text(stmt, 0)), - sqlite3_column_bytes(stmt, 0)))); - - sqlite3_finalize(stmt); -} - -void -SecPublicInfoSqlite3::getAllKeyNames(vector& nameList, bool isDefault) -{ - sqlite3_stmt* stmt; - - if (isDefault) - sqlite3_prepare_v2(m_database, - "SELECT identity_name, key_identifier FROM Key WHERE default_key=1", - -1, &stmt, 0); - else - sqlite3_prepare_v2(m_database, - "SELECT identity_name, key_identifier FROM Key WHERE default_key=0", - -1, &stmt, 0); - - while (sqlite3_step(stmt) == SQLITE_ROW) { - Name keyName(string(reinterpret_cast(sqlite3_column_text(stmt, 0)), - sqlite3_column_bytes(stmt, 0))); - keyName.append(string(reinterpret_cast(sqlite3_column_text(stmt, 1)), - sqlite3_column_bytes(stmt, 1))); - nameList.push_back(keyName); - } - sqlite3_finalize(stmt); -} - -void -SecPublicInfoSqlite3::getAllKeyNamesOfIdentity(const Name& identity, - vector& nameList, - bool isDefault) -{ - sqlite3_stmt* stmt; - - if (isDefault) - sqlite3_prepare_v2(m_database, - "SELECT key_identifier FROM Key WHERE default_key=1 and identity_name=?", - -1, &stmt, 0); - else - sqlite3_prepare_v2(m_database, - "SELECT key_identifier FROM Key WHERE default_key=0 and identity_name=?", - -1, &stmt, 0); - - sqlite3_bind_string(stmt, 1, identity.toUri(), SQLITE_TRANSIENT); - - while (sqlite3_step(stmt) == SQLITE_ROW) { - Name keyName(identity); - keyName.append(string(reinterpret_cast(sqlite3_column_text(stmt, 0)), - sqlite3_column_bytes(stmt, 0))); - nameList.push_back(keyName); - } - sqlite3_finalize(stmt); -} - -void -SecPublicInfoSqlite3::getAllCertificateNames(vector& nameList, bool isDefault) -{ - sqlite3_stmt* stmt; - - if (isDefault) - sqlite3_prepare_v2(m_database, - "SELECT cert_name FROM Certificate WHERE default_cert=1", - -1, &stmt, 0); - else - sqlite3_prepare_v2(m_database, - "SELECT cert_name FROM Certificate WHERE default_cert=0", - -1, &stmt, 0); - - while (sqlite3_step(stmt) == SQLITE_ROW) - nameList.push_back(string(reinterpret_cast(sqlite3_column_text(stmt, 0)), - sqlite3_column_bytes(stmt, 0))); - - sqlite3_finalize(stmt); -} - -void -SecPublicInfoSqlite3::getAllCertificateNamesOfKey(const Name& keyName, - vector& nameList, - bool isDefault) -{ - if (keyName.empty()) - return; - - sqlite3_stmt* stmt; - if (isDefault) - sqlite3_prepare_v2(m_database, - "SELECT cert_name FROM Certificate \ - WHERE default_cert=1 and identity_name=? and key_identifier=?", - -1, &stmt, 0); - else - sqlite3_prepare_v2(m_database, - "SELECT cert_name FROM Certificate \ - WHERE default_cert=0 and identity_name=? and key_identifier=?", - -1, &stmt, 0); - - Name identity = keyName.getPrefix(-1); - sqlite3_bind_string(stmt, 1, identity.toUri(), SQLITE_TRANSIENT); - - std::string baseKeyName = keyName.get(-1).toUri(); - sqlite3_bind_string(stmt, 2, baseKeyName, SQLITE_TRANSIENT); - - while (sqlite3_step(stmt) == SQLITE_ROW) - nameList.push_back(string(reinterpret_cast(sqlite3_column_text(stmt, 0)), - sqlite3_column_bytes(stmt, 0))); - - sqlite3_finalize(stmt); -} - -void -SecPublicInfoSqlite3::deleteCertificateInfo(const Name& certName) -{ - if (certName.empty()) - return; - - sqlite3_stmt* stmt; - sqlite3_prepare_v2(m_database, "DELETE FROM Certificate WHERE cert_name=?", -1, &stmt, 0); - sqlite3_bind_string(stmt, 1, certName.toUri(), SQLITE_TRANSIENT); - sqlite3_step(stmt); - sqlite3_finalize(stmt); -} - -void -SecPublicInfoSqlite3::deletePublicKeyInfo(const Name& keyName) -{ - if (keyName.empty()) - return; - - string identity = keyName.getPrefix(-1).toUri(); - string keyId = keyName.get(-1).toUri(); - - sqlite3_stmt* stmt; - sqlite3_prepare_v2(m_database, - "DELETE FROM Certificate WHERE identity_name=? and key_identifier=?", - -1, &stmt, 0); - sqlite3_bind_string(stmt, 1, identity, SQLITE_TRANSIENT); - sqlite3_bind_string(stmt, 2, keyId, SQLITE_TRANSIENT); - sqlite3_step(stmt); - sqlite3_finalize(stmt); - - sqlite3_prepare_v2(m_database, - "DELETE FROM Key WHERE identity_name=? and key_identifier=?", - -1, &stmt, 0); - sqlite3_bind_string(stmt, 1, identity, SQLITE_TRANSIENT); - sqlite3_bind_string(stmt, 2, keyId, SQLITE_TRANSIENT); - sqlite3_step(stmt); - sqlite3_finalize(stmt); -} - -void -SecPublicInfoSqlite3::deleteIdentityInfo(const Name& identityName) -{ - string identity = identityName.toUri(); - - sqlite3_stmt* stmt; - sqlite3_prepare_v2(m_database, "DELETE FROM Certificate WHERE identity_name=?", -1, &stmt, 0); - sqlite3_bind_string(stmt, 1, identity, SQLITE_TRANSIENT); - sqlite3_step(stmt); - sqlite3_finalize(stmt); - - sqlite3_prepare_v2(m_database, "DELETE FROM Key WHERE identity_name=?", -1, &stmt, 0); - sqlite3_bind_string(stmt, 1, identity, SQLITE_TRANSIENT); - sqlite3_step(stmt); - sqlite3_finalize(stmt); - - sqlite3_prepare_v2(m_database, "DELETE FROM Identity WHERE identity_name=?", -1, &stmt, 0); - sqlite3_bind_string(stmt, 1, identity, SQLITE_TRANSIENT); - sqlite3_step(stmt); - sqlite3_finalize(stmt); -} - -std::string -SecPublicInfoSqlite3::getScheme() -{ - return SCHEME; -} - -} // namespace security -} // namespace ndn diff --git a/src/security/sec-public-info-sqlite3.hpp b/src/security/sec-public-info-sqlite3.hpp deleted file mode 100644 index fbe7d7e22..000000000 --- a/src/security/sec-public-info-sqlite3.hpp +++ /dev/null @@ -1,172 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - * @author Jeff Thompson - */ - -#ifndef NDN_SECURITY_SEC_PUBLIC_INFO_SQLITE3_HPP -#define NDN_SECURITY_SEC_PUBLIC_INFO_SQLITE3_HPP - -#include "../common.hpp" -#include "sec-public-info.hpp" - -struct sqlite3; - -namespace ndn { -namespace security { - -class SecPublicInfoSqlite3 : public SecPublicInfo -{ -public: - class Error : public SecPublicInfo::Error - { - public: - explicit - Error(const std::string& what) - : SecPublicInfo::Error(what) - { - } - }; - - explicit - SecPublicInfoSqlite3(const std::string& dir = ""); - - virtual - ~SecPublicInfoSqlite3(); - - /********************** - * from SecPublicInfo * - **********************/ - - virtual void - setTpmLocator(const std::string& tpmLocator); - - virtual std::string - getTpmLocator(); - - virtual std::string - getPibLocator(); - - virtual bool - doesIdentityExist(const Name& identityName); - - virtual void - addIdentity(const Name& identityName); - - virtual bool - revokeIdentity(); - - virtual bool - doesPublicKeyExist(const Name& keyName); - - virtual void - addKey(const Name& keyName, const v1::PublicKey& publicKeyDer); - - virtual shared_ptr - getPublicKey(const Name& keyName); - - virtual KeyType - getPublicKeyType(const Name& keyName); - - virtual bool - doesCertificateExist(const Name& certificateName); - - virtual void - addCertificate(const v1::IdentityCertificate& certificate); - - virtual shared_ptr - getCertificate(const Name& certificateName); - - - - virtual Name - getDefaultIdentity(); - - virtual Name - getDefaultKeyNameForIdentity(const Name& identityName); - - virtual Name - getDefaultCertificateNameForKey(const Name& keyName); - - virtual void - getAllIdentities(std::vector& nameList, bool isDefault); - - virtual void - getAllKeyNames(std::vector& nameList, bool isDefault); - - virtual void - getAllKeyNamesOfIdentity(const Name& identity, std::vector& nameList, bool isDefault); - - virtual void - getAllCertificateNames(std::vector& nameList, bool isDefault); - - virtual void - getAllCertificateNamesOfKey(const Name& keyName, std::vector& nameList, bool isDefault); - - virtual void - deleteCertificateInfo(const Name& certificateName); - - virtual void - deletePublicKeyInfo(const Name& keyName); - - virtual void - deleteIdentityInfo(const Name& identity); - -private: - bool - initializeTable(const std::string& tableName, const std::string& initCommand); - - void - deleteTable(const std::string& tableName); - - void - setTpmLocatorInternal(const std::string& tpmLocator, bool needReset); - - void - setDefaultIdentityInternal(const Name& identityName); - - void - setDefaultKeyNameForIdentityInternal(const Name& keyName); - - void - setDefaultCertificateNameForKeyInternal(const Name& certificateName); - - std::string - getScheme(); - -NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: - bool - doesTableExist(const std::string& tableName); - -public: - static const std::string SCHEME; - -private: - sqlite3* m_database; -}; - -} // namespace security - -using security::SecPublicInfoSqlite3; - -} // namespace ndn - -#endif // NDN_SECURITY_SEC_PUBLIC_INFO_SQLITE3_HPP diff --git a/src/security/sec-public-info.cpp b/src/security/sec-public-info.cpp deleted file mode 100644 index 7002d3618..000000000 --- a/src/security/sec-public-info.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "sec-public-info.hpp" - -namespace ndn { -namespace security { - -SecPublicInfo::SecPublicInfo(const std::string& location) - : m_location(location) -{ -} - -SecPublicInfo::~SecPublicInfo() -{ -} - -std::string -SecPublicInfo::getPibLocator() -{ - return this->getScheme() + ":" + m_location; -} - -void -SecPublicInfo::addPublicKey(const Name& keyName, KeyType keyType, const v1::PublicKey& publicKey) -{ - addKey(keyName, publicKey); -} - -void -SecPublicInfo::setDefaultIdentity(const Name& identityName) -{ - setDefaultIdentityInternal(identityName); - refreshDefaultCertificate(); -} - -void -SecPublicInfo::setDefaultKeyNameForIdentity(const Name& keyName) -{ - setDefaultKeyNameForIdentityInternal(keyName); - refreshDefaultCertificate(); -} - -void -SecPublicInfo::setDefaultCertificateNameForKey(const Name& certificateName) -{ - setDefaultCertificateNameForKeyInternal(certificateName); - refreshDefaultCertificate(); -} - -Name -SecPublicInfo::getDefaultCertificateNameForIdentity(const Name& identityName) -{ - return getDefaultCertificateNameForKey(getDefaultKeyNameForIdentity(identityName)); -} - -Name -SecPublicInfo::getDefaultCertificateName() -{ - if (m_defaultCertificate == nullptr) - refreshDefaultCertificate(); - - if (m_defaultCertificate == nullptr) - BOOST_THROW_EXCEPTION(Error("No default certificate is set")); - - return m_defaultCertificate->getName(); -} - -Name -SecPublicInfo::getNewKeyName(const Name& identityName, bool useKsk) -{ - std::ostringstream oss; - - if (useKsk) - oss << "ksk-"; - else - oss << "dsk-"; - - oss << time::toUnixTimestamp(time::system_clock::now()).count(); - - Name keyName = Name(identityName).append(oss.str()); - - if (doesPublicKeyExist(keyName)) - BOOST_THROW_EXCEPTION(Error("Key name already exists: " + keyName.toUri())); - - return keyName; -} - -void -SecPublicInfo::addCertificateAsKeyDefault(const v1::IdentityCertificate& certificate) -{ - addCertificate(certificate); - setDefaultCertificateNameForKeyInternal(certificate.getName()); - refreshDefaultCertificate(); -} - -void -SecPublicInfo::addCertificateAsIdentityDefault(const v1::IdentityCertificate& certificate) -{ - addCertificate(certificate); - Name certName = certificate.getName(); - Name keyName = v1::IdentityCertificate::certificateNameToPublicKeyName(certName); - setDefaultKeyNameForIdentityInternal(keyName); - setDefaultCertificateNameForKeyInternal(certName); - refreshDefaultCertificate(); -} - -void -SecPublicInfo::addCertificateAsSystemDefault(const v1::IdentityCertificate& certificate) -{ - addCertificate(certificate); - Name certName = certificate.getName(); - Name keyName = v1::IdentityCertificate::certificateNameToPublicKeyName(certName); - setDefaultIdentityInternal(keyName.getPrefix(-1)); - setDefaultKeyNameForIdentityInternal(keyName); - setDefaultCertificateNameForKeyInternal(certName); - refreshDefaultCertificate(); -} - -shared_ptr -SecPublicInfo::defaultCertificate() -{ - return getDefaultCertificate(); -} - -shared_ptr -SecPublicInfo::getDefaultCertificate() -{ - return m_defaultCertificate; -} - -void -SecPublicInfo::refreshDefaultCertificate() -{ - try { - Name certName = getDefaultCertificateNameForIdentity(getDefaultIdentity()); - m_defaultCertificate = getCertificate(certName); - } - catch (SecPublicInfo::Error&) { - m_defaultCertificate.reset(); - } -} - -} // namespace security -} // namespace ndn diff --git a/src/security/sec-public-info.hpp b/src/security/sec-public-info.hpp deleted file mode 100644 index 9f24538bb..000000000 --- a/src/security/sec-public-info.hpp +++ /dev/null @@ -1,464 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_SEC_PUBLIC_INFO_HPP -#define NDN_SECURITY_SEC_PUBLIC_INFO_HPP - -#include "../name.hpp" -#include "security-common.hpp" -#include "v1/public-key.hpp" -#include "v1/identity-certificate.hpp" - -namespace ndn { -namespace security { - -/** - * @brief SecPublicInfo is a base class for the storage of public information. - * - * It specify interfaces related to public information, such as identity, public keys and - * certificates. - */ -class SecPublicInfo : noncopyable -{ -public: - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - - explicit - SecPublicInfo(const std::string& location); - - /** - * @brief The virtual Destructor - */ - virtual - ~SecPublicInfo(); - - /** - * @brief Set the corresponding TPM information to @p tpmLocator - * - * If the provided @p tpmLocator is different from the existing one, the PIB will be reset, - * otherwise nothing will be changed. - * - * For legacy issue, the TPM info may not exist (some old PIB content may not have this info), - * this method will simply set the TPM info as provided without changing anything else. Thus an - * ideal process of handling old PIB is to check if TPM info exists. If it does not exist, - * then set it to the default value according to configuration. - */ - virtual void - setTpmLocator(const std::string& tpmLocator) = 0; - - /** - * @brief Get TPM Locator - * - * @throws SecPublicInfo::Error if the TPM info does not exist - */ - virtual std::string - getTpmLocator() = 0; - - /** - * @brief Get PIB Locator - */ - std::string - getPibLocator(); - - /** - * @brief Check if the specified identity already exists - * - * @param identityName The identity name - * @return true if the identity exists, otherwise false - */ - virtual bool - doesIdentityExist(const Name& identityName) = 0; - - /** - * @brief Add a new identity - * - * if identity already exist, do not add it again - * - * @param identityName The identity name to be added - */ - virtual void - addIdentity(const Name& identityName) = 0; - - /** - * @brief Revoke the identity - * - * @return true if the identity was revoked, otherwise false - */ - virtual bool - revokeIdentity() = 0; - - /** - * @brief Check if the specified key already exists - * - * @param keyName The name of the key - * @return true if the key exists, otherwise false - */ - virtual bool - doesPublicKeyExist(const Name& keyName) = 0; - - /** - * @brief Add a public key to the identity storage. - * - * @param keyName The name of the public key to be added - * @param keyType Type of the public key to be added - * @param publicKey Reference to the PublicKey object - * @deprecated Use addKey instead - */ - DEPRECATED( - void - addPublicKey(const Name& keyName, KeyType keyType, const v1::PublicKey& publicKey)); - - /** - * @brief Add a public key to the identity storage. - * - * @param keyName The name of the public key to be added - * @param publicKey Reference to the PublicKey object - */ - virtual void - addKey(const Name& keyName, const v1::PublicKey& publicKey) = 0; - - /** - * @brief Get shared pointer to PublicKey object from the identity storage - * - * @param keyName The name of the requested public key - * @throws SecPublicInfo::Error if public key does not exist - */ - virtual shared_ptr - getPublicKey(const Name& keyName) = 0; - - /** - * @brief Get the type of the queried public key - * - * @note KeyType is also available from PublicKey instance. - * This method is more efficient if only KeyType is needed. - * - * @param keyName The name of the requested public key - * @return the type of the key. If the queried key does not exist, KeyType::NONE will be returned - */ - virtual KeyType - getPublicKeyType(const Name& keyName) = 0; - - /** - * @brief Check if the specified certificate already exists - * - * @param certificateName The name of the certificate - */ - virtual bool - doesCertificateExist(const Name& certificateName) = 0; - - /** - * @brief Add a certificate to the identity storage. - * - * It will add the corresponding public key and identity if they do not exist - * - * @param certificate The certificate to be added - */ - virtual void - addCertificate(const v1::IdentityCertificate& certificate) = 0; - - /** - * @brief Get a shared pointer to identity certificate object from the identity storage - * - * @param certificateName The name of the requested certificate - * @throws SecPublicInfo::Error if the certificate does not exist - */ - virtual shared_ptr - getCertificate(const Name& certificateName) = 0; - - - /***************************************** - * Default Getter * - *****************************************/ - - /** - * @brief Get name of the default identity - * - * @throws SecPublicInfo::Error if there is no default. - */ - virtual Name - getDefaultIdentity() = 0; - - /** - * @brief Get name of the default key name for the specified identity - * - * @param identityName The identity name - * @throws SecPublicInfo::Error if there is no default - */ - virtual Name - getDefaultKeyNameForIdentity(const Name& identityName) = 0; - - /** - * @brief Get name of the default certificate name for the specified key - * - * @param keyName The key name. - * @throws SecPublicInfo::Error if there is no default. - */ - virtual Name - getDefaultCertificateNameForKey(const Name& keyName) = 0; - - /** - * @brief Get all the identities from public info - * - * @param [out] nameList On return, the identity list - * @param isDefault If specified, only the default identity is returned - */ - virtual void - getAllIdentities(std::vector& nameList, bool isDefault) = 0; - - /** - * @brief Get all the key names from public info - * - * @param [out] nameList On return, the key name list. - * @param isDefault If specified, only the default keys are returned - */ - virtual void - getAllKeyNames(std::vector& nameList, bool isDefault) = 0; - - /** - * @brief Get all the key names of a particular identity - * - * @param identity The specified identity name - * @param [out] nameList On return, the key name list - * @param isDefault If specified, only the default key is returned - */ - virtual void - getAllKeyNamesOfIdentity(const Name& identity, std::vector& nameList, bool isDefault) = 0; - - /** - * @brief Get all the certificate name in public info - * - * @param [out] nameList On return, the certificate name list - * @param isDefault If specified, only the default certificates are returned - */ - virtual void - getAllCertificateNames(std::vector& nameList, bool isDefault) = 0; - - /** - * @brief Get all the certificate name of a particular key name - * - * @param keyName The specified key name - * @param [out] nameList On return, the certificate name list - * @param isDefault If specified, only the default certificate is returned - */ - virtual void - getAllCertificateNamesOfKey(const Name& keyName, std::vector& nameList, bool isDefault) = 0; - - /***************************************** - * Delete Methods * - *****************************************/ - - /** - * @brief Delete a certificate - * - * @param certificateName The certificate name - */ - virtual void - deleteCertificateInfo(const Name& certificateName) = 0; - - /** - * @brief Delete a public key and related certificates - * - * @param keyName The key name - */ - virtual void - deletePublicKeyInfo(const Name& keyName) = 0; - - /** - * @brief Delete an identity and related public keys and certificates - * - * @param identity The identity name - */ - virtual void - deleteIdentityInfo(const Name& identity) = 0; - -protected: - - /***************************************** - * Default Setter * - *****************************************/ - - /** - * @brief Set the default identity - * - * @param identityName The default identity name - */ - virtual void - setDefaultIdentityInternal(const Name& identityName) = 0; - - /** - * @brief Set the default key name for the corresponding identity - * - * @param keyName The key name - * @throws SecPublicInfo::Error if the key does not exist - */ - virtual void - setDefaultKeyNameForIdentityInternal(const Name& keyName) = 0; - - /** - * @brief Set the default certificate name for the corresponding key - * - * @param certificateName The certificate name - * @throws SecPublicInfo::Error if the certificate does not exist - */ - virtual void - setDefaultCertificateNameForKeyInternal(const Name& certificateName) = 0; - - /** - * @brief return the scheme of the PibLocator - */ - virtual std::string - getScheme() = 0; - -public: - - /***************************************** - * Helper Methods * - *****************************************/ - - /** - * @brief Set the default identity - * - * @param identityName The default identity name - * @throws SecPublicInfo::Error if the identity does not exist - */ - void - setDefaultIdentity(const Name& identityName); - - /** - * @brief Set the default key name for the corresponding identity - * - * @param keyName The key name - * @throws SecPublicInfo::Error if either the identity or key does not exist - */ - void - setDefaultKeyNameForIdentity(const Name& keyName); - - /** - * @brief Set the default certificate name for the corresponding key - * - * @param certificateName The certificate name - * @throws SecPublicInfo::Error if either the certificate or key does not exist - */ - void - setDefaultCertificateNameForKey(const Name& certificateName); - - /** - * @brief Generate a key name for the identity - * - * @param identityName The identity name - * @param useKsk If true, generate a KSK name, otherwise a DSK name - * @return The generated key name - */ - Name - getNewKeyName(const Name& identityName, bool useKsk); - - /** - * @brief Get the default certificate name for the specified identity - * - * @param identityName The identity name - * @return The default certificate name - * @throws SecPublicInfo::Error if no certificate is found - */ - Name - getDefaultCertificateNameForIdentity(const Name& identityName); - - /** - * @brief Get the default certificate name of the default identity - * - * @return The requested certificate name - * @throws SecPublicInfo::Error if no certificate is found - */ - Name - getDefaultCertificateName(); - - /** - * @brief Add a certificate and set the certificate as the default one of its corresponding key - * - * @param certificate The certificate to be added - * @throws SecPublicInfo::Error if the certificate cannot be added (though it is really rare) - */ - void - addCertificateAsKeyDefault(const v1::IdentityCertificate& certificate); - - /** - * @brief Add a certificate into the public key identity storage and set the certificate as the - * default one of its corresponding identity - * - * @param certificate The certificate to be added - * @throws SecPublicInfo::Error if the certificate cannot be added (though it is really rare) - */ - void - addCertificateAsIdentityDefault(const v1::IdentityCertificate& certificate); - - /** - * @brief Add a certificate into the public key identity storage and set the certificate as the - * default one of the default identity - * - * @param certificate The certificate to be added - * @throws SecPublicInfo::Error if the certificate cannot be added (though it is really rare) - */ - void - addCertificateAsSystemDefault(const v1::IdentityCertificate& certificate); - - /** - * @brief Get cached default certificate of the default identity - * - * @return The certificate which might be empty shared_ptr() - * @deprecated Use getDefaultCertificate instead - */ - DEPRECATED( - shared_ptr - defaultCertificate()); - - /** - * @brief Get cached default certificate of the default identity - * - * @return The certificate which might be empty shared_ptr() - */ - shared_ptr - getDefaultCertificate(); - - /** - * @brief try to get the default certificate of the default identity from the public info - */ - void - refreshDefaultCertificate(); - -protected: - shared_ptr m_defaultCertificate; - std::string m_location; -}; - -} // namespace security - -using security::SecPublicInfo; - -} // namespace ndn - -#endif // NDN_SECURITY_SEC_PUBLIC_INFO_HPP diff --git a/src/security/sec-rule-relative.cpp b/src/security/sec-rule-relative.cpp deleted file mode 100644 index 7f8de8f7d..000000000 --- a/src/security/sec-rule-relative.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#include "common.hpp" - -#include "sec-rule-relative.hpp" - -#include "signature-sha256-with-rsa.hpp" -#include "security-common.hpp" - -namespace ndn { - -using std::string; - -SecRuleRelative::SecRuleRelative(const string& dataRegex, const string& signerRegex, - const string& op, - const string& dataExpand, const string& signerExpand, - bool isPositive) - : SecRule(isPositive), - m_dataRegex(dataRegex), - m_signerRegex(signerRegex), - m_op(op), - m_dataExpand(dataExpand), - m_signerExpand(signerExpand), - m_dataNameRegex(dataRegex, dataExpand), - m_signerNameRegex(signerRegex, signerExpand) -{ - if (op != ">" && op != ">=" && op != "==") - BOOST_THROW_EXCEPTION(Error("op is wrong")); -} - -SecRuleRelative::~SecRuleRelative() -{ -} - -bool -SecRuleRelative::satisfy(const Data& data) -{ - Name dataName = data.getName(); - try - { - if (!data.getSignature().hasKeyLocator()) - return false; - - const KeyLocator& keyLocator = data.getSignature().getKeyLocator(); - if (keyLocator.getType() != KeyLocator::KeyLocator_Name) - return false; - - const Name& signerName = keyLocator.getName(); - return satisfy(dataName, signerName); - } - catch (tlv::Error& e) - { - return false; - } - catch (RegexMatcher::Error& e) - { - return false; - } -} - -bool -SecRuleRelative::satisfy(const Name& dataName, const Name& signerName) -{ - if (!m_dataNameRegex.match(dataName)) - return false; - Name expandDataName = m_dataNameRegex.expand(); - - if (!m_signerNameRegex.match(signerName)) - return false; - Name expandSignerName = m_signerNameRegex.expand(); - - bool matched = compare(expandDataName, expandSignerName); - - return matched; -} - -bool -SecRuleRelative::matchDataName(const Data& data) -{ - return m_dataNameRegex.match(data.getName()); -} - -bool -SecRuleRelative::matchSignerName(const Data& data) -{ - try - { - if (!data.getSignature().hasKeyLocator()) - return false; - - const KeyLocator& keyLocator = data.getSignature().getKeyLocator(); - if (keyLocator.getType() != KeyLocator::KeyLocator_Name) - return false; - - const Name& signerName = keyLocator.getName(); - return m_signerNameRegex.match(signerName); - } - catch (tlv::Error& e) - { - return false; - } - catch (RegexMatcher::Error& e) - { - return false; - } -} - -bool -SecRuleRelative::compare(const Name& dataName, const Name& signerName) -{ - if ((dataName == signerName) && ("==" == m_op || ">=" == m_op)) - return true; - - Name::const_iterator i = dataName.begin(); - Name::const_iterator j = signerName.begin(); - - for (; i != dataName.end() && j != signerName.end(); i++, j++) - { - if (i->compare(*j) == 0) - continue; - else - return false; - } - - if (i == dataName.end()) - return false; - else - return true; -} - -} // namespace ndn diff --git a/src/security/sec-rule-relative.hpp b/src/security/sec-rule-relative.hpp deleted file mode 100644 index 105c621d6..000000000 --- a/src/security/sec-rule-relative.hpp +++ /dev/null @@ -1,82 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_SECURITY_SEC_RULE_RELATIVE_HPP -#define NDN_SECURITY_SEC_RULE_RELATIVE_HPP - -#include "sec-rule.hpp" -#include "../util/regex.hpp" - -namespace ndn { - -class SecRuleRelative : public SecRule -{ -public: - class Error : public SecRule::Error - { - public: - explicit - Error(const std::string& what) - : SecRule::Error(what) - { - } - }; - - SecRuleRelative(const std::string& dataRegex, const std::string& signerRegex, - const std::string& op, - const std::string& dataExpand, const std::string& signerExpand, - bool isPositive); - - virtual - ~SecRuleRelative(); - - virtual bool - matchDataName(const Data& data); - - virtual bool - matchSignerName(const Data& data); - - virtual bool - satisfy(const Data& data); - - virtual bool - satisfy(const Name& dataName, const Name& signerName); - -private: - bool - compare(const Name& dataName, const Name& signerName); - -private: - const std::string m_dataRegex; - const std::string m_signerRegex; - const std::string m_op; - const std::string m_dataExpand; - const std::string m_signerExpand; - - Regex m_dataNameRegex; - Regex m_signerNameRegex; -}; - -} // namespace ndn - -#endif //NDN_SECURITY_SEC_RULE_RELATIVE_HPP diff --git a/src/security/sec-rule-specific.cpp b/src/security/sec-rule-specific.cpp deleted file mode 100644 index 061132fcc..000000000 --- a/src/security/sec-rule-specific.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#include "common.hpp" - -#include "sec-rule-specific.hpp" -#include "signature-sha256-with-rsa.hpp" - -namespace ndn { - -SecRuleSpecific::SecRuleSpecific(shared_ptr dataRegex, - shared_ptr signerRegex) - : SecRule(true) - , m_dataRegex(dataRegex) - , m_signerRegex(signerRegex) - , m_isExempted(false) -{ -} - -SecRuleSpecific::SecRuleSpecific(shared_ptr dataRegex) - : SecRule(true) - , m_dataRegex(dataRegex) - , m_isExempted(true) -{ -} - -SecRuleSpecific::SecRuleSpecific(const SecRuleSpecific& rule) - : SecRule(true) - , m_dataRegex(rule.m_dataRegex) - , m_signerRegex(rule.m_signerRegex) - , m_isExempted(rule.m_isExempted) -{ -} - -bool -SecRuleSpecific::matchDataName(const Data& data) -{ - return m_dataRegex->match(data.getName()); -} - -bool -SecRuleSpecific::matchSignerName(const Data& data) -{ - if (m_isExempted) - return true; - - try - { - if (!data.getSignature().hasKeyLocator()) - return false; - - const KeyLocator& keyLocator = data.getSignature().getKeyLocator(); - if (keyLocator.getType() != KeyLocator::KeyLocator_Name) - return false; - - const Name& signerName = keyLocator.getName(); - return m_signerRegex->match(signerName); - } - catch (tlv::Error& e) - { - return false; - } - catch (RegexMatcher::Error& e) - { - return false; - } -} - -bool -SecRuleSpecific::satisfy(const Data& data) -{ - return (matchDataName(data) && matchSignerName(data)) ? true : false; -} - -bool -SecRuleSpecific::satisfy(const Name& dataName, const Name& signerName) -{ - bool isSignerMatched = m_isExempted || m_signerRegex->match(signerName); - return m_dataRegex->match(dataName) && isSignerMatched; -} - -} // namespace ndn diff --git a/src/security/sec-rule-specific.hpp b/src/security/sec-rule-specific.hpp deleted file mode 100644 index ade4b0c6e..000000000 --- a/src/security/sec-rule-specific.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_SECURITY_SEC_RULE_SPECIFIC_H -#define NDN_SECURITY_SEC_RULE_SPECIFIC_H - -#include "../common.hpp" -#include "sec-rule.hpp" -#include "../util/regex.hpp" - -namespace ndn { - -class SecRuleSpecific : public SecRule -{ - -public: - SecRuleSpecific(shared_ptr dataRegex, - shared_ptr signerRegex); - - explicit - SecRuleSpecific(shared_ptr dataRegex); - - explicit - SecRuleSpecific(const SecRuleSpecific& rule); - - virtual - ~SecRuleSpecific() {}; - - bool - matchDataName(const Data& data); - - bool - matchSignerName(const Data& data); - - bool - satisfy(const Data& data); - - bool - satisfy(const Name& dataName, const Name& signerName); - - bool - isExempted() const - { - return m_isExempted; - } - -private: - shared_ptr m_dataRegex; - shared_ptr m_signerRegex; - bool m_isExempted; -}; - -} // namespace ndn - -#endif //NDN_SECURITY_SEC_RULE_SPECIFIC_H diff --git a/src/security/sec-rule.hpp b/src/security/sec-rule.hpp deleted file mode 100644 index 43f504c64..000000000 --- a/src/security/sec-rule.hpp +++ /dev/null @@ -1,83 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_SECURITY_SEC_RULE_HPP -#define NDN_SECURITY_SEC_RULE_HPP - -#include "../common.hpp" -#include "../data.hpp" - -namespace ndn { - -class SecRule -{ -public: - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - - explicit - SecRule(bool isPositive) - : m_isPositive(isPositive) - { - } - - virtual - ~SecRule() - { - } - - virtual bool - matchDataName(const Data& data) = 0; - - virtual bool - matchSignerName(const Data& data) = 0; - - virtual bool - satisfy(const Data& data) = 0; - - virtual bool - satisfy(const Name& dataName, const Name& signerName) = 0; - - inline bool - isPositive(); - -protected: - bool m_isPositive; -}; - -bool -SecRule::isPositive() -{ - return m_isPositive; -} - -} // namespace ndn - -#endif //NDN_SECURITY_SEC_RULE_HPP diff --git a/src/security/sec-tpm-file.cpp b/src/security/sec-tpm-file.cpp deleted file mode 100644 index 931d8fdb5..000000000 --- a/src/security/sec-tpm-file.cpp +++ /dev/null @@ -1,591 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Xingyu Ma - * @author Yingdi Yu - * @author Alexander Afanasyev - */ - -#include "sec-tpm-file.hpp" - -#include "../encoding/buffer-stream.hpp" - -#include -#include - -#include "v1/cryptopp.hpp" - -#include -#include - -#include - -namespace ndn { -namespace security { - -using std::string; -using std::ostringstream; -using std::ofstream; - -const std::string SecTpmFile::SCHEME("tpm-file"); - -class SecTpmFile::Impl -{ -public: - explicit - Impl(const string& dir) - { - boost::filesystem::path actualDir; - if (dir.empty()) { -#ifdef NDN_CXX_HAVE_TESTS - if (getenv("TEST_HOME") != nullptr) { - actualDir = boost::filesystem::path(getenv("TEST_HOME")) / ".ndn"; - } - else -#endif // NDN_CXX_HAVE_TESTS - if (getenv("HOME") != nullptr) { - actualDir = boost::filesystem::path(getenv("HOME")) / ".ndn"; - } - else { - actualDir = boost::filesystem::path(".") / ".ndn"; - } - } - else { - actualDir = boost::filesystem::path(dir); - } - - m_keystorePath = actualDir / "ndnsec-tpm-file"; - boost::filesystem::create_directories(m_keystorePath); - } - - boost::filesystem::path - transformName(const string& keyName, const string& extension) - { - using namespace CryptoPP; - string digest; - SHA256 hash; - StringSource src(keyName, - true, - new HashFilter(hash, - new Base64Encoder(new CryptoPP::StringSink(digest)))); - - boost::algorithm::trim(digest); - std::replace(digest.begin(), digest.end(), '/', '%'); - - return m_keystorePath / (digest + extension); - } - - string - maintainMapping(const string& keyName) - { - string keyFileName = transformName(keyName, "").string(); - - ofstream outfile; - string dirFile = (m_keystorePath / "mapping.txt").string(); - - outfile.open(dirFile.c_str(), std::ios_base::app); - outfile << keyName << ' ' << keyFileName << '\n'; - outfile.close(); - - return keyFileName; - } - -public: - boost::filesystem::path m_keystorePath; -}; - - -SecTpmFile::SecTpmFile(const string& location) - : SecTpm(location) - , m_impl(new Impl(location)) - , m_inTerminal(false) -{ -} - -SecTpmFile::~SecTpmFile() -{ -} - -void -SecTpmFile::generateKeyPairInTpm(const Name& keyName, const KeyParams& params) -{ - string keyURI = keyName.toUri(); - - if (doesKeyExistInTpm(keyName, KeyClass::PUBLIC)) - BOOST_THROW_EXCEPTION(Error("public key exists")); - if (doesKeyExistInTpm(keyName, KeyClass::PRIVATE)) - BOOST_THROW_EXCEPTION(Error("private key exists")); - - string keyFileName = m_impl->maintainMapping(keyURI); - - try { - switch (params.getKeyType()) { - case KeyType::RSA: { - using namespace CryptoPP; - - const RsaKeyParams& rsaParams = static_cast(params); - AutoSeededRandomPool rng; - InvertibleRSAFunction privateKey; - privateKey.Initialize(rng, rsaParams.getKeySize()); - - string privateKeyFileName = keyFileName + ".pri"; - Base64Encoder privateKeySink(new FileSink(privateKeyFileName.c_str())); - privateKey.DEREncode(privateKeySink); - privateKeySink.MessageEnd(); - - RSAFunction publicKey(privateKey); - string publicKeyFileName = keyFileName + ".pub"; - Base64Encoder publicKeySink(new FileSink(publicKeyFileName.c_str())); - publicKey.DEREncode(publicKeySink); - publicKeySink.MessageEnd(); - - // set file permission - chmod(privateKeyFileName.c_str(), 0000400); - chmod(publicKeyFileName.c_str(), 0000444); - return; - } - - case KeyType::EC: { - using namespace CryptoPP; - - const EcdsaKeyParams& ecdsaParams = static_cast(params); - - CryptoPP::OID curveName; - switch (ecdsaParams.getKeySize()) { - case 256: - curveName = ASN1::secp256r1(); - break; - case 384: - curveName = ASN1::secp384r1(); - break; - default: - curveName = ASN1::secp256r1(); - break; - } - - AutoSeededRandomPool rng; - - ECDSA::PrivateKey privateKey; - DL_GroupParameters_EC cryptoParams(curveName); - cryptoParams.SetEncodeAsOID(true); - privateKey.Initialize(rng, cryptoParams); - - ECDSA::PublicKey publicKey; - privateKey.MakePublicKey(publicKey); - publicKey.AccessGroupParameters().SetEncodeAsOID(true); - - string privateKeyFileName = keyFileName + ".pri"; - Base64Encoder privateKeySink(new FileSink(privateKeyFileName.c_str())); - privateKey.DEREncode(privateKeySink); - privateKeySink.MessageEnd(); - - string publicKeyFileName = keyFileName + ".pub"; - Base64Encoder publicKeySink(new FileSink(publicKeyFileName.c_str())); - publicKey.Save(publicKeySink); - publicKeySink.MessageEnd(); - - // set file permission - chmod(privateKeyFileName.c_str(), 0000400); - chmod(publicKeyFileName.c_str(), 0000444); - return; - } - - default: - BOOST_THROW_EXCEPTION(Error("Unsupported key type")); - } - } - catch (const KeyParams::Error& e) { - BOOST_THROW_EXCEPTION(Error(e.what())); - } - catch (const CryptoPP::Exception& e) { - BOOST_THROW_EXCEPTION(Error(e.what())); - } -} - -void -SecTpmFile::deleteKeyPairInTpm(const Name& keyName) -{ - boost::filesystem::path publicKeyPath(m_impl->transformName(keyName.toUri(), ".pub")); - boost::filesystem::path privateKeyPath(m_impl->transformName(keyName.toUri(), ".pri")); - - if (boost::filesystem::exists(publicKeyPath)) - boost::filesystem::remove(publicKeyPath); - - if (boost::filesystem::exists(privateKeyPath)) - boost::filesystem::remove(privateKeyPath); -} - -shared_ptr -SecTpmFile::getPublicKeyFromTpm(const Name& keyName) -{ - string keyURI = keyName.toUri(); - - if (!doesKeyExistInTpm(keyName, KeyClass::PUBLIC)) - BOOST_THROW_EXCEPTION(Error("Public Key does not exist")); - - ostringstream os; - try { - using namespace CryptoPP; - FileSource(m_impl->transformName(keyURI, ".pub").string().c_str(), - true, - new Base64Decoder(new FileSink(os))); - } - catch (const CryptoPP::Exception& e) { - BOOST_THROW_EXCEPTION(Error(e.what())); - } - - return make_shared(reinterpret_cast(os.str().c_str()), - os.str().size()); -} - -std::string -SecTpmFile::getScheme() -{ - return SCHEME; -} - -ConstBufferPtr -SecTpmFile::exportPrivateKeyPkcs8FromTpm(const Name& keyName) -{ - OBufferStream privateKeyOs; - CryptoPP::FileSource(m_impl->transformName(keyName.toUri(), ".pri").string().c_str(), true, - new CryptoPP::Base64Decoder(new CryptoPP::FileSink(privateKeyOs))); - - return privateKeyOs.buf(); -} - -bool -SecTpmFile::importPrivateKeyPkcs8IntoTpm(const Name& keyName, const uint8_t* buf, size_t size) -{ - try { - using namespace CryptoPP; - - string keyFileName = m_impl->maintainMapping(keyName.toUri()); - keyFileName.append(".pri"); - StringSource(buf, size, - true, - new Base64Encoder(new FileSink(keyFileName.c_str()))); - return true; - } - catch (const CryptoPP::Exception& e) { - return false; - } -} - -bool -SecTpmFile::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size) -{ - try { - using namespace CryptoPP; - - string keyFileName = m_impl->maintainMapping(keyName.toUri()); - keyFileName.append(".pub"); - StringSource(buf, size, - true, - new Base64Encoder(new FileSink(keyFileName.c_str()))); - return true; - } - catch (const CryptoPP::Exception& e) { - return false; - } -} - -Block -SecTpmFile::signInTpm(const uint8_t* data, size_t dataLength, - const Name& keyName, DigestAlgorithm digestAlgorithm) -{ - string keyURI = keyName.toUri(); - - if (!doesKeyExistInTpm(keyName, KeyClass::PRIVATE)) - BOOST_THROW_EXCEPTION(Error("private key doesn't exist")); - - try { - using namespace CryptoPP; - AutoSeededRandomPool rng; - - // Read public key - shared_ptr pubkeyPtr; - pubkeyPtr = getPublicKeyFromTpm(keyName); - - switch (pubkeyPtr->getKeyType()) { - case KeyType::RSA: { - // Read private key - ByteQueue bytes; - FileSource file(m_impl->transformName(keyURI, ".pri").string().c_str(), - true, new Base64Decoder); - file.TransferTo(bytes); - bytes.MessageEnd(); - RSA::PrivateKey privateKey; - privateKey.Load(bytes); - - // Sign message - switch (digestAlgorithm) { - case DigestAlgorithm::SHA256: { - RSASS::Signer signer(privateKey); - - OBufferStream os; - StringSource(data, dataLength, - true, - new SignerFilter(rng, signer, new FileSink(os))); - - return Block(tlv::SignatureValue, os.buf()); - } - - default: - BOOST_THROW_EXCEPTION(Error("Unsupported digest algorithm")); - } - } - - case KeyType::EC: { - // Read private key - ByteQueue bytes; - FileSource file(m_impl->transformName(keyURI, ".pri").string().c_str(), - true, new Base64Decoder); - file.TransferTo(bytes); - bytes.MessageEnd(); - - // Sign message - switch (digestAlgorithm) { - case DigestAlgorithm::SHA256: { - ECDSA::PrivateKey privateKey; - privateKey.Load(bytes); - ECDSA::Signer signer(privateKey); - - OBufferStream os; - StringSource(data, dataLength, - true, - new SignerFilter(rng, signer, new FileSink(os))); - - uint8_t buf[200]; - size_t bufSize = DSAConvertSignatureFormat(buf, sizeof(buf), DSA_DER, - os.buf()->buf(), os.buf()->size(), - DSA_P1363); - - shared_ptr sigBuffer = make_shared(buf, bufSize); - - return Block(tlv::SignatureValue, sigBuffer); - } - - default: - BOOST_THROW_EXCEPTION(Error("Unsupported digest algorithm")); - } - } - - default: - BOOST_THROW_EXCEPTION(Error("Unsupported key type")); - } - } - catch (const CryptoPP::Exception& e) { - BOOST_THROW_EXCEPTION(Error(e.what())); - } -} - - -ConstBufferPtr -SecTpmFile::decryptInTpm(const uint8_t* data, size_t dataLength, - const Name& keyName, bool isSymmetric) -{ - BOOST_THROW_EXCEPTION(Error("SecTpmFile::decryptInTpm is not supported")); - // string keyURI = keyName.toUri(); - // if (!isSymmetric) - // { - // if (!doesKeyExistInTpm(keyName, KeyClass::PRIVATE)) - // throw Error("private key doesn't exist"); - - // try{ - // using namespace CryptoPP; - // AutoSeededRandomPool rng; - - // //Read private key - // ByteQueue bytes; - // FileSource file(m_impl->transformName(keyURI, ".pri").string().c_str(), true, new Base64Decoder); - // file.TransferTo(bytes); - // bytes.MessageEnd(); - // RSA::PrivateKey privateKey; - // privateKey.Load(bytes); - // RSAES_PKCS1v15_Decryptor decryptor(privateKey); - - // OBufferStream os; - // StringSource(data, dataLength, true, new PK_DecryptorFilter(rng, decryptor, new FileSink(os))); - - // return os.buf(); - // } - // catch (const CryptoPP::Exception& e){ - // throw Error(e.what()); - // } - // } - // else - // { - // throw Error("Symmetric encryption is not implemented!"); - // // if (!doesKeyExistInTpm(keyName, KeyClass::SYMMETRIC)) - // // throw Error("symmetric key doesn't exist"); - - // // try{ - // // string keyBits; - // // string symKeyFileName = m_impl->transformName(keyURI, ".key"); - // // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits))); - - // // using CryptoPP::AES; - // // AutoSeededRandomPool rnd; - // // byte iv[AES::BLOCKSIZE]; - // // rnd.GenerateBlock(iv, AES::BLOCKSIZE); - - // // CFB_Mode::Decryption decryptor; - // // decryptor.SetKeyWithIV(reinterpret_cast(keyBits.c_str()), keyBits.size(), iv); - - // // OBufferStream os; - // // StringSource(data, dataLength, true, new StreamTransformationFilter(decryptor,new FileSink(os))); - // // return os.buf(); - - // // } - // // catch (const CryptoPP::Exception& e){ - // // throw Error(e.what()); - // // } - // } -} - -ConstBufferPtr -SecTpmFile::encryptInTpm(const uint8_t* data, size_t dataLength, - const Name& keyName, bool isSymmetric) -{ - BOOST_THROW_EXCEPTION(Error("SecTpmFile::encryptInTpm is not supported")); - // string keyURI = keyName.toUri(); - - // if (!isSymmetric) - // { - // if (!doesKeyExistInTpm(keyName, KeyClass::PUBLIC)) - // throw Error("public key doesn't exist"); - // try - // { - // using namespace CryptoPP; - // AutoSeededRandomPool rng; - - // //Read private key - // ByteQueue bytes; - // FileSource file(m_impl->transformName(keyURI, ".pub").string().c_str(), true, new Base64Decoder); - // file.TransferTo(bytes); - // bytes.MessageEnd(); - // RSA::PublicKey publicKey; - // publicKey.Load(bytes); - - // OBufferStream os; - // RSAES_PKCS1v15_Encryptor encryptor(publicKey); - - // StringSource(data, dataLength, true, new PK_EncryptorFilter(rng, encryptor, new FileSink(os))); - // return os.buf(); - // } - // catch (const CryptoPP::Exception& e){ - // throw Error(e.what()); - // } - // } - // else - // { - // throw Error("Symmetric encryption is not implemented!"); - // // if (!doesKeyExistInTpm(keyName, KeyClass::SYMMETRIC)) - // // throw Error("symmetric key doesn't exist"); - - // // try{ - // // string keyBits; - // // string symKeyFileName = m_impl->transformName(keyURI, ".key"); - // // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits))); - - // // using CryptoPP::AES; - // // AutoSeededRandomPool rnd; - // // byte iv[AES::BLOCKSIZE]; - // // rnd.GenerateBlock(iv, AES::BLOCKSIZE); - - // // CFB_Mode::Encryption encryptor; - // // encryptor.SetKeyWithIV(reinterpret_cast(keyBits.c_str()), keyBits.size(), iv); - - // // OBufferStream os; - // // StringSource(data, dataLength, true, new StreamTransformationFilter(encryptor, new FileSink(os))); - // // return os.buf(); - // // } catch (const CryptoPP::Exception& e){ - // // throw Error(e.what()); - // // } - // } -} - -void -SecTpmFile::generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params) -{ - BOOST_THROW_EXCEPTION(Error("SecTpmFile::generateSymmetricKeyInTpm is not supported")); - // string keyURI = keyName.toUri(); - - // if (doesKeyExistInTpm(keyName, KeyClass::SYMMETRIC)) - // throw Error("symmetric key exists"); - - // string keyFileName = m_impl->maintainMapping(keyURI); - // string symKeyFileName = keyFileName + ".key"; - - // try{ - // switch (keyType){ - // case KeyType::AES: - // { - // using namespace CryptoPP; - // AutoSeededRandomPool rng; - - // SecByteBlock key(0x00, keySize); - // rng.GenerateBlock(key, keySize); - - // StringSource(key, key.size(), true, new HexEncoder(new FileSink(symKeyFileName.c_str()))); - - // chmod(symKeyFileName.c_str(), 0000400); - // return; - // } - // default: - // throw Error("Unsupported symmetric key type!"); - // } - // } catch (const CryptoPP::Exception& e){ - // throw Error(e.what()); - // } -} - -bool -SecTpmFile::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass) -{ - string keyURI = keyName.toUri(); - if (keyClass == KeyClass::PUBLIC) { - return boost::filesystem::exists(m_impl->transformName(keyURI, ".pub")); - } - if (keyClass == KeyClass::PRIVATE) { - return boost::filesystem::exists(m_impl->transformName(keyURI, ".pri")); - } - if (keyClass == KeyClass::SYMMETRIC) { - return boost::filesystem::exists(m_impl->transformName(keyURI, ".key")); - } - return false; -} - -bool -SecTpmFile::generateRandomBlock(uint8_t* res, size_t size) -{ - try { - CryptoPP::AutoSeededRandomPool rng; - rng.GenerateBlock(res, size); - return true; - } - catch (const CryptoPP::Exception& e) { - return false; - } -} - -} // namespace security -} // namespace ndn diff --git a/src/security/sec-tpm-file.hpp b/src/security/sec-tpm-file.hpp deleted file mode 100644 index ed25d2d59..000000000 --- a/src/security/sec-tpm-file.hpp +++ /dev/null @@ -1,153 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Xingyu Ma - * @author Yingdi Yu - * @author Alexander Afanasyev - */ - -#ifndef NDN_SECURITY_SEC_TPM_FILE_HPP -#define NDN_SECURITY_SEC_TPM_FILE_HPP - -#include "../common.hpp" - -#include "sec-tpm.hpp" - -namespace ndn { -namespace security { - -class SecTpmFile : public SecTpm -{ -public: - class Error : public SecTpm::Error - { - public: - explicit - Error(const std::string& what) - : SecTpm::Error(what) - { - } - }; - - explicit - SecTpmFile(const std::string& dir = ""); - - virtual - ~SecTpmFile(); - - virtual void - setTpmPassword(const uint8_t* password, size_t passwordLength) - { - } - - virtual void - resetTpmPassword() - { - } - - virtual void - setInTerminal(bool inTerminal) - { - m_inTerminal = inTerminal; - } - - virtual bool - getInTerminal() const - { - return m_inTerminal; - } - - virtual bool - isLocked() - { - return false; - } - - virtual bool - unlockTpm(const char* password, size_t passwordLength, bool usePassword) - { - return !isLocked(); - } - - virtual void - generateKeyPairInTpm(const Name& keyName, const KeyParams& params); - - virtual void - deleteKeyPairInTpm(const Name& keyName); - - virtual shared_ptr - getPublicKeyFromTpm(const Name& keyName); - - virtual Block - signInTpm(const uint8_t* data, size_t dataLength, - const Name& keyName, DigestAlgorithm digestAlgorithm); - - virtual ConstBufferPtr - decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric); - - virtual ConstBufferPtr - encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric); - - virtual void - generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params); - - virtual bool - doesKeyExistInTpm(const Name& keyName, KeyClass keyClass); - - virtual bool - generateRandomBlock(uint8_t* res, size_t size); - - virtual void - addAppToAcl(const Name& keyName, KeyClass keyClass, const std::string& appPath, AclType acl) - { - } - -protected: - //////////////////////////////// - // From TrustedPlatformModule // - //////////////////////////////// - virtual std::string - getScheme(); - - virtual ConstBufferPtr - exportPrivateKeyPkcs8FromTpm(const Name& keyName); - - virtual bool - importPrivateKeyPkcs8IntoTpm(const Name& keyName, const uint8_t* buf, size_t size); - - virtual bool - importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size); - -public: - static const std::string SCHEME; - -private: - class Impl; - unique_ptr m_impl; - bool m_inTerminal; -}; - -} // namespace security - -using security::SecTpmFile; - -} // namespace ndn - -#endif // NDN_SECURITY_SEC_TPM_FILE_HPP diff --git a/src/security/sec-tpm-osx.cpp b/src/security/sec-tpm-osx.cpp deleted file mode 100644 index 671a6f183..000000000 --- a/src/security/sec-tpm-osx.cpp +++ /dev/null @@ -1,1143 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#include "sec-tpm-osx.hpp" -#include "v1/public-key.hpp" - -#include "../encoding/oid.hpp" -#include "../encoding/buffer-stream.hpp" -#include "v1/cryptopp.hpp" - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include - -namespace ndn { -namespace security { - -using std::string; - -const std::string SecTpmOsx::SCHEME("tpm-osxkeychain"); - -/** - * @brief Helper class to wrap CoreFoundation object pointers - * - * The class is similar in spirit to shared_ptr, but uses CoreFoundation - * mechanisms to retain/release object. - * - * Original implementation by Christopher Hunt and it was borrowed from - * http://www.cocoabuilder.com/archive/cocoa/130776-auto-cfrelease-and.html - */ -template -class CFReleaser -{ -public: - ////////////////////////////// - // Construction/destruction // - - CFReleaser() - : m_typeRef(nullptr) - { - } - - CFReleaser(const T& typeRef) - : m_typeRef(typeRef) - { - } - - CFReleaser(const CFReleaser& inReleaser) - : m_typeRef(nullptr) - { - retain(inReleaser.m_typeRef); - } - - CFReleaser& - operator=(const T& typeRef) - { - if (typeRef != m_typeRef) { - release(); - m_typeRef = typeRef; - } - return *this; - } - - CFReleaser& - operator=(const CFReleaser& inReleaser) - { - retain(inReleaser.m_typeRef); - return *this; - } - - ~CFReleaser() - { - release(); - } - - //////////// - // Access // - - // operator const T&() const - // { - // return m_typeRef; - // } - - // operator T&() - // { - // return m_typeRef; - // } - - const T& - get() const - { - return m_typeRef; - } - - T& - get() - { - return m_typeRef; - } - - /////////////////// - // Miscellaneous // - - void - retain(const T& typeRef) - { - if (typeRef != nullptr) { - CFRetain(typeRef); - } - release(); - m_typeRef = typeRef; - } - - void - release() - { - if (m_typeRef != nullptr) { - CFRelease(m_typeRef); - m_typeRef = nullptr; - } - }; - - bool - operator==(std::nullptr_t) - { - return get() == nullptr; - } - - bool - operator!=(std::nullptr_t) - { - return get() != nullptr; - } - -private: - T m_typeRef; -}; - - -class SecTpmOsx::Impl -{ -public: - Impl() - : m_passwordSet(false) - , m_inTerminal(false) - { - } - - /** - * @brief Convert NDN name of a key to internal name of the key. - * - * @return the internal key name - */ - std::string - toInternalKeyName(const Name& keyName, KeyClass keyClass); - - /** - * @brief Get key. - * - * @returns pointer to the key - */ - CFReleaser - getKey(const Name& keyName, KeyClass keyClass); - - /** - * @brief Convert keyType to MAC OS symmetric key key type - * - * @returns MAC OS key type - */ - CFTypeRef - getSymKeyType(KeyType keyType); - - /** - * @brief Convert keyType to MAC OS asymmetirc key type - * - * @returns MAC OS key type - */ - CFTypeRef - getAsymKeyType(KeyType keyType); - - /** - * @brief Convert keyClass to MAC OS key class - * - * @returns MAC OS key class - */ - CFTypeRef - getKeyClass(KeyClass keyClass); - - /** - * @brief Convert digestAlgo to MAC OS algorithm id - * - * @returns MAC OS algorithm id - */ - CFStringRef - getDigestAlgorithm(DigestAlgorithm digestAlgo); - - /** - * @brief Get the digest size of the corresponding algorithm - * - * @return digest size - */ - long - getDigestSize(DigestAlgorithm digestAlgo); - - /////////////////////////////////////////////// - // everything here is public, including data // - /////////////////////////////////////////////// -public: - SecKeychainRef m_keyChainRef; - bool m_passwordSet; - string m_password; - bool m_inTerminal; -}; - -SecTpmOsx::SecTpmOsx(const std::string& location) - : SecTpm(location) - , m_impl(new Impl) -{ - // TODO: add location support - if (m_impl->m_inTerminal) - SecKeychainSetUserInteractionAllowed(false); - else - SecKeychainSetUserInteractionAllowed(true); - - OSStatus res = SecKeychainCopyDefault(&m_impl->m_keyChainRef); - - if (res == errSecNoDefaultKeychain) //If no default key chain, create one. - BOOST_THROW_EXCEPTION(Error("No default keychain, please create one first")); -} - -SecTpmOsx::~SecTpmOsx() -{ -} - -void -SecTpmOsx::setTpmPassword(const uint8_t* password, size_t passwordLength) -{ - m_impl->m_passwordSet = true; - std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0); - m_impl->m_password.clear(); - m_impl->m_password.append(reinterpret_cast(password), passwordLength); -} - -void -SecTpmOsx::resetTpmPassword() -{ - m_impl->m_passwordSet = false; - std::fill(m_impl->m_password.begin(), m_impl->m_password.end(), 0); - m_impl->m_password.clear(); -} - -void -SecTpmOsx::setInTerminal(bool inTerminal) -{ - m_impl->m_inTerminal = inTerminal; - if (inTerminal) - SecKeychainSetUserInteractionAllowed(false); - else - SecKeychainSetUserInteractionAllowed(true); -} - -bool -SecTpmOsx::getInTerminal() const -{ - return m_impl->m_inTerminal; -} - -bool -SecTpmOsx::isLocked() -{ - SecKeychainStatus keychainStatus; - - OSStatus res = SecKeychainGetStatus(m_impl->m_keyChainRef, &keychainStatus); - if (res != errSecSuccess) - return true; - else - return ((kSecUnlockStateStatus & keychainStatus) == 0); -} - -bool -SecTpmOsx::unlockTpm(const char* password, size_t passwordLength, bool usePassword) -{ - OSStatus res; - - // If the default key chain is already unlocked, return immediately. - if (!isLocked()) - return true; - - // If the default key chain is locked, unlock the key chain. - if (usePassword) { - // Use the supplied password. - res = SecKeychainUnlock(m_impl->m_keyChainRef, - passwordLength, - password, - true); - } - else if (m_impl->m_passwordSet) { - // If no password supplied, then use the configured password if exists. - SecKeychainUnlock(m_impl->m_keyChainRef, - m_impl->m_password.size(), - m_impl->m_password.c_str(), - true); - } -#ifdef NDN_CXX_HAVE_GETPASS - else if (m_impl->m_inTerminal) { - // If no configured password, get password from terminal if inTerminal set. - bool isLocked = true; - const char* fmt = "Password to unlock the default keychain: "; - int count = 0; - - while (isLocked) { - if (count > 2) - break; - - char* getPassword = nullptr; - getPassword = getpass(fmt); - count++; - - if (!getPassword) - continue; - - res = SecKeychainUnlock(m_impl->m_keyChainRef, - strlen(getPassword), - getPassword, - true); - - memset(getPassword, 0, strlen(getPassword)); - - if (res == errSecSuccess) - break; - } - } -#endif // NDN_CXX_HAVE_GETPASS - else { - // If inTerminal is not set, get the password from GUI. - SecKeychainUnlock(m_impl->m_keyChainRef, 0, nullptr, false); - } - - return !isLocked(); -} - -void -SecTpmOsx::generateKeyPairInTpmInternal(const Name& keyName, - const KeyParams& params, - bool needRetry) -{ - - if (doesKeyExistInTpm(keyName, KeyClass::PUBLIC)) { - BOOST_THROW_EXCEPTION(Error("keyName already exists")); - } - - string keyNameUri = m_impl->toInternalKeyName(keyName, KeyClass::PUBLIC); - - CFReleaser keyLabel = - CFStringCreateWithCString(0, - keyNameUri.c_str(), - kCFStringEncodingUTF8); - - CFReleaser attrDict = - CFDictionaryCreateMutable(0, - 3, - &kCFTypeDictionaryKeyCallBacks, - 0); - - KeyType keyType = params.getKeyType(); - uint32_t keySize = 0; - switch (keyType) { - case KeyType::RSA: { - const RsaKeyParams& rsaParams = static_cast(params); - keySize = rsaParams.getKeySize(); - break; - } - - case KeyType::EC: { - const EcdsaKeyParams& ecdsaParams = static_cast(params); - keySize = ecdsaParams.getKeySize(); - break; - } - - default: - BOOST_THROW_EXCEPTION(Error("Fail to create a key pair: Unsupported key type")); - } - - CFReleaser cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize); - - CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getAsymKeyType(keyType)); - CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get()); - CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get()); - - CFReleaser publicKey, privateKey; - // C-style cast is used as per Apple convention - OSStatus res = SecKeyGeneratePair((CFDictionaryRef)attrDict.get(), - &publicKey.get(), &privateKey.get()); - - if (res == errSecSuccess) { - return; - } - - if (res == errSecAuthFailed && !needRetry) { - if (unlockTpm(nullptr, 0, false)) - generateKeyPairInTpmInternal(keyName, params, true); - else - BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain")); - } - else { - BOOST_THROW_EXCEPTION(Error("Fail to create a key pair")); - } -} - -void -SecTpmOsx::deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry) -{ - CFReleaser keyLabel = - CFStringCreateWithCString(0, - keyName.toUri().c_str(), - kCFStringEncodingUTF8); - - CFReleaser searchDict = - CFDictionaryCreateMutable(0, 5, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - CFDictionaryAddValue(searchDict.get(), kSecClass, kSecClassKey); - CFDictionaryAddValue(searchDict.get(), kSecAttrLabel, keyLabel.get()); - CFDictionaryAddValue(searchDict.get(), kSecMatchLimit, kSecMatchLimitAll); - OSStatus res = SecItemDelete(searchDict.get()); - - if (res == errSecSuccess) - return; - - if (res == errSecAuthFailed && !needRetry) { - if (unlockTpm(nullptr, 0, false)) - deleteKeyPairInTpmInternal(keyName, true); - } -} - -void -SecTpmOsx::generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params) -{ - BOOST_THROW_EXCEPTION(Error("SecTpmOsx::generateSymmetricKeyInTpm is not supported")); - // if (doesKeyExistInTpm(keyName, KeyClass::SYMMETRIC)) - // throw Error("keyName has existed!"); - - // string keyNameUri = m_impl->toInternalKeyName(keyName, KeyClass::SYMMETRIC); - - // CFReleaser attrDict = - // CFDictionaryCreateMutable(kCFAllocatorDefault, - // 0, - // &kCFTypeDictionaryKeyCallBacks, - // &kCFTypeDictionaryValueCallBacks); - - // CFReleaser keyLabel = - // CFStringCreateWithCString(0, - // keyNameUri.c_str(), - // kCFStringEncodingUTF8); - - // CFReleaser cfKeySize = CFNumberCreate(0, kCFNumberIntType, &keySize); - - // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyType, m_impl->getSymKeyType(keyType)); - // CFDictionaryAddValue(attrDict.get(), kSecAttrKeySizeInBits, cfKeySize.get()); - // CFDictionaryAddValue(attrDict.get(), kSecAttrIsPermanent, kCFBooleanTrue); - // CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get()); - - // CFErrorRef error = 0; - - // SecKeyRef symmetricKey = SecKeyGenerateSymmetric(attrDict, &error); - - // if (error) - // throw Error("Fail to create a symmetric key"); -} - -shared_ptr -SecTpmOsx::getPublicKeyFromTpm(const Name& keyName) -{ - CFReleaser publicKey = m_impl->getKey(keyName, KeyClass::PUBLIC); - if (publicKey == nullptr) { - BOOST_THROW_EXCEPTION(Error("Requested public key [" + keyName.toUri() + "] does not exist " - "in OSX Keychain")); - } - - CFReleaser exportedKey; - OSStatus res = SecItemExport(publicKey.get(), - kSecFormatOpenSSL, - 0, - nullptr, - &exportedKey.get()); - if (res != errSecSuccess) { - BOOST_THROW_EXCEPTION(Error("Cannot export requested public key from OSX Keychain")); - } - - shared_ptr key = make_shared(CFDataGetBytePtr(exportedKey.get()), - CFDataGetLength(exportedKey.get())); - return key; -} - -std::string -SecTpmOsx::getScheme() -{ - return SCHEME; -} - -ConstBufferPtr -SecTpmOsx::exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry) -{ - using namespace CryptoPP; - - CFReleaser privateKey = m_impl->getKey(keyName, KeyClass::PRIVATE); - if (privateKey == nullptr) { - /// @todo Can this happen because of keychain is locked? - BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist " - "in OSX Keychain")); - } - - shared_ptr publicKey = getPublicKeyFromTpm(keyName); - - CFReleaser exportedKey; - OSStatus res = SecItemExport(privateKey.get(), - kSecFormatOpenSSL, - 0, - nullptr, - &exportedKey.get()); - - if (res != errSecSuccess) { - if (res == errSecAuthFailed && !needRetry) { - if (unlockTpm(nullptr, 0, false)) - return exportPrivateKeyPkcs8FromTpmInternal(keyName, true); - else - return nullptr; - } - else - return nullptr; - } - - uint32_t version = 0; - Oid algorithm; - bool hasParameters = false; - Oid algorithmParameter; - switch (publicKey->getKeyType()) { - case KeyType::RSA: { - algorithm = oid::RSA; // "RSA encryption" - hasParameters = false; - break; - } - - case KeyType::EC: { - // "ECDSA encryption" - StringSource src(publicKey->get().buf(), publicKey->get().size(), true); - BERSequenceDecoder subjectPublicKeyInfo(src); - { - BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo); - { - algorithm.decode(algorithmInfo); - algorithmParameter.decode(algorithmInfo); - } - } - hasParameters = true; - break; - } - - default: - BOOST_THROW_EXCEPTION(Error("Unsupported key type" + - boost::lexical_cast(publicKey->getKeyType()))); - } - - OBufferStream pkcs8Os; - FileSink sink(pkcs8Os); - - SecByteBlock rawKeyBits; - // PrivateKeyInfo ::= SEQUENCE { - // version INTEGER, - // privateKeyAlgorithm SEQUENCE, - // privateKey OCTECT STRING} - DERSequenceEncoder privateKeyInfo(sink); - { - DEREncodeUnsigned(privateKeyInfo, version, INTEGER); - DERSequenceEncoder privateKeyAlgorithm(privateKeyInfo); - { - algorithm.encode(privateKeyAlgorithm); - if (hasParameters) - algorithmParameter.encode(privateKeyAlgorithm); - else - DEREncodeNull(privateKeyAlgorithm); - } - privateKeyAlgorithm.MessageEnd(); - DEREncodeOctetString(privateKeyInfo, - CFDataGetBytePtr(exportedKey.get()), - CFDataGetLength(exportedKey.get())); - } - privateKeyInfo.MessageEnd(); - - return pkcs8Os.buf(); -} - -#ifdef __GNUC__ -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -#pragma GCC diagnostic push -#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif // __GNUC__ - -bool -SecTpmOsx::importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName, - const uint8_t* buf, size_t size, - bool needRetry) -{ - using namespace CryptoPP; - - StringSource privateKeySource(buf, size, true); - SecByteBlock rawKeyBits; - // PrivateKeyInfo ::= SEQUENCE { - // INTEGER, - // SEQUENCE, - // OCTECT STRING} - BERSequenceDecoder privateKeyInfo(privateKeySource); - { - uint32_t versionNum; - BERDecodeUnsigned(privateKeyInfo, versionNum, INTEGER); - BERSequenceDecoder sequenceDecoder(privateKeyInfo); - { - Oid keyTypeOid; - keyTypeOid.decode(sequenceDecoder); - - if (keyTypeOid == oid::RSA) - BERDecodeNull(sequenceDecoder); - else if (keyTypeOid == oid::ECDSA) { - Oid parameterOid; - parameterOid.decode(sequenceDecoder); - } - else - return false; // Unsupported key type; - } - BERDecodeOctetString(privateKeyInfo, rawKeyBits); - } - privateKeyInfo.MessageEnd(); - - CFReleaser importedKey = CFDataCreateWithBytesNoCopy(0, - rawKeyBits.BytePtr(), - rawKeyBits.size(), - kCFAllocatorNull); - - SecExternalFormat externalFormat = kSecFormatOpenSSL; - SecExternalItemType externalType = kSecItemTypePrivateKey; - SecKeyImportExportParameters keyParams; - memset(&keyParams, 0, sizeof(keyParams)); - keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; - keyParams.keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT; - CFReleaser access; - CFReleaser keyLabel = CFStringCreateWithCString(0, - keyName.toUri().c_str(), - kCFStringEncodingUTF8); - SecAccessCreate(keyLabel.get(), 0, &access.get()); - keyParams.accessRef = access.get(); - CFReleaser outItems; - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif // __clang__ - - OSStatus res = SecKeychainItemImport(importedKey.get(), - 0, - &externalFormat, - &externalType, - 0, - &keyParams, - m_impl->m_keyChainRef, - &outItems.get()); - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif // __clang__ - - if (res != errSecSuccess) { - if (res == errSecAuthFailed && !needRetry) { - if (unlockTpm(nullptr, 0, false)) - return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, true); - else - return false; - } - else - return false; - } - - // C-style cast is used as per Apple convention - SecKeychainItemRef privateKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0); - SecKeychainAttribute attrs[1]; // maximum number of attributes - SecKeychainAttributeList attrList = {0, attrs}; - string keyUri = keyName.toUri(); - { - attrs[attrList.count].tag = kSecKeyPrintName; - attrs[attrList.count].length = keyUri.size(); - attrs[attrList.count].data = const_cast(keyUri.c_str()); - attrList.count++; - } - - res = SecKeychainItemModifyAttributesAndData(privateKey, - &attrList, - 0, - nullptr); - - if (res != errSecSuccess) { - return false; - } - - return true; -} - -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -#pragma GCC diagnostic pop -#endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) - -bool -SecTpmOsx::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size) -{ - CFReleaser importedKey = CFDataCreateWithBytesNoCopy(0, - buf, - size, - kCFAllocatorNull); - - SecExternalFormat externalFormat = kSecFormatOpenSSL; - SecExternalItemType externalType = kSecItemTypePublicKey; - CFReleaser outItems; - - OSStatus res = SecItemImport(importedKey.get(), - 0, - &externalFormat, - &externalType, - 0, - 0, - m_impl->m_keyChainRef, - &outItems.get()); - - if (res != errSecSuccess) - return false; - - // C-style cast is used as per Apple convention - SecKeychainItemRef publicKey = (SecKeychainItemRef)CFArrayGetValueAtIndex(outItems.get(), 0); - SecKeychainAttribute attrs[1]; // maximum number of attributes - SecKeychainAttributeList attrList = { 0, attrs }; - string keyUri = keyName.toUri(); - { - attrs[attrList.count].tag = kSecKeyPrintName; - attrs[attrList.count].length = keyUri.size(); - attrs[attrList.count].data = const_cast(keyUri.c_str()); - attrList.count++; - } - - res = SecKeychainItemModifyAttributesAndData(publicKey, - &attrList, - 0, - 0); - - if (res != errSecSuccess) - return false; - - return true; -} - -Block -SecTpmOsx::signInTpmInternal(const uint8_t* data, size_t dataLength, - const Name& keyName, DigestAlgorithm digestAlgorithm, bool needRetry) -{ - CFReleaser dataRef = CFDataCreateWithBytesNoCopy(0, - data, - dataLength, - kCFAllocatorNull); - - CFReleaser privateKey = m_impl->getKey(keyName, KeyClass::PRIVATE); - if (privateKey == nullptr) { - BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist " - "in OSX Keychain")); - } - - CFReleaser error; - // C-style cast is used as per Apple convention - CFReleaser signer = SecSignTransformCreate((SecKeyRef)privateKey.get(), - &error.get()); - if (error != nullptr) - BOOST_THROW_EXCEPTION(Error("Fail to create signer")); - - // Set input - SecTransformSetAttribute(signer.get(), - kSecTransformInputAttributeName, - dataRef.get(), - &error.get()); - if (error != nullptr) - BOOST_THROW_EXCEPTION(Error("Fail to configure input of signer")); - - // Enable use of padding - SecTransformSetAttribute(signer.get(), - kSecPaddingKey, - kSecPaddingPKCS1Key, - &error.get()); - if (error != nullptr) - BOOST_THROW_EXCEPTION(Error("Fail to configure digest algorithm of signer")); - - // Set padding type - SecTransformSetAttribute(signer.get(), - kSecDigestTypeAttribute, - m_impl->getDigestAlgorithm(digestAlgorithm), - &error.get()); - if (error != nullptr) - BOOST_THROW_EXCEPTION(Error("Fail to configure digest algorithm of signer")); - - // Set padding attribute - long digestSize = m_impl->getDigestSize(digestAlgorithm); - CFReleaser cfDigestSize = CFNumberCreate(0, kCFNumberLongType, &digestSize); - SecTransformSetAttribute(signer.get(), - kSecDigestLengthAttribute, - cfDigestSize.get(), - &error.get()); - if (error != nullptr) - BOOST_THROW_EXCEPTION(Error("Fail to configure digest size of signer")); - - // Actually sign - // C-style cast is used as per Apple convention - CFReleaser signature = (CFDataRef)SecTransformExecute(signer.get(), &error.get()); - if (error != nullptr) { - if (!needRetry) { - if (unlockTpm(nullptr, 0, false)) - return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, true); - else - BOOST_THROW_EXCEPTION(Error("Fail to unlock the keychain")); - } - else { - CFShow(error.get()); - BOOST_THROW_EXCEPTION(Error("Fail to sign data")); - } - } - - if (signature == nullptr) - BOOST_THROW_EXCEPTION(Error("Signature is NULL!\n")); - - return Block(tlv::SignatureValue, - make_shared(CFDataGetBytePtr(signature.get()), - CFDataGetLength(signature.get()))); -} - -ConstBufferPtr -SecTpmOsx::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym) -{ - BOOST_THROW_EXCEPTION(Error("SecTpmOsx::decryptInTpm is not supported")); - - // KeyClass keyClass; - // if (sym) - // keyClass = KeyClass::SYMMETRIC; - // else - // keyClass = KeyClass::PRIVATE; - - // CFDataRef dataRef = CFDataCreate(0, - // reinterpret_cast(data), - // dataLength - // ); - - // CFReleaser decryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass); - // if (decryptKey == nullptr) - // { - // /// @todo Can this happen because of keychain is locked? - // throw Error("Decruption key [" + ??? + "] does not exist in OSX Keychain"); - // } - - // CFErrorRef error; - // SecTransformRef decrypt = SecDecryptTransformCreate(decryptKey, &error); - // if (error) throw Error("Fail to create decrypt"); - - // Boolean set_res = SecTransformSetAttribute(decrypt, - // kSecTransformInputAttributeName, - // dataRef, - // &error); - // if (error) throw Error("Fail to configure decrypt"); - - // CFDataRef output = (CFDataRef) SecTransformExecute(decrypt, &error); - // if (error) - // { - // CFShow(error); - // throw Error("Fail to decrypt data"); - // } - // if (!output) throw Error("Output is NULL!\n"); - - // return make_shared(CFDataGetBytePtr(output), CFDataGetLength(output)); -} - -void -SecTpmOsx::addAppToAcl(const Name& keyName, KeyClass keyClass, const string& appPath, AclType acl) -{ - if (keyClass == KeyClass::PRIVATE && acl == AclType::PRIVATE) { - CFReleaser privateKey = m_impl->getKey(keyName, keyClass); - if (privateKey == nullptr) { - BOOST_THROW_EXCEPTION(Error("Private key [" + keyName.toUri() + "] does not exist " - "in OSX Keychain")); - } - - CFReleaser accRef; - SecKeychainItemCopyAccess(privateKey.get(), &accRef.get()); - - CFReleaser signACL = SecAccessCopyMatchingACLList(accRef.get(), - kSecACLAuthorizationSign); - - // C-style cast is used as per Apple convention - SecACLRef aclRef = (SecACLRef)CFArrayGetValueAtIndex(signACL.get(), 0); - - CFReleaser appList; - CFReleaser description; - SecKeychainPromptSelector promptSelector; - SecACLCopyContents(aclRef, - &appList.get(), - &description.get(), - &promptSelector); - - CFReleaser newAppList = CFArrayCreateMutableCopy(0, - 0, - appList.get()); - - CFReleaser trustedApp; - SecTrustedApplicationCreateFromPath(appPath.c_str(), - &trustedApp.get()); - - CFArrayAppendValue(newAppList.get(), trustedApp.get()); - - SecACLSetContents(aclRef, - newAppList.get(), - description.get(), - promptSelector); - - SecKeychainItemSetAccess(privateKey.get(), accRef.get()); - } -} - -ConstBufferPtr -SecTpmOsx::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool sym) -{ - BOOST_THROW_EXCEPTION(Error("SecTpmOsx::encryptInTpm is not supported")); - - // KeyClass keyClass; - // if (sym) - // keyClass = KeyClass::SYMMETRIC; - // else - // keyClass = KeyClass::PUBLIC; - - // CFDataRef dataRef = CFDataCreate(0, - // reinterpret_cast(data), - // dataLength - // ); - - // CFReleaser encryptKey = (SecKeyRef)m_impl->getKey(keyName, keyClass); - // if (encryptKey == nullptr) - // { - // throw Error("Encryption key [" + ???? + "] does not exist in OSX Keychain"); - // } - - // CFErrorRef error; - // SecTransformRef encrypt = SecEncryptTransformCreate(encryptKey, &error); - // if (error) throw Error("Fail to create encrypt"); - - // Boolean set_res = SecTransformSetAttribute(encrypt, - // kSecTransformInputAttributeName, - // dataRef, - // &error); - // if (error) throw Error("Fail to configure encrypt"); - - // CFDataRef output = (CFDataRef) SecTransformExecute(encrypt, &error); - // if (error) throw Error("Fail to encrypt data"); - - // if (!output) throw Error("Output is NULL!\n"); - - // return make_shared (CFDataGetBytePtr(output), CFDataGetLength(output)); -} - -bool -SecTpmOsx::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass) -{ - string keyNameUri = m_impl->toInternalKeyName(keyName, keyClass); - - CFReleaser keyLabel = CFStringCreateWithCString(0, - keyNameUri.c_str(), - kCFStringEncodingUTF8); - - CFReleaser attrDict = - CFDictionaryCreateMutable(0, - 4, - &kCFTypeDictionaryKeyCallBacks, - 0); - - CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey); - // CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, m_impl->getKeyClass(keyClass)); - CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get()); - CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue); - - CFReleaser itemRef; - // C-style cast is used as per Apple convention - OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&itemRef.get()); - - if (res == errSecSuccess) - return true; - else - return false; - -} - -bool -SecTpmOsx::generateRandomBlock(uint8_t* res, size_t size) -{ - return SecRandomCopyBytes(kSecRandomDefault, size, res) == 0; -} - -//////////////////////////////// -// OSXPrivateKeyStorage::Impl // -//////////////////////////////// - -CFReleaser -SecTpmOsx::Impl::getKey(const Name& keyName, KeyClass keyClass) -{ - string keyNameUri = toInternalKeyName(keyName, keyClass); - - CFReleaser keyLabel = CFStringCreateWithCString(0, - keyNameUri.c_str(), - kCFStringEncodingUTF8); - - CFReleaser attrDict = - CFDictionaryCreateMutable(0, - 5, - &kCFTypeDictionaryKeyCallBacks, - 0); - - CFDictionaryAddValue(attrDict.get(), kSecClass, kSecClassKey); - CFDictionaryAddValue(attrDict.get(), kSecAttrLabel, keyLabel.get()); - CFDictionaryAddValue(attrDict.get(), kSecAttrKeyClass, getKeyClass(keyClass)); - CFDictionaryAddValue(attrDict.get(), kSecReturnRef, kCFBooleanTrue); - - CFReleaser keyItem; - // C-style cast is used as per Apple convention - OSStatus res = SecItemCopyMatching((CFDictionaryRef)attrDict.get(), (CFTypeRef*)&keyItem.get()); - - if (res != errSecSuccess) - return 0; - else - return keyItem; -} - -string -SecTpmOsx::Impl::toInternalKeyName(const Name& keyName, KeyClass keyClass) -{ - string keyUri = keyName.toUri(); - - if (KeyClass::SYMMETRIC == keyClass) - return keyUri + "/symmetric"; - else - return keyUri; -} - -CFTypeRef -SecTpmOsx::Impl::getAsymKeyType(KeyType keyType) -{ - switch (keyType) { - case KeyType::RSA: - return kSecAttrKeyTypeRSA; - case KeyType::EC: - return kSecAttrKeyTypeECDSA; - default: - return 0; - } -} - -CFTypeRef -SecTpmOsx::Impl::getSymKeyType(KeyType keyType) -{ - switch (keyType) { - case KeyType::AES: - return kSecAttrKeyTypeAES; - default: - return 0; - } -} - -CFTypeRef -SecTpmOsx::Impl::getKeyClass(KeyClass keyClass) -{ - switch (keyClass) { - case KeyClass::PRIVATE: - return kSecAttrKeyClassPrivate; - case KeyClass::PUBLIC: - return kSecAttrKeyClassPublic; - case KeyClass::SYMMETRIC: - return kSecAttrKeyClassSymmetric; - default: - return 0; - } -} - -CFStringRef -SecTpmOsx::Impl::getDigestAlgorithm(DigestAlgorithm digestAlgo) -{ - switch (digestAlgo) { - case DigestAlgorithm::SHA256: - return kSecDigestSHA2; - default: - return 0; - } -} - -long -SecTpmOsx::Impl::getDigestSize(DigestAlgorithm digestAlgo) -{ - switch (digestAlgo) { - case DigestAlgorithm::SHA256: - return 256; - default: - return -1; - } -} - -} // namespace security -} // namespace ndn diff --git a/src/security/sec-tpm-osx.hpp b/src/security/sec-tpm-osx.hpp deleted file mode 100644 index 1713f0666..000000000 --- a/src/security/sec-tpm-osx.hpp +++ /dev/null @@ -1,170 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_SECURITY_SEC_TPM_OSX_HPP -#define NDN_SECURITY_SEC_TPM_OSX_HPP - -#include "../common.hpp" - -#ifndef NDN_CXX_HAVE_OSX_SECURITY -#error "This files should not be compiled ..." -#endif - -#include "sec-tpm.hpp" - -namespace ndn { -namespace security { - -class SecTpmOsx : public SecTpm -{ -public: - class Error : public SecTpm::Error - { - public: - explicit - Error(const std::string& what) - : SecTpm::Error(what) - { - } - }; - - explicit - SecTpmOsx(const std::string& location = ""); - - virtual - ~SecTpmOsx(); - - // Following methods are inherited from SecTpm - virtual void - setTpmPassword(const uint8_t* password, size_t passwordLength); - - virtual void - resetTpmPassword(); - - virtual void - setInTerminal(bool inTerminal); - - virtual bool - getInTerminal() const; - - virtual bool - isLocked(); - - virtual bool - unlockTpm(const char* password, size_t passwordLength, bool usePassword); - - virtual void - generateKeyPairInTpm(const Name& keyName, const KeyParams& params) - { - generateKeyPairInTpmInternal(keyName, params, false); - } - - virtual void - deleteKeyPairInTpm(const Name& keyName) - { - deleteKeyPairInTpmInternal(keyName, false); - } - - virtual shared_ptr - getPublicKeyFromTpm(const Name& keyName); - - virtual Block - signInTpm(const uint8_t* data, size_t dataLength, - const Name& keyName, DigestAlgorithm digestAlgorithm) - { - return signInTpmInternal(data, dataLength, keyName, digestAlgorithm, false); - } - - virtual ConstBufferPtr - decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric); - - virtual ConstBufferPtr - encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric); - - virtual void - generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params); - - virtual bool - doesKeyExistInTpm(const Name& keyName, KeyClass keyClass); - - virtual bool - generateRandomBlock(uint8_t* res, size_t size); - - virtual void - addAppToAcl(const Name& keyName, KeyClass keyClass, const std::string& appPath, AclType acl); - -protected: - // Following methods are inherited from SecTpm - virtual std::string - getScheme(); - - virtual ConstBufferPtr - exportPrivateKeyPkcs8FromTpm(const Name& keyName) - { - return exportPrivateKeyPkcs8FromTpmInternal(keyName, false); - } - - virtual bool - importPrivateKeyPkcs8IntoTpm(const Name& keyName, const uint8_t* buf, size_t size) - { - return importPrivateKeyPkcs8IntoTpmInternal(keyName, buf, size, false); - } - - virtual bool - importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size); - - // Following methods are OSX-specific - void - generateKeyPairInTpmInternal(const Name& keyName, const KeyParams& params, bool needRetry); - - void - deleteKeyPairInTpmInternal(const Name& keyName, bool needRetry); - - ConstBufferPtr - exportPrivateKeyPkcs8FromTpmInternal(const Name& keyName, bool needRetry); - - bool - importPrivateKeyPkcs8IntoTpmInternal(const Name& keyName, - const uint8_t* buf, size_t size, - bool needRetry); - - Block - signInTpmInternal(const uint8_t* data, size_t dataLength, - const Name& keyName, DigestAlgorithm digestAlgorithm, - bool needRetry); - -public: - static const std::string SCHEME; - -private: - class Impl; - shared_ptr m_impl; -}; - -} // namespace security - -using security::SecTpmOsx; - -} // namespace ndn - -#endif // NDN_SECURITY_SEC_TPM_OSX_HPP diff --git a/src/security/sec-tpm.cpp b/src/security/sec-tpm.cpp deleted file mode 100644 index 2ce3d6613..000000000 --- a/src/security/sec-tpm.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#include "sec-tpm.hpp" - -#include "../encoding/oid.hpp" -#include "../encoding/buffer-stream.hpp" -#include "v1/cryptopp.hpp" -#include - -namespace ndn { -namespace security { - -SecTpm::SecTpm(const std::string& location) - : m_location(location) -{ -} - -SecTpm::~SecTpm() -{ -} - -std::string -SecTpm::getTpmLocator() -{ - return this->getScheme() + ":" + m_location; -} - -ConstBufferPtr -SecTpm::exportPrivateKeyPkcs5FromTpm(const Name& keyName, const std::string& passwordStr) -{ - using namespace CryptoPP; - - uint8_t salt[8] = {0}; - uint8_t iv[8] = {0}; - - // derive key - if (!generateRandomBlock(salt, 8) || !generateRandomBlock(iv, 8)) - BOOST_THROW_EXCEPTION(Error("Cannot generate salt or iv")); - - uint32_t iterationCount = 2048; - - PKCS5_PBKDF2_HMAC keyGenerator; - size_t derivedLen = 24; // For DES-EDE3-CBC-PAD - byte derived[24] = {0}; - byte purpose = 0; - - try { - keyGenerator.DeriveKey(derived, derivedLen, purpose, - reinterpret_cast(passwordStr.c_str()), passwordStr.size(), - salt, 8, iterationCount); - } - catch (const CryptoPP::Exception& e) { - BOOST_THROW_EXCEPTION(Error("Cannot derived the encryption key")); - } - - // encrypt - CBC_Mode< DES_EDE3 >::Encryption e; - e.SetKeyWithIV(derived, derivedLen, iv); - - ConstBufferPtr pkcs8PrivateKey = exportPrivateKeyPkcs8FromTpm(keyName); - - if (pkcs8PrivateKey == nullptr) - BOOST_THROW_EXCEPTION(Error("Cannot export the private key, #1")); - - OBufferStream encryptedOs; - try { - StringSource stringSource(pkcs8PrivateKey->buf(), pkcs8PrivateKey->size(), true, - new StreamTransformationFilter(e, new FileSink(encryptedOs))); - } - catch (const CryptoPP::Exception& e) { - BOOST_THROW_EXCEPTION(Error("Cannot export the private key, #2")); - } - - // encode - Oid pbes2Id("1.2.840.113549.1.5.13"); - Oid pbkdf2Id("1.2.840.113549.1.5.12"); - Oid pbes2encsId("1.2.840.113549.3.7"); - - OBufferStream pkcs8Os; - try { - FileSink sink(pkcs8Os); - - // EncryptedPrivateKeyInfo ::= SEQUENCE { - // encryptionAlgorithm EncryptionAlgorithmIdentifier, - // encryptedData OCTET STRING } - DERSequenceEncoder encryptedPrivateKeyInfo(sink); - { - // EncryptionAlgorithmIdentifier ::= SEQUENCE { - // algorithm OBJECT IDENTIFIER {{PBES2-id}}, - // parameters SEQUENCE {{PBES2-params}} } - DERSequenceEncoder encryptionAlgorithm(encryptedPrivateKeyInfo); - { - pbes2Id.encode(encryptionAlgorithm); - // PBES2-params ::= SEQUENCE { - // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, - // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} } - DERSequenceEncoder pbes2Params(encryptionAlgorithm); - { - // AlgorithmIdentifier ::= SEQUENCE { - // algorithm OBJECT IDENTIFIER {{PBKDF2-id}}, - // parameters SEQUENCE {{PBKDF2-params}} } - DERSequenceEncoder pbes2KDFs(pbes2Params); - { - pbkdf2Id.encode(pbes2KDFs); - // AlgorithmIdentifier ::= SEQUENCE { - // salt OCTET STRING, - // iterationCount INTEGER (1..MAX), - // keyLength INTEGER (1..MAX) OPTIONAL, - // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 } - DERSequenceEncoder pbkdf2Params(pbes2KDFs); - { - DEREncodeOctetString(pbkdf2Params, salt, 8); - DEREncodeUnsigned(pbkdf2Params, iterationCount, INTEGER); - } - pbkdf2Params.MessageEnd(); - } - pbes2KDFs.MessageEnd(); - - // AlgorithmIdentifier ::= SEQUENCE { - // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}}, - // parameters OCTET STRING} {{iv}} } - DERSequenceEncoder pbes2Encs(pbes2Params); - { - pbes2encsId.encode(pbes2Encs); - DEREncodeOctetString(pbes2Encs, iv, 8); - } - pbes2Encs.MessageEnd(); - } - pbes2Params.MessageEnd(); - } - encryptionAlgorithm.MessageEnd(); - - DEREncodeOctetString(encryptedPrivateKeyInfo, - encryptedOs.buf()->buf(), encryptedOs.buf()->size()); - } - encryptedPrivateKeyInfo.MessageEnd(); - - return pkcs8Os.buf(); - } - catch (const CryptoPP::Exception& e) { - BOOST_THROW_EXCEPTION(Error("Cannot export the private key, #3")); - } -} - -bool -SecTpm::importPrivateKeyPkcs5IntoTpm(const Name& keyName, - const uint8_t* buf, size_t size, - const std::string& passwordStr) -{ - using namespace CryptoPP; - - Oid pbes2Id; - Oid pbkdf2Id; - SecByteBlock saltBlock; - uint32_t iterationCount; - Oid pbes2encsId; - SecByteBlock ivBlock; - SecByteBlock encryptedDataBlock; - - try { - // decode some decoding processes are not necessary for now, - // because we assume only one encryption scheme. - StringSource source(buf, size, true); - - // EncryptedPrivateKeyInfo ::= SEQUENCE { - // encryptionAlgorithm EncryptionAlgorithmIdentifier, - // encryptedData OCTET STRING } - BERSequenceDecoder encryptedPrivateKeyInfo(source); - { - // EncryptionAlgorithmIdentifier ::= SEQUENCE { - // algorithm OBJECT IDENTIFIER {{PBES2-id}}, - // parameters SEQUENCE {{PBES2-params}} } - BERSequenceDecoder encryptionAlgorithm(encryptedPrivateKeyInfo); - { - pbes2Id.decode(encryptionAlgorithm); - // PBES2-params ::= SEQUENCE { - // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, - // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} } - BERSequenceDecoder pbes2Params(encryptionAlgorithm); - { - // AlgorithmIdentifier ::= SEQUENCE { - // algorithm OBJECT IDENTIFIER {{PBKDF2-id}}, - // parameters SEQUENCE {{PBKDF2-params}} } - BERSequenceDecoder pbes2KDFs(pbes2Params); - { - pbkdf2Id.decode(pbes2KDFs); - // AlgorithmIdentifier ::= SEQUENCE { - // salt OCTET STRING, - // iterationCount INTEGER (1..MAX), - // keyLength INTEGER (1..MAX) OPTIONAL, - // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 } - BERSequenceDecoder pbkdf2Params(pbes2KDFs); - { - BERDecodeOctetString(pbkdf2Params, saltBlock); - BERDecodeUnsigned(pbkdf2Params, iterationCount, INTEGER); - } - pbkdf2Params.MessageEnd(); - } - pbes2KDFs.MessageEnd(); - - // AlgorithmIdentifier ::= SEQUENCE { - // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}}, - // parameters OCTET STRING} {{iv}} } - BERSequenceDecoder pbes2Encs(pbes2Params); - { - pbes2encsId.decode(pbes2Encs); - BERDecodeOctetString(pbes2Encs, ivBlock); - } - pbes2Encs.MessageEnd(); - } - pbes2Params.MessageEnd(); - } - encryptionAlgorithm.MessageEnd(); - - BERDecodeOctetString(encryptedPrivateKeyInfo, encryptedDataBlock); - } - encryptedPrivateKeyInfo.MessageEnd(); - } - catch (const CryptoPP::Exception& e) { - return false; - } - - PKCS5_PBKDF2_HMAC keyGenerator; - size_t derivedLen = 24; //For DES-EDE3-CBC-PAD - byte derived[24] = {0}; - byte purpose = 0; - - try { - keyGenerator.DeriveKey(derived, derivedLen, - purpose, - reinterpret_cast(passwordStr.c_str()), passwordStr.size(), - saltBlock.BytePtr(), saltBlock.size(), - iterationCount); - } - catch (const CryptoPP::Exception& e) { - return false; - } - - //decrypt - CBC_Mode< DES_EDE3 >::Decryption d; - d.SetKeyWithIV(derived, derivedLen, ivBlock.BytePtr()); - - OBufferStream privateKeyOs; - try { - StringSource encryptedSource(encryptedDataBlock.BytePtr(), encryptedDataBlock.size(), true, - new StreamTransformationFilter(d, new FileSink(privateKeyOs))); - } - catch (const CryptoPP::Exception& e) { - return false; - } - - if (!importPrivateKeyPkcs8IntoTpm(keyName, - privateKeyOs.buf()->buf(), privateKeyOs.buf()->size())) - return false; - - // determine key type - StringSource privateKeySource(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size(), true); - - KeyType publicKeyType = KeyType::NONE; - SecByteBlock rawKeyBits; - // PrivateKeyInfo ::= SEQUENCE { - // INTEGER, - // SEQUENCE, - // OCTECT STRING} - BERSequenceDecoder privateKeyInfo(privateKeySource); - { - uint32_t versionNum; - BERDecodeUnsigned(privateKeyInfo, versionNum, INTEGER); - BERSequenceDecoder sequenceDecoder(privateKeyInfo); - { - Oid keyTypeOid; - keyTypeOid.decode(sequenceDecoder); - if (keyTypeOid == oid::RSA) - publicKeyType = KeyType::RSA; - else if (keyTypeOid == oid::ECDSA) - publicKeyType = KeyType::EC; - else - return false; // Unsupported key type; - } - } - - - // derive public key - OBufferStream publicKeyOs; - - try { - switch (publicKeyType) { - case KeyType::RSA: { - RSA::PrivateKey privateKey; - privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref()); - RSAFunction publicKey(privateKey); - - FileSink publicKeySink(publicKeyOs); - publicKey.DEREncode(publicKeySink); - publicKeySink.MessageEnd(); - break; - } - - case KeyType::EC: { - ECDSA::PrivateKey privateKey; - privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref()); - - ECDSA::PublicKey publicKey; - privateKey.MakePublicKey(publicKey); - publicKey.AccessGroupParameters().SetEncodeAsOID(true); - - FileSink publicKeySink(publicKeyOs); - publicKey.DEREncode(publicKeySink); - publicKeySink.MessageEnd(); - break; - } - - default: - return false; - } - } - catch (const CryptoPP::Exception& e) { - return false; - } - - if (!importPublicKeyPkcs1IntoTpm(keyName, publicKeyOs.buf()->buf(), publicKeyOs.buf()->size())) - return false; - - return true; -} - -bool -SecTpm::getImpExpPassWord(std::string& password, const std::string& prompt) -{ - bool isInitialized = false; - -#ifdef NDN_CXX_HAVE_GETPASS - char* pw0 = nullptr; - - pw0 = getpass(prompt.c_str()); - if (pw0 == nullptr) - return false; - std::string password1 = pw0; - memset(pw0, 0, strlen(pw0)); - - pw0 = getpass("Confirm:"); - if (pw0 == nullptr) { - std::fill(password1.begin(), password1.end(), 0); - return false; - } - - if (password1.compare(pw0) == 0) { - isInitialized = true; - password.swap(password1); - } - - std::fill(password1.begin(), password1.end(), 0); - memset(pw0, 0, strlen(pw0)); - - if (password.empty()) - return false; - -#endif // NDN_CXX_HAVE_GETPASS - - return isInitialized; -} - -} // namespace security -} // namespace ndn diff --git a/src/security/sec-tpm.hpp b/src/security/sec-tpm.hpp deleted file mode 100644 index 3da278e76..000000000 --- a/src/security/sec-tpm.hpp +++ /dev/null @@ -1,310 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_SECURITY_SEC_TPM_HPP -#define NDN_SECURITY_SEC_TPM_HPP - -#include "../common.hpp" -#include "security-common.hpp" -#include "../name.hpp" -#include "../data.hpp" -#include "key-params.hpp" -#include "v1/public-key.hpp" - -namespace ndn { -namespace security { - -/** - * @brief SecTpm is the base class of the TPM classes. - * - * It specifies the interfaces of private/secret key related operations. - */ -class SecTpm : noncopyable -{ -public: - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - - explicit - SecTpm(const std::string& location); - - virtual - ~SecTpm(); - - std::string - getTpmLocator(); - - /** - * @brief set password of TPM - * - * Password is used to unlock TPM when it is locked. - * You should be cautious when using this method, because remembering password is kind of - * dangerous. - * - * @param password The password - * @param passwordLength The length of password - */ - virtual void - setTpmPassword(const uint8_t* password, size_t passwordLength) = 0; - - /** - * @brief reset password of TPM - */ - virtual void - resetTpmPassword() = 0; - - /** - * @brief Set inTerminal flag to @p inTerminal - * - * If the inTerminal flag is set, and password is not set, TPM may ask for password via terminal. - * inTerminal flag is set by default. - */ - virtual void - setInTerminal(bool inTerminal) = 0; - - /** - * @brief Get value of inTerminal flag - */ - virtual bool - getInTerminal() const = 0; - - /** - * @brief Check if TPM is locked - */ - virtual bool - isLocked() = 0; - - /** - * @brief Unlock the TPM - * - * @param password The password. - * @param passwordLength The password size. 0 indicates no password. - * @param usePassword True if we want to use the supplied password to unlock the TPM. - * @return true if TPM is unlocked, otherwise false. - */ - virtual bool - unlockTpm(const char* password, size_t passwordLength, bool usePassword) = 0; - - /** - * @brief Generate a pair of asymmetric keys. - * - * @param keyName The name of the key pair. - * @param params The parameters of key. - * @throws SecTpm::Error if fails. - */ - virtual void - generateKeyPairInTpm(const Name& keyName, const KeyParams& params) = 0; - - /** - * @brief Delete a key pair of asymmetric keys. - * - * @param keyName The name of the key pair. - */ - virtual void - deleteKeyPairInTpm(const Name& keyName) = 0; - - /** - * @brief Get a public key. - * - * @param keyName The public key name. - * @return The public key. - * @throws SecTpm::Error if public key does not exist in TPM. - */ - virtual shared_ptr - getPublicKeyFromTpm(const Name& keyName) = 0; - - /** - * @brief Sign data. - * - * @param data Pointer to the byte array to be signed. - * @param dataLength The length of data. - * @param keyName The name of the signing key. - * @param digestAlgorithm the digest algorithm. - * @return The signature block. - * @throws SecTpm::Error if signing fails. - */ - virtual Block - signInTpm(const uint8_t* data, size_t dataLength, - const Name& keyName, - DigestAlgorithm digestAlgorithm) = 0; - - /** - * @brief Decrypt data. - * - * @param data Pointer to the byte arry to be decrypted. - * @param dataLength The length of data. - * @param keyName The name of the decrypting key. - * @param isSymmetric If true symmetric encryption is used, otherwise asymmetric encryption. - * @return The decrypted data. - * @throws SecTpm::Error if decryption fails. - */ - virtual ConstBufferPtr - decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric) = 0; - - /** - * @brief Encrypt data. - * - * @param data Pointer to the byte arry to be decrypted. - * @param dataLength The length of data. - * @param keyName The name of the encrypting key. - * @param isSymmetric If true symmetric encryption is used, otherwise asymmetric encryption. - * @return The encrypted data. - * @throws SecTpm::Error if encryption fails. - */ - virtual ConstBufferPtr - encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric) = 0; - - /** - * @brief Generate a symmetric key. - * - * @param keyName The name of the key. - * @param params The parameter of the key. - * @throws SecTpm::Error if key generating fails. - */ - virtual void - generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params) = 0; - - /** - * @brief Check if a particular key exists. - * - * @param keyName The name of the key. - * @param keyClass The class of the key, e.g. KeyClass::PUBLIC, KeyClass::PRIVATE. - * @return True if the key exists, otherwise false. - */ - virtual bool - doesKeyExistInTpm(const Name& keyName, KeyClass keyClass) = 0; - - /** - * @brief Generate a random block - * - * @param res The pointer to the generated block - * @param size The random block size - * @return true for success, otherwise false - */ - virtual bool - generateRandomBlock(uint8_t* res, size_t size) = 0; - - /** - * @brief Add the application into the ACL of a particular key - * - * @param keyName the name of key - * @param keyClass the class of key, e.g. Private Key - * @param appPath the absolute path to the application - * @param acl the new acl of the key - */ - virtual void - addAppToAcl(const Name& keyName, KeyClass keyClass, const std::string& appPath, AclType acl) = 0; - - /** - * @brief Export a private key in PKCS#5 format - * - * @param keyName The private key name - * @param password The password to encrypt the private key - * @return The private key info (in PKCS8 format) if exist - * @throws SecTpm::Error if private key cannot be exported - */ - ConstBufferPtr - exportPrivateKeyPkcs5FromTpm(const Name& keyName, const std::string& password); - - /** - * @brief Import a private key in PKCS#5 formatted buffer of size @p bufferSize - * - * Also recover the public key and installed it in TPM. - * - * @param keyName The private key name - * @param buffer Pointer to the first byte of the buffer containing PKCS#5-encoded - * private key info - * @param bufferSize Size of the buffer - * @param password The password to encrypt the private key - * @return false if import fails - */ - bool - importPrivateKeyPkcs5IntoTpm(const Name& keyName, - const uint8_t* buffer, size_t bufferSize, - const std::string& password); - -protected: - virtual std::string - getScheme() = 0; - - /** - * @brief Export a private key in PKCS#8 format. - * - * @param keyName The private key name. - * @return The private key info (in PKCS#8 format) if exist, otherwise a NULL pointer. - */ - virtual ConstBufferPtr - exportPrivateKeyPkcs8FromTpm(const Name& keyName) = 0; - - /** - * @brief Import a private key from PKCS#8 formatted buffer of size @p bufferSize - * - * @param keyName The private key name. - * @param buffer Pointer to the first byte of the buffer containing PKCS#8-encoded - * private key info - * @param bufferSize Size of the buffer - * @return false if import fails - */ - virtual bool - importPrivateKeyPkcs8IntoTpm(const Name& keyName, const uint8_t* buffer, size_t bufferSize) = 0; - - /** - * @brief Import a public key in PKCS#1 formatted buffer of size @p bufferSize - * - * @param keyName The public key name - * @param buffer Pointer to the first byte of the buffer containing PKCS#1-encoded - * private key info - * @param bufferSize Size of the buffer - * @return false if import fails - */ - virtual bool - importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buffer, size_t bufferSize) = 0; - - /** - * @brief Get import/export password. - * - * @param password On return, the password. - * @param prompt Prompt for password, i.e., "Password for key:" - * @return true if password has been obtained. - */ - virtual bool - getImpExpPassWord(std::string& password, const std::string& prompt); - -protected: - std::string m_location; -}; - -} // namespace security - -using security::SecTpm; - -} // namespace ndn - -#endif // NDN_SECURITY_SEC_TPM_HPP diff --git a/src/security/secured-bag.cpp b/src/security/secured-bag.cpp deleted file mode 100644 index 66fad0295..000000000 --- a/src/security/secured-bag.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "secured-bag.hpp" -#include "encoding/tlv-security.hpp" -#include "util/concepts.hpp" - -namespace ndn { - -//BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "SecuredBag::Error must inherit from tlv::Error"); - -SecuredBag::SecuredBag() - : m_wire(tlv::security::IdentityPackage) -{ -} - -SecuredBag::SecuredBag(const Block& wire) -{ - this->wireDecode(wire); -} - -SecuredBag::SecuredBag(const v1::IdentityCertificate& cert, ConstBufferPtr key) - : m_cert(cert) - , m_key(key) - , m_wire(tlv::security::IdentityPackage) -{ - Block wireKey(tlv::security::KeyPackage, m_key); - Block wireCert(tlv::security::CertificatePackage, cert.wireEncode()); - m_wire.push_back(wireCert); - m_wire.push_back(wireKey); -} - -SecuredBag::~SecuredBag() -{ -} - -void -SecuredBag::wireDecode(const Block& wire) -{ - m_wire = wire; - m_wire.parse(); - - m_cert.wireDecode(m_wire.get(tlv::security::CertificatePackage).blockFromValue()); - - Block wireKey = m_wire.get(tlv::security::KeyPackage); - shared_ptr key = make_shared(wireKey.value(), wireKey.value_size()); - m_key = key; -} - -const Block& -SecuredBag::wireEncode() const -{ - m_wire.encode(); - return m_wire; -} - -} // namespace ndn diff --git a/src/security/secured-bag.hpp b/src/security/secured-bag.hpp deleted file mode 100644 index 5dd27fc8d..000000000 --- a/src/security/secured-bag.hpp +++ /dev/null @@ -1,86 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_SECURED_BAG_HPP -#define NDN_SECURITY_SECURED_BAG_HPP - -#include "../common.hpp" -#include "v1/identity-certificate.hpp" - -namespace ndn { -namespace security { - -class SecuredBag -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - - SecuredBag(); - - explicit - SecuredBag(const Block& wire); - - SecuredBag(const v1::IdentityCertificate& cert, - ConstBufferPtr key); - - virtual - ~SecuredBag(); - - void - wireDecode(const Block& wire); - - const Block& - wireEncode() const; - - const v1::IdentityCertificate& - getCertificate() const - { - return m_cert; - } - - ConstBufferPtr - getKey() const - { - return m_key; - } - -private: - v1::IdentityCertificate m_cert; - ConstBufferPtr m_key; - - mutable Block m_wire; -}; - -} // namespace security - -using security::SecuredBag; - -} // namespace ndn - -#endif // NDN_SECURITY_SECURED_BAG_HPP diff --git a/src/security/security-common.cpp b/src/security/security-common.cpp deleted file mode 100644 index 0ea60cb5e..000000000 --- a/src/security/security-common.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security-common.hpp" -#include - -namespace ndn { - -std::ostream& -operator<<(std::ostream& os, KeyType keyType) -{ - switch (keyType) { - case KeyType::NONE: - os << "NONE"; - break; - case KeyType::RSA: - os << "RSA"; - break; - case KeyType::EC: - os << "EC"; - break; - case KeyType::AES: - os << "AES"; - break; - default: - os << static_cast(keyType); - break; - }; - return os; -} - -std::ostream& -operator<<(std::ostream& os, KeyClass keyClass) -{ - switch (keyClass) { - case KeyClass::NONE: - os << "NONE"; - break; - case KeyClass::PUBLIC: - os << "PUBLIC"; - break; - case KeyClass::PRIVATE: - os << "PRIVATE"; - break; - case KeyClass::SYMMETRIC: - os << "SYMMETRIC"; - break; - default: - os << static_cast(keyClass); - break; - }; - return os; -} - -std::ostream& -operator<<(std::ostream& os, DigestAlgorithm algorithm) -{ - switch (algorithm) { - case DigestAlgorithm::NONE: - os << "NONE"; - break; - case DigestAlgorithm::SHA256: - os << "SHA256"; - break; - default: - os << static_cast(algorithm); - break; - }; - return os; -} - -std::ostream& -operator<<(std::ostream& os, BlockCipherAlgorithm algorithm) -{ - switch (algorithm) { - case BlockCipherAlgorithm::NONE: - os << "NONE"; - break; - case BlockCipherAlgorithm::AES_CBC: - os << "AES_CBC"; - break; - default: - os << static_cast(algorithm); - break; - }; - return os; -} - -std::ostream& -operator<<(std::ostream& os, CipherOperator op) -{ - switch (op) { - case CipherOperator::DECRYPT: - os << "DECRYPT"; - break; - case CipherOperator::ENCRYPT: - os << "ENCRYPT"; - break; - default: - os << static_cast(op); - break; - }; - return os; -} - -std::ostream& -operator<<(std::ostream& os, AclType aclType) -{ - switch (aclType) { - case AclType::NONE: - os << "NONE"; - break; - case AclType::PUBLIC: - os << "PUBLIC"; - break; - case AclType::PRIVATE: - os << "PRIVATE"; - break; - default: - os << static_cast(aclType); - break; - }; - return os; -} - -} // namespace ndn diff --git a/src/security/security-common.hpp b/src/security/security-common.hpp deleted file mode 100644 index bd709f5d7..000000000 --- a/src/security/security-common.hpp +++ /dev/null @@ -1,105 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_COMMON_HPP -#define NDN_SECURITY_COMMON_HPP - -#include "../common.hpp" - -#define NDN_CXX_KEEP_SECURITY_V1_ALIASES - -namespace ndn { - -namespace signed_interest { - -const ssize_t POS_SIG_VALUE = -1; -const ssize_t POS_SIG_INFO = -2; -const ssize_t POS_RANDOM_VAL = -3; -const ssize_t POS_TIMESTAMP = -4; - -/** \brief minimal number of components for Command Interest - * \sa https://redmine.named-data.net/projects/ndn-cxx/wiki/CommandInterest - */ -const size_t MIN_LENGTH = 4; - -/** \brief minimal number of components for Signed Interest - * \sa https://redmine.named-data.net/projects/ndn-cxx/wiki/SignedInterest - */ -const size_t MIN_LENGTH_SIG_ONLY = 2; - -} // namespace signed_interest - -enum class KeyType { - NONE = 0, - RSA = 1, - EC = 2, - AES = 128 -}; - -std::ostream& -operator<<(std::ostream& os, KeyType keyType); - -enum class KeyClass { - NONE, - PUBLIC, - PRIVATE, - SYMMETRIC -}; - -std::ostream& -operator<<(std::ostream& os, KeyClass keyClass); - -enum class DigestAlgorithm { - NONE = 0, - SHA256 = 1 -}; - -std::ostream& -operator<<(std::ostream& os, DigestAlgorithm algorithm); - -enum class BlockCipherAlgorithm { - NONE, - AES_CBC -}; - -std::ostream& -operator<<(std::ostream& os, BlockCipherAlgorithm algorithm); - -enum class CipherOperator { - DECRYPT = 0, - ENCRYPT = 1 -}; - -std::ostream& -operator<<(std::ostream& os, CipherOperator op); - -enum class AclType { - NONE, - PUBLIC, - PRIVATE -}; - -std::ostream& -operator<<(std::ostream& os, AclType aclType); - -} // namespace ndn - -#endif // NDN_SECURITY_COMMON_HPP diff --git a/src/security/signature-sha256-with-ecdsa.hpp b/src/security/signature-sha256-with-ecdsa.hpp deleted file mode 100644 index 4b0eb7fa4..000000000 --- a/src/security/signature-sha256-with-ecdsa.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_SIGNATURE_SHA256_WITH_ECDSA_HPP -#define NDN_SECURITY_SIGNATURE_SHA256_WITH_ECDSA_HPP - -#include "../signature.hpp" - -namespace ndn { - -/** - * represents a Sha256WithEcdsa signature. - */ -class SignatureSha256WithEcdsa : public Signature -{ -public: - class Error : public Signature::Error - { - public: - explicit - Error(const std::string& what) - : Signature::Error(what) - { - } - }; - - explicit - SignatureSha256WithEcdsa(const KeyLocator& keyLocator = KeyLocator()); - - explicit - SignatureSha256WithEcdsa(const Signature& signature); - -private: - void - unsetKeyLocator(); -}; - -} // namespace ndn - -#endif //NDN_SECURITY_SIGNATURE_SHA256_WITH_ECDSA_HPP diff --git a/src/security/signature-sha256-with-rsa.hpp b/src/security/signature-sha256-with-rsa.hpp deleted file mode 100644 index 937794bb4..000000000 --- a/src/security/signature-sha256-with-rsa.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_SIGNATURE_SHA256_WITH_RSA_HPP -#define NDN_SECURITY_SIGNATURE_SHA256_WITH_RSA_HPP - -#include "../signature.hpp" - -namespace ndn { - -/** - * Represent a SHA256-with-RSA signature. - */ -class SignatureSha256WithRsa : public Signature -{ -public: - class Error : public Signature::Error - { - public: - explicit - Error(const std::string& what) - : Signature::Error(what) - { - } - }; - - explicit - SignatureSha256WithRsa(const KeyLocator& keyLocator = KeyLocator()); - - explicit - SignatureSha256WithRsa(const Signature& signature); - -private: - void - unsetKeyLocator(); -}; - -} // namespace ndn - -#endif //NDN_SECURITY_SIGNATURE_SHA256_WITH_RSA_HPP diff --git a/src/security/signing-helpers.cpp b/src/security/signing-helpers.cpp deleted file mode 100644 index 37de8dcdf..000000000 --- a/src/security/signing-helpers.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "signing-helpers.hpp" - -namespace ndn { -namespace security { - -SigningInfo -signingByIdentity(const Name& identity) -{ - return SigningInfo(SigningInfo::SIGNER_TYPE_ID, identity); -} - -SigningInfo -signingByKey(const Name& keyName) -{ - return SigningInfo(SigningInfo::SIGNER_TYPE_KEY, keyName); -} - -SigningInfo -signingByCertificate(const Name& certName) -{ - return SigningInfo(SigningInfo::SIGNER_TYPE_CERT, certName); -} - -SigningInfo -signingWithSha256() -{ - return SigningInfo(SigningInfo::SIGNER_TYPE_SHA256); -} - -} // namespace security -} // namespace ndn \ No newline at end of file diff --git a/src/security/signing-helpers.hpp b/src/security/signing-helpers.hpp deleted file mode 100644 index 689eba6d7..000000000 --- a/src/security/signing-helpers.hpp +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_CXX_SECURITY_SIGNING_HELPERS_HPP -#define NDN_CXX_SECURITY_SIGNING_HELPERS_HPP - -#include "../common.hpp" -#include "signing-info.hpp" - -namespace ndn { -namespace security { - -/** - * \return a SigningInfo for signing with an identity - */ -SigningInfo -signingByIdentity(const Name& identity); - -/** - * \return a SigningInfo for signing with a key - */ -SigningInfo -signingByKey(const Name& keyName); - -/** - * \return a SigningInfo for signing with a certificate - */ -SigningInfo -signingByCertificate(const Name& certName); - -/** - * \return a SigningInfo for signing with Sha256 - */ -SigningInfo -signingWithSha256(); - -} // namespace security - -using security::signingByIdentity; -using security::signingByKey; -using security::signingByCertificate; -using security::signingWithSha256; - -} // namespace ndn - -#endif // NDN_CXX_SECURITY_SIGNING_HELPERS_HPP \ No newline at end of file diff --git a/src/security/signing-info.cpp b/src/security/signing-info.cpp deleted file mode 100644 index 57cf04651..000000000 --- a/src/security/signing-info.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "signing-info.hpp" -#include "key-chain.hpp" - -namespace ndn { -namespace security { - -const Name SigningInfo::EMPTY_NAME; -const SignatureInfo SigningInfo::EMPTY_SIGNATURE_INFO; - -SigningInfo::SigningInfo(SignerType signerType, - const Name& signerName, - const SignatureInfo& signatureInfo) - : m_type(signerType) - , m_name(signerName) - , m_digestAlgorithm(DigestAlgorithm::SHA256) - , m_info(signatureInfo) -{ -} - -SigningInfo::SigningInfo(const std::string& signingStr) -{ - *this = SigningInfo(); - - if (signingStr.empty()) { - return; - } - - size_t pos = signingStr.find(':'); - - if (pos == std::string::npos) { - BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid signing string cannot represent SigningInfo")); - } - - std::string scheme = signingStr.substr(0, pos); - std::string nameArg = signingStr.substr(pos + 1); - - if (scheme == "id") { - if (nameArg == KeyChain::DIGEST_SHA256_IDENTITY.toUri()) { - setSha256Signing(); - } - else { - setSigningIdentity(nameArg); - } - } - else if (scheme == "key") { - setSigningKeyName(nameArg); - } - else if (scheme == "cert") { - setSigningCertName(nameArg); - } - else { - BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid signing string scheme")); - } -} - -void -SigningInfo::setSigningIdentity(const Name& identity) -{ - m_type = SIGNER_TYPE_ID; - m_name = identity; -} -void -SigningInfo::setSigningKeyName(const Name& keyName) -{ - m_type = SIGNER_TYPE_KEY; - m_name = keyName; -} - -void -SigningInfo::setSigningCertName(const Name& certificateName) -{ - m_type = SIGNER_TYPE_CERT; - m_name = certificateName; -} - -void -SigningInfo::setSha256Signing() -{ - m_type = SIGNER_TYPE_SHA256; - m_name.clear(); -} - -void -SigningInfo::setSignatureInfo(const SignatureInfo& signatureInfo) -{ - m_info = signatureInfo; -} - -std::ostream& -operator<<(std::ostream& os, const SigningInfo& si) -{ - switch (si.getSignerType()) { - case SigningInfo::SIGNER_TYPE_NULL: - return os; - case SigningInfo::SIGNER_TYPE_ID: - os << "id:"; - break; - case SigningInfo::SIGNER_TYPE_KEY: - os << "key:"; - break; - case SigningInfo::SIGNER_TYPE_CERT: - os << "cert:"; - break; - case SigningInfo::SIGNER_TYPE_SHA256: - os << "id:" << KeyChain::DIGEST_SHA256_IDENTITY; - return os; - default: - BOOST_THROW_EXCEPTION(std::invalid_argument("Unknown signer type")); - } - - os << si.getSignerName(); - return os; -} - -} // namespace security -} // namespace ndn diff --git a/src/security/signing-info.hpp b/src/security/signing-info.hpp deleted file mode 100644 index aaa277023..000000000 --- a/src/security/signing-info.hpp +++ /dev/null @@ -1,190 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_SIGNING_INFO_HPP -#define NDN_SECURITY_SIGNING_INFO_HPP - -#include "../name.hpp" -#include "../signature-info.hpp" -#include "security-common.hpp" - - -namespace ndn { -namespace security { - -/** - * @brief Signing parameters passed to KeyChain - */ -class SigningInfo -{ -public: - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - - enum SignerType { - /// @brief no signer is specified, use default setting or follow the trust schema - SIGNER_TYPE_NULL = 0, - /// @brief signer is an identity, use its default key and default certificate - SIGNER_TYPE_ID = 1, - /// @brief signer is a key, use its default certificate - SIGNER_TYPE_KEY = 2, - /// @brief signer is a certificate, use it directly - SIGNER_TYPE_CERT = 3, - /// @brief use sha256 digest, no signer needs to be specified - SIGNER_TYPE_SHA256 = 4 - }; - -public: - /** - * @brief Constructor - * - * @param signerType The type of signer - * @param signerName The name of signer; interpretation differs per signerType - * @param signatureInfo A semi-prepared SignatureInfo which contains other information except - * SignatureType and KeyLocator. If SignatureType and KeyLocator are - * specified, they may be overwritten by KeyChain. - */ - explicit - SigningInfo(SignerType signerType = SIGNER_TYPE_NULL, - const Name& signerName = EMPTY_NAME, - const SignatureInfo& signatureInfo = EMPTY_SIGNATURE_INFO); - - /** - * @brief Construct SigningInfo from its string representation - * - * @param signingStr The representative signing string for SigningInfo signing method - * - * Structure of the representative string is as follows: - * - default signing: "" (empty string) - * - signing with a default certificate of a default key for the identity: `id:/my-identity` - * - signing with a default certificate of the key: `key:/my-identity/ksk-1` - * - signing with the certificate: `cert:/my-identity/KEY/ksk-1/ID-CERT/%FD%01` - * - signing with sha256 digest: `id:/localhost/identity/digest-sha256` - */ - explicit - SigningInfo(const std::string& signingStr); - - /** - * @brief Set signer as an identity with name @p identity - * @post Change the signerType to SIGNER_TYPE_ID - */ - void - setSigningIdentity(const Name& identity); - - /** - * @brief Set signer as a key with name @p keyName - * @post Change the signerType to SIGNER_TYPE_KEY - */ - void - setSigningKeyName(const Name& keyName); - - /** - * @brief Set signer as a certificate with name @p certificateName - * @post Change the signerType to SIGNER_TYPE_CERT - */ - void - setSigningCertName(const Name& certificateName); - - /** - * @brief Set Sha256 as the signing method - * @post Reset signerName, also change the signerType to SIGNER_TYPE_SHA256 - */ - void - setSha256Signing(); - - /** - * @return Type of the signer - */ - SignerType - getSignerType() const - { - return m_type; - } - - /** - * @return Name of signer; interpretation differs per signerType - */ - const Name& - getSignerName() const - { - return m_name; - } - - /** - * @brief Set the digest algorithm for public key operations - */ - void - setDigestAlgorithm(const DigestAlgorithm& algorithm) - { - m_digestAlgorithm = algorithm; - } - - /** - * @return The digest algorithm for public key operations - */ - DigestAlgorithm - getDigestAlgorithm() const - { - return m_digestAlgorithm; - } - - /** - * @brief Set a semi-prepared SignatureInfo; - */ - void - setSignatureInfo(const SignatureInfo& signatureInfo); - - /** - * @return Semi-prepared SignatureInfo - */ - const SignatureInfo& - getSignatureInfo() const - { - return m_info; - } - -public: - static const Name EMPTY_NAME; - static const SignatureInfo EMPTY_SIGNATURE_INFO; - -private: - SignerType m_type; - Name m_name; - - DigestAlgorithm m_digestAlgorithm; - - SignatureInfo m_info; -}; - -std::ostream& -operator<<(std::ostream& os, const SigningInfo& si); - -} // namespace security -} // namespace ndn - -#endif // NDN_SECURITY_SIGNING_INFO_HPP diff --git a/src/security/transform.hpp b/src/security/transform.hpp deleted file mode 100644 index 8ecfed578..000000000 --- a/src/security/transform.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_CXX_SECURITY_TRANSFORM_HPP -#define NDN_CXX_SECURITY_TRANSFORM_HPP - -#include "transform/buffer-source.hpp" -#include "transform/stream-source.hpp" -#include "transform/step-source.hpp" - -#include "transform/bool-sink.hpp" -#include "transform/stream-sink.hpp" - -#include "transform/strip-space.hpp" -#include "transform/hex-encode.hpp" -#include "transform/hex-decode.hpp" -#include "transform/base64-encode.hpp" -#include "transform/base64-decode.hpp" -#include "transform/digest-filter.hpp" -#include "transform/hmac-filter.hpp" -#include "transform/block-cipher.hpp" -#include "transform/signer-filter.hpp" -#include "transform/verifier-filter.hpp" - -#endif // NDN_CXX_SECURITY_TRANSFORM_HPP diff --git a/src/security/transform/block-cipher.cpp b/src/security/transform/block-cipher.cpp deleted file mode 100644 index 327aba6bb..000000000 --- a/src/security/transform/block-cipher.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "block-cipher.hpp" -#include "../detail/openssl.hpp" - -#include - -namespace ndn { -namespace security { -namespace transform { - -class BlockCipher::Impl -{ -public: - Impl() - : m_cipher(BIO_new(BIO_f_cipher())) - , m_sink(BIO_new(BIO_s_mem())) - { - BIO_push(m_cipher, m_sink); - } - - ~Impl() - { - BIO_free_all(m_cipher); - } - -public: - BIO* m_cipher; - BIO* m_sink; // BIO_f_cipher alone does not work without a sink -}; - -BlockCipher::BlockCipher(BlockCipherAlgorithm algo, CipherOperator op, - const uint8_t* key, size_t keyLen, - const uint8_t* iv, size_t ivLen) - : m_impl(new Impl) -{ - switch (algo) { - case BlockCipherAlgorithm::AES_CBC: - initializeAesCbc(key, keyLen, iv, ivLen, op); - break; - default: - BOOST_THROW_EXCEPTION(Error(getIndex(), "Cipher algorithm " + - boost::lexical_cast(algo) + " is not supported")); - } -} - -void -BlockCipher::preTransform() -{ - fillOutputBuffer(); -} - -size_t -BlockCipher::convert(const uint8_t* data, size_t dataLen) -{ - if (dataLen == 0) - return 0; - - int wLen = BIO_write(m_impl->m_cipher, data, dataLen); - - if (wLen <= 0) { // fail to write data - if (!BIO_should_retry(m_impl->m_cipher)) { - // we haven't written everything but some error happens, and we cannot retry - BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to accept more input")); - } - return 0; - } - else { // update number of bytes written - fillOutputBuffer(); - return wLen; - } -} - -void -BlockCipher::finalize() -{ - if (BIO_flush(m_impl->m_cipher) != 1) - BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to flush")); - - while (!isConverterEmpty()) { - fillOutputBuffer(); - while (!isOutputBufferEmpty()) { - flushOutputBuffer(); - } - } -} - -void -BlockCipher::fillOutputBuffer() -{ - int nRead = BIO_pending(m_impl->m_sink); - if (nRead <= 0) - return; - - // there is something to read from BIO - auto buffer = make_unique(nRead); - int rLen = BIO_read(m_impl->m_sink, &(*buffer)[0], nRead); - if (rLen < 0) - return; - - if (rLen < nRead) - buffer->erase(buffer->begin() + rLen, buffer->end()); - setOutputBuffer(std::move(buffer)); -} - -bool -BlockCipher::isConverterEmpty() const -{ - return (BIO_pending(m_impl->m_sink) <= 0); -} - -void -BlockCipher::initializeAesCbc(const uint8_t* key, size_t keyLen, - const uint8_t* iv, size_t ivLen, - CipherOperator op) -{ - if (keyLen != ivLen) - BOOST_THROW_EXCEPTION(Error(getIndex(), "Key length must be the same as IV length")); - - const EVP_CIPHER* cipherType = nullptr; - switch (keyLen) { - case 16: - cipherType = EVP_aes_128_cbc(); - break; - case 24: - cipherType = EVP_aes_192_cbc(); - break; - case 32: - cipherType = EVP_aes_256_cbc(); - break; - default: - BOOST_THROW_EXCEPTION(Error(getIndex(), "Key length is not supported")); - } - BIO_set_cipher(m_impl->m_cipher, cipherType, key, iv, static_cast(op)); -} - -unique_ptr -blockCipher(BlockCipherAlgorithm algo, CipherOperator op, - const uint8_t* key, size_t keyLen, - const uint8_t* iv, size_t ivLen) -{ - return make_unique(algo, op, key, keyLen, iv, ivLen); -} - -} // namespace transform -} // namespace security -} // namespace ndn diff --git a/src/security/transform/digest-filter.cpp b/src/security/transform/digest-filter.cpp deleted file mode 100644 index c984b8c7e..000000000 --- a/src/security/transform/digest-filter.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "digest-filter.hpp" -#include "../../encoding/buffer.hpp" -#include "../detail/openssl-helper.hpp" - -#include - -namespace ndn { -namespace security { -namespace transform { - -/** - * @brief The implementation class which contains the internal state of - * the digest calculator which includes openssl specific structures. - */ -class DigestFilter::Impl -{ -public: - Impl() - : m_md(BIO_new(BIO_f_md())) - , m_sink(BIO_new(BIO_s_null())) - { - BIO_push(m_md, m_sink); - } - - ~Impl() - { - BIO_free_all(m_md); - } - -public: - BIO* m_md; - BIO* m_sink; -}; - -DigestFilter::DigestFilter(DigestAlgorithm algo) - : m_impl(new Impl) -{ - const EVP_MD* md = detail::toDigestEvpMd(algo); - if (md == nullptr) { - BOOST_THROW_EXCEPTION(Error(getIndex(), "Unsupported digest algorithm " + - boost::lexical_cast(algo))); - } - - if (!BIO_set_md(m_impl->m_md, md)) { - BOOST_THROW_EXCEPTION(Error(getIndex(), "Cannot set digest"+ - boost::lexical_cast(algo))); - } -} - -size_t -DigestFilter::convert(const uint8_t* buf, size_t size) -{ - int wLen = BIO_write(m_impl->m_md, buf, size); - - if (wLen <= 0) { // fail to write data - if (!BIO_should_retry(m_impl->m_md)) { - // we haven't written everything but some error happens, and we cannot retry - BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to accept more input")); - } - return 0; - } - else { // update number of bytes written - return wLen; - } -} - -void -DigestFilter::finalize() -{ - auto buffer = make_unique(EVP_MAX_MD_SIZE); - - int mdLen = BIO_gets(m_impl->m_md, reinterpret_cast(&(*buffer)[0]), EVP_MAX_MD_SIZE); - if (mdLen <= 0) - BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to compute digest")); - - buffer->erase(buffer->begin() + mdLen, buffer->end()); - setOutputBuffer(std::move(buffer)); - - flushAllOutput(); -} - -unique_ptr -digestFilter(DigestAlgorithm algo) -{ - return make_unique(algo); -} - -} // namespace transform -} // namespace security -} // namespace ndn diff --git a/src/security/transform/hmac-filter.cpp b/src/security/transform/hmac-filter.cpp deleted file mode 100644 index d45cd851c..000000000 --- a/src/security/transform/hmac-filter.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "hmac-filter.hpp" -#include "../detail/openssl-helper.hpp" - -namespace ndn { -namespace security { -namespace transform { - -class HmacFilter::Impl -{ -public: -#if OPENSSL_VERSION_NUMBER < 0x1010000fL - Impl() - { - HMAC_CTX_init(&m_context); - } - - ~Impl() - { - HMAC_CTX_cleanup(&m_context); - } - - operator HMAC_CTX*() - { - return &m_context; - } - -private: - HMAC_CTX m_context; -#else - Impl() - : m_context(HMAC_CTX_new()) - { - } - - ~Impl() - { - HMAC_CTX_free(m_context); - } - - operator HMAC_CTX*() - { - return m_context; - } - -private: - HMAC_CTX* m_context; -#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL -}; - -HmacFilter::HmacFilter(DigestAlgorithm algo, const uint8_t* key, size_t keyLen) - : m_impl(new Impl) -{ - BOOST_ASSERT(key != nullptr); - BOOST_ASSERT(keyLen > 0); - - const EVP_MD* algorithm = detail::toDigestEvpMd(algo); - if (algorithm == nullptr) - BOOST_THROW_EXCEPTION(Error(getIndex(), "Unsupported digest algorithm")); - - if (HMAC_Init_ex(*m_impl, key, keyLen, algorithm, nullptr) == 0) - BOOST_THROW_EXCEPTION(Error(getIndex(), "Cannot initialize HMAC")); -} - -size_t -HmacFilter::convert(const uint8_t* buf, size_t size) -{ - if (HMAC_Update(*m_impl, buf, size) == 0) - BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to update HMAC")); - - return size; -} - -void -HmacFilter::finalize() -{ - auto buffer = make_unique(EVP_MAX_MD_SIZE); - unsigned int mdLen = 0; - - if (HMAC_Final(*m_impl, &(*buffer)[0], &mdLen) == 0) - BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to finalize HMAC")); - - buffer->erase(buffer->begin() + mdLen, buffer->end()); - setOutputBuffer(std::move(buffer)); - - flushAllOutput(); -} - -unique_ptr -hmacFilter(DigestAlgorithm algo, const uint8_t* key, size_t keyLen) -{ - return make_unique(algo, key, keyLen); -} - -} // namespace transform -} // namespace security -} // namespace ndn diff --git a/src/security/transform/hmac-filter.hpp b/src/security/transform/hmac-filter.hpp deleted file mode 100644 index 54099521f..000000000 --- a/src/security/transform/hmac-filter.hpp +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_CXX_SECURITY_TRANSFORM_HMAC_FILTER_HPP -#define NDN_CXX_SECURITY_TRANSFORM_HMAC_FILTER_HPP - -#include "transform-base.hpp" -#include "../security-common.hpp" - -namespace ndn { -namespace security { -namespace transform { - -/** - * @brief The module to generate HMAC for input data. - */ -class HmacFilter : public Transform -{ -public: - - /** - * @brief Create a HMAC module to generate HMAC using algorithm @p algo and @p key - * @pre @p key must not be nullptr, and @p size must be a positive integer. - */ - HmacFilter(DigestAlgorithm algo, const uint8_t* key, size_t keyLen); - -private: - /** - * @brief write data @p buf into HMAC signer - * - * @return The number of bytes that are actually accepted - */ - virtual size_t - convert(const uint8_t* buf, size_t size) final; - - /** - * @brief Finalize HMAC calculation and write the HMAC into next module. - */ - virtual void - finalize() final; - -private: - class Impl; - unique_ptr m_impl; -}; - -unique_ptr -hmacFilter(DigestAlgorithm algo, const uint8_t* key, size_t keyLen); - -} // namespace transform -} // namespace security -} // namespace ndn - -#endif // NDN_CXX_SECURITY_TRANSFORM_HMAC_FILTER_HPP diff --git a/src/security/transform/private-key.cpp b/src/security/transform/private-key.cpp deleted file mode 100644 index 8dfef0081..000000000 --- a/src/security/transform/private-key.cpp +++ /dev/null @@ -1,444 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "private-key.hpp" -#include "buffer-source.hpp" -#include "stream-source.hpp" -#include "base64-encode.hpp" -#include "base64-decode.hpp" -#include "stream-sink.hpp" -#include "../../encoding/buffer-stream.hpp" -#include "../detail/openssl-helper.hpp" -#include "../key-params.hpp" - -#include - -#define ENSURE_PRIVATE_KEY_LOADED(key) \ - do { \ - if (key == nullptr) \ - BOOST_THROW_EXCEPTION(Error("Private key has not been loaded yet")); \ - } while (false) - -namespace ndn { -namespace security { -namespace transform { - -class PrivateKey::Impl -{ -public: - Impl() - : key(nullptr) - { - } - - ~Impl() - { - EVP_PKEY_free(key); - } - -public: - EVP_PKEY* key; -}; - -PrivateKey::PrivateKey() - : m_impl(new Impl) -{ -} - -PrivateKey::~PrivateKey() = default; - -void -PrivateKey::loadPkcs1(const uint8_t* buf, size_t size) -{ - detail::Bio mem(BIO_s_mem()); - BIO_write(mem.get(), buf, size); - - d2i_PrivateKey_bio(mem.get(), &m_impl->key); - - ENSURE_PRIVATE_KEY_LOADED(m_impl->key); -} - -void -PrivateKey::loadPkcs1(std::istream& is) -{ - OBufferStream os; - streamSource(is) >> streamSink(os); - this->loadPkcs1(os.buf()->buf(), os.buf()->size()); -} - -void -PrivateKey::loadPkcs1Base64(const uint8_t* buf, size_t size) -{ - OBufferStream os; - bufferSource(buf, size) >> base64Decode() >> streamSink(os); - this->loadPkcs1(os.buf()->buf(), os.buf()->size()); -} - -void -PrivateKey::loadPkcs1Base64(std::istream& is) -{ - OBufferStream os; - streamSource(is) >> base64Decode() >> streamSink(os); - this->loadPkcs1(os.buf()->buf(), os.buf()->size()); -} - -void -PrivateKey::loadPkcs8(const uint8_t* buf, size_t size, const char* pw, size_t pwLen) -{ - BOOST_ASSERT(std::strlen(pw) == pwLen); - - detail::Bio mem(BIO_s_mem()); - BIO_write(mem.get(), buf, size); - - m_impl->key = d2i_PKCS8PrivateKey_bio(mem.get(), &m_impl->key, nullptr, const_cast(pw)); - - ENSURE_PRIVATE_KEY_LOADED(m_impl->key); -} - -static inline int -passwordCallback(char* buf, int size, int rwflag, void* u) -{ - auto cb = reinterpret_cast(u); - return (*cb)(buf, size, rwflag); -} - -void -PrivateKey::loadPkcs8(const uint8_t* buf, size_t size, PasswordCallback pwCallback) -{ - OpenSSL_add_all_algorithms(); - detail::Bio mem(BIO_s_mem()); - BIO_write(mem.get(), buf, size); - - if (pwCallback) - m_impl->key = d2i_PKCS8PrivateKey_bio(mem.get(), &m_impl->key, passwordCallback, &pwCallback); - else - m_impl->key = d2i_PKCS8PrivateKey_bio(mem.get(), &m_impl->key, nullptr, nullptr); - - ENSURE_PRIVATE_KEY_LOADED(m_impl->key); -} - -void -PrivateKey::loadPkcs8(std::istream& is, const char* pw, size_t pwLen) -{ - OBufferStream os; - streamSource(is) >> streamSink(os); - this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pw, pwLen); -} - -void -PrivateKey::loadPkcs8(std::istream& is, PasswordCallback pwCallback) -{ - OBufferStream os; - streamSource(is) >> streamSink(os); - this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pwCallback); -} - -void -PrivateKey::loadPkcs8Base64(const uint8_t* buf, size_t size, const char* pw, size_t pwLen) -{ - OBufferStream os; - bufferSource(buf, size) >> base64Decode() >> streamSink(os); - this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pw, pwLen); -} - -void -PrivateKey::loadPkcs8Base64(const uint8_t* buf, size_t size, PasswordCallback pwCallback) -{ - OBufferStream os; - bufferSource(buf, size) >> base64Decode() >> streamSink(os); - this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pwCallback); -} - -void -PrivateKey::loadPkcs8Base64(std::istream& is, const char* pw, size_t pwLen) -{ - OBufferStream os; - streamSource(is) >> base64Decode() >> streamSink(os); - this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pw, pwLen); -} - -void -PrivateKey::loadPkcs8Base64(std::istream& is, PasswordCallback pwCallback) -{ - OBufferStream os; - streamSource(is) >> base64Decode() >> streamSink(os); - this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pwCallback); -} - -void -PrivateKey::savePkcs1(std::ostream& os) const -{ - bufferSource(*this->toPkcs1()) >> streamSink(os); -} - -void -PrivateKey::savePkcs1Base64(std::ostream& os) const -{ - bufferSource(*this->toPkcs1()) >> base64Encode() >> streamSink(os); -} - -void -PrivateKey::savePkcs8(std::ostream& os, const char* pw, size_t pwLen) const -{ - bufferSource(*this->toPkcs8(pw, pwLen)) >> streamSink(os); -} - -void -PrivateKey::savePkcs8(std::ostream& os, PasswordCallback pwCallback) const -{ - bufferSource(*this->toPkcs8(pwCallback)) >> streamSink(os); -} - -void -PrivateKey::savePkcs8Base64(std::ostream& os, const char* pw, size_t pwLen) const -{ - bufferSource(*this->toPkcs8(pw, pwLen)) >> base64Encode() >> streamSink(os); -} - -void -PrivateKey::savePkcs8Base64(std::ostream& os, PasswordCallback pwCallback) const -{ - bufferSource(*this->toPkcs8(pwCallback)) >> base64Encode() >> streamSink(os); -} - -ConstBufferPtr -PrivateKey::derivePublicKey() const -{ - ENSURE_PRIVATE_KEY_LOADED(m_impl->key); - - uint8_t* pkcs8 = nullptr; - int len = i2d_PUBKEY(m_impl->key, &pkcs8); - - if (len <= 0) - BOOST_THROW_EXCEPTION(Error("Failed to derive public key")); - - auto result = make_shared(pkcs8, len); - OPENSSL_free(pkcs8); - - return result; -} - -ConstBufferPtr -PrivateKey::decrypt(const uint8_t* cipherText, size_t cipherLen) const -{ - ENSURE_PRIVATE_KEY_LOADED(m_impl->key); - -#if OPENSSL_VERSION_NUMBER < 0x1010000fL - switch (EVP_PKEY_type(m_impl->key->type)) { -#else - switch (EVP_PKEY_base_id(m_impl->key)) { -#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL - case EVP_PKEY_RSA: - return rsaDecrypt(cipherText, cipherLen); - default: - BOOST_THROW_EXCEPTION(Error("Decryption is not supported for this key type")); - } -} - -void* -PrivateKey::getEvpPkey() const -{ - return m_impl->key; -} - -ConstBufferPtr -PrivateKey::toPkcs1() const -{ - ENSURE_PRIVATE_KEY_LOADED(m_impl->key); - - OpenSSL_add_all_algorithms(); - detail::Bio mem(BIO_s_mem()); - int ret = i2d_PrivateKey_bio(mem.get(), m_impl->key); - if (ret != 1) - BOOST_THROW_EXCEPTION(Error("Cannot convert key into PKCS1 format")); - - int len8 = BIO_pending(mem.get()); - auto buffer = make_shared(len8); - BIO_read(mem.get(), buffer->buf(), len8); - - return buffer; -} - -ConstBufferPtr -PrivateKey::toPkcs8(const char* pw, size_t pwLen) const -{ - ENSURE_PRIVATE_KEY_LOADED(m_impl->key); - - BOOST_ASSERT(std::strlen(pw) == pwLen); - - OpenSSL_add_all_algorithms(); - detail::Bio mem(BIO_s_mem()); - int ret = i2d_PKCS8PrivateKey_bio(mem.get(), m_impl->key, EVP_des_cbc(), - const_cast(pw), pwLen, nullptr, nullptr); - if (ret != 1) - BOOST_THROW_EXCEPTION(Error("Cannot convert key into PKCS8 format")); - - int len8 = BIO_pending(mem.get()); - auto buffer = make_shared(len8); - BIO_read(mem.get(), buffer->buf(), len8); - - return buffer; -} - -ConstBufferPtr -PrivateKey::toPkcs8(PasswordCallback pwCallback) const -{ - ENSURE_PRIVATE_KEY_LOADED(m_impl->key); - - OpenSSL_add_all_algorithms(); - detail::Bio mem(BIO_s_mem()); - int ret = i2d_PKCS8PrivateKey_bio(mem.get(), m_impl->key, EVP_des_cbc(), - nullptr, 0, - passwordCallback, &pwCallback); - if (ret != 1) - BOOST_THROW_EXCEPTION(Error("Cannot convert key into PKCS8 format")); - - int len8 = BIO_pending(mem.get()); - auto buffer = make_shared(len8); - BIO_read(mem.get(), buffer->buf(), len8); - - return buffer; -} - -ConstBufferPtr -PrivateKey::rsaDecrypt(const uint8_t* cipherText, size_t cipherLen) const -{ - detail::EvpPkeyCtx ctx(m_impl->key); - - if (EVP_PKEY_decrypt_init(ctx.get()) <= 0) - BOOST_THROW_EXCEPTION(Error("Failed to initialize decryption context")); - - if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING) <= 0) - BOOST_THROW_EXCEPTION(Error("Failed to set padding")); - - size_t outlen = 0; - // Determine buffer length - if (EVP_PKEY_decrypt(ctx.get(), nullptr, &outlen, cipherText, cipherLen) <= 0) - BOOST_THROW_EXCEPTION(Error("Failed to estimate output length")); - - auto out = make_shared(outlen); - - if (EVP_PKEY_decrypt(ctx.get(), out->buf(), &outlen, cipherText, cipherLen) <= 0) - BOOST_THROW_EXCEPTION(Error("Failed to decrypt cipher text")); - - out->resize(outlen); - return out; -} - -static unique_ptr -generateRsaKey(uint32_t keySize) -{ - detail::EvpPkeyCtx kctx(EVP_PKEY_RSA); - - int ret = EVP_PKEY_keygen_init(kctx.get()); - if (ret != 1) - BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate RSA key")); - - ret = EVP_PKEY_CTX_set_rsa_keygen_bits(kctx.get(), keySize); - if (ret != 1) - BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate RSA key")); - - detail::EvpPkey key; - ret = EVP_PKEY_keygen(kctx.get(), &key); - if (ret != 1) - BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate RSA key")); - - detail::Bio mem(BIO_s_mem()); - i2d_PrivateKey_bio(mem.get(), key.get()); - int len = BIO_pending(mem.get()); - Buffer buffer(len); - BIO_read(mem.get(), buffer.buf(), len); - - auto privateKey = make_unique(); - privateKey->loadPkcs1(buffer.buf(), buffer.size()); - - return privateKey; -} - -static unique_ptr -generateEcKey(uint32_t keySize) -{ - detail::EvpPkeyCtx ctx(EVP_PKEY_EC); - - int ret = EVP_PKEY_paramgen_init(ctx.get()); - if (ret != 1) - BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key")); - - switch (keySize) { - case 256: - ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), NID_X9_62_prime256v1); - break; - case 384: - ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), NID_secp384r1); - break; - default: - BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key")); - } - if (ret != 1) - BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key")); - - detail::EvpPkey params; - ret = EVP_PKEY_paramgen(ctx.get(), ¶ms); - if (ret != 1) - BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key")); - - detail::EvpPkeyCtx kctx(params.get()); - ret = EVP_PKEY_keygen_init(kctx.get()); - if (ret != 1) - BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key")); - - detail::EvpPkey key; - ret = EVP_PKEY_keygen(kctx.get(), &key); - if (ret != 1) - BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key")); - - detail::Bio mem(BIO_s_mem()); - i2d_PrivateKey_bio(mem.get(), key.get()); - int len = BIO_pending(mem.get()); - Buffer buffer(len); - BIO_read(mem.get(), buffer.buf(), len); - - auto privateKey = make_unique(); - privateKey->loadPkcs1(buffer.buf(), buffer.size()); - - return privateKey; -} - -unique_ptr -generatePrivateKey(const KeyParams& keyParams) -{ - switch (keyParams.getKeyType()) { - case KeyType::RSA: { - const RsaKeyParams& rsaParams = static_cast(keyParams); - return generateRsaKey(rsaParams.getKeySize()); - } - case KeyType::EC: { - const EcdsaKeyParams& ecdsaParams = static_cast(keyParams); - return generateEcKey(ecdsaParams.getKeySize()); - } - default: - BOOST_THROW_EXCEPTION(std::invalid_argument("Unsupported asymmetric key type")); - } -} - -} // namespace transform -} // namespace security -} // namespace ndn diff --git a/src/security/transform/public-key.cpp b/src/security/transform/public-key.cpp deleted file mode 100644 index 3232e5e5c..000000000 --- a/src/security/transform/public-key.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "public-key.hpp" -#include "buffer-source.hpp" -#include "stream-source.hpp" -#include "base64-encode.hpp" -#include "base64-decode.hpp" -#include "stream-sink.hpp" -#include "../../encoding/buffer-stream.hpp" -#include "../detail/openssl-helper.hpp" - -#define ENSURE_PUBLIC_KEY_LOADED(key) \ - do { \ - if (key == nullptr) \ - BOOST_THROW_EXCEPTION(Error("Public key has not been loaded yet")); \ - } while (false) - -namespace ndn { -namespace security { -namespace transform { - -class PublicKey::Impl -{ -public: - Impl() - : key(nullptr) - { - } - - ~Impl() - { - EVP_PKEY_free(key); - } - -public: - EVP_PKEY* key; -}; - -PublicKey::PublicKey() - : m_impl(new Impl) -{ -} - -PublicKey::~PublicKey() = default; - -KeyType -PublicKey::getKeyType() const -{ - ENSURE_PUBLIC_KEY_LOADED(m_impl->key); - -#if OPENSSL_VERSION_NUMBER < 0x1010000fL - switch (EVP_PKEY_type(m_impl->key->type)) { -#else - switch (EVP_PKEY_base_id(m_impl->key)) { -#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL - case EVP_PKEY_RSA: - return KeyType::RSA; - case EVP_PKEY_EC: - return KeyType::EC; - default: - BOOST_THROW_EXCEPTION(Error("Public key type is not recognized")); - } -} - -void -PublicKey::loadPkcs8(const uint8_t* buf, size_t size) -{ - m_impl->key = d2i_PUBKEY(nullptr, &buf, size); - - ENSURE_PUBLIC_KEY_LOADED(m_impl->key); -} - -void -PublicKey::loadPkcs8(std::istream& is) -{ - OBufferStream os; - { - using namespace transform; - streamSource(is) >> streamSink(os); - } - this->loadPkcs8(os.buf()->buf(), os.buf()->size()); -} - -void -PublicKey::loadPkcs8Base64(const uint8_t* buf, size_t size) -{ - OBufferStream os; - { - using namespace transform; - bufferSource(buf, size) >> base64Decode() >> streamSink(os); - } - this->loadPkcs8(os.buf()->buf(), os.buf()->size()); -} - -void -PublicKey::loadPkcs8Base64(std::istream& is) -{ - OBufferStream os; - { - using namespace transform; - streamSource(is) >> base64Decode() >> streamSink(os); - } - this->loadPkcs8(os.buf()->buf(), os.buf()->size()); -} - -void -PublicKey::savePkcs8(std::ostream& os) const -{ - using namespace transform; - bufferSource(*this->toPkcs8()) >> streamSink(os); -} - -void -PublicKey::savePkcs8Base64(std::ostream& os) const -{ - using namespace transform; - bufferSource(*this->toPkcs8()) >> base64Encode() >> streamSink(os); -} - -ConstBufferPtr -PublicKey::encrypt(const uint8_t* plainText, size_t plainLen) const -{ - ENSURE_PUBLIC_KEY_LOADED(m_impl->key); - -#if OPENSSL_VERSION_NUMBER < 0x1010000fL - switch (EVP_PKEY_type(m_impl->key->type)) { -#else - switch (EVP_PKEY_base_id(m_impl->key)) { -#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL - case EVP_PKEY_RSA: - return rsaEncrypt(plainText, plainLen); - default: - BOOST_THROW_EXCEPTION(Error("Encryption is not supported for this key type")); - } -} - -void* -PublicKey::getEvpPkey() const -{ - return m_impl->key; -} - -ConstBufferPtr -PublicKey::toPkcs8() const -{ - ENSURE_PUBLIC_KEY_LOADED(m_impl->key); - - uint8_t* pkcs8 = nullptr; - int len = i2d_PUBKEY(m_impl->key, &pkcs8); - - if (pkcs8 == nullptr) - BOOST_THROW_EXCEPTION(Error("Failed to convert to pkcs8 format")); - - auto buffer = make_shared(pkcs8, len); - OPENSSL_free(pkcs8); - - return buffer; -} - -ConstBufferPtr -PublicKey::rsaEncrypt(const uint8_t* plainText, size_t plainLen) const -{ - detail::EvpPkeyCtx ctx(m_impl->key); - - if (EVP_PKEY_encrypt_init(ctx.get()) <= 0) - BOOST_THROW_EXCEPTION(Error("Failed to initialize encryption context")); - - if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING) <= 0) - BOOST_THROW_EXCEPTION(Error("Failed to set padding")); - - size_t outlen = 0; - // Determine buffer length - if (EVP_PKEY_encrypt(ctx.get(), nullptr, &outlen, plainText, plainLen) <= 0) - BOOST_THROW_EXCEPTION(Error("Failed to estimate output length")); - - auto out = make_shared(outlen); - - if (EVP_PKEY_encrypt(ctx.get(), out->buf(), &outlen, plainText, plainLen) <= 0) - BOOST_THROW_EXCEPTION(Error("Failed to decrypt cipher text")); - - out->resize(outlen); - return out; -} - -} // namespace transform -} // namespace security -} // namespace ndn diff --git a/src/security/transform/public-key.hpp b/src/security/transform/public-key.hpp deleted file mode 100644 index 169b9e05e..000000000 --- a/src/security/transform/public-key.hpp +++ /dev/null @@ -1,137 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_CXX_SECURITY_TRANSFORM_PUBLIC_KEY_HPP -#define NDN_CXX_SECURITY_TRANSFORM_PUBLIC_KEY_HPP - -#include "../security-common.hpp" -#include "../../encoding/buffer.hpp" - -namespace ndn { -namespace security { -namespace transform { - -class VerifierFilter; - -/** - * @brief Abstraction of public key in crypto transformation - */ -class PublicKey : noncopyable -{ -public: - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - - friend class VerifierFilter; - -public: - /** - * @brief Create a public key instance - * - * One must call loadXXXX(...) to load public key. - */ - PublicKey(); - - ~PublicKey(); - - /** - * @brief Get the type of the public key - */ - KeyType - getKeyType() const; - - /** - * @brief Load the public key in PKCS#8 format from a buffer @p buf - */ - void - loadPkcs8(const uint8_t* buf, size_t size); - - /** - * @brief Load the public key in PKCS#8 format from a stream @p is - */ - void - loadPkcs8(std::istream& is); - - /** - * @brief Load the public key in base64-encoded PKCS#8 format from a buffer @p buf - */ - void - loadPkcs8Base64(const uint8_t* buf, size_t size); - - /** - * @brief Load the public key in base64-encoded PKCS#8 format from a stream @p is - */ - void - loadPkcs8Base64(std::istream& is); - - /** - * @brief Save the public key in PKCS#8 format into a stream @p os - */ - void - savePkcs8(std::ostream& os) const; - - /** - * @brief Save the public key in base64-encoded PKCS#8 format into a stream @p os - */ - void - savePkcs8Base64(std::ostream& os) const; - - /** - * @return Cipher text of @p plainText encrypted using the public key. - * - * Only RSA encryption is supported for now. - */ - ConstBufferPtr - encrypt(const uint8_t* plainText, size_t plainLen) const; - -private: - /** - * @return A pointer to an EVP_PKEY instance. - * - * One need to explicitly cast the return value to EVP_PKEY*. - */ - void* - getEvpPkey() const; - -private: - ConstBufferPtr - toPkcs8() const; - - ConstBufferPtr - rsaEncrypt(const uint8_t* plainText, size_t plainLen) const; - -private: - class Impl; - unique_ptr m_impl; -}; - -} // namespace transform -} // namespace security -} // namespace ndn - -#endif // NDN_CXX_SECURITY_TRANSFORM_PUBLIC_KEY_HPP diff --git a/src/security/transform/signer-filter.cpp b/src/security/transform/signer-filter.cpp deleted file mode 100644 index 16d314662..000000000 --- a/src/security/transform/signer-filter.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "signer-filter.hpp" -#include "../../encoding/buffer.hpp" -#include "../detail/openssl.hpp" - -namespace ndn { -namespace security { -namespace transform { - -class SignerFilter::Impl -{ -public: - Impl(const PrivateKey& key) - : m_key(key) - , m_md(BIO_new(BIO_f_md())) - , m_sink(BIO_new(BIO_s_null())) - { - BIO_push(m_md, m_sink); - } - - ~Impl() - { - BIO_free_all(m_md); - } - -public: - const PrivateKey& m_key; - - BIO* m_md; - BIO* m_sink; -}; - -SignerFilter::SignerFilter(DigestAlgorithm algo, const PrivateKey& key) - : m_impl(new Impl(key)) -{ - switch (algo) { - case DigestAlgorithm::SHA256: { - if (!BIO_set_md(m_impl->m_md, EVP_sha256())) - BOOST_THROW_EXCEPTION(Error(getIndex(), "Cannot set digest")); - break; - } - - default: - BOOST_THROW_EXCEPTION(Error(getIndex(), "Digest algorithm is not supported")); - } -} - -size_t -SignerFilter::convert(const uint8_t* buf, size_t size) -{ - int wLen = BIO_write(m_impl->m_md, buf, size); - - if (wLen <= 0) { // fail to write data - if (!BIO_should_retry(m_impl->m_md)) { - // we haven't written everything but some error happens, and we cannot retry - BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to accept more input")); - } - return 0; - } - else { // update number of bytes written - return wLen; - } -} - -void -SignerFilter::finalize() -{ - EVP_PKEY* key = reinterpret_cast(m_impl->m_key.getEvpPkey()); - auto buffer = make_unique(EVP_PKEY_size(key)); - unsigned int sigLen = 0; - - EVP_MD_CTX* ctx = nullptr; - BIO_get_md_ctx(m_impl->m_md, &ctx); - EVP_SignFinal(ctx, &(*buffer)[0], &sigLen, key); // should be ok, enough space is allocated in buffer - - buffer->erase(buffer->begin() + sigLen, buffer->end()); - setOutputBuffer(std::move(buffer)); - - flushAllOutput(); -} - -unique_ptr -signerFilter(DigestAlgorithm algo, const PrivateKey& key) -{ - return make_unique(algo, key); -} - -} // namespace transform -} // namespace security -} // namespace ndn diff --git a/src/security/transform/verifier-filter.cpp b/src/security/transform/verifier-filter.cpp deleted file mode 100644 index 5f0c7162e..000000000 --- a/src/security/transform/verifier-filter.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "verifier-filter.hpp" -#include "../detail/openssl.hpp" - -namespace ndn { -namespace security { -namespace transform { - -class VerifierFilter::Impl -{ -public: - Impl(const PublicKey& key, const uint8_t* sig, size_t sigLen) - : m_key(key) - , m_md(BIO_new(BIO_f_md())) - , m_sink(BIO_new(BIO_s_null())) - , m_sig(sig) - , m_sigLen(sigLen) - { - BIO_push(m_md, m_sink); - } - - ~Impl() - { - BIO_free_all(m_md); - } - -public: - const PublicKey& m_key; - - BIO* m_md; - BIO* m_sink; - - const uint8_t* m_sig; - size_t m_sigLen; -}; - -VerifierFilter::VerifierFilter(DigestAlgorithm algo, const PublicKey& key, - const uint8_t* sig, size_t sigLen) - : m_impl(new Impl(key, sig, sigLen)) -{ - switch (algo) { - case DigestAlgorithm::SHA256: { - if (!BIO_set_md(m_impl->m_md, EVP_sha256())) - BOOST_THROW_EXCEPTION(Error(getIndex(), "Cannot set digest")); - break; - } - - default: - BOOST_THROW_EXCEPTION(Error(getIndex(), "Digest algorithm is not supported")); - } -} - -size_t -VerifierFilter::convert(const uint8_t* buf, size_t size) -{ - int wLen = BIO_write(m_impl->m_md, buf, size); - - if (wLen <= 0) { // fail to write data - if (!BIO_should_retry(m_impl->m_md)) { - // we haven't written everything but some error happens, and we cannot retry - BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to accept more input")); - } - return 0; - } - else { // update number of bytes written - return wLen; - } -} - -void -VerifierFilter::finalize() -{ - EVP_PKEY* key = reinterpret_cast(m_impl->m_key.getEvpPkey()); - auto buffer = make_unique(1); - - EVP_MD_CTX* ctx = nullptr; - BIO_get_md_ctx(m_impl->m_md, &ctx); - int res = EVP_VerifyFinal(ctx, m_impl->m_sig, m_impl->m_sigLen, key); - - if (res < 0) - BOOST_THROW_EXCEPTION(Error(getIndex(), "Verification error")); - - (*buffer)[0] = (res != 0) ? 1 : 0; - setOutputBuffer(std::move(buffer)); - - flushAllOutput(); -} - -unique_ptr -verifierFilter(DigestAlgorithm algo, const PublicKey& key, - const uint8_t* sig, size_t sigLen) -{ - return make_unique(algo, key, sig, sigLen); -} - -} // namespace transform -} // namespace security -} // namespace ndn diff --git a/src/security/transform/verifier-filter.hpp b/src/security/transform/verifier-filter.hpp deleted file mode 100644 index ee69f0333..000000000 --- a/src/security/transform/verifier-filter.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_CXX_SECURITY_TRANSFORM_VERIFIER_FILTER_HPP -#define NDN_CXX_SECURITY_TRANSFORM_VERIFIER_FILTER_HPP - -#include "transform-base.hpp" -#include "public-key.hpp" -#include "../security-common.hpp" - -namespace ndn { -namespace security { -namespace transform { - -/** - * @brief The module to verify signature. - * - * The next module is usually SinkBool. - */ -class VerifierFilter : public Transform -{ -public: - /** - * @brief Create a verifier module to verify signature @p sig using algorithm @p algo and @p key - */ - VerifierFilter(DigestAlgorithm algo, const PublicKey& key, const uint8_t* sig, size_t sigLen); - -private: - /** - * @brief Write data @p buf into verifier - * - * @return The number of bytes that are actually written - */ - virtual size_t - convert(const uint8_t* buf, size_t size) final; - - /** - * @brief Finalize verification and write the result (single byte) into next module. - */ - virtual void - finalize() final; - -private: - class Impl; - unique_ptr m_impl; -}; - -unique_ptr -verifierFilter(DigestAlgorithm algo, const PublicKey& key, const uint8_t* sig, size_t sigLen); - -} // namespace transform -} // namespace security -} // namespace ndn - -#endif // NDN_CXX_SECURITY_TRANSFORM_VERIFIER_FILTER_HPP diff --git a/src/security/v1/certificate-extension.cpp b/src/security/v1/certificate-extension.cpp deleted file mode 100644 index d871eace8..000000000 --- a/src/security/v1/certificate-extension.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - * @author Alexander Afanasyev - */ - -#include "certificate-extension.hpp" -#include "cryptopp.hpp" - -namespace ndn { -namespace security { -namespace v1 { - -void -CertificateExtension::encode(CryptoPP::BufferedTransformation& out) const -{ - using namespace CryptoPP; - - // Extension ::= SEQUENCE { - // extnID OBJECT IDENTIFIER, - // critical BOOLEAN DEFAULT FALSE, - // extnValue OCTET STRING } - - DERSequenceEncoder extension(out); - { - m_extensionId.encode(extension); - DEREncodeUnsigned(extension, m_isCritical, BOOLEAN); - DEREncodeOctetString(extension, m_extensionValue.buf(), m_extensionValue.size()); - } - extension.MessageEnd(); -} - -void -CertificateExtension::decode(CryptoPP::BufferedTransformation& in) -{ - using namespace CryptoPP; - - // Extension ::= SEQUENCE { - // extnID OBJECT IDENTIFIER, - // critical BOOLEAN DEFAULT FALSE, - // extnValue OCTET STRING } - - BERSequenceDecoder extension(in); - { - m_extensionId.decode(extension); - BERDecodeUnsigned(extension, m_isCritical, BOOLEAN); - - // the extra copy operation can be optimized, but not trivial, - // since the length is not known in advance - SecByteBlock tmpBlock; - BERDecodeOctetString(extension, tmpBlock); - m_extensionValue.assign(tmpBlock.begin(), tmpBlock.end()); - } - extension.MessageEnd(); -} - -} // namespace v1 -} // namespace security -} // namespace ndn diff --git a/src/security/v1/certificate-extension.hpp b/src/security/v1/certificate-extension.hpp deleted file mode 100644 index c8988356b..000000000 --- a/src/security/v1/certificate-extension.hpp +++ /dev/null @@ -1,128 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - * @author Jeff Thompson - * @author Alexander Afanasyev - */ - -#ifndef NDN_SECURITY_V1_CERTIFICATE_EXTENSION_HPP -#define NDN_SECURITY_V1_CERTIFICATE_EXTENSION_HPP - -#include "../../common.hpp" -#include "../../encoding/buffer.hpp" -#include "../../encoding/oid.hpp" - -namespace CryptoPP { -class BufferedTransformation; -} // namespace CryptoPP - -namespace ndn { -namespace security { -namespace v1 { - -/** - * A CertificateExtension represents the Extension entry in a certificate. - */ -class CertificateExtension -{ -public: - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - - explicit - CertificateExtension(CryptoPP::BufferedTransformation& in) - { - decode(in); - } - - /** - * Create a new CertificateExtension. - * @param oid The oid of subject description entry. - * @param isCritical If true, the extension must be handled. - * @param value The extension value. - */ - CertificateExtension(const Oid& oid, const bool isCritical, const Buffer& value) - : m_extensionId(oid), m_isCritical(isCritical), m_extensionValue(value) - { - } - - CertificateExtension(const Oid& oid, const bool isCritical, - const uint8_t* value, size_t valueSize) - : m_extensionId(oid), m_isCritical(isCritical), m_extensionValue(value, valueSize) - { - } - - /** - * The virtual destructor. - */ - virtual - ~CertificateExtension() - { - } - - void - encode(CryptoPP::BufferedTransformation& out) const; - - void - decode(CryptoPP::BufferedTransformation& in); - - inline const Oid& - getOid() const - { - return m_extensionId; - } - - inline bool - getIsCritical() const - { - return m_isCritical; - } - - inline const Buffer& - getValue() const - { - return m_extensionValue; - } - -protected: - Oid m_extensionId; - bool m_isCritical; - Buffer m_extensionValue; -}; - -} // namespace v1 -} // namespace security - -#ifdef NDN_CXX_KEEP_SECURITY_V1_ALIASES -/// @deprecated When needed, use explicit namespace -using security::v1::CertificateExtension; -#endif // NDN_CXX_KEEP_SECURITY_V1_ALIASES - -} // namespace ndn - -#endif // NDN_SECURITY_V1_CERTIFICATE_EXTENSION_HPP diff --git a/src/security/v1/certificate-subject-description.cpp b/src/security/v1/certificate-subject-description.cpp deleted file mode 100644 index 1e910c2fb..000000000 --- a/src/security/v1/certificate-subject-description.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - * @author Jeff Thompson - * @author Alexander Afanasyev - */ - -#include "certificate-subject-description.hpp" - -#include "cryptopp.hpp" - -namespace ndn { -namespace security { -namespace v1 { - -void -CertificateSubjectDescription::encode(CryptoPP::BufferedTransformation& out) const -{ - using namespace CryptoPP; - // RelativeDistinguishedName ::= - // SET OF AttributeTypeAndValue - // - // AttributeTypeAndValue ::= SEQUENCE { - // type AttributeType, - // value AttributeValue } - // - // AttributeType ::= OBJECT IDENTIFIER - // - // AttributeValue ::= ANY DEFINED BY AttributeType - DERSequenceEncoder attributeTypeAndValue(out); - { - m_oid.encode(attributeTypeAndValue); - DEREncodeTextString(attributeTypeAndValue, m_value, PRINTABLE_STRING); - } - attributeTypeAndValue.MessageEnd(); -} - -void -CertificateSubjectDescription::decode(CryptoPP::BufferedTransformation& in) -{ - using namespace CryptoPP; - // RelativeDistinguishedName ::= - // SET OF AttributeTypeAndValue - // - // AttributeTypeAndValue ::= SEQUENCE { - // type AttributeType, - // value AttributeValue } - // - // AttributeType ::= OBJECT IDENTIFIER - // - // AttributeValue ::= ANY DEFINED BY AttributeType - - BERSequenceDecoder attributeTypeAndValue(in); - { - m_oid.decode(attributeTypeAndValue); - - /// @todo May be add more intelligent processing, since the following - /// may fail if somebody encoded attribute that uses non PRINTABLE_STRING as value - BERDecodeTextString(attributeTypeAndValue, m_value, PRINTABLE_STRING); - } - attributeTypeAndValue.MessageEnd(); -} - -} // namespace v1 -} // namespace security -} // namespace ndn diff --git a/src/security/v1/certificate-subject-description.hpp b/src/security/v1/certificate-subject-description.hpp deleted file mode 100644 index 00eab7600..000000000 --- a/src/security/v1/certificate-subject-description.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - * @author Jeff Thompson - * @author Alexander Afanasyev - */ - -#ifndef NDN_SECURITY_V1_CERTIFICATE_SUBJECT_DESCRIPTION_HPP -#define NDN_SECURITY_V1_CERTIFICATE_SUBJECT_DESCRIPTION_HPP - -#include "../../common.hpp" -#include "../../encoding/oid.hpp" - -namespace CryptoPP { -class BufferedTransformation; -} // namespace CryptoPP - -namespace ndn { -namespace security { -namespace v1 { - -/** - * A CertificateSubjectDescription represents the SubjectDescription entry in a Certificate. - */ -class CertificateSubjectDescription -{ -public: - explicit - CertificateSubjectDescription(CryptoPP::BufferedTransformation& in) - { - decode(in); - } - - /** - * Create a new CertificateSubjectDescription. - * @param oid The oid of the subject description entry. - * @param value The value of the subject description entry. - */ - CertificateSubjectDescription(const Oid& oid, const std::string& value) - : m_oid(oid), m_value(value) - { - } - - void - encode(CryptoPP::BufferedTransformation& out) const; - - void - decode(CryptoPP::BufferedTransformation& in); - - std::string - getOidString() const - { - return m_oid.toString(); - } - - const std::string& - getValue() const - { - return m_value; - } - -private: - Oid m_oid; - std::string m_value; -}; - -} // namespace v1 -} // namespace security - -#ifdef NDN_CXX_KEEP_SECURITY_V1_ALIASES -/// @deprecated When needed, use explicit namespace -using security::v1::CertificateSubjectDescription; -#endif // NDN_CXX_KEEP_SECURITY_V1_ALIASES - -} // namespace ndn - -#endif // NDN_SECURITY_V1_CERTIFICATE_SUBJECT_DESCRIPTION_HPP diff --git a/src/security/v1/certificate.cpp b/src/security/v1/certificate.cpp deleted file mode 100644 index 823c994a4..000000000 --- a/src/security/v1/certificate.cpp +++ /dev/null @@ -1,359 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - * @author Jeff Thompson - * @author Alexander Afanasyev - */ - -#include "certificate.hpp" -#include "../../util/time.hpp" -#include "cryptopp.hpp" -#include "../../encoding/cryptopp/asn_ext.hpp" -#include "../../encoding/buffer-stream.hpp" -#include "../../util/concepts.hpp" -#include "../../util/indented-stream.hpp" - -#include - -namespace ndn { -namespace security { -namespace v1 { - -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "Certificate::Error must inherit from tlv::Error"); - -Certificate::Certificate() - : m_notBefore(time::system_clock::TimePoint::max()) - , m_notAfter(time::system_clock::TimePoint::min()) -{ -} - -Certificate::Certificate(const Data& data) - // Use the copy constructor. It clones the signature object. - : Data(data) -{ - decode(); -} - -Certificate::Certificate(const Block& block) - : Data(block) -{ - decode(); -} - -Certificate::~Certificate() -{ -} - -void -Certificate::wireDecode(const Block& wire) -{ - Data::wireDecode(wire); - decode(); -} - -bool -Certificate::isTooEarly() -{ - if (time::system_clock::now() < m_notBefore) - return true; - else - return false; -} - -bool -Certificate::isTooLate() -{ - if (time::system_clock::now() > m_notAfter) - return true; - else - return false; -} - -void -Certificate::encode() -{ - // Name - // /ID-CERT/ - // Content - // DER encoded idCert: - // - // idCert ::= SEQUENCE { - // validity Validity, - // subject Name, - // subjectPubKeyInfo SubjectPublicKeyInfo, - // extension Extensions OPTIONAL } - // - // Validity ::= SEQUENCE { - // notBefore Time, - // notAfter Time } - // - // Name ::= CHOICE { - // RDNSequence } - // - // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName - // - // RelativeDistinguishedName ::= - // SET OF AttributeTypeAndValue - // - // SubjectPublicKeyInfo ::= SEQUENCE { - // algorithm AlgorithmIdentifier - // keybits BIT STRING } - // - // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension - // - // (see http://www.ietf.org/rfc/rfc3280.txt for more detail) - // - // KeyLocator - // issuer’s certificate name - // Signature - - using namespace CryptoPP; - - OBufferStream os; - CryptoPP::FileSink sink(os); - - // idCert ::= SEQUENCE { - // validity Validity, - // subject Name, - // subjectPubKeyInfo SubjectPublicKeyInfo, - // extension Extensions OPTIONAL } - DERSequenceEncoder idCert(sink); - { - // Validity ::= SEQUENCE { - // notBefore Time, - // notAfter Time } - DERSequenceEncoder validity(idCert); - { - DEREncodeGeneralTime(validity, m_notBefore); - DEREncodeGeneralTime(validity, m_notAfter); - } - validity.MessageEnd(); - - // Name ::= CHOICE { - // RDNSequence } - // - // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName - DERSequenceEncoder name(idCert); - { - for (SubjectDescriptionList::iterator it = m_subjectDescriptionList.begin(); - it != m_subjectDescriptionList.end(); ++it) - { - it->encode(name); - } - } - name.MessageEnd(); - - // SubjectPublicKeyInfo - m_key.encode(idCert); - - // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension - // - // Extension ::= SEQUENCE { - // extnID OBJECT IDENTIFIER, - // critical BOOLEAN DEFAULT FALSE, - // extnValue OCTET STRING } - if (!m_extensionList.empty()) - { - DERSequenceEncoder extensions(idCert); - { - for (ExtensionList::iterator it = m_extensionList.begin(); - it != m_extensionList.end(); ++it) - { - it->encode(extensions); - } - } - extensions.MessageEnd(); - } - } - - idCert.MessageEnd(); - - setContent(os.buf()); - setContentType(tlv::ContentType_Key); -} - -void -Certificate::decode() -{ - using namespace CryptoPP; - - try { - OBufferStream os; - StringSource source(getContent().value(), getContent().value_size(), true); - - // idCert ::= SEQUENCE { - // validity Validity, - // subject Name, - // subjectPubKeyInfo SubjectPublicKeyInfo, - // extension Extensions OPTIONAL } - BERSequenceDecoder idCert(source); - { - // Validity ::= SEQUENCE { - // notBefore Time, - // notAfter Time } - BERSequenceDecoder validity(idCert); - { - BERDecodeTime(validity, m_notBefore); - BERDecodeTime(validity, m_notAfter); - } - validity.MessageEnd(); - - // Name ::= CHOICE { - // RDNSequence } - // - // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName - m_subjectDescriptionList.clear(); - BERSequenceDecoder name(idCert); - { - while (!name.EndReached()) - { - m_subjectDescriptionList.push_back(CertificateSubjectDescription(name)); - } - } - name.MessageEnd(); - - // SubjectPublicKeyInfo ::= SEQUENCE { - // algorithm AlgorithmIdentifier - // keybits BIT STRING } - m_key.decode(idCert); - - // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension - // - // Extension ::= SEQUENCE { - // extnID OBJECT IDENTIFIER, - // critical BOOLEAN DEFAULT FALSE, - // extnValue OCTET STRING } - m_extensionList.clear(); - if (!idCert.EndReached()) - { - BERSequenceDecoder extensions(idCert); - { - while (!extensions.EndReached()) - { - m_extensionList.push_back(CertificateExtension(extensions)); - } - } - extensions.MessageEnd(); - } - } - - idCert.MessageEnd(); - } - catch (CryptoPP::BERDecodeErr&) { - BOOST_THROW_EXCEPTION(Error("Certificate Decoding Error")); - } -} - -void -Certificate::printCertificate(std::ostream& oss, const std::string& indent) const -{ - util::IndentedStream os(oss, indent); - - os << "Certificate name:\n"; - os << " " << getName() << "\n"; - os << "Validity:\n"; - { - os << " NotBefore: " << time::toIsoString(m_notBefore) << "\n"; - os << " NotAfter: " << time::toIsoString(m_notAfter) << "\n"; - } - - os << "Subject Description:\n"; - for (const auto& description : m_subjectDescriptionList) - os << " " << description.getOidString() << ": " << description.getValue() << "\n"; - - os << "Public key bits: "; - switch (m_key.getKeyType()) { - case KeyType::RSA: - os << "(RSA)"; - break; - case KeyType::EC: - os << "(ECDSA)"; - break; - default: - os << "(Unknown key type)"; - break; - } - os << "\n"; - - { - util::IndentedStream os2(os, " "); - CryptoPP::Base64Encoder encoder(new CryptoPP::FileSink(os2), true, 64); - m_key.encode(encoder); - } - - os << "Signature Information:\n"; - { - os << " Signature Type: "; - switch (getSignature().getType()) { - case tlv::SignatureTypeValue::DigestSha256: - os << "DigestSha256"; - break; - case tlv::SignatureTypeValue::SignatureSha256WithRsa: - os << "SignatureSha256WithRsa"; - break; - case tlv::SignatureTypeValue::SignatureSha256WithEcdsa: - os << "SignatureSha256WithEcdsa"; - break; - default: - os << "Unknown Signature Type"; - } - os << "\n"; - - if (getSignature().hasKeyLocator()) { - const KeyLocator& keyLocator = getSignature().getKeyLocator(); - os << " Key Locator: "; - switch (keyLocator.getType()) { - case KeyLocator::KeyLocator_Name: - { - const Name& signerName = keyLocator.getName(); - if (signerName.isPrefixOf(getName())) - os << "(Self-Signed) " << keyLocator.getName(); - else - os << "(Name) " << keyLocator.getName(); - break; - } - case KeyLocator::KeyLocator_KeyDigest: - os << "(KeyDigest)"; - break; - case KeyLocator::KeyLocator_None: - os << "None"; - break; - default: - os << "Unknown"; - } - os << "\n"; - } - } -} - -std::ostream& -operator<<(std::ostream& os, const Certificate& cert) -{ - cert.printCertificate(os); - return os; -} - -} // namespace v1 -} // namespace security -} // namespace ndn diff --git a/src/security/v1/certificate.hpp b/src/security/v1/certificate.hpp deleted file mode 100644 index f2f70bf8f..000000000 --- a/src/security/v1/certificate.hpp +++ /dev/null @@ -1,226 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - * @author Jeff Thompson - * @author Alexander Afanasyev - */ - -#ifndef NDN_SECURITY_V1_CERTIFICATE_HPP -#define NDN_SECURITY_V1_CERTIFICATE_HPP - -#include "../../common.hpp" -#include "../../data.hpp" -#include "certificate-subject-description.hpp" -#include "certificate-extension.hpp" -#include "public-key.hpp" - -namespace ndn { -namespace security { -namespace v1 { - -class Certificate : public Data -{ -public: - class Error : public Data::Error - { - public: - explicit - Error(const std::string& what) - : Data::Error(what) - { - } - }; - - typedef std::vector SubjectDescriptionList; - typedef std::vector ExtensionList; - - /** - * @brief The default constructor. - */ - Certificate(); - - /** - * @brief Create a Certificate from the content in the data packet. - * @param data The data packet with the content to decode. - */ - explicit - Certificate(const Data& data); - - /** - * @brief Create a Certificate from the a block - * @param block The raw block of the certificate - */ - explicit - Certificate(const Block& block); - - virtual - ~Certificate(); - - void - wireDecode(const Block& wire); - - /** - * @brief encode certificate info into content - */ - void - encode(); - - /** - * @brief Add a subject description. - * @param description The description to be added. - */ - void - addSubjectDescription(const CertificateSubjectDescription& description) - { - m_subjectDescriptionList.push_back(description); - } - - const SubjectDescriptionList& - getSubjectDescriptionList() const - { - return m_subjectDescriptionList; - } - - SubjectDescriptionList& - getSubjectDescriptionList() - { - return m_subjectDescriptionList; - } - - /** - * @brief Add a certificate extension. - * @param extension the extension to be added - */ - void - addExtension(const CertificateExtension& extension) - { - m_extensionList.push_back(extension); - } - - const ExtensionList& - getExtensionList() const - { - return m_extensionList; - } - - ExtensionList& - getExtensionList() - { - return m_extensionList; - } - - void - setNotBefore(const time::system_clock::TimePoint& notBefore) - { - m_notBefore = notBefore; - } - - time::system_clock::TimePoint& - getNotBefore() - { - return m_notBefore; - } - - const time::system_clock::TimePoint& - getNotBefore() const - { - return m_notBefore; - } - - void - setNotAfter(const time::system_clock::TimePoint& notAfter) - { - m_notAfter = notAfter; - } - - time::system_clock::TimePoint& - getNotAfter() - { - return m_notAfter; - } - - const time::system_clock::TimePoint& - getNotAfter() const - { - return m_notAfter; - } - - void - setPublicKeyInfo(const PublicKey& key) - { - m_key = key; - } - - PublicKey& - getPublicKeyInfo() - { - return m_key; - } - - const PublicKey& - getPublicKeyInfo() const - { - return m_key; - } - - /** - * @brief Check if the certificate is valid. - * @return True if the current time is earlier than notBefore. - */ - bool - isTooEarly(); - - /** - * @brief Check if the certificate is valid. - * @return True if the current time is later than notAfter. - */ - bool - isTooLate(); - - void - printCertificate(std::ostream& os, const std::string& indent = "") const; - -protected: - void - decode(); - -protected: - SubjectDescriptionList m_subjectDescriptionList; - time::system_clock::TimePoint m_notBefore; - time::system_clock::TimePoint m_notAfter; - PublicKey m_key; - ExtensionList m_extensionList; -}; - -std::ostream& -operator<<(std::ostream& os, const Certificate& cert); - -} // namespace v1 -} // namespace security - -#ifdef NDN_CXX_KEEP_SECURITY_V1_ALIASES -/// @deprecated When needed, use explicit namespace -using security::v1::Certificate; -#endif // NDN_CXX_KEEP_SECURITY_V1_ALIASES - -} // namespace ndn - -#endif // NDN_SECURITY_V1_CERTIFICATE_HPP diff --git a/src/security/v1/cryptopp.hpp b/src/security/v1/cryptopp.hpp deleted file mode 100644 index 4de66bb56..000000000 --- a/src/security/v1/cryptopp.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_V1_CRYPTOPP_HPP -#define NDN_SECURITY_V1_CRYPTOPP_HPP - -// suppress CryptoPP warnings -#pragma GCC system_header -#pragma clang system_header - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif // NDN_SECURITY_V1_CRYPTOPP_HPP diff --git a/src/security/v1/identity-certificate.cpp b/src/security/v1/identity-certificate.cpp deleted file mode 100644 index ea8a94687..000000000 --- a/src/security/v1/identity-certificate.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "identity-certificate.hpp" -#include "../../util/concepts.hpp" - -namespace ndn { -namespace security { -namespace v1 { - -using std::string; - -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "IdentityCertificate::Error must inherit from Certificate::Error"); - -IdentityCertificate::IdentityCertificate() -{ - this->setFreshnessPeriod(time::hours(1)); -} - -IdentityCertificate::IdentityCertificate(const Data& data) - : Certificate(data) -{ - setPublicKeyName(); -} - -IdentityCertificate::IdentityCertificate(const Block& block) - : Certificate(block) -{ - setPublicKeyName(); -} - -void -IdentityCertificate::wireDecode(const Block& wire) -{ - Certificate::wireDecode(wire); - setPublicKeyName(); -} - -void -IdentityCertificate::setName(const Name& name) -{ - Certificate::setName(name); - setPublicKeyName(); -} - -bool -IdentityCertificate::isCorrectName(const Name& name) -{ - string idString("ID-CERT"); - ssize_t i = name.size() - 1; - for (; i >= 0; i--) { - if (name.get(i).toUri() == idString) - break; - } - - if (i < 0) - return false; - - string keyString("KEY"); - size_t keyIndex = 0; - for (; keyIndex < name.size(); keyIndex++) { - if (name.get(keyIndex).toUri() == keyString) - break; - } - - if (keyIndex >= name.size()) - return false; - - return true; -} - -void -IdentityCertificate::setPublicKeyName() -{ - if (!isCorrectName(getName())) - BOOST_THROW_EXCEPTION(Error("Wrong Identity Certificate Name")); - - m_publicKeyName = certificateNameToPublicKeyName(getName()); -} - -bool -IdentityCertificate::isIdentityCertificate(const Certificate& certificate) -{ - return dynamic_cast(&certificate); -} - -Name -IdentityCertificate::certificateNameToPublicKeyName(const Name& certificateName) -{ - string idString("ID-CERT"); - bool foundIdString = false; - size_t idCertComponentIndex = certificateName.size() - 1; - for (; idCertComponentIndex + 1 > 0; --idCertComponentIndex) { - if (certificateName.get(idCertComponentIndex).toUri() == idString) - { - foundIdString = true; - break; - } - } - - if (!foundIdString) - BOOST_THROW_EXCEPTION(Error("Incorrect identity certificate name " + certificateName.toUri())); - - Name tmpName = certificateName.getSubName(0, idCertComponentIndex); - string keyString("KEY"); - bool foundKeyString = false; - size_t keyComponentIndex = 0; - for (; keyComponentIndex < tmpName.size(); keyComponentIndex++) { - if (tmpName.get(keyComponentIndex).toUri() == keyString) - { - foundKeyString = true; - break; - } - } - - if (!foundKeyString) - BOOST_THROW_EXCEPTION(Error("Incorrect identity certificate name " + certificateName.toUri())); - - return tmpName - .getSubName(0, keyComponentIndex) - .append(tmpName.getSubName(keyComponentIndex + 1, - tmpName.size() - keyComponentIndex - 1)); -} - -} // namespace v1 -} // namespace security -} // namespace ndn diff --git a/src/security/v1/identity-certificate.hpp b/src/security/v1/identity-certificate.hpp deleted file mode 100644 index 7ea4fe459..000000000 --- a/src/security/v1/identity-certificate.hpp +++ /dev/null @@ -1,110 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_SECURITY_V1_IDENTITY_CERTIFICATE_HPP -#define NDN_SECURITY_V1_IDENTITY_CERTIFICATE_HPP - -#include "../../common.hpp" -#include "certificate.hpp" - -namespace ndn { -namespace security { -namespace v1 { - -class IdentityCertificate : public Certificate -{ -public: - class Error : public Certificate::Error - { - public: - explicit - Error(const std::string& what) - : Certificate::Error(what) - { - } - }; - - /** - * @brief The default constructor. - */ - IdentityCertificate(); - - /** - * @brief Create an IdentityCertificate from the content in the data packet. - * @param data The data packet with the content to decode. - */ - explicit - IdentityCertificate(const Data& data); - - /** - * @brief Create an IdentityCertificate from a block. - * @param block The raw block of the certificate. - */ - explicit - IdentityCertificate(const Block& block); - - void - wireDecode(const Block& wire); - - void - setName(const Name& name); - - const Name& - getPublicKeyName() const - { - return m_publicKeyName; - } - - static bool - isIdentityCertificate(const Certificate& certificate); - - /** - * @brief Get the public key name from the full certificate name. - * @param certificateName The full certificate name. - * @return The related public key name. - */ - static Name - certificateNameToPublicKeyName(const Name& certificateName); - -private: - static bool - isCorrectName(const Name& name); - - void - setPublicKeyName(); - -protected: - Name m_publicKeyName; -}; - -} // namespace v1 -} // namespace security - -#ifdef NDN_CXX_KEEP_SECURITY_V1_ALIASES -/// @deprecated When needed, use explicit namespace -using security::v1::IdentityCertificate; -#endif // NDN_CXX_KEEP_SECURITY_V1_ALIASES - -} // namespace ndn - -#endif // NDN_SECURITY_V1_IDENTITY_CERTIFICATE_HPP diff --git a/src/security/v1/public-key.cpp b/src/security/v1/public-key.cpp deleted file mode 100644 index 2721dee7e..000000000 --- a/src/security/v1/public-key.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - * @author Alexander Afanasyev - */ - -#include "public-key.hpp" - -#include "../../encoding/oid.hpp" -#include "../../util/crypto.hpp" -#include "cryptopp.hpp" - -namespace ndn { -namespace security { -namespace v1 { - -PublicKey::PublicKey() - : m_type(KeyType::NONE) -{ -} - -PublicKey::PublicKey(const uint8_t* keyDerBuf, size_t keyDerSize) - : m_type(KeyType::NONE) -{ - CryptoPP::StringSource src(keyDerBuf, keyDerSize, true); - decode(src); -} - -const Block& -PublicKey::computeDigest() const -{ - if (m_key.empty()) - BOOST_THROW_EXCEPTION(Error("Public key is empty")); - - if (m_digest.hasWire()) - return m_digest; - else { - m_digest = Block(tlv::KeyDigest, crypto::computeSha256Digest(m_key.buf(), m_key.size())); - m_digest.encode(); - return m_digest; - } -} - - -void -PublicKey::encode(CryptoPP::BufferedTransformation& out) const -{ - // SubjectPublicKeyInfo ::= SEQUENCE { - // algorithm AlgorithmIdentifier - // keybits BIT STRING } - - out.Put(m_key.buf(), m_key.size()); -} - -void -PublicKey::decode(CryptoPP::BufferedTransformation& in) -{ - // SubjectPublicKeyInfo ::= SEQUENCE { - // algorithm AlgorithmIdentifier - // keybits BIT STRING } - - using namespace CryptoPP; - try - { - std::string out; - StringSink sink(out); - - //////////////////////// - // part 1: copy as is // - //////////////////////// - BERSequenceDecoder decoder(in); - { - assert(decoder.IsDefiniteLength()); - - DERSequenceEncoder encoder(sink); - decoder.TransferTo(encoder, decoder.RemainingLength()); - encoder.MessageEnd(); - } - decoder.MessageEnd(); - - //////////////////////// - // part 2: check if the key is RSA (since it is the only supported for now) - //////////////////////// - StringSource checkedSource(out, true); - BERSequenceDecoder subjectPublicKeyInfo(checkedSource); - { - BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo); - { - Oid algorithm; - algorithm.decode(algorithmInfo); - - if (algorithm == oid::RSA) - m_type = KeyType::RSA; - else if (algorithm == oid::ECDSA) - m_type = KeyType::EC; - else - BOOST_THROW_EXCEPTION(Error("Only RSA/ECDSA public keys are supported for now (" + - algorithm.toString() + " requested)")); - } - } - - m_key.assign(out.begin(), out.end()); - } - catch (CryptoPP::BERDecodeErr& err) - { - m_type = KeyType::NONE; - BOOST_THROW_EXCEPTION(Error("PublicKey decoding error")); - } - - m_digest.reset(); -} - -// Blob -// PublicKey::getDigest(DigestAlgorithm digestAlgorithm) const -// { -// if (digestAlgorithm == DigestAlgorithm::SHA256) { -// uint8_t digest[SHA256_DIGEST_LENGTH]; -// ndn_digestSha256(keyDer_.buf(), keyDer_.size(), digest); - -// return Blob(digest, sizeof(digest)); -// } -// else -// throw UnrecognizedDigestAlgorithmException("Wrong format!"); -// } - -std::ostream& -operator<<(std::ostream& os, const PublicKey& key) -{ - CryptoPP::StringSource(key.get().buf(), key.get().size(), true, - new CryptoPP::Base64Encoder(new CryptoPP::FileSink(os), true, 64)); - - return os; -} - -} // namespace v1 -} // namespace security -} // namespace ndn diff --git a/src/security/v1/public-key.hpp b/src/security/v1/public-key.hpp deleted file mode 100644 index 6b67535c4..000000000 --- a/src/security/v1/public-key.hpp +++ /dev/null @@ -1,133 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - * @author Alexander Afanasyev - * @author Jeff Thompson - */ - -#ifndef NDN_SECURITY_V1_PUBLIC_KEY_HPP -#define NDN_SECURITY_V1_PUBLIC_KEY_HPP - -#include "../../common.hpp" - -#include "../../encoding/buffer.hpp" -#include "../../encoding/block.hpp" -#include "../security-common.hpp" - -namespace CryptoPP { -class BufferedTransformation; -} // namespace CryptoPP - -namespace ndn { -namespace security { -namespace v1 { - -class PublicKey -{ -public: - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - - /** - * The default constructor. - */ - PublicKey(); - - /** - * @brief Create a new PublicKey from @p keyDerBuf in DER buffer - * - * @param keyDerBuf The pointer to the first byte of buffer containing DER of public key - * @param keyDerSize Size of the buffer - * - * @throws PublicKey::Error If DER in buffer cannot be decoded - */ - PublicKey(const uint8_t* keyDerBuf, size_t keyDerSize); - - const Buffer& - get() const - { - return m_key; - } - - void - set(const uint8_t* keyDerBuf, size_t keyDerSize) - { - Buffer buf(keyDerBuf, keyDerSize); - m_key.swap(buf); - } - - KeyType - getKeyType() const - { - return m_type; - } - - /** - * @return a KeyDigest block that matches this public key - */ - const Block& - computeDigest() const; - - void - encode(CryptoPP::BufferedTransformation& out) const; - - void - decode(CryptoPP::BufferedTransformation& in); - - bool - operator==(const PublicKey& key) const - { - return m_key == key.m_key; - } - - bool - operator!=(const PublicKey& key) const - { - return m_key != key.m_key; - } - -private: - KeyType m_type; - Buffer m_key; - mutable Block m_digest; -}; - -std::ostream& -operator<<(std::ostream& os, const PublicKey& key); - -} // namespace v1 -} // namespace security - -#ifdef NDN_CXX_KEEP_SECURITY_V1_ALIASES -/// @deprecated When needed, use explicit namespace -using security::v1::PublicKey; -#endif // NDN_CXX_KEEP_SECURITY_V1_ALIASES - -} // namespace ndn - -#endif // NDN_SECURITY_V1_PUBLIC_KEY_HPP diff --git a/src/security/v2/additional-description.cpp b/src/security/v2/additional-description.cpp deleted file mode 100644 index 6fdfd53ce..000000000 --- a/src/security/v2/additional-description.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "additional-description.hpp" -#include "../../util/concepts.hpp" -#include "../../encoding/block-helpers.hpp" - -namespace ndn { -namespace security { -namespace v2 { - -BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "AdditionalDescription::Error must inherit from tlv::Error"); - -static const size_t KEY_OFFSET = 0; -static const size_t VALUE_OFFSET = 1; - -AdditionalDescription::AdditionalDescription(const Block& block) -{ - wireDecode(block); -} - -const std::string& -AdditionalDescription::get(const std::string& key) const -{ - auto it = m_info.find(key); - if (it == m_info.end()) - BOOST_THROW_EXCEPTION(Error("Entry does not exist for key (" + key + ")")); - - return it->second; -} - -void -AdditionalDescription::set(const std::string& key, const std::string& value) -{ - m_info[key] = value; -} - -bool -AdditionalDescription::has(const std::string& key) const -{ - return (m_info.find(key) != m_info.end()); -} - -AdditionalDescription::iterator -AdditionalDescription::begin() -{ - return m_info.begin(); -} - -AdditionalDescription::iterator -AdditionalDescription::end() -{ - return m_info.end(); -} - -AdditionalDescription::const_iterator -AdditionalDescription::begin() const -{ - return m_info.begin(); -} - -AdditionalDescription::const_iterator -AdditionalDescription::end() const -{ - return m_info.end(); -} - -template -size_t -AdditionalDescription::wireEncode(EncodingImpl& encoder) const -{ - size_t totalLength = 0; - - for (auto it = m_info.rbegin(); it != m_info.rend(); it++) { - size_t entryLength = 0; - entryLength += prependStringBlock(encoder, tlv::DescriptionValue, it->second); - entryLength += prependStringBlock(encoder, tlv::DescriptionKey, it->first); - entryLength += encoder.prependVarNumber(entryLength); - entryLength += encoder.prependVarNumber(tlv::DescriptionEntry); - - totalLength += entryLength; - } - - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::AdditionalDescription); - return totalLength; -} - -template size_t -AdditionalDescription::wireEncode(EncodingImpl& encoder) const; - -template size_t -AdditionalDescription::wireEncode(EncodingImpl& encoder) const; - -const Block& -AdditionalDescription::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(); - m_wire.parse(); - - return m_wire; -} - -void -AdditionalDescription::wireDecode(const Block& wire) -{ - if (!wire.hasWire()) { - BOOST_THROW_EXCEPTION(Error("The supplied block does not contain wire format")); - } - - m_wire = wire; - m_wire.parse(); - - if (m_wire.type() != tlv::AdditionalDescription) - BOOST_THROW_EXCEPTION(Error("Unexpected TLV type when decoding AdditionalDescription")); - - Block::element_const_iterator it = m_wire.elements_begin(); - while (it != m_wire.elements_end()) { - const Block& entry = *it; - entry.parse(); - - if (entry.type() != tlv::DescriptionEntry) - BOOST_THROW_EXCEPTION(Error("Unexpected TLV type when decoding DescriptionEntry")); - - if (entry.elements_size() != 2) - BOOST_THROW_EXCEPTION(Error("DescriptionEntry does not have two sub-TLVs")); - - if (entry.elements()[KEY_OFFSET].type() != tlv::DescriptionKey || - entry.elements()[VALUE_OFFSET].type() != tlv::DescriptionValue) - BOOST_THROW_EXCEPTION(Error("Invalid DescriptionKey or DescriptionValue field")); - - m_info[readString(entry.elements()[KEY_OFFSET])] = readString(entry.elements()[VALUE_OFFSET]); - it++; - } -} - -bool -AdditionalDescription::operator==(const AdditionalDescription& other) const -{ - return (m_info == other.m_info); -} - -bool -AdditionalDescription::operator!=(const AdditionalDescription& other) const -{ - return !(*this == other); -} - -std::ostream& -operator<<(std::ostream& os, const AdditionalDescription& other) -{ - size_t count = 0; - os << "("; - for (const auto& entry : other) { - if (count > 0) - os << ", "; - os << "(" << entry.first << ":" << entry.second << ")"; - count++; - } - os << ")"; - - return os; -} - -} // namespace v2 -} // namespace security -} // namespace ndn diff --git a/src/security/v2/additional-description.hpp b/src/security/v2/additional-description.hpp deleted file mode 100644 index d5142ae61..000000000 --- a/src/security/v2/additional-description.hpp +++ /dev/null @@ -1,136 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SECURITY_V2_ADDITIONAL_DESCRIPTION_HPP -#define NDN_SECURITY_V2_ADDITIONAL_DESCRIPTION_HPP - -#include "../../common.hpp" -#include "../../encoding/tlv.hpp" -#include "../../encoding/block.hpp" -#include - -namespace ndn { -namespace security { -namespace v2 { - -/** - * @brief Abstraction of AdditionalDescription - * @sa docs/tutorials/certificate-format.rst - */ -class AdditionalDescription -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - - typedef std::map::iterator iterator; - typedef std::map::const_iterator const_iterator; - -public: - - /** - * @brief Create an empty AdditionalDescription - */ - AdditionalDescription() = default; - - /** - * @brief Create AdditionalDescription from @p block - */ - explicit - AdditionalDescription(const Block& block); - - const std::string& - get(const std::string& key) const; - - void - set(const std::string& key, const std::string& value); - - bool - has(const std::string& key) const; - - size_t - size() const - { - return m_info.size(); - } - - iterator - begin(); - - iterator - end(); - - const_iterator - begin() const; - - const_iterator - end() const; - - /** @brief Fast encoding or block size estimation - */ - template - size_t - wireEncode(EncodingImpl& encoder) const; - - /** @brief Encode ValidityPeriod into TLV block - */ - const Block& - wireEncode() const; - - /** @brief Decode ValidityPeriod from TLV block - * @throw Error when an invalid TLV block supplied - */ - void - wireDecode(const Block& wire); - -public: // EqualityComparable concept - - bool - operator==(const AdditionalDescription& other) const; - - bool - operator!=(const AdditionalDescription& other) const; - -private: - - std::map m_info; - - mutable Block m_wire; -}; - -std::ostream& -operator<<(std::ostream& os, const AdditionalDescription& period); - -} // namespace v2 - -using v2::AdditionalDescription; - -} // namespace security -} // namespace ndn - -#endif // NDN_SECURITY_V2_ADDITIONAL_DESCRIPTION_HPP diff --git a/src/security/validation-request.hpp b/src/security/validation-request.hpp deleted file mode 100644 index 000f61b15..000000000 --- a/src/security/validation-request.hpp +++ /dev/null @@ -1,97 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_SECURITY_VALIDATION_REQUEST_HPP -#define NDN_SECURITY_VALIDATION_REQUEST_HPP - -#include "../interest.hpp" - -namespace ndn { -namespace security { - -/// @brief Callback to report a successful Interest validation. -typedef function&)> OnInterestValidated; - -/// @brief Callback to report a failed Interest validation. -typedef function&, - const std::string&)> OnInterestValidationFailed; - -/// @brief Callback to report a successful Data validation. -typedef function&)> OnDataValidated; - -/// @brief Callback to report a failed Data validation. -typedef function&, - const std::string&)> OnDataValidationFailed; - -/** - * @brief ValidationRequest contains information related to further validation. - * - * During a validation process, validator may not have retrieved the corresponding public - * key of the signature in a packet. ValidationRequest contains the interest for the - * certificate that carries the public key and also contains the context for the certificate - * including how to proceed when the public key is authenticated or not, the number of - * validation steps that have been performed, and how to handle interest timeout. - */ -class ValidationRequest -{ -public: - ValidationRequest(const Interest& interest, - const OnDataValidated& onDataValidated, - const OnDataValidationFailed& onDataValidationFailed, - int nRetries, int nSteps) - : m_interest(interest) - , m_onDataValidated(onDataValidated) - , m_onDataValidationFailed(onDataValidationFailed) - , m_nRetries(nRetries) - , m_nSteps(nSteps) - { - } - - virtual - ~ValidationRequest() - { - } - - /// @brief the Interest for the requested data/certificate. - Interest m_interest; - /// @brief callback when the retrieved certificate is authenticated. - OnDataValidated m_onDataValidated; - /// @brief callback when the retrieved certificate cannot be authenticated. - OnDataValidationFailed m_onDataValidationFailed; - /// @brief the number of retries when the interest times out. - int m_nRetries; - /// @brief the number of validation steps that have been performed. - int m_nSteps; -}; - -} // namespace security - -using security::ValidationRequest; -using security::OnInterestValidated; -using security::OnInterestValidationFailed; -using security::OnDataValidated; -using security::OnDataValidationFailed; - -} // namespace ndn - -#endif //NDN_SECURITY_VALIDATION_REQUEST_HPP diff --git a/src/security/validator-config.cpp b/src/security/validator-config.cpp deleted file mode 100644 index 13bcc7306..000000000 --- a/src/security/validator-config.cpp +++ /dev/null @@ -1,786 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - * @author Zhiyi Zhang - */ - -#include "validator-config.hpp" -#include "certificate-cache-ttl.hpp" -#include "../util/io.hpp" - -#include -#include -#include - -namespace ndn { -namespace security { - -const shared_ptr ValidatorConfig::DEFAULT_CERTIFICATE_CACHE; -const time::milliseconds ValidatorConfig::DEFAULT_GRACE_INTERVAL(3000); -const time::system_clock::Duration ValidatorConfig::DEFAULT_KEY_TIMESTAMP_TTL = time::hours(1); - -ValidatorConfig::ValidatorConfig(Face* face, - const shared_ptr& certificateCache, - const time::milliseconds& graceInterval, - const size_t stepLimit, - const size_t maxTrackedKeys, - const time::system_clock::Duration& keyTimestampTtl) - : Validator(face) - , m_shouldValidate(true) - , m_stepLimit(stepLimit) - , m_certificateCache(certificateCache) - , m_graceInterval(graceInterval < time::milliseconds::zero() ? - DEFAULT_GRACE_INTERVAL : graceInterval) - , m_maxTrackedKeys(maxTrackedKeys) - , m_keyTimestampTtl(keyTimestampTtl) -{ - if (m_certificateCache == nullptr && face != nullptr) - m_certificateCache = make_shared(ref(face->getIoService())); -} - -ValidatorConfig::ValidatorConfig(Face& face, - const shared_ptr& certificateCache, - const time::milliseconds& graceInterval, - const size_t stepLimit, - const size_t maxTrackedKeys, - const time::system_clock::Duration& keyTimestampTtl) - : Validator(face) - , m_shouldValidate(true) - , m_stepLimit(stepLimit) - , m_certificateCache(certificateCache) - , m_graceInterval(graceInterval < time::milliseconds::zero() ? - DEFAULT_GRACE_INTERVAL : graceInterval) - , m_maxTrackedKeys(maxTrackedKeys) - , m_keyTimestampTtl(keyTimestampTtl) -{ - if (m_certificateCache == nullptr) - m_certificateCache = make_shared(ref(face.getIoService())); -} - -void -ValidatorConfig::load(const std::string& filename) -{ - std::ifstream inputFile; - inputFile.open(filename.c_str()); - if (!inputFile.good() || !inputFile.is_open()) { - std::string msg = "Failed to read configuration file: "; - msg += filename; - BOOST_THROW_EXCEPTION(security::conf::Error(msg)); - } - load(inputFile, filename); - inputFile.close(); -} - -void -ValidatorConfig::load(const std::string& input, const std::string& filename) -{ - std::istringstream inputStream(input); - load(inputStream, filename); -} - - -void -ValidatorConfig::load(std::istream& input, const std::string& filename) -{ - security::conf::ConfigSection tree; - try { - boost::property_tree::read_info(input, tree); - } - catch (const boost::property_tree::info_parser_error& error) { - std::stringstream msg; - msg << "Failed to parse configuration file"; - msg << " " << filename; - msg << " " << error.message() << " line " << error.line(); - BOOST_THROW_EXCEPTION(security::conf::Error(msg.str())); - } - - load(tree, filename); -} - -void -ValidatorConfig::load(const security::conf::ConfigSection& configSection, - const std::string& filename) -{ - BOOST_ASSERT(!filename.empty()); - - reset(); - - if (configSection.begin() == configSection.end()) { - std::string msg = "Error processing configuration file"; - msg += ": "; - msg += filename; - msg += " no data"; - BOOST_THROW_EXCEPTION(security::conf::Error(msg)); - } - - for (security::conf::ConfigSection::const_iterator i = configSection.begin(); - i != configSection.end(); ++i) { - const std::string& sectionName = i->first; - const security::conf::ConfigSection& section = i->second; - - if (boost::iequals(sectionName, "rule")) { - onConfigRule(section, filename); - } - else if (boost::iequals(sectionName, "trust-anchor")) { - onConfigTrustAnchor(section, filename); - } - else { - std::string msg = "Error processing configuration file"; - msg += " "; - msg += filename; - msg += " unrecognized section: " + sectionName; - BOOST_THROW_EXCEPTION(security::conf::Error(msg)); - } - } -} - -void -ValidatorConfig::onConfigRule(const security::conf::ConfigSection& configSection, - const std::string& filename) -{ - using namespace ndn::security::conf; - - ConfigSection::const_iterator propertyIt = configSection.begin(); - - // Get rule.id - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "id")) - BOOST_THROW_EXCEPTION(Error("Expect !")); - - std::string ruleId = propertyIt->second.data(); - propertyIt++; - - // Get rule.for - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first,"for")) - BOOST_THROW_EXCEPTION(Error("Expect in rule: " + ruleId + "!")); - - std::string usage = propertyIt->second.data(); - propertyIt++; - - bool isForData = false; - if (boost::iequals(usage, "data")) - isForData = true; - else if (boost::iequals(usage, "interest")) - isForData = false; - else - BOOST_THROW_EXCEPTION(Error("Unrecognized : " + usage - + " in rule: " + ruleId)); - - // Get rule.filter(s) - std::vector> filters; - for (; propertyIt != configSection.end(); propertyIt++) { - if (!boost::iequals(propertyIt->first, "filter")) { - if (boost::iequals(propertyIt->first, "checker")) - break; - BOOST_THROW_EXCEPTION(Error("Expect in rule: " + ruleId)); - } - - filters.push_back(FilterFactory::create(propertyIt->second)); - continue; - } - - // Get rule.checker(s) - std::vector> checkers; - for (; propertyIt != configSection.end(); propertyIt++) { - if (!boost::iequals(propertyIt->first, "checker")) - BOOST_THROW_EXCEPTION(Error("Expect in rule: " + ruleId)); - - checkers.push_back(CheckerFactory::create(propertyIt->second, filename)); - continue; - } - - // Check other stuff - if (propertyIt != configSection.end()) - BOOST_THROW_EXCEPTION(Error("Expect the end of rule: " + ruleId)); - - if (checkers.empty()) - BOOST_THROW_EXCEPTION(Error("No is specified in rule: " + ruleId)); - - if (isForData) { - shared_ptr rule = make_shared(ruleId); - for (const auto& filter : filters) - rule->addFilter(filter); - for (const auto& checker : checkers) - rule->addChecker(checker); - - m_dataRules.push_back(rule); - } - else { - shared_ptr rule = make_shared(ruleId);; - for (const auto& filter : filters) - rule->addFilter(filter); - for (const auto& checker : checkers) - rule->addChecker(checker); - - m_interestRules.push_back(rule); - } -} - -void -ValidatorConfig::onConfigTrustAnchor(const security::conf::ConfigSection& configSection, - const std::string& filename) -{ - using namespace ndn::security::conf; - using namespace boost::filesystem; - - ConfigSection::const_iterator propertyIt = configSection.begin(); - - // Get trust-anchor.type - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "type")) - BOOST_THROW_EXCEPTION(Error("Expect !")); - - std::string type = propertyIt->second.data(); - propertyIt++; - - if (boost::iequals(type, "file")) { - // Get trust-anchor.file - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "file-name")) - BOOST_THROW_EXCEPTION(Error("Expect !")); - - std::string file = propertyIt->second.data(); - propertyIt++; - - // Check other stuff - if (propertyIt != configSection.end()) - BOOST_THROW_EXCEPTION(Error("Expect the end of trust-anchor!")); - - path certfilePath = absolute(file, path(filename).parent_path()); - auto idCert = io::load(certfilePath.string()); - - if (idCert != nullptr) { - BOOST_ASSERT(idCert->getName().size() >= 1); - m_staticContainer.add(idCert); - m_anchors[idCert->getName().getPrefix(-1)] = idCert; - } - else - BOOST_THROW_EXCEPTION(Error("Cannot read certificate from file: " + certfilePath.native())); - - return; - } - else if (boost::iequals(type, "base64")) { - // Get trust-anchor.base64-string - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "base64-string")) - BOOST_THROW_EXCEPTION(Error("Expect !")); - - std::stringstream ss(propertyIt->second.data()); - propertyIt++; - - // Check other stuff - if (propertyIt != configSection.end()) - BOOST_THROW_EXCEPTION(Error("Expect the end of trust-anchor!")); - - auto idCert = io::load(ss); - - if (idCert != nullptr) { - BOOST_ASSERT(idCert->getName().size() >= 1); - m_staticContainer.add(idCert); - m_anchors[idCert->getName().getPrefix(-1)] = idCert; - } - else - BOOST_THROW_EXCEPTION(Error("Cannot decode certificate from base64-string")); - - return; - } - else if (boost::iequals(type, "dir")) { - if (propertyIt == configSection.end() || !boost::iequals(propertyIt->first, "dir")) - BOOST_THROW_EXCEPTION(Error("Expect ")); - - std::string dirString(propertyIt->second.data()); - propertyIt++; - - if (propertyIt != configSection.end()) { - if (boost::iequals(propertyIt->first, "refresh")) { - using namespace boost::filesystem; - - time::nanoseconds refresh = getRefreshPeriod(propertyIt->second.data()); - propertyIt++; - - if (propertyIt != configSection.end()) - BOOST_THROW_EXCEPTION(Error("Expect the end of trust-anchor")); - - path dirPath = absolute(dirString, path(filename).parent_path()); - - m_dynamicContainers.push_back(DynamicTrustAnchorContainer(dirPath, true, refresh)); - - m_dynamicContainers.rbegin()->setLastRefresh(time::system_clock::now() - refresh); - - return; - } - else - BOOST_THROW_EXCEPTION(Error("Expect !")); - } - else { - using namespace boost::filesystem; - - path dirPath = absolute(dirString, path(filename).parent_path()); - - directory_iterator end; - - for (directory_iterator it(dirPath); it != end; it++) { - auto idCert = io::load(it->path().string()); - - if (idCert != nullptr) - m_staticContainer.add(idCert); - } - - return; - } - } - else if (boost::iequals(type, "any")) { - m_shouldValidate = false; - } - else - BOOST_THROW_EXCEPTION(Error("Unsupported trust-anchor.type: " + type)); -} - -void -ValidatorConfig::reset() -{ - if (m_certificateCache != nullptr) - m_certificateCache->reset(); - m_interestRules.clear(); - m_dataRules.clear(); - - m_anchors.clear(); - - m_staticContainer = TrustAnchorContainer(); - - m_dynamicContainers.clear(); -} - -bool -ValidatorConfig::isEmpty() -{ - return ((m_certificateCache == nullptr || m_certificateCache->isEmpty()) && - m_interestRules.empty() && m_dataRules.empty() && m_anchors.empty()); -} - -time::nanoseconds -ValidatorConfig::getRefreshPeriod(std::string inputString) -{ - char unit = inputString[inputString.size() - 1]; - std::string refreshString = inputString.substr(0, inputString.size() - 1); - - uint32_t refreshPeriod = 0; - - try { - refreshPeriod = boost::lexical_cast(refreshString); - } - catch (const boost::bad_lexical_cast&) { - BOOST_THROW_EXCEPTION(Error("Bad number: " + refreshString)); - } - - if (refreshPeriod == 0) - return getDefaultRefreshPeriod(); - - switch (unit) { - case 'h': - return time::duration_cast(time::hours(refreshPeriod)); - case 'm': - return time::duration_cast(time::minutes(refreshPeriod)); - case 's': - return time::duration_cast(time::seconds(refreshPeriod)); - default: - BOOST_THROW_EXCEPTION(Error(std::string("Wrong time unit: ") + unit)); - } -} - -time::nanoseconds -ValidatorConfig::getDefaultRefreshPeriod() -{ - return time::duration_cast(time::seconds(3600)); -} - -void -ValidatorConfig::refreshAnchors() -{ - time::system_clock::TimePoint now = time::system_clock::now(); - - bool isRefreshed = false; - - for (auto cIt = m_dynamicContainers.begin(); - cIt != m_dynamicContainers.end() && cIt->getLastRefresh() + cIt->getRefreshPeriod() < now; - cIt++) { - isRefreshed = true; - cIt->refresh(); - cIt->setLastRefresh(now); - } - - if (isRefreshed) { - m_anchors.clear(); - - for (const auto& cert : m_staticContainer.getAll()) { - m_anchors[cert->getName().getPrefix(-1)] = cert; - } - - for (const auto& container : m_dynamicContainers) { - const CertificateList& certList = container.getAll(); - - for (const auto& cert :certList) { - m_anchors[cert->getName().getPrefix(-1)] = cert; - } - } - m_dynamicContainers.sort(ValidatorConfig::compareDynamicContainer); - } -} - -void -ValidatorConfig::checkPolicy(const Data& data, - int nSteps, - const OnDataValidated& onValidated, - const OnDataValidationFailed& onValidationFailed, - std::vector>& nextSteps) -{ - if (!m_shouldValidate) - return onValidated(data.shared_from_this()); - - bool isMatched = false; - int8_t checkResult = -1; - - for (const auto& dataRule : m_dataRules) { - if (dataRule->match(data)) { - isMatched = true; - checkResult = dataRule->check(data, onValidated, onValidationFailed); - break; - } - } - - if (!isMatched) - return onValidationFailed(data.shared_from_this(), "No rule matched!"); - - if (checkResult == 0) { - const Signature& signature = data.getSignature(); - checkSignature(data, signature, nSteps, - onValidated, onValidationFailed, nextSteps); - } -} - -void -ValidatorConfig::checkPolicy(const Interest& interest, - int nSteps, - const OnInterestValidated& onValidated, - const OnInterestValidationFailed& onValidationFailed, - std::vector>& nextSteps) -{ - if (!m_shouldValidate) - return onValidated(interest.shared_from_this()); - - // If interestName has less than 4 name components, - // it is definitely not a signed interest. - if (interest.getName().size() < signed_interest::MIN_LENGTH) - return onValidationFailed(interest.shared_from_this(), - "Interest is not signed: " + interest.getName().toUri()); - - try { - const Name& interestName = interest.getName(); - Signature signature(interestName[signed_interest::POS_SIG_INFO].blockFromValue(), - interestName[signed_interest::POS_SIG_VALUE].blockFromValue()); - - 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"); - - Name keyName = v1::IdentityCertificate::certificateNameToPublicKeyName(keyLocator.getName()); - - bool isMatched = false; - int8_t checkResult = -1; - - for (const auto& interestRule : m_interestRules) { - if (interestRule->match(interest)) { - isMatched = true; - checkResult = interestRule->check(interest, - bind(&ValidatorConfig::checkTimestamp, this, _1, - keyName, onValidated, onValidationFailed), - onValidationFailed); - break; - } - } - - if (!isMatched) - return onValidationFailed(interest.shared_from_this(), "No rule matched!"); - - if (checkResult == 0) { - checkSignature - (interest, signature, nSteps, - bind(&ValidatorConfig::checkTimestamp, this, _1, - keyName, onValidated, onValidationFailed), - onValidationFailed, - nextSteps); - } - } - catch (const Signature::Error& e) { - return onValidationFailed(interest.shared_from_this(), "No valid signature"); - } - catch (const KeyLocator::Error& e){ - return onValidationFailed(interest.shared_from_this(), "No valid KeyLocator"); - } - catch (const v1::IdentityCertificate::Error& e){ - return onValidationFailed(interest.shared_from_this(), "Cannot determine the signing key"); - } - catch (const tlv::Error& e){ - return onValidationFailed(interest.shared_from_this(), "Cannot decode signature"); - } -} - -void -ValidatorConfig::checkTimestamp(const shared_ptr& interest, - const Name& keyName, - const OnInterestValidated& onValidated, - const OnInterestValidationFailed& onValidationFailed) -{ - const Name& interestName = interest->getName(); - time::system_clock::TimePoint interestTime; - - try { - interestTime = - time::fromUnixTimestamp(time::milliseconds(interestName.get(-signed_interest::MIN_LENGTH).toNumber())); - } - catch (const tlv::Error& e) { - return onValidationFailed(interest, - "Cannot decode signature related TLVs"); - } - - time::system_clock::TimePoint currentTime = time::system_clock::now(); - - LastTimestampMap::iterator timestampIt = m_lastTimestamp.find(keyName); - if (timestampIt == m_lastTimestamp.end()) { - if (!(currentTime - m_graceInterval <= interestTime && - interestTime <= currentTime + m_graceInterval)) - return onValidationFailed(interest, - "The command is not in grace interval: " + interest->getName().toUri()); - } - else { - if (interestTime <= timestampIt->second) - return onValidationFailed(interest, - "The command is outdated: " + interest->getName().toUri()); - } - - // Update timestamp - if (timestampIt == m_lastTimestamp.end()) { - cleanOldKeys(); - m_lastTimestamp[keyName] = interestTime; - } - else { - timestampIt->second = interestTime; - } - - return onValidated(interest); -} - -void -ValidatorConfig::cleanOldKeys() -{ - if (m_lastTimestamp.size() < m_maxTrackedKeys) - return; - - LastTimestampMap::iterator timestampIt = m_lastTimestamp.begin(); - LastTimestampMap::iterator end = m_lastTimestamp.end(); - - time::system_clock::TimePoint now = time::system_clock::now(); - LastTimestampMap::iterator oldestKeyIt = m_lastTimestamp.begin(); - time::system_clock::TimePoint oldestTimestamp = oldestKeyIt->second; - - while (timestampIt != end) { - if (now - timestampIt->second > m_keyTimestampTtl) { - LastTimestampMap::iterator toDelete = timestampIt; - timestampIt++; - m_lastTimestamp.erase(toDelete); - continue; - } - - if (timestampIt->second < oldestTimestamp) { - oldestTimestamp = timestampIt->second; - oldestKeyIt = timestampIt; - } - - timestampIt++; - } - - if (m_lastTimestamp.size() >= m_maxTrackedKeys) - m_lastTimestamp.erase(oldestKeyIt); -} - -void -ValidatorConfig::DynamicTrustAnchorContainer::refresh() -{ - using namespace boost::filesystem; - - m_certificates.clear(); - - if (m_isDir) { - directory_iterator end; - - for (directory_iterator it(m_path); it != end; it++) { - auto idCert = io::load(it->path().string()); - - if (idCert != nullptr) - m_certificates.push_back(idCert); - } - } - else { - auto idCert = io::load(m_path.string()); - - if (idCert != nullptr) - m_certificates.push_back(idCert); - } -} - -template -void -ValidatorConfig::checkSignature(const Packet& packet, - const Signature& signature, - size_t nSteps, - const OnValidated& onValidated, - const OnFailed& onValidationFailed, - std::vector>& nextSteps) -{ - if (signature.getType() == tlv::DigestSha256) { - DigestSha256 sigSha256(signature); - - if (verifySignature(packet, sigSha256)) - return onValidated(packet.shared_from_this()); - else - return onValidationFailed(packet.shared_from_this(), "Sha256 Signature cannot be verified!"); - } - - try { - switch (signature.getType()) { - case tlv::SignatureSha256WithRsa: - case tlv::SignatureSha256WithEcdsa: { - if (!signature.hasKeyLocator()) { - return onValidationFailed(packet.shared_from_this(), - "Missing KeyLocator in SignatureInfo"); - } - break; - } - default: - return onValidationFailed(packet.shared_from_this(), "Unsupported signature type"); - } - } - catch (const KeyLocator::Error& e) { - return onValidationFailed(packet.shared_from_this(), - "Cannot decode KeyLocator in public key signature"); - } - catch (const tlv::Error& e) { - return onValidationFailed(packet.shared_from_this(), "Cannot decode public key signature"); - } - - if (signature.getKeyLocator().getType() != KeyLocator::KeyLocator_Name) { - return onValidationFailed(packet.shared_from_this(), "Unsupported KeyLocator type"); - } - - const Name& keyLocatorName = signature.getKeyLocator().getName(); - - shared_ptr trustedCert; - - refreshAnchors(); - - AnchorList::const_iterator it = m_anchors.find(keyLocatorName); - if (m_anchors.end() == it && m_certificateCache != nullptr) - trustedCert = m_certificateCache->getCertificate(keyLocatorName); - else if (m_anchors.end() != it) - trustedCert = it->second; - - if (trustedCert != nullptr) { - if (verifySignature(packet, signature, trustedCert->getPublicKeyInfo())) - return onValidated(packet.shared_from_this()); - else - return onValidationFailed(packet.shared_from_this(), "Cannot verify signature"); - } - else { - if (m_stepLimit == nSteps) - return onValidationFailed(packet.shared_from_this(), "Maximum steps of validation reached"); - - OnDataValidated onCertValidated = - bind(&ValidatorConfig::onCertValidated, - this, _1, packet.shared_from_this(), onValidated, onValidationFailed); - - OnDataValidationFailed onCertValidationFailed = - bind(&ValidatorConfig::onCertFailed, - this, _1, _2, packet.shared_from_this(), onValidationFailed); - - Interest certInterest(keyLocatorName); - - auto nextStep = make_shared(certInterest, - onCertValidated, - onCertValidationFailed, - 1, nSteps + 1); - - nextSteps.push_back(nextStep); - return; - } - return onValidationFailed(packet.shared_from_this(), "Unsupported Signature Type"); -} - -template -void -ValidatorConfig::onCertValidated(const shared_ptr& signCertificate, - const shared_ptr& packet, - const OnValidated& onValidated, - const OnFailed& onValidationFailed) -{ - if (signCertificate->getContentType() != tlv::ContentType_Key) - return onValidationFailed(packet, - "Cannot retrieve signer's cert: " + - signCertificate->getName().toUri()); - - shared_ptr certificate; - try { - certificate = make_shared(*signCertificate); - } - catch (const tlv::Error&) { - return onValidationFailed(packet, - "Cannot decode signer's cert: " + - signCertificate->getName().toUri()); - } - - if (!certificate->isTooLate() && !certificate->isTooEarly()) { - if (m_certificateCache != nullptr) - m_certificateCache->insertCertificate(certificate); - - if (verifySignature(*packet, certificate->getPublicKeyInfo())) - return onValidated(packet); - else - return onValidationFailed(packet, - "Cannot verify signature: " + packet->getName().toUri()); - } - else { - return onValidationFailed(packet, - "Signing certificate " + - signCertificate->getName().toUri() + " is no longer valid."); - } -} - -template -void -ValidatorConfig::onCertFailed(const shared_ptr& signCertificate, - const std::string& failureInfo, - const shared_ptr& packet, - const OnFailed& onValidationFailed) -{ - onValidationFailed(packet, failureInfo); -} - -} // namespace security -} // namespace ndn diff --git a/src/security/validator-config.hpp b/src/security/validator-config.hpp deleted file mode 100644 index a477325d9..000000000 --- a/src/security/validator-config.hpp +++ /dev/null @@ -1,267 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - * @author Zhiyi Zhang - */ - -#ifndef NDN_SECURITY_VALIDATOR_CONFIG_HPP -#define NDN_SECURITY_VALIDATOR_CONFIG_HPP - -#include "validator.hpp" -#include "certificate-cache.hpp" -#include "conf/rule.hpp" -#include "conf/common.hpp" - -namespace ndn { -namespace security { - -/** - * @brief The validator which can be set up via a configuration file. - */ -class ValidatorConfig : public Validator -{ -public: - class Error : public Validator::Error - { - public: - explicit - Error(const std::string& what) - : Validator::Error(what) - { - } - }; - - /** - * @note When both certificate cache and face are not supplied, no cache will be used. - * However, if only face is supplied, a default cache will be created and used. - */ - explicit - ValidatorConfig(Face* face = nullptr, - const shared_ptr& certificateCache = DEFAULT_CERTIFICATE_CACHE, - const time::milliseconds& graceInterval = DEFAULT_GRACE_INTERVAL, - const size_t stepLimit = 10, - const size_t maxTrackedKeys = 1000, - const time::system_clock::Duration& keyTimestampTtl = DEFAULT_KEY_TIMESTAMP_TTL); - - /// @deprecated Use the constructor taking Face* as parameter. - explicit - ValidatorConfig(Face& face, - const shared_ptr& certificateCache = DEFAULT_CERTIFICATE_CACHE, - const time::milliseconds& graceInterval = DEFAULT_GRACE_INTERVAL, - const size_t stepLimit = 10, - const size_t maxTrackedKeys = 1000, - const time::system_clock::Duration& keyTimestampTtl = DEFAULT_KEY_TIMESTAMP_TTL); - - void - load(const std::string& filename); - - void - load(const std::string& input, const std::string& filename); - - void - load(std::istream& input, const std::string& filename); - - void - load(const security::conf::ConfigSection& configSection, - const std::string& filename); - - void - reset(); - - bool - isEmpty(); - -protected: - virtual void - checkPolicy(const Data& data, - int nSteps, - const OnDataValidated& onValidated, - const OnDataValidationFailed& onValidationFailed, - std::vector>& nextSteps) override; - - virtual void - checkPolicy(const Interest& interest, - int nSteps, - const OnInterestValidated& onValidated, - const OnInterestValidationFailed& onValidationFailed, - std::vector>& nextSteps) override; - -private: - template - void - checkSignature(const Packet& packet, - const Signature& signature, - size_t nSteps, - const OnValidated& onValidated, - const OnFailed& onValidationFailed, - std::vector>& nextSteps); - - void - checkTimestamp(const shared_ptr& interest, - const Name& keyName, - const OnInterestValidated& onValidated, - const OnInterestValidationFailed& onValidationFailed); - - template - void - onCertValidated(const shared_ptr& signCertificate, - const shared_ptr& packet, - const OnValidated& onValidated, - const OnFailed& onValidationFailed); - - template - void - onCertFailed(const shared_ptr& signCertificate, - const std::string& failureInfo, - const shared_ptr& packet, - const OnFailed& onValidationFailed); - - void - onConfigRule(const security::conf::ConfigSection& section, - const std::string& filename); - - void - onConfigTrustAnchor(const security::conf::ConfigSection& section, - const std::string& filename); - - time::nanoseconds - getRefreshPeriod(std::string refreshString); - - time::nanoseconds - getDefaultRefreshPeriod(); - - void - refreshAnchors(); - - void - cleanOldKeys(); - - class TrustAnchorContainer - { - public: - const std::list>& - getAll() const - { - return m_certificates; - } - - void - add(shared_ptr certificate) - { - m_certificates.push_back(certificate); - } - - protected: - std::list> m_certificates; - }; - - class DynamicTrustAnchorContainer : public TrustAnchorContainer - { - public: - DynamicTrustAnchorContainer(const boost::filesystem::path& path, bool isDir, - time::nanoseconds refreshPeriod) - : m_path(path) - , m_isDir(isDir) - , m_refreshPeriod(refreshPeriod) - { - } - - void - setLastRefresh(const time::system_clock::TimePoint& lastRefresh) - { - m_lastRefresh = lastRefresh; - } - - const time::system_clock::TimePoint& - getLastRefresh() const - { - return m_lastRefresh; - } - - const time::nanoseconds& - getRefreshPeriod() const - { - return m_refreshPeriod; - } - - void - refresh(); - - private: - boost::filesystem::path m_path; - bool m_isDir; - - time::system_clock::TimePoint m_lastRefresh; - time::nanoseconds m_refreshPeriod; - }; - - static inline bool - compareDynamicContainer(const DynamicTrustAnchorContainer& containerA, - const DynamicTrustAnchorContainer& containerB) - { - return (containerA.getLastRefresh() < containerB.getLastRefresh()); - } - -public: - static const shared_ptr DEFAULT_CERTIFICATE_CACHE; - static const time::milliseconds DEFAULT_GRACE_INTERVAL; - static const time::system_clock::Duration DEFAULT_KEY_TIMESTAMP_TTL; - -NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: - typedef security::conf::Rule InterestRule; - typedef security::conf::Rule DataRule; - typedef std::vector> InterestRuleList; - typedef std::vector> DataRuleList; - typedef std::map> AnchorList; - typedef std::list DynamicContainers; // sorted by m_lastRefresh - typedef std::list> CertificateList; - - /** - * @brief gives whether validation should be preformed - * - * If false, no validation occurs, and any packet is considered validated immediately. - */ - bool m_shouldValidate; - - size_t m_stepLimit; - shared_ptr m_certificateCache; - - InterestRuleList m_interestRules; - DataRuleList m_dataRules; - - AnchorList m_anchors; - TrustAnchorContainer m_staticContainer; - DynamicContainers m_dynamicContainers; - - time::milliseconds m_graceInterval; - size_t m_maxTrackedKeys; - typedef std::map LastTimestampMap; - LastTimestampMap m_lastTimestamp; - const time::system_clock::Duration& m_keyTimestampTtl; -}; - -} // namespace security - -using security::ValidatorConfig; - -} // namespace ndn - -#endif // NDN_SECURITY_VALIDATOR_CONFIG_HPP diff --git a/src/security/validator-null.hpp b/src/security/validator-null.hpp deleted file mode 100644 index 36448aff1..000000000 --- a/src/security/validator-null.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - * @author Jeff Thompson - */ - -#ifndef NDN_SECURITY_VALIDATOR_NULL_HPP -#define NDN_SECURITY_VALIDATOR_NULL_HPP - -#include "validator.hpp" - -namespace ndn { -namespace security { - -class ValidatorNull : public Validator -{ -public: - virtual - ~ValidatorNull() - { - } - -protected: - virtual void - checkPolicy(const Data& data, - int nSteps, - const OnDataValidated& onValidated, - const OnDataValidationFailed& onValidationFailed, - std::vector >& nextSteps) - { - onValidated(data.shared_from_this()); - } - - virtual void - checkPolicy(const Interest& interest, - int nSteps, - const OnInterestValidated& onValidated, - const OnInterestValidationFailed& onValidationFailed, - std::vector >& nextSteps) - { - onValidated(interest.shared_from_this()); - } -}; - -} // namespace security - -using security::ValidatorNull; - -} // namespace ndn - -#endif //NDN_SECURITY_VALIDATOR_NULL_HPP diff --git a/src/security/validator-regex.cpp b/src/security/validator-regex.cpp deleted file mode 100644 index caa2e6c1f..000000000 --- a/src/security/validator-regex.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#include "common.hpp" - -#include "validator-regex.hpp" -#include "signature-sha256-with-rsa.hpp" -#include "certificate-cache-ttl.hpp" - -namespace ndn { -namespace security { - -const shared_ptr ValidatorRegex::DEFAULT_CERTIFICATE_CACHE; - -ValidatorRegex::ValidatorRegex(Face* face, - shared_ptr certificateCache, - const int stepLimit) - : Validator(face) - , m_stepLimit(stepLimit) - , m_certificateCache(certificateCache) -{ - if (!static_cast(m_certificateCache) && face != nullptr) - m_certificateCache = make_shared(ref(face->getIoService())); -} - -ValidatorRegex::ValidatorRegex(Face& face, - shared_ptr certificateCache, - const int stepLimit) - : Validator(face) - , m_stepLimit(stepLimit) - , m_certificateCache(certificateCache) -{ - if (certificateCache == nullptr) - m_certificateCache = make_shared(ref(face.getIoService())); -} - -void -ValidatorRegex::addDataVerificationRule(shared_ptr rule) -{ - rule->isPositive() ? m_verifyPolicies.push_back(rule) : m_mustFailVerify.push_back(rule); -} - -void -ValidatorRegex::addTrustAnchor(shared_ptr certificate) -{ - m_trustAnchors[certificate->getName().getPrefix(-1)] = certificate; -} - -void -ValidatorRegex::onCertificateValidated(const shared_ptr& signCertificate, - const shared_ptr& data, - const OnDataValidated& onValidated, - const OnDataValidationFailed& onValidationFailed) -{ - shared_ptr certificate = - make_shared(*signCertificate); - - if (!certificate->isTooLate() && !certificate->isTooEarly()) { - if (m_certificateCache != nullptr) - m_certificateCache->insertCertificate(certificate); - - if (verifySignature(*data, certificate->getPublicKeyInfo())) - return onValidated(data); - else - return onValidationFailed(data, - "Cannot verify signature: " + - data->getName().toUri()); - } - else { - return onValidationFailed(data, - "Signing certificate " + - signCertificate->getName().toUri() + - " is no longer valid."); - } -} - -void -ValidatorRegex::onCertificateValidationFailed(const shared_ptr& signCertificate, - const std::string& failureInfo, - const shared_ptr& data, - const OnDataValidationFailed& onValidationFailed) -{ - onValidationFailed(data, failureInfo); -} - -void -ValidatorRegex::checkPolicy(const Data& data, - int nSteps, - const OnDataValidated& onValidated, - const OnDataValidationFailed& onValidationFailed, - std::vector >& nextSteps) -{ - if (m_stepLimit == nSteps) - return onValidationFailed(data.shared_from_this(), - "Maximum steps of validation reached: " + - data.getName().toUri()); - - for (RuleList::iterator it = m_mustFailVerify.begin(); - it != m_mustFailVerify.end(); - it++) - if ((*it)->satisfy(data)) - return onValidationFailed(data.shared_from_this(), - "Comply with mustFail policy: " + - data.getName().toUri()); - - for (RuleList::iterator it = m_verifyPolicies.begin(); - it != m_verifyPolicies.end(); - it++) { - if ((*it)->satisfy(data)) { - try { - if (!data.getSignature().hasKeyLocator()) - return onValidationFailed(data.shared_from_this(), - "Key Locator is missing in Data packet: " + - data.getName().toUri()); - - const KeyLocator& keyLocator = data.getSignature().getKeyLocator(); - if (keyLocator.getType() != KeyLocator::KeyLocator_Name) - return onValidationFailed(data.shared_from_this(), - "Key Locator is not a name: " + - data.getName().toUri()); - - - const Name& keyLocatorName = keyLocator.getName(); - shared_ptr trustedCert; - if (m_trustAnchors.end() == m_trustAnchors.find(keyLocatorName) && - m_certificateCache != nullptr) - trustedCert = m_certificateCache->getCertificate(keyLocatorName); - else - trustedCert = m_trustAnchors[keyLocatorName]; - - if (trustedCert != nullptr) { - if (verifySignature(data, data.getSignature(), trustedCert->getPublicKeyInfo())) - return onValidated(data.shared_from_this()); - else - return onValidationFailed(data.shared_from_this(), - "Cannot verify signature: " + - data.getName().toUri()); - } - else { - // KeyLocator is not a trust anchor - - OnDataValidated onKeyValidated = - bind(&ValidatorRegex::onCertificateValidated, this, _1, - data.shared_from_this(), onValidated, onValidationFailed); - - OnDataValidationFailed onKeyValidationFailed = - bind(&ValidatorRegex::onCertificateValidationFailed, this, _1, _2, - data.shared_from_this(), onValidationFailed); - - Interest interest(keyLocatorName); - shared_ptr nextStep = - make_shared(interest, - onKeyValidated, - onKeyValidationFailed, - 3, - nSteps + 1); - - nextSteps.push_back(nextStep); - - return; - } - } - catch (const KeyLocator::Error& e) { - return onValidationFailed(data.shared_from_this(), - "Key Locator is not a name: " + - data.getName().toUri()); - } - catch (const tlv::Error& e) { - return onValidationFailed(data.shared_from_this(), - "Cannot decode signature"); - } - } - } - - return onValidationFailed(data.shared_from_this(), - "No policy found for data: " + data.getName().toUri()); -} - -} // namespace security -} // namespace ndn diff --git a/src/security/validator-regex.hpp b/src/security/validator-regex.hpp deleted file mode 100644 index 7d97f22e2..000000000 --- a/src/security/validator-regex.hpp +++ /dev/null @@ -1,135 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_SECURITY_VALIDATOR_REGEX_HPP -#define NDN_SECURITY_VALIDATOR_REGEX_HPP - -#include "validator.hpp" -#include "v1/identity-certificate.hpp" -#include "sec-rule-relative.hpp" -#include "certificate-cache.hpp" -#include "../util/regex.hpp" - -namespace ndn { -namespace security { - -class ValidatorRegex : public Validator -{ -public: - class Error : public Validator::Error - { - public: - explicit - Error(const std::string& what) - : Validator::Error(what) - { - } - }; - - /** - * @note When both certificate cache and face are not supplied, no cache will be used. - * However, if only face is supplied, a default cache will be created and used. - */ - explicit - ValidatorRegex(Face* face = nullptr, - shared_ptr certificateCache = DEFAULT_CERTIFICATE_CACHE, - const int stepLimit = 3); - - /// @deprecated Use the constructor taking Face* as parameter. - explicit - ValidatorRegex(Face& face, - shared_ptr certificateCache = DEFAULT_CERTIFICATE_CACHE, - const int stepLimit = 3); - - virtual - ~ValidatorRegex() - { - } - - /** - * @brief Add a rule for data verification. - * - * @param rule The verification rule - */ - void - addDataVerificationRule(shared_ptr rule); - - /** - * @brief Add a trust anchor - * - * @param certificate The trust anchor - */ - void - addTrustAnchor(shared_ptr certificate); - -protected: - virtual void - checkPolicy(const Data& data, - int nSteps, - const OnDataValidated& onValidated, - const OnDataValidationFailed& onValidationFailed, - std::vector >& nextSteps); - - virtual void - checkPolicy(const Interest& interest, - int nSteps, - const OnInterestValidated& onValidated, - const OnInterestValidationFailed& onValidationFailed, - std::vector >& nextSteps) - { - onValidationFailed(interest.shared_from_this(), "No policy for signed interest checking"); - } - - void - onCertificateValidated(const shared_ptr& signCertificate, - const shared_ptr& data, - const OnDataValidated& onValidated, - const OnDataValidationFailed& onValidationFailed); - - void - onCertificateValidationFailed(const shared_ptr& signCertificate, - const std::string& failureInfo, - const shared_ptr& data, - const OnDataValidationFailed& onValidationFailed); - -public: - static const shared_ptr DEFAULT_CERTIFICATE_CACHE; - -protected: - typedef std::vector< shared_ptr > RuleList; - typedef std::vector< shared_ptr > RegexList; - - int m_stepLimit; - shared_ptr m_certificateCache; - RuleList m_mustFailVerify; - RuleList m_verifyPolicies; - std::map > m_trustAnchors; -}; - -} // namespace security - -using security::ValidatorRegex; - -} // namespace ndn - -#endif // NDN_SECURITY_VALIDATOR_REGEX_HPP diff --git a/src/security/validator.cpp b/src/security/validator.cpp deleted file mode 100644 index 84aaa0f74..000000000 --- a/src/security/validator.cpp +++ /dev/null @@ -1,326 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - * @author Jeff Thompson - */ - -#include "validator.hpp" -#include "../util/crypto.hpp" - -#include "v1/cryptopp.hpp" - -namespace ndn { -namespace security { - -static Oid SECP256R1("1.2.840.10045.3.1.7"); -static Oid SECP384R1("1.3.132.0.34"); - -Validator::Validator(Face* face) - : m_face(face) -{ -} - -Validator::Validator(Face& face) - : m_face(&face) -{ -} - -Validator::~Validator() = default; - -void -Validator::validate(const Interest& interest, - const OnInterestValidated& onValidated, - const OnInterestValidationFailed& onValidationFailed, - int nSteps) -{ - std::vector > nextSteps; - checkPolicy(interest, nSteps, onValidated, onValidationFailed, nextSteps); - - if (nextSteps.empty()) { - // If there is no nextStep, - // that means InterestPolicy has already been able to verify the Interest. - // No more further processes. - return; - } - - OnFailure onFailure = bind(onValidationFailed, interest.shared_from_this(), _1); - afterCheckPolicy(nextSteps, onFailure); -} - -void -Validator::validate(const Data& data, - const OnDataValidated& onValidated, - const OnDataValidationFailed& onValidationFailed, - int nSteps) -{ - std::vector > nextSteps; - checkPolicy(data, nSteps, onValidated, onValidationFailed, nextSteps); - - if (nextSteps.empty()) { - // If there is no nextStep, - // that means Data Policy has already been able to verify the Interest. - // No more further processes. - return; - } - - OnFailure onFailure = bind(onValidationFailed, data.shared_from_this(), _1); - afterCheckPolicy(nextSteps, onFailure); -} - -void -Validator::onData(const Interest& interest, - const Data& data, - const shared_ptr& nextStep) -{ - shared_ptr certificateData = preCertificateValidation(data); - - if (!static_cast(certificateData)) - return nextStep->m_onDataValidationFailed(data.shared_from_this(), - "Cannot decode cert: " + data.getName().toUri()); - - validate(*certificateData, - nextStep->m_onDataValidated, nextStep->m_onDataValidationFailed, - nextStep->m_nSteps); -} - -bool -Validator::verifySignature(const Data& data, const v1::PublicKey& key) -{ - if (!data.getSignature().hasKeyLocator()) - return false; - - return verifySignature(data.wireEncode().value(), - data.wireEncode().value_size() - - data.getSignature().getValue().size(), - data.getSignature(), key); -} - -bool -Validator::verifySignature(const Interest& interest, const v1::PublicKey& key) -{ - const Name& name = interest.getName(); - - if (name.size() < signed_interest::MIN_LENGTH_SIG_ONLY) - return false; - - Signature sig; - try { - sig.setInfo(name[signed_interest::POS_SIG_INFO].blockFromValue()); - sig.setValue(name[signed_interest::POS_SIG_VALUE].blockFromValue()); - } - catch (const tlv::Error&) { - return false; - } - - if (!sig.hasKeyLocator()) - return false; - - const Block& nameWire = name.wireEncode(); - return verifySignature(nameWire.value(), - nameWire.value_size() - name[signed_interest::POS_SIG_VALUE].size(), - sig, key); -} - -bool -Validator::verifySignature(const uint8_t* buf, - const size_t size, - const Signature& sig, - const v1::PublicKey& key) -{ - try { - using namespace CryptoPP; - - switch (sig.getType()) { - case tlv::SignatureSha256WithRsa: { - if (key.getKeyType() != KeyType::RSA) - return false; - - RSA::PublicKey publicKey; - ByteQueue queue; - - queue.Put(reinterpret_cast(key.get().buf()), key.get().size()); - publicKey.Load(queue); - - RSASS::Verifier verifier(publicKey); - return verifier.VerifyMessage(buf, size, - sig.getValue().value(), sig.getValue().value_size()); - } - - case tlv::SignatureSha256WithEcdsa: { - if (key.getKeyType() != KeyType::EC) - return false; - - ECDSA::PublicKey publicKey; - ByteQueue queue; - - queue.Put(reinterpret_cast(key.get().buf()), key.get().size()); - publicKey.Load(queue); - - ECDSA::Verifier verifier(publicKey); - - uint32_t length = 0; - StringSource src(key.get().buf(), key.get().size(), true); - BERSequenceDecoder subjectPublicKeyInfo(src); - { - BERSequenceDecoder algorithmInfo(subjectPublicKeyInfo); - { - Oid algorithm; - algorithm.decode(algorithmInfo); - - Oid curveId; - curveId.decode(algorithmInfo); - - if (curveId == SECP256R1) - length = 256; - else if (curveId == SECP384R1) - length = 384; - else - return false; - } - } - - switch (length) { - case 256: { - uint8_t buffer[64]; - size_t usedSize = DSAConvertSignatureFormat(buffer, sizeof(buffer), DSA_P1363, - sig.getValue().value(), - sig.getValue().value_size(), - DSA_DER); - return verifier.VerifyMessage(buf, size, buffer, usedSize); - } - - case 384: { - uint8_t buffer[96]; - size_t usedSize = DSAConvertSignatureFormat(buffer, sizeof(buffer), DSA_P1363, - sig.getValue().value(), - sig.getValue().value_size(), - DSA_DER); - return verifier.VerifyMessage(buf, size, buffer, usedSize); - } - - default: - return false; - } - } - - default: - // Unsupported sig type - return false; - } - } - catch (const CryptoPP::Exception& e) { - return false; - } -} - -bool -Validator::verifySignature(const uint8_t* buf, const size_t size, const DigestSha256& sig) -{ - try { - ConstBufferPtr buffer = crypto::computeSha256Digest(buf, size); - const Block& sigValue = sig.getValue(); - - if (buffer != nullptr && - buffer->size() == sigValue.value_size() && - buffer->size() == crypto::SHA256_DIGEST_SIZE) { - const uint8_t* p1 = buffer->buf(); - const uint8_t* p2 = sigValue.value(); - - return 0 == memcmp(p1, p2, crypto::SHA256_DIGEST_SIZE); - } - else - return false; - } - catch (const CryptoPP::Exception& e) { - return false; - } -} - -void -Validator::onNack(const Interest& interest, - const lp::Nack& nack, - int remainingRetries, - const OnFailure& onFailure, - const shared_ptr& validationRequest) -{ - if (remainingRetries > 0) { - Interest newInterest = Interest(interest); - newInterest.refreshNonce(); - - //Express the same interest with different nonce and decremented remainingRetries. - m_face->expressInterest(newInterest, - bind(&Validator::onData, this, _1, _2, validationRequest), - bind(&Validator::onNack, this, _1, _2, - remainingRetries - 1, onFailure, validationRequest), - bind(&Validator::onTimeout, this, _1, - remainingRetries - 1, onFailure, validationRequest)); - } - else { - onFailure("Cannot fetch cert: " + interest.getName().toUri()); - } -} - -void -Validator::onTimeout(const Interest& interest, - int remainingRetries, - const OnFailure& onFailure, - const shared_ptr& validationRequest) -{ - if (remainingRetries > 0) { - Interest newInterest = Interest(interest); - newInterest.refreshNonce(); - - // Express the same interest with different nonce and decremented remainingRetries. - m_face->expressInterest(newInterest, - bind(&Validator::onData, this, _1, _2, validationRequest), - bind(&Validator::onNack, this, _1, _2, - remainingRetries - 1, onFailure, validationRequest), - bind(&Validator::onTimeout, this, _1, - remainingRetries - 1, onFailure, validationRequest)); - } - else { - onFailure("Cannot fetch cert: " + interest.getName().toUri()); - } -} - -void -Validator::afterCheckPolicy(const std::vector>& nextSteps, - const OnFailure& onFailure) -{ - if (m_face == nullptr) { - onFailure("Require more information to validate the packet!"); - return; - } - - for (shared_ptr step : nextSteps) { - m_face->expressInterest(step->m_interest, - bind(&Validator::onData, this, _1, _2, step), - bind(&Validator::onNack, this, _1, _2, - step->m_nRetries, onFailure, step), - bind(&Validator::onTimeout, - this, _1, step->m_nRetries, - onFailure, - step)); - } -} - -} // namespace security -} // namespace ndn diff --git a/src/security/validator.hpp b/src/security/validator.hpp deleted file mode 100644 index edc036597..000000000 --- a/src/security/validator.hpp +++ /dev/null @@ -1,340 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - * @author Jeff Thompson - */ - -#ifndef NDN_SECURITY_VALIDATOR_HPP -#define NDN_SECURITY_VALIDATOR_HPP - -#include "../face.hpp" -#include "signature-sha256-with-rsa.hpp" -#include "signature-sha256-with-ecdsa.hpp" -#include "digest-sha256.hpp" -#include "validation-request.hpp" -#include "v1/public-key.hpp" -#include "v1/identity-certificate.hpp" - -namespace ndn { -namespace security { - -/** - * @brief provides the interfaces for packet validation. - */ -class Validator -{ -public: - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - - /** - * @brief Validator constructor - * - * @param face Pointer to face through which validator may retrieve certificates. - * Passing a null pointer implies the validator is in offline mode. - * - * @note Make sure the lifetime of the passed Face is longer than validator. - */ - explicit - Validator(Face* face = nullptr); - - /// @deprecated Use the constructor taking Face* as parameter. - explicit - Validator(Face& face); - - virtual - ~Validator(); - - /** - * @brief Validate Data and call either onValidated or onValidationFailed. - * - * @param data The Data with the signature to check. - * @param onValidated If the Data is validated, this calls onValidated(data). - * @param onValidationFailed If validation fails, this calls onValidationFailed(data). - */ - void - validate(const Data& data, - const OnDataValidated& onValidated, - const OnDataValidationFailed& onValidationFailed) - { - validate(data, onValidated, onValidationFailed, 0); - } - - /** - * @brief Validate Interest and call either onValidated or onValidationFailed. - * - * @param interest The Interest with the signature to check. - * @param onValidated If the Interest is validated, this calls onValidated(interest). - * @param onValidationFailed If validation fails, this calls onValidationFailed(interest). - */ - void - validate(const Interest& interest, - const OnInterestValidated& onValidated, - const OnInterestValidationFailed& onValidationFailed) - { - validate(interest, onValidated, onValidationFailed, 0); - } - - /***************************************** - * verifySignature method set * - *****************************************/ - - /// @brief Verify the data using the publicKey. - static bool - verifySignature(const Data& data, const v1::PublicKey& publicKey); - - /** - * @brief Verify the signed Interest using the publicKey. - * - * (Note the signature covers the first n-2 name components). - */ - static bool - verifySignature(const Interest& interest, const v1::PublicKey& publicKey); - - /// @brief Verify the blob using the publicKey against the signature. - static bool - verifySignature(const Buffer& blob, const Signature& sig, const v1::PublicKey& publicKey) - { - return verifySignature(blob.buf(), blob.size(), sig, publicKey); - } - - /// @brief Verify the data using the publicKey against the SHA256-RSA signature. - static bool - verifySignature(const Data& data, - const Signature& sig, - const v1::PublicKey& publicKey) - { - return verifySignature(data.wireEncode().value(), - data.wireEncode().value_size() - data.getSignature().getValue().size(), - sig, publicKey); - } - - /** @brief Verify the interest using the publicKey against the SHA256-RSA signature. - * - * (Note the signature covers the first n-2 name components). - */ - static bool - verifySignature(const Interest& interest, - const Signature& sig, - const v1::PublicKey& publicKey) - { - if (interest.getName().size() < 2) - return false; - - const Name& name = interest.getName(); - - return verifySignature(name.wireEncode().value(), - name.wireEncode().value_size() - name[-1].size(), - sig, publicKey); - } - - /// @brief Verify the blob using the publicKey against the SHA256-RSA signature. - static bool - verifySignature(const uint8_t* buf, - const size_t size, - const Signature& sig, - const v1::PublicKey& publicKey); - - - /// @brief Verify the data against the SHA256 signature. - static bool - verifySignature(const Data& data, const DigestSha256& sig) - { - return verifySignature(data.wireEncode().value(), - data.wireEncode().value_size() - - data.getSignature().getValue().size(), - sig); - } - - /** @brief Verify the interest against the SHA256 signature. - * - * (Note the signature covers the first n-2 name components). - */ - static bool - verifySignature(const Interest& interest, const DigestSha256& sig) - { - if (interest.getName().size() < 2) - return false; - - const Name& name = interest.getName(); - - return verifySignature(name.wireEncode().value(), - name.wireEncode().value_size() - name[-1].size(), - sig); - } - - /// @brief Verify the blob against the SHA256 signature. - static bool - verifySignature(const Buffer& blob, const DigestSha256& sig) - { - return verifySignature (blob.buf(), blob.size(), sig); - } - - /// @brief Verify the blob against the SHA256 signature. - static bool - verifySignature(const uint8_t* buf, const size_t size, const DigestSha256& sig); - -protected: - /** - * @brief Check the Data against policy and return the next validation step if necessary. - * - * If there is no next validation step, that validation MUST have been done. - * i.e., either onValidated or onValidationFailed callback is invoked. - * - * @param data The Data to check. - * @param nSteps The number of validation steps that have been done. - * @param onValidated If the Data is validated, this calls onValidated(data) - * @param onValidationFailed If validation fails, this calls onValidationFailed(data) - * @param nextSteps On return, contains the next validation step - */ - virtual void - checkPolicy(const Data& data, - int nSteps, - const OnDataValidated& onValidated, - const OnDataValidationFailed& onValidationFailed, - std::vector>& nextSteps) = 0; - - /** - * @brief Check the Interest against validation policy and return the next validation step - * if necessary. - * - * If there is no next validation step, that validation MUST have been done. - * i.e., either onValidated or onValidationFailed callback is invoked. - * - * @param interest The Interest to check. - * @param nSteps The number of validation steps that have been done. - * @param onValidated If the Interest is validated, this calls onValidated(data) - * @param onValidationFailed If validation fails, this calls onValidationFailed(data) - * @param nextSteps On return, contains the next validation step - */ - virtual void - checkPolicy(const Interest& interest, - int nSteps, - const OnInterestValidated& onValidated, - const OnInterestValidationFailed& onValidationFailed, - std::vector>& nextSteps) = 0; - - typedef function OnFailure; - - /// @brief Process the received certificate. - void - onData(const Interest& interest, - const Data& data, - const shared_ptr& nextStep); - - void - validate(const Data& data, - const OnDataValidated& onValidated, - const OnDataValidationFailed& onValidationFailed, - int nSteps); - - void - validate(const Interest& interest, - const OnInterestValidated& onValidated, - const OnInterestValidationFailed& onValidationFailed, - int nSteps); - - /// Hooks - - /** - * @brief trigger before validating requested certificate. - * - * The Data: - * - matches the interest in the validation-request. - * - may be certificate or a data encapsulating certificate. - * - * This method returns a data (actually certificate) that is will be passed as Data into: - * Validator::validate(const Data& data, - * const OnDataValidated& onValidated, - * const OnDataValidationFailed& onValidationFailed, - * int nSteps); - */ - virtual shared_ptr - preCertificateValidation(const Data& data) - { - return data.shared_from_this(); - } - - /** - * @brief trigger when interest retrieves a Nack. - * - * Validator can decide how to handle a Nack, either call onFailure, or retry. - * - * @param interest The interest that retrieves a Nack. - * @param nack The Nack that is retrieved. - * @param nRemainingRetries The number of retries left. - * @param onFailure Failure callback when there is no more retries remaining. - * @param validationRequest The validationRequest containing the context of the interest. - */ - virtual void - onNack(const Interest& interest, - const lp::Nack& nack, - int nRemainingRetries, - const OnFailure& onFailure, - const shared_ptr& validationRequest); - - /** - * @brief trigger when interest for certificate times out. - * - * Validator can decide how to handle the timeout, either call onFailure, or retry. - * - * @param interest The interest that times out. - * @param nRemainingRetries The number of retries left. - * @param onFailure Failure callback when there is no more retries remaining. - * @param validationRequest The validationRequest containing the context of the interest. - */ - virtual void - onTimeout(const Interest& interest, - int nRemainingRetries, - const OnFailure& onFailure, - const shared_ptr& validationRequest); - - /** - * @brief trigger after checkPolicy is done. - * - * Validator can decide how to handle the set of validation requests according to - * the trust model. - * - * @param nextSteps A set of validation request made by checkPolicy. - * @param onFailure Failure callback when errors happen in processing nextSteps. - */ - virtual void - afterCheckPolicy(const std::vector>& nextSteps, - const OnFailure& onFailure); - -protected: - Face* m_face; -}; - -} // namespace security - -using security::Validator; - -} // namespace ndn - -#endif // NDN_SECURITY_VALIDATOR_HPP diff --git a/src/selectors.cpp b/src/selectors.cpp deleted file mode 100644 index 7b46b1e9a..000000000 --- a/src/selectors.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "selectors.hpp" -#include "encoding/encoding-buffer.hpp" -#include "encoding/block-helpers.hpp" - -namespace ndn { - -BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "Selectors::Error must inherit from tlv::Error"); - -Selectors::Selectors() - : m_minSuffixComponents(-1) - , m_maxSuffixComponents(-1) - , m_childSelector(-1) - , m_mustBeFresh(false) -{ -} - -Selectors::Selectors(const Block& wire) -{ - wireDecode(wire); -} - -bool -Selectors::empty() const -{ - return m_minSuffixComponents < 0 && - m_maxSuffixComponents < 0 && - m_publisherPublicKeyLocator.empty() && - m_exclude.empty() && - m_childSelector < 0 && - !m_mustBeFresh; -} - -template -size_t -Selectors::wireEncode(EncodingImpl& encoder) const -{ - size_t totalLength = 0; - - // Selectors ::= SELECTORS-TYPE TLV-LENGTH - // MinSuffixComponents? - // MaxSuffixComponents? - // PublisherPublicKeyLocator? - // Exclude? - // ChildSelector? - // MustBeFresh? - - // (reverse encoding) - - // MustBeFresh - if (getMustBeFresh()) { - totalLength += prependEmptyBlock(encoder, tlv::MustBeFresh); - } - - // ChildSelector - if (getChildSelector() >= 0) { - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::ChildSelector, getChildSelector()); - } - - // Exclude - if (!getExclude().empty()) { - totalLength += getExclude().wireEncode(encoder); - } - - // PublisherPublicKeyLocator - if (!getPublisherPublicKeyLocator().empty()) { - totalLength += getPublisherPublicKeyLocator().wireEncode(encoder); - } - - // MaxSuffixComponents - if (getMaxSuffixComponents() >= 0) { - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::MaxSuffixComponents, - getMaxSuffixComponents()); - } - - // MinSuffixComponents - if (getMinSuffixComponents() >= 0) { - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::MinSuffixComponents, - getMinSuffixComponents()); - } - - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::Selectors); - return totalLength; -} - -template size_t -Selectors::wireEncode(EncodingImpl& encoder) const; - -template size_t -Selectors::wireEncode(EncodingImpl& encoder) const; - -const Block& -Selectors::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 -Selectors::wireDecode(const Block& wire) -{ - if (wire.type() != tlv::Selectors) - BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding Selectors")); - - *this = Selectors(); - - m_wire = wire; - m_wire.parse(); - - // MinSuffixComponents - Block::element_const_iterator val = m_wire.find(tlv::MinSuffixComponents); - if (val != m_wire.elements_end()) { - m_minSuffixComponents = readNonNegativeInteger(*val); - } - - // MaxSuffixComponents - val = m_wire.find(tlv::MaxSuffixComponents); - if (val != m_wire.elements_end()) { - m_maxSuffixComponents = readNonNegativeInteger(*val); - } - - // PublisherPublicKeyLocator - val = m_wire.find(tlv::KeyLocator); - if (val != m_wire.elements_end()) { - m_publisherPublicKeyLocator.wireDecode(*val); - } - - // Exclude - val = m_wire.find(tlv::Exclude); - if (val != m_wire.elements_end()) { - m_exclude.wireDecode(*val); - } - - // ChildSelector - val = m_wire.find(tlv::ChildSelector); - if (val != m_wire.elements_end()) { - m_childSelector = readNonNegativeInteger(*val); - } - - // MustBeFresh - val = m_wire.find(tlv::MustBeFresh); - if (val != m_wire.elements_end()) { - m_mustBeFresh = true; - } -} - -Selectors& -Selectors::setMinSuffixComponents(int minSuffixComponents) -{ - m_minSuffixComponents = minSuffixComponents; - m_wire.reset(); - return *this; -} - -Selectors& -Selectors::setMaxSuffixComponents(int maxSuffixComponents) -{ - m_maxSuffixComponents = maxSuffixComponents; - m_wire.reset(); - return *this; -} - -Selectors& -Selectors::setPublisherPublicKeyLocator(const KeyLocator& keyLocator) -{ - m_publisherPublicKeyLocator = keyLocator; - m_wire.reset(); - return *this; -} - -Selectors& -Selectors::setExclude(const Exclude& exclude) -{ - m_exclude = exclude; - m_wire.reset(); - return *this; -} - -Selectors& -Selectors::setChildSelector(int childSelector) -{ - m_childSelector = childSelector; - m_wire.reset(); - return *this; -} - -Selectors& -Selectors::setMustBeFresh(bool mustBeFresh) -{ - m_mustBeFresh = mustBeFresh; - m_wire.reset(); - return *this; -} - -bool -Selectors::operator==(const Selectors& other) const -{ - return wireEncode() == other.wireEncode(); -} - -} // namespace ndn diff --git a/src/selectors.hpp b/src/selectors.hpp deleted file mode 100644 index 9a1d8a446..000000000 --- a/src/selectors.hpp +++ /dev/null @@ -1,155 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SELECTORS_HPP -#define NDN_SELECTORS_HPP - -#include "common.hpp" -#include "key-locator.hpp" -#include "exclude.hpp" - -namespace ndn { - -/** - * @brief Abstraction implementing Interest selectors - */ -class Selectors -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - - Selectors(); - - /** - * @brief Create from wire encoding - */ - explicit - Selectors(const Block& wire); - - bool - empty() const; - - /** - * @brief Fast encoding or block size estimation - */ - template - size_t - wireEncode(EncodingImpl& encoder) const; - - /** - * @brief Encode to a wire format - */ - const Block& - wireEncode() const; - - /** - * @brief Decode the input from wire format - */ - void - wireDecode(const Block& wire); - -public: // getters & setters - int - getMinSuffixComponents() const - { - return m_minSuffixComponents; - } - - Selectors& - setMinSuffixComponents(int minSuffixComponents); - - int - getMaxSuffixComponents() const - { - return m_maxSuffixComponents; - } - - Selectors& - setMaxSuffixComponents(int maxSuffixComponents); - - const KeyLocator& - getPublisherPublicKeyLocator() const - { - return m_publisherPublicKeyLocator; - } - - Selectors& - setPublisherPublicKeyLocator(const KeyLocator& keyLocator); - - const Exclude& - getExclude() const - { - return m_exclude; - } - - Selectors& - setExclude(const Exclude& exclude); - - int - getChildSelector() const - { - return m_childSelector; - } - - Selectors& - setChildSelector(int childSelector); - - int - getMustBeFresh() const - { - return m_mustBeFresh; - } - - Selectors& - setMustBeFresh(bool mustBeFresh); - -public: // EqualityComparable concept - bool - operator==(const Selectors& other) const; - - bool - operator!=(const Selectors& other) const - { - return !this->operator==(other); - } - -private: - int m_minSuffixComponents; - int m_maxSuffixComponents; - KeyLocator m_publisherPublicKeyLocator; - Exclude m_exclude; - int m_childSelector; - bool m_mustBeFresh; - - mutable Block m_wire; -}; - -} // namespace ndn - -#endif // NDN_SELECTORS_HPP diff --git a/src/signature-info.cpp b/src/signature-info.cpp deleted file mode 100644 index 821d5a73d..000000000 --- a/src/signature-info.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "signature-info.hpp" -#include "encoding/block-helpers.hpp" -#include "util/concepts.hpp" - -#include - -namespace ndn { - -BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); -BOOST_CONCEPT_ASSERT((WireEncodable)); -BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer)); -BOOST_CONCEPT_ASSERT((WireDecodable)); -static_assert(std::is_base_of::value, - "SignatureInfo::Error must inherit from tlv::Error"); - -SignatureInfo::SignatureInfo() - : m_type(-1) - , m_hasKeyLocator(false) -{ -} - -SignatureInfo::SignatureInfo(tlv::SignatureTypeValue type) - : m_type(type) - , m_hasKeyLocator(false) -{ -} - -SignatureInfo::SignatureInfo(tlv::SignatureTypeValue type, const KeyLocator& keyLocator) - : m_type(type) - , m_hasKeyLocator(true) - , m_keyLocator(keyLocator) -{ -} - -SignatureInfo::SignatureInfo(const Block& block) -{ - wireDecode(block); -} - -void -SignatureInfo::setSignatureType(tlv::SignatureTypeValue type) -{ - m_wire.reset(); - m_type = type; -} - -void -SignatureInfo::setKeyLocator(const KeyLocator& keyLocator) -{ - m_wire.reset(); - m_keyLocator = keyLocator; - m_hasKeyLocator = true; -} - -void -SignatureInfo::unsetKeyLocator() -{ - m_wire.reset(); - m_keyLocator = KeyLocator(); - m_hasKeyLocator = false; -} - -const KeyLocator& -SignatureInfo::getKeyLocator() const -{ - if (m_hasKeyLocator) - return m_keyLocator; - else - BOOST_THROW_EXCEPTION(Error("KeyLocator does not exist")); -} - -void -SignatureInfo::setValidityPeriod(const security::ValidityPeriod& validityPeriod) -{ - unsetValidityPeriod(); - m_otherTlvs.push_front(validityPeriod.wireEncode()); -} - -void -SignatureInfo::unsetValidityPeriod() -{ - m_wire.reset(); - if (!m_otherTlvs.empty() && m_otherTlvs.front().type() == tlv::ValidityPeriod) { - m_otherTlvs.erase(m_otherTlvs.begin()); - } -} - -security::ValidityPeriod -SignatureInfo::getValidityPeriod() const -{ - if (m_otherTlvs.empty() || m_otherTlvs.front().type() != tlv::ValidityPeriod) { - BOOST_THROW_EXCEPTION(Error("SignatureInfo does not contain the requested ValidityPeriod field")); - } - - return security::ValidityPeriod(m_otherTlvs.front()); -} - -void -SignatureInfo::appendTypeSpecificTlv(const Block& block) -{ - m_wire.reset(); - m_otherTlvs.push_back(block); -} - - -const Block& -SignatureInfo::getTypeSpecificTlv(uint32_t type) const -{ - for (std::list::const_iterator i = m_otherTlvs.begin(); - i != m_otherTlvs.end(); i++) { - if (i->type() == type) - return *i; - } - - BOOST_THROW_EXCEPTION(Error("(SignatureInfo::getTypeSpecificTlv) Requested a non-existed type [" + - boost::lexical_cast(type) + "] from SignatureInfo")); -} - -template -size_t -SignatureInfo::wireEncode(EncodingImpl& encoder) const -{ - size_t totalLength = 0; - - for (std::list::const_reverse_iterator i = m_otherTlvs.rbegin(); - i != m_otherTlvs.rend(); i++) { - totalLength += encoder.appendBlock(*i); - } - - if (m_hasKeyLocator) - totalLength += m_keyLocator.wireEncode(encoder); - - totalLength += prependNonNegativeIntegerBlock(encoder, tlv::SignatureType, m_type); - - totalLength += encoder.prependVarNumber(totalLength); - totalLength += encoder.prependVarNumber(tlv::SignatureInfo); - return totalLength; -} - -template size_t -SignatureInfo::wireEncode(EncodingImpl& encoder) const; - -template size_t -SignatureInfo::wireEncode(EncodingImpl& encoder) const; - - -const Block& -SignatureInfo::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 -SignatureInfo::wireDecode(const Block& wire) -{ - if (!wire.hasWire()) { - BOOST_THROW_EXCEPTION(Error("The supplied block does not contain wire format")); - } - - m_hasKeyLocator = false; - - m_wire = wire; - m_wire.parse(); - - if (m_wire.type() != tlv::SignatureInfo) - BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding Name")); - - Block::element_const_iterator it = m_wire.elements_begin(); - - // the first block must be SignatureType - if (it != m_wire.elements_end() && it->type() == tlv::SignatureType) { - m_type = readNonNegativeInteger(*it); - it++; - } - else - BOOST_THROW_EXCEPTION(Error("SignatureInfo does not have sub-TLV or the first sub-TLV is not " - "SignatureType")); - - // the second block could be KeyLocator - if (it != m_wire.elements_end() && it->type() == tlv::KeyLocator) { - m_keyLocator.wireDecode(*it); - m_hasKeyLocator = true; - it++; - } - - // Decode the rest of type-specific TLVs, if any - while (it != m_wire.elements_end()) { - m_otherTlvs.push_back(*it); - it++; - } -} - -bool -SignatureInfo::operator==(const SignatureInfo& rhs) const -{ - return (m_type == rhs.m_type && - m_hasKeyLocator == rhs.m_hasKeyLocator && - m_keyLocator == rhs.m_keyLocator && - m_otherTlvs == rhs.m_otherTlvs); -} - -} // namespace ndn diff --git a/src/signature-info.hpp b/src/signature-info.hpp deleted file mode 100644 index 4ee8e6472..000000000 --- a/src/signature-info.hpp +++ /dev/null @@ -1,152 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SIGNATURE_INFO_HPP -#define NDN_SIGNATURE_INFO_HPP - -#include "encoding/tlv.hpp" -#include "key-locator.hpp" -#include "security/validity-period.hpp" -#include - -namespace ndn { - -class SignatureInfo -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - - SignatureInfo(); - - explicit - SignatureInfo(tlv::SignatureTypeValue type); - - SignatureInfo(tlv::SignatureTypeValue type, const KeyLocator& keyLocator); - - /** - * @brief Generate SignatureInfo from a block - * - * @throws tlv::Error if supplied block is not formatted correctly - */ - explicit - SignatureInfo(const Block& block); - - /// @brief Set SignatureType - void - setSignatureType(tlv::SignatureTypeValue type); - - /// @brief Get SignatureType - int32_t - getSignatureType() const - { - return m_type; - } - - /// @brief Check if KeyLocator is set - bool - hasKeyLocator() const - { - return m_hasKeyLocator; - } - - /// @brief Set KeyLocator - void - setKeyLocator(const KeyLocator& keyLocator); - - /// @brief Unset KeyLocator - void - unsetKeyLocator(); - - /** - * @brief Get KeyLocator - * - * @throws SignatureInfo::Error if keyLocator does not exist - */ - const KeyLocator& - getKeyLocator() const; - - /// @brief Set ValidityPeriod - void - setValidityPeriod(const security::ValidityPeriod& validityPeriod); - - /// @brief Unset ValidityPeriod - void - unsetValidityPeriod(); - - /// @brief Get ValidityPeriod - security::ValidityPeriod - getValidityPeriod() const; - - /// @brief Append signature type specific tlv block - void - appendTypeSpecificTlv(const Block& block); - - /** - * @brief Get signature type specific tlv block - * - * @throws SignatureInfo::Error if the block does not exist - */ - const Block& - getTypeSpecificTlv(uint32_t type) const; - - /// @brief Encode to a wire format or estimate wire format - template - size_t - wireEncode(EncodingImpl& encoder) const; - - /// @brief Encode to a wire format - const Block& - wireEncode() const; - - /// @brief Decode from a wire format - void - wireDecode(const Block& wire); - -public: // EqualityComparable concept - bool - operator==(const SignatureInfo& rhs) const; - - bool - operator!=(const SignatureInfo& rhs) const - { - return !(*this == rhs); - } - -private: - int32_t m_type; - bool m_hasKeyLocator; - KeyLocator m_keyLocator; - std::list m_otherTlvs; - - mutable Block m_wire; -}; - -} // namespace ndn - -#endif // NDN_SIGNATURE_INFO_HPP diff --git a/src/signature.hpp b/src/signature.hpp deleted file mode 100644 index 362e17255..000000000 --- a/src/signature.hpp +++ /dev/null @@ -1,190 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_SIGNATURE_HPP -#define NDN_SIGNATURE_HPP - -#include "common.hpp" -#include "signature-info.hpp" - -namespace ndn { - -/** - * A Signature is storage for the signature-related information (info and value) in a Data packet. - */ -class Signature -{ -public: - class Error : public tlv::Error - { - public: - explicit - Error(const std::string& what) - : tlv::Error(what) - { - } - }; - - /// @deprecated use tlv::SignatureTypeValue instead. - enum { - Sha256 = tlv::DigestSha256, - Sha256WithRsa = tlv::SignatureSha256WithRsa, - Sha256WithEcdsa = tlv::SignatureSha256WithEcdsa - }; - - Signature() = default; - - explicit - Signature(const Block& info, const Block& value = Block()); - - explicit - Signature(const SignatureInfo& info, const Block& value = Block()); - - operator bool() const - { - return m_info.getSignatureType() != -1; - } - - /** - * @brief Get SignatureInfo in the wire format - */ - const Block& - getInfo() const - { - return m_info.wireEncode(); // will do nothing if wire already exists - } - - /** - * @brief Get SignatureInfo - */ - const SignatureInfo& - getSignatureInfo() const - { - return m_info; - } - - /** - * @brief Set SignatureInfo from a block - * - * @throws tlv::Error if supplied block is not formatted correctly - */ - void - setInfo(const Block& info); - - /** - * @brief Set SignatureInfo - */ - void - setInfo(const SignatureInfo& info) - { - m_info = info; - } - - /** - * @brief Get SignatureValue in the wire format - */ - const Block& - getValue() const - { - m_value.encode(); // will do nothing if wire already exists - return m_value; - } - - /** - * @brief Get SignatureValue from a block - * - * @throws tlv::Error if supplied block has type different from SignatureValue - */ - void - setValue(const Block& value); - - /** - * @brief Get signature type - */ - uint32_t - getType() const - { - return m_info.getSignatureType(); - } - - /** - * @brief Check if SignatureInfo block has a KeyLocator - */ - bool - hasKeyLocator() const - { - return m_info.hasKeyLocator(); - } - - /** - * @brief Get KeyLocator - * - * @throws Signature::Error if KeyLocator does not exist - */ - const KeyLocator& - getKeyLocator() const - { - return m_info.getKeyLocator(); - } - - /** - * @brief Set KeyLocator - */ - void - setKeyLocator(const KeyLocator& keyLocator) - { - m_info.setKeyLocator(keyLocator); - } - - /** - * @brief Unset KeyLocator - * - * Note that specific signature types may provide advisory (non-virtual) override - * to prevent unsetting KeyLocator if it is required by the specification. - */ - void - unsetKeyLocator() - { - m_info.unsetKeyLocator(); - } - -public: // EqualityComparable concept - bool - operator==(const Signature& other) const - { - return getInfo() == other.getInfo() && - getValue() == other.getValue(); - } - - bool - operator!=(const Signature& other) const - { - return !(*this == other); - } - -protected: - SignatureInfo m_info; - mutable Block m_value; -}; - -} // namespace ndn - -#endif // NDN_SIGNATURE_HPP diff --git a/src/transport/stream-transport-impl.hpp b/src/transport/stream-transport-impl.hpp deleted file mode 100644 index d542741a9..000000000 --- a/src/transport/stream-transport-impl.hpp +++ /dev/null @@ -1,281 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_TRANSPORT_STREAM_TRANSPORT_IMPL_HPP -#define NDN_TRANSPORT_STREAM_TRANSPORT_IMPL_HPP - -#include "transport.hpp" - -#include -#include - -namespace ndn { - -/** \brief implementation detail of a Boost.Asio-based stream-oriented transport - * \tparam BaseTransport a subclass of Transport - * \tparam Protocol a Boost.Asio stream-oriented protocol, including boost::asio::ip::tcp - * and boost::asio::local::stream_protocol - */ -template -class StreamTransportImpl : public enable_shared_from_this> -{ -public: - typedef StreamTransportImpl Impl; - typedef std::list BlockSequence; - typedef std::list TransmissionQueue; - - StreamTransportImpl(BaseTransport& transport, boost::asio::io_service& ioService) - : m_transport(transport) - , m_socket(ioService) - , m_inputBufferSize(0) - , m_isConnecting(false) - , m_connectTimer(ioService) - { - } - - void - connect(const typename Protocol::endpoint& endpoint) - { - if (!m_isConnecting) { - m_isConnecting = true; - - // Wait at most 4 seconds to connect - /// @todo Decide whether this number should be configurable - m_connectTimer.expires_from_now(boost::posix_time::seconds(4)); - m_connectTimer.async_wait(bind(&Impl::connectTimeoutHandler, this->shared_from_this(), _1)); - - m_socket.open(); - m_socket.async_connect(endpoint, bind(&Impl::connectHandler, this->shared_from_this(), _1)); - } - } - - void - close() - { - m_isConnecting = false; - - boost::system::error_code error; // to silently ignore all errors - m_connectTimer.cancel(error); - m_socket.cancel(error); - m_socket.close(error); - - m_transport.m_isConnected = false; - m_transport.m_isReceiving = false; - m_transmissionQueue.clear(); - } - - void - pause() - { - if (m_isConnecting) - return; - - if (m_transport.m_isReceiving) { - m_transport.m_isReceiving = false; - m_socket.cancel(); - } - } - - void - resume() - { - if (m_isConnecting) - return; - - if (!m_transport.m_isReceiving) { - m_transport.m_isReceiving = true; - m_inputBufferSize = 0; - asyncReceive(); - } - } - - void - send(const Block& wire) - { - BlockSequence sequence; - sequence.push_back(wire); - send(std::move(sequence)); - } - - void - send(const Block& header, const Block& payload) - { - BlockSequence sequence; - sequence.push_back(header); - sequence.push_back(payload); - send(std::move(sequence)); - } - -protected: - void - connectHandler(const boost::system::error_code& error) - { - m_isConnecting = false; - m_connectTimer.cancel(); - - if (!error) { - resume(); - m_transport.m_isConnected = true; - - if (!m_transmissionQueue.empty()) { - asyncWrite(); - } - } - else { - m_transport.m_isConnected = false; - m_transport.close(); - BOOST_THROW_EXCEPTION(Transport::Error(error, "error while connecting to the forwarder")); - } - } - - void - connectTimeoutHandler(const boost::system::error_code& error) - { - if (error) // e.g., cancelled timer - return; - - m_transport.close(); - BOOST_THROW_EXCEPTION(Transport::Error(error, "error while connecting to the forwarder")); - } - - void - send(BlockSequence&& sequence) - { - m_transmissionQueue.emplace_back(sequence); - - if (m_transport.m_isConnected && m_transmissionQueue.size() == 1) { - asyncWrite(); - } - - // if not connected or there is transmission in progress (m_transmissionQueue.size() > 1), - // next write will be scheduled either in connectHandler or in asyncWriteHandler - } - - void - asyncWrite() - { - BOOST_ASSERT(!m_transmissionQueue.empty()); - boost::asio::async_write(m_socket, m_transmissionQueue.front(), - bind(&Impl::handleAsyncWrite, this->shared_from_this(), _1, m_transmissionQueue.begin())); - } - - void - handleAsyncWrite(const boost::system::error_code& error, TransmissionQueue::iterator queueItem) - { - if (error) { - if (error == boost::system::errc::operation_canceled) { - // async receive has been explicitly cancelled (e.g., socket close) - return; - } - - m_transport.close(); - BOOST_THROW_EXCEPTION(Transport::Error(error, "error while sending data to socket")); - } - - if (!m_transport.m_isConnected) { - return; // queue has been already cleared - } - - m_transmissionQueue.erase(queueItem); - - if (!m_transmissionQueue.empty()) { - asyncWrite(); - } - } - - void - asyncReceive() - { - m_socket.async_receive(boost::asio::buffer(m_inputBuffer + m_inputBufferSize, - MAX_NDN_PACKET_SIZE - m_inputBufferSize), 0, - bind(&Impl::handleAsyncReceive, this->shared_from_this(), _1, _2)); - } - - void - handleAsyncReceive(const boost::system::error_code& error, std::size_t nBytesRecvd) - { - if (error) { - if (error == boost::system::errc::operation_canceled) { - // async receive has been explicitly cancelled (e.g., socket close) - return; - } - - m_transport.close(); - BOOST_THROW_EXCEPTION(Transport::Error(error, "error while receiving data from socket")); - } - - m_inputBufferSize += nBytesRecvd; - // do magic - - std::size_t offset = 0; - bool hasProcessedSome = processAllReceived(m_inputBuffer, offset, m_inputBufferSize); - if (!hasProcessedSome && m_inputBufferSize == MAX_NDN_PACKET_SIZE && offset == 0) { - m_transport.close(); - BOOST_THROW_EXCEPTION(Transport::Error(boost::system::error_code(), - "input buffer full, but a valid TLV cannot be " - "decoded")); - } - - if (offset > 0) { - if (offset != m_inputBufferSize) { - std::copy(m_inputBuffer + offset, m_inputBuffer + m_inputBufferSize, m_inputBuffer); - m_inputBufferSize -= offset; - } - else { - m_inputBufferSize = 0; - } - } - - asyncReceive(); - } - - bool - processAllReceived(uint8_t* buffer, size_t& offset, size_t nBytesAvailable) - { - while (offset < nBytesAvailable) { - bool isOk = false; - Block element; - std::tie(isOk, element) = Block::fromBuffer(buffer + offset, nBytesAvailable - offset); - if (!isOk) - return false; - - m_transport.receive(element); - offset += element.size(); - } - return true; - } - -protected: - BaseTransport& m_transport; - - typename Protocol::socket m_socket; - uint8_t m_inputBuffer[MAX_NDN_PACKET_SIZE]; - size_t m_inputBufferSize; - - TransmissionQueue m_transmissionQueue; - bool m_isConnecting; - - boost::asio::deadline_timer m_connectTimer; -}; - -} // namespace ndn - -#endif // NDN_TRANSPORT_STREAM_TRANSPORT_IMPL_HPP diff --git a/src/transport/stream-transport-with-resolver-impl.hpp b/src/transport/stream-transport-with-resolver-impl.hpp deleted file mode 100644 index ede844415..000000000 --- a/src/transport/stream-transport-with-resolver-impl.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_TRANSPORT_STREAM_TRANSPORT_WITH_RESOLVER_IMPL_HPP -#define NDN_TRANSPORT_STREAM_TRANSPORT_WITH_RESOLVER_IMPL_HPP - -#include "stream-transport-impl.hpp" - -namespace ndn { - -/** \brief implementation detail of a Boost.Asio-based stream-oriented transport - * with resolver support - */ -template -class StreamTransportWithResolverImpl : public StreamTransportImpl -{ -public: - typedef StreamTransportWithResolverImpl Impl; - - StreamTransportWithResolverImpl(BaseTransport& transport, boost::asio::io_service& ioService) - : StreamTransportImpl(transport, ioService) - { - } - - void - connect(const typename Protocol::resolver::query& query) - { - if (this->m_isConnecting) { - return; - } - - this->m_isConnecting = true; - - // Wait at most 4 seconds to connect - /// @todo Decide whether this number should be configurable - this->m_connectTimer.expires_from_now(boost::posix_time::seconds(4)); - this->m_connectTimer.async_wait(bind(&Impl::connectTimeoutHandler, this->shared_from_this(), _1)); - - // typename boost::asio::ip::basic_resolver< Protocol > resolver; - auto resolver = make_shared(ref(this->m_socket.get_io_service())); - resolver->async_resolve(query, bind(&Impl::resolveHandler, this->shared_from_base(), _1, _2, resolver)); - } - -protected: - void - resolveHandler(const boost::system::error_code& error, - typename Protocol::resolver::iterator endpoint, - const shared_ptr&) - { - if (error) { - if (error == boost::system::errc::operation_canceled) - return; - - BOOST_THROW_EXCEPTION(Transport::Error(error, "Error during resolution of host or port")); - } - - typename Protocol::resolver::iterator end; - if (endpoint == end) { - this->m_transport.close(); - BOOST_THROW_EXCEPTION(Transport::Error(error, "Unable to resolve because host or port")); - } - - this->m_socket.async_connect(*endpoint, bind(&Impl::connectHandler, this->shared_from_this(), _1)); - } - -private: - shared_ptr - shared_from_base() - { - return static_pointer_cast(this->shared_from_this()); - } -}; - - -} // namespace ndn - -#endif // NDN_TRANSPORT_STREAM_TRANSPORT_WITH_RESOLVER_IMPL_HPP diff --git a/src/transport/tcp-transport.cpp b/src/transport/tcp-transport.cpp deleted file mode 100644 index 343ddd29e..000000000 --- a/src/transport/tcp-transport.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "tcp-transport.hpp" -#include "stream-transport-with-resolver-impl.hpp" -#include "util/face-uri.hpp" - -namespace ndn { - -TcpTransport::TcpTransport(const std::string& host, const std::string& port/* = "6363"*/) - : m_host(host) - , m_port(port) -{ -} - -TcpTransport::~TcpTransport() = default; - -shared_ptr -TcpTransport::create(const std::string& uri) -{ - const auto hostAndPort(getSocketHostAndPortFromUri(uri)); - return make_shared(hostAndPort.first, hostAndPort.second); -} - -std::pair -TcpTransport::getSocketHostAndPortFromUri(const std::string& uriString) -{ - std::string host = "localhost"; - std::string port = "6363"; - - if (uriString.empty()) { - return {host, port}; - } - - try { - const util::FaceUri uri(uriString); - - const std::string scheme = uri.getScheme(); - if (scheme != "tcp" && scheme != "tcp4" && scheme != "tcp6") { - BOOST_THROW_EXCEPTION(Error("Cannot create TcpTransport from \"" + scheme + "\" URI")); - } - - if (!uri.getHost().empty()) { - host = uri.getHost(); - } - - if (!uri.getPort().empty()) { - port = uri.getPort(); - } - } - catch (const util::FaceUri::Error& error) { - BOOST_THROW_EXCEPTION(Error(error.what())); - } - - return {host, port}; -} - -void -TcpTransport::connect(boost::asio::io_service& ioService, - const ReceiveCallback& receiveCallback) -{ - if (m_impl == nullptr) { - Transport::connect(ioService, receiveCallback); - - m_impl = make_shared(ref(*this), ref(ioService)); - } - - boost::asio::ip::tcp::resolver::query query(m_host, m_port); - m_impl->connect(query); -} - -void -TcpTransport::send(const Block& wire) -{ - BOOST_ASSERT(m_impl != nullptr); - m_impl->send(wire); -} - -void -TcpTransport::send(const Block& header, const Block& payload) -{ - BOOST_ASSERT(m_impl != nullptr); - m_impl->send(header, payload); -} - -void -TcpTransport::close() -{ - BOOST_ASSERT(m_impl != nullptr); - m_impl->close(); - m_impl.reset(); -} - -void -TcpTransport::pause() -{ - if (m_impl != nullptr) { - m_impl->pause(); - } -} - -void -TcpTransport::resume() -{ - BOOST_ASSERT(m_impl != nullptr); - m_impl->resume(); -} - -} // namespace ndn diff --git a/src/transport/tcp-transport.hpp b/src/transport/tcp-transport.hpp deleted file mode 100644 index eb7878bb0..000000000 --- a/src/transport/tcp-transport.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_TRANSPORT_TCP_TRANSPORT_HPP -#define NDN_TRANSPORT_TCP_TRANSPORT_HPP - -#include "transport.hpp" -#include "../util/config-file.hpp" - -namespace boost { -namespace asio { -namespace ip { -class tcp; -} // namespace ip -} // namespace asio -} // namespace boost - -namespace ndn { - -template -class StreamTransportImpl; - -template -class StreamTransportWithResolverImpl; - -/** \brief a transport using TCP socket - */ -class TcpTransport : public Transport -{ -public: - explicit - TcpTransport(const std::string& host, const std::string& port = "6363"); - - ~TcpTransport(); - - virtual void - connect(boost::asio::io_service& ioService, - const ReceiveCallback& receiveCallback) override; - - virtual void - close() override; - - virtual void - pause() override; - - virtual void - resume() override; - - virtual void - send(const Block& wire) override; - - virtual void - send(const Block& header, const Block& payload) override; - - /** \brief Create transport with parameters defined in URI - * \throw Transport::Error incorrect URI or unsupported protocol is specified - */ - static shared_ptr - create(const std::string& uri); - -NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: - static std::pair - getSocketHostAndPortFromUri(const std::string& uri); - -private: - std::string m_host; - std::string m_port; - - typedef StreamTransportWithResolverImpl Impl; - friend class StreamTransportImpl; - friend class StreamTransportWithResolverImpl; - shared_ptr m_impl; -}; - -} // namespace ndn - -#endif // NDN_TRANSPORT_TCP_TRANSPORT_HPP diff --git a/src/transport/transport.cpp b/src/transport/transport.cpp deleted file mode 100644 index 0ea5beeab..000000000 --- a/src/transport/transport.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "transport.hpp" - -namespace ndn { - -Transport::Error::Error(const boost::system::error_code& code, const std::string& msg) - : std::runtime_error(msg + (code.value() ? " (" + code.category().message(code.value()) + ")" : "")) -{ -} - -Transport::Error::Error(const std::string& msg) - : std::runtime_error(msg) -{ -} - -Transport::Transport() - : m_ioService(nullptr) - , m_isConnected(false) - , m_isReceiving(false) -{ -} - -void -Transport::connect(boost::asio::io_service& ioService, - const ReceiveCallback& receiveCallback) -{ - BOOST_ASSERT(receiveCallback != nullptr); - - m_ioService = &ioService; - m_receiveCallback = receiveCallback; -} - -} // namespace ndn diff --git a/src/transport/transport.hpp b/src/transport/transport.hpp deleted file mode 100644 index f656802f0..000000000 --- a/src/transport/transport.hpp +++ /dev/null @@ -1,147 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_TRANSPORT_TRANSPORT_HPP -#define NDN_TRANSPORT_TRANSPORT_HPP - -#include "../common.hpp" -#include "../encoding/block.hpp" - -#include - -namespace boost { -namespace asio { -class io_service; -} // namespace asio -} // namespace boost - -namespace ndn { - -/** \brief provides TLV-block delivery service - */ -class Transport : noncopyable -{ -public: - class Error : public std::runtime_error - { - public: - Error(const boost::system::error_code& code, const std::string& msg); - - explicit - Error(const std::string& msg); - }; - - typedef function ReceiveCallback; - typedef function ErrorCallback; - - Transport(); - - virtual - ~Transport() = default; - - /** \brief asynchronously open the connection - * \param ioService io_service to create socket on - * \param receiveCallback callback function when a TLV block is received; must not be empty - * \throw boost::system::system_error connection cannot be established - */ - virtual void - connect(boost::asio::io_service& ioService, const ReceiveCallback& receiveCallback); - - /** \brief Close the connection. - */ - virtual void - close() = 0; - - /** \brief send a TLV block through the transport - */ - virtual void - send(const Block& wire) = 0; - - /** \brief send two memory blocks through the transport - * - * Scatter/gather API is utilized to send two non-consecutive memory blocks together - * (as part of the same message in datagram-oriented transports). - */ - virtual void - send(const Block& header, const Block& payload) = 0; - - /** \brief pause the transport - * \post receiveCallback will not be invoked - * \note This operation has no effect if transport has been paused, - * or when connection is being established. - */ - virtual void - pause() = 0; - - /** \brief resume the transport - * \post receiveCallback will be invoked - * \note This operation has no effect if transport is not paused, - * or when connection is being established. - */ - virtual void - resume() = 0; - - /** \retval true connection has been established - * \retval false connection is not yet established or has been closed - */ - bool - isConnected() const; - - /** \retval true incoming packets are expected, receiveCallback will be invoked - * \retval false incoming packets are not expected, receiveCallback will not be invoked - */ - bool - isReceiving() const; - -protected: - /** \brief invoke the receive callback - */ - void - receive(const Block& wire); - -protected: - boost::asio::io_service* m_ioService; - bool m_isConnected; - bool m_isReceiving; - ReceiveCallback m_receiveCallback; -}; - -inline bool -Transport::isConnected() const -{ - return m_isConnected; -} - -inline bool -Transport::isReceiving() const -{ - return m_isReceiving; -} - -inline void -Transport::receive(const Block& wire) -{ - m_receiveCallback(wire); -} - -} // namespace ndn - -#endif // NDN_TRANSPORT_TRANSPORT_HPP diff --git a/src/transport/unix-transport.cpp b/src/transport/unix-transport.cpp deleted file mode 100644 index f2e44aa22..000000000 --- a/src/transport/unix-transport.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "unix-transport.hpp" -#include "stream-transport-impl.hpp" - -#include "../face.hpp" -#include "util/face-uri.hpp" - -namespace ndn { - -UnixTransport::UnixTransport(const std::string& unixSocket) - : m_unixSocket(unixSocket) -{ -} - -UnixTransport::~UnixTransport() -{ -} - -std::string -UnixTransport::getSocketNameFromUri(const std::string& uriString) -{ - // Assume the default nfd.sock location. - std::string path = "/var/run/nfd.sock"; - - if (uriString.empty()) { - return path; - } - - try { - const util::FaceUri uri(uriString); - - if (uri.getScheme() != "unix") { - BOOST_THROW_EXCEPTION(Error("Cannot create UnixTransport from \"" + - uri.getScheme() + "\" URI")); - } - - if (!uri.getPath().empty()) { - path = uri.getPath(); - } - } - catch (const util::FaceUri::Error& error) { - BOOST_THROW_EXCEPTION(Error(error.what())); - } - - return path; -} - -shared_ptr -UnixTransport::create(const std::string& uri) -{ - return make_shared(getSocketNameFromUri(uri)); -} - -void -UnixTransport::connect(boost::asio::io_service& ioService, - const ReceiveCallback& receiveCallback) -{ - if (m_impl == nullptr) { - Transport::connect(ioService, receiveCallback); - - m_impl = make_shared(ref(*this), ref(ioService)); - } - - m_impl->connect(boost::asio::local::stream_protocol::endpoint(m_unixSocket)); -} - -void -UnixTransport::send(const Block& wire) -{ - BOOST_ASSERT(m_impl != nullptr); - m_impl->send(wire); -} - -void -UnixTransport::send(const Block& header, const Block& payload) -{ - BOOST_ASSERT(m_impl != nullptr); - m_impl->send(header, payload); -} - -void -UnixTransport::close() -{ - BOOST_ASSERT(m_impl != nullptr); - m_impl->close(); - m_impl.reset(); -} - -void -UnixTransport::pause() -{ - if (m_impl != nullptr) { - m_impl->pause(); - } -} - -void -UnixTransport::resume() -{ - BOOST_ASSERT(m_impl != nullptr); - m_impl->resume(); -} - -} // namespace ndn diff --git a/src/transport/unix-transport.hpp b/src/transport/unix-transport.hpp deleted file mode 100644 index 99d868839..000000000 --- a/src/transport/unix-transport.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_TRANSPORT_UNIX_TRANSPORT_HPP -#define NDN_TRANSPORT_UNIX_TRANSPORT_HPP - -#include "transport.hpp" -#include "../util/config-file.hpp" - -namespace boost { -namespace asio { -namespace local { -class stream_protocol; -} // namespace local -} // namespace asio -} // namespace boost - -namespace ndn { - -template -class StreamTransportImpl; - -/** \brief a transport using Unix stream socket - */ -class UnixTransport : public Transport -{ -public: - explicit - UnixTransport(const std::string& unixSocket); - - ~UnixTransport(); - - virtual void - connect(boost::asio::io_service& ioService, - const ReceiveCallback& receiveCallback) override; - - virtual void - close() override; - - virtual void - pause() override; - - virtual void - resume() override; - - virtual void - send(const Block& wire) override; - - virtual void - send(const Block& header, const Block& payload) override; - - /** \brief Create transport with parameters defined in URI - * \throw Transport::Error if incorrect URI or unsupported protocol is specified - */ - static shared_ptr - create(const std::string& uri); - -NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: - static std::string - getSocketNameFromUri(const std::string& uri); - -private: - std::string m_unixSocket; - - typedef StreamTransportImpl Impl; - friend class StreamTransportImpl; - shared_ptr m_impl; -}; - -} // namespace ndn - -#endif // NDN_TRANSPORT_UNIX_TRANSPORT_HPP diff --git a/src/util/backports-optional.hpp b/src/util/backports-optional.hpp deleted file mode 100644 index c93e855a8..000000000 --- a/src/util/backports-optional.hpp +++ /dev/null @@ -1,309 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * \brief C++17 std::optional backport implemented using boost::optional - * \sa http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/n4594.pdf section 20.6 - * \sa http://en.cppreference.com/w/cpp/utility/optional - * - * Differences from C++17 include: - * \li No constructor and operator= taking a T&&, - * because boost::optional lacks a move constructor as of Boost 1.54 - * \li No constructor, operator=, emplace, and make_optional with std::initializer_list - * \li In-place constructor and emplace require copyable arguments, - * because boost::in_place requires such - * \li Move constructor may or may not exist (it's implicitly defined when available), - * because boost::optional lacks a move constructor as of Boost 1.54 - * \li Non-const operator-> and operator* are not constexpr - * \li value() is not constexpr - * \li swap is declared without noexcept specification - * \li No comparison operators with const T& or nullopt_t - * \li No specialized std::hash support - */ - -#ifndef NDN_UTIL_BACKPORTS_OPTIONAL_HPP -#define NDN_UTIL_BACKPORTS_OPTIONAL_HPP - -#include "../common.hpp" - -#include -#include -#include - -namespace ndn { - -template -class optional; - -struct in_place_t -{ -}; -constexpr in_place_t in_place{}; - -class nullopt_t -{ -public: - constexpr explicit - nullopt_t(int) - { - } -}; -constexpr nullopt_t nullopt(0); - -#if BOOST_VERSION >= 105600 -using boost::bad_optional_access; -#else -class bad_optional_access : public std::logic_error -{ -public: - bad_optional_access() - : std::logic_error("bad optional access") - { - } -}; -#endif - -template -constexpr bool -operator==(const optional& lhs, const optional& rhs); - -template -constexpr bool -operator!=(const optional& lhs, const optional& rhs); - -template -constexpr bool -operator<(const optional& lhs, const optional& rhs); - -template -constexpr bool -operator<=(const optional& lhs, const optional& rhs); - -template -constexpr bool -operator>(const optional& lhs, const optional& rhs); - -template -constexpr bool -operator>=(const optional& lhs, const optional& rhs); - -template -class optional -{ -public: - static_assert(!std::is_same::type, in_place_t>::value && - !std::is_same::type, nullopt_t>::value && - !std::is_reference::value, - "Invalid instantiation of optional"); - - typedef T value_type; - - constexpr - optional() noexcept - { - } - - constexpr - optional(nullopt_t) noexcept - { - } - - constexpr - optional(const T& value) - : m_boostOptional(value) - { - } - - template - constexpr explicit - optional(in_place_t, Args&&... args) - : m_boostOptional(boost::in_place(std::forward(args)...)) - { - } - - optional& - operator=(nullopt_t) noexcept - { - m_boostOptional = boost::none; - return *this; - } - - optional& - operator=(const optional& other) - { - m_boostOptional = other.m_boostOptional; - return *this; - } - - template::type, T>::value>::type> - optional& - operator=(U&& value) - { - m_boostOptional = std::forward(value); - return *this; - } - -public: // observers - constexpr const T* - operator->() const - { - return m_boostOptional.get_ptr(); - } - - T* - operator->() - { - return m_boostOptional.get_ptr(); - } - - constexpr const T& - operator*() const - { - return m_boostOptional.get(); - } - - T& - operator*() - { - return m_boostOptional.get(); - } - - constexpr explicit - operator bool() const noexcept - { - return static_cast(m_boostOptional); - } - - const T& - value() const - { - return const_cast(this)->value(); - } - - T& - value() - { -#if BOOST_VERSION >= 105600 - return m_boostOptional.value(); -#else - if (!m_boostOptional) { - BOOST_THROW_EXCEPTION(bad_optional_access()); - } - return m_boostOptional.get(); -#endif - } - - template - constexpr T - value_or(U&& default_value) const - { -#if BOOST_VERSION >= 105600 - return m_boostOptional.value_or(default_value); -#else - return m_boostOptional.get_value_or(default_value); -#endif - } - -public: // modifiers - void - swap(optional& other) - { - boost::swap(m_boostOptional, other.m_boostOptional); - } - - template - void - emplace(Args&&... args) - { - m_boostOptional = boost::in_place(std::forward(args)...); - } - -private: - boost::optional m_boostOptional; - - friend bool operator==(const optional&, const optional&); - friend bool operator!=(const optional&, const optional&); - friend bool operator< (const optional&, const optional&); - friend bool operator<=(const optional&, const optional&); - friend bool operator> (const optional&, const optional&); - friend bool operator>=(const optional&, const optional&); -}; - -template -constexpr bool -operator==(const optional& lhs, const optional& rhs) -{ - return operator==(lhs.m_boostOptional, rhs.m_boostOptional); -} - -template -constexpr bool -operator!=(const optional& lhs, const optional& rhs) -{ - return operator!=(lhs.m_boostOptional, rhs.m_boostOptional); -} - -template -constexpr bool -operator<(const optional& lhs, const optional& rhs) -{ - return operator<(lhs.m_boostOptional, rhs.m_boostOptional); -} - -template -constexpr bool -operator<=(const optional& lhs, const optional& rhs) -{ - return operator<=(lhs.m_boostOptional, rhs.m_boostOptional); -} - -template -constexpr bool -operator>(const optional& lhs, const optional& rhs) -{ - return operator>(lhs.m_boostOptional, rhs.m_boostOptional); -} - -template -constexpr bool -operator>=(const optional& lhs, const optional& rhs) -{ - return operator>=(lhs.m_boostOptional, rhs.m_boostOptional); -} - -template -constexpr optional::type> -make_optional(T&& value) -{ - return optional::type>(std::forward(value)); -} - -template -constexpr optional -make_optional(Args&&... args) -{ - return optional(in_place, std::forward(args)...); -} - -} // namespace ndn - -#endif // NDN_UTIL_BACKPORTS_OPTIONAL_HPP diff --git a/src/util/backports.hpp b/src/util/backports.hpp deleted file mode 100644 index acb03e646..000000000 --- a/src/util/backports.hpp +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2015-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_BACKPORTS_HPP -#define NDN_UTIL_BACKPORTS_HPP - -#include "../common.hpp" - -#ifndef NDN_CXX_HAVE_STD_TO_STRING -#include -#endif - -#include - -namespace ndn { - -#if __cpp_lib_make_unique -using std::make_unique; -#else -template -inline unique_ptr -make_unique(Args&&... args) -{ - return unique_ptr(new T(std::forward(args)...)); -} -#endif // __cpp_lib_make_unique - -#ifdef NDN_CXX_HAVE_STD_TO_STRING -using std::to_string; -#else -template -inline std::string -to_string(const V& v) -{ - return boost::lexical_cast(v); -} -#endif // NDN_CXX_HAVE_STD_TO_STRING - -#if __cpp_lib_clamp >= 201603 -using std::clamp; -#else -template -constexpr const T& -clamp(const T& v, const T& lo, const T& hi, Compare comp) -{ - return comp(v, lo) ? lo : comp(hi, v) ? hi : v; -} - -template -constexpr const T& -clamp(const T& v, const T& lo, const T& hi) -{ - return (v < lo) ? lo : (hi < v) ? hi : v; -} -#endif // __cpp_lib_clamp - -} // namespace ndn - -#include "backports-optional.hpp" - -#endif // NDN_UTIL_BACKPORTS_HPP diff --git a/src/util/concepts.hpp b/src/util/concepts.hpp deleted file mode 100644 index 8d4567ef0..000000000 --- a/src/util/concepts.hpp +++ /dev/null @@ -1,101 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_CONCEPTS_HPP -#define NDN_UTIL_CONCEPTS_HPP - -#include -#include "../encoding/block.hpp" -#include "../encoding/encoding-buffer.hpp" - -namespace ndn { - -/** \brief a concept check for TLV abstraction with .wireEncode method - */ -template -class WireEncodable -{ -public: - BOOST_CONCEPT_USAGE(WireEncodable) - { - Block block = j.wireEncode(); - block.size(); // avoid 'unused variable block' - } - -private: - X j; -}; - -/** \brief a concept check for TLV abstraction with .wireEncode method - */ -template -class WireEncodableWithEncodingBuffer -{ -public: - BOOST_CONCEPT_USAGE(WireEncodableWithEncodingBuffer) - { - EncodingEstimator estimator; - size_t estimatedSize = j.wireEncode(estimator); - - EncodingBuffer encoder(estimatedSize, 0); - j.wireEncode(encoder); - } - -private: - X j; -}; - -/** \brief a concept check for TLV abstraction with .wireDecode method - * and constructible from Block - */ -template -class WireDecodable -{ -public: - BOOST_CONCEPT_USAGE(WireDecodable) - { - Block block; - X j(block); - j.wireDecode(block); - } -}; - -/** \brief a concept check for CryptoPP hash algorithm - */ -template -class Hashable -{ -public: - BOOST_CONCEPT_USAGE(Hashable) - { - X hash; - uint8_t* buf = 0; - size_t size = hash.DigestSize(); - - hash.Update(buf, size); - hash.Final(buf); - hash.Restart(); - } -}; - -} // namespace ndn - -#endif // NDN_UTIL_CONCEPTS_HPP diff --git a/src/util/config-file.cpp b/src/util/config-file.cpp deleted file mode 100644 index aa467a21e..000000000 --- a/src/util/config-file.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "config-file.hpp" - -#include -#include - -namespace ndn { - -ConfigFile::ConfigFile() - : m_path(findConfigFile()) -{ - if (open()) - { - parse(); - close(); - } -} - -ConfigFile::~ConfigFile() -{ - if (m_input.is_open()) - { - m_input.close(); - } -} - -boost::filesystem::path -ConfigFile::findConfigFile() -{ - using namespace boost::filesystem; - -#ifdef NDN_CXX_HAVE_TESTS - if (std::getenv("TEST_HOME")) - { - path testHome(std::getenv("TEST_HOME")); - testHome /= ".ndn/client.conf"; - if (exists(testHome)) - { - return absolute(testHome); - } - } -#endif // NDN_CXX_HAVE_TESTS - - if (std::getenv("HOME")) - { - path home(std::getenv("HOME")); - home /= ".ndn/client.conf"; - if (exists(home)) - { - return absolute(home); - } - } - -#ifdef NDN_CXX_SYSCONFDIR - path sysconfdir(NDN_CXX_SYSCONFDIR); - sysconfdir /= "ndn/client.conf"; - - if (exists(sysconfdir)) - { - return absolute(sysconfdir); - } -#endif // NDN_CXX_SYSCONFDIR - - path etc("/etc/ndn/client.conf"); - if (exists(etc)) - { - return absolute(etc); - } - - return path(); -} - - - -bool -ConfigFile::open() -{ - if (m_path.empty()) - { - return false; - } - - m_input.open(m_path.c_str()); - if (!m_input.good() || !m_input.is_open()) - { - return false; - } - return true; -} - -void -ConfigFile::close() -{ - if (m_input.is_open()) - { - m_input.close(); - } -} - - -const ConfigFile::Parsed& -ConfigFile::parse() -{ - if (m_path.empty()) - { - BOOST_THROW_EXCEPTION(Error("Failed to locate configuration file for parsing")); - } - else if (!m_input.is_open() && !open()) - { - BOOST_THROW_EXCEPTION(Error("Failed to open configuration file for parsing")); - } - - try - { - boost::property_tree::read_ini(m_input, m_config); - } - catch (boost::property_tree::ini_parser_error& error) - { - std::stringstream msg; - msg << "Failed to parse configuration file"; - msg << " " << m_path; - msg << " " << error.message() << " line " << error.line(); - BOOST_THROW_EXCEPTION(Error(msg.str())); - } - return m_config; -} - -} diff --git a/src/util/crypto.cpp b/src/util/crypto.cpp deleted file mode 100644 index 1e22c0e08..000000000 --- a/src/util/crypto.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "crypto.hpp" -#include "../encoding/buffer-stream.hpp" - -#include "../security/v1/cryptopp.hpp" - -namespace ndn { -namespace crypto { - -ConstBufferPtr -computeSha256Digest(const uint8_t* data, size_t dataLength) -{ - try { - CryptoPP::SHA256 hash; - OBufferStream os; - CryptoPP::StringSource(data, dataLength, true, - new CryptoPP::HashFilter(hash, new CryptoPP::FileSink(os))); - return os.buf(); - } - catch (CryptoPP::Exception& e) { - return ConstBufferPtr(); - } -} - -} // namespace crypto -} // namespace ndn diff --git a/src/util/crypto.hpp b/src/util/crypto.hpp deleted file mode 100644 index e406006df..000000000 --- a/src/util/crypto.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_CRYPTO_HPP -#define NDN_UTIL_CRYPTO_HPP - -#include "../common.hpp" -#include "../encoding/buffer.hpp" - -namespace ndn { -namespace crypto { - -/// @brief number of octets in a SHA256 digest -static const size_t SHA256_DIGEST_SIZE = 32; - -/** - * @brief Compute the sha-256 digest of data. - * - * @param data Pointer to the input byte array. - * @param dataLength The length of data. - * @return A pointer to a buffer of SHA256_DIGEST. - */ -ConstBufferPtr -computeSha256Digest(const uint8_t* data, size_t dataLength); - -/** - * @brief Compute the sha-256 digest of data. - * - * @deprecated Use computeSha256Digest function instead - */ -inline ConstBufferPtr -sha256(const uint8_t* data, size_t dataLength) -{ - return computeSha256Digest(data, dataLength); -} - -} // namespace crypto - -} // namespace ndn - -#endif // NDN_UTIL_CRYPTO_HPP diff --git a/src/util/detail/network-monitor-impl-osx.cpp b/src/util/detail/network-monitor-impl-osx.cpp deleted file mode 100644 index bfa38775f..000000000 --- a/src/util/detail/network-monitor-impl-osx.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * - * Parts of this implementation is based on daemondo command of MacPorts - * (https://www.macports.org/): - * - * Copyright (c) 2005-2007 James Berry - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of The MacPorts Project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "ndn-cxx-config.hpp" - -#ifdef NDN_CXX_HAVE_COREFOUNDATION_COREFOUNDATION_H - -#include "network-monitor-impl-osx.hpp" - -namespace ndn { -namespace util { - -NetworkMonitor::Impl::Impl(NetworkMonitor& nm, boost::asio::io_service& io) - : m_nm(nm) - , m_scheduler(io) - , m_cfLoopEvent(m_scheduler) -{ - scheduleCfLoop(); - - // Potentially useful System Configuration regex patterns: - // - // State:/Network/Interface/.*/Link - // State:/Network/Interface/.*/IPv4 - // State:/Network/Interface/.*/IPv6 - // - // State:/Network/Global/DNS - // State:/Network/Global/IPv4 - // - // Potentially useful notifications from Darwin Notify Center: - // - // com.apple.system.config.network_change - // - CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), - static_cast(this), - &Impl::afterNotificationCenterEvent, - CFSTR("com.apple.system.config.network_change"), - nullptr, // object to observe - CFNotificationSuspensionBehaviorDeliverImmediately); -} - -NetworkMonitor::Impl::~Impl() -{ - CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDarwinNotifyCenter(), - static_cast(this)); -} - -void -NetworkMonitor::Impl::afterNotificationCenterEvent(CFNotificationCenterRef center, - void *observer, - CFStringRef name, - const void *object, - CFDictionaryRef userInfo) -{ - static_cast(observer)->m_nm.onNetworkStateChanged(); -} - -void -NetworkMonitor::Impl::scheduleCfLoop() -{ - // poll each second for new events - m_cfLoopEvent = m_scheduler.scheduleEvent(time::seconds(1), bind(&Impl::pollCfLoop, this)); -} - -void -NetworkMonitor::Impl::pollCfLoop() -{ - // this should dispatch ready events and exit - CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); - - scheduleCfLoop(); -} - -} // namespace util -} // namespace ndn - -#endif // NDN_CXX_HAVE_COREFOUNDATION_COREFOUNDATION_H diff --git a/src/util/detail/network-monitor-impl-osx.hpp b/src/util/detail/network-monitor-impl-osx.hpp deleted file mode 100644 index 4015a787c..000000000 --- a/src/util/detail/network-monitor-impl-osx.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_NETWORK_MONITOR_IMPL_OSX_HPP -#define NDN_UTIL_NETWORK_MONITOR_IMPL_OSX_HPP - -#include "../network-monitor.hpp" - -#include "../scheduler.hpp" -#include "../scheduler-scoped-event-id.hpp" - -#include -#include - -namespace ndn { -namespace util { - -class NetworkMonitor::Impl -{ -public: - Impl(NetworkMonitor& nm, boost::asio::io_service& io); - - ~Impl(); - - static void - afterNotificationCenterEvent(CFNotificationCenterRef center, - void *observer, - CFStringRef name, - const void *object, - CFDictionaryRef userInfo); - -private: - void - scheduleCfLoop(); - - void - pollCfLoop(); - -private: - NetworkMonitor& m_nm; - - Scheduler m_scheduler; - scheduler::ScopedEventId m_cfLoopEvent; -}; - -} // namespace util -} // namespace ndn - -#endif // NDN_UTIL_NETWORK_MONITOR_IMPL_OSX_HPP diff --git a/src/util/detail/network-monitor-impl-rtnl.cpp b/src/util/detail/network-monitor-impl-rtnl.cpp deleted file mode 100644 index 36c9190da..000000000 --- a/src/util/detail/network-monitor-impl-rtnl.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "ndn-cxx-config.hpp" - -#ifdef NDN_CXX_HAVE_RTNETLINK - -#include "network-monitor-impl-rtnl.hpp" - -#include -#include -#include -#include - -#include -#include - -namespace ndn { -namespace util { - -NetworkMonitor::Impl::Impl(NetworkMonitor& nm, boost::asio::io_service& io) - : m_nm(nm) - , m_socket(io) -{ - int fd = ::socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (fd < 0) - BOOST_THROW_EXCEPTION(Error(std::string("Cannot create netlink socket (") + - std::strerror(errno) + ")")); - - sockaddr_nl addr{}; - addr.nl_family = AF_NETLINK; - addr.nl_groups = RTMGRP_LINK | - RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | - RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE; - - if (::bind(fd, reinterpret_cast(&addr), sizeof(addr)) == -1) { - BOOST_THROW_EXCEPTION(Error(std::string("Cannot bind on netlink socket (") + - std::strerror(errno) + ")")); - } - - m_socket.assign(fd); - - m_socket.async_read_some(boost::asio::buffer(m_buffer, NETLINK_BUFFER_SIZE), - bind(&Impl::onReceiveRtNetlink, this, _1, _2)); -} - -void -NetworkMonitor::Impl::onReceiveRtNetlink(const boost::system::error_code& error, size_t nBytesReceived) -{ - if (error) { - return; - } - - const nlmsghdr* nlh = reinterpret_cast(m_buffer); - while ((NLMSG_OK(nlh, nBytesReceived)) && (nlh->nlmsg_type != NLMSG_DONE)) { - if (nlh->nlmsg_type == RTM_NEWADDR || nlh->nlmsg_type == RTM_DELADDR || - nlh->nlmsg_type == RTM_NEWLINK || nlh->nlmsg_type == RTM_DELLINK || - nlh->nlmsg_type == RTM_NEWROUTE || nlh->nlmsg_type == RTM_DELROUTE) { - m_nm.onNetworkStateChanged(); - break; - } - nlh = NLMSG_NEXT(nlh, nBytesReceived); - } - - m_socket.async_read_some(boost::asio::buffer(m_buffer, NETLINK_BUFFER_SIZE), - bind(&Impl::onReceiveRtNetlink, this, _1, _2)); -} - -} // namespace util -} // namespace ndn - -#endif // NDN_CXX_HAVE_RTNETLINK diff --git a/src/util/detail/network-monitor-impl-rtnl.hpp b/src/util/detail/network-monitor-impl-rtnl.hpp deleted file mode 100644 index 141554db3..000000000 --- a/src/util/detail/network-monitor-impl-rtnl.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_NETWORK_MONITOR_IMPL_RTNL_HPP -#define NDN_UTIL_NETWORK_MONITOR_IMPL_RTNL_HPP - -#include "../network-monitor.hpp" - -#include - -namespace ndn { -namespace util { - -const size_t NETLINK_BUFFER_SIZE = 4096; - -class NetworkMonitor::Impl -{ -public: - Impl(NetworkMonitor& nm, boost::asio::io_service& io); - -private: - void - onReceiveRtNetlink(const boost::system::error_code& error, size_t nBytesReceived); - -private: - NetworkMonitor& m_nm; - - uint8_t m_buffer[NETLINK_BUFFER_SIZE]; - boost::asio::posix::stream_descriptor m_socket; -}; - -} // namespace util -} // namespace ndn - -#endif // NDN_UTIL_NETWORK_MONITOR_IMPL_RTNL_HPP diff --git a/src/util/digest.cpp b/src/util/digest.cpp deleted file mode 100644 index 67fd7085f..000000000 --- a/src/util/digest.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "digest.hpp" -#include "string-helper.hpp" -#include - -namespace ndn { -namespace util { - -template -Digest::Digest() -{ - reset(); -} - -template -Digest::Digest(std::istream& is) - : m_isInProcess(false) - , m_isFinalized(true) -{ - using namespace CryptoPP; - - m_buffer = make_shared(m_hash.DigestSize()); - FileSource(is, true, - new HashFilter(m_hash, - new ArraySink(m_buffer->get(), m_buffer->size()))); -} - -template -void -Digest::reset() -{ - m_hash.Restart(); - m_buffer = make_shared(m_hash.DigestSize()); - m_isInProcess = false; - m_isFinalized = false; -} - -template -void -Digest::finalize() -{ - // return immediately if Digest is finalized already. - if (m_isFinalized) - return; - - m_hash.Final(m_buffer->get()); - - m_isFinalized = true; -} - -template -ConstBufferPtr -Digest::computeDigest() -{ - finalize(); - return m_buffer; -} - -template -bool -Digest::operator==(Digest& digest) -{ - return *computeDigest() == *digest.computeDigest(); -} - -template -Digest& -Digest::operator<<(Digest& src) -{ - ConstBufferPtr buffer = src.computeDigest(); - update(buffer->get(), buffer->size()); - - return *this; -} - -template -Digest& -Digest::operator<<(const std::string& str) -{ - update(reinterpret_cast(str.c_str()), str.size()); - - return *this; -} - -template -Digest& -Digest::operator<<(const Block& block) -{ - update(block.wire(), block.size()); - - return *this; -} - -template -Digest& -Digest::operator<<(uint64_t value) -{ - update(reinterpret_cast(&value), sizeof(uint64_t)); - - return *this; -} - -template -void -Digest::update(const uint8_t* buffer, size_t size) -{ - // cannot update Digest when it has been finalized - if (m_isFinalized) - BOOST_THROW_EXCEPTION(Error("Digest has been already finalized")); - - m_hash.Update(buffer, size); - - m_isInProcess = true; -} - -template -ConstBufferPtr -Digest::computeDigest(const uint8_t* buffer, size_t size) -{ - Hash hash; - BufferPtr result = make_shared(hash.DigestSize()); - hash.Update(buffer, size); - hash.Final(result->get()); - - return result; -} - -template -std::string -Digest::toString() -{ - std::ostringstream os; - os << *this; - - return os.str(); -} - -template -std::ostream& -operator<<(std::ostream& os, Digest& digest) -{ - ConstBufferPtr buffer = digest.computeDigest(); - printHex(os, buffer->buf(), buffer->size()); - - return os; -} - -template -class Digest; - -template -std::ostream& -operator<<(std::ostream& os, Digest& digest); - - -} // namespace util -} // namespace ndn diff --git a/src/util/digest.hpp b/src/util/digest.hpp deleted file mode 100644 index ce86e1df9..000000000 --- a/src/util/digest.hpp +++ /dev/null @@ -1,216 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_DIGEST_HPP -#define NDN_UTIL_DIGEST_HPP - -#include "../encoding/buffer.hpp" -#include "../encoding/block.hpp" -#include "../security/v1/cryptopp.hpp" -#include "concepts.hpp" - -namespace ndn { -namespace util { - -/** - * @brief provides a digest calculation - * - * Take SHA256 as an example: - * - * Digest digest; - * digest.update(buf1, size1); - * digest.update(buf2, size2); - * ... - * ConstBufferPtr result = digest.computeDigest(); - * - * @sa http://redmine.named-data.net/issues/1934 - */ -template -class Digest -{ -public: - BOOST_CONCEPT_ASSERT((Hashable)); - - typedef Hash HashFunction; - - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - - Digest(); - - /** - * @brief Create digest of the input stream @p is - * @param is input stream - */ - explicit - Digest(std::istream& is); - - /** - * @brief Discard the current state and start a new digest. - */ - void - reset(); - - /** - * @brief Check if digest is empty. - * - * An empty digest means nothing has been taken into calculation. - */ - bool - empty() const - { - return !m_isInProcess; - } - - /** - * @brief Obtain the digest - * - * Note this digest is finalized once this method is invoked. - */ - ConstBufferPtr - computeDigest(); - - /** - * @brief Check if supplied digest equal to this digest - * - * Note that this method will invoke computeDigest(). - * Once this method is invoked, both this digest and the supplied digest are finalized. - * - * @warning This method cannot be used in security related context - * because it is vulnerable to timing attack - */ - bool - operator==(Digest& digest); - - /** - * @brief Check if supplied digest is not equal to this digest - * - * Note that this method will invoke computeDigest(). - * Once this method is invoked, both this digest and the supplied digest are finalized. - * - * @warning This method cannot be used in security related context - * because it is vulnerable to timing attack - */ - bool - operator!=(Digest& digest) - { - return !(*this == digest); - } - - /** - * @brief Add existing digest to digest calculation - * @param src digest to combine with - * - * The result of this combination is hash (hash (...)) - * Note that this method will invoke computeDigest(). - * Once this method is invoked, the supplied digest is fixed. - */ - Digest& - operator<<(Digest& src); - - /** - * @brief Add string to digest calculation - * @param str string to put into digest - */ - Digest& - operator<<(const std::string& str); - - /** - * @brief Add block to digest calculation - * @param block to put into digest - */ - Digest& - operator<<(const Block& block); - - /** - * @brief Add uint64_t value to digest calculation - * @param value uint64_t value to put into digest - */ - Digest& - operator<<(uint64_t value); - - /** - * @brief Add a buffer to digest calculation - * - * Update the state of the digest if it is not finalized - * and mark the digest as InProcess. - * - * @param buffer the input buffer - * @param size the size of the input buffer. - * @throws Error if the digest has been finalized. - */ - void - update(const uint8_t* buffer, size_t size); - - /** - * @brief Compute one-time digest - * @param buffer the input buffer - * @param size the size of the input buffer. - * @return digest computed according to the HashAlgorithm - */ - static ConstBufferPtr - computeDigest(const uint8_t* buffer, size_t size); - - /** - * @brief Convert digest to std::string - * - * Note that this method will invoke computeDigest(). - * Once this method is invoked, the digest is finalized. - */ - std::string - toString(); - -private: - /** - * @brief Finalize digest. - * - * All subsequent calls to "operator<<" will throw an exception - */ - void - finalize(); - -private: - Hash m_hash; - BufferPtr m_buffer; - bool m_isInProcess; - bool m_isFinalized; -}; - -template -std::ostream& -operator<<(std::ostream& os, Digest& digest); - -/** - * @brief A digest using SHA256 as the hash function. - */ -typedef Digest Sha256; - -} // namespace util -} // namespace ndn - -#endif // NDN_UTIL_DIGEST_HPP diff --git a/src/util/dns.cpp b/src/util/dns.cpp deleted file mode 100644 index 73fd8b1d6..000000000 --- a/src/util/dns.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "dns.hpp" -#include "scheduler.hpp" - -#include -#include - -namespace ndn { -namespace dns { - -class Resolver : noncopyable -{ -public: - typedef boost::asio::ip::udp protocol; - typedef protocol::resolver::iterator iterator; - typedef protocol::resolver::query query; - -public: - Resolver(boost::asio::io_service& ioService, - const AddressSelector& addressSelector) - : m_resolver(ioService) - , m_addressSelector(addressSelector) - , m_scheduler(ioService) - { - BOOST_ASSERT(m_addressSelector != nullptr); - } - - void - asyncResolve(const query& q, - const SuccessCallback& onSuccess, - const ErrorCallback& onError, - time::nanoseconds timeout, - const shared_ptr& self) - { - m_onSuccess = onSuccess; - m_onError = onError; - - m_resolver.async_resolve(q, bind(&Resolver::onResolveResult, this, _1, _2, self)); - - m_resolveTimeout = m_scheduler.scheduleEvent(timeout, bind(&Resolver::onResolveTimeout, this, self)); - } - - iterator - syncResolve(const query& q) - { - return selectAddress(m_resolver.resolve(q)); - } - -private: - void - onResolveResult(const boost::system::error_code& error, - iterator it, const shared_ptr& self) - { - m_scheduler.cancelEvent(m_resolveTimeout); - // ensure the Resolver isn't destructed while callbacks are still pending, see #2653 - m_resolver.get_io_service().post(bind([] (const shared_ptr&) {}, self)); - - if (error) { - if (error == boost::asio::error::operation_aborted) - return; - - if (m_onError) - m_onError("Hostname cannot be resolved: " + error.message()); - - return; - } - - it = selectAddress(it); - - if (it != iterator() && m_onSuccess) { - m_onSuccess(it->endpoint().address()); - } - else if (m_onError) { - m_onError("No endpoints match the specified address selector"); - } - } - - void - onResolveTimeout(const shared_ptr& self) - { - m_resolver.cancel(); - // ensure the Resolver isn't destructed while callbacks are still pending, see #2653 - m_resolver.get_io_service().post(bind([] (const shared_ptr&) {}, self)); - - if (m_onError) - m_onError("Hostname resolution timed out"); - } - - iterator - selectAddress(iterator it) const - { - while (it != iterator() && - !m_addressSelector(it->endpoint().address())) { - ++it; - } - - return it; - } - -private: - protocol::resolver m_resolver; - - AddressSelector m_addressSelector; - SuccessCallback m_onSuccess; - ErrorCallback m_onError; - - util::scheduler::Scheduler m_scheduler; - util::scheduler::EventId m_resolveTimeout; -}; - -void -asyncResolve(const std::string& host, - const SuccessCallback& onSuccess, - const ErrorCallback& onError, - boost::asio::io_service& ioService, - const AddressSelector& addressSelector, - time::nanoseconds timeout) -{ - auto resolver = make_shared(ref(ioService), addressSelector); - resolver->asyncResolve(Resolver::query(host, ""), onSuccess, onError, timeout, resolver); - // resolver will be destroyed when async operation finishes or ioService stops -} - -IpAddress -syncResolve(const std::string& host, - boost::asio::io_service& ioService, - const AddressSelector& addressSelector) -{ - Resolver resolver(ioService, addressSelector); - auto it = resolver.syncResolve(Resolver::query(host, "")); - - if (it == Resolver::iterator()) { - BOOST_THROW_EXCEPTION(Error("No endpoints match the specified address selector")); - } - - return it->endpoint().address(); -} - -} // namespace dns -} // namespace ndn diff --git a/src/util/dns.hpp b/src/util/dns.hpp deleted file mode 100644 index fec923bba..000000000 --- a/src/util/dns.hpp +++ /dev/null @@ -1,124 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_DNS_HPP -#define NDN_UTIL_DNS_HPP - -#include "../util/time.hpp" - -#include - -// forward declaration -namespace boost { -namespace asio { -class io_service; -} // namespace asio -} // namespace boost - -namespace ndn { -namespace dns { - -typedef boost::asio::ip::address IpAddress; -typedef function AddressSelector; - -struct AnyAddress -{ - bool - operator()(const IpAddress& address) const - { - return true; - } -}; - -struct Ipv4Only -{ - bool - operator()(const IpAddress& address) const - { - return address.is_v4(); - } -}; - -struct Ipv6Only -{ - bool - operator()(const IpAddress& address) const - { - return address.is_v6(); - } -}; - -struct Error : public std::runtime_error -{ - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } -}; - -typedef function SuccessCallback; -typedef function ErrorCallback; - -/** \brief Asynchronously resolve host - * - * If an address selector predicate is specified, then each resolved IP address - * is checked against the predicate. - * - * Available address selector predicates: - * - * - dns::AnyAddress() - * - dns::Ipv4Address() - * - dns::Ipv6Address() - * - * \warning Even after the DNS resolution has timed out, it's possible that - * \p ioService keeps running and \p onSuccess is invoked at a later time. - * This could cause segmentation fault if \p onSuccess is deallocated. - * To stop the io_service, explicitly invoke \p ioService.stop(). - */ -void -asyncResolve(const std::string& host, - const SuccessCallback& onSuccess, - const ErrorCallback& onError, - boost::asio::io_service& ioService, - const AddressSelector& addressSelector = AnyAddress(), - time::nanoseconds timeout = time::seconds(4)); - -/** \brief Synchronously resolve host - * - * If an address selector predicate is specified, then each resolved IP address - * is checked against the predicate. - * - * Available address selector predicates: - * - * - dns::AnyAddress() - * - dns::Ipv4Address() - * - dns::Ipv6Address() - */ -IpAddress -syncResolve(const std::string& host, - boost::asio::io_service& ioService, - const AddressSelector& addressSelector = AnyAddress()); - -} // namespace dns -} // namespace ndn - -#endif // NDN_UTIL_DNS_HPP diff --git a/src/util/dummy-client-face.cpp b/src/util/dummy-client-face.cpp deleted file mode 100644 index 911d3bb74..000000000 --- a/src/util/dummy-client-face.cpp +++ /dev/null @@ -1,276 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "dummy-client-face.hpp" -#include "../lp/packet.hpp" -#include "../lp/tags.hpp" -#include "../mgmt/nfd/controller.hpp" -#include "../mgmt/nfd/control-response.hpp" -#include "../transport/transport.hpp" - -#include - -namespace ndn { -namespace util { - -class DummyClientFace::Transport : public ndn::Transport -{ -public: - void - receive(Block block) const - { - block.encode(); - if (m_receiveCallback) { - m_receiveCallback(block); - } - } - - virtual void - close() override - { - } - - virtual void - pause() override - { - } - - virtual void - resume() override - { - } - - virtual void - send(const Block& wire) override - { - onSendBlock(wire); - } - - virtual void - send(const Block& header, const Block& payload) override - { - EncodingBuffer encoder(header.size() + payload.size(), header.size() + payload.size()); - encoder.appendByteArray(header.wire(), header.size()); - encoder.appendByteArray(payload.wire(), payload.size()); - - this->send(encoder.block()); - } - - boost::asio::io_service& - getIoService() - { - return *m_ioService; - } - -public: - Signal onSendBlock; -}; - -DummyClientFace::DummyClientFace(const Options& options/* = DummyClientFace::DEFAULT_OPTIONS*/) - : Face(make_shared()) - , m_internalKeyChain(new KeyChain) - , m_keyChain(*m_internalKeyChain) -{ - this->construct(options); -} - -DummyClientFace::DummyClientFace(KeyChain& keyChain, - const Options& options/* = DummyClientFace::DEFAULT_OPTIONS*/) - : Face(make_shared(), keyChain) - , m_keyChain(keyChain) -{ - this->construct(options); -} - -DummyClientFace::DummyClientFace(boost::asio::io_service& ioService, - const Options& options/* = DummyClientFace::DEFAULT_OPTIONS*/) - : Face(make_shared(), ioService) - , m_internalKeyChain(new KeyChain) - , m_keyChain(*m_internalKeyChain) -{ - this->construct(options); -} - -DummyClientFace::DummyClientFace(boost::asio::io_service& ioService, KeyChain& keyChain, - const Options& options/* = DummyClientFace::DEFAULT_OPTIONS*/) - : Face(make_shared(), ioService, keyChain) - , m_keyChain(keyChain) -{ - this->construct(options); -} - -void -DummyClientFace::construct(const Options& options) -{ - static_pointer_cast(getTransport())->onSendBlock.connect([this] (const Block& blockFromDaemon) { - Block packet(blockFromDaemon); - packet.encode(); - lp::Packet lpPacket(packet); - - Buffer::const_iterator begin, end; - std::tie(begin, end) = lpPacket.get(); - Block block(&*begin, std::distance(begin, end)); - - if (block.type() == tlv::Interest) { - shared_ptr interest = make_shared(block); - if (lpPacket.has()) { - shared_ptr nack = make_shared(std::move(*interest)); - nack->setHeader(lpPacket.get()); - if (lpPacket.has()) { - nack->setTag(make_shared(lpPacket.get())); - } - if (lpPacket.has()) { - nack->setTag(make_shared(lpPacket.get())); - } - onSendNack(*nack); - } - else { - if (lpPacket.has()) { - interest->setTag(make_shared(lpPacket.get())); - } - if (lpPacket.has()) { - interest->setTag(make_shared(lpPacket.get())); - } - onSendInterest(*interest); - } - } - else if (block.type() == tlv::Data) { - shared_ptr data = make_shared(block); - - if (lpPacket.has()) { - data->setTag(make_shared(lpPacket.get())); - } - if (lpPacket.has()) { - data->setTag(make_shared(lpPacket.get())); - } - - onSendData(*data); - } - }); - - if (options.enablePacketLogging) - this->enablePacketLogging(); - - if (options.enableRegistrationReply) - this->enableRegistrationReply(); - - m_processEventsOverride = options.processEventsOverride; -} - -void -DummyClientFace::enablePacketLogging() -{ - onSendInterest.connect([this] (const Interest& interest) { - this->sentInterests.push_back(interest); - }); - onSendData.connect([this] (const Data& data) { - this->sentData.push_back(data); - }); - onSendNack.connect([this] (const lp::Nack& nack) { - this->sentNacks.push_back(nack); - }); -} - -void -DummyClientFace::enableRegistrationReply() -{ - onSendInterest.connect([this] (const Interest& interest) { - static const Name localhostRegistration("/localhost/nfd/rib"); - if (!localhostRegistration.isPrefixOf(interest.getName())) - return; - - nfd::ControlParameters params(interest.getName().get(-5).blockFromValue()); - params.setFaceId(1); - params.setOrigin(0); - if (interest.getName().get(3) == name::Component("register")) { - params.setCost(0); - } - - nfd::ControlResponse resp; - resp.setCode(200); - resp.setBody(params.wireEncode()); - - shared_ptr data = make_shared(interest.getName()); - data->setContent(resp.wireEncode()); - - m_keyChain.sign(*data, security::SigningInfo(security::SigningInfo::SIGNER_TYPE_SHA256)); - - this->getIoService().post([this, data] { this->receive(*data); }); - }); -} - -template -static void -addFieldFromTag(lp::Packet& lpPacket, const Packet& packet) -{ - shared_ptr tag = static_cast(packet).getTag(); - if (tag != nullptr) { - lpPacket.add(*tag); - } -} - -template -void -DummyClientFace::receive(const Packet& packet) -{ - lp::Packet lpPacket(packet.wireEncode()); - - addFieldFromTag(lpPacket, packet); - addFieldFromTag(lpPacket, packet); - addFieldFromTag(lpPacket, packet); - - static_pointer_cast(getTransport())->receive(lpPacket.wireEncode()); -} - -template void -DummyClientFace::receive(const Interest& packet); - -template void -DummyClientFace::receive(const Data& packet); - -template<> -void -DummyClientFace::receive(const lp::Nack& nack) -{ - lp::Packet lpPacket; - lpPacket.add(nack.getHeader()); - Block interest = nack.getInterest().wireEncode(); - lpPacket.add(make_pair(interest.begin(), interest.end())); - - addFieldFromTag(lpPacket, nack); - addFieldFromTag(lpPacket, nack); - - static_pointer_cast(getTransport())->receive(lpPacket.wireEncode()); -} - -void -DummyClientFace::doProcessEvents(const time::milliseconds& timeout, bool keepThread) -{ - if (m_processEventsOverride != nullptr) { - m_processEventsOverride(timeout); - } - else { - this->Face::doProcessEvents(timeout, keepThread); - } -} - -} // namespace util -} // namespace ndn diff --git a/src/util/face-uri.cpp b/src/util/face-uri.cpp deleted file mode 100644 index acdbc118b..000000000 --- a/src/util/face-uri.cpp +++ /dev/null @@ -1,585 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2015-2016, Regents of the University of California, - * Arizona Board of Regents, - * Colorado State University, - * University Pierre & Marie Curie, Sorbonne University, - * Washington University in St. Louis, - * Beijing Institute of Technology, - * The University of Memphis. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "face-uri.hpp" -#include "dns.hpp" - -#include -#include -#include -#include -#include -#include - -namespace ndn { -namespace util { - -BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); - -FaceUri::FaceUri() - : m_isV6(false) -{ -} - -FaceUri::FaceUri(const std::string& uri) -{ - if (!parse(uri)) { - BOOST_THROW_EXCEPTION(Error("Malformed URI: " + uri)); - } -} - -FaceUri::FaceUri(const char* uri) -{ - if (!parse(uri)) { - BOOST_THROW_EXCEPTION(Error("Malformed URI: " + std::string(uri))); - } -} - -bool -FaceUri::parse(const std::string& uri) -{ - m_scheme.clear(); - m_host.clear(); - m_isV6 = false; - m_port.clear(); - m_path.clear(); - - static const boost::regex protocolExp("(\\w+\\d?(\\+\\w+)?)://([^/]*)(\\/[^?]*)?"); - boost::smatch protocolMatch; - if (!boost::regex_match(uri, protocolMatch, protocolExp)) { - return false; - } - m_scheme = protocolMatch[1]; - const std::string& authority = protocolMatch[3]; - m_path = protocolMatch[4]; - - // pattern for IPv6 address enclosed in [ ], with optional port number - static const boost::regex v6Exp("^\\[([a-fA-F0-9:]+)\\](?:\\:(\\d+))?$"); - // pattern for Ethernet address in standard hex-digits-and-colons notation - static const boost::regex etherExp("^\\[((?:[a-fA-F0-9]{1,2}\\:){5}(?:[a-fA-F0-9]{1,2}))\\]$"); - // pattern for IPv4-mapped IPv6 address, with optional port number - static const boost::regex v4MappedV6Exp("^\\[::ffff:(\\d+(?:\\.\\d+){3})\\](?:\\:(\\d+))?$"); - // pattern for IPv4/hostname/fd/ifname, with optional port number - static const boost::regex v4HostExp("^([^:]+)(?:\\:(\\d+))?$"); - - if (authority.empty()) { - // UNIX, internal - } - else { - boost::smatch match; - m_isV6 = boost::regex_match(authority, match, v6Exp); - if (m_isV6 || - boost::regex_match(authority, match, etherExp) || - boost::regex_match(authority, match, v4MappedV6Exp) || - boost::regex_match(authority, match, v4HostExp)) { - m_host = match[1]; - m_port = match[2]; - } - else { - return false; - } - } - - return true; -} - -FaceUri::FaceUri(const boost::asio::ip::udp::endpoint& endpoint) -{ - m_isV6 = endpoint.address().is_v6(); - m_scheme = m_isV6 ? "udp6" : "udp4"; - m_host = endpoint.address().to_string(); - m_port = to_string(endpoint.port()); -} - -FaceUri::FaceUri(const boost::asio::ip::tcp::endpoint& endpoint) -{ - m_isV6 = endpoint.address().is_v6(); - m_scheme = m_isV6 ? "tcp6" : "tcp4"; - m_host = endpoint.address().to_string(); - m_port = to_string(endpoint.port()); -} - -FaceUri::FaceUri(const boost::asio::ip::tcp::endpoint& endpoint, const std::string& scheme) - : m_scheme(scheme) -{ - m_isV6 = endpoint.address().is_v6(); - m_host = endpoint.address().to_string(); - m_port = to_string(endpoint.port()); -} - -#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS -FaceUri::FaceUri(const boost::asio::local::stream_protocol::endpoint& endpoint) - : m_isV6(false) -{ - m_scheme = "unix"; - m_path = endpoint.path(); -} -#endif // BOOST_ASIO_HAS_LOCAL_SOCKETS - -FaceUri -FaceUri::fromFd(int fd) -{ - FaceUri uri; - uri.m_scheme = "fd"; - uri.m_host = to_string(fd); - return uri; -} - -FaceUri::FaceUri(const ethernet::Address& address) - : m_isV6(true) -{ - m_scheme = "ether"; - m_host = address.toString(); -} - -FaceUri -FaceUri::fromDev(const std::string& ifname) -{ - FaceUri uri; - uri.m_scheme = "dev"; - uri.m_host = ifname; - return uri; -} - -FaceUri -FaceUri::fromUdpDev(const boost::asio::ip::udp::endpoint& endpoint, const std::string& ifname) -{ - FaceUri uri; - uri.m_scheme = endpoint.address().is_v6() ? "udp6+dev" : "udp4+dev"; - uri.m_host = ifname; - uri.m_port = to_string(endpoint.port()); - return uri; -} - -bool -FaceUri::operator==(const FaceUri& rhs) const -{ - return (m_scheme == rhs.m_scheme && - m_host == rhs.m_host && - m_isV6 == rhs.m_isV6 && - m_port == rhs.m_port && - m_path == rhs.m_path); -} - -bool -FaceUri::operator!=(const FaceUri& rhs) const -{ - return !(*this == rhs); -} - -std::string -FaceUri::toString() const -{ - std::ostringstream os; - os << *this; - return os.str(); -} - -std::ostream& -operator<<(std::ostream& os, const FaceUri& uri) -{ - os << uri.m_scheme << "://"; - if (uri.m_isV6) { - os << "[" << uri.m_host << "]"; - } - else { - os << uri.m_host; - } - if (!uri.m_port.empty()) { - os << ":" << uri.m_port; - } - os << uri.m_path; - return os; -} - -/** \brief a CanonizeProvider provides FaceUri canonization functionality for a group of schemes - */ -class CanonizeProvider : noncopyable -{ -public: - virtual - ~CanonizeProvider() = default; - - virtual std::set - getSchemes() const = 0; - - virtual bool - isCanonical(const FaceUri& faceUri) const = 0; - - virtual void - canonize(const FaceUri& faceUri, - const FaceUri::CanonizeSuccessCallback& onSuccess, - const FaceUri::CanonizeFailureCallback& onFailure, - boost::asio::io_service& io, const time::nanoseconds& timeout) const = 0; -}; - -template -class IpHostCanonizeProvider : public CanonizeProvider -{ -public: - virtual std::set - getSchemes() const override - { - std::set schemes; - schemes.insert(m_baseScheme); - schemes.insert(m_v4Scheme); - schemes.insert(m_v6Scheme); - return schemes; - } - - virtual bool - isCanonical(const FaceUri& faceUri) const override - { - if (faceUri.getPort().empty()) { - return false; - } - if (!faceUri.getPath().empty()) { - return false; - } - - boost::system::error_code ec; - boost::asio::ip::address addr; - if (faceUri.getScheme() == m_v4Scheme) { - addr = boost::asio::ip::address_v4::from_string(faceUri.getHost(), ec); - } - else if (faceUri.getScheme() == m_v6Scheme) { - addr = boost::asio::ip::address_v6::from_string(faceUri.getHost(), ec); - } - else { - return false; - } - return !static_cast(ec) && addr.to_string() == faceUri.getHost() && - this->checkAddress(addr).first; - } - - virtual void - canonize(const FaceUri& faceUri, - const FaceUri::CanonizeSuccessCallback& onSuccess, - const FaceUri::CanonizeFailureCallback& onFailure, - boost::asio::io_service& io, const time::nanoseconds& timeout) const override - { - if (this->isCanonical(faceUri)) { - onSuccess(faceUri); - return; - } - - dns::AddressSelector addressSelector; - if (faceUri.getScheme() == m_v4Scheme) { - addressSelector = dns::Ipv4Only(); - } - else if (faceUri.getScheme() == m_v6Scheme) { - addressSelector = dns::Ipv6Only(); - } - else { - BOOST_ASSERT(faceUri.getScheme() == m_baseScheme); - addressSelector = dns::AnyAddress(); - } - - // make a copy because caller may modify faceUri - shared_ptr uri = make_shared(faceUri); - dns::asyncResolve(faceUri.getHost(), - bind(&IpHostCanonizeProvider::onDnsSuccess, this, uri, onSuccess, onFailure, _1), - bind(&IpHostCanonizeProvider::onDnsFailure, this, uri, onFailure, _1), - io, addressSelector, timeout); - } - -protected: - explicit - IpHostCanonizeProvider(const std::string& baseScheme, - uint32_t defaultUnicastPort = 6363, - uint32_t defaultMulticastPort = 56363) - : m_baseScheme(baseScheme) - , m_v4Scheme(baseScheme + "4") - , m_v6Scheme(baseScheme + "6") - , m_defaultUnicastPort(defaultUnicastPort) - , m_defaultMulticastPort(defaultMulticastPort) - { - } - -private: - // faceUri is a shared_ptr passed by value because this function can take ownership - void - onDnsSuccess(shared_ptr faceUri, - const FaceUri::CanonizeSuccessCallback& onSuccess, - const FaceUri::CanonizeFailureCallback& onFailure, - const dns::IpAddress& ipAddress) const - { - std::pair checkAddressRes = this->checkAddress(ipAddress); - if (!checkAddressRes.first) { - onFailure(checkAddressRes.second); - return; - } - - uint32_t port = 0; - if (faceUri->getPort().empty()) { - port = ipAddress.is_multicast() ? m_defaultMulticastPort : m_defaultUnicastPort; - } - else { - try { - port = boost::lexical_cast(faceUri->getPort()); - } - catch (boost::bad_lexical_cast&) { - onFailure("invalid port number"); - return; - } - } - - FaceUri canonicalUri(typename Protocol::endpoint(ipAddress, port)); - BOOST_ASSERT(canonicalUri.isCanonical()); - onSuccess(canonicalUri); - } - - // faceUri is a shared_ptr passed by value because this function can take ownership - void - onDnsFailure(shared_ptr faceUri, const FaceUri::CanonizeFailureCallback& onFailure, - const std::string& reason) const - { - onFailure(reason); - } - - /** \brief when overriden in a subclass, check the IP address is allowable - * \return (true,ignored) if the address is allowable; - * (false,reason) if the address is not allowable. - */ - virtual std::pair - checkAddress(const dns::IpAddress& ipAddress) const - { - return {true, ""}; - } - -private: - std::string m_baseScheme; - std::string m_v4Scheme; - std::string m_v6Scheme; - uint32_t m_defaultUnicastPort; - uint32_t m_defaultMulticastPort; -}; - -class UdpCanonizeProvider : public IpHostCanonizeProvider -{ -public: - UdpCanonizeProvider() - : IpHostCanonizeProvider("udp") - { - } - -protected: - // checkAddress is not overriden: - // Although NFD doesn't support IPv6 multicast, it's an implementation limitation. - // FaceMgmt protocol allows IPv6 multicast address in UDP. -}; - -class TcpCanonizeProvider : public IpHostCanonizeProvider -{ -public: - TcpCanonizeProvider() - : IpHostCanonizeProvider("tcp") - { - } - -protected: - virtual std::pair - checkAddress(const dns::IpAddress& ipAddress) const override - { - if (ipAddress.is_multicast()) { - return {false, "cannot use multicast address"}; - } - return {true, ""}; - } -}; - -class EtherCanonizeProvider : public CanonizeProvider -{ -public: - virtual std::set - getSchemes() const override - { - std::set schemes; - schemes.insert("ether"); - return schemes; - } - - virtual bool - isCanonical(const FaceUri& faceUri) const override - { - if (!faceUri.getPort().empty()) { - return false; - } - if (!faceUri.getPath().empty()) { - return false; - } - - ethernet::Address addr = ethernet::Address::fromString(faceUri.getHost()); - return addr.toString() == faceUri.getHost(); - } - - virtual void - canonize(const FaceUri& faceUri, - const FaceUri::CanonizeSuccessCallback& onSuccess, - const FaceUri::CanonizeFailureCallback& onFailure, - boost::asio::io_service& io, const time::nanoseconds& timeout) const override - { - ethernet::Address addr = ethernet::Address::fromString(faceUri.getHost()); - if (addr.isNull()) { - onFailure("cannot parse address"); - return; - } - - FaceUri canonicalUri(addr); - BOOST_ASSERT(canonicalUri.isCanonical()); - onSuccess(canonicalUri); - } -}; - -class UdpDevCanonizeProvider : public CanonizeProvider -{ -public: - virtual std::set - getSchemes() const override - { - return {"udp4+dev", "udp6+dev"}; - } - - virtual bool - isCanonical(const FaceUri& faceUri) const override - { - if (faceUri.getPort().empty()) { - return false; - } - if (!faceUri.getPath().empty()) { - return false; - } - return true; - } - - virtual void - canonize(const FaceUri& faceUri, - const FaceUri::CanonizeSuccessCallback& onSuccess, - const FaceUri::CanonizeFailureCallback& onFailure, - boost::asio::io_service& io, const time::nanoseconds& timeout) const override - { - if (this->isCanonical(faceUri)) { - onSuccess(faceUri); - } - else { - onFailure("cannot canonize " + faceUri.toString()); - } - } -}; - -typedef boost::mpl::vector< - UdpCanonizeProvider*, - TcpCanonizeProvider*, - EtherCanonizeProvider*, - UdpDevCanonizeProvider* - > CanonizeProviders; -typedef std::map > CanonizeProviderTable; - -class CanonizeProviderTableInitializer -{ -public: - explicit - CanonizeProviderTableInitializer(CanonizeProviderTable& providerTable) - : m_providerTable(providerTable) - { - } - - template void - operator()(CP*) - { - shared_ptr cp = make_shared(); - - std::set schemes = cp->getSchemes(); - BOOST_ASSERT(!schemes.empty()); - for (std::set::iterator it = schemes.begin(); - it != schemes.end(); ++it) { - BOOST_ASSERT(m_providerTable.count(*it) == 0); - m_providerTable[*it] = cp; - } - } - -private: - CanonizeProviderTable& m_providerTable; -}; - -static const CanonizeProvider* -getCanonizeProvider(const std::string& scheme) -{ - static CanonizeProviderTable providerTable; - if (providerTable.empty()) { - boost::mpl::for_each(CanonizeProviderTableInitializer(providerTable)); - BOOST_ASSERT(!providerTable.empty()); - } - - auto it = providerTable.find(scheme); - if (it == providerTable.end()) { - return nullptr; - } - return it->second.get(); -} - -bool -FaceUri::canCanonize(const std::string& scheme) -{ - return getCanonizeProvider(scheme) != 0; -} - -bool -FaceUri::isCanonical() const -{ - const CanonizeProvider* cp = getCanonizeProvider(this->getScheme()); - if (cp == 0) { - return false; - } - - return cp->isCanonical(*this); -} - -void -FaceUri::canonize(const CanonizeSuccessCallback& onSuccess, - const CanonizeFailureCallback& onFailure, - boost::asio::io_service& io, const time::nanoseconds& timeout) const -{ - const CanonizeProvider* cp = getCanonizeProvider(this->getScheme()); - if (cp == nullptr) { - if (onFailure) { - onFailure("scheme not supported"); - } - return; - } - - static CanonizeSuccessCallback successNop = bind([]{}); - static CanonizeFailureCallback failureNop = bind([]{}); - - cp->canonize(*this, - onSuccess ? onSuccess : successNop, - onFailure ? onFailure : failureNop, - io, timeout); -} - -} // namespace util -} // namespace ndn diff --git a/src/util/in-memory-storage.cpp b/src/util/in-memory-storage.cpp deleted file mode 100644 index 69f2b5aff..000000000 --- a/src/util/in-memory-storage.cpp +++ /dev/null @@ -1,457 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "in-memory-storage.hpp" -#include "in-memory-storage-entry.hpp" - -#include "crypto.hpp" - -#include "../security/signature-sha256-with-rsa.hpp" - -namespace ndn { -namespace util { - -const time::milliseconds InMemoryStorage::INFINITE_WINDOW(-1); -const time::milliseconds InMemoryStorage::ZERO_WINDOW(0); - -InMemoryStorage::const_iterator::const_iterator(const Data* ptr, const Cache* cache, - Cache::index::type::iterator it) - : m_ptr(ptr) - , m_cache(cache) - , m_it(it) -{ -} - -InMemoryStorage::const_iterator& -InMemoryStorage::const_iterator::operator++() -{ - m_it++; - if (m_it != m_cache->get().end()) { - m_ptr = &((*m_it)->getData()); - } - else { - m_ptr = 0; - } - - return *this; -} - -InMemoryStorage::const_iterator -InMemoryStorage::const_iterator::operator++(int) -{ - InMemoryStorage::const_iterator i(*this); - this->operator++(); - return i; -} - -const Data& -InMemoryStorage::const_iterator::operator*() -{ - return *m_ptr; -} - -const Data* -InMemoryStorage::const_iterator::operator->() -{ - return m_ptr; -} - -bool -InMemoryStorage::const_iterator::operator==(const const_iterator& rhs) -{ - return m_it == rhs.m_it; -} - -bool -InMemoryStorage::const_iterator::operator!=(const const_iterator& rhs) -{ - return m_it != rhs.m_it; -} - -InMemoryStorage::InMemoryStorage(size_t limit) - : m_limit(limit) - , m_nPackets(0) -{ - init(); -} - -InMemoryStorage::InMemoryStorage(boost::asio::io_service& ioService, size_t limit) - : m_limit(limit) - , m_nPackets(0) -{ - m_scheduler = make_unique(ioService); - init(); -} - -void -InMemoryStorage::init() -{ - // TODO consider a more suitable initial value - m_capacity = 10; - - if (m_limit != std::numeric_limits::max() && m_capacity > m_limit) { - m_capacity = m_limit; - } - - for (size_t i = 0; i < m_capacity; i++) { - m_freeEntries.push(new InMemoryStorageEntry()); - } -} - -InMemoryStorage::~InMemoryStorage() -{ - // evict all items from cache - Cache::iterator it = m_cache.begin(); - while (it != m_cache.end()) { - it = freeEntry(it); - } - - BOOST_ASSERT(m_freeEntries.size() == m_capacity); - - while (!m_freeEntries.empty()) { - delete m_freeEntries.top(); - m_freeEntries.pop(); - } -} - -void -InMemoryStorage::setCapacity(size_t capacity) -{ - size_t oldCapacity = m_capacity; - m_capacity = capacity; - - if (size() > m_capacity) { - ssize_t nAllowedFailures = size() - m_capacity; - while (size() > m_capacity) { - if (!evictItem() && --nAllowedFailures < 0) { - BOOST_THROW_EXCEPTION(Error()); - } - } - } - - if (m_capacity >= oldCapacity) { - for (size_t i = oldCapacity; i < m_capacity; i++) { - m_freeEntries.push(new InMemoryStorageEntry()); - } - } - else { - for (size_t i = oldCapacity; i > m_capacity; i--) { - delete m_freeEntries.top(); - m_freeEntries.pop(); - } - } - - BOOST_ASSERT(size() + m_freeEntries.size() == m_capacity); -} - -void -InMemoryStorage::insert(const Data& data, const time::milliseconds& mustBeFreshProcessingWindow) -{ - //check if identical Data/Name already exists - Cache::index::type::iterator it = m_cache.get().find(data.getFullName()); - if (it != m_cache.get().end()) - return; - - //if full, double the capacity - bool doesReachLimit = (getLimit() == getCapacity()); - if (isFull() && !doesReachLimit) { - // note: This is incorrect if 2*capacity overflows, but memory should run out before that - size_t newCapacity = std::min(2 * getCapacity(), getLimit()); - setCapacity(newCapacity); - } - - //if full and reach limitation of the capacity, employ replacement policy - if (isFull() && doesReachLimit) { - evictItem(); - } - - //insert to cache - BOOST_ASSERT(m_freeEntries.size() > 0); - // take entry for the memory pool - InMemoryStorageEntry* entry = m_freeEntries.top(); - m_freeEntries.pop(); - m_nPackets++; - entry->setData(data); - if (m_scheduler != nullptr && mustBeFreshProcessingWindow > ZERO_WINDOW) { - auto eventId = make_unique(*m_scheduler); - *eventId = m_scheduler->scheduleEvent(mustBeFreshProcessingWindow, - bind(&InMemoryStorageEntry::markStale, entry)); - entry->setMarkStaleEventId(std::move(eventId)); - } - m_cache.insert(entry); - - //let derived class do something with the entry - afterInsert(entry); -} - -shared_ptr -InMemoryStorage::find(const Name& name) -{ - Cache::index::type::iterator it = m_cache.get().lower_bound(name); - - //if not found, return null - if (it == m_cache.get().end()) { - return shared_ptr(); - } - - //if the given name is not the prefix of the lower_bound, return null - if (!name.isPrefixOf((*it)->getFullName())) { - return shared_ptr(); - } - - afterAccess(*it); - return ((*it)->getData()).shared_from_this(); -} - -shared_ptr -InMemoryStorage::find(const Interest& interest) -{ - //if the interest contains implicit digest, it is possible to directly locate a packet. - Cache::index::type::iterator it = m_cache.get() - .find(interest.getName()); - - //if a packet is located by its full name, it must be the packet to return. - if (it != m_cache.get().end()) { - return ((*it)->getData()).shared_from_this(); - } - - //if the packet is not discovered by last step, either the packet is not in the storage or - //the interest doesn't contains implicit digest. - it = m_cache.get().lower_bound(interest.getName()); - - if (it == m_cache.get().end()) { - return shared_ptr(); - } - - //to locate the element that has a just smaller name than the interest's - if (it != m_cache.get().begin()) - it--; - - InMemoryStorageEntry* ret = selectChild(interest, it); - if (ret != 0) { - //let derived class do something with the entry - afterAccess(ret); - return ret->getData().shared_from_this(); - } - else { - return shared_ptr(); - } -} - -InMemoryStorage::Cache::index::type::iterator -InMemoryStorage::findNextFresh(Cache::index::type::iterator it) const -{ - for (; it != m_cache.get().end(); it++) { - if ((*it)->isFresh()) - return it; - } - - return it; -} - -InMemoryStorageEntry* -InMemoryStorage::selectChild(const Interest& interest, - Cache::index::type::iterator startingPoint) const -{ - BOOST_ASSERT(startingPoint != m_cache.get().end()); - - if (startingPoint != m_cache.get().begin()) - { - BOOST_ASSERT((*startingPoint)->getFullName() < interest.getName()); - } - - bool hasLeftmostSelector = (interest.getChildSelector() <= 0); - bool hasRightmostSelector = !hasLeftmostSelector; - - // filter out "stale" data - if (interest.getMustBeFresh()) - startingPoint = findNextFresh(startingPoint); - - if (startingPoint == m_cache.get().end()) { - return nullptr; - } - - if (hasLeftmostSelector) - { - if (interest.matchesData((*startingPoint)->getData())) - { - return *startingPoint; - } - } - - //iterate to the right - Cache::index::type::iterator rightmost = startingPoint; - if (startingPoint != m_cache.get().end()) - { - Cache::index::type::iterator rightmostCandidate = startingPoint; - Name currentChildPrefix(""); - - while (true) - { - ++rightmostCandidate; - // filter out "stale" data - if (interest.getMustBeFresh()) - rightmostCandidate = findNextFresh(rightmostCandidate); - - bool isInBoundaries = (rightmostCandidate != m_cache.get().end()); - bool isInPrefix = false; - if (isInBoundaries) - { - isInPrefix = interest.getName().isPrefixOf((*rightmostCandidate)->getFullName()); - } - - if (isInPrefix) - { - if (interest.matchesData((*rightmostCandidate)->getData())) - { - if (hasLeftmostSelector) - { - return *rightmostCandidate; - } - - if (hasRightmostSelector) - { - // get prefix which is one component longer than Interest name - const Name& childPrefix = (*rightmostCandidate)->getFullName() - .getPrefix(interest.getName().size() + 1); - - if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix)) - { - currentChildPrefix = childPrefix; - rightmost = rightmostCandidate; - } - } - } - } - else - break; - } - } - - if (rightmost != startingPoint) - { - return *rightmost; - } - - if (hasRightmostSelector) // if rightmost was not found, try starting point - { - if (interest.matchesData((*startingPoint)->getData())) - { - return *startingPoint; - } - } - - return 0; -} - -InMemoryStorage::Cache::iterator -InMemoryStorage::freeEntry(Cache::iterator it) -{ - //push the *empty* entry into mem pool - (*it)->release(); - m_freeEntries.push(*it); - m_nPackets--; - return m_cache.erase(it); -} - -void -InMemoryStorage::erase(const Name& prefix, const bool isPrefix) -{ - if (isPrefix) { - Cache::index::type::iterator it = m_cache.get().lower_bound(prefix); - - while (it != m_cache.get().end() && prefix.isPrefixOf((*it)->getName())) { - //let derived class do something with the entry - beforeErase(*it); - it = freeEntry(it); - } - } - else { - Cache::index::type::iterator it = m_cache.get().find(prefix); - - if (it == m_cache.get().end()) - return; - - //let derived class do something with the entry - beforeErase(*it); - freeEntry(it); - } - - if (m_freeEntries.size() > (2 * size())) - setCapacity(getCapacity() / 2); -} - -void -InMemoryStorage::eraseImpl(const Name& name) -{ - Cache::index::type::iterator it = m_cache.get().find(name); - - if (it == m_cache.get().end()) - return; - - freeEntry(it); -} - -InMemoryStorage::const_iterator -InMemoryStorage::begin() const -{ - Cache::index::type::iterator it = m_cache.get().begin(); - - return const_iterator(&((*it)->getData()), &m_cache, it); -} - -InMemoryStorage::const_iterator -InMemoryStorage::end() const -{ - Cache::index::type::iterator it = m_cache.get().end(); - - const Data* ptr = NULL; - - return const_iterator(ptr, &m_cache, it); -} - -void -InMemoryStorage::afterInsert(InMemoryStorageEntry* entry) -{ -} - -void -InMemoryStorage::beforeErase(InMemoryStorageEntry* entry) -{ -} - -void -InMemoryStorage::afterAccess(InMemoryStorageEntry* entry) -{ -} - -void -InMemoryStorage::printCache(std::ostream& os) const -{ - //start from the upper layer towards bottom - const Cache::index::type& cacheIndex = m_cache.get(); - for (Cache::index::type::iterator it = cacheIndex.begin(); - it != cacheIndex.end(); it++) - os << (*it)->getFullName() << std::endl; -} - -} // namespace util -} // namespace ndn diff --git a/src/util/io.cpp b/src/util/io.cpp deleted file mode 100644 index 76fe18c0a..000000000 --- a/src/util/io.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "io.hpp" -#include "../encoding/buffer-stream.hpp" -#include "../security/transform.hpp" - -namespace ndn { -namespace io { - -optional -loadBlock(std::istream& is, IoEncoding encoding) -{ - namespace t = ndn::security::transform; - - OBufferStream os; - try { - switch (encoding) { - case NO_ENCODING: - t::streamSource(is) >> t::streamSink(os); - break; - case BASE64: - t::streamSource(is) >> t::stripSpace("\n") >> t::base64Decode(false) >> t::streamSink(os); - break; - case HEX: - t::streamSource(is) >> t::hexDecode() >> t::streamSink(os); - break; - default: - return nullopt; - } - } - catch (const t::Error&) { - return nullopt; - } - - try { - return make_optional(os.buf()); - } - catch (const tlv::Error&) { - return nullopt; - } -} - -void -saveBlock(const Block& block, std::ostream& os, IoEncoding encoding) -{ - namespace t = ndn::security::transform; - - try { - switch (encoding) { - case NO_ENCODING: - t::bufferSource(block.wire(), block.size()) >> t::streamSink(os); - break; - case BASE64: - t::bufferSource(block.wire(), block.size()) >> t::base64Encode() >> t::streamSink(os); - break; - case HEX: - t::bufferSource(block.wire(), block.size()) >> t::hexEncode(true) >> t::streamSink(os); - break; - default: - BOOST_THROW_EXCEPTION(Error("unrecognized IoEncoding")); - } - } - catch (const t::Error& e) { - BOOST_THROW_EXCEPTION(Error(e.what())); - } -} - -} // namespace io -} // namespace ndn diff --git a/src/util/io.hpp b/src/util/io.hpp deleted file mode 100644 index 7da812e35..000000000 --- a/src/util/io.hpp +++ /dev/null @@ -1,170 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_IO_HPP -#define NDN_UTIL_IO_HPP - -#include "concepts.hpp" -#include "../encoding/block.hpp" - -#include -#include - -namespace ndn { -namespace io { - -class Error : public std::runtime_error -{ -public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } -}; - -/** \brief indicates how a file or stream is encoded - */ -enum IoEncoding { - /** \brief binary without encoding - */ - NO_ENCODING, - - /** \brief base64 encoding - * - * \p save() inserts a newline after every 64 characters, - * \p load() can accept base64 text with or without newlines - */ - BASE64, - - /** \brief hexadecimal encoding - * - * \p save() uses uppercase letters A-F, \p load() can accept mixed-case - */ - HEX -}; - -constexpr IoEncoding DEPRECATED(BASE_64) = BASE64; - -namespace detail { - -template -static void -checkInnerError(typename T::Error*) -{ - static_assert(std::is_base_of::value, - "T::Error, if declared, must inherit from ndn::tlv::Error"); -} - -template -static void -checkInnerError(...) -{ - // T::Error is not declared -} - -} // namespace detail - -/** \brief loads a TLV block from a stream - * \return if success, the Block and true - * otherwise, a default-constructed Block and false - */ -optional -loadBlock(std::istream& is, IoEncoding encoding = BASE64); - -/** \brief loads a TLV element from a stream - * \tparam T type of TLV element; T must be WireDecodable, - * and must have a Error nested type - * \return the TLV element, or nullptr if an error occurs - */ -template -shared_ptr -load(std::istream& is, IoEncoding encoding = BASE64) -{ - BOOST_CONCEPT_ASSERT((WireDecodable)); - detail::checkInnerError(nullptr); - - optional block = loadBlock(is, encoding); - if (!block) { - return nullptr; - } - - try { - return make_shared(*block); - } - catch (const tlv::Error&) { - return nullptr; - } -} - -/** \brief loads a TLV element from a file - */ -template -shared_ptr -load(const std::string& filename, IoEncoding encoding = BASE64) -{ - std::ifstream is(filename); - return load(is, encoding); -} - -/** \brief saves a TLV block to a stream - * \throw Error error during saving - */ -void -saveBlock(const Block& block, std::ostream& os, IoEncoding encoding = BASE64); - -/** \brief saves a TLV element to a stream - * \tparam T type of TLV element; T must be WireEncodable, - * and must have a Error nested type - * \throw Error error during encoding or saving - */ -template -void -save(const T& obj, std::ostream& os, IoEncoding encoding = BASE64) -{ - BOOST_CONCEPT_ASSERT((WireEncodable)); - detail::checkInnerError(nullptr); - - Block block; - try { - block = obj.wireEncode(); - } - catch (const tlv::Error& e) { - BOOST_THROW_EXCEPTION(Error(e.what())); - } - - saveBlock(block, os, encoding); -} - -/** \brief saves a TLV element to a file - */ -template -void -save(const T& obj, const std::string& filename, IoEncoding encoding = BASE64) -{ - std::ofstream os(filename); - save(obj, os, encoding); -} - -} // namespace io -} // namespace ndn - -#endif // NDN_UTIL_IO_HPP diff --git a/src/util/logger.cpp b/src/util/logger.cpp deleted file mode 100644 index 04ad95406..000000000 --- a/src/util/logger.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "logger.hpp" - -#include "logging.hpp" -#include "time.hpp" - -#include -#include -#include - -namespace ndn { -namespace util { - -std::ostream& -operator<<(std::ostream& os, LogLevel level) -{ - switch (level) { - case LogLevel::FATAL: - return os << "FATAL"; - case LogLevel::NONE: - return os << "NONE"; - case LogLevel::ERROR: - return os << "ERROR"; - case LogLevel::WARN: - return os << "WARN"; - case LogLevel::INFO: - return os << "INFO"; - case LogLevel::DEBUG: - return os << "DEBUG"; - case LogLevel::TRACE: - return os << "TRACE"; - case LogLevel::ALL: - return os << "ALL"; - } - - BOOST_THROW_EXCEPTION(std::invalid_argument("unknown log level " + to_string(static_cast(level)))); -} - -LogLevel -parseLogLevel(const std::string& s) -{ - if (s == "FATAL") - return LogLevel::FATAL; - else if (s == "NONE") - return LogLevel::NONE; - else if (s == "ERROR") - return LogLevel::ERROR; - else if (s == "WARN") - return LogLevel::WARN; - else if (s == "INFO") - return LogLevel::INFO; - else if (s == "DEBUG") - return LogLevel::DEBUG; - else if (s == "TRACE") - return LogLevel::TRACE; - else if (s == "ALL") - return LogLevel::ALL; - - BOOST_THROW_EXCEPTION(std::invalid_argument("unrecognized log level '" + s + "'")); -} - -Logger::Logger(const std::string& name) - : m_moduleName(name) -{ - this->setLevel(LogLevel::NONE); - Logging::addLogger(*this); -} - -std::ostream& -operator<<(std::ostream& os, const LoggerTimestamp&) -{ - using namespace ndn::time; - - static const microseconds::rep ONE_SECOND = 1000000; - microseconds::rep usecs = duration_cast( - system_clock::now().time_since_epoch()).count(); - - // 10 (whole seconds) + '.' + 6 (fraction) + '\0' - char buffer[10 + 1 + 6 + 1]; - BOOST_ASSERT_MSG(usecs / ONE_SECOND <= 9999999999L, - "whole seconds cannot fit in 10 characters"); - - static_assert(std::is_same::value, - "PRIdLEAST64 is incompatible with microseconds::rep"); - // std::snprintf unavailable in some environments - snprintf(buffer, sizeof(buffer), "%" PRIdLEAST64 ".%06" PRIdLEAST64, - usecs / ONE_SECOND, usecs % ONE_SECOND); - - return os << buffer; -} - -} // namespace util -} // namespace ndn diff --git a/src/util/logger.hpp b/src/util/logger.hpp deleted file mode 100644 index e9efba9fd..000000000 --- a/src/util/logger.hpp +++ /dev/null @@ -1,173 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_LOGGER_HPP -#define NDN_UTIL_LOGGER_HPP - -#include "../common.hpp" - -#ifdef HAVE_NDN_CXX_CUSTOM_LOGGER -#include "ndn-cxx-custom-logger.hpp" -#else - -#include -#include -#include - -namespace ndn { -namespace util { - -/** \brief indicates the severity level of a log message - */ -enum class LogLevel { - FATAL = -1, ///< fatal (will be logged unconditionally) - NONE = 0, ///< no messages - ERROR = 1, ///< serious error messages - WARN = 2, ///< warning messages - INFO = 3, ///< informational messages - DEBUG = 4, ///< debug messages - TRACE = 5, ///< trace messages (most verbose) - ALL = 255 ///< all messages -}; - -/** \brief output LogLevel as string - * \throw std::invalid_argument unknown \p level - */ -std::ostream& -operator<<(std::ostream& os, LogLevel level); - -/** \brief parse LogLevel from string - * \throw std::invalid_argument unknown level name - */ -LogLevel -parseLogLevel(const std::string& s); - -/** \brief represents a logger in logging facility - * \note User should declare a new logger with \p NDN_LOG_INIT macro. - */ -class Logger : public boost::log::sources::logger_mt -{ -public: - explicit - Logger(const std::string& name); - - const std::string& - getModuleName() const - { - return m_moduleName; - } - - bool - isLevelEnabled(LogLevel level) const - { - return m_currentLevel.load(std::memory_order_relaxed) >= level; - } - - void - setLevel(LogLevel level) - { - m_currentLevel.store(level, std::memory_order_relaxed); - } - -private: - const std::string m_moduleName; - std::atomic m_currentLevel; -}; - -/** \brief declare a log module - */ -#define NDN_LOG_INIT(name) \ - namespace { \ - inline ::ndn::util::Logger& getNdnCxxLogger() \ - { \ - static ::ndn::util::Logger logger(BOOST_STRINGIZE(name)); \ - return logger; \ - } \ - } \ - struct ndn_cxx__allow_trailing_semicolon - -/** \brief a tag that writes a timestamp upon stream output - * \code - * std::clog << LoggerTimestamp(); - * \endcode - */ -struct LoggerTimestamp -{ -}; - -/** \brief write a timestamp to \p os - * \note This function is thread-safe. - */ -std::ostream& -operator<<(std::ostream& os, const LoggerTimestamp&); - -#if (BOOST_VERSION >= 105900) && (BOOST_VERSION < 106000) -// workaround Boost bug 11549 -#define NDN_BOOST_LOG(x) BOOST_LOG(x) << "" -#else -#define NDN_BOOST_LOG(x) BOOST_LOG(x) -#endif - -#define NDN_LOG(lvl, lvlstr, expression) \ - do { \ - if (getNdnCxxLogger().isLevelEnabled(::ndn::util::LogLevel::lvl)) { \ - NDN_BOOST_LOG(getNdnCxxLogger()) << ::ndn::util::LoggerTimestamp{} \ - << " " BOOST_STRINGIZE(lvlstr) ": [" << getNdnCxxLogger().getModuleName() << "] " \ - << expression; \ - } \ - } while (false) - -/** \brief log at TRACE level - * \pre A log module must be declared in the same translation unit. - */ -#define NDN_LOG_TRACE(expression) NDN_LOG(TRACE, TRACE, expression) - -/** \brief log at DEBUG level - * \pre A log module must be declared in the same translation unit. - */ -#define NDN_LOG_DEBUG(expression) NDN_LOG(DEBUG, DEBUG, expression) - -/** \brief log at INFO level - * \pre A log module must be declared in the same translation unit. - */ -#define NDN_LOG_INFO(expression) NDN_LOG(INFO, INFO, expression) - -/** \brief log at WARN level - * \pre A log module must be declared in the same translation unit. - */ -#define NDN_LOG_WARN(expression) NDN_LOG(WARN, WARNING, expression) - -/** \brief log at ERROR level - * \pre A log module must be declared in the same translation unit. - */ -#define NDN_LOG_ERROR(expression) NDN_LOG(ERROR, ERROR, expression) - -/** \brief log at FATAL level - * \pre A log module must be declared in the same translation unit. - */ -#define NDN_LOG_FATAL(expression) NDN_LOG(FATAL, FATAL, expression) - -} // namespace util -} // namespace ndn - -#endif // HAVE_NDN_CXX_CUSTOM_LOGGER - -#endif // NDN_UTIL_LOGGER_HPP diff --git a/src/util/logging.cpp b/src/util/logging.cpp deleted file mode 100644 index 89d0fd7a1..000000000 --- a/src/util/logging.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "logging.hpp" -#include "logger.hpp" - -#include -#include -#include - -namespace ndn { -namespace util { - -static const LogLevel INITIAL_DEFAULT_LEVEL = LogLevel::NONE; - -Logging& -Logging::get() -{ - // Initialization of block-scope variables with static storage duration is thread-safe. - // See ISO C++ standard [stmt.dcl]/4 - static Logging instance; - return instance; -} - -Logging::Logging() -{ - this->setDestinationImpl(shared_ptr(&std::clog, bind([]{}))); - - const char* environ = std::getenv("NDN_LOG"); - if (environ != nullptr) { - this->setLevelImpl(environ); - } -} - -void -Logging::addLoggerImpl(Logger& logger) -{ - std::lock_guard lock(m_mutex); - - const std::string& moduleName = logger.getModuleName(); - m_loggers.insert({moduleName, &logger}); - - auto levelIt = m_enabledLevel.find(moduleName); - if (levelIt == m_enabledLevel.end()) { - levelIt = m_enabledLevel.find("*"); - } - LogLevel level = levelIt == m_enabledLevel.end() ? INITIAL_DEFAULT_LEVEL : levelIt->second; - logger.setLevel(level); -} - -#ifdef NDN_CXX_HAVE_TESTS -bool -Logging::removeLogger(Logger& logger) -{ - const std::string& moduleName = logger.getModuleName(); - auto range = m_loggers.equal_range(moduleName); - for (auto i = range.first; i != range.second; ++i) { - if (i->second == &logger) { - m_loggers.erase(i); - return true; - } - } - return false; -} -#endif // NDN_CXX_HAVE_TESTS - -void -Logging::setLevelImpl(const std::string& moduleName, LogLevel level) -{ - std::lock_guard lock(m_mutex); - - if (moduleName == "*") { - this->setDefaultLevel(level); - return; - } - - m_enabledLevel[moduleName] = level; - auto range = m_loggers.equal_range(moduleName); - for (auto i = range.first; i != range.second; ++i) { - i->second->setLevel(level); - } -} - -void -Logging::setDefaultLevel(LogLevel level) -{ - m_enabledLevel.clear(); - m_enabledLevel["*"] = level; - - for (auto i = m_loggers.begin(); i != m_loggers.end(); ++i) { - i->second->setLevel(level); - } -} - -void -Logging::setLevelImpl(const std::string& config) -{ - std::stringstream ss(config); - std::string configModule; - while (std::getline(ss, configModule, ':')) { - size_t ind = configModule.find('='); - if (ind == std::string::npos) { - BOOST_THROW_EXCEPTION(std::invalid_argument("malformed logging config: '=' is missing")); - } - - std::string moduleName = configModule.substr(0, ind); - LogLevel level = parseLogLevel(configModule.substr(ind+1)); - - this->setLevelImpl(moduleName, level); - } -} - -#ifdef NDN_CXX_HAVE_TESTS -std::string -Logging::getLevels() const -{ - std::ostringstream os; - - auto defaultLevelIt = m_enabledLevel.find("*"); - if (defaultLevelIt != m_enabledLevel.end()) { - os << "*=" << defaultLevelIt->second << ':'; - } - - for (auto it = m_enabledLevel.begin(); it != m_enabledLevel.end(); ++it) { - if (it->first == "*") { - continue; - } - os << it->first << '=' << it->second << ':'; - } - - std::string s = os.str(); - if (!s.empty()) { - s.pop_back(); // delete last ':' - } - return s; -} -#endif // NDN_CXX_HAVE_TESTS - -#ifdef NDN_CXX_HAVE_TESTS -void -Logging::resetLevels() -{ - this->setDefaultLevel(INITIAL_DEFAULT_LEVEL); - m_enabledLevel.clear(); -} -#endif // NDN_CXX_HAVE_TESTS - -void -Logging::setDestination(std::ostream& os) -{ - setDestination(shared_ptr(&os, bind([]{}))); -} - -void -Logging::setDestinationImpl(shared_ptr os) -{ - std::lock_guard lock(m_mutex); - - m_destination = os; - - auto backend = boost::make_shared(); - backend->auto_flush(true); - backend->add_stream(boost::shared_ptr(os.get(), bind([]{}))); - - if (m_sink != nullptr) { - boost::log::core::get()->remove_sink(m_sink); - m_sink->flush(); - m_sink.reset(); - } - - m_sink = boost::make_shared(backend); - m_sink->set_formatter(boost::log::expressions::stream << boost::log::expressions::message); - boost::log::core::get()->add_sink(m_sink); -} - -#ifdef NDN_CXX_HAVE_TESTS -shared_ptr -Logging::getDestination() -{ - return m_destination; -} -#endif // NDN_CXX_HAVE_TESTS - -void -Logging::flushImpl() -{ - m_sink->flush(); -} - -} // namespace util -} // namespace ndn diff --git a/src/util/logging.hpp b/src/util/logging.hpp deleted file mode 100644 index 45dbe0767..000000000 --- a/src/util/logging.hpp +++ /dev/null @@ -1,193 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_LOGGING_HPP -#define NDN_UTIL_LOGGING_HPP - -#include "../common.hpp" - -#ifdef HAVE_NDN_CXX_CUSTOM_LOGGER -#include "ndn-cxx-custom-logging.hpp" -#else - -#include -#include -#include - -namespace ndn { -namespace util { - -enum class LogLevel; -class Logger; - -/** \brief controls the logging facility - * - * \note Public static methods are thread safe. - * Non-public methods are not guaranteed to be thread safe. - */ -class Logging : noncopyable -{ -public: - /** \brief register a new logger - * \note App should declare a new logger with \p NDN_LOG_INIT macro. - */ - static void - addLogger(Logger& logger); - - /** \brief set severity level - * \param moduleName logger name, or "*" for default level - * \param level minimum severity level - * - * Log messages are output only if its severity is greater than the set minimum severity level. - * Initial default severity level is \p LogLevel::NONE which enables FATAL only. - * - * Changing the default level overwrites individual settings. - */ - static void - setLevel(const std::string& moduleName, LogLevel level); - - /** \brief set severity levels with a config string - * \param config colon-separate key=value pairs - * \throw std::invalid_argument config string is malformed - * - * \code - * Logging::setSeverityLevels("*=INFO:Face=DEBUG:NfdController=WARN"); - * \endcode - * is equivalent to - * \code - * Logging::setSeverityLevel("*", LogLevel::INFO); - * Logging::setSeverityLevel("Face", LogLevel::DEBUG); - * Logging::setSeverityLevel("NfdController", LogLevel::WARN); - * \endcode - */ - static void - setLevel(const std::string& config); - - /** \brief set log destination - * \param os a stream for log output - * - * Initial destination is \p std::clog . - */ - static void - setDestination(shared_ptr os); - - /** \brief set log destination - * \param os a stream for log output; caller must ensure this is valid - * until setDestination is invoked again or program exits - * - * This is equivalent to setDestination(shared_ptr(&os, nullDeleter)) - */ - static void - setDestination(std::ostream& os); - - /** \brief flush log backend - * - * This ensures log messages are written to the destination stream. - */ - static void - flush(); - -private: - Logging(); - - void - addLoggerImpl(Logger& logger); - - void - setLevelImpl(const std::string& moduleName, LogLevel level); - - void - setDefaultLevel(LogLevel level); - - void - setLevelImpl(const std::string& config); - - void - setDestinationImpl(shared_ptr os); - - void - flushImpl(); - -NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE: - static Logging& - get(); - -#ifdef NDN_CXX_HAVE_TESTS - bool - removeLogger(Logger& logger); - - std::string - getLevels() const; - - void - resetLevels(); - - shared_ptr - getDestination(); -#endif // NDN_CXX_HAVE_TESTS - -private: - std::mutex m_mutex; - std::unordered_map m_enabledLevel; ///< moduleName => minimum level - std::unordered_multimap m_loggers; ///< moduleName => logger - - shared_ptr m_destination; - typedef boost::log::sinks::asynchronous_sink Sink; - boost::shared_ptr m_sink; -}; - -inline void -Logging::addLogger(Logger& logger) -{ - get().addLoggerImpl(logger); -} - -inline void -Logging::setLevel(const std::string& moduleName, LogLevel level) -{ - get().setLevelImpl(moduleName, level); -} - -inline void -Logging::setLevel(const std::string& config) -{ - get().setLevelImpl(config); -} - -inline void -Logging::setDestination(shared_ptr os) -{ - get().setDestinationImpl(os); -} - -inline void -Logging::flush() -{ - get().flushImpl(); -} - - -} // namespace util -} // namespace ndn - -#endif // HAVE_NDN_CXX_CUSTOM_LOGGER - -#endif // NDN_UTIL_LOGGING_HPP diff --git a/src/util/monotonic_deadline_timer.hpp b/src/util/monotonic_deadline_timer.hpp deleted file mode 100644 index c2b28cf3a..000000000 --- a/src/util/monotonic_deadline_timer.hpp +++ /dev/null @@ -1,82 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** - * This code is based on https://svn.boost.org/trac/boost/attachment/ticket/3504/MonotonicDeadlineTimer.h - */ - -#ifndef NDN_UTIL_MONOTONIC_DEADLINE_TIMER_HPP -#define NDN_UTIL_MONOTONIC_DEADLINE_TIMER_HPP - -#include "time.hpp" - -#include - -namespace boost { -namespace asio { - -template<> -struct time_traits -{ - typedef ndn::time::steady_clock::TimePoint time_type; - typedef ndn::time::steady_clock::Duration duration_type; - - static time_type - now() - { - return ndn::time::steady_clock::now(); - } - - static time_type - add(const time_type& time, const duration_type& duration) - { - return time + duration; - } - - static duration_type - subtract(const time_type& timeLhs, const time_type& timeRhs) - { - return timeLhs - timeRhs; - } - - static bool - less_than(const time_type& timeLhs, const time_type& timeRhs) - { - return timeLhs < timeRhs; - } - - static boost::posix_time::time_duration - to_posix_duration(const duration_type& duration) - { - return ndn::time::steady_clock::to_posix_duration(duration); - } -}; - -} // namespace asio -} // namespace boost - -namespace ndn { - -typedef boost::asio::basic_deadline_timer monotonic_deadline_timer; - -} // namespace ndn - -#endif // NDN_UTIL_MONOTONIC_DEADLINE_TIMER_HPP diff --git a/src/util/network-monitor.cpp b/src/util/network-monitor.cpp deleted file mode 100644 index a12e37346..000000000 --- a/src/util/network-monitor.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "network-monitor.hpp" - -#include "ndn-cxx-config.hpp" - -#if defined(NDN_CXX_HAVE_COREFOUNDATION_COREFOUNDATION_H) -#include "detail/network-monitor-impl-osx.hpp" -#elif defined(NDN_CXX_HAVE_RTNETLINK) -#include "detail/network-monitor-impl-rtnl.hpp" -#else - -namespace ndn { -namespace util { - -class NetworkMonitor::Impl -{ -public: - Impl(NetworkMonitor& nm, boost::asio::io_service& io) - { - BOOST_THROW_EXCEPTION(Error("Network monitoring is not supported on this platform")); - } -}; - -} // namespace util -} // namespace ndn - -#endif - -namespace ndn { -namespace util { - -NetworkMonitor::NetworkMonitor(boost::asio::io_service& io) - : m_impl(new Impl(*this, io)) -{ -} - -NetworkMonitor::~NetworkMonitor() = default; - -} // namespace util -} // namespace ndn diff --git a/src/util/network-monitor.hpp b/src/util/network-monitor.hpp deleted file mode 100644 index dae4941cc..000000000 --- a/src/util/network-monitor.hpp +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_NETWORK_MONITOR_HPP -#define NDN_UTIL_NETWORK_MONITOR_HPP - -#include "signal.hpp" - -// forward declaration -namespace boost { -namespace asio { -class io_service; -} // namespace asio -} // namespace boost - -namespace ndn { -namespace util { - -/** - * @brief Network state change monitor - * - * When network change is detected, onNetworkStateChanged signal will be fired. - * Monitoring is run for the lifetime of the NetworkMonitor instance. - * - * @note Implementation of this class is platform dependent and not all supported platforms - * are supported: - * - OS X: CFNotificationCenterAddObserver - * - Linux: rtnetlink notifications - * - * Network state change detection is not guaranteed to be precise and (zero or more) - * notifications are expected to be fired for the following events: - * - any network interface going up or down - * - IPv4 or IPv6 address changes on any of the interfaces - */ -class NetworkMonitor : boost::noncopyable -{ -public: - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - - /** - * @brief Construct instance and start monitoring for network state changes - * @param io io_service thread that will dispatch events - * @throw Error when network monitoring is not supported or there is an error starting monitoring - */ - explicit - NetworkMonitor(boost::asio::io_service& io); - - /** - * @brief Terminate network state monitoring - */ - ~NetworkMonitor(); - - Signal onNetworkStateChanged; - -private: - class Impl; - std::unique_ptr m_impl; -}; - -} // namespace util -} // namespace autoconfig - -#endif // NDN_UTIL_NETWORK_MONITOR_HPP diff --git a/src/util/notification-stream.hpp b/src/util/notification-stream.hpp deleted file mode 100644 index 42d0e366c..000000000 --- a/src/util/notification-stream.hpp +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** - * Original copyright notice from NFD: - * - * Copyright (c) 2014, Regents of the University of California, - * Arizona Board of Regents, - * Colorado State University, - * University Pierre & Marie Curie, Sorbonne University, - * Washington University in St. Louis, - * Beijing Institute of Technology, - * The University of Memphis - * - * This file is part of NFD (Named Data Networking Forwarding Daemon). - * See AUTHORS.md for complete list of NFD authors and contributors. - * - * NFD 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. - * - * NFD 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 - * NFD, e.g., in COPYING.md file. If not, see . - */ - -#ifndef NDN_UTIL_NOTIFICATION_STREAM_HPP -#define NDN_UTIL_NOTIFICATION_STREAM_HPP - -#include "../name.hpp" -#include "../face.hpp" -#include "../security/key-chain.hpp" - -#include "concepts.hpp" - -namespace ndn { - -namespace util { - -/** \brief provides a publisher of Notification Stream - * \sa http://redmine.named-data.net/projects/nfd/wiki/Notification - */ -template -class NotificationStream : noncopyable -{ -public: - BOOST_CONCEPT_ASSERT((WireEncodable)); - - NotificationStream(Face& face, const Name& prefix, KeyChain& keyChain) - : m_face(face) - , m_prefix(prefix) - , m_keyChain(keyChain) - , m_sequenceNo(0) - { - } - - virtual - ~NotificationStream() - { - } - - void - postNotification(const Notification& notification) - { - Name dataName = m_prefix; - dataName.appendSequenceNumber(m_sequenceNo); - - shared_ptr data = make_shared(dataName); - data->setContent(notification.wireEncode()); - data->setFreshnessPeriod(time::seconds(1)); - - m_keyChain.sign(*data); - m_face.put(*data); - - ++m_sequenceNo; - } - -private: - Face& m_face; - const Name m_prefix; - KeyChain& m_keyChain; - uint64_t m_sequenceNo; -}; - -} // namespace util -} // namespace ndn - -#endif // NDN_UTIL_NOTIFICATION_STREAM_HPP diff --git a/src/util/notification-subscriber.hpp b/src/util/notification-subscriber.hpp deleted file mode 100644 index a102cfa72..000000000 --- a/src/util/notification-subscriber.hpp +++ /dev/null @@ -1,299 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** - * Original copyright notice from NFD: - * - * Copyright (c) 2014, Regents of the University of California, - * Arizona Board of Regents, - * Colorado State University, - * University Pierre & Marie Curie, Sorbonne University, - * Washington University in St. Louis, - * Beijing Institute of Technology, - * The University of Memphis - * - * This file is part of NFD (Named Data Networking Forwarding Daemon). - * See AUTHORS.md for complete list of NFD authors and contributors. - * - * NFD 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. - * - * NFD 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 - * NFD, e.g., in COPYING.md file. If not, see . - */ - -#ifndef NDN_UTIL_NOTIFICATION_SUBSCRIBER_HPP -#define NDN_UTIL_NOTIFICATION_SUBSCRIBER_HPP - -#include "../face.hpp" -#include "signal.hpp" -#include "concepts.hpp" -#include "time.hpp" -#include "random.hpp" -#include "scheduler.hpp" -#include "scheduler-scoped-event-id.hpp" -#include - -namespace ndn { -namespace util { - -/** \brief provides a subscriber of Notification Stream - * \sa http://redmine.named-data.net/projects/nfd/wiki/Notification - * \tparam Notification type of Notification item, appears in payload of Data packets - */ -template -class NotificationSubscriber : noncopyable -{ -public: - BOOST_CONCEPT_ASSERT((boost::DefaultConstructible)); - BOOST_CONCEPT_ASSERT((WireDecodable)); - - /** \brief construct a NotificationSubscriber - * \note The subscriber is not started after construction. - * User should add one or more handlers to onNotification, and invoke .start(). - */ - NotificationSubscriber(Face& face, const Name& prefix, - const time::milliseconds& interestLifetime = time::milliseconds(60000)) - : m_face(face) - , m_prefix(prefix) - , m_isRunning(false) - , m_lastSequenceNo(std::numeric_limits::max()) - , m_lastNackSequenceNo(std::numeric_limits::max()) - , m_attempts(1) - , m_scheduler(face.getIoService()) - , m_nackEvent(m_scheduler) - , m_interestLifetime(interestLifetime) - { - } - - virtual - ~NotificationSubscriber() - { - } - - /** \return InterestLifetime of Interests to retrieve notifications - * \details This must be greater than FreshnessPeriod of Notification Data packets, - * to ensure correct operation of this subscriber implementation. - */ - time::milliseconds - getInterestLifetime() const - { - return m_interestLifetime; - } - - bool - isRunning() const - { - return m_isRunning; - } - - /** \brief start or resume receiving notifications - * \note onNotification must have at least one listener, - * otherwise this operation has no effect. - */ - void - start() - { - if (m_isRunning) // already running - return; - m_isRunning = true; - - this->sendInitialInterest(); - } - - /** \brief stop receiving notifications - */ - void - stop() - { - if (!m_isRunning) // not running - return; - m_isRunning = false; - - if (m_lastInterestId != 0) - m_face.removePendingInterest(m_lastInterestId); - m_lastInterestId = 0; - } - -public: // subscriptions - /** \brief fires when a Notification is received - * \note Removing all handlers will cause the subscriber to stop. - */ - signal::Signal onNotification; - - /** \brief fires when a NACK is received - */ - signal::Signal onNack; - - /** \brief fires when no Notification is received within .getInterestLifetime period - */ - signal::Signal onTimeout; - - /** \brief fires when a Data packet in the Notification Stream cannot be decoded as Notification - */ - signal::Signal onDecodeError; - -private: - void - sendInitialInterest() - { - if (this->shouldStop()) - return; - - shared_ptr interest = make_shared(m_prefix); - interest->setMustBeFresh(true); - interest->setChildSelector(1); - interest->setInterestLifetime(getInterestLifetime()); - - m_lastInterestId = m_face.expressInterest(*interest, - bind(&NotificationSubscriber::afterReceiveData, this, _2), - bind(&NotificationSubscriber::afterReceiveNack, this, _2), - bind(&NotificationSubscriber::afterTimeout, this)); - } - - void - sendNextInterest() - { - if (this->shouldStop()) - return; - - BOOST_ASSERT(m_lastSequenceNo != - std::numeric_limits::max());// overflow or missing initial reply - - Name nextName = m_prefix; - nextName.appendSequenceNumber(m_lastSequenceNo + 1); - - shared_ptr interest = make_shared(nextName); - interest->setInterestLifetime(getInterestLifetime()); - - m_lastInterestId = m_face.expressInterest(*interest, - bind(&NotificationSubscriber::afterReceiveData, this, _2), - bind(&NotificationSubscriber::afterReceiveNack, this, _2), - bind(&NotificationSubscriber::afterTimeout, this)); - } - - /** \brief Check if the subscriber is or should be stopped. - * \return true if the subscriber is stopped. - */ - bool - shouldStop() - { - if (!m_isRunning) - return true; - if (onNotification.isEmpty() && onNack.isEmpty()) { - this->stop(); - return true; - } - return false; - } - - void - afterReceiveData(const Data& data) - { - if (this->shouldStop()) - return; - - Notification notification; - try { - m_lastSequenceNo = data.getName().get(-1).toSequenceNumber(); - notification.wireDecode(data.getContent().blockFromValue()); - } - catch (tlv::Error&) { - this->onDecodeError(data); - this->sendInitialInterest(); - return; - } - - this->onNotification(notification); - - this->sendNextInterest(); - } - - void - afterReceiveNack(const lp::Nack& nack) - { - if (this->shouldStop()) - return; - - this->onNack(nack); - - time::milliseconds delay = exponentialBackoff(nack); - m_nackEvent = m_scheduler.scheduleEvent(delay, [this] {this->sendInitialInterest();}); - } - - void - afterTimeout() - { - if (this->shouldStop()) - return; - - this->onTimeout(); - - this->sendInitialInterest(); - } - - time::milliseconds - exponentialBackoff(lp::Nack nack) - { - uint64_t nackSequenceNo; - - try { - nackSequenceNo = nack.getInterest().getName().get(-1).toSequenceNumber(); - } - catch (name::Component::Error&) { - nackSequenceNo = 0; - } - - if (m_lastNackSequenceNo == nackSequenceNo) { - ++m_attempts; - } else { - m_attempts = 1; - } - - time::milliseconds delayTime = - time::milliseconds (static_cast( pow(2, m_attempts) * 100 + random::generateWord32() % 100)); - - m_lastNackSequenceNo = nackSequenceNo; - return delayTime; - } - -private: - Face& m_face; - Name m_prefix; - bool m_isRunning; - uint64_t m_lastSequenceNo; - uint64_t m_lastNackSequenceNo; - uint64_t m_attempts; - util::scheduler::Scheduler m_scheduler; - util::scheduler::ScopedEventId m_nackEvent; - const PendingInterestId* m_lastInterestId; - time::milliseconds m_interestLifetime; -}; - -} // namespace util -} // namespace ndn - -#endif // NDN_UTIL_NOTIFICATION_SUBSCRIBER_HPP diff --git a/src/util/random.cpp b/src/util/random.cpp deleted file mode 100644 index 41775e420..000000000 --- a/src/util/random.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "random.hpp" -#include "../security/detail/openssl.hpp" - -#include - -namespace ndn { -namespace random { - -uint32_t -generateSecureWord32() -{ - uint32_t random; - generateSecureBytes(reinterpret_cast(&random), sizeof(random)); - return random; -} - -uint64_t -generateSecureWord64() -{ - uint64_t random; - generateSecureBytes(reinterpret_cast(&random), sizeof(random)); - return random; -} - -void -generateSecureBytes(uint8_t* bytes, size_t size) -{ - if (RAND_bytes(bytes, size) != 1) { - BOOST_THROW_EXCEPTION(std::runtime_error("Failed to generate random bytes (error code " + - std::to_string(ERR_get_error()) + ")")); - } -} - -static std::mt19937& -getRandomGenerator() -{ - static std::mt19937 rng{std::random_device{}()}; - return rng; -} - -uint32_t -generateWord32() -{ - static std::uniform_int_distribution distribution; - return distribution(getRandomGenerator()); -} - -uint64_t -generateWord64() -{ - static std::uniform_int_distribution distribution; - return distribution(getRandomGenerator()); -} - -} // namespace random -} // namespace ndn diff --git a/src/util/regex/regex-backref-manager.hpp b/src/util/regex/regex-backref-manager.hpp deleted file mode 100644 index ceb1337d4..000000000 --- a/src/util/regex/regex-backref-manager.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_UTIL_REGEX_BACKREF_MANAGER_HPP -#define NDN_UTIL_REGEX_BACKREF_MANAGER_HPP - -#include "../../common.hpp" - -#include - -namespace ndn { - -class RegexMatcher; - -class RegexBackrefManager -{ -public: - RegexBackrefManager() - { - } - - virtual - ~RegexBackrefManager(); - - size_t - pushRef(const shared_ptr& matcher); - - void - popRef(); - - size_t - size(); - - const shared_ptr& - getBackref(size_t backrefNo); - -private: - std::vector > m_backrefs; -}; - - -inline -RegexBackrefManager::~RegexBackrefManager() -{ - m_backrefs.clear(); -} - -inline size_t -RegexBackrefManager::pushRef(const shared_ptr& matcher) -{ - size_t last = m_backrefs.size(); - m_backrefs.push_back(matcher); - - return last; -} - -inline void -RegexBackrefManager::popRef() -{ - m_backrefs.pop_back(); -} - -inline size_t -RegexBackrefManager::size() -{ - return m_backrefs.size(); -} - -inline const shared_ptr& -RegexBackrefManager::getBackref(size_t backrefNo) -{ - return m_backrefs[backrefNo]; -} - - -} // namespace ndn - -#endif // NDN_UTIL_REGEX_BACKREF_MANAGER_HPP diff --git a/src/util/regex/regex-backref-matcher.hpp b/src/util/regex/regex-backref-matcher.hpp deleted file mode 100644 index d5145729b..000000000 --- a/src/util/regex/regex-backref-matcher.hpp +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_UTIL_REGEX_REGEX_BACKREF_MATCHER_HPP -#define NDN_UTIL_REGEX_REGEX_BACKREF_MATCHER_HPP - -#include "../../common.hpp" - -#include "regex-matcher.hpp" - -namespace ndn { - -class RegexBackrefMatcher : public RegexMatcher -{ -public: - RegexBackrefMatcher(const std::string& expr, shared_ptr backrefManager); - - virtual - ~RegexBackrefMatcher() - { - } - - void - lateCompile() - { - compile(); - } - -protected: - virtual void - compile(); -}; - -} // namespace ndn - -#include "regex-pattern-list-matcher.hpp" - -namespace ndn { - -inline -RegexBackrefMatcher::RegexBackrefMatcher(const std::string& expr, - shared_ptr backrefManager) - : RegexMatcher(expr, EXPR_BACKREF, backrefManager) -{ - // compile(); -} - -inline void -RegexBackrefMatcher::compile() -{ - if (m_expr.size() < 2) - BOOST_THROW_EXCEPTION(RegexMatcher::Error("Unrecognized format: " + m_expr)); - - size_t lastIndex = m_expr.size() - 1; - if ('(' == m_expr[0] && ')' == m_expr[lastIndex]) { - // m_backRefManager->pushRef(this); - - shared_ptr matcher(new RegexPatternListMatcher(m_expr.substr(1, lastIndex - 1), - m_backrefManager)); - m_matchers.push_back(matcher); - } - else - BOOST_THROW_EXCEPTION(RegexMatcher::Error("Unrecognized format: " + m_expr)); -} - - -} // namespace ndn - -#endif // NDN_UTIL_REGEX_REGEX_BACKREF_MATCHER_HPP diff --git a/src/util/regex/regex-component-matcher.hpp b/src/util/regex/regex-component-matcher.hpp deleted file mode 100644 index 08cefdb46..000000000 --- a/src/util/regex/regex-component-matcher.hpp +++ /dev/null @@ -1,148 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_UTIL_REGEX_REGEX_COMPONENT_MATCHER_HPP -#define NDN_UTIL_REGEX_REGEX_COMPONENT_MATCHER_HPP - -#include - -#include "regex-matcher.hpp" -#include "regex-pseudo-matcher.hpp" - -namespace ndn { - -class RegexComponentMatcher : public RegexMatcher -{ -public: - /** - * @brief Create a RegexComponent matcher from expr - * @param expr The standard regular expression to match a component - * @param backrefManager The back reference manager - * @param isExactMatch The flag to provide exact match - */ - RegexComponentMatcher(const std::string& expr, - shared_ptr backrefManager, - bool isExactMatch = true); - - virtual - ~RegexComponentMatcher() - { - } - - virtual bool - match(const Name& name, size_t offset, size_t len = 1); - -protected: - /** - * @brief Compile the regular expression to generate the more matchers when necessary - */ - virtual void - compile(); - -private: - bool m_isExactMatch; - boost::regex m_componentRegex; - std::vector > m_pseudoMatchers; - -}; - - -inline -RegexComponentMatcher::RegexComponentMatcher(const std::string& expr, - shared_ptr backrefManager, - bool isExactMatch) - : RegexMatcher(expr, EXPR_COMPONENT, backrefManager) - , m_isExactMatch(isExactMatch) -{ - compile(); -} - -// Re: http://www.boost.org/users/history/version_1_56_0.html -// -// Breaking change: corrected behavior of basic_regex<>::mark_count() to match existing -// documentation, basic_regex<>::subexpression(n) changed to match, see -// https://svn.boost.org/trac/boost/ticket/9227 -static const size_t BOOST_REGEXP_MARK_COUNT_CORRECTION = -#if BOOST_VERSION < 105600 - 1; -#else - 0; -#endif - -inline void -RegexComponentMatcher::compile() -{ - m_componentRegex = boost::regex(m_expr); - - m_pseudoMatchers.clear(); - m_pseudoMatchers.push_back(make_shared()); - - for (size_t i = 1; - i <= m_componentRegex.mark_count() - BOOST_REGEXP_MARK_COUNT_CORRECTION; i++) - { - shared_ptr pMatcher = make_shared(); - m_pseudoMatchers.push_back(pMatcher); - m_backrefManager->pushRef(static_pointer_cast(pMatcher)); - } -} - -inline bool -RegexComponentMatcher::match(const Name& name, size_t offset, size_t len) -{ - m_matchResult.clear(); - - if (m_expr.empty()) - { - m_matchResult.push_back(name.get(offset)); - return true; - } - - if (m_isExactMatch) - { - boost::smatch subResult; - std::string targetStr = name.get(offset).toUri(); - if (boost::regex_match(targetStr, subResult, m_componentRegex)) - { - for (size_t i = 1; - i <= m_componentRegex.mark_count() - BOOST_REGEXP_MARK_COUNT_CORRECTION; i++) - { - m_pseudoMatchers[i]->resetMatchResult(); - m_pseudoMatchers[i]->setMatchResult(subResult[i]); - } - m_matchResult.push_back(name.get(offset)); - return true; - } - } - else - { - BOOST_THROW_EXCEPTION(RegexMatcher::Error("Non-exact component search is not supported " - "yet")); - } - - return false; -} - - -} // namespace ndn - -#endif // NDN_UTIL_REGEX_REGEX_COMPONENT_MATCHER_HPP diff --git a/src/util/regex/regex-component-set-matcher.hpp b/src/util/regex/regex-component-set-matcher.hpp deleted file mode 100644 index 7bf5a5e20..000000000 --- a/src/util/regex/regex-component-set-matcher.hpp +++ /dev/null @@ -1,225 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_UTIL_REGEX_COMPONENT_SET_MATCHER_HPP -#define NDN_UTIL_REGEX_COMPONENT_SET_MATCHER_HPP - -#include "../../common.hpp" - -#include "regex-matcher.hpp" -#include "regex-component-matcher.hpp" - -#include - -namespace ndn { - -class RegexComponentSetMatcher : public RegexMatcher -{ -public: - /** - * @brief Create a RegexComponentSetMatcher matcher from expr - * @param expr The standard regular expression to match a component - * @param backrefManager Shared pointer to back-reference manager - */ - RegexComponentSetMatcher(const std::string& expr, shared_ptr backrefManager); - - virtual - ~RegexComponentSetMatcher(); - - virtual bool - match(const Name& name, size_t offset, size_t len = 1); - -protected: - /** - * @brief Compile the regular expression to generate the more matchers when necessary - */ - virtual void - compile(); - -private: - size_t - extractComponent(size_t index); - - void - compileSingleComponent(); - - void - compileMultipleComponents(size_t start, size_t lastIndex); - -private: - typedef std::set > ComponentsSet; - ComponentsSet m_components; - bool m_isInclusion; -}; - - -inline -RegexComponentSetMatcher::RegexComponentSetMatcher(const std::string& expr, - shared_ptr backrefManager) - : RegexMatcher(expr, EXPR_COMPONENT_SET, backrefManager) - , m_isInclusion(true) -{ - compile(); -} - -inline -RegexComponentSetMatcher::~RegexComponentSetMatcher() -{ -} - -inline void -RegexComponentSetMatcher::compile() -{ - if (m_expr.size() < 2) - BOOST_THROW_EXCEPTION(RegexMatcher::Error("Regexp compile error (cannot parse " + - m_expr + ")")); - - switch (m_expr[0]) { - case '<': - return compileSingleComponent(); - case '[': - { - size_t lastIndex = m_expr.size() - 1; - if (']' != m_expr[lastIndex]) - BOOST_THROW_EXCEPTION(RegexMatcher::Error("Regexp compile error (no matching ']' in " + - m_expr + ")")); - - if ('^' == m_expr[1]) { - m_isInclusion = false; - compileMultipleComponents(2, lastIndex); - } - else - compileMultipleComponents(1, lastIndex); - break; - } - default: - BOOST_THROW_EXCEPTION(RegexMatcher::Error("Regexp compile error (cannot parse " + - m_expr + ")")); - } -} - -inline void -RegexComponentSetMatcher::compileSingleComponent() -{ - size_t end = extractComponent(1); - - if (m_expr.size() != end) - { - BOOST_THROW_EXCEPTION(RegexMatcher::Error("Component expr error " + m_expr)); - } - else - { - shared_ptr component = - make_shared(m_expr.substr(1, end - 2), m_backrefManager); - - m_components.insert(component); - } -} - -inline void -RegexComponentSetMatcher::compileMultipleComponents(size_t start, size_t lastIndex) -{ - size_t index = start; - size_t tempIndex = start; - - while (index < lastIndex) { - if ('<' != m_expr[index]) - BOOST_THROW_EXCEPTION(RegexMatcher::Error("Component expr error " + m_expr)); - - tempIndex = index + 1; - index = extractComponent(tempIndex); - - shared_ptr component = - make_shared(m_expr.substr(tempIndex, index - tempIndex - 1), - m_backrefManager); - - m_components.insert(component); - } - - if (index != lastIndex) - BOOST_THROW_EXCEPTION(RegexMatcher::Error("Not sufficient expr to parse " + m_expr)); -} - -inline bool -RegexComponentSetMatcher::match(const Name& name, size_t offset, size_t len) -{ - bool isMatched = false; - - /* componentset only matches one component */ - if (len != 1) - { - return false; - } - - for (ComponentsSet::iterator it = m_components.begin(); - it != m_components.end(); - ++it) - { - if ((*it)->match(name, offset, len)) - { - isMatched = true; - break; - } - } - - m_matchResult.clear(); - - if (m_isInclusion ? isMatched : !isMatched) - { - m_matchResult.push_back(name.get(offset)); - return true; - } - else - return false; -} - -inline size_t -RegexComponentSetMatcher::extractComponent(size_t index) -{ - size_t lcount = 1; - size_t rcount = 0; - - while (lcount > rcount) { - switch (m_expr[index]) { - case '<': - lcount++; - break; - - case '>': - rcount++; - break; - - case 0: - BOOST_THROW_EXCEPTION(RegexMatcher::Error("Error: square brackets mismatch")); - break; - } - index++; - - } - - return index; -} - -} // namespace ndn - -#endif // NDN_UTIL_REGEX_COMPONENT_SET_MATCHER_HPP diff --git a/src/util/regex/regex-matcher.hpp b/src/util/regex/regex-matcher.hpp deleted file mode 100644 index 9b5d26f8b..000000000 --- a/src/util/regex/regex-matcher.hpp +++ /dev/null @@ -1,179 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_UTIL_REGEX_REGEX_MATCHER_H -#define NDN_UTIL_REGEX_REGEX_MATCHER_H - -#include "../../common.hpp" -#include "../../name.hpp" - -namespace ndn { - -class RegexBackrefManager; - -class RegexMatcher -{ -public: - class Error : public std::runtime_error - { - public: - explicit - Error(const std::string& what) - : std::runtime_error(what) - { - } - }; - - enum RegexExprType { - EXPR_TOP, - EXPR_PATTERN_LIST, - EXPR_REPEAT_PATTERN, - EXPR_BACKREF, - EXPR_COMPONENT_SET, - EXPR_COMPONENT, - EXPR_PSEUDO - }; - - RegexMatcher(const std::string& expr, - const RegexExprType& type, - shared_ptr backrefManager = shared_ptr()); - - virtual - ~RegexMatcher(); - - virtual bool - match(const Name& name, size_t offset, size_t len); - - /** - * @brief get the matched name components - * @returns the matched name components - */ - const std::vector& - getMatchResult() const - { - return m_matchResult; - } - - const std::string& - getExpr() const - { - return m_expr; - } - -protected: - /** - * @brief Compile the regular expression to generate the more matchers when necessary - */ - virtual void - compile() = 0; - -private: - bool - recursiveMatch(size_t matcherNo, const Name& name, size_t offset, size_t len); - - -protected: - const std::string m_expr; - const RegexExprType m_type; - shared_ptr m_backrefManager; - std::vector > m_matchers; - std::vector m_matchResult; -}; - -inline std::ostream& -operator<<(std::ostream& os, const RegexMatcher& regex) -{ - os << regex.getExpr(); - return os; -} - -} // namespace ndn - -#include "regex-backref-manager.hpp" - -namespace ndn { - -inline -RegexMatcher::RegexMatcher(const std::string& expr, - const RegexExprType& type, - shared_ptr backrefManager) - : m_expr(expr) - , m_type(type) - , m_backrefManager(backrefManager) -{ - if (!static_cast(m_backrefManager)) - m_backrefManager = make_shared(); -} - -inline -RegexMatcher::~RegexMatcher() -{ -} - -inline bool -RegexMatcher::match(const Name& name, size_t offset, size_t len) -{ - bool result = false; - - m_matchResult.clear(); - - if (recursiveMatch(0, name, offset, len)) - { - for (size_t i = offset; i < offset + len ; i++) - m_matchResult.push_back(name.get(i)); - result = true; - } - else - { - result = false; - } - - return result; -} - -inline bool -RegexMatcher::recursiveMatch(size_t matcherNo, const Name& name, size_t offset, size_t len) -{ - ssize_t tried = len; - - if (matcherNo >= m_matchers.size()) - return (len == 0); - - shared_ptr matcher = m_matchers[matcherNo]; - - while (tried >= 0) - { - if (matcher->match(name, offset, tried) && - recursiveMatch(matcherNo + 1, name, offset + tried, len - tried)) - return true; - tried--; - } - - return false; -} - - -} // namespace ndn - - -#endif // NDN_UTIL_REGEX_REGEX_MATCHER_H diff --git a/src/util/regex/regex-pattern-list-matcher.hpp b/src/util/regex/regex-pattern-list-matcher.hpp deleted file mode 100644 index fb0743bd9..000000000 --- a/src/util/regex/regex-pattern-list-matcher.hpp +++ /dev/null @@ -1,199 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_UTIL_REGEX_REGEX_PATTERN_LIST_MATCHER_HPP -#define NDN_UTIL_REGEX_REGEX_PATTERN_LIST_MATCHER_HPP - -#include "../../common.hpp" - -#include "regex-matcher.hpp" - -namespace ndn { - -class RegexBackrefManager; - -class RegexPatternListMatcher : public RegexMatcher -{ -public: - RegexPatternListMatcher(const std::string& expr, shared_ptr backrefManager); - - virtual - ~RegexPatternListMatcher() - { - }; - -protected: - virtual void - compile(); - -private: - bool - extractPattern(size_t index, size_t* next); - - int - extractSubPattern(const char left, const char right, size_t index); - - int - extractRepetition(size_t index); - -private: - -}; - -} // namespace ndn - -#include "regex-repeat-matcher.hpp" -#include "regex-backref-matcher.hpp" - -namespace ndn { - -inline -RegexPatternListMatcher::RegexPatternListMatcher(const std::string& expr, - shared_ptr backrefManager) - : RegexMatcher(expr, EXPR_PATTERN_LIST, backrefManager) -{ - compile(); -} - -inline void -RegexPatternListMatcher::compile() -{ - size_t len = m_expr.size(); - size_t index = 0; - size_t subHead = index; - - while (index < len) { - subHead = index; - - if (!extractPattern(subHead, &index)) - BOOST_THROW_EXCEPTION(RegexMatcher::Error("Compile error")); - } -} - -inline bool -RegexPatternListMatcher::extractPattern(size_t index, size_t* next) -{ - size_t start = index; - size_t end = index; - size_t indicator = index; - - switch (m_expr[index]) { - case '(': - index++; - index = extractSubPattern('(', ')', index); - indicator = index; - end = extractRepetition(index); - if (indicator == end) { - shared_ptr matcher = - make_shared(m_expr.substr(start, end - start), m_backrefManager); - m_backrefManager->pushRef(matcher); - dynamic_pointer_cast(matcher)->lateCompile(); - - m_matchers.push_back(matcher); - } - else - m_matchers.push_back(make_shared(m_expr.substr(start, end - start), - m_backrefManager, indicator - start)); - break; - - case '<': - index++; - index = extractSubPattern('<', '>', index); - indicator = index; - end = extractRepetition(index); - m_matchers.push_back(make_shared(m_expr.substr(start, end - start), - m_backrefManager, indicator - start)); - break; - - case '[': - index++; - index = extractSubPattern('[', ']', index); - indicator = index; - end = extractRepetition(index); - m_matchers.push_back(make_shared(m_expr.substr(start, end - start), - m_backrefManager, indicator - start)); - break; - - default: - BOOST_THROW_EXCEPTION(RegexMatcher::Error("Unexpected syntax")); - } - - *next = end; - - return true; -} - -inline int -RegexPatternListMatcher::extractSubPattern(const char left, const char right, size_t index) -{ - size_t lcount = 1; - size_t rcount = 0; - - while (lcount > rcount) { - - if (index >= m_expr.size()) - BOOST_THROW_EXCEPTION(RegexMatcher::Error("Parenthesis mismatch")); - - if (left == m_expr[index]) - lcount++; - - if (right == m_expr[index]) - rcount++; - - index++; - } - return index; -} - -inline int -RegexPatternListMatcher::extractRepetition(size_t index) -{ - size_t exprSize = m_expr.size(); - - if (index == exprSize) - return index; - - if (('+' == m_expr[index] || '?' == m_expr[index] || '*' == m_expr[index])) { - return ++index; - } - - if ('{' == m_expr[index]) { - while ('}' != m_expr[index]) { - index++; - if (index == exprSize) - break; - } - if (index == exprSize) - BOOST_THROW_EXCEPTION(RegexMatcher::Error("Missing right brace bracket")); - else - return ++index; - } - else { - return index; - } -} - - -} // namespace ndn - -#endif // NDN_UTIL_REGEX_REGEX_PATTERN_LIST_MATCHER_HPP diff --git a/src/util/regex/regex-pseudo-matcher.hpp b/src/util/regex/regex-pseudo-matcher.hpp deleted file mode 100644 index 990840afe..000000000 --- a/src/util/regex/regex-pseudo-matcher.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_UTIL_REGEX_REGEX_PSEUDO_MATCHER_HPP -#define NDN_UTIL_REGEX_REGEX_PSEUDO_MATCHER_HPP - -#include "../../common.hpp" -#include "regex-matcher.hpp" - -namespace ndn { - -class RegexPseudoMatcher : public RegexMatcher -{ -public: - RegexPseudoMatcher(); - - virtual - ~RegexPseudoMatcher() - { - } - - virtual void - compile() - { - } - - void - setMatchResult(const std::string& str); - - void - resetMatchResult(); -}; - -inline -RegexPseudoMatcher::RegexPseudoMatcher() - : RegexMatcher("", EXPR_PSEUDO) -{ -} - -inline void -RegexPseudoMatcher::setMatchResult(const std::string& str) -{ - m_matchResult.push_back(name::Component(reinterpret_cast(str.c_str()), - str.size())); -} - -inline void -RegexPseudoMatcher::resetMatchResult() -{ - m_matchResult.clear(); -} - - -} // namespace ndn - -#endif // NDN_UTIL_REGEX_REGEX_PSEUDO_MATCHER_HPP diff --git a/src/util/regex/regex-repeat-matcher.hpp b/src/util/regex/regex-repeat-matcher.hpp deleted file mode 100644 index 3baaa4698..000000000 --- a/src/util/regex/regex-repeat-matcher.hpp +++ /dev/null @@ -1,234 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_UTIL_REGEX_REGEX_REPEAT_MATCHER_HPP -#define NDN_UTIL_REGEX_REGEX_REPEAT_MATCHER_HPP - -#include "../../common.hpp" - -#include - -#include "regex-matcher.hpp" - -namespace ndn { - -class RegexRepeatMatcher : public RegexMatcher -{ -public: - RegexRepeatMatcher(const std::string& expr, - shared_ptr backrefManager, - size_t indicator); - - virtual - ~RegexRepeatMatcher() - { - } - - virtual bool - match(const Name& name, size_t offset, size_t len); - -protected: - /** - * @brief Compile the regular expression to generate the more matchers when necessary - */ - virtual void - compile(); - -private: - bool - parseRepetition(); - - bool - recursiveMatch(size_t repeat, - const Name& name, - size_t offset, size_t len); - -private: - size_t m_indicator; - size_t m_repeatMin; - size_t m_repeatMax; -}; - -} // namespace ndn - -#include "regex-backref-matcher.hpp" -#include "regex-component-set-matcher.hpp" - -namespace ndn { - -inline -RegexRepeatMatcher::RegexRepeatMatcher(const std::string& expr, - shared_ptr backrefManager, - size_t indicator) - : RegexMatcher(expr, EXPR_REPEAT_PATTERN, backrefManager) - , m_indicator(indicator) -{ - compile(); -} - -inline void -RegexRepeatMatcher::compile() -{ - shared_ptr matcher; - - if ('(' == m_expr[0]) { - matcher = make_shared(m_expr.substr(0, m_indicator), m_backrefManager); - m_backrefManager->pushRef(matcher); - dynamic_pointer_cast(matcher)->lateCompile(); - } - else{ - matcher = make_shared(m_expr.substr(0, m_indicator), - m_backrefManager); - } - m_matchers.push_back(matcher); - - parseRepetition(); -} - -inline bool -RegexRepeatMatcher::parseRepetition() -{ - size_t exprSize = m_expr.size(); - const size_t MAX_REPETITIONS = std::numeric_limits::max(); - - if (exprSize == m_indicator) { - m_repeatMin = 1; - m_repeatMax = 1; - - return true; - } - else { - if (exprSize == (m_indicator + 1)) { - if ('?' == m_expr[m_indicator]) { - m_repeatMin = 0; - m_repeatMax = 1; - return true; - } - if ('+' == m_expr[m_indicator]) { - m_repeatMin = 1; - m_repeatMax = MAX_REPETITIONS; - return true; - } - if ('*' == m_expr[m_indicator]) { - m_repeatMin = 0; - m_repeatMax = MAX_REPETITIONS; - return true; - } - } - else { - std::string repeatStruct = m_expr.substr(m_indicator, exprSize - m_indicator); - size_t rsSize = repeatStruct.size(); - size_t min = 0; - size_t max = 0; - - if (boost::regex_match(repeatStruct, boost::regex("\\{[0-9]+,[0-9]+\\}"))) { - size_t separator = repeatStruct.find_first_of(',', 0); - min = atoi(repeatStruct.substr(1, separator - 1).c_str()); - max = atoi(repeatStruct.substr(separator + 1, rsSize - separator - 2).c_str()); - } - else if (boost::regex_match(repeatStruct, boost::regex("\\{,[0-9]+\\}"))) { - size_t separator = repeatStruct.find_first_of(',', 0); - min = 0; - max = atoi(repeatStruct.substr(separator + 1, rsSize - separator - 2).c_str()); - } - else if (boost::regex_match(repeatStruct, boost::regex("\\{[0-9]+,\\}"))) { - size_t separator = repeatStruct.find_first_of(',', 0); - min = atoi(repeatStruct.substr(1, separator).c_str()); - max = MAX_REPETITIONS; - } - else if (boost::regex_match(repeatStruct, boost::regex("\\{[0-9]+\\}"))) { - min = atoi(repeatStruct.substr(1, rsSize - 1).c_str()); - max = min; - } - else - BOOST_THROW_EXCEPTION(RegexMatcher::Error(std::string("Error: RegexRepeatMatcher.ParseRepetition():") - + " Unrecognized format "+ m_expr)); - - if (min > MAX_REPETITIONS || max > MAX_REPETITIONS || min > max) - BOOST_THROW_EXCEPTION(RegexMatcher::Error(std::string("Error: RegexRepeatMatcher.ParseRepetition():") - + " Wrong number " + m_expr)); - - m_repeatMin = min; - m_repeatMax = max; - - return true; - } - } - return false; -} - -inline bool -RegexRepeatMatcher::match(const Name& name, size_t offset, size_t len) -{ - m_matchResult.clear(); - - if (0 == m_repeatMin) - if (0 == len) - return true; - - if (recursiveMatch(0, name, offset, len)) - { - for (size_t i = offset; i < offset + len; i++) - m_matchResult.push_back(name.get(i)); - return true; - } - else - return false; -} - -inline bool -RegexRepeatMatcher::recursiveMatch(size_t repeat, const Name& name, size_t offset, size_t len) -{ - ssize_t tried = len; - shared_ptr matcher = m_matchers[0]; - - if (0 < len && repeat >= m_repeatMax) - { - return false; - } - - if (0 == len && repeat < m_repeatMin) - { - return false; - } - - if (0 == len && repeat >= m_repeatMin) - { - return true; - } - - while (tried >= 0) - { - if (matcher->match(name, offset, tried) && - recursiveMatch(repeat + 1, name, offset + tried, len - tried)) - return true; - tried--; - } - - return false; -} - - -} // namespace ndn - -#endif // NDN_UTIL_REGEX_REGEX_REPEAT_MATCHER_HPP diff --git a/src/util/regex/regex-top-matcher.cpp b/src/util/regex/regex-top-matcher.cpp deleted file mode 100644 index d9ff669c8..000000000 --- a/src/util/regex/regex-top-matcher.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#include "regex-top-matcher.hpp" - -#include "regex-backref-manager.hpp" -#include "regex-pattern-list-matcher.hpp" - -#include - -namespace ndn { - -RegexTopMatcher::RegexTopMatcher(const std::string& expr, const std::string& expand) - : RegexMatcher(expr, EXPR_TOP) - , m_expand(expand) - , m_isSecondaryUsed(false) -{ - m_primaryBackrefManager = make_shared(); - m_secondaryBackrefManager = make_shared(); - compile(); -} - -RegexTopMatcher::~RegexTopMatcher() -{ -} - -void -RegexTopMatcher::compile() -{ - std::string errMsg = "Error: RegexTopMatcher.Compile(): "; - - std::string expr = m_expr; - - if ('$' != expr[expr.size() - 1]) - expr = expr + "<.*>*"; - else - expr = expr.substr(0, expr.size() - 1); - - if ('^' != expr[0]) { - m_secondaryMatcher = make_shared( - "<.*>*" + expr, - m_secondaryBackrefManager); - } - else { - expr = expr.substr(1, expr.size() - 1); - } - - // On OSX 10.9, boost, and C++03 the following doesn't work without ndn:: - // because the argument-dependent lookup prefers STL to boost - m_primaryMatcher = ndn::make_shared(expr, - m_primaryBackrefManager); -} - -bool -RegexTopMatcher::match(const Name& name) -{ - m_isSecondaryUsed = false; - - m_matchResult.clear(); - - if (m_primaryMatcher->match(name, 0, name.size())) - { - m_matchResult = m_primaryMatcher->getMatchResult(); - return true; - } - else - { - if (static_cast(m_secondaryMatcher) && m_secondaryMatcher->match(name, 0, name.size())) - { - m_matchResult = m_secondaryMatcher->getMatchResult(); - m_isSecondaryUsed = true; - return true; - } - return false; - } -} - -bool -RegexTopMatcher::match(const Name& name, size_t, size_t) -{ - return match(name); -} - -Name -RegexTopMatcher::expand(const std::string& expandStr) -{ - Name result; - - shared_ptr backrefManager = - (m_isSecondaryUsed ? m_secondaryBackrefManager : m_primaryBackrefManager); - - size_t backrefNo = backrefManager->size(); - - std::string expand; - - if (!expandStr.empty()) - expand = expandStr; - else - expand = m_expand; - - size_t offset = 0; - while (offset < expand.size()) - { - std::string item = getItemFromExpand(expand, offset); - if (item[0] == '<') - { - result.append(item.substr(1, item.size() - 2)); - } - if (item[0] == '\\') - { - size_t index = boost::lexical_cast(item.substr(1, item.size() - 1)); - - if (0 == index) { - std::vector::iterator it = m_matchResult.begin(); - std::vector::iterator end = m_matchResult.end(); - for (; it != end; it++) - result.append(*it); - } - else if (index <= backrefNo) - { - std::vector::const_iterator it = - backrefManager->getBackref(index - 1)->getMatchResult().begin(); - std::vector::const_iterator end = - backrefManager->getBackref(index - 1)->getMatchResult().end(); - for (; it != end; it++) - result.append(*it); - } - else - BOOST_THROW_EXCEPTION(RegexMatcher::Error("Exceed the range of back reference")); - } - } - return result; -} - -std::string -RegexTopMatcher::getItemFromExpand(const std::string& expand, size_t& offset) -{ - size_t begin = offset; - - if (expand[offset] == '\\') - { - offset++; - if (offset >= expand.size()) - BOOST_THROW_EXCEPTION(RegexMatcher::Error("wrong format of expand string!")); - - while (expand[offset] <= '9' and expand[offset] >= '0') { - offset++; - if (offset > expand.size()) - BOOST_THROW_EXCEPTION(RegexMatcher::Error("wrong format of expand string!")); - } - if (offset > begin + 1) - return expand.substr(begin, offset - begin); - else - BOOST_THROW_EXCEPTION(RegexMatcher::Error("wrong format of expand string!")); - } - else if (expand[offset] == '<') - { - offset++; - if (offset >= expand.size()) - BOOST_THROW_EXCEPTION(RegexMatcher::Error("wrong format of expand string!")); - - size_t left = 1; - size_t right = 0; - while (right < left) - { - if (expand[offset] == '<') - left++; - if (expand[offset] == '>') - right++; - offset++; - if (offset >= expand.size()) - BOOST_THROW_EXCEPTION(RegexMatcher::Error("wrong format of expand string!")); - } - return expand.substr(begin, offset - begin); - } - else - BOOST_THROW_EXCEPTION(RegexMatcher::Error("wrong format of expand string!")); -} - -shared_ptr -RegexTopMatcher::fromName(const Name& name, bool hasAnchor) -{ - std::string regexStr("^"); - - for (Name::const_iterator it = name.begin(); it != name.end(); it++) - { - regexStr.append("<"); - regexStr.append(convertSpecialChar(it->toUri())); - regexStr.append(">"); - } - - if (hasAnchor) - regexStr.append("$"); - - // On OSX 10.9, boost, and C++03 the following doesn't work without ndn:: - // because the argument-dependent lookup prefers STL to boost - return ndn::make_shared(regexStr); -} - -std::string -RegexTopMatcher::convertSpecialChar(const std::string& str) -{ - std::string newStr; - for (size_t i = 0; i < str.size(); i++) - { - char c = str[i]; - switch (c) - { - case '.': - case '[': - case '{': - case '}': - case '(': - case ')': - case '\\': - case '*': - case '+': - case '?': - case '|': - case '^': - case '$': - newStr.push_back('\\'); - // Fallthrough - default: - newStr.push_back(c); - break; - } - } - - return newStr; -} - -} // namespace ndn diff --git a/src/util/scheduler-scoped-event-id.cpp b/src/util/scheduler-scoped-event-id.cpp deleted file mode 100644 index f5378c8f9..000000000 --- a/src/util/scheduler-scoped-event-id.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "scheduler-scoped-event-id.hpp" - -namespace ndn { -namespace util { -namespace scheduler { - -#if NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE -static_assert(std::is_nothrow_move_constructible::value, - "ScopedEventId must be MoveConstructible with noexcept"); -#endif // NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE - -ScopedEventId::ScopedEventId(Scheduler& scheduler) - : m_scheduler(&scheduler) -{ -} - -ScopedEventId::ScopedEventId(ScopedEventId&& other) noexcept - : m_scheduler(other.m_scheduler) - , m_event(other.m_event) -{ - other.release(); -} - -ScopedEventId& -ScopedEventId::operator=(const EventId& event) -{ - if (m_event != event) { - m_scheduler->cancelEvent(m_event); - m_event = event; - } - return *this; -} - -ScopedEventId::~ScopedEventId() noexcept -{ - m_scheduler->cancelEvent(m_event); -} - -void -ScopedEventId::cancel() -{ - m_scheduler->cancelEvent(m_event); -} - -void -ScopedEventId::release() noexcept -{ - m_event.reset(); -} - -} // namespace scheduler -} // namespace util -} // namespace ndn diff --git a/src/util/scheduler-scoped-event-id.hpp b/src/util/scheduler-scoped-event-id.hpp deleted file mode 100644 index ea270165a..000000000 --- a/src/util/scheduler-scoped-event-id.hpp +++ /dev/null @@ -1,82 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_SCHEDULER_SCOPED_EVENT_ID_HPP -#define NDN_UTIL_SCHEDULER_SCOPED_EVENT_ID_HPP - -#include "scheduler.hpp" - -namespace ndn { -namespace util { -namespace scheduler { - -/** \brief Event that is automatically cancelled upon destruction - */ -class ScopedEventId : noncopyable -{ -public: - /** \brief Construct ScopedEventId tied to the specified scheduler - * \param scheduler Scheduler to which the event is tied. Behavior is undefined if - * scheduler is destructed before an uncanceled ScopedEventId. - */ - explicit - ScopedEventId(Scheduler& scheduler); - - /** \brief move constructor - */ - ScopedEventId(ScopedEventId&& other) noexcept; - - /** \brief assigns an event - * - * If a different event has been assigned to this instance previously, - * that event will be cancelled immediately. - * - * \note The caller should ensure that ScopedEventId is tied to a correct scheduler. - * Behavior is undefined when assigning event scheduled in another scheduler instance. - */ - ScopedEventId& - operator=(const EventId& event); - - /** \brief cancels the event - */ - ~ScopedEventId() noexcept; - - /** \brief cancels the event manually - */ - void - cancel(); - - /** \brief releases the event so that it won't be canceled - * when this ScopedEventId is destructed - */ - void - release() noexcept; - -private: - Scheduler* m_scheduler; // pointer to allow move semantics - EventId m_event; -}; - -} // namespace scheduler -} // namespace util -} // namespace ndn - -#endif // NDN_UTIL_SCHEDULER_SCOPED_EVENT_ID_HPP diff --git a/src/util/scheduler.cpp b/src/util/scheduler.cpp deleted file mode 100644 index 15200c985..000000000 --- a/src/util/scheduler.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "scheduler.hpp" -#include - -namespace ndn { -namespace util { -namespace scheduler { - -class EventInfo : noncopyable -{ -public: - EventInfo(time::nanoseconds after, const EventCallback& callback) - : expireTime(time::steady_clock::now() + after) - , isExpired(false) - , callback(callback) - { - } - - time::nanoseconds - expiresFromNow() const - { - return std::max(expireTime - time::steady_clock::now(), time::nanoseconds::zero()); - } - -public: - time::steady_clock::TimePoint expireTime; - bool isExpired; - EventCallback callback; - EventQueue::const_iterator queueIt; -}; - -bool -EventId::operator!() const -{ - return m_info.expired() || m_info.lock()->isExpired; -} - -bool -EventId::operator==(const EventId& other) const -{ - return (!(*this) && !other) || - !(m_info.owner_before(other.m_info) || other.m_info.owner_before(m_info)); -} - -std::ostream& -operator<<(std::ostream& os, const EventId& eventId) -{ - return os << eventId.m_info.lock(); -} - -bool -EventQueueCompare::operator()(const shared_ptr& a, const shared_ptr& b) const -{ - return a->expireTime < b->expireTime; -} - -Scheduler::Scheduler(boost::asio::io_service& ioService) - : m_deadlineTimer(ioService) - , m_isEventExecuting(false) -{ -} - -EventId -Scheduler::scheduleEvent(const time::nanoseconds& after, const EventCallback& callback) -{ - BOOST_ASSERT(callback != nullptr); - - EventQueue::iterator i = m_queue.insert(make_shared(after, callback)); - (*i)->queueIt = i; - - if (!m_isEventExecuting && i == m_queue.begin()) { - // the new event is the first one to expire - this->scheduleNext(); - } - - return EventId(*i); -} - -void -Scheduler::cancelEvent(const EventId& eventId) -{ - shared_ptr info = eventId.m_info.lock(); - if (info == nullptr || info->isExpired) { - return; // event already expired or cancelled - } - - if (info->queueIt == m_queue.begin()) { - m_deadlineTimer.cancel(); - } - m_queue.erase(info->queueIt); - - if (!m_isEventExecuting) { - this->scheduleNext(); - } -} - -void -Scheduler::cancelAllEvents() -{ - m_queue.clear(); - m_deadlineTimer.cancel(); -} - -void -Scheduler::scheduleNext() -{ - if (!m_queue.empty()) { - m_deadlineTimer.expires_from_now((*m_queue.begin())->expiresFromNow()); - m_deadlineTimer.async_wait(bind(&Scheduler::executeEvent, this, _1)); - } -} - -void -Scheduler::executeEvent(const boost::system::error_code& error) -{ - if (error) { // e.g., cancelled - return; - } - - m_isEventExecuting = true; - - BOOST_SCOPE_EXIT_ALL(this) { - m_isEventExecuting = false; - this->scheduleNext(); - }; - - // process all expired events - time::steady_clock::TimePoint now = time::steady_clock::now(); - while (!m_queue.empty()) { - EventQueue::iterator head = m_queue.begin(); - shared_ptr info = *head; - if (info->expireTime > now) { - break; - } - - m_queue.erase(head); - info->isExpired = true; - info->callback(); - } -} - -} // namespace scheduler -} // namespace util -} // namespace ndn diff --git a/src/util/scheduler.hpp b/src/util/scheduler.hpp deleted file mode 100644 index cad5c09ed..000000000 --- a/src/util/scheduler.hpp +++ /dev/null @@ -1,191 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_SCHEDULER_HPP -#define NDN_UTIL_SCHEDULER_HPP - -#include "../common.hpp" -#include "monotonic_deadline_timer.hpp" - -#include - -namespace ndn { -namespace util { -namespace scheduler { - -/** - * \brief Function to be invoked when a scheduled event expires - */ -typedef function EventCallback; - -/** - * \brief Stores internal information about a scheduled event - */ -class EventInfo; - -/** - * \brief Identifies a scheduled event - */ -class EventId -{ -public: - /** - * \brief Constructs an empty EventId - * \note EventId is implicitly convertible from nullptr. - */ - EventId(std::nullptr_t = nullptr) - { - } - - /** - * \retval true The event is valid. - * \retval false This EventId is empty, or the event is expired or cancelled. - */ - explicit - operator bool() const - { - return !this->operator!(); - } - - /** - * \retval true This EventId is empty, or the event is expired or cancelled. - * \retval false The event is valid. - */ - bool - operator!() const; - - /** - * \return whether this and other refer to the same event, or are both empty/expired/cancelled - */ - bool - operator==(const EventId& other) const; - - bool - operator!=(const EventId& other) const - { - return !this->operator==(other); - } - - /** - * \brief clear this EventId - * \note This does not cancel the event. - * \post !(*this) - */ - void - reset() - { - m_info.reset(); - } - -private: - explicit - EventId(const weak_ptr& info) - : m_info(info) - { - } - -private: - weak_ptr m_info; - - friend class Scheduler; - friend std::ostream& operator<<(std::ostream& os, const EventId& eventId); -}; - -std::ostream& -operator<<(std::ostream& os, const EventId& eventId); - -class EventQueueCompare -{ -public: - bool - operator()(const shared_ptr& a, const shared_ptr& b) const; -}; - -typedef std::multiset, EventQueueCompare> EventQueue; - -/** - * \brief Generic scheduler - */ -class Scheduler : noncopyable -{ -public: - /** - * \deprecated use EventCallback - */ - typedef EventCallback Event; - - explicit - Scheduler(boost::asio::io_service& ioService); - - /** - * \brief Schedule a one-time event after the specified delay - * \return EventId that can be used to cancel the scheduled event - */ - EventId - scheduleEvent(const time::nanoseconds& after, const EventCallback& callback); - - /** - * \brief Cancel a scheduled event - */ - void - cancelEvent(const EventId& eventId); - - /** - * \brief Cancel all scheduled events - */ - void - cancelAllEvents(); - -private: - /** - * \brief Schedule the next event on the deadline timer - */ - void - scheduleNext(); - - /** - * \brief Execute expired events - * \note If an event callback throws, the exception is propagated to the thread running the - * io_service. In case there are other expired events, they will be processed in the next - * invocation of this method. - */ - void - executeEvent(const boost::system::error_code& code); - -private: - monotonic_deadline_timer m_deadlineTimer; - EventQueue m_queue; - bool m_isEventExecuting; -}; - -} // namespace scheduler - -using util::scheduler::Scheduler; - -} // namespace util - -// for backwards compatibility -using util::scheduler::Scheduler; -using util::scheduler::EventId; - -} // namespace ndn - -#endif // NDN_UTIL_SCHEDULER_HPP diff --git a/src/util/segment-fetcher.cpp b/src/util/segment-fetcher.cpp deleted file mode 100644 index 70ad63237..000000000 --- a/src/util/segment-fetcher.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "segment-fetcher.hpp" -#include "../encoding/buffer-stream.hpp" -#include "../name-component.hpp" -#include "../lp/nack.hpp" -#include "../lp/nack-header.hpp" - -namespace ndn { -namespace util { - -const uint32_t SegmentFetcher::MAX_INTEREST_REEXPRESS = 3; - -SegmentFetcher::SegmentFetcher(Face& face, - shared_ptr validator, - const CompleteCallback& completeCallback, - const ErrorCallback& errorCallback) - : m_face(face) - , m_scheduler(m_face.getIoService()) - , m_validator(validator) - , m_completeCallback(completeCallback) - , m_errorCallback(errorCallback) - , m_buffer(make_shared()) -{ -} - -void -SegmentFetcher::fetch(Face& face, - const Interest& baseInterest, - Validator& validator, - const CompleteCallback& completeCallback, - const ErrorCallback& errorCallback) -{ - shared_ptr sharedValidator = shared_ptr(&validator, [] (Validator*) {}); - - fetch(face, baseInterest, sharedValidator, completeCallback, errorCallback); -} - -void -SegmentFetcher::fetch(Face& face, - const Interest& baseInterest, - shared_ptr validator, - const CompleteCallback& completeCallback, - const ErrorCallback& errorCallback) -{ - shared_ptr fetcher(new SegmentFetcher(face, validator, completeCallback, - errorCallback)); - - fetcher->fetchFirstSegment(baseInterest, fetcher); -} - -void -SegmentFetcher::fetchFirstSegment(const Interest& baseInterest, - shared_ptr self) -{ - Interest interest(baseInterest); - interest.setChildSelector(1); - interest.setMustBeFresh(true); - - m_face.expressInterest(interest, - bind(&SegmentFetcher::afterSegmentReceived, this, _1, _2, true, self), - bind(&SegmentFetcher::afterNackReceived, this, _1, _2, 0, self), - bind(m_errorCallback, INTEREST_TIMEOUT, "Timeout")); -} - -void -SegmentFetcher::fetchNextSegment(const Interest& origInterest, const Name& dataName, - uint64_t segmentNo, - shared_ptr self) -{ - Interest interest(origInterest); // to preserve any selectors - interest.refreshNonce(); - interest.setChildSelector(0); - interest.setMustBeFresh(false); - interest.setName(dataName.getPrefix(-1).appendSegment(segmentNo)); - m_face.expressInterest(interest, - bind(&SegmentFetcher::afterSegmentReceived, this, _1, _2, false, self), - bind(&SegmentFetcher::afterNackReceived, this, _1, _2, 0, self), - bind(m_errorCallback, INTEREST_TIMEOUT, "Timeout")); -} - -void -SegmentFetcher::afterSegmentReceived(const Interest& origInterest, - const Data& data, bool isSegmentZeroExpected, - shared_ptr self) -{ - m_validator->validate(data, - bind(&SegmentFetcher::afterValidationSuccess, this, _1, - isSegmentZeroExpected, origInterest, self), - bind(&SegmentFetcher::afterValidationFailure, this, _1)); - -} - -void -SegmentFetcher::afterValidationSuccess(const shared_ptr data, - bool isSegmentZeroExpected, - const Interest& origInterest, - shared_ptr self) -{ - name::Component currentSegment = data->getName().get(-1); - - if (currentSegment.isSegment()) { - if (isSegmentZeroExpected && currentSegment.toSegment() != 0) { - fetchNextSegment(origInterest, data->getName(), 0, self); - } - else { - m_buffer->write(reinterpret_cast(data->getContent().value()), - data->getContent().value_size()); - - const name::Component& finalBlockId = data->getMetaInfo().getFinalBlockId(); - if (finalBlockId.empty() || (finalBlockId > currentSegment)) { - fetchNextSegment(origInterest, data->getName(), currentSegment.toSegment() + 1, self); - } - else { - return m_completeCallback(m_buffer->buf()); - } - } - } - else { - m_errorCallback(DATA_HAS_NO_SEGMENT, "Data Name has no segment number."); - } -} - -void -SegmentFetcher::afterValidationFailure(const shared_ptr data) -{ - return m_errorCallback(SEGMENT_VALIDATION_FAIL, "Segment validation fail"); -} - - -void -SegmentFetcher::afterNackReceived(const Interest& origInterest, const lp::Nack& nack, - uint32_t reExpressCount, shared_ptr self) -{ - if (reExpressCount >= MAX_INTEREST_REEXPRESS) { - m_errorCallback(NACK_ERROR, "Nack Error"); - } - else { - switch (nack.getReason()) { - case lp::NackReason::DUPLICATE: - reExpressInterest(origInterest, reExpressCount, self); - break; - case lp::NackReason::CONGESTION: - m_scheduler.scheduleEvent(time::milliseconds(static_cast(pow(2, reExpressCount + 1))), - bind(&SegmentFetcher::reExpressInterest, this, - origInterest, reExpressCount, self)); - break; - default: - m_errorCallback(NACK_ERROR, "Nack Error"); - break; - } - } -} - -void -SegmentFetcher::reExpressInterest(Interest interest, uint32_t reExpressCount, - shared_ptr self) -{ - interest.refreshNonce(); - BOOST_ASSERT(interest.hasNonce()); - - bool isSegmentZeroExpected = true; - if (!interest.getName().empty()) { - name::Component lastComponent = interest.getName().get(-1); - isSegmentZeroExpected = !lastComponent.isSegment(); - } - - m_face.expressInterest(interest, - bind(&SegmentFetcher::afterSegmentReceived, this, _1, _2, - isSegmentZeroExpected, self), - bind(&SegmentFetcher::afterNackReceived, this, _1, _2, - ++reExpressCount, self), - bind(m_errorCallback, INTEREST_TIMEOUT, "Timeout")); -} - -} // namespace util -} // namespace ndn diff --git a/src/util/segment-fetcher.hpp b/src/util/segment-fetcher.hpp deleted file mode 100644 index 0c2e908e9..000000000 --- a/src/util/segment-fetcher.hpp +++ /dev/null @@ -1,217 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_SEGMENT_FETCHER_HPP -#define NDN_UTIL_SEGMENT_FETCHER_HPP - -#include "scheduler.hpp" -#include "../common.hpp" -#include "../face.hpp" -#include "../security/validator.hpp" - -namespace ndn { - -class OBufferStream; - -namespace util { - -/** - * @brief Utility class to fetch latest version of the segmented data - * - * SegmentFetcher assumes that the data is named `///`, - * where: - * - `` is the specified prefix, - * - `` is an unknown version that needs to be discovered, and - * - `` is a segment number (number of segments is unknown and is controlled - * by `FinalBlockId` field in at least the last Data packet - * - * The following logic is implemented in SegmentFetcher: - * - * 1. Express first interest to discover version: - * - * >> Interest: `/?ChildSelector=1&MustBeFresh=yes` - * - * 2. Infer the latest version of Data: ` = Data.getName().get(-2)` - * - * 3. If segment number in the retrieved packet == 0, go to step 5. - * - * 4. Send Interest for segment 0: - * - * >> Interest: `///` - * - * 5. Keep sending Interests for the next segment while the retrieved Data does not have - * FinalBlockId or FinalBlockId != Data.getName().get(-1). - * - * >> Interest: `///` - * - * 6. Fire onCompletion callback with memory block that combines content part from all - * segmented objects. - * - * If an error occurs during the fetching process, an error callback is fired - * with a proper error code. The following errors are possible: - * - * - `INTEREST_TIMEOUT`: if any of the Interests times out - * - `DATA_HAS_NO_SEGMENT`: if any of the retrieved Data packets don't have segment - * as a last component of the name (not counting implicit digest) - * - `SEGMENT_VALIDATION_FAIL`: if any retrieved segment fails user-provided validation - * - * In order to validate individual segments, a Validator instance needs to be specified. - * If the segment validation is successful, afterValidationSuccess callback is fired, otherwise - * afterValidationFailure callback. - * - * Examples: - * - * void - * afterFetchComplete(const ConstBufferPtr& data) - * { - * ... - * } - * - * void - * afterFetchError(uint32_t errorCode, const std::string& errorMsg) - * { - * ... - * } - * - * ... - * SegmentFetcher::fetch(face, Interest("/data/prefix", time::seconds(1000)), - * validator, - * bind(&afterFetchComplete, this, _1), - * bind(&afterFetchError, this, _1, _2)); - * - */ -class SegmentFetcher : noncopyable -{ -public: - /** - * @brief Maximum number of times an interest will be reexpressed incase of NackCallback - */ - static const uint32_t MAX_INTEREST_REEXPRESS; - - typedef function CompleteCallback; - typedef function ErrorCallback; - - /** - * @brief Error codes that can be passed to ErrorCallback - */ - enum ErrorCode { - INTEREST_TIMEOUT = 1, - DATA_HAS_NO_SEGMENT = 2, - SEGMENT_VALIDATION_FAIL = 3, - NACK_ERROR = 4 - }; - - /** - * @brief Initiate segment fetching - * - * @param face Reference to the Face that should be used to fetch data - * @param baseInterest An Interest for the initial segment of requested data. - * This interest may include custom InterestLifetime and selectors that - * will propagate to all subsequent Interests. The only exception is that - * the initial Interest will be forced to include "ChildSelector=rightmost" and - * "MustBeFresh=true" selectors, which will be turned off in subsequent - * Interests. - * @param validator Reference to the Validator that should be used to validate data. Caller - * must ensure validator is valid until either completeCallback or errorCallback - * is invoked. - * - * @param completeCallback Callback to be fired when all segments are fetched - * @param errorCallback Callback to be fired when an error occurs (@see Errors) - */ - static - void - fetch(Face& face, - const Interest& baseInterest, - Validator& validator, - const CompleteCallback& completeCallback, - const ErrorCallback& errorCallback); - - /** - * @brief Initiate segment fetching - * - * @param face Reference to the Face that should be used to fetch data - * @param baseInterest An Interest for the initial segment of requested data. - * This interest may include custom InterestLifetime and selectors that - * will propagate to all subsequent Interests. The only exception is that - * the initial Interest will be forced to include "ChildSelector=1" and - * "MustBeFresh=true" selectors, which will be turned off in subsequent - * Interests. - * @param validator A shared_ptr to the Validator that should be used to validate data. - * - * @param completeCallback Callback to be fired when all segments are fetched - * @param errorCallback Callback to be fired when an error occurs (@see Errors) - */ - static - void - fetch(Face& face, - const Interest& baseInterest, - shared_ptr validator, - const CompleteCallback& completeCallback, - const ErrorCallback& errorCallback); - -private: - SegmentFetcher(Face& face, - shared_ptr validator, - const CompleteCallback& completeCallback, - const ErrorCallback& errorCallback); - - void - fetchFirstSegment(const Interest& baseInterest, shared_ptr self); - - void - fetchNextSegment(const Interest& origInterest, const Name& dataName, uint64_t segmentNo, - shared_ptr self); - - void - afterSegmentReceived(const Interest& origInterest, - const Data& data, bool isSegmentZeroExpected, - shared_ptr self); - void - afterValidationSuccess(const shared_ptr data, - bool isSegmentZeroExpected, - const Interest& origInterest, - shared_ptr self); - - void - afterValidationFailure(const shared_ptr data); - - void - afterNackReceived(const Interest& origInterest, const lp::Nack& nack, - uint32_t reExpressCount, shared_ptr self); - - void - reExpressInterest(Interest interest, uint32_t reExpressCount, - shared_ptr self); - -private: - Face& m_face; - Scheduler m_scheduler; - shared_ptr m_validator; - CompleteCallback m_completeCallback; - ErrorCallback m_errorCallback; - - shared_ptr m_buffer; -}; - -} // namespace util -} // namespace ndn - -#endif // NDN_UTIL_SEGMENT_FETCHER_HPP diff --git a/src/util/signal-connection.cpp b/src/util/signal-connection.cpp deleted file mode 100644 index 2d331164d..000000000 --- a/src/util/signal-connection.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "signal-connection.hpp" - -namespace ndn { -namespace util { -namespace signal { - -BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); - -Connection::Connection() -{ -} - -Connection::Connection(weak_ptr> disconnect) - : m_disconnect(disconnect) -{ -} - -void -Connection::disconnect() -{ - shared_ptr> f = m_disconnect.lock(); - if (f != nullptr) { - (*f)(); - } -} - -bool -Connection::isConnected() const -{ - return !m_disconnect.expired(); -} - -bool -Connection::operator==(const Connection& other) const -{ - shared_ptr> f1 = m_disconnect.lock(); - shared_ptr> f2 = other.m_disconnect.lock(); - return f1 == f2; -} - -bool -Connection::operator!=(const Connection& other) const -{ - return !(this->operator==(other)); -} - -} // namespace signal -} // namespace util -} // namespace ndn diff --git a/src/util/signal-connection.hpp b/src/util/signal-connection.hpp deleted file mode 100644 index dbbfd5af8..000000000 --- a/src/util/signal-connection.hpp +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_SIGNAL_CONNECTION_HPP -#define NDN_UTIL_SIGNAL_CONNECTION_HPP - -#include "../common.hpp" - -namespace ndn { -namespace util { -namespace signal { - -/** \brief represents a connection to a signal - * \note This type is copyable. Any copy can be used to disconnect. - */ -class Connection -{ -public: - Connection(); - - /** \brief disconnects from the signal - * \note If the connection is already disconnected, or if the Signal has been destructed, - * this operation has no effect. - * \warning During signal emission, attempting to disconnect a connection other than - * the executing handler's own connection results in undefined behavior. - */ - void - disconnect(); - - /** \brief check if connected to the signal - * \return false if disconnected from the signal - */ - bool - isConnected() const; - - /** \brief compare for equality - * - * Two connections are equal if they both refer to the same connection that isn't disconnected, - * or they are both disconnected. - */ - bool - operator==(const Connection& other) const; - - bool - operator!=(const Connection& other) const; - -private: - /** \param disconnect weak_ptr to a function that disconnects the handler - */ - explicit - Connection(weak_ptr> disconnect); - - template - friend class Signal; - -private: - /** \note The only shared_ptr to the disconnect function is stored in Signal<..>::Slot, - * and will be destructed if the handler is disconnected (through another Connection - * instance) or the Signal is destructed. - * Connection needs a weak_ptr instead of a shared_ptr to the disconnect function, - * because the disconnect function is bound with an iterator to the Slot, - * which is invalidated when the Slot is erased. - */ - weak_ptr> m_disconnect; -}; - -} // namespace signal -} // namespace util -} // namespace ndn - -#endif // NDN_UTIL_SIGNAL_CONNECTION_HPP diff --git a/src/util/signal-emit.hpp b/src/util/signal-emit.hpp deleted file mode 100644 index 17eacd0df..000000000 --- a/src/util/signal-emit.hpp +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -/** \file - * - * This header provides macros that allows a signal to be emitted - * from a derived class of its owner. - * - * In 'protected' section of owner class declaration, - * DECLARE_SIGNAL_EMIT(signalName) - * From a derived class of owner, - * this->emitSignal(signalName, arg1, arg2); - */ - -#ifndef NDN_UTIL_SIGNAL_EMIT_HPP -#define NDN_UTIL_SIGNAL_EMIT_HPP - -namespace ndn { -namespace util { -namespace signal { - -/** \brief (implementation detail) a filler for extra argument - */ -class DummyExtraArg -{ -}; - -} // namespace signal -} // namespace util -} // namespace ndn - -/** \brief (implementation detail) declares a 'emit_signalName' method - * \note This macro should be used in 'protected' section so that it's accessible - * by derived classes. - * \note emit_signalName method is implementation detail. - * Derived classes should use 'emitSignal' macro. - * \note The name 'emit_signalName' is an intentional violation of code-style rule 2.5. - * \note The method is declared as a template, so that the macro doesn't need argument types. - * But only argument types that are compatible with Signal declaration will work. - */ -#define DECLARE_SIGNAL_EMIT(signalName) \ - template \ - void emit_##signalName(const TArgs&... args) \ - { \ - signalName(args...); \ - } - -/** \brief (implementation detail) invokes emit_signalName method - * \note C99 requires at least one argument to be passed in __VA_ARGS__, - * thus a DummyExtraArg is expected at the end of __VA_ARGS__, - * which will be accepted but ignored by Signal::operator() overload. - */ -#define NDN_CXX_SIGNAL_EMIT(signalName, ...) \ - emit_##signalName(__VA_ARGS__) - -/** \brief (implementation detail) - */ -#define emitSignal(...) \ - NDN_CXX_SIGNAL_EMIT(__VA_ARGS__, ::ndn::util::signal::DummyExtraArg()) - -#endif // NDN_UTIL_SIGNAL_EMIT_HPP diff --git a/src/util/signal-scoped-connection.cpp b/src/util/signal-scoped-connection.cpp deleted file mode 100644 index aaed7abc6..000000000 --- a/src/util/signal-scoped-connection.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "signal-scoped-connection.hpp" - -namespace ndn { -namespace util { -namespace signal { - -#if NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE -static_assert(std::is_nothrow_move_constructible::value, - "ScopedConnection must be MoveConstructible with noexcept"); -#endif // NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE - -ScopedConnection::ScopedConnection() -{ -} - -ScopedConnection::ScopedConnection(const Connection& connection) - : m_connection(connection) -{ -} - -ScopedConnection::ScopedConnection(ScopedConnection&& other) noexcept - : m_connection(other.m_connection) -{ - other.release(); -} - -ScopedConnection& -ScopedConnection::operator=(const Connection& connection) -{ - if (m_connection != connection) { - m_connection.disconnect(); - m_connection = connection; - } - return *this; -} - -ScopedConnection::~ScopedConnection() noexcept -{ - m_connection.disconnect(); -} - -void -ScopedConnection::disconnect() -{ - m_connection.disconnect(); -} - -bool -ScopedConnection::isConnected() const -{ - return m_connection.isConnected(); -} - -void -ScopedConnection::release() -{ - m_connection = {}; -} - -} // namespace signal -} // namespace util -} // namespace ndn diff --git a/src/util/signal-scoped-connection.hpp b/src/util/signal-scoped-connection.hpp deleted file mode 100644 index 0fe28d443..000000000 --- a/src/util/signal-scoped-connection.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_SIGNAL_SCOPED_CONNECTION_HPP -#define NDN_UTIL_SIGNAL_SCOPED_CONNECTION_HPP - -#include "signal-connection.hpp" - -namespace ndn { -namespace util { -namespace signal { - -/** \brief disconnects a Connection automatically upon destruction - */ -class ScopedConnection : noncopyable -{ -public: - ScopedConnection(); - - /** \brief implicit constructor from Connection - * \param connection the Connection to be disconnected upon destruction - */ - ScopedConnection(const Connection& connection); - - /** \brief move constructor - */ - ScopedConnection(ScopedConnection&& other) noexcept; - - /** \brief assigns a connection - * - * If a different connection has been assigned to this instance previously, - * that connection will be disconnected immediately. - */ - ScopedConnection& - operator=(const Connection& connection); - - /** \brief disconnects the connection - */ - ~ScopedConnection() noexcept; - - /** \brief disconnects the connection manually - */ - void - disconnect(); - - /** \brief check if the connection is connected to the signal - * \return false when a default-constructed connection is used, the connection is released, - * or the connection is disconnected - */ - bool - isConnected() const; - - /** \brief releases the connection so that it won't be disconnected - * when this ScopedConnection is destructed - */ - void - release(); - -private: - Connection m_connection; -}; - -} // namespace signal -} // namespace util -} // namespace ndn - -#endif // NDN_UTIL_SIGNAL_SCOPED_CONNECTION_HPP diff --git a/src/util/signal-signal.hpp b/src/util/signal-signal.hpp deleted file mode 100644 index fb5b14b93..000000000 --- a/src/util/signal-signal.hpp +++ /dev/null @@ -1,268 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_SIGNAL_SIGNAL_HPP -#define NDN_UTIL_SIGNAL_SIGNAL_HPP - -#include "signal-connection.hpp" -#include - -namespace ndn { -namespace util { -namespace signal { - -class DummyExtraArg; - -/** \brief provides a lightweight signal / event system - * - * To declare a signal: - * public: - * Signal signalName; - * To connect to a signal: - * owner->signalName.connect(f); - * Multiple functions can connect to the same signal. - * To emit a signal from owner: - * this->signalName(arg1, arg2); - * - * \tparam Owner the signal owner class; only this class can emit the signal - * \tparam TArgs types of signal arguments - * \sa signal-emit.hpp allows owner's derived classes to emit signals - */ -template -class Signal : noncopyable -{ -public: // API for anyone - /** \brief represents a function that can connect to the signal - */ - typedef function Handler; - - Signal(); - - ~Signal(); - - /** \brief connects a handler to the signal - * \note If invoked from a handler, the new handler won't receive the current emitted signal. - * \warning The handler is permitted to disconnect itself, but it must ensure its validity. - */ - Connection - connect(const Handler& handler); - - /** \brief connects a single-shot handler to the signal - * - * After the handler is executed once, it is automatically disconnected. - */ - Connection - connectSingleShot(const Handler& handler); - -private: // API for owner - /** \retval true if there is no connection - */ - bool - isEmpty() const; - - /** \brief emits a signal - * \param args arguments passed to all handlers - * \warning Emitting the signal from a handler is undefined behavior. - * \warning Destructing the Signal object during signal emission is undefined behavior. - * \note If a handler throws, the exception will be propagated to the caller - * who emits this signal, and some handlers may not be executed. - */ - void - operator()(const TArgs&... args); - - /** \brief (implementation detail) emits a signal - * \note This overload is used by signal-emit.hpp. - */ - void - operator()(const TArgs&... args, const DummyExtraArg&); - - // make Owner a friend of Signal so that API for owner can be called - friend Owner; - -private: // internal implementation - typedef Signal Self; - struct Slot; - - /** \brief stores slots - * \note std::list is used because iterators must not be invalidated - * when other slots are added or removed - */ - typedef std::list SlotList; - - /** \brief stores a handler function, and a function to disconnect this handler - */ - struct Slot - { - /** \brief the handler function who will receive emitted signals - */ - Handler handler; - - /** \brief the disconnect function which will disconnect this handler - * - * In practice this is the Signal::disconnect method bound to an iterator - * pointing at this slot. - * - * This is the only shared_ptr to this function object. - * Connection class has a weak_ptr which references the same function object. - * When the slot is erased or the signal is destructed, this function object is - * destructed, and the related Connections cannot disconnect this slot again. - */ - shared_ptr> disconnect; - }; - - /** \brief stores slots - */ - SlotList m_slots; - - /** \brief is a signal handler executing? - */ - bool m_isExecuting; - - /** \brief iterator to current executing slot - * \note This field is meaningful when isExecuting==true - */ - typename SlotList::iterator m_currentSlot; - - /** \brief disconnects the handler in a slot - */ - void - disconnect(typename SlotList::iterator it); -}; - -template -Signal::Signal() - : m_isExecuting(false) -{ -} - -template -Signal::~Signal() -{ - BOOST_ASSERT(!m_isExecuting); -} - -template -Connection -Signal::connect(const Handler& handler) -{ - typename SlotList::iterator it = m_slots.insert(m_slots.end(), {handler, nullptr}); - it->disconnect = make_shared>(bind(&Self::disconnect, this, it)); - - return signal::Connection(weak_ptr>(it->disconnect)); -} - -template -Connection -Signal::connectSingleShot(const Handler& handler) -{ - typename SlotList::iterator it = m_slots.insert(m_slots.end(), {nullptr, nullptr}); - it->disconnect = make_shared>(bind(&Self::disconnect, this, it)); - signal::Connection conn(weak_ptr>(it->disconnect)); - - it->handler = [conn, handler] (const TArgs&... args) mutable { - handler(args...); - conn.disconnect(); - }; - - return conn; -} - -template -void -Signal::disconnect(typename SlotList::iterator it) -{ - // 'it' could be const_iterator, but gcc 4.6 doesn't support std::list::erase(const_iterator) - - if (m_isExecuting) { - // during signal emission, only the currently executing handler can be disconnected - BOOST_ASSERT_MSG(it == m_currentSlot, "cannot disconnect another handler from a handler"); - - // this serves to indicate that the current slot needs to be erased from the list - // after it finishes executing; we cannot do it here because of bug #2333 - m_currentSlot = m_slots.end(); - - // expire all weak_ptrs, to prevent double disconnections - it->disconnect.reset(); - } - else { - m_slots.erase(it); - } -} - -template -bool -Signal::isEmpty() const -{ - return !m_isExecuting && m_slots.empty(); -} - -template -void -Signal::operator()(const TArgs&... args) -{ - BOOST_ASSERT_MSG(!m_isExecuting, "cannot emit signal from a handler"); - - if (m_slots.empty()) { - return; - } - - auto it = m_slots.begin(); - auto last = std::prev(m_slots.end()); - m_isExecuting = true; - - try { - bool isLast = false; - while (!isLast) { - m_currentSlot = it; - isLast = it == last; - - m_currentSlot->handler(args...); - - if (m_currentSlot == m_slots.end()) - it = m_slots.erase(it); - else - ++it; - } - } - catch (...) { - m_isExecuting = false; - throw; - } - - m_isExecuting = false; -} - -template -void -Signal::operator()(const TArgs&... args, const DummyExtraArg&) -{ - this->operator()(args...); -} - -} // namespace signal - -// expose as ndn::util::Signal -using signal::Signal; - -} // namespace util -} // namespace ndn - -#endif // NDN_UTIL_SIGNAL_SIGNAL_HPP diff --git a/src/util/signal.hpp b/src/util/signal.hpp deleted file mode 100644 index cd36b5dcc..000000000 --- a/src/util/signal.hpp +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_UTIL_SIGNAL_HPP -#define NDN_UTIL_SIGNAL_HPP - -#include "signal-signal.hpp" -#include "signal-emit.hpp" -#include "signal-connection.hpp" -#include "signal-scoped-connection.hpp" - -#endif // NDN_UTIL_SIGNAL_HPP diff --git a/src/util/string-helper.cpp b/src/util/string-helper.cpp deleted file mode 100644 index 0f54e14d5..000000000 --- a/src/util/string-helper.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "string-helper.hpp" -#include "../encoding/buffer-stream.hpp" -#include "../security/v1/cryptopp.hpp" - -#include -#include - -#include - -namespace ndn { - -void -printHex(std::ostream& os, const uint8_t* buffer, size_t length, bool isUpperCase/* = true*/) -{ - if (buffer == nullptr || length == 0) - return; - - auto newFlags = std::ios::hex; - if (isUpperCase) { - newFlags |= std::ios::uppercase; - } - auto oldFlags = os.flags(newFlags); - auto oldFill = os.fill('0'); - for (size_t i = 0; i < length; ++i) { - os << std::setw(2) << static_cast(buffer[i]); - } - os.fill(oldFill); - os.flags(oldFlags); -} - -void -printHex(std::ostream& os, const Buffer& buffer, bool isUpperCase/* = true*/) -{ - return printHex(os, buffer.buf(), buffer.size(), isUpperCase); -} - -std::string -toHex(const uint8_t* buffer, size_t length, bool isUpperCase/* = true*/) -{ - if (buffer == nullptr || length == 0) - return ""; - - std::ostringstream result; - printHex(result, buffer, length, isUpperCase); - return result.str(); -} - -std::string -toHex(const Buffer& buffer, bool isUpperCase/* = true*/) -{ - return toHex(buffer.buf(), buffer.size(), isUpperCase); -} - -int -fromHexChar(uint8_t c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - else if (c >= 'A' && c <= 'F') - return c - 'A' + 0xA; - else if (c >= 'a' && c <= 'f') - return c - 'a' + 0xA; - else - return -1; -} - -shared_ptr -fromHex(const std::string& hexString) -{ - if (hexString.size() % 2 != 0) { - BOOST_THROW_EXCEPTION(StringHelperError("Invalid number of characters in the supplied hex " - "string")); - } - - using namespace CryptoPP; - - OBufferStream os; - StringSource(hexString, true, new HexDecoder(new FileSink(os))); - shared_ptr buffer = os.buf(); - - if (buffer->size() * 2 != hexString.size()) { - BOOST_THROW_EXCEPTION(StringHelperError("The supplied hex string contains non-hex characters")); - } - - return buffer; -} - -void -trimLeft(std::string& str) -{ - boost::algorithm::trim_left(str); -} - -void -trimRight(std::string& str) -{ - boost::algorithm::trim_right(str); -} - -void -trim(std::string& str) -{ - boost::algorithm::trim(str); -} - -std::string -unescape(const std::string& str) -{ - std::ostringstream result; - - for (size_t i = 0; i < str.size(); ++i) { - if (str[i] == '%' && i + 2 < str.size()) { - int hi = fromHexChar(str[i + 1]); - int lo = fromHexChar(str[i + 2]); - - if (hi < 0 || lo < 0) - // Invalid hex characters, so just keep the escaped string. - result << str[i] << str[i + 1] << str[i + 2]; - else - result << static_cast((hi << 4) | lo); - - // Skip ahead past the escaped value. - i += 2; - } - else - // Just copy through. - result << str[i]; - } - - return result.str(); -} - -} // namespace ndn diff --git a/src/util/string-helper.hpp b/src/util/string-helper.hpp deleted file mode 100644 index 4be9e4d9d..000000000 --- a/src/util/string-helper.hpp +++ /dev/null @@ -1,147 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_STRING_HELPER_HPP -#define NDN_STRING_HELPER_HPP - -#include "../common.hpp" -#include "../encoding/buffer.hpp" - -namespace ndn { - -class StringHelperError : public std::invalid_argument -{ -public: - explicit - StringHelperError(const std::string& what) - : std::invalid_argument(what) - { - } -}; - -/** - * @brief Output the hex representation of the bytes in array to the output stream @p os - * - * @param os Output stream - * @param buffer The array of bytes - * @param length Size of the array - * @param isUpperCase if true (default) output use uppercase for hex values - * - * Examples: - * - * printHex(std::cout, "Hello, World!") outputs "48656C6C6F2C20776F726C6421" - * printHex(std::cout, "Hello, World!", false) outputs "48656c6c6f2c20776f726c6421" - * - * Each octet is always represented as two hex characters ("00" for octet==0). - * - * The output string is a continuous sequence of hex characters without any whitespace separators. - */ -void -printHex(std::ostream& os, const uint8_t* buffer, size_t length, bool isUpperCase = true); - -/** - * @brief Output the hex representation of the bytes in the @p buffer to the output stream @p os - * - * @param os Output stream - * @param buffer The array of bytes - * @param isUpperCase if true (default) output use uppercase for hex values - */ -void -printHex(std::ostream& os, const Buffer& buffer, bool isUpperCase = true); - -/** - * @brief Return the hex representation of the bytes in array - * - * @param buffer The array of bytes - * @param length Size of the array - * @param isUpperCase if true (default) output use uppercase for hex values - * - * Examples: - * - * toHex("Hello, World!") == "48656C6C6F2C20776F726C6421" - * toHex("Hello, World!", false) == "48656c6c6f2c20776f726c6421" - * - * Each octet is always represented as two hex characters ("00" for octet==0). - * - * The output string is a continuous sequence of hex characters without any whitespace separators. - */ -std::string -toHex(const uint8_t* buffer, size_t length, bool isUpperCase = true); - -/** - * @brief Return the hex representation of the bytes in the @p buffer to the output stream @p os - * - * @param buffer The array of bytes - * @param isUpperCase if true (default) output use uppercase for hex values - */ -std::string -toHex(const Buffer& buffer, bool isUpperCase = true); - -/** - * @brief Convert the hex string to buffer - * @param hexString sequence of pairs of hex numbers (lower and upper case can be mixed) - * without any whitespace separators (e.g., "48656C6C6F2C20776F726C6421") - * @throw StringHelperError if input is invalid - */ -shared_ptr -fromHex(const std::string& hexString); - -/** - * @brief Modify str in place to erase whitespace on the left - */ -void -trimLeft(std::string& str); - -/** - * @brief Modify str in place to erase whitespace on the right - */ -void -trimRight(std::string& str); - -/** - * @brief Modify str in place to erase whitespace on the left and right - */ -void -trim(std::string& str); - -/** - * @brief Convert the hex character to an integer from 0 to 15, or -1 if not a hex character - */ -int -fromHexChar(uint8_t c); - -/** - * @brief Decode a percent-encoded string - * @see RFC 3986 section 2 - * - * When % is not followed by two hex characters, the output is not transformed. - * - * Examples: - * - * unescape("hello%20world") == "hello world" - * unescape("hello%20world%FooBar") == "hello world%FooBar" - */ -std::string -unescape(const std::string& str); - -} // namespace ndn - -#endif // NDN_STRING_HELPER_HPP diff --git a/src/util/time-unit-test-clock.cpp b/src/util/time-unit-test-clock.cpp deleted file mode 100644 index 7ed848dbe..000000000 --- a/src/util/time-unit-test-clock.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "time-unit-test-clock.hpp" -#include "monotonic_deadline_timer.hpp" -#include - -namespace ndn { -namespace time { - -const std::chrono::microseconds SLEEP_AFTER_TIME_CHANGE(2); - -template -UnitTestClock::UnitTestClock(const nanoseconds& startTime) - : m_currentTime(startTime) -{ -} - -template -std::string -UnitTestClock::getSince() const -{ - return " since unit test clock advancements"; -} - -template -typename BaseClock::time_point -UnitTestClock::getNow() const -{ - return typename BaseClock::time_point(duration_cast(m_currentTime)); -} - -template -boost::posix_time::time_duration -UnitTestClock::toPosixDuration(const typename BaseClock::duration& duration) const -{ - return -#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS - boost::posix_time::nanoseconds(1) -#else - boost::posix_time::microseconds(1) -#endif - ; -} - - -template -void -UnitTestClock::advance(const nanoseconds& duration) -{ - m_currentTime += duration; - - // On some platforms, boost::asio::io_service for deadline_timer (e.g., the one used in - // Scheduler) will call time_traits<>::now() and will "sleep" for - // time_traits<>::to_posix_time(duration) period before calling time_traits<>::now() - // again. (Note that such "sleep" will occur even if there is no actual waiting and - // program is calling io_service.poll().) - // - // As a result, in order for the clock advancement to be effective, we must sleep for a - // period greater than time_traits<>::to_posix_time(). - // - // See also http://blog.think-async.com/2007/08/time-travel.html - BOOST_ASSERT(boost::posix_time::microseconds(SLEEP_AFTER_TIME_CHANGE.count()) > - boost::asio::time_traits::to_posix_duration(duration)); - std::this_thread::sleep_for(SLEEP_AFTER_TIME_CHANGE); -} - -template -void -UnitTestClock::setNow(const nanoseconds& timeSinceEpoch) -{ - BOOST_ASSERT(boost::posix_time::microseconds(SLEEP_AFTER_TIME_CHANGE.count()) > - boost::asio::time_traits::to_posix_duration(timeSinceEpoch - - m_currentTime)); - m_currentTime = timeSinceEpoch; - std::this_thread::sleep_for(SLEEP_AFTER_TIME_CHANGE); -} - -template -class UnitTestClock; - -template -class UnitTestClock; - -} // namespace time -} // namespace ndn diff --git a/src/util/time-unit-test-clock.hpp b/src/util/time-unit-test-clock.hpp deleted file mode 100644 index 253e1e770..000000000 --- a/src/util/time-unit-test-clock.hpp +++ /dev/null @@ -1,111 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_TIME_UNIT_TEST_CLOCK_HPP -#define NDN_TIME_UNIT_TEST_CLOCK_HPP - -#include "time-custom-clock.hpp" - -namespace ndn { -namespace time { - -/** - * @brief Traits for UnitTestClock, defining default behavior for different clocks - * - * The only behavior that is currently controlled by the traits is default start - * time. The generic implementation assumes start time to be zero. - */ -template -class UnitTestClockTraits -{ -public: - static nanoseconds - getDefaultStartTime() - { - return nanoseconds::zero(); - } -}; - -/** - * @brief Specialization of UnitTestClockTraits for system_clock - * - * This specialization sets the default start time to 1415684132 seconds - * (equivalent to Tue, 11 Nov 2014 05:35:32 UTC if unix epoch is assumed). - */ -template<> -class UnitTestClockTraits -{ -public: - static nanoseconds - getDefaultStartTime() - { - return seconds(1415684132); - } -}; - -/** - * @brief Clock that can be used in unit tests for time-dependent tests independent of wall clock - * - * This clock should be explicitly advanced with UnitTestClock::advance() or set - * with UnitTestClock::setNow() methods. - * - * @note Default start time is determined by UnitTestClockTraits - */ -template -class UnitTestClock : public CustomClock -{ -public: - explicit - UnitTestClock(const nanoseconds& startTime = UnitTestClockTraits::getDefaultStartTime()); - - /** - * @brief Advance unit test clock by @p duration - */ - void - advance(const nanoseconds& duration); - - /** - * @brief Explicitly set clock to @p timeSinceEpoch - */ - void - setNow(const nanoseconds& timeSinceEpoch); - -public: // CustomClock - virtual std::string - getSince() const override; - - virtual typename BaseClock::time_point - getNow() const override; - - virtual boost::posix_time::time_duration - toPosixDuration(const typename BaseClock::duration& duration) const override; - -private: - nanoseconds m_currentTime; -}; - -typedef UnitTestClock UnitTestSystemClock; -typedef UnitTestClock UnitTestSteadyClock; - -} // namespace time -} // namespace ndn - -#endif // NDN_TIME_UNIT_TEST_CLOCK_HPP diff --git a/src/util/time.cpp b/src/util/time.cpp deleted file mode 100644 index b652a7bbc..000000000 --- a/src/util/time.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "time.hpp" -#include "time-custom-clock.hpp" - -#include - -namespace ndn { -namespace time { - -static shared_ptr g_systemClock; -static shared_ptr g_steadyClock; - -// this method is defined in time-custom-clock.hpp -void -setCustomClocks(shared_ptr steadyClock, - shared_ptr systemClock) -{ - g_systemClock = systemClock; - g_steadyClock = steadyClock; -} - -///////////////////////////////////////////////////////////////////////////////////////////// - -system_clock::time_point -system_clock::now() noexcept -{ - if (g_systemClock == nullptr) { - // optimized default version - return time_point(boost::chrono::system_clock::now().time_since_epoch()); - } - else { - return g_systemClock->getNow(); - } -} - -std::time_t -system_clock::to_time_t(const time_point& t) noexcept -{ - return duration_cast(t.time_since_epoch()).count(); -} - -system_clock::time_point -system_clock::from_time_t(std::time_t t) noexcept -{ - return time_point(seconds(t)); -} - -///////////////////////////////////////////////////////////////////////////////////////////// - -#ifdef __APPLE__ - // Note that on OS X platform boost::steady_clock is not truly monotonic, so we use - // system_clock instead. Refer to https://svn.boost.org/trac/boost/ticket/7719) - typedef boost::chrono::system_clock base_steady_clock; -#else - typedef boost::chrono::steady_clock base_steady_clock; -#endif - -steady_clock::time_point -steady_clock::now() noexcept -{ - if (g_steadyClock == nullptr) { - // optimized default version - return time_point(base_steady_clock::now().time_since_epoch()); - } - else { - return g_steadyClock->getNow(); - } -} - -boost::posix_time::time_duration -steady_clock::to_posix_duration(const duration& duration) -{ - if (g_steadyClock == nullptr) { - // optimized default version - return -#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS - boost::posix_time::nanoseconds(duration_cast(duration).count()) -#else - boost::posix_time::microseconds(duration_cast(duration).count()) -#endif - ; - } - else { - return g_steadyClock->toPosixDuration(duration); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////// - -const system_clock::TimePoint& -getUnixEpoch() -{ - static system_clock::TimePoint epoch = system_clock::from_time_t(0); - return epoch; -} - -milliseconds -toUnixTimestamp(const system_clock::TimePoint& point) -{ - return duration_cast(point - getUnixEpoch()); -} - -system_clock::TimePoint -fromUnixTimestamp(const milliseconds& duration) -{ - return getUnixEpoch() + duration; -} - -std::string -toIsoString(const system_clock::TimePoint& timePoint) -{ - namespace bpt = boost::posix_time; - bpt::ptime ptime = bpt::from_time_t(system_clock::to_time_t(timePoint)); - - uint64_t micro = duration_cast(timePoint - getUnixEpoch()).count() % 1000000; - if (micro > 0) - { - ptime += bpt::microseconds(micro); - return bpt::to_iso_string(ptime); - } - else - return bpt::to_iso_string(ptime); -} - - -system_clock::TimePoint -fromIsoString(const std::string& isoString) -{ - namespace bpt = boost::posix_time; - static bpt::ptime posixTimeEpoch = bpt::from_time_t(0); - - bpt::ptime ptime = bpt::from_iso_string(isoString); - - system_clock::TimePoint point = - system_clock::from_time_t((ptime - posixTimeEpoch).total_seconds()); - point += microseconds((ptime - posixTimeEpoch).total_microseconds() % 1000000); - return point; -} - - -std::string -toString(const system_clock::TimePoint& timePoint, - const std::string& format/* = "%Y-%m-%d %H:%M:%S"*/, - const std::locale& locale/* = std::locale("C")*/) -{ - namespace bpt = boost::posix_time; - bpt::ptime ptime = bpt::from_time_t(system_clock::to_time_t(timePoint)); - - uint64_t micro = duration_cast(timePoint - getUnixEpoch()).count() % 1000000; - ptime += bpt::microseconds(micro); - - bpt::time_facet* facet = new bpt::time_facet(format.c_str()); - std::ostringstream formattedTimePoint; - formattedTimePoint.imbue(std::locale(locale, facet)); - formattedTimePoint << ptime; - - return formattedTimePoint.str(); -} - - -system_clock::TimePoint -fromString(const std::string& formattedTimePoint, - const std::string& format/* = "%Y-%m-%d %H:%M:%S"*/, - const std::locale& locale/* = std::locale("C")*/) -{ - namespace bpt = boost::posix_time; - static bpt::ptime posixTimeEpoch = bpt::from_time_t(0); - - bpt::time_input_facet* facet = new bpt::time_input_facet(format); - std::istringstream is(formattedTimePoint); - - is.imbue(std::locale(locale, facet)); - bpt::ptime ptime; - is >> ptime; - - system_clock::TimePoint point = - system_clock::from_time_t((ptime - posixTimeEpoch).total_seconds()); - point += microseconds((ptime - posixTimeEpoch).total_microseconds() % 1000000); - return point; -} - -} // namespace time -} // namespace ndn - -namespace boost { -namespace chrono { - -///////////////////////////////////////////////////////////////////////////////////////////// - -template -std::basic_string -clock_string::since() -{ - if (ndn::time::g_systemClock == nullptr) { - // optimized default version - return clock_string::since(); - } - else { - return ndn::time::g_systemClock->getSince(); - } -} - -template -struct clock_string; - -///////////////////////////////////////////////////////////////////////////////////////////// - -template -std::basic_string -clock_string::since() -{ - if (ndn::time::g_steadyClock == nullptr) { - // optimized default version - return clock_string::since(); - } - else { - return ndn::time::g_steadyClock->getSince(); - } -} - -template -struct clock_string; - -} // namespace chrono -} // namespace boost diff --git a/src/util/time.hpp b/src/util/time.hpp deleted file mode 100644 index e239ccdfb..000000000 --- a/src/util/time.hpp +++ /dev/null @@ -1,253 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_TIME_HPP -#define NDN_TIME_HPP - -#include "../common.hpp" -#include -#include -#include - -namespace ndn { -namespace time { - -using boost::chrono::duration; - -typedef duration > days; -using boost::chrono::hours; -using boost::chrono::minutes; -using boost::chrono::seconds; - -using boost::chrono::milliseconds; -using boost::chrono::microseconds; -using boost::chrono::nanoseconds; - -using boost::chrono::duration_cast; - -/** \return the absolute value of the duration d - * \note The function does not participate in the overload resolution - * unless std::numeric_limits::is_signed is true. - */ -template::is_signed>::type> -constexpr duration -abs(duration d) -{ - return d >= d.zero() ? d : -d; -} - -/** - * \brief System clock - * - * System clock represents the system-wide real time wall clock. - * - * It may not be monotonic: on most systems, the system time can be - * adjusted at any moment. It is the only clock that has the ability - * to be displayed and converted to/from UNIX timestamp. - * - * To get current TimePoint: - * - * - * system_clock::TimePoint now = system_clock::now(); - * - * - * To convert TimePoint to/from UNIX timestamp: - * - * - * system_clock::TimePoint time = ...; - * uint64_t timestampInMilliseconds = toUnixTimestamp(time).count(); - * system_clock::TimePoint time2 = fromUnixTimestamp(milliseconds(timestampInMilliseconds)); - * - */ -class system_clock -{ -public: - typedef BOOST_SYSTEM_CLOCK_DURATION duration; - typedef duration::rep rep; - typedef duration::period period; - typedef boost::chrono::time_point time_point; - static constexpr bool is_steady = false; - - typedef time_point TimePoint; - typedef duration Duration; - - static time_point - now() noexcept; - - static std::time_t - to_time_t(const time_point& t) noexcept; - - static time_point - from_time_t(std::time_t t) noexcept; -}; // class system_clock - -/** - * \brief Steady clock - * - * Steady clock represents a monotonic clock. The time points of this - * clock cannot decrease as physical time moves forward. This clock is - * not related to wall clock time, and is best suitable for measuring - * intervals. - */ -class steady_clock -{ -public: - typedef nanoseconds duration; - typedef duration::rep rep; - typedef duration::period period; - typedef boost::chrono::time_point time_point; - static constexpr bool is_steady = true; - - typedef time_point TimePoint; - typedef duration Duration; - - static time_point - now() noexcept; - -private: - /** - * \brief Method to be used in deadline timer to select proper waiting - * - * Mock time implementations should return minimum value to ensure Boost.Asio - * is not enabling any waiting on mock timers. - * - * @sa http://stackoverflow.com/questions/14191855/how-do-you-mock-the-time-for-boost-timers - */ - static boost::posix_time::time_duration - to_posix_duration(const duration& duration); - - friend struct boost::asio::time_traits; -}; // class steady_clock - - -/** - * \brief Get system_clock::TimePoint representing UNIX time epoch (00:00:00 on Jan 1, 1970) - */ -const system_clock::TimePoint& -getUnixEpoch(); - -/** - * \brief Convert system_clock::TimePoint to UNIX timestamp - */ -milliseconds -toUnixTimestamp(const system_clock::TimePoint& point); - -/** - * \brief Convert UNIX timestamp to system_clock::TimePoint - */ -system_clock::TimePoint -fromUnixTimestamp(const milliseconds& duration); - -/** - * \brief Convert to the ISO string representation of the time (YYYYMMDDTHHMMSS,fffffffff) - * - * If timePoint contains doesn't contain fractional seconds the - * output format is YYYYMMDDTHHMMSS - * - * Examples: - * - * - with fractional nanoseconds: 20020131T100001,123456789 - * - with fractional microseconds: 20020131T100001,123456 - * - with fractional milliseconds: 20020131T100001,123 - * - without fractional seconds: 20020131T100001 - */ -std::string -toIsoString(const system_clock::TimePoint& timePoint); - -/** - * \brief Convert from the ISO string (YYYYMMDDTHHMMSS,fffffffff) representation - * to the internal time format - * - * Examples of accepted ISO strings: - * - * - with fractional nanoseconds: 20020131T100001,123456789 - * - with fractional microseconds: 20020131T100001,123456 - * - with fractional milliseconds: 20020131T100001,123 - * - without fractional seconds: 20020131T100001 - * - */ -system_clock::TimePoint -fromIsoString(const std::string& isoString); - -/** - * \brief Convert time point to string with specified format - * - * By default, `%Y-%m-%d %H:%M:%S` is used, producing dates like - * `2014-04-10 22:51:00` - * - * \param timePoint time point of system_clock - * \param format desired output format (default: `%Y-%m-%d %H:%M:%S`) - * \param locale desired locale (default: "C" locale) - * - * \sa http://www.boost.org/doc/libs/1_54_0/doc/html/date_time/date_time_io.html#date_time.format_flags - * described possible formatting flags - **/ -std::string -toString(const system_clock::TimePoint& timePoint, - const std::string& format = "%Y-%m-%d %H:%M:%S", - const std::locale& locale = std::locale("C")); - -/** - * \brief Convert from string of specified format into time point - * - * By default, `%Y-%m-%d %H:%M:%S` is used, accepting dates like - * `2014-04-10 22:51:00` - * - * \param formattedTimePoint string representing time point - * \param format input output format (default: `%Y-%m-%d %H:%M:%S`) - * \param locale input locale (default: "C" locale) - * - * \sa http://www.boost.org/doc/libs/1_54_0/doc/html/date_time/date_time_io.html#date_time.format_flags - * described possible formatting flags - */ -system_clock::TimePoint -fromString(const std::string& formattedTimePoint, - const std::string& format = "%Y-%m-%d %H:%M:%S", - const std::locale& locale = std::locale("C")); - - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace time -} // namespace ndn - -namespace boost { -namespace chrono { - -template -struct clock_string -{ - static std::basic_string - since(); -}; - -template -struct clock_string -{ - static std::basic_string - since(); -}; - -} // namespace chrono -} // namespace boost - -#endif // NDN_TIME_HPP diff --git a/tests/boost-test.hpp b/tests/boost-test.hpp index 70e542667..51e0973d9 100644 --- a/tests/boost-test.hpp +++ b/tests/boost-test.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2014 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -26,8 +26,7 @@ #pragma GCC system_header #pragma clang system_header +#define BOOST_TEST_DYN_LINK #include -#include -#include #endif // NDN_TESTS_BOOST_TEST_HPP diff --git a/tests/dummy-validator.hpp b/tests/dummy-validator.hpp deleted file mode 100644 index 40e4bcbe6..000000000 --- a/tests/dummy-validator.hpp +++ /dev/null @@ -1,108 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_TESTS_DUMMY_VALIDATOR_HPP -#define NDN_TESTS_DUMMY_VALIDATOR_HPP - -#include "security/validator.hpp" - -namespace ndn { -namespace tests { - -/** \brief a Validator for unit testing - */ -class DummyValidator : public Validator -{ -public: - /** \brief constructor - * \param shouldAccept whether to accept or reject all validation requests - */ - explicit - DummyValidator(bool shouldAccept = true) - { - this->setResult(shouldAccept); - } - - /** \brief change the validation result - * \param shouldAccept whether to accept or reject all validation requests - */ - void - setResult(bool shouldAccept) - { - m_decide = [shouldAccept] (const Name&) { return shouldAccept; }; - } - - /** \brief set a callback for validation - * \param cb a callback which receives the Interest/Data name for each validation request; - * its return value determines the validation result - */ - void - setResultCallback(const function& cb) - { - m_decide = cb; - } - -protected: - virtual void - checkPolicy(const Interest& interest, int nSteps, - const OnInterestValidated& accept, const OnInterestValidationFailed& reject, - std::vector>&) override - { - if (m_decide(interest.getName())) { - accept(interest.shared_from_this()); - } - else { - reject(interest.shared_from_this(), ""); - } - } - - virtual void - checkPolicy(const Data& data, int nSteps, - const OnDataValidated& accept, const OnDataValidationFailed& reject, - std::vector>&) override - { - if (m_decide(data.getName())) { - accept(data.shared_from_this()); - } - else { - reject(data.shared_from_this(), ""); - } - } - -private: - function m_decide; -}; - -/** \brief a DummyValidator initialized to reject all requests - */ -class DummyRejectValidator : public DummyValidator -{ -public: - DummyRejectValidator() - : DummyValidator(false) - { - } -}; - -} // namespace tests -} // namespace ndn - -#endif // NDN_TESTS_DUMMY_VALIDATOR_HPP diff --git a/tests/identity-management-fixture.cpp b/tests/identity-management-fixture.cpp index 8c9f410e6..781b2a157 100644 --- a/tests/identity-management-fixture.cpp +++ b/tests/identity-management-fixture.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,24 +19,20 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "identity-management-fixture.hpp" -#include "util/io.hpp" +#include "tests/identity-management-fixture.hpp" + +#include "ndn-cxx/security/v2/additional-description.hpp" +#include "ndn-cxx/util/io.hpp" #include namespace ndn { namespace tests { -IdentityManagementFixture::IdentityManagementFixture() -{ -} +namespace v2 = security::v2; -IdentityManagementFixture::~IdentityManagementFixture() +IdentityManagementBaseFixture::~IdentityManagementBaseFixture() { - for (const auto& identity : m_identities) { - m_keyChain.deleteIdentity(identity); - } - boost::system::error_code ec; for (const auto& certFile : m_certFiles) { boost::filesystem::remove(certFile, ec); // ignore error @@ -44,41 +40,91 @@ IdentityManagementFixture::~IdentityManagementFixture() } bool -IdentityManagementFixture::addIdentity(const Name& identity, const KeyParams& params) +IdentityManagementBaseFixture::saveCertToFile(const Data& obj, const std::string& filename) { + m_certFiles.insert(filename); try { - m_keyChain.createIdentity(identity, params); - m_identities.push_back(identity); + io::save(obj, filename); return true; } - catch (std::runtime_error&) { + catch (const io::Error&) { return false; } } +IdentityManagementFixture::IdentityManagementFixture() + : m_keyChain("pib-memory:", "tpm-memory:") +{ +} + +security::Identity +IdentityManagementFixture::addIdentity(const Name& identityName, const KeyParams& params) +{ + auto identity = m_keyChain.createIdentity(identityName, params); + m_identities.insert(identityName); + return identity; +} + bool -IdentityManagementFixture::saveIdentityCertificate(const Name& identity, - const std::string& filename, bool wantAdd) +IdentityManagementFixture::saveCertificate(const security::Identity& identity, const std::string& filename) { - shared_ptr cert; try { - cert = m_keyChain.getCertificate(m_keyChain.getDefaultCertificateNameForIdentity(identity)); + auto cert = identity.getDefaultKey().getDefaultCertificate(); + return saveCertToFile(cert, filename); } - catch (const ndn::SecPublicInfo::Error&) { - if (wantAdd && this->addIdentity(identity)) { - return this->saveIdentityCertificate(identity, filename, false); - } + catch (const security::Pib::Error&) { return false; } +} - m_certFiles.push_back(filename); - try { - ndn::io::save(*cert, filename); - return true; - } - catch (const ndn::io::Error&) { - return false; - } +security::Identity +IdentityManagementFixture::addSubCertificate(const Name& subIdentityName, + const security::Identity& issuer, const KeyParams& params) +{ + auto subIdentity = addIdentity(subIdentityName, params); + + v2::Certificate request = subIdentity.getDefaultKey().getDefaultCertificate(); + + request.setName(request.getKeyName().append("parent").appendVersion()); + + SignatureInfo info; + auto now = time::system_clock::now(); + info.setValidityPeriod(security::ValidityPeriod(now, now + 7300_days)); + + v2::AdditionalDescription description; + description.set("type", "sub-certificate"); + info.appendTypeSpecificTlv(description.wireEncode()); + + m_keyChain.sign(request, signingByIdentity(issuer).setSignatureInfo(info)); + m_keyChain.setDefaultCertificate(subIdentity.getDefaultKey(), request); + + return subIdentity; +} + +v2::Certificate +IdentityManagementFixture::addCertificate(const security::Key& key, const std::string& issuer) +{ + Name certificateName = key.getName(); + certificateName + .append(issuer) + .appendVersion(); + v2::Certificate certificate; + certificate.setName(certificateName); + + // set metainfo + certificate.setContentType(tlv::ContentType_Key); + certificate.setFreshnessPeriod(1_h); + + // set content + certificate.setContent(key.getPublicKey().data(), key.getPublicKey().size()); + + // set signature-info + SignatureInfo info; + auto now = time::system_clock::now(); + info.setValidityPeriod(security::ValidityPeriod(now, now + 10_days)); + + m_keyChain.sign(certificate, signingByKey(key).setSignatureInfo(info)); + return certificate; } } // namespace tests diff --git a/tests/identity-management-fixture.hpp b/tests/identity-management-fixture.hpp index 4df61bf05..ba42ca308 100644 --- a/tests/identity-management-fixture.hpp +++ b/tests/identity-management-fixture.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,47 +22,78 @@ #ifndef NDN_TESTS_IDENTITY_MANAGEMENT_FIXTURE_HPP #define NDN_TESTS_IDENTITY_MANAGEMENT_FIXTURE_HPP -#include "security/key-chain.hpp" -#include +#include "ndn-cxx/security/v2/key-chain.hpp" +#include "ndn-cxx/security/signing-helpers.hpp" + +#include "tests/test-home-fixture.hpp" -#include "boost-test.hpp" +#include namespace ndn { namespace tests { +class IdentityManagementBaseFixture : public TestHomeFixture +{ +public: + ~IdentityManagementBaseFixture(); + + bool + saveCertToFile(const Data& obj, const std::string& filename); + +protected: + std::set m_identities; + std::set m_certFiles; +}; + /** - * @brief IdentityManagementFixture 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. + * @brief A test suite level fixture to help with identity management + * + * Test cases in the suite can use this fixture to create identities. Identities, + * certificates, and saved certificates are automatically removed during test teardown. */ -class IdentityManagementFixture +class IdentityManagementFixture : public IdentityManagementBaseFixture { public: IdentityManagementFixture(); - ~IdentityManagementFixture(); - - /// @brief add identity, return true if succeed. - bool - addIdentity(const Name& identity, const KeyParams& params = KeyChain::DEFAULT_KEY_PARAMS); + /** + * @brief Add identity @p identityName + * @return name of the created self-signed certificate + */ + security::Identity + addIdentity(const Name& identityName, + const KeyParams& params = security::v2::KeyChain::getDefaultKeyParams()); /** - * @brief save identity certificate to a file - * @param identity identity name + * @brief Save identity certificate to a file + * @param identity identity * @param filename file name, should be writable - * @param wantAdd if true, add new identity when necessary * @return whether successful */ bool - saveIdentityCertificate(const Name& identity, const std::string& filename, bool wantAdd = false); + saveCertificate(const security::Identity& identity, const std::string& filename); + + /** + * @brief Issue a certificate for \p subIdentityName signed by \p issuer + * + * If identity does not exist, it is created. + * A new key is generated as the default key for identity. + * A default certificate for the key is signed by the issuer using its default certificate. + * + * @return the sub identity + */ + security::Identity + addSubCertificate(const Name& subIdentityName, const security::Identity& issuer, + const KeyParams& params = security::v2::KeyChain::getDefaultKeyParams()); + + /** + * @brief Add a self-signed certificate to @p key with issuer ID @p issuer + */ + security::v2::Certificate + addCertificate(const security::Key& key, const std::string& issuer); protected: KeyChain m_keyChain; - -private: - std::vector m_identities; - std::vector m_certFiles; }; } // namespace tests diff --git a/tests/integrated/default-can-be-prefix-0.cpp b/tests/integrated/default-can-be-prefix-0.cpp new file mode 100644 index 000000000..77a30426b --- /dev/null +++ b/tests/integrated/default-can-be-prefix-0.cpp @@ -0,0 +1,43 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#define BOOST_TEST_MODULE ndn-cxx Integrated Tests (DefaultCanBePrefix=0) +#include "tests/boost-test.hpp" + +#include "ndn-cxx/interest.hpp" + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(TestInterest) + +BOOST_AUTO_TEST_CASE(DefaultCanBePrefix0) +{ + Interest::setDefaultCanBePrefix(false); + Interest interest1; + Interest interest2(interest1.wireEncode()); + BOOST_CHECK_EQUAL(interest2.getCanBePrefix(), false); +} + +BOOST_AUTO_TEST_SUITE_END() // TestInterest + +} // namespace tests +} // namespace ndn diff --git a/tests/integrated/default-can-be-prefix-1.cpp b/tests/integrated/default-can-be-prefix-1.cpp new file mode 100644 index 000000000..f2f6a5256 --- /dev/null +++ b/tests/integrated/default-can-be-prefix-1.cpp @@ -0,0 +1,43 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#define BOOST_TEST_MODULE ndn-cxx Integrated Tests (DefaultCanBePrefix=1) +#include "tests/boost-test.hpp" + +#include "ndn-cxx/interest.hpp" + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(TestInterest) + +BOOST_AUTO_TEST_CASE(DefaultCanBePrefix1) +{ + Interest::setDefaultCanBePrefix(true); + Interest interest1; + Interest interest2(interest1.wireEncode()); + BOOST_CHECK_EQUAL(interest2.getCanBePrefix(), true); +} + +BOOST_AUTO_TEST_SUITE_END() // TestInterest + +} // namespace tests +} // namespace ndn diff --git a/tests/integrated/default-can-be-prefix-unset.cpp b/tests/integrated/default-can-be-prefix-unset.cpp new file mode 100644 index 000000000..0498eae2e --- /dev/null +++ b/tests/integrated/default-can-be-prefix-unset.cpp @@ -0,0 +1,44 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#define BOOST_TEST_MODULE ndn-cxx Integrated Tests (DefaultCanBePrefix=unset) +#include "tests/boost-test.hpp" + +#include "ndn-cxx/interest.hpp" + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(TestInterest) + +BOOST_AUTO_TEST_CASE(DefaultCanBePrefixUnset) +{ + Interest interest1; + BOOST_CHECK_THROW(interest1.wireEncode(), std::logic_error); + Interest::s_errorIfCanBePrefixUnset = false; + Interest interest2(interest1.wireEncode()); + BOOST_CHECK_EQUAL(interest2.getCanBePrefix(), true); +} + +BOOST_AUTO_TEST_SUITE_END() // TestInterest + +} // namespace tests +} // namespace ndn diff --git a/tests/integrated/default-can-be-prefix.README.md b/tests/integrated/default-can-be-prefix.README.md new file mode 100644 index 000000000..23b01ae76 --- /dev/null +++ b/tests/integrated/default-can-be-prefix.README.md @@ -0,0 +1,10 @@ +# DefaultCanBePrefix test + +`default-can-be-prefix-*.cpp` verifies the effect of `Interest::setDefaultCanBePrefix`. +They are written as integration tests because ndn-cxx unit tests are prohibited from calling `Interest::setDefaultCanBePrefix`. + +Manual verification steps: + +1. `default-can-be-prefix-unset` program should print a "CanBePrefix unset" warning to stderr. +2. `default-can-be-prefix-0` and `default-can-be-prefix-1` test cases should not print that warning. + diff --git a/tests/integrated/encoding-benchmark.cpp b/tests/integrated/encoding-benchmark.cpp new file mode 100644 index 000000000..8f503a0e4 --- /dev/null +++ b/tests/integrated/encoding-benchmark.cpp @@ -0,0 +1,135 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#define BOOST_TEST_MODULE ndn-cxx Encoding Benchmark +#include "tests/boost-test.hpp" + +#include "ndn-cxx/encoding/tlv.hpp" +#include "tests/integrated/timed-execute.hpp" + +#include +#include + +#include + +namespace ndn { +namespace tlv { +namespace tests { + +using namespace ndn::tests; + +template +struct ReadVarNumberTest; + +template<> +struct ReadVarNumberTest<1> +{ + static const uint8_t WIRE[]; + static const uint64_t VALUE = 252; +}; +const uint8_t ReadVarNumberTest<1>::WIRE[] = {0xfc}; + +template<> +struct ReadVarNumberTest<3> +{ + static const uint8_t WIRE[]; + static const uint64_t VALUE = 253; +}; +const uint8_t ReadVarNumberTest<3>::WIRE[] = {0xfd, 0x00, 0xfd}; + +template<> +struct ReadVarNumberTest<5> +{ + static const uint8_t WIRE[]; + static const uint64_t VALUE = 65536; +}; +const uint8_t ReadVarNumberTest<5>::WIRE[] = {0xfe, 0x00, 0x01, 0x00, 0x00}; + +template<> +struct ReadVarNumberTest<9> +{ + static const uint8_t WIRE[]; + static const uint64_t VALUE = 4294967296; +}; +const uint8_t ReadVarNumberTest<9>::WIRE[] = {0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}; + +template +struct ReadVarNumberAlignTest : public ReadVarNumberTest +{ + using AlignmentOffset = std::integral_constant; + + static_assert(sizeof(ReadVarNumberTest::WIRE) == WIRE_SIZE, ""); +}; + +using ReadVarNumberTests = boost::mpl::vector< + ReadVarNumberAlignTest<1, 0>, + ReadVarNumberAlignTest<3, 0>, + ReadVarNumberAlignTest<3, 1>, + ReadVarNumberAlignTest<5, 0>, + ReadVarNumberAlignTest<5, 1>, + ReadVarNumberAlignTest<5, 2>, + ReadVarNumberAlignTest<5, 3>, + ReadVarNumberAlignTest<9, 0>, + ReadVarNumberAlignTest<9, 1>, + ReadVarNumberAlignTest<9, 2>, + ReadVarNumberAlignTest<9, 3>, + ReadVarNumberAlignTest<9, 4>, + ReadVarNumberAlignTest<9, 5>, + ReadVarNumberAlignTest<9, 6>, + ReadVarNumberAlignTest<9, 7> +>; + +// Benchmark of ndn::tlv::readVarNumber with different number lengths and alignments. +// Run this benchmark with: +// ./encoding-benchmark -t 'ReadVarNumber*' +// For accurate results, it is required to compile ndn-cxx in release mode. +// It is recommended to run the benchmark multiple times and take the average. +BOOST_AUTO_TEST_CASE_TEMPLATE(ReadVarNumber, Test, ReadVarNumberTests) +{ + const int N_ITERATIONS = 100000000; + + alignas(8) uint8_t buffer[16]; + static_assert(Test::AlignmentOffset::value + sizeof(Test::WIRE) <= sizeof(buffer), ""); + uint8_t* const begin = buffer + Test::AlignmentOffset::value; + std::memcpy(begin, Test::WIRE, sizeof(Test::WIRE)); + const uint8_t* const end = begin + sizeof(Test::WIRE); + + int nOks = 0; + int nCorrects = 0; + auto d = timedExecute([&] { + uint64_t number = 0; + for (int i = 0; i < N_ITERATIONS; ++i) { + const uint8_t* begin2 = begin; // make a copy because readVarNumber increments the pointer + nOks += readVarNumber(begin2, end, number); + nCorrects += number == Test::VALUE; + // use the number and the return value, so compiler won't optimize out their computation + } + }); + BOOST_CHECK_EQUAL(nOks, N_ITERATIONS); + BOOST_CHECK_EQUAL(nCorrects, N_ITERATIONS); + std::cout << "size=" << sizeof(Test::WIRE) + << " offset=" << Test::AlignmentOffset::value + << " " << d << std::endl; +} + +} // namespace tests +} // namespace tlv +} // namespace ndn diff --git a/tests/integrated/face.cpp b/tests/integrated/face.cpp index 3ef7297a3..a26338208 100644 --- a/tests/integrated/face.cpp +++ b/tests/integrated/face.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,534 +19,368 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#define BOOST_TEST_MAIN 1 -#define BOOST_TEST_DYN_LINK 1 #define BOOST_TEST_MODULE ndn-cxx Integrated Tests (Face) +#include "tests/boost-test.hpp" -#include "face.hpp" -#include "util/scheduler.hpp" -#include "security/key-chain.hpp" +#include "ndn-cxx/face.hpp" +#include "ndn-cxx/transport/tcp-transport.hpp" +#include "ndn-cxx/transport/unix-transport.hpp" +#include "ndn-cxx/util/scheduler.hpp" -#include "identity-management-fixture.hpp" -#include "boost-test.hpp" -#include "key-chain-fixture.hpp" +#include "tests/identity-management-fixture.hpp" +#include "tests/make-interest-data.hpp" #include +#include +#include +#include + +#include namespace ndn { namespace tests { -struct PibDirWithDefaultTpm -{ - const std::string PATH = "build/keys-with-default-tpm"; -}; - -class FacesFixture : public IdentityManagementFixture, - public PibDirFixture +static Name +makeVeryLongName(Name prefix = Name()) { -public: - FacesFixture() - : nData(0) - , nTimeouts(0) - , regPrefixId(0) - , nInInterests(0) - , nInInterests2(0) - , nRegFailures(0) - { - } - - void - onData() - { - ++nData; + for (size_t i = 0; i <= MAX_NDN_PACKET_SIZE / 10; i++) { + prefix.append("0123456789"); } + return prefix; +} - void - onTimeout() - { - ++nTimeouts; - } - - void - onInterest(Face& face, - const Name&, const Interest&) - { - ++nInInterests; - - face.unsetInterestFilter(regPrefixId); - } - - void - onInterest2(Face& face, - const Name&, const Interest&) - { - ++nInInterests2; - - face.unsetInterestFilter(regPrefixId2); +static std::string +executeCommand(const std::string& cmd) +{ + std::string output; + char buf[256]; + FILE* pipe = popen(cmd.data(), "r"); + BOOST_REQUIRE_MESSAGE(pipe != nullptr, "popen(" << cmd << ")"); + while (fgets(buf, sizeof(buf), pipe) != nullptr) { + output += buf; } + pclose(pipe); + return output; +} - void - onInterestRegex(Face& face, - const InterestFilter&, const Interest&) +template +class FaceFixture : public IdentityManagementFixture +{ +protected: + FaceFixture() + : face(TransportType::create(""), m_keyChain) + , sched(face.getIoService()) { - ++nInInterests; } - void - onInterestRegexError(Face& face, - const Name&, const Interest&) + /** \brief Send an Interest from a secondary face + * \param delay scheduling delay before sending Interest + * \param interest the Interest + * \param[out] outcome the response, initially '?', 'D' for Data, 'N' for Nack, 'T' for timeout + * \return scheduled event id + */ + scheduler::EventId + sendInterest(time::nanoseconds delay, const Interest& interest, char& outcome) { - BOOST_FAIL("InterestFilter::Error should have been triggered"); - } + if (face2 == nullptr) { + face2 = make_unique(TransportType::create(""), face.getIoService(), m_keyChain); + } - void - onRegFailed() - { - ++nRegFailures; + outcome = '?'; + return sched.schedule(delay, [this, interest, &outcome] { + face2->expressInterest(interest, + [&] (const Interest&, const Data&) { outcome = 'D'; }, + [&] (const Interest&, const lp::Nack&) { outcome = 'N'; }, + [&] (const Interest&) { outcome = 'T'; }); + }); } - void - expressInterest(Face& face, const Name& name) + scheduler::EventId + sendInterest(time::nanoseconds delay, const Interest& interest) { - Interest i(name); - i.setInterestLifetime(time::milliseconds(50)); - face.expressInterest(i, - bind(&FacesFixture::onData, this), - bind(&FacesFixture::onTimeout, this)); + static char ignoredOutcome; + return sendInterest(delay, interest, ignoredOutcome); } - void - terminate(Face& face) + /** \brief Stop io_service after a delay + * \return scheduled event id + */ + scheduler::EventId + terminateAfter(time::nanoseconds delay) { - face.getIoService().stop(); + return sched.schedule(delay, [this] { face.getIoService().stop(); }); } - uint32_t nData; - uint32_t nTimeouts; - - const RegisteredPrefixId* regPrefixId; - const RegisteredPrefixId* regPrefixId2; - uint32_t nInInterests; - uint32_t nInInterests2; - uint32_t nRegFailures; -}; - -BOOST_FIXTURE_TEST_SUITE(TestFaces, FacesFixture) - -BOOST_AUTO_TEST_CASE(Unix) -{ +protected: Face face; + unique_ptr face2; + Scheduler sched; +}; - face.expressInterest(Interest("/", time::milliseconds(1000)), - bind(&FacesFixture::onData, this), - bind(&FacesFixture::onTimeout, this)); - - BOOST_REQUIRE_NO_THROW(face.processEvents()); - - BOOST_CHECK_EQUAL(nData, 1); - BOOST_CHECK_EQUAL(nTimeouts, 0); - - face.expressInterest(Interest("/localhost/non-existing/data/should/not/exist/anywhere", - time::milliseconds(50)), - bind(&FacesFixture::onData, this), - bind(&FacesFixture::onTimeout, this)); - - Name veryLongName; - for (size_t i = 0; i <= MAX_NDN_PACKET_SIZE / 10; i++) - { - veryLongName.append("0123456789"); - } +using Transports = boost::mpl::vector; - BOOST_CHECK_THROW(face.expressInterest(veryLongName, OnData(), OnTimeout()), Face::Error); +BOOST_FIXTURE_TEST_SUITE(TestFace, FaceFixture) - shared_ptr data = make_shared(veryLongName); - data->setContent(reinterpret_cast("01234567890"), 10); - m_keyChain.sign(*data); - BOOST_CHECK_THROW(face.put(*data), Face::Error); +BOOST_AUTO_TEST_SUITE(Consumer) - BOOST_REQUIRE_NO_THROW(face.processEvents()); +BOOST_FIXTURE_TEST_CASE_TEMPLATE(ExpressInterestData, TransportType, Transports, FaceFixture) +{ + int nData = 0; + this->face.expressInterest(*makeInterest("/localhost", true), + [&] (const Interest&, const Data&) { ++nData; }, + [] (const Interest&, const lp::Nack&) { BOOST_ERROR("unexpected Nack"); }, + [] (const Interest&) { BOOST_ERROR("unexpected timeout"); }); + this->face.processEvents(); BOOST_CHECK_EQUAL(nData, 1); - BOOST_CHECK_EQUAL(nTimeouts, 1); } -BOOST_AUTO_TEST_CASE(Tcp) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(ExpressInterestNack, TransportType, Transports, FaceFixture) { - Face face("localhost"); - - face.expressInterest(Interest("/", time::milliseconds(1000)), - bind(&FacesFixture::onData, this), - bind(&FacesFixture::onTimeout, this)); - - BOOST_REQUIRE_NO_THROW(face.processEvents()); - - BOOST_CHECK_EQUAL(nData, 1); - BOOST_CHECK_EQUAL(nTimeouts, 0); - - face.expressInterest(Interest("/localhost/non-existing/data/should/not/exist/anywhere", - time::milliseconds(50)), - bind(&FacesFixture::onData, this), - bind(&FacesFixture::onTimeout, this)); - - BOOST_REQUIRE_NO_THROW(face.processEvents()); - - BOOST_CHECK_EQUAL(nData, 1); - BOOST_CHECK_EQUAL(nTimeouts, 1); + int nNacks = 0; + this->face.expressInterest(*makeInterest("/localhost/non-existent-should-nack"), + [] (const Interest&, const Data&) { BOOST_ERROR("unexpected Data"); }, + [&] (const Interest&, const lp::Nack&) { ++nNacks; }, + [] (const Interest&) { BOOST_ERROR("unexpected timeout"); }); + + this->face.processEvents(); + BOOST_CHECK_EQUAL(nNacks, 1); } - -BOOST_AUTO_TEST_CASE(SetFilter) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(ExpressInterestTimeout, TransportType, Transports, FaceFixture) { - Face face; - Face face2(face.getIoService()); - Scheduler scheduler(face.getIoService()); - scheduler.scheduleEvent(time::seconds(4), - bind(&FacesFixture::terminate, this, ref(face))); - - regPrefixId = face.setInterestFilter("/Hello/World", - bind(&FacesFixture::onInterest, this, ref(face), _1, _2), - RegisterPrefixSuccessCallback(), - bind(&FacesFixture::onRegFailed, this)); + // add route toward null face so Interest would timeout instead of getting Nacked + executeCommand("nfdc route add /localhost/non-existent-should-timeout null://"); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); // wait for FIB update to take effect - scheduler.scheduleEvent(time::milliseconds(200), - bind(&FacesFixture::expressInterest, this, - ref(face2), Name("/Hello/World/!"))); + int nTimeouts = 0; + this->face.expressInterest(*makeInterest("/localhost/non-existent-should-timeout", false, 1_s), + [] (const Interest&, const Data&) { BOOST_ERROR("unexpected Data"); }, + [] (const Interest&, const lp::Nack&) { BOOST_ERROR("unexpected Nack"); }, + [&] (const Interest&) { ++nTimeouts; }); - BOOST_REQUIRE_NO_THROW(face.processEvents()); - - BOOST_CHECK_EQUAL(nRegFailures, 0); - BOOST_CHECK_EQUAL(nInInterests, 1); + this->face.processEvents(); BOOST_CHECK_EQUAL(nTimeouts, 1); - BOOST_CHECK_EQUAL(nData, 0); } -BOOST_AUTO_TEST_CASE(SetTwoFilters) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(OversizedInterest, TransportType, Transports, FaceFixture) { - Face face; - Face face2(face.getIoService()); - Scheduler scheduler(face.getIoService()); - scheduler.scheduleEvent(time::seconds(1), - bind(&FacesFixture::terminate, this, ref(face))); - - regPrefixId = face.setInterestFilter("/Hello/World", - bind(&FacesFixture::onInterest, this, ref(face), _1, _2), - RegisterPrefixSuccessCallback(), - bind(&FacesFixture::onRegFailed, this)); - - regPrefixId2 = face.setInterestFilter("/Los/Angeles/Lakers", - bind(&FacesFixture::onInterest2, this, ref(face), _1, _2), - RegisterPrefixSuccessCallback(), - bind(&FacesFixture::onRegFailed, this)); - - - scheduler.scheduleEvent(time::milliseconds(200), - bind(&FacesFixture::expressInterest, this, - ref(face2), Name("/Hello/World/!"))); + BOOST_CHECK_THROW(do { + this->face.expressInterest(*makeInterest(makeVeryLongName()), nullptr, nullptr, nullptr); + this->face.processEvents(); + } while (false), Face::OversizedPacketError); +} - BOOST_REQUIRE_NO_THROW(face.processEvents()); +BOOST_AUTO_TEST_SUITE_END() // Consumer - BOOST_CHECK_EQUAL(nRegFailures, 0); - BOOST_CHECK_EQUAL(nInInterests, 1); - BOOST_CHECK_EQUAL(nInInterests2, 0); - BOOST_CHECK_EQUAL(nTimeouts, 1); - BOOST_CHECK_EQUAL(nData, 0); -} +BOOST_AUTO_TEST_SUITE(Producer) -BOOST_AUTO_TEST_CASE(SetRegexFilterError) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(RegisterUnregisterPrefix, TransportType, Transports, FaceFixture) { - Face face; - Face face2(face.getIoService()); - Scheduler scheduler(face.getIoService()); - scheduler.scheduleEvent(time::seconds(4), - bind(&FacesFixture::terminate, this, ref(face))); - - regPrefixId = face.setInterestFilter(InterestFilter("/Hello/World", "<>?"), - bind(&FacesFixture::onInterestRegexError, this, - ref(face), _1, _2), - RegisterPrefixSuccessCallback(), - bind(&FacesFixture::onRegFailed, this)); - - scheduler.scheduleEvent(time::milliseconds(300), - bind(&FacesFixture::expressInterest, this, - ref(face2), Name("/Hello/World/XXX/b/c"))); // should match - - BOOST_REQUIRE_THROW(face.processEvents(), InterestFilter::Error); + this->terminateAfter(4_s); + + int nRegSuccess = 0, nUnregSuccess = 0; + auto handle = this->face.registerPrefix("/Hello/World", + [&] (const Name&) { ++nRegSuccess; }, + [] (const Name&, const auto& msg) { BOOST_ERROR("unexpected register prefix failure: " << msg); }); + + this->sched.schedule(1_s, [&nRegSuccess] { + BOOST_CHECK_EQUAL(nRegSuccess, 1); + std::string output = executeCommand("nfdc route list | grep /Hello/World"); + BOOST_CHECK(!output.empty()); + }); + + this->sched.schedule(2_s, [&] { + handle.unregister( + [&] { ++nUnregSuccess; }, + [] (const auto& msg) { BOOST_ERROR("unexpected unregister prefix failure: " << msg); }); + }); + + this->sched.schedule(3_s, [&nUnregSuccess] { + BOOST_CHECK_EQUAL(nUnregSuccess, 1); + + // Boost.Test would fail if a child process exits with non-zero. http://stackoverflow.com/q/5325202 + std::string output = executeCommand("nfdc route list | grep /Hello/World || true"); + BOOST_CHECK(output.empty()); + }); + + this->face.processEvents(); } -BOOST_AUTO_TEST_CASE(SetRegexFilter) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(RegularFilter, TransportType, Transports, FaceFixture) { - Face face; - Face face2(face.getIoService()); - Scheduler scheduler(face.getIoService()); - scheduler.scheduleEvent(time::seconds(4), - bind(&FacesFixture::terminate, this, ref(face))); - - regPrefixId = face.setInterestFilter(InterestFilter("/Hello/World", "<>?"), - bind(&FacesFixture::onInterestRegex, this, - ref(face), _1, _2), - RegisterPrefixSuccessCallback(), - bind(&FacesFixture::onRegFailed, this)); - - scheduler.scheduleEvent(time::milliseconds(200), - bind(&FacesFixture::expressInterest, this, - ref(face2), Name("/Hello/World/a"))); // shouldn't match - - scheduler.scheduleEvent(time::milliseconds(300), - bind(&FacesFixture::expressInterest, this, - ref(face2), Name("/Hello/World/a/b"))); // should match - - scheduler.scheduleEvent(time::milliseconds(400), - bind(&FacesFixture::expressInterest, this, - ref(face2), Name("/Hello/World/a/b/c"))); // should match - - scheduler.scheduleEvent(time::milliseconds(500), - bind(&FacesFixture::expressInterest, this, - ref(face2), Name("/Hello/World/a/b/d"))); // should not match - - BOOST_REQUIRE_NO_THROW(face.processEvents()); - - BOOST_CHECK_EQUAL(nRegFailures, 0); - BOOST_CHECK_EQUAL(nInInterests, 2); - BOOST_CHECK_EQUAL(nTimeouts, 4); - BOOST_CHECK_EQUAL(nData, 0); + this->terminateAfter(2_s); + + int nInterests1 = 0, nRegSuccess1 = 0, nRegSuccess2 = 0; + this->face.setInterestFilter("/Hello/World", + [&] (const InterestFilter&, const Interest&) { ++nInterests1; }, + [&] (const Name&) { ++nRegSuccess1; }, + [] (const Name&, const auto& msg) { BOOST_ERROR("unexpected register prefix failure: " << msg); }); + this->face.setInterestFilter("/Los/Angeles/Lakers", + [&] (const InterestFilter&, const Interest&) { BOOST_ERROR("unexpected Interest"); }, + [&] (const Name&) { ++nRegSuccess2; }, + [] (const Name&, const auto& msg) { BOOST_ERROR("unexpected register prefix failure: " << msg); }); + + this->sched.schedule(500_ms, [] { + std::string output = executeCommand("nfdc route list | grep /Hello/World"); + BOOST_CHECK(!output.empty()); + }); + + char interestOutcome; + this->sendInterest(1_s, *makeInterest("/Hello/World/regular", false, 50_ms), interestOutcome); + + this->face.processEvents(); + BOOST_CHECK_EQUAL(interestOutcome, 'T'); + BOOST_CHECK_EQUAL(nInterests1, 1); + BOOST_CHECK_EQUAL(nRegSuccess1, 1); + BOOST_CHECK_EQUAL(nRegSuccess2, 1); } -class FacesFixture2 : public FacesFixture -{ -public: - void - checkPrefix(bool shouldExist) - { - // Boost.Test fails if a child process exits with non-zero. - // http://stackoverflow.com/q/5325202 - std::string output = this->executeCommand("nfd-status -r | grep /Hello/World || true"); - - if (shouldExist) { - BOOST_CHECK_NE(output.size(), 0); - } - else { - BOOST_CHECK_EQUAL(output.size(), 0); - } - } - -protected: - std::string - executeCommand(const std::string& cmd) - { - std::string output; - char buf[256]; - FILE* pipe = popen(cmd.c_str(), "r"); - BOOST_REQUIRE_MESSAGE(pipe != nullptr, "cannot execute '" << cmd << "'"); - while (fgets(buf, sizeof(buf), pipe) != nullptr) { - output += buf; - } - pclose(pipe); - return output; - } -}; - -BOOST_FIXTURE_TEST_CASE(RegisterUnregisterPrefix, FacesFixture2) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(RegexFilter, TransportType, Transports, FaceFixture) { - Face face; - Scheduler scheduler(face.getIoService()); - scheduler.scheduleEvent(time::seconds(4), - bind(&FacesFixture::terminate, this, ref(face))); - - regPrefixId = face.setInterestFilter(InterestFilter("/Hello/World"), - bind(&FacesFixture::onInterest, this, - ref(face), _1, _2), - RegisterPrefixSuccessCallback(), - bind(&FacesFixture::onRegFailed, this)); - - scheduler.scheduleEvent(time::milliseconds(500), - bind(&FacesFixture2::checkPrefix, this, true)); - - scheduler.scheduleEvent(time::seconds(1), - bind(static_cast(&Face::unsetInterestFilter), - &face, - regPrefixId)); // shouldn't match - - scheduler.scheduleEvent(time::milliseconds(2000), - bind(&FacesFixture2::checkPrefix, this, false)); - - BOOST_REQUIRE_NO_THROW(face.processEvents()); + this->terminateAfter(2_s); + + int nRegSuccess = 0; + std::set receivedInterests; + this->face.setInterestFilter(InterestFilter("/Hello/World", "<>?"), + [&] (const InterestFilter&, const Interest& interest) { receivedInterests.insert(interest.getName()); }, + [&] (const Name&) { ++nRegSuccess; }, + [] (const Name&, const auto& msg) { BOOST_ERROR("unexpected register prefix failure: " << msg); }); + + this->sched.schedule(700_ms, [] { + std::string output = executeCommand("nfdc route list | grep /Hello/World"); + BOOST_CHECK(!output.empty()); + }); + + this->sendInterest(200_ms, *makeInterest("/Hello/World/a", false, 50_ms)); + this->sendInterest(300_ms, *makeInterest("/Hello/World/a/b", false, 50_ms)); + this->sendInterest(400_ms, *makeInterest("/Hello/World/a/b/c", false, 50_ms)); + this->sendInterest(500_ms, *makeInterest("/Hello/World/a/b/d", false, 50_ms)); + + this->face.processEvents(); + BOOST_CHECK_EQUAL(nRegSuccess, 1); + std::set expectedInterests{"/Hello/World/a/b", "/Hello/World/a/b/c"}; + BOOST_CHECK_EQUAL_COLLECTIONS(receivedInterests.begin(), receivedInterests.end(), + expectedInterests.begin(), expectedInterests.end()); } - -class FacesFixture3 : public FacesFixture2 -{ -public: - FacesFixture3() - : nRegSuccesses(0) - , nUnregSuccesses(0) - , nUnregFailures(0) - { - } - - void - onRegSucceeded() - { - ++nRegSuccesses; - } - - void - onUnregSucceeded() - { - ++nUnregSuccesses; - } - - void - onUnregFailed() - { - ++nUnregFailures; - } - -public: - uint64_t nRegSuccesses; - uint64_t nUnregSuccesses; - uint64_t nUnregFailures; -}; - -BOOST_FIXTURE_TEST_CASE(RegisterPrefix, FacesFixture3) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(RegexFilterNoRegister, TransportType, Transports, FaceFixture) { - Face face; - Face face2(face.getIoService()); - Scheduler scheduler(face.getIoService()); - scheduler.scheduleEvent(time::seconds(2), - bind(&FacesFixture::terminate, this, ref(face))); + this->terminateAfter(2_s); - scheduler.scheduleEvent(time::milliseconds(500), - bind(&FacesFixture2::checkPrefix, this, true)); + // no Interest shall arrive because prefix isn't registered in forwarder + this->face.setInterestFilter(InterestFilter("/Hello/World", "<>?"), + [&] (const InterestFilter&, const Interest&) { BOOST_ERROR("unexpected Interest"); }); - regPrefixId = face.registerPrefix("/Hello/World", - bind(&FacesFixture3::onRegSucceeded, this), - bind(&FacesFixture3::onRegFailed, this)); + this->sched.schedule(700_ms, [] { + // Boost.Test would fail if a child process exits with non-zero. http://stackoverflow.com/q/5325202 + std::string output = executeCommand("nfdc route list | grep /Hello/World || true"); + BOOST_CHECK(output.empty()); + }); - scheduler.scheduleEvent(time::seconds(1), - bind(&Face::unregisterPrefix, &face, - regPrefixId, - static_cast(bind(&FacesFixture3::onUnregSucceeded, this)), - static_cast(bind(&FacesFixture3::onUnregFailed, this)))); + this->sendInterest(200_ms, *makeInterest("/Hello/World/a", false, 50_ms)); + this->sendInterest(300_ms, *makeInterest("/Hello/World/a/b", false, 50_ms)); + this->sendInterest(400_ms, *makeInterest("/Hello/World/a/b/c", false, 50_ms)); + this->sendInterest(500_ms, *makeInterest("/Hello/World/a/b/d", false, 50_ms)); - scheduler.scheduleEvent(time::milliseconds(2500), - bind(&FacesFixture2::checkPrefix, this, false)); - - BOOST_REQUIRE_NO_THROW(face.processEvents()); - - BOOST_CHECK_EQUAL(nRegFailures, 0); - BOOST_CHECK_EQUAL(nRegSuccesses, 1); - - BOOST_CHECK_EQUAL(nUnregFailures, 0); - BOOST_CHECK_EQUAL(nUnregSuccesses, 1); + this->face.processEvents(); } -BOOST_AUTO_TEST_CASE(SetRegexFilterButNoRegister) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(PutDataNack, TransportType, Transports, FaceFixture) { - Face face; - Face face2(face.getIoService()); - Scheduler scheduler(face.getIoService()); - scheduler.scheduleEvent(time::seconds(2), - bind(&FacesFixture::terminate, this, ref(face))); - - face.setInterestFilter(InterestFilter("/Hello/World", "<>?"), - bind(&FacesFixture::onInterestRegex, this, - ref(face), _1, _2)); - - // prefix is not registered, and also does not match regex - scheduler.scheduleEvent(time::milliseconds(200), - bind(&FacesFixture::expressInterest, this, - ref(face2), Name("/Hello/World/a"))); - - // matches regex, but prefix is not registered - scheduler.scheduleEvent(time::milliseconds(300), - bind(&FacesFixture::expressInterest, this, - ref(face2), Name("/Hello/World/a/b"))); - - // matches regex, but prefix is not registered - scheduler.scheduleEvent(time::milliseconds(400), - bind(&FacesFixture::expressInterest, this, - ref(face2), Name("/Hello/World/a/b/c"))); - - // prefix is not registered, and also does not match regex - scheduler.scheduleEvent(time::milliseconds(500), - bind(&FacesFixture::expressInterest, this, - ref(face2), Name("/Hello/World/a/b/d"))); - - BOOST_REQUIRE_NO_THROW(face.processEvents()); - - BOOST_CHECK_EQUAL(nRegFailures, 0); - BOOST_CHECK_EQUAL(nInInterests, 0); - BOOST_CHECK_EQUAL(nTimeouts, 4); - BOOST_CHECK_EQUAL(nData, 0); + this->terminateAfter(2_s); + + this->face.setInterestFilter("/Hello/World", + [&] (const InterestFilter&, const Interest& interest) { + if (interest.getName().at(2) == name::Component("nack")) { + this->face.put(makeNack(interest, lp::NackReason::NO_ROUTE)); + } + else { + this->face.put(*makeData(interest.getName())); + } + }, + nullptr, + [] (const Name&, const auto& msg) { BOOST_ERROR("unexpected register prefix failure: " << msg); }); + + char outcome1, outcome2; + this->sendInterest(700_ms, *makeInterest("/Hello/World/data", false, 50_ms), outcome1); + this->sendInterest(800_ms, *makeInterest("/Hello/World/nack", false, 50_ms), outcome2); + + this->face.processEvents(); + BOOST_CHECK_EQUAL(outcome1, 'D'); + BOOST_CHECK_EQUAL(outcome2, 'N'); } - -BOOST_FIXTURE_TEST_CASE(SetRegexFilterAndRegister, FacesFixture3) +BOOST_FIXTURE_TEST_CASE_TEMPLATE(OversizedData, TransportType, Transports, FaceFixture) { - Face face; - Face face2(face.getIoService()); - Scheduler scheduler(face.getIoService()); - scheduler.scheduleEvent(time::seconds(2), - bind(&FacesFixture::terminate, this, ref(face))); - - face.setInterestFilter(InterestFilter("/Hello/World", "<>?"), - bind(&FacesFixture::onInterestRegex, this, - ref(face), _1, _2)); + this->terminateAfter(2_s); - face.registerPrefix("/Hello/World", - bind(&FacesFixture3::onRegSucceeded, this), - bind(&FacesFixture3::onRegFailed, this)); + this->face.setInterestFilter("/Hello/World", + [&] (const InterestFilter&, const Interest& interest) { + this->face.put(*makeData(makeVeryLongName(interest.getName()))); + }, + nullptr, + [] (const Name&, const auto& msg) { BOOST_ERROR("unexpected register prefix failure: " << msg); }); - scheduler.scheduleEvent(time::milliseconds(200), - bind(&FacesFixture::expressInterest, this, - ref(face2), Name("/Hello/World/a"))); // shouldn't match + this->sendInterest(1_s, *makeInterest("/Hello/World/oversized", true, 50_ms)); - scheduler.scheduleEvent(time::milliseconds(300), - bind(&FacesFixture::expressInterest, this, - ref(face2), Name("/Hello/World/a/b"))); // should match - - scheduler.scheduleEvent(time::milliseconds(400), - bind(&FacesFixture::expressInterest, this, - ref(face2), Name("/Hello/World/a/b/c"))); // should match - - scheduler.scheduleEvent(time::milliseconds(500), - bind(&FacesFixture::expressInterest, this, - ref(face2), Name("/Hello/World/a/b/d"))); // should not match - - BOOST_REQUIRE_NO_THROW(face.processEvents()); + BOOST_CHECK_THROW(this->face.processEvents(), Face::OversizedPacketError); +} - BOOST_CHECK_EQUAL(nRegFailures, 0); - BOOST_CHECK_EQUAL(nRegSuccesses, 1); +BOOST_AUTO_TEST_SUITE_END() // Producer - BOOST_CHECK_EQUAL(nInInterests, 2); - BOOST_CHECK_EQUAL(nTimeouts, 4); -} +BOOST_AUTO_TEST_SUITE(IoRoutine) BOOST_AUTO_TEST_CASE(ShutdownWhileSendInProgress) // Bug #3136 { - Face face; - face.expressInterest(Name("/Hello/World/!"), bind([]{}), bind([]{})); - BOOST_REQUIRE_NO_THROW(face.processEvents(time::seconds(1))); + this->face.expressInterest(*makeInterest("/Hello/World"), nullptr, nullptr, nullptr); + this->face.processEvents(1_s); - face.expressInterest(Name("/Bye/World/1"), bind([]{}), bind([]{})); - face.expressInterest(Name("/Bye/World/2"), bind([]{}), bind([]{})); - face.expressInterest(Name("/Bye/World/3"), bind([]{}), bind([]{})); - face.shutdown(); + this->face.expressInterest(*makeInterest("/Bye/World/1"), nullptr, nullptr, nullptr); + this->face.expressInterest(*makeInterest("/Bye/World/2"), nullptr, nullptr, nullptr); + this->face.expressInterest(*makeInterest("/Bye/World/3"), nullptr, nullptr, nullptr); + this->face.shutdown(); - BOOST_REQUIRE_NO_THROW(face.processEvents(time::seconds(1))); - // should not segfault + this->face.processEvents(1_s); // should not segfault + BOOST_CHECK(true); } BOOST_AUTO_TEST_CASE(LargeDelayBetweenFaceConstructorAndProcessEvents) // Bug #2742 { - ndn::Face face; + std::this_thread::sleep_for(std::chrono::seconds(5)); // simulate setup workload + this->face.processEvents(1_s); // should not throw + BOOST_CHECK(true); +} - ::sleep(5); // simulate setup workload +BOOST_AUTO_TEST_CASE(ProcessEventsBlocksForeverWhenNothingScheduled) // Bug #3957 +{ + std::mutex m; + std::condition_variable cv; + bool processEventsFinished = false; - BOOST_CHECK_NO_THROW(face.processEvents(time::seconds(1))); + std::thread faceThread([&] { + this->face.processEvents(); + + processEventsFinished = true; + std::lock_guard lk(m); + cv.notify_one(); + }); + + { + std::unique_lock lk(m); + cv.wait_for(lk, std::chrono::seconds(5), [&] { return processEventsFinished; }); + } + + BOOST_CHECK_EQUAL(processEventsFinished, true); + if (!processEventsFinished) { + this->face.shutdown(); + } + faceThread.join(); } -BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() // IoRoutine + +BOOST_AUTO_TEST_SUITE_END() // TestFace } // namespace tests } // namespace ndn diff --git a/tests/integrated/network-monitor.README.md b/tests/integrated/network-monitor.README.md new file mode 100644 index 000000000..a9a9af146 --- /dev/null +++ b/tests/integrated/network-monitor.README.md @@ -0,0 +1,70 @@ +# NetworkMonitor test + +These instructions are only for Linux and macOS. + +Run the network-monitor integrated test binary, e.g.: +``` +./build/tests/integrated/network-monitor +``` +Note: sudo is not required. + +You should see an `onInterfaceAdded` message for each ethernet and loopback +network interface present on the system, followed by an `onAddressAdded` +message for each IPv4/IPv6 address on each interface. Finally, +`onEnumerationCompleted` is printed, along with a summary of all interfaces +discovered thus far. + +## Linux + +[The following commands assume eth0 is the name of an ethernet interface +on the machine. If your interfaces are named differently, replace eth0 +with the name of any ethernet interface that you have available.] + +Command | Expected output +--------|---------------- +sudo ip link add link eth0 name nmtest0 type vlan id 42 | `nmtest0: onInterfaceAdded` +sudo ip link set dev nmtest0 mtu 1342 | `nmtest0: onMtuChanged -> 1342` (`old_mtu` is most likely 1500) +sudo ip link set dev nmtest0 up | `nmtest0: onStateChanged down -> ` (`new_state` is one of: running, dormant, no-carrier) +sudo ip address add 198.51.100.100/24 dev nmtest0 | `nmtest0: onAddressAdded 198.51.100.100/24` +sudo ip address del 198.51.100.100/24 dev nmtest0 | `nmtest0: onAddressRemoved 198.51.100.100/24` +sudo ip address add 2001:db8::1/80 dev nmtest0 | `nmtest0: onAddressAdded 2001:db8::1/80` +sudo ip address del 2001:db8::1/80 dev nmtest0 | `nmtest0: onAddressRemoved 2001:db8::1/80` +sudo ip link delete dev nmtest0 | `nmtest0: onInterfaceRemoved` + +If you unplug the ethernet cable from your network card, you should see: +``` +eth0: onStateChanged running -> no-carrier +nmtest0: onStateChanged running -> no-carrier +``` + +Plugging the cable back in should produce the following messages: +``` +eth0: onStateChanged no-carrier -> running +nmtest0: onStateChanged no-carrier -> running +``` + +## macOS + +[The following commands assume en0 is the name of an ethernet interface +on the machine. If your interfaces are named differently, replace en0 +with the name of any ethernet interface that you have available.] + +Command | Expected output +--------|---------------- +sudo ifconfig vlan1 create | `vlan1: onInterfaceAdded` +sudo ifconfig vlan1 vlan 1 vlandev en0 | `vlan1: onStateChanged down -> running` +sudo ifconfig vlan1 198.51.100.100/24 | `vlan1: onAddressAdded 198.51.100.100/24` +sudo ifconfig vlan1 198.51.100.100/24 remove | `vlan1: onAddressRemoved 198.51.100.100/24` +sudo ifconfig vlan1 inet6 2001:db8::1/80 | `vlan1: onAddressAdded 2001:db8::1/80` (and potentially link-local addresses) +sudo ifconfig vlan1 inet6 2001:db8::1/80 remove | `vlan1: onAddressRemoved 2001:db8::1/80` +sudo ifconfig vlan1 destroy | `vlan1: onInterfaceRemoved` + +If you unplug the ethernet cable from your network card, you should see: +``` +en6: onStateChanged running -> down +``` + +Plugging the cable back in should produce the following messages: +``` +en6: onStateChanged down -> running +``` diff --git a/tests/integrated/network-monitor.cpp b/tests/integrated/network-monitor.cpp index cbc0e8a8a..57cea9775 100644 --- a/tests/integrated/network-monitor.cpp +++ b/tests/integrated/network-monitor.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,40 +19,84 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#define BOOST_TEST_MAIN 1 -#define BOOST_TEST_DYN_LINK 1 #define BOOST_TEST_MODULE ndn-cxx Integrated Tests (Network Monitor) +#include "tests/boost-test.hpp" -#include "util/network-monitor.hpp" +#include "ndn-cxx/net/network-monitor.hpp" -#include "util/time.hpp" - -#include "boost-test.hpp" +#include "ndn-cxx/net/network-address.hpp" +#include "ndn-cxx/net/network-interface.hpp" +#include "ndn-cxx/net/impl/link-type-helper.hpp" +#include "ndn-cxx/util/string-helper.hpp" +#include "ndn-cxx/util/time.hpp" #include #include namespace ndn { -namespace util { +namespace net { +namespace tests { -BOOST_AUTO_TEST_SUITE(UtilNetworkMonitor) +BOOST_AUTO_TEST_SUITE(TestNetworkMonitor) -BOOST_AUTO_TEST_CASE(Basic) +static std::ostream& +logEvent(const shared_ptr& ni = nullptr, std::ostream& os = std::cout) { - boost::asio::io_service io; - BOOST_REQUIRE_NO_THROW((NetworkMonitor(io))); + os << '[' << time::toIsoString(time::system_clock::now()) << "] "; + if (ni != nullptr) + os << ni->getName() << ": "; + return os; +} +BOOST_AUTO_TEST_CASE(Signals) +{ + boost::asio::io_service io; NetworkMonitor monitor(io); + std::cout << "capabilities=" << AsHex{monitor.getCapabilities()} << std::endl; + monitor.onNetworkStateChanged.connect([] { - std::cout << time::toString(time::system_clock::now()) - << "\tReceived network state change event" << std::endl; + logEvent() << "onNetworkStateChanged" << std::endl; + }); + + monitor.onEnumerationCompleted.connect([&monitor] { + logEvent() << "onEnumerationCompleted" << std::endl; + for (const auto& ni : monitor.listNetworkInterfaces()) { + std::cout << *ni; + } + }); + + monitor.onInterfaceAdded.connect([] (const shared_ptr& ni) { + logEvent(ni) << "onInterfaceAdded\n" << *ni; + logEvent(ni) << "link-type: " << detail::getLinkType(ni->getName()) << std::endl; + + ni->onAddressAdded.connect([ni] (const NetworkAddress& address) { + logEvent(ni) << "onAddressAdded " << address << std::endl; + }); + + ni->onAddressRemoved.connect([ni] (const NetworkAddress& address) { + logEvent(ni) << "onAddressRemoved " << address << std::endl; + }); + + ni->onStateChanged.connect([ni] (InterfaceState oldState, InterfaceState newState) { + logEvent(ni) << "onStateChanged " << oldState << " -> " << newState << std::endl; + logEvent(ni) << "link-type: " << detail::getLinkType(ni->getName()) << std::endl; + }); + + ni->onMtuChanged.connect([ni] (uint32_t oldMtu, uint32_t newMtu) { + logEvent(ni) << "onMtuChanged " << oldMtu << " -> " << newMtu << std::endl; }); + }); // monitor.onInterfaceAdded.connect + + monitor.onInterfaceRemoved.connect([] (const shared_ptr& ni) { + logEvent(ni) << "onInterfaceRemoved" << std::endl; + }); io.run(); } -BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() // TestNetworkMonitor -} // namespace util +} // namespace tests +} // namespace net } // namespace ndn diff --git a/tests/integrated/scheduler-benchmark.cpp b/tests/integrated/scheduler-benchmark.cpp index 16a6bdc71..51192ee30 100644 --- a/tests/integrated/scheduler-benchmark.cpp +++ b/tests/integrated/scheduler-benchmark.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,39 +19,43 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#define BOOST_TEST_MAIN 1 -#define BOOST_TEST_DYN_LINK 1 #define BOOST_TEST_MODULE ndn-cxx Scheduler Benchmark +#include "tests/boost-test.hpp" -#include "util/scheduler.hpp" +#include "ndn-cxx/util/scheduler.hpp" +#include "tests/integrated/timed-execute.hpp" -#include "boost-test.hpp" +#include +#include namespace ndn { -namespace util { namespace scheduler { namespace tests { +using namespace ndn::tests; + BOOST_AUTO_TEST_CASE(ScheduleCancel) { boost::asio::io_service io; Scheduler sched(io); - const int nEvents = 1000000; + const size_t nEvents = 1000000; std::vector eventIds(nEvents); - time::steady_clock::TimePoint t1 = time::steady_clock::now(); - for (int i = 0; i < nEvents; ++i) { - eventIds[i] = sched.scheduleEvent(time::seconds(1), []{}); - } - time::steady_clock::TimePoint t2 = time::steady_clock::now(); - for (int i = 0; i < nEvents; ++i) { - sched.cancelEvent(eventIds[i]); - } - time::steady_clock::TimePoint t3 = time::steady_clock::now(); + auto d1 = timedExecute([&] { + for (size_t i = 0; i < nEvents; ++i) { + eventIds[i] = sched.schedule(1_s, []{}); + } + }); + + auto d2 = timedExecute([&] { + for (size_t i = 0; i < nEvents; ++i) { + eventIds[i].cancel(); + } + }); - BOOST_TEST_MESSAGE("schedule " << nEvents << " events: " << (t2 - t1)); - BOOST_TEST_MESSAGE("cancel " << nEvents << " events: " << (t3 - t2)); + std::cout << "schedule " << nEvents << " events: " << d1 << std::endl; + std::cout << "cancel " << nEvents << " events: " << d2 << std::endl; } BOOST_AUTO_TEST_CASE(Execute) @@ -59,30 +63,29 @@ BOOST_AUTO_TEST_CASE(Execute) boost::asio::io_service io; Scheduler sched(io); - const int nEvents = 1000000; - int nExpired = 0; + const size_t nEvents = 1000000; + size_t nExpired = 0; // Events should expire at t1, but execution finishes at t2. The difference is the overhead. - time::steady_clock::TimePoint t1 = time::steady_clock::now() + time::seconds(5); + time::steady_clock::TimePoint t1 = time::steady_clock::now() + 5_s; time::steady_clock::TimePoint t2; // +1ms ensures this extra event is executed last. In case the overhead is less than 1ms, // it will be reported as 1ms. - sched.scheduleEvent(t1 - time::steady_clock::now() + time::milliseconds(1), [&] { + sched.schedule(t1 - time::steady_clock::now() + 1_ms, [&] { t2 = time::steady_clock::now(); BOOST_REQUIRE_EQUAL(nExpired, nEvents); }); - for (int i = 0; i < nEvents; ++i) { - sched.scheduleEvent(t1 - time::steady_clock::now(), [&] { ++nExpired; }); + for (size_t i = 0; i < nEvents; ++i) { + sched.schedule(t1 - time::steady_clock::now(), [&] { ++nExpired; }); } io.run(); BOOST_REQUIRE_EQUAL(nExpired, nEvents); - BOOST_TEST_MESSAGE("execute " << nEvents << " events: " << (t2 - t1)); + std::cout << "execute " << nEvents << " events: " << (t2 - t1) << std::endl; } } // namespace tests } // namespace scheduler -} // namespace util } // namespace ndn diff --git a/tests/integrated/timed-execute.hpp b/tests/integrated/timed-execute.hpp new file mode 100644 index 000000000..83767a14a --- /dev/null +++ b/tests/integrated/timed-execute.hpp @@ -0,0 +1,43 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TESTS_INTEGRATED_TIMED_EXECUTE_HPP +#define NDN_TESTS_INTEGRATED_TIMED_EXECUTE_HPP + +#include "ndn-cxx/util/time.hpp" + +namespace ndn { +namespace tests { + +template +time::nanoseconds +timedExecute(const F& f) +{ + auto before = time::steady_clock::now(); + f(); + auto after = time::steady_clock::now(); + return after - before; +} + +} // namespace tests +} // namespace ndn + +#endif // NDN_TESTS_INTEGRATED_TIMED_EXECUTE_HPP diff --git a/tests/integrated/wscript b/tests/integrated/wscript index 08260b73f..73158d8cd 100644 --- a/tests/integrated/wscript +++ b/tests/integrated/wscript @@ -1,15 +1,12 @@ # -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -from waflib import Utils - -top = '..' +top = '../..' def build(bld): - for i in bld.path.ant_glob(['*.cpp']): - name = str(i)[:-len(".cpp")] - bld(features='cxx cxxprogram', - target=name, - source=[i], - use='ndn-cxx boost-tests-base BOOST', - includes='..', - install_path=None) + for test in bld.path.ant_glob('*.cpp'): + name = test.change_ext('').path_from(bld.path.get_bld()) + bld.program(name='test-%s' % name, + target=name, + source=[test], + use='tests-common', + install_path=None) diff --git a/tests/key-chain-fixture.cpp b/tests/key-chain-fixture.cpp deleted file mode 100644 index a8f951b52..000000000 --- a/tests/key-chain-fixture.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "key-chain-fixture.hpp" - -namespace ndn { -namespace tests { - -KeyChainFixture::KeyChainFixture() -{ - addIdentity(Name("/localhost/ndn-cxx-test-identity").appendVersion()); -} - -BOOST_GLOBAL_FIXTURE(KeyChainFixture) -#if BOOST_VERSION >= 105900 -; -#endif // BOOST_VERSION >= 105900 - -} // namespace tests -} // namespace ndn diff --git a/tests/key-chain-fixture.hpp b/tests/key-chain-fixture.hpp deleted file mode 100644 index e9218a67f..000000000 --- a/tests/key-chain-fixture.hpp +++ /dev/null @@ -1,138 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_TESTS_KEY_CHAIN_FIXTURE_HPP -#define NDN_TESTS_KEY_CHAIN_FIXTURE_HPP - -#include "security/key-chain.hpp" - -#include "boost-test.hpp" -#include "identity-management-fixture.hpp" - -#include -#include -#include - -namespace ndn { -namespace tests { - -/** - * @brief Fixture to adjust/restore NDN_CLIENT_PIB and NDN_CLIENT_TPM paths - * - * Note that the specified PATH will be removed after fixture is destroyed. - * **Do not specify non-temporary paths.** - */ -template -class PibDirFixture -{ -public: - PibDirFixture() - : m_pibDir(Path().PATH) - { - if (getenv("NDN_CLIENT_PIB") != nullptr) { - m_oldPib = getenv("NDN_CLIENT_PIB"); - } - if (getenv("NDN_CLIENT_TPM") != nullptr) { - m_oldTpm = getenv("NDN_CLIENT_TPM"); - } - - /// @todo Consider change to an in-memory PIB/TPM - setenv("NDN_CLIENT_PIB", ("pib-sqlite3:" + m_pibDir).c_str(), true); - setenv("NDN_CLIENT_TPM", ("tpm-file:" + m_pibDir).c_str(), true); - } - - ~PibDirFixture() - { - if (!m_oldPib.empty()) { - setenv("NDN_CLIENT_PIB", m_oldPib.c_str(), true); - } - else { - unsetenv("NDN_CLIENT_PIB"); - } - - if (!m_oldTpm.empty()) { - setenv("NDN_CLIENT_TPM", m_oldTpm.c_str(), true); - } - else { - unsetenv("NDN_CLIENT_TPM"); - } - - boost::filesystem::remove_all(m_pibDir); - } - -protected: - const std::string m_pibDir; - -private: - std::string m_oldPib; - std::string m_oldTpm; -}; - -/** - * @brief Extension of PibDirFixture to set TEST_HOME variable and allow config file creation - */ -template -class TestHomeFixture : public PibDirFixture -{ -public: - TestHomeFixture() - { - setenv("TEST_HOME", this->m_pibDir.c_str(), true); - } - - ~TestHomeFixture() - { - unsetenv("TEST_HOME"); - } - - void - createClientConf(std::initializer_list lines) - { - boost::filesystem::create_directories(boost::filesystem::path(this->m_pibDir) / ".ndn"); - std::ofstream of((boost::filesystem::path(this->m_pibDir) / ".ndn" / "client.conf").c_str()); - for (auto line : lines) { - boost::replace_all(line, "%PATH%", this->m_pibDir); - of << line << std::endl; - } - } -}; - - -struct DefaultPibDir -{ - const std::string PATH = "build/keys"; -}; - -/** - * @brief Fixture to create a test KeyChain with default identity - */ -class KeyChainFixture : public PibDirFixture, - public IdentityManagementFixture -{ -public: - KeyChainFixture(); -}; - - -} // namespace tests -} // namespace ndn - -#endif // NDN_TESTS_KEY_CHAIN_FIXTURE_HPP diff --git a/tests/unit-tests/make-interest-data.cpp b/tests/make-interest-data.cpp similarity index 80% rename from tests/unit-tests/make-interest-data.cpp rename to tests/make-interest-data.cpp index ab9c6ff8e..76b2f44a6 100644 --- a/tests/unit-tests/make-interest-data.cpp +++ b/tests/make-interest-data.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,16 +19,18 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "make-interest-data.hpp" -#include "security/signature-sha256-with-rsa.hpp" +#include "tests/make-interest-data.hpp" + +#include "ndn-cxx/security/signature-sha256-with-rsa.hpp" namespace ndn { namespace tests { shared_ptr -makeInterest(const Name& name, uint32_t nonce) +makeInterest(const Name& name, bool canBePrefix, time::milliseconds lifetime, uint32_t nonce) { - auto interest = make_shared(name); + auto interest = make_shared(name, lifetime); + interest->setCanBePrefix(canBePrefix); if (nonce != 0) { interest->setNonce(nonce); } @@ -52,14 +54,6 @@ signData(Data& data) return data; } -shared_ptr -makeLink(const Name& name, std::initializer_list> delegations) -{ - auto link = make_shared(name, delegations); - signData(link); - return link; -} - lp::Nack makeNack(const Interest& interest, lp::NackReason reason) { diff --git a/tests/make-interest-data.hpp b/tests/make-interest-data.hpp new file mode 100644 index 000000000..10381fdf5 --- /dev/null +++ b/tests/make-interest-data.hpp @@ -0,0 +1,88 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TESTS_MAKE_INTEREST_DATA_HPP +#define NDN_TESTS_MAKE_INTEREST_DATA_HPP + +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/link.hpp" +#include "ndn-cxx/lp/nack.hpp" + +namespace ndn { +namespace tests { + +/** \brief create an Interest + * \param name Interest name + * \param canBePrefix CanBePrefix setting + * \param lifetime InterestLifetime + * \param nonce if non-zero, set Nonce to this value (useful for creating Nack with same Nonce) + */ +shared_ptr +makeInterest(const Name& name, bool canBePrefix = false, + time::milliseconds lifetime = DEFAULT_INTEREST_LIFETIME, uint32_t nonce = 0); + +/** \brief create a Data with fake signature + * \note Data may be modified afterwards without losing the fake signature. + * If a real signature is desired, sign again with KeyChain. + */ +shared_ptr +makeData(const Name& name); + +/** \brief add a fake signature to Data + */ +Data& +signData(Data& data); + +/** \brief add a fake signature to Data + */ +inline shared_ptr +signData(shared_ptr data) +{ + signData(*data); + return data; +} + +/** \brief create a Nack + * \param interest Interest + * \param reason Nack reason + */ +lp::Nack +makeNack(const Interest& interest, lp::NackReason reason); + +/** \brief replace a name component in a packet + * \param[inout] pkt the packet + * \param index the index of the name component to replace + * \param args arguments to name::Component constructor + */ +template +void +setNameComponent(Packet& pkt, ssize_t index, Args&& ...args) +{ + Name name = pkt.getName(); + name.set(index, name::Component(std::forward(args)...)); + pkt.setName(name); +} + +} // namespace tests +} // namespace ndn + +#endif // NDN_TESTS_MAKE_INTEREST_DATA_HPP diff --git a/tests/test-home-fixture.hpp b/tests/test-home-fixture.hpp new file mode 100644 index 000000000..38fd3f1a7 --- /dev/null +++ b/tests/test-home-fixture.hpp @@ -0,0 +1,128 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TESTS_TEST_HOME_FIXTURE_HPP +#define NDN_TESTS_TEST_HOME_FIXTURE_HPP + +#include "ndn-cxx/security/v2/key-chain.hpp" + +#include +#include +#include + +#include +#include + +namespace ndn { +namespace tests { + +/** + * @brief Fixture to adjust/restore NDN_CLIENT_PIB and NDN_CLIENT_TPM paths + * + * Note that the specified PATH will be removed after fixture is destroyed. + * **Do not specify non-temporary paths.** + */ +template +class PibDirFixture +{ +public: + PibDirFixture() + : m_pibDir(Path().PATH) + { + if (std::getenv("NDN_CLIENT_PIB") != nullptr) { + m_oldPib = std::getenv("NDN_CLIENT_PIB"); + } + if (std::getenv("NDN_CLIENT_TPM") != nullptr) { + m_oldTpm = std::getenv("NDN_CLIENT_TPM"); + } + + /// @todo Consider change to an in-memory PIB/TPM + setenv("NDN_CLIENT_PIB", ("pib-sqlite3:" + m_pibDir).c_str(), true); + setenv("NDN_CLIENT_TPM", ("tpm-file:" + m_pibDir).c_str(), true); + } + + ~PibDirFixture() + { + if (!m_oldPib.empty()) { + setenv("NDN_CLIENT_PIB", m_oldPib.data(), true); + } + else { + unsetenv("NDN_CLIENT_PIB"); + } + + if (!m_oldTpm.empty()) { + setenv("NDN_CLIENT_TPM", m_oldTpm.data(), true); + } + else { + unsetenv("NDN_CLIENT_TPM"); + } + + boost::filesystem::remove_all(m_pibDir); + const_cast(security::v2::KeyChain::getDefaultPibLocator()).clear(); + const_cast(security::v2::KeyChain::getDefaultTpmLocator()).clear(); + } + +protected: + const std::string m_pibDir; + +private: + std::string m_oldPib; + std::string m_oldTpm; +}; + +/** + * @brief Extension of PibDirFixture to set TEST_HOME variable and allow config file creation + */ +template +class TestHomeFixture : public PibDirFixture +{ +public: + TestHomeFixture() + { + setenv("TEST_HOME", this->m_pibDir.c_str(), true); + } + + ~TestHomeFixture() + { + unsetenv("TEST_HOME"); + } + + void + createClientConf(std::initializer_list lines) const + { + boost::filesystem::create_directories(boost::filesystem::path(this->m_pibDir) / ".ndn"); + std::ofstream of((boost::filesystem::path(this->m_pibDir) / ".ndn" / "client.conf").c_str()); + for (auto line : lines) { + boost::replace_all(line, "%PATH%", this->m_pibDir); + of << line << std::endl; + } + } +}; + +struct DefaultPibDir +{ + const std::string PATH = "build/keys"; +}; + +} // namespace tests +} // namespace ndn + +#endif // NDN_TESTS_TEST_HOME_FIXTURE_HPP diff --git a/tests/unit-tests/data.t.cpp b/tests/unit-tests/data.t.cpp deleted file mode 100644 index 2940c77b3..000000000 --- a/tests/unit-tests/data.t.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "data.hpp" -#include "security/key-chain.hpp" -#include "security/v1/cryptopp.hpp" -#include "encoding/buffer-stream.hpp" - -#include "boost-test.hpp" -#include "identity-management-fixture.hpp" - -namespace ndn { -namespace tests { - -BOOST_AUTO_TEST_SUITE(TestData) - -const uint8_t Content1[] = {0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x21}; - -const uint8_t Data1[] = { -0x06, 0xc5, // NDN Data - 0x07, 0x14, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x08, 0x06, - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x14, 0x04, // MetaInfo - 0x19, 0x02, // FreshnessPeriod - 0x27, 0x10, - 0x15, 0x08, // Content - 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x21, - 0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x01, - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x17, 0x80, // SignatureValue - 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, - 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, - 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, - 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, - 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, - 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, - 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, - 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, - 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, - 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1 -}; - -const unsigned char DEFAULT_PRIVATE_KEY_DER[] = { - 0x30, 0x82, 0x02, 0x74, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, - 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x5e, 0x30, 0x82, - 0x02, 0x5a, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0x9e, 0x06, 0x3e, 0x47, 0x85, - 0xb2, 0x34, 0x37, 0xaa, 0x85, 0x47, 0xac, 0x03, 0x24, 0x83, 0xb5, 0x9c, 0xa8, 0x05, - 0x3a, 0x24, 0x1e, 0xeb, 0x89, 0x01, 0xbb, 0xe9, 0x9b, 0xb2, 0xc3, 0x22, 0xac, 0x68, - 0xe3, 0xf0, 0x6c, 0x02, 0xce, 0x68, 0xa6, 0xc4, 0xd0, 0xa7, 0x06, 0x90, 0x9c, 0xaa, - 0x1b, 0x08, 0x1d, 0x8b, 0x43, 0x9a, 0x33, 0x67, 0x44, 0x6d, 0x21, 0xa3, 0x1b, 0x88, - 0x9a, 0x97, 0x5e, 0x59, 0xc4, 0x15, 0x0b, 0xd9, 0x2c, 0xbd, 0x51, 0x07, 0x61, 0x82, - 0xad, 0xc1, 0xb8, 0xd7, 0xbf, 0x9b, 0xcf, 0x7d, 0x24, 0xc2, 0x63, 0xf3, 0x97, 0x17, - 0xeb, 0xfe, 0x62, 0x25, 0xba, 0x5b, 0x4d, 0x8a, 0xc2, 0x7a, 0xbd, 0x43, 0x8a, 0x8f, - 0xb8, 0xf2, 0xf1, 0xc5, 0x6a, 0x30, 0xd3, 0x50, 0x8c, 0xc8, 0x9a, 0xdf, 0xef, 0xed, - 0x35, 0xe7, 0x7a, 0x62, 0xea, 0x76, 0x7c, 0xbb, 0x08, 0x26, 0xc7, 0x02, 0x01, 0x11, - 0x02, 0x81, 0x80, 0x04, 0xa5, 0xd4, 0xa7, 0xc0, 0x2a, 0xe3, 0x6b, 0x0c, 0x8b, 0x73, - 0x0c, 0x96, 0xae, 0x40, 0x1b, 0xee, 0x04, 0xf1, 0x18, 0x4c, 0x5b, 0x43, 0x29, 0xad, - 0x3a, 0x3b, 0x93, 0xa3, 0x60, 0x17, 0x9b, 0xa8, 0xbb, 0x68, 0xf4, 0x1e, 0x33, 0x3f, - 0x50, 0x32, 0xf7, 0x13, 0xf8, 0xa9, 0xe6, 0x7d, 0x79, 0x44, 0x00, 0xde, 0x72, 0xed, - 0xf2, 0x73, 0xfa, 0x7b, 0xae, 0x2a, 0x71, 0xc0, 0x40, 0xc8, 0x37, 0x6f, 0x38, 0xb2, - 0x69, 0x1f, 0xa8, 0x83, 0x7b, 0x42, 0x00, 0x73, 0x46, 0xe6, 0x4c, 0x91, 0x7f, 0x13, - 0x06, 0x69, 0x06, 0xd8, 0x3f, 0x22, 0x15, 0x75, 0xf6, 0xde, 0xcd, 0xb0, 0xbc, 0x66, - 0x61, 0x91, 0x08, 0x9b, 0x2b, 0xb2, 0x00, 0xa9, 0x67, 0x05, 0x39, 0x40, 0xb9, 0x37, - 0x85, 0x88, 0x4f, 0x76, 0x79, 0x63, 0xc0, 0x88, 0x3c, 0x86, 0xa8, 0x12, 0x94, 0x5f, - 0xe4, 0x36, 0x3d, 0xea, 0xb9, 0x02, 0x41, 0x00, 0xb6, 0x2e, 0xbb, 0xcd, 0x2f, 0x3a, - 0x99, 0xe0, 0xa1, 0xa5, 0x44, 0x77, 0xea, 0x0b, 0xbe, 0x16, 0x95, 0x0e, 0x64, 0xa7, - 0x68, 0xd7, 0x4b, 0x15, 0x15, 0x23, 0xe2, 0x1e, 0x4e, 0x00, 0x2c, 0x22, 0x97, 0xae, - 0xb0, 0x74, 0xa6, 0x99, 0xd0, 0x5d, 0xb7, 0x1b, 0x10, 0x34, 0x13, 0xd2, 0x5f, 0x6e, - 0x56, 0xad, 0x85, 0x4a, 0xdb, 0xf0, 0x78, 0xbd, 0xf4, 0x8c, 0xb7, 0x9a, 0x3e, 0x99, - 0xef, 0xb9, 0x02, 0x41, 0x00, 0xde, 0x0d, 0xa7, 0x48, 0x75, 0x90, 0xad, 0x11, 0xa1, - 0xac, 0xee, 0xcb, 0x41, 0x81, 0xc6, 0xc8, 0x7f, 0xe7, 0x25, 0x94, 0xa1, 0x2a, 0x21, - 0xa8, 0x57, 0xfe, 0x84, 0xf2, 0x5e, 0xb4, 0x96, 0x35, 0xaf, 0xef, 0x2e, 0x7a, 0xf8, - 0xda, 0x3f, 0xac, 0x8a, 0x3c, 0x1c, 0x9c, 0xbd, 0x44, 0xd6, 0x90, 0xb5, 0xce, 0x1b, - 0x12, 0xf9, 0x3b, 0x8c, 0x69, 0xf6, 0xa9, 0x02, 0x93, 0x48, 0x35, 0x0a, 0x7f, 0x02, - 0x40, 0x6b, 0x2a, 0x8c, 0x96, 0xd0, 0x7c, 0xd2, 0xfc, 0x9b, 0x52, 0x28, 0x46, 0x89, - 0xac, 0x8d, 0xef, 0x2a, 0x80, 0xef, 0xea, 0x01, 0x6f, 0x95, 0x93, 0xee, 0x51, 0x57, - 0xd5, 0x97, 0x4b, 0x65, 0x41, 0x86, 0x66, 0xc2, 0x26, 0x80, 0x1e, 0x3e, 0x55, 0x3e, - 0x88, 0x63, 0xe2, 0x66, 0x03, 0x47, 0x31, 0xd8, 0xa2, 0x4e, 0x68, 0x45, 0x24, 0x0a, - 0xca, 0x17, 0x61, 0xd5, 0x69, 0xca, 0x78, 0xab, 0x21, 0x02, 0x41, 0x00, 0x8f, 0xae, - 0x7b, 0x4d, 0x00, 0xc7, 0x06, 0x92, 0xf0, 0x24, 0x9a, 0x83, 0x84, 0xbd, 0x62, 0x81, - 0xbc, 0x2c, 0x27, 0x60, 0x2c, 0x0c, 0x33, 0xe5, 0x66, 0x1d, 0x28, 0xd9, 0x10, 0x1a, - 0x7f, 0x4f, 0xea, 0x4f, 0x78, 0x6d, 0xb0, 0x14, 0xbf, 0xc9, 0xff, 0x17, 0xd6, 0x47, - 0x4d, 0x4a, 0xa8, 0xf4, 0x39, 0x67, 0x3e, 0xb1, 0xec, 0x8f, 0xf1, 0x71, 0xbd, 0xb8, - 0xa7, 0x50, 0x3d, 0xc7, 0xf7, 0xbb, 0x02, 0x40, 0x0d, 0x85, 0x32, 0x73, 0x9f, 0x0a, - 0x33, 0x2f, 0x4b, 0xa2, 0xbd, 0xd1, 0xb1, 0x42, 0xf0, 0x72, 0xa8, 0x7a, 0xc8, 0x15, - 0x37, 0x1b, 0xde, 0x76, 0x70, 0xce, 0xfd, 0x69, 0x20, 0x00, 0x4d, 0xc9, 0x4f, 0x35, - 0x6f, 0xd1, 0x35, 0xa1, 0x04, 0x95, 0x30, 0xe8, 0x3b, 0xd5, 0x03, 0x5a, 0x50, 0x21, - 0x6d, 0xa0, 0x84, 0x39, 0xe9, 0x2e, 0x1e, 0xfc, 0xe4, 0x82, 0x43, 0x20, 0x46, 0x7d, - 0x0a, 0xb6 -}; - -BOOST_AUTO_TEST_CASE(DataEqualityChecks) -{ - using namespace time; - - Data a; - Data b; - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - a.setName("ndn:/A"); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setName("ndn:/B"); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setName("ndn:/A"); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - a.setFreshnessPeriod(seconds(10)); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setFreshnessPeriod(seconds(10)); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - static const uint8_t someData[] = "someData"; - a.setContent(someData, sizeof(someData)); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setContent(someData, sizeof(someData)); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - a.setSignature(SignatureSha256WithRsa()); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setSignature(SignatureSha256WithRsa()); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); -} - -BOOST_AUTO_TEST_CASE(SignatureEqualityChecks) -{ - Signature a; - Signature b; - - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - a = SignatureSha256WithRsa(); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b = SignatureSha256WithRsa(); - static const uint8_t someData[256] = {}; - Block signatureValue = makeBinaryBlock(tlv::SignatureValue, someData, sizeof(someData)); - b.setValue(signatureValue); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - a.setValue(signatureValue); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - a = DigestSha256(); - b = SignatureSha256WithRsa(); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b = DigestSha256(); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); -} - -class TestDataFixture -{ -public: - TestDataFixture() - { - CryptoPP::StringSource source(DEFAULT_PRIVATE_KEY_DER, sizeof(DEFAULT_PRIVATE_KEY_DER), true); - privateKey_.Load(source); - publicKey_ = privateKey_; - } - -protected: - CryptoPP::AutoSeededRandomPool rng_; - CryptoPP::RSA::PrivateKey privateKey_; - CryptoPP::RSA::PublicKey publicKey_; -}; - -BOOST_FIXTURE_TEST_CASE(Decode, TestDataFixture) -{ - Block dataBlock(Data1, sizeof(Data1)); - - ndn::Data d; - BOOST_REQUIRE_NO_THROW(d.wireDecode(dataBlock)); - - BOOST_REQUIRE_EQUAL(d.getName().toUri(), "/local/ndn/prefix"); - BOOST_REQUIRE_EQUAL(d.getContentType(), static_cast(tlv::ContentType_Blob)); - BOOST_REQUIRE_EQUAL(d.getFreshnessPeriod(), time::seconds(10)); - - BOOST_REQUIRE_EQUAL(std::string(reinterpret_cast(d.getContent().value()), - d.getContent().value_size()), "SUCCESS!"); - - BOOST_REQUIRE_EQUAL(d.getSignature().getType(), static_cast(Signature::Sha256WithRsa)); - ndn::Block block = d.getSignature().getInfo(); - block.parse(); - KeyLocator keyLocator; - BOOST_REQUIRE_NO_THROW(keyLocator.wireDecode(block.get(tlv::KeyLocator))); - - BOOST_REQUIRE_EQUAL(keyLocator.getName().toUri(), "/test/key/locator"); - - using namespace CryptoPP; - RSASS::Verifier verifier(publicKey_); - bool signatureVerified = verifier.VerifyMessage(d.wireEncode().value(), - d.wireEncode().value_size() - - d.getSignature().getValue().size(), - d.getSignature().getValue().value(), - d.getSignature().getValue().value_size()); - BOOST_REQUIRE_EQUAL(signatureVerified, true); -} - -BOOST_FIXTURE_TEST_CASE(Encode, TestDataFixture) -{ - // manual data packet creation for now - - ndn::Data d(ndn::Name("/local/ndn/prefix")); - d.setContentType(tlv::ContentType_Blob); - d.setFreshnessPeriod(time::seconds(10)); - - d.setContent(Content1, sizeof(Content1)); - - Block signatureInfo(tlv::SignatureInfo); - // SignatureType - { - signatureInfo.push_back(makeNonNegativeIntegerBlock(tlv::SignatureType, Signature::Sha256WithRsa)); - } - // KeyLocator - { - KeyLocator keyLocator; - keyLocator.setName("/test/key/locator"); - - signatureInfo.push_back(keyLocator.wireEncode()); - } - signatureInfo.encode(); - - // SignatureValue - OBufferStream os; - tlv::writeVarNumber(os, tlv::SignatureValue); - - using namespace CryptoPP; - - RSASS::Signer signer(privateKey_); - - PK_MessageAccumulator *hash = signer.NewSignatureAccumulator(rng_); - hash->Update(d.getName(). wireEncode().wire(), d.getName(). wireEncode().size()); - hash->Update(d.getMetaInfo().wireEncode().wire(), d.getMetaInfo().wireEncode().size()); - hash->Update(d.getContent(). wire(), d.getContent(). size()); - hash->Update(signatureInfo. wire(), signatureInfo. size()); - - size_t length = signer.MaxSignatureLength(); - SecByteBlock buf(length); - signer.Sign(rng_, hash, buf); - - tlv::writeVarNumber(os, buf.size()); - os.write(reinterpret_cast(buf.BytePtr()), buf.size()); - - ndn::Block signatureValue(Block(os.buf())); - - Signature signature(signatureInfo, signatureValue); - - d.setSignature(signature); - - Block dataBlock; - BOOST_REQUIRE_NO_THROW(dataBlock = d.wireEncode()); - - BOOST_REQUIRE_EQUAL_COLLECTIONS(Data1, Data1+sizeof(Data1), - dataBlock.begin(), dataBlock.end()); - - std::ostringstream strStream; - BOOST_CHECK_NO_THROW(strStream << d); - - BOOST_CHECK_EQUAL(strStream.str(), - "Name: /local/ndn/prefix\n" - "MetaInfo: ContentType: 0, FreshnessPeriod: 10000 milliseconds\n" - "Content: (size: 8)\n" - "Signature: (type: 1, value_length: 128)\n"); -} - -BOOST_FIXTURE_TEST_CASE(FullName, IdentityManagementFixture) -{ - // Encoding pipeline - - ndn::Data d(ndn::Name("/local/ndn/prefix")); - d.setContentType(tlv::ContentType_Blob); - d.setFreshnessPeriod(time::seconds(10)); - - d.setContent(Content1, sizeof(Content1)); - - BOOST_CHECK_THROW(d.getFullName(), Data::Error); - - m_keyChain.sign(d); - - Name fullName; - BOOST_REQUIRE_NO_THROW(fullName = d.getFullName()); - - BOOST_CHECK_EQUAL(d.getName().hasWire(), true); - BOOST_CHECK_EQUAL(fullName.hasWire(), false); - - // check if name was properly cached - BOOST_CHECK_EQUAL(fullName.get(-1).value(), d.getFullName().get(-1).value()); - - // check FullName content - BOOST_REQUIRE_EQUAL(d.getName().size() + 1, fullName.size()); - BOOST_CHECK_EQUAL_COLLECTIONS(d.getName().begin(), d.getName().end(), - fullName.begin(), fullName.end() - 1); - BOOST_CHECK_EQUAL(fullName.get(-1).value_size(), 32); - - // FullName should be reset after the next line - d.setFreshnessPeriod(time::seconds(100)); - BOOST_CHECK_THROW(d.getFullName(), Data::Error); - - // Decoding pipeline - d.wireDecode(Block(Data1, sizeof(Data1))); - BOOST_REQUIRE_NO_THROW(fullName = d.getFullName()); - - BOOST_CHECK_EQUAL(fullName.toUri(), - "/local/ndn/prefix/" - "sha256digest=28bad4b5275bd392dbb670c75cf0b66f13f7942b21e80f55c0e86b374753a548"); -} - -BOOST_AUTO_TEST_SUITE_END() // TestData - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/encoding/block-helpers.t.cpp b/tests/unit-tests/encoding/block-helpers.t.cpp deleted file mode 100644 index c4afa4018..000000000 --- a/tests/unit-tests/encoding/block-helpers.t.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "encoding/block-helpers.hpp" -#include "name.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace encoding { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Encoding) -BOOST_AUTO_TEST_SUITE(TestBlockHelpers) - -BOOST_AUTO_TEST_CASE(NonNegativeInteger) -{ - Block b = makeNonNegativeIntegerBlock(100, 1000); - BOOST_CHECK_EQUAL(b.type(), 100); - BOOST_CHECK_GT(b.value_size(), 0); - BOOST_CHECK_EQUAL(readNonNegativeInteger(b), 1000); - - BOOST_CHECK_THROW(readNonNegativeInteger(Block()), tlv::Error); -} - -BOOST_AUTO_TEST_CASE(Empty) -{ - Block b = makeEmptyBlock(200); - BOOST_CHECK_EQUAL(b.type(), 200); - BOOST_CHECK_EQUAL(b.value_size(), 0); -} - -BOOST_AUTO_TEST_CASE(String) -{ - Block b = makeStringBlock(100, "Hello, world!"); - BOOST_CHECK_EQUAL(b.type(), 100); - BOOST_CHECK_GT(b.value_size(), 0); - BOOST_CHECK_EQUAL(readString(b), "Hello, world!"); -} - -BOOST_AUTO_TEST_CASE(Data) -{ - std::string buf1{1, 1, 1, 1}; - const uint8_t buf2[]{1, 1, 1, 1}; - std::list buf3{1, 1, 1, 1}; - - Block b1 = makeBinaryBlock(100, buf1.data(), buf1.size()); - Block b2 = makeBinaryBlock(100, buf2, sizeof(buf2)); - Block b3 = makeBinaryBlock(100, buf1.begin(), buf1.end()); // fast encoding (random access iterator) - Block b4 = makeBinaryBlock(100, buf3.begin(), buf3.end()); // slow encoding (general iterator) - - BOOST_CHECK(b1 == b2); - BOOST_CHECK(b1 == b3); - BOOST_CHECK_EQUAL(b1.type(), 100); - BOOST_CHECK_EQUAL(b1.value_size(), buf1.size()); - BOOST_CHECK_EQUAL_COLLECTIONS(b1.value_begin(), b1.value_end(), - buf2, buf2 + sizeof(buf2)); -} - -BOOST_AUTO_TEST_CASE(Nested) -{ - Name name("ndn:/Hello/World!"); - Block b1 = makeNestedBlock(100, name); - - BOOST_CHECK_EQUAL(b1.type(), 100); - b1.parse(); - BOOST_CHECK_EQUAL(b1.elements().size(), 1); - BOOST_CHECK_EQUAL(b1.elements().begin()->type(), name.wireEncode().type()); - BOOST_CHECK(*b1.elements().begin() == name.wireEncode()); -} - -BOOST_AUTO_TEST_SUITE_END() // TestBlockHelpers -BOOST_AUTO_TEST_SUITE_END() // Encoding - -} // namespace tests -} // namespace encoding -} // namespace ndn diff --git a/tests/unit-tests/encoding/block.t.cpp b/tests/unit-tests/encoding/block.t.cpp deleted file mode 100644 index 599f37c70..000000000 --- a/tests/unit-tests/encoding/block.t.cpp +++ /dev/null @@ -1,574 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "encoding/block.hpp" -#include "encoding/block-helpers.hpp" -#include "encoding/encoding-buffer.hpp" - -#include "boost-test.hpp" - -#include -#include - -namespace ndn { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Encoding) -BOOST_AUTO_TEST_SUITE(TestBlock) - -class BasicBlockFixture -{ -public: - EncodingBuffer buffer; - EncodingEstimator estimator; -}; - -BOOST_FIXTURE_TEST_SUITE(Basic, BasicBlockFixture) - -BOOST_AUTO_TEST_CASE(VarNumberOneByte1) -{ - size_t s1 = buffer.prependVarNumber(252); - size_t s2 = estimator.prependVarNumber(252); - BOOST_CHECK_EQUAL(buffer.size(), 1); - BOOST_CHECK_EQUAL(s1, 1); - BOOST_CHECK_EQUAL(s2, 1); -} - -BOOST_AUTO_TEST_CASE(VarNumberOneByte2) -{ - size_t s1 = buffer.prependVarNumber(253); - size_t s2 = estimator.prependVarNumber(253); - BOOST_CHECK_EQUAL(buffer.size(), 3); - BOOST_CHECK_EQUAL(s1, 3); - BOOST_CHECK_EQUAL(s2, 3); -} - -BOOST_AUTO_TEST_CASE(VarNumberThreeBytes1) -{ - size_t s1 = buffer.prependVarNumber(255); - size_t s2 = estimator.prependVarNumber(255); - BOOST_CHECK_EQUAL(buffer.size(), 3); - BOOST_CHECK_EQUAL(s1, 3); - BOOST_CHECK_EQUAL(s2, 3); -} - -BOOST_AUTO_TEST_CASE(VarNumberThreeBytes2) -{ - size_t s1 = buffer.prependVarNumber(65535); - size_t s2 = estimator.prependVarNumber(65535); - BOOST_CHECK_EQUAL(buffer.size(), 3); - BOOST_CHECK_EQUAL(s1, 3); - BOOST_CHECK_EQUAL(s2, 3); -} - -BOOST_AUTO_TEST_CASE(VarNumberFiveBytes1) -{ - size_t s1 = buffer.prependVarNumber(65536); - size_t s2 = estimator.prependVarNumber(65536); - BOOST_CHECK_EQUAL(buffer.size(), 5); - BOOST_CHECK_EQUAL(s1, 5); - BOOST_CHECK_EQUAL(s2, 5); -} - -BOOST_AUTO_TEST_CASE(VarNumberFiveBytes2) -{ - size_t s1 = buffer.prependVarNumber(4294967295LL); - size_t s2 = estimator.prependVarNumber(4294967295LL); - BOOST_CHECK_EQUAL(buffer.size(), 5); - BOOST_CHECK_EQUAL(s1, 5); - BOOST_CHECK_EQUAL(s2, 5); -} - -BOOST_AUTO_TEST_CASE(VarNumberNineBytes) -{ - size_t s1 = buffer.prependVarNumber(4294967296LL); - size_t s2 = estimator.prependVarNumber(4294967296LL); - BOOST_CHECK_EQUAL(buffer.size(), 9); - BOOST_CHECK_EQUAL(s1, 9); - BOOST_CHECK_EQUAL(s2, 9); -} - -BOOST_AUTO_TEST_CASE(NonNegativeNumberOneByte1) -{ - size_t s1 = buffer.prependNonNegativeInteger(252); - size_t s2 = estimator.prependNonNegativeInteger(252); - BOOST_CHECK_EQUAL(buffer.size(), 1); - BOOST_CHECK_EQUAL(s1, 1); - BOOST_CHECK_EQUAL(s2, 1); -} - -BOOST_AUTO_TEST_CASE(NonNegativeNumberOneByte2) -{ - size_t s1 = buffer.prependNonNegativeInteger(255); - size_t s2 = estimator.prependNonNegativeInteger(255); - BOOST_CHECK_EQUAL(buffer.size(), 1); - BOOST_CHECK_EQUAL(s1, 1); - BOOST_CHECK_EQUAL(s2, 1); -} - -BOOST_AUTO_TEST_CASE(NonNegativeNumberTwoBytes1) -{ - size_t s1 = buffer.prependNonNegativeInteger(256); - size_t s2 = estimator.prependNonNegativeInteger(256); - BOOST_CHECK_EQUAL(buffer.size(), 2); - BOOST_CHECK_EQUAL(s1, 2); - BOOST_CHECK_EQUAL(s2, 2); -} - -BOOST_AUTO_TEST_CASE(NonNegativeNumberTwoBytes2) -{ - size_t s1 = buffer.prependNonNegativeInteger(65535); - size_t s2 = estimator.prependNonNegativeInteger(65535); - BOOST_CHECK_EQUAL(buffer.size(), 2); - BOOST_CHECK_EQUAL(s1, 2); - BOOST_CHECK_EQUAL(s2, 2); -} - -BOOST_AUTO_TEST_CASE(NonNegativeNumberFourBytes1) -{ - size_t s1 = buffer.prependNonNegativeInteger(65536); - size_t s2 = estimator.prependNonNegativeInteger(65536); - BOOST_CHECK_EQUAL(buffer.size(), 4); - BOOST_CHECK_EQUAL(s1, 4); - BOOST_CHECK_EQUAL(s2, 4); -} - -BOOST_AUTO_TEST_CASE(NonNegativeNumberFourBytes2) -{ - size_t s1 = buffer.prependNonNegativeInteger(4294967295LL); - size_t s2 = estimator.prependNonNegativeInteger(4294967295LL); - BOOST_CHECK_EQUAL(buffer.size(), 4); - BOOST_CHECK_EQUAL(s1, 4); - BOOST_CHECK_EQUAL(s2, 4); -} - -BOOST_AUTO_TEST_CASE(NonNegativeNumberEightBytes) -{ - size_t s1 = buffer.prependNonNegativeInteger(4294967296LL); - size_t s2 = estimator.prependNonNegativeInteger(4294967296LL); - BOOST_CHECK_EQUAL(buffer.size(), 8); - BOOST_CHECK_EQUAL(s1, 8); - BOOST_CHECK_EQUAL(s2, 8); -} - -BOOST_AUTO_TEST_SUITE_END() // Basic - -BOOST_AUTO_TEST_SUITE(Construction) - -BOOST_AUTO_TEST_CASE(FromBlock) -{ - static uint8_t buffer[] = {0x80, 0x06, 0x81, 0x01, 0x01, 0x82, 0x01, 0x01}; - Block block(buffer, sizeof(buffer)); - - Block derivedBlock(block, block.begin(), block.end()); - BOOST_CHECK_EQUAL(derivedBlock.wire(), block.wire()); // pointers should match - BOOST_CHECK(derivedBlock == block); // blocks should match - - derivedBlock = Block(block, block.begin() + 2, block.begin() + 5); - BOOST_CHECK(derivedBlock.begin() == block.begin() + 2); - BOOST_CHECK(derivedBlock == Block(buffer + 2, 3)); - - Buffer otherBuffer(buffer, sizeof(buffer)); - BOOST_CHECK_THROW(Block(block, otherBuffer.begin(), block.end()), Block::Error); - BOOST_CHECK_THROW(Block(block, block.begin(), otherBuffer.end()), Block::Error); - BOOST_CHECK_THROW(Block(block, otherBuffer.begin(), otherBuffer.end()), Block::Error); -} - -BOOST_AUTO_TEST_CASE(FromBlockCopyOnWriteModifyOriginal) -{ - static uint8_t buffer[] = { - 0x05, 0x0b, 0x07, 0x03, 0x01, 0x02, 0x03, 0x0a, 0x04, 0x04, 0x05, 0x06, 0x07, - }; - - Block block1(buffer, sizeof(buffer)); - - Block block2(block1, block1.begin(), block1.end()); - auto buf2 = block2.getBuffer(); - - block1.parse(); - block1.remove(tlv::Name); - block1.encode(); - - block2.parse(); - - BOOST_CHECK_EQUAL_COLLECTIONS(block2.begin(), block2.end(), buffer, buffer + sizeof(buffer)); - BOOST_CHECK_EQUAL(buf2, block2.getBuffer()); -} - -BOOST_AUTO_TEST_CASE(FromBlockCopyOnWriteModifyCopy) -{ - static uint8_t buffer[] = { - 0x05, 0x0b, 0x07, 0x03, 0x01, 0x02, 0x03, 0x0a, 0x04, 0x04, 0x05, 0x06, 0x07, - }; - - Block block1(buffer, sizeof(buffer)); - auto buf1 = block1.getBuffer(); - - Block block2(block1, block1.begin(), block1.end()); - - block2.parse(); - block2.remove(tlv::Name); - block2.encode(); - - block1.parse(); - - BOOST_CHECK_EQUAL_COLLECTIONS(block1.begin(), block1.end(), buffer, buffer + sizeof(buffer)); - BOOST_CHECK_EQUAL(buf1, block1.getBuffer()); -} - -BOOST_AUTO_TEST_CASE(FromEncodingBuffer) -{ - uint8_t value[4]; - - EncodingBuffer buffer; - size_t length = buffer.prependByteArray(value, sizeof(value)); - buffer.prependVarNumber(length); - buffer.prependVarNumber(0xe0); - - Block block; - BOOST_REQUIRE_NO_THROW(block = buffer.block()); - BOOST_CHECK_EQUAL(block.type(), 0xe0); - BOOST_CHECK_EQUAL(block.value_size(), sizeof(value)); - - BOOST_REQUIRE_NO_THROW(block = Block(buffer)); - BOOST_CHECK_EQUAL(block.type(), 0xe0); - BOOST_CHECK_EQUAL(block.value_size(), sizeof(value)); -} - -BOOST_AUTO_TEST_CASE(ToEncodingBuffer) -{ - shared_ptr buf = make_shared(10); - for (int i = 0; i < 10; i++) - (*buf)[i] = i; - - Block block(0xab, buf); - block.encode(); - - { - BOOST_REQUIRE_NO_THROW(EncodingBuffer(block)); - EncodingBuffer buffer(block); - BOOST_CHECK_EQUAL(buffer.size(), 12); - BOOST_CHECK_EQUAL(buffer.capacity(), 12); - } - - (*buf)[1] = 0xe0; - (*buf)[2] = 2; - BOOST_REQUIRE_NO_THROW(block = Block(buf, buf->begin() + 1, buf->begin() + 5)); - BOOST_CHECK_EQUAL(block.type(), 0xe0); - - { - BOOST_REQUIRE_NO_THROW(EncodingBuffer(block)); - EncodingBuffer buffer(block); - BOOST_CHECK_EQUAL(buffer.size(), 4); - BOOST_CHECK_EQUAL(buffer.capacity(), 10); - } -} - -BOOST_AUTO_TEST_CASE(FromBuffer) -{ - const uint8_t TEST_BUFFER[] = {0x00, 0x01, 0xfa, // ok - 0x01, 0x01, 0xfb, // ok - 0x03, 0x02, 0xff}; // not ok - BufferPtr buffer(new Buffer(TEST_BUFFER, sizeof(TEST_BUFFER))); - - // using BufferPtr (avoids memory copy) - size_t offset = 0; - bool isOk = false; - Block testBlock; - std::tie(isOk, testBlock) = Block::fromBuffer(buffer, offset); - BOOST_CHECK(isOk); - BOOST_CHECK_EQUAL(testBlock.type(), 0); - BOOST_CHECK_EQUAL(testBlock.size(), 3); - BOOST_CHECK_EQUAL(testBlock.value_size(), 1); - BOOST_CHECK_EQUAL(*testBlock.wire(), 0x00); - BOOST_CHECK_EQUAL(*testBlock.value(), 0xfa); - offset += testBlock.size(); - - std::tie(isOk, testBlock) = Block::fromBuffer(buffer, offset); - BOOST_CHECK(isOk); - BOOST_CHECK_EQUAL(testBlock.type(), 1); - BOOST_CHECK_EQUAL(testBlock.size(), 3); - BOOST_CHECK_EQUAL(testBlock.value_size(), 1); - BOOST_CHECK_EQUAL(*testBlock.wire(), 0x01); - BOOST_CHECK_EQUAL(*testBlock.value(), 0xfb); - offset += testBlock.size(); - - std::tie(isOk, testBlock) = Block::fromBuffer(buffer, offset); - BOOST_CHECK(!isOk); - - // just buffer, copies memory - offset = 0; - std::tie(isOk, testBlock) = Block::fromBuffer(TEST_BUFFER + offset, - sizeof(TEST_BUFFER) - offset); - BOOST_CHECK(isOk); - BOOST_CHECK_EQUAL(testBlock.type(), 0); - BOOST_CHECK_EQUAL(testBlock.size(), 3); - BOOST_CHECK_EQUAL(testBlock.value_size(), 1); - BOOST_CHECK_EQUAL(*testBlock.wire(), 0x00); - BOOST_CHECK_EQUAL(*testBlock.value(), 0xfa); - offset += testBlock.size(); - - std::tie(isOk, testBlock) = Block::fromBuffer(TEST_BUFFER + offset, - sizeof(TEST_BUFFER) - offset); - BOOST_CHECK(isOk); - BOOST_CHECK_EQUAL(testBlock.type(), 1); - BOOST_CHECK_EQUAL(testBlock.size(), 3); - BOOST_CHECK_EQUAL(testBlock.value_size(), 1); - BOOST_CHECK_EQUAL(*testBlock.wire(), 0x01); - BOOST_CHECK_EQUAL(*testBlock.value(), 0xfb); - offset += testBlock.size(); - - std::tie(isOk, testBlock) = Block::fromBuffer(TEST_BUFFER + offset, - sizeof(TEST_BUFFER) - offset); - BOOST_CHECK(!isOk); -} - -BOOST_AUTO_TEST_CASE(FromStream) -{ - const uint8_t TEST_BUFFER[] = {0x00, 0x01, 0xfa, // ok - 0x01, 0x01, 0xfb, // ok - 0x03, 0x02, 0xff}; // not ok - - typedef boost::iostreams::stream ArrayStream; - ArrayStream stream(reinterpret_cast(TEST_BUFFER), sizeof(TEST_BUFFER)); - - Block testBlock; - BOOST_REQUIRE_NO_THROW(testBlock = Block::fromStream(stream)); - BOOST_CHECK_EQUAL(testBlock.type(), 0); - BOOST_CHECK_EQUAL(testBlock.size(), 3); - BOOST_CHECK_EQUAL(testBlock.value_size(), 1); - BOOST_CHECK_EQUAL(*testBlock.wire(), 0x00); - BOOST_CHECK_EQUAL(*testBlock.value(), 0xfa); - - BOOST_REQUIRE_NO_THROW(testBlock = Block::fromStream(stream)); - BOOST_CHECK_EQUAL(testBlock.type(), 1); - BOOST_CHECK_EQUAL(testBlock.size(), 3); - BOOST_CHECK_EQUAL(testBlock.value_size(), 1); - BOOST_CHECK_EQUAL(*testBlock.wire(), 0x01); - BOOST_CHECK_EQUAL(*testBlock.value(), 0xfb); - - BOOST_CHECK_THROW(Block::fromStream(stream), tlv::Error); -} - -BOOST_AUTO_TEST_CASE(FromStreamWhitespace) // Bug 2728 -{ - uint8_t PACKET[] = { - 0x06, 0x20, // Data - 0x07, 0x11, // Name - 0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, // NameComponent 'hello' - 0x08, 0x01, 0x31, // NameComponent '1' - 0x08, 0x05, 0x77, 0x6f, 0x72, 0x6c, 0x64, // NameComponent 'world' - 0x14, 0x00, // MetaInfo empty - 0x15, 0x00, // Content empty - 0x16, 0x05, // SignatureInfo - 0x1b, 0x01, 0x01, // SignatureType RSA - 0x1c, 0x00, // KeyLocator empty - 0x17, 0x00 // SignatureValue empty - }; - // TLV-LENGTH of is 0x20 which happens to be ASCII whitespace - - std::stringstream stream; - stream.write(reinterpret_cast(PACKET), sizeof(PACKET)); - stream.seekg(0); - - Block block = Block::fromStream(stream); - BOOST_CHECK_NO_THROW(block.parse()); -} - -BOOST_AUTO_TEST_CASE(FromStreamZeroLength) // Bug 2729 -{ - uint8_t BUFFER[] = { 0x07, 0x00 }; // TLV-LENGTH is zero - - std::stringstream stream; - stream.write(reinterpret_cast(BUFFER), sizeof(BUFFER)); - stream.seekg(0); - - Block block; - BOOST_CHECK_NO_THROW(block = Block::fromStream(stream)); - BOOST_CHECK_EQUAL(block.type(), 0x07); - BOOST_CHECK_EQUAL(block.value_size(), 0); -} - -BOOST_AUTO_TEST_SUITE_END() // Construction - -BOOST_AUTO_TEST_CASE(Equality) -{ - BOOST_CONCEPT_ASSERT((boost::EqualityComparable)); - - Block a("\x08\x00", 2); - Block b("\x08\x00", 2);; - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - Block c("\x06\x00", 2); - Block d("\x08\x00", 2);; - BOOST_CHECK_EQUAL(c == d, false); - BOOST_CHECK_EQUAL(c != d, true); - - Block e("\x06\x00", 2); - Block f("\x06\x01\xcc", 3);; - BOOST_CHECK_EQUAL(e == f, false); - BOOST_CHECK_EQUAL(e != f, true); -} - -BOOST_AUTO_TEST_CASE(InsertBeginning) -{ - Block masterBlock(tlv::Name); - Block firstBlock = makeStringBlock(tlv::NameComponent, "firstName"); - Block secondBlock = makeStringBlock(tlv::NameComponent, "secondName"); - Block thirdBlock = makeStringBlock(tlv::NameComponent, "thirdName"); - - BOOST_CHECK_EQUAL(masterBlock.elements_size(), 0); - masterBlock.push_back(secondBlock); - masterBlock.push_back(thirdBlock); - BOOST_CHECK_EQUAL(masterBlock.elements_size(), 2); - Block::element_const_iterator it = masterBlock.find(tlv::NameComponent); - BOOST_CHECK_EQUAL(*it == secondBlock, true); - - it = masterBlock.insert(it, firstBlock); - - BOOST_CHECK_EQUAL(masterBlock.elements_size(), 3); - BOOST_CHECK_EQUAL(*(it + 1) == secondBlock, true); - BOOST_CHECK_EQUAL(*(masterBlock.elements_begin()) == firstBlock, true); -} - -BOOST_AUTO_TEST_CASE(InsertEnd) -{ - Block masterBlock(tlv::Name); - Block firstBlock = makeStringBlock(tlv::NameComponent, "firstName"); - Block secondBlock = makeStringBlock(tlv::NameComponent, "secondName"); - Block thirdBlock = makeStringBlock(tlv::NameComponent, "thirdName"); - - BOOST_CHECK_EQUAL(masterBlock.elements_size(), 0); - masterBlock.push_back(firstBlock); - masterBlock.push_back(secondBlock); - BOOST_CHECK_EQUAL(masterBlock.elements_size(), 2); - Block::element_const_iterator it = masterBlock.elements_end(); - BOOST_CHECK_EQUAL(*(it - 1) == secondBlock, true); - - it = masterBlock.insert(it, thirdBlock); - - BOOST_CHECK_EQUAL(masterBlock.elements_size(), 3); - BOOST_CHECK_EQUAL(*(it - 1) == secondBlock, true); - BOOST_CHECK_EQUAL(*(masterBlock.elements_end() - 1) == thirdBlock, true); -} - -BOOST_AUTO_TEST_CASE(InsertMiddle) -{ - Block masterBlock(tlv::Name); - Block firstBlock = makeStringBlock(tlv::NameComponent, "firstName"); - Block secondBlock = makeStringBlock(tlv::NameComponent, "secondName"); - Block thirdBlock = makeStringBlock(tlv::NameComponent, "thirdName"); - - BOOST_CHECK_EQUAL(masterBlock.elements_size(), 0); - masterBlock.push_back(firstBlock); - masterBlock.push_back(thirdBlock); - BOOST_CHECK_EQUAL(masterBlock.elements_size(), 2); - Block::element_const_iterator it = masterBlock.find(tlv::NameComponent); - BOOST_CHECK_EQUAL(*it == firstBlock, true); - - it = masterBlock.insert(it+1, secondBlock); - - BOOST_CHECK_EQUAL(*it == secondBlock, true); - BOOST_CHECK_EQUAL(*(it + 1) == thirdBlock, true); - BOOST_CHECK_EQUAL(*(it - 1) == firstBlock, true); -} - -BOOST_AUTO_TEST_CASE(EraseSingleElement) -{ - Block masterBlock(tlv::Name); - Block firstBlock = makeStringBlock(tlv::NameComponent, "firstName"); - Block secondBlock = makeStringBlock(tlv::NameComponent, "secondName"); - Block thirdBlock = makeStringBlock(tlv::NameComponent, "thirdName"); - - BOOST_CHECK_EQUAL(masterBlock.elements_size(), 0); - masterBlock.push_back(firstBlock); - masterBlock.push_back(secondBlock); - masterBlock.push_back(thirdBlock); - BOOST_CHECK_EQUAL(masterBlock.elements_size(), 3); - Block::element_const_iterator it = masterBlock.find(tlv::NameComponent); - it++; - BOOST_CHECK_EQUAL(*it == secondBlock, true); - - it = masterBlock.erase(it); - - BOOST_CHECK_EQUAL(masterBlock.elements_size(), 2); - BOOST_CHECK_EQUAL(*(it) == thirdBlock, true); - BOOST_CHECK_EQUAL(*(it - 1) == firstBlock, true); -} - -BOOST_AUTO_TEST_CASE(EraseRange) -{ - Block masterBlock(tlv::Name); - Block firstBlock = makeStringBlock(tlv::NameComponent, "firstName"); - Block secondBlock = makeStringBlock(tlv::NameComponent, "secondName"); - Block thirdBlock = makeStringBlock(tlv::NameComponent, "thirdName"); - Block fourthBlock = makeStringBlock(tlv::NameComponent, "fourthName"); - Block fifthBlock = makeStringBlock(tlv::NameComponent, "fifthName"); - Block sixthBlock = makeStringBlock(tlv::NameComponent, "sixthName"); - - BOOST_CHECK_EQUAL(masterBlock.elements_size(), 0); - masterBlock.push_back(firstBlock); - masterBlock.push_back(secondBlock); - masterBlock.push_back(thirdBlock); - masterBlock.push_back(fourthBlock); - masterBlock.push_back(fifthBlock); - masterBlock.push_back(sixthBlock); - BOOST_CHECK_EQUAL(masterBlock.elements_size(), 6); - Block::element_const_iterator itStart = masterBlock.find(tlv::NameComponent); - itStart++; - Block::element_const_iterator itEnd = itStart + 3; - BOOST_CHECK_EQUAL(*itStart == secondBlock, true); - BOOST_CHECK_EQUAL(*itEnd == fifthBlock, true); - - Block::element_const_iterator newIt = masterBlock.erase(itStart, itEnd); - - BOOST_CHECK_EQUAL(masterBlock.elements_size(), 3); - BOOST_CHECK_EQUAL(*(newIt) == fifthBlock, true); - BOOST_CHECK_EQUAL(*(newIt - 1) == firstBlock, true); -} - -BOOST_AUTO_TEST_CASE(Remove) -{ - Block block(tlv::Data); - block.push_back(makeNonNegativeIntegerBlock(tlv::ContentType, 0)); - block.push_back(makeNonNegativeIntegerBlock(tlv::FreshnessPeriod, 123)); - block.push_back(makeStringBlock(tlv::Name, "ndn:/test-prefix")); - block.push_back(makeNonNegativeIntegerBlock(tlv::ContentType, 2)); - block.push_back(makeNonNegativeIntegerBlock(tlv::ContentType, 1)); - - BOOST_CHECK_EQUAL(5, block.elements_size()); - BOOST_REQUIRE_NO_THROW(block.remove(tlv::ContentType)); - BOOST_CHECK_EQUAL(2, block.elements_size()); - - Block::element_container elements = block.elements(); - - BOOST_CHECK_EQUAL(tlv::FreshnessPeriod, elements[0].type()); - BOOST_CHECK_EQUAL(123, readNonNegativeInteger(elements[0])); - BOOST_CHECK_EQUAL(tlv::Name, elements[1].type()); - BOOST_CHECK(readString(elements[1]).compare("ndn:/test-prefix") == 0); -} - -BOOST_AUTO_TEST_SUITE_END() // TestBlock -BOOST_AUTO_TEST_SUITE_END() // Encoding - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/encoding/nfd-constants.t.cpp b/tests/unit-tests/encoding/nfd-constants.t.cpp deleted file mode 100644 index 61463074f..000000000 --- a/tests/unit-tests/encoding/nfd-constants.t.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "encoding/nfd-constants.hpp" - -#include "boost-test.hpp" -#include - -namespace ndn { -namespace nfd { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Encoding) -BOOST_AUTO_TEST_SUITE(TestNfdConstants) - -BOOST_AUTO_TEST_CASE(FaceScopeOutputStream) -{ - BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_SCOPE_NONE), "none"); - BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_SCOPE_NON_LOCAL), "non-local"); - BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_SCOPE_LOCAL), "local"); - BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(126)), "126"); -} - -BOOST_AUTO_TEST_CASE(FacePersistencyOutputStream) -{ - BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_PERSISTENCY_NONE), "none"); - BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_PERSISTENCY_ON_DEMAND), "on-demand"); - BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_PERSISTENCY_PERSISTENT), "persistent"); - BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_PERSISTENCY_PERMANENT), "permanent"); - BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(110)), "110"); -} - -BOOST_AUTO_TEST_CASE(LinkTypeOutputStream) -{ - BOOST_CHECK_EQUAL(boost::lexical_cast(LINK_TYPE_NONE), "none"); - BOOST_CHECK_EQUAL(boost::lexical_cast(LINK_TYPE_POINT_TO_POINT), "point-to-point"); - BOOST_CHECK_EQUAL(boost::lexical_cast(LINK_TYPE_MULTI_ACCESS), "multi-access"); - BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(104)), "104"); -} - -BOOST_AUTO_TEST_CASE(RouteOriginOutputStream) -{ - BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_ORIGIN_NONE), "none"); - BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_ORIGIN_APP), "app"); - BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_ORIGIN_AUTOREG), "autoreg"); - BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_ORIGIN_CLIENT), "client"); - BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_ORIGIN_AUTOCONF), "autoconf"); - BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_ORIGIN_NLSR), "nlsr"); - BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_ORIGIN_STATIC), "static"); - BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(27)), "27"); -} - -BOOST_AUTO_TEST_CASE(RouteFlagsOutputStream) -{ - BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_FLAGS_NONE), "none"); - BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_FLAG_CHILD_INHERIT), "child-inherit"); - BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_FLAG_CAPTURE), "capture"); - BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast( - ROUTE_FLAG_CHILD_INHERIT | ROUTE_FLAG_CAPTURE)), - "child-inherit|capture"); - BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast( - ROUTE_FLAG_CAPTURE | static_cast(0x9c))), - "capture|0x9c"); -} - -BOOST_AUTO_TEST_SUITE_END() // TestNfdConstants -BOOST_AUTO_TEST_SUITE_END() // Encoding - -} // namespace tests -} // namespace nfd -} // namespace ndn diff --git a/tests/unit-tests/encoding/tlv.t.cpp b/tests/unit-tests/encoding/tlv.t.cpp deleted file mode 100644 index 635aecf81..000000000 --- a/tests/unit-tests/encoding/tlv.t.cpp +++ /dev/null @@ -1,409 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "encoding/tlv.hpp" - -#include "boost-test.hpp" - -#include -#include - -namespace ndn { -namespace tlv { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Encoding) -BOOST_AUTO_TEST_SUITE(TestTlv) - -using ArrayStream = boost::iostreams::stream; -using Iterator = std::istream_iterator; - -BOOST_AUTO_TEST_SUITE(VarNumber) - -static const uint8_t BUFFER[] = { - 0x01, // == 1 - 0xfc, // == 252 - 0xfd, 0x00, 0xfd, // == 253 - 0xfe, 0x00, 0x01, 0x00, 0x00, // == 65536 - 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 // == 4294967296LL -}; - -BOOST_AUTO_TEST_CASE(SizeOf) -{ - BOOST_CHECK_EQUAL(sizeOfVarNumber(1), 1); - BOOST_CHECK_EQUAL(sizeOfVarNumber(252), 1); - BOOST_CHECK_EQUAL(sizeOfVarNumber(253), 3); - BOOST_CHECK_EQUAL(sizeOfVarNumber(65536), 5); - BOOST_CHECK_EQUAL(sizeOfVarNumber(4294967296LL), 9); -} - -BOOST_AUTO_TEST_CASE(Write) -{ - std::ostringstream os; - - writeVarNumber(os, 1); - writeVarNumber(os, 252); - writeVarNumber(os, 253); - writeVarNumber(os, 65536); - writeVarNumber(os, 4294967296LL); - - std::string buffer = os.str(); - const uint8_t* actual = reinterpret_cast(buffer.c_str()); - - BOOST_CHECK_EQUAL(buffer.size(), sizeof(BUFFER)); - BOOST_CHECK_EQUAL_COLLECTIONS(BUFFER, BUFFER + sizeof(BUFFER), - actual, actual + sizeof(BUFFER)); -} - -BOOST_AUTO_TEST_CASE(ReadFromBuffer) -{ - const uint8_t* begin; - uint64_t value; - - begin = BUFFER; - BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), true); - begin = BUFFER; - BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 1)); - BOOST_CHECK_EQUAL(value, 1); - - begin = BUFFER + 1; - BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), true); - begin = BUFFER + 1; - BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 1)); - BOOST_CHECK_EQUAL(value, 252); - - begin = BUFFER + 2; - BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), false); - begin = BUFFER + 2; - BOOST_CHECK_THROW(readVarNumber(begin, begin + 1), Error); - - begin = BUFFER + 2; - BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 2, value), false); - begin = BUFFER + 2; - BOOST_CHECK_THROW(readVarNumber(begin, begin + 2), Error); - - begin = BUFFER + 2; - BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 3, value), true); - begin = BUFFER + 2; - BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 3)); - BOOST_CHECK_EQUAL(value, 253); - - - begin = BUFFER + 5; - BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), false); - begin = BUFFER + 5; - BOOST_CHECK_THROW(readVarNumber(begin, begin + 1), Error); - - begin = BUFFER + 5; - BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 4, value), false); - begin = BUFFER + 5; - BOOST_CHECK_THROW(readVarNumber(begin, begin + 4), Error); - - begin = BUFFER + 5; - BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 5, value), true); - begin = BUFFER + 5; - BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 5)); - BOOST_CHECK_EQUAL(value, 65536); - - begin = BUFFER + 10; - BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), false); - begin = BUFFER + 10; - BOOST_CHECK_THROW(readVarNumber(begin, begin + 1), Error); - - begin = BUFFER + 10; - BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 8, value), false); - begin = BUFFER + 10; - BOOST_CHECK_THROW(readVarNumber(begin, begin + 8), Error); - - begin = BUFFER + 10; - BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 9, value), true); - begin = BUFFER + 10; - BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 9)); - BOOST_CHECK_EQUAL(value, 4294967296LL); -} - -BOOST_AUTO_TEST_CASE(ReadFromStream) -{ - Iterator end; // end of stream - uint64_t value; - { - ArrayStream stream(reinterpret_cast(BUFFER), 1); - Iterator begin(stream); - BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true); - } - { - ArrayStream stream(reinterpret_cast(BUFFER), 1); - Iterator begin(stream); - BOOST_CHECK_NO_THROW(readVarNumber(begin, end)); - BOOST_CHECK_EQUAL(value, 1); - } - - { - ArrayStream stream(reinterpret_cast(BUFFER) + 1, 1); - Iterator begin(stream); - BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true); - } - { - ArrayStream stream(reinterpret_cast(BUFFER) + 1, 1); - Iterator begin(stream); - BOOST_CHECK_NO_THROW(readVarNumber(begin, end)); - BOOST_CHECK_EQUAL(value, 252); - } - - { - ArrayStream stream(reinterpret_cast(BUFFER) + 2, 1); - Iterator begin(stream); - BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false); - } - { - ArrayStream stream(reinterpret_cast(BUFFER) + 2, 1); - Iterator begin(stream); - BOOST_CHECK_THROW(readVarNumber(begin, end), Error); - } - - { - ArrayStream stream(reinterpret_cast(BUFFER) + 2, 2); - Iterator begin(stream); - BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false); - } - { - ArrayStream stream(reinterpret_cast(BUFFER) + 2, 2); - Iterator begin(stream); - BOOST_CHECK_THROW(readVarNumber(begin, end), Error); - } - - { - ArrayStream stream(reinterpret_cast(BUFFER) + 2, 3); - Iterator begin(stream); - BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true); - } - { - ArrayStream stream(reinterpret_cast(BUFFER) + 2, 3); - Iterator begin(stream); - BOOST_CHECK_NO_THROW(readVarNumber(begin, end)); - BOOST_CHECK_EQUAL(value, 253); - } - - { - ArrayStream stream(reinterpret_cast(BUFFER) + 5, 1); - Iterator begin(stream); - BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false); - } - { - ArrayStream stream(reinterpret_cast(BUFFER) + 5, 1); - Iterator begin(stream); - BOOST_CHECK_THROW(readVarNumber(begin, end), Error); - } - - { - ArrayStream stream(reinterpret_cast(BUFFER) + 5, 4); - Iterator begin(stream); - BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false); - } - { - ArrayStream stream(reinterpret_cast(BUFFER) + 5, 4); - Iterator begin(stream); - BOOST_CHECK_THROW(readVarNumber(begin, end), Error); - } - - { - ArrayStream stream(reinterpret_cast(BUFFER) + 5, 5); - Iterator begin(stream); - BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true); - } - { - ArrayStream stream(reinterpret_cast(BUFFER) + 5, 5); - Iterator begin(stream); - BOOST_CHECK_NO_THROW(readVarNumber(begin, end)); - BOOST_CHECK_EQUAL(value, 65536); - } - - { - ArrayStream stream(reinterpret_cast(BUFFER) + 10, 1); - Iterator begin(stream); - BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false); - } - { - ArrayStream stream(reinterpret_cast(BUFFER) + 10, 1); - Iterator begin(stream); - BOOST_CHECK_THROW(readVarNumber(begin, end), Error); - } - - { - ArrayStream stream(reinterpret_cast(BUFFER) + 10, 8); - Iterator begin(stream); - BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false); - } - { - ArrayStream stream(reinterpret_cast(BUFFER) + 10, 8); - Iterator begin(stream); - BOOST_CHECK_THROW(readVarNumber(begin, end), Error); - } - - { - ArrayStream stream(reinterpret_cast(BUFFER) + 10, 9); - Iterator begin(stream); - BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true); - } - { - ArrayStream stream(reinterpret_cast(BUFFER) + 10, 9); - Iterator begin(stream); - BOOST_CHECK_NO_THROW(readVarNumber(begin, end)); - BOOST_CHECK_EQUAL(value, 4294967296LL); - } -} - -BOOST_AUTO_TEST_SUITE_END() // VarNumber - -BOOST_AUTO_TEST_SUITE(NonNegativeInteger) - -static const uint8_t BUFFER[] = { - 0x01, // 1 - 0x01, 0x01, // 257 - 0x01, 0x01, 0x01, 0x01, // 16843009LL - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 // 72340172838076673LL -}; - -BOOST_AUTO_TEST_CASE(SizeOf) -{ - BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(1), 1); - BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(252), 1); - BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(253), 2); - BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(257), 2); - BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(65536), 4); - BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(16843009LL), 4); - BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(4294967296LL), 8); - BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(72340172838076673LL), 8); -} - -BOOST_AUTO_TEST_CASE(Write) -{ - std::ostringstream os; - - writeNonNegativeInteger(os, 1); - writeNonNegativeInteger(os, 257); - writeNonNegativeInteger(os, 16843009LL); - writeNonNegativeInteger(os, 72340172838076673LL); - - std::string buffer = os.str(); - const uint8_t* actual = reinterpret_cast(buffer.c_str()); - - BOOST_CHECK_EQUAL(buffer.size(), sizeof(BUFFER)); - BOOST_CHECK_EQUAL_COLLECTIONS(BUFFER, BUFFER + sizeof(BUFFER), - actual, actual + sizeof(BUFFER)); -} - -BOOST_AUTO_TEST_CASE(ReadFromBuffer) -{ - const uint8_t* begin; - uint64_t value; - - begin = BUFFER; - BOOST_CHECK_THROW(value = readNonNegativeInteger(1, begin, begin + 0), Error); - BOOST_CHECK_NO_THROW(value = readNonNegativeInteger(1, begin, begin + 1)); - BOOST_CHECK_EQUAL(value, 1); - - begin = BUFFER + 1; - BOOST_CHECK_THROW(value = readNonNegativeInteger(2, begin, begin + 1), Error); - BOOST_CHECK_NO_THROW(value = readNonNegativeInteger(2, begin, begin + 2)); - BOOST_CHECK_EQUAL(value, 257); - - begin = BUFFER + 3; - BOOST_CHECK_THROW(value = readNonNegativeInteger(4, begin, begin + 3), Error); - BOOST_CHECK_NO_THROW(value = readNonNegativeInteger(4, begin, begin + 4)); - BOOST_CHECK_EQUAL(value, 16843009LL); - - begin = BUFFER + 7; - BOOST_CHECK_THROW(value = readNonNegativeInteger(8, begin, begin + 7), Error); - BOOST_CHECK_NO_THROW(value = readNonNegativeInteger(8, begin, begin + 8)); - BOOST_CHECK_EQUAL(value, 72340172838076673LL); - - begin = BUFFER; - BOOST_CHECK_THROW(value = readNonNegativeInteger(3, begin, begin + 3), Error); -} - -BOOST_AUTO_TEST_CASE(ReadFromStream) -{ - Iterator end; // end of stream - uint64_t value; - { - ArrayStream stream(reinterpret_cast(BUFFER), 0); - Iterator begin(stream); - BOOST_CHECK_THROW(value = readNonNegativeInteger(1, begin, end), Error); - } - { - ArrayStream stream(reinterpret_cast(BUFFER), 1); - Iterator begin(stream); - BOOST_CHECK_NO_THROW(value = readNonNegativeInteger(1, begin, end)); - BOOST_CHECK_EQUAL(value, 1); - } - - { - ArrayStream stream(reinterpret_cast(BUFFER + 1), 1); - Iterator begin(stream); - BOOST_CHECK_THROW(value = readNonNegativeInteger(2, begin, end), Error); - } - { - ArrayStream stream(reinterpret_cast(BUFFER + 1), 2); - Iterator begin(stream); - BOOST_CHECK_NO_THROW(value = readNonNegativeInteger(2, begin, end)); - BOOST_CHECK_EQUAL(value, 257); - } - - { - ArrayStream stream(reinterpret_cast(BUFFER + 3), 3); - Iterator begin(stream); - BOOST_CHECK_THROW(value = readNonNegativeInteger(4, begin, end), Error); - } - { - ArrayStream stream(reinterpret_cast(BUFFER + 3), 4); - Iterator begin(stream); - BOOST_CHECK_NO_THROW(value = readNonNegativeInteger(4, begin, end)); - BOOST_CHECK_EQUAL(value, 16843009LL); - } - - { - ArrayStream stream(reinterpret_cast(BUFFER + 7), 7); - Iterator begin(stream); - BOOST_CHECK_THROW(value = readNonNegativeInteger(8, begin, end), Error); - } - { - ArrayStream stream(reinterpret_cast(BUFFER + 7), 8); - Iterator begin(stream); - BOOST_CHECK_NO_THROW(value = readNonNegativeInteger(8, begin, end)); - BOOST_CHECK_EQUAL(value, 72340172838076673LL); - } - - { - ArrayStream stream(reinterpret_cast(BUFFER), 3); - Iterator begin(stream); - BOOST_CHECK_THROW(value = readNonNegativeInteger(3, begin, end), Error); - } -} - -BOOST_AUTO_TEST_SUITE_END() // NonNegativeInteger - -BOOST_AUTO_TEST_SUITE_END() // TestTlv -BOOST_AUTO_TEST_SUITE_END() // Encoding - -} // namespace tests -} // namespace tlv -} // namespace ndn diff --git a/tests/unit-tests/exclude.t.cpp b/tests/unit-tests/exclude.t.cpp deleted file mode 100644 index 1e074d54f..000000000 --- a/tests/unit-tests/exclude.t.cpp +++ /dev/null @@ -1,568 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "exclude.hpp" -#include "util/crypto.hpp" - -#include "boost-test.hpp" - -#include - -namespace ndn { -namespace tests { - -BOOST_AUTO_TEST_SUITE(TestExclude) - -BOOST_AUTO_TEST_SUITE(GenericComponent) // exclude generic NameComponent - -BOOST_AUTO_TEST_CASE(One) -{ - Exclude e; - std::vector enumerated; - - e.excludeOne(name::Component("b")); - BOOST_CHECK_EQUAL(e.toUri(), "b"); - BOOST_CHECK_EQUAL(e.size(), 1); - enumerated.clear(); - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 1); - BOOST_CHECK_EQUAL(enumerated[0].isSingular(), true); - BOOST_CHECK_EQUAL(enumerated[0].from, name::Component("b")); - - e.excludeOne(name::Component("d")); - BOOST_CHECK_EQUAL(e.toUri(), "b,d"); - BOOST_CHECK_EQUAL(e.size(), 2); - enumerated.clear(); - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 2); - BOOST_CHECK_EQUAL(enumerated[0].isSingular(), true); - BOOST_CHECK_EQUAL(enumerated[0].from, name::Component("b")); - BOOST_CHECK_EQUAL(enumerated[1].isSingular(), true); - BOOST_CHECK_EQUAL(enumerated[1].from, name::Component("d")); - - e.excludeOne(name::Component("a")); - BOOST_CHECK_EQUAL(e.toUri(), "a,b,d"); - BOOST_CHECK_EQUAL(e.size(), 3); - enumerated.clear(); - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 3); - BOOST_CHECK_EQUAL(enumerated[0].isSingular(), true); - BOOST_CHECK_EQUAL(enumerated[0].from, name::Component("a")); - BOOST_CHECK_EQUAL(enumerated[1].isSingular(), true); - BOOST_CHECK_EQUAL(enumerated[1].from, name::Component("b")); - BOOST_CHECK_EQUAL(enumerated[2].isSingular(), true); - BOOST_CHECK_EQUAL(enumerated[2].from, name::Component("d")); - - e.excludeOne(name::Component("aa")); - BOOST_CHECK_EQUAL(e.toUri(), "a,b,d,aa"); - BOOST_CHECK_EQUAL(e.size(), 4); - - e.excludeOne(name::Component("cc")); - BOOST_CHECK_EQUAL(e.toUri(), "a,b,d,aa,cc"); - BOOST_CHECK_EQUAL(e.size(), 5); - - e.excludeOne(name::Component("c")); - BOOST_CHECK_EQUAL(e.toUri(), "a,b,c,d,aa,cc"); - BOOST_CHECK_EQUAL(e.size(), 6); -} - -BOOST_AUTO_TEST_CASE(Before) -{ - // based on http://redmine.named-data.net/issues/1158 - ndn::Exclude e; - BOOST_REQUIRE_NO_THROW(e.excludeBefore(name::Component("PuQxMaf91"))); - - BOOST_CHECK_EQUAL(e.toUri(), "*,PuQxMaf91"); -} - -BOOST_AUTO_TEST_CASE(Ranges) -{ - // example: ANY /b /d ANY /f - - Exclude e; - std::vector enumerated; - - e.excludeOne(name::Component("b0")); - BOOST_CHECK_EQUAL(e.toUri(), "b0"); - BOOST_CHECK_EQUAL(e.size(), 1); - enumerated.clear(); - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 1); - BOOST_CHECK_EQUAL(enumerated[0].isSingular(), true); - BOOST_CHECK_EQUAL(enumerated[0].from, name::Component("b0")); - BOOST_CHECK_EQUAL(boost::lexical_cast(enumerated[0]), "{b0}"); - BOOST_CHECK_EQUAL(enumerated[0], (Exclude::Range{false, name::Component("b0"), false, name::Component("b0")})); - BOOST_CHECK_NE(enumerated[0], (Exclude::Range{false, name::Component("b0"), false, name::Component("b1")})); - - e.excludeBefore(name::Component("b1")); - BOOST_CHECK_EQUAL(e.toUri(), "*,b1"); - BOOST_CHECK_EQUAL(e.size(), 1); - enumerated.clear(); - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 1); - BOOST_CHECK_EQUAL(enumerated[0].fromInfinity, true); - BOOST_CHECK_EQUAL(enumerated[0].toInfinity, false); - BOOST_CHECK_EQUAL(enumerated[0].to, name::Component("b1")); - - e.excludeBefore(name::Component("c0")); - BOOST_CHECK_EQUAL(e.toUri(), "*,c0"); - BOOST_CHECK_EQUAL(e.size(), 1); - enumerated.clear(); - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 1); - BOOST_CHECK_EQUAL(enumerated[0].fromInfinity, true); - BOOST_CHECK_EQUAL(enumerated[0].toInfinity, false); - BOOST_CHECK_EQUAL(enumerated[0].to, name::Component("c0")); - - e.excludeRange(name::Component("a0"), name::Component("c0")); - BOOST_CHECK_EQUAL(e.toUri(), "*,c0"); - BOOST_CHECK_EQUAL(e.size(), 1); - enumerated.clear(); - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 1); - BOOST_CHECK_EQUAL(enumerated[0].fromInfinity, true); - BOOST_CHECK_EQUAL(enumerated[0].toInfinity, false); - BOOST_CHECK_EQUAL(enumerated[0].to, name::Component("c0")); - - e.excludeRange(name::Component("d0"), name::Component("e0")); - BOOST_CHECK_EQUAL(e.toUri(), "*,c0,d0,*,e0"); - BOOST_CHECK_EQUAL(e.size(), 2); - enumerated.clear(); - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 2); - BOOST_CHECK_EQUAL(enumerated[0].fromInfinity, true); - BOOST_CHECK_EQUAL(enumerated[0].toInfinity, false); - BOOST_CHECK_EQUAL(enumerated[0].to, name::Component("c0")); - BOOST_CHECK_EQUAL(enumerated[1].fromInfinity, false); - BOOST_CHECK_EQUAL(enumerated[1].from, name::Component("d0")); - BOOST_CHECK_EQUAL(enumerated[1].toInfinity, false); - BOOST_CHECK_EQUAL(enumerated[1].to, name::Component("e0")); - - e.excludeRange(name::Component("c1"), name::Component("d1")); - BOOST_CHECK_EQUAL(e.toUri(), "*,c0,c1,*,e0"); - BOOST_CHECK_EQUAL(e.size(), 2); - enumerated.clear(); - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 2); - BOOST_CHECK_EQUAL(enumerated[0].fromInfinity, true); - BOOST_CHECK_EQUAL(enumerated[0].toInfinity, false); - BOOST_CHECK_EQUAL(enumerated[0].to, name::Component("c0")); - BOOST_CHECK_EQUAL(enumerated[1].fromInfinity, false); - BOOST_CHECK_EQUAL(enumerated[1].from, name::Component("c1")); - BOOST_CHECK_EQUAL(enumerated[1].toInfinity, false); - BOOST_CHECK_EQUAL(enumerated[1].to, name::Component("e0")); - - e.excludeRange(name::Component("a1"), name::Component("d1")); - BOOST_CHECK_EQUAL(e.toUri(), "*,e0"); - BOOST_CHECK_EQUAL(e.size(), 1); - enumerated.clear(); - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 1); - BOOST_CHECK_EQUAL(enumerated[0].fromInfinity, true); - BOOST_CHECK_EQUAL(enumerated[0].toInfinity, false); - BOOST_CHECK_EQUAL(enumerated[0].to, name::Component("e0")); - - e.excludeBefore(name::Component("e2")); - BOOST_CHECK_EQUAL(e.toUri(), "*,e2"); - BOOST_CHECK_EQUAL(e.size(), 1); - enumerated.clear(); - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 1); - BOOST_CHECK_EQUAL(enumerated[0].fromInfinity, true); - BOOST_CHECK_EQUAL(enumerated[0].toInfinity, false); - BOOST_CHECK_EQUAL(enumerated[0].to, name::Component("e2")); - - e.excludeAfter(name::Component("f0")); - BOOST_CHECK_EQUAL(e.toUri(), "*,e2,f0,*"); - BOOST_CHECK_EQUAL(e.size(), 2); - enumerated.clear(); - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 2); - BOOST_CHECK_EQUAL(enumerated[0].fromInfinity, true); - BOOST_CHECK_EQUAL(enumerated[0].toInfinity, false); - BOOST_CHECK_EQUAL(enumerated[0].to, name::Component("e2")); - BOOST_CHECK_EQUAL(boost::lexical_cast(enumerated[0]), "(-∞,e2]"); - BOOST_CHECK_EQUAL(enumerated[0], (Exclude::Range{true, name::Component("ignore"), false, name::Component("e2")})); - BOOST_CHECK_EQUAL(enumerated[1].fromInfinity, false); - BOOST_CHECK_EQUAL(enumerated[1].from, name::Component("f0")); - BOOST_CHECK_EQUAL(enumerated[1].toInfinity, true); - BOOST_CHECK_EQUAL(boost::lexical_cast(enumerated[1]), "[f0,+∞)"); - BOOST_CHECK_EQUAL(enumerated[1], (Exclude::Range{false, name::Component("f0"), true, name::Component("ignore")})); - - e.excludeAfter(name::Component("e5")); - BOOST_CHECK_EQUAL(e.toUri(), "*,e2,e5,*"); - BOOST_CHECK_EQUAL(e.size(), 2); - enumerated.clear(); - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 2); - BOOST_CHECK_EQUAL(enumerated[0].fromInfinity, true); - BOOST_CHECK_EQUAL(enumerated[0].toInfinity, false); - BOOST_CHECK_EQUAL(enumerated[0].to, name::Component("e2")); - BOOST_CHECK_EQUAL(enumerated[1].fromInfinity, false); - BOOST_CHECK_EQUAL(enumerated[1].from, name::Component("e5")); - BOOST_CHECK_EQUAL(enumerated[1].toInfinity, true); - - e.excludeAfter(name::Component("b2")); - BOOST_CHECK_EQUAL(e.toUri(), "*"); - BOOST_CHECK_EQUAL(e.size(), 1); - enumerated.clear(); - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 1); - BOOST_CHECK_EQUAL(enumerated[0].fromInfinity, true); - BOOST_CHECK_EQUAL(enumerated[0].toInfinity, true); - - BOOST_REQUIRE_THROW(e.excludeRange(name::Component("d0"), name::Component("a0")), - Exclude::Error); -} - -BOOST_AUTO_TEST_SUITE_END() // GenericComponent - -BOOST_AUTO_TEST_SUITE(ImplicitDigest) // exclude ImplicitSha256DigestComponent - -/** \brief make a name::Component with an octet repeated crypto::SHA256_DIGEST_SIZE times - * \param octet the octet to fill the component - * \param isDigest whether to make an ImplicitSha256DigestComponent or a generic NameComponent - * \param lastOctet if non-negative, set the last octet to a different value - */ -static name::Component -makeComponent(uint8_t octet, bool isDigest, int lastOctet = -1) -{ - uint8_t wire[crypto::SHA256_DIGEST_SIZE]; - std::memset(wire, octet, sizeof(wire)); - if (lastOctet >= 0) { - wire[crypto::SHA256_DIGEST_SIZE - 1] = static_cast(lastOctet); - } - - if (isDigest) { - return name::Component::fromImplicitSha256Digest(wire, sizeof(wire)); - } - else { - return name::Component(wire, sizeof(wire)); - } -} - -BOOST_AUTO_TEST_CASE(One) -{ - name::Component digestC = makeComponent(0xCC, true);; - name::Component genericC = makeComponent(0xCC, false); - name::Component digestD = makeComponent(0xDD, true); - - Exclude e; - e.excludeOne(digestC); - BOOST_CHECK_EQUAL(e.isExcluded(digestC), true); - BOOST_CHECK_EQUAL(e.isExcluded(genericC), false); - BOOST_CHECK_EQUAL(e.isExcluded(digestD), false); - - e.clear(); - e.excludeOne(genericC); - BOOST_CHECK_EQUAL(e.isExcluded(digestC), false); - BOOST_CHECK_EQUAL(e.isExcluded(genericC), true); -} - -BOOST_AUTO_TEST_CASE(BeforeDigest) -{ - name::Component digestBA = makeComponent(0xBB, true, 0xBA); - name::Component digestBB = makeComponent(0xBB, true); - name::Component digestBC = makeComponent(0xBB, true, 0xBC); - - Exclude e; - e.excludeBefore(digestBB); - BOOST_CHECK_EQUAL(e.isExcluded(digestBA), true); - BOOST_CHECK_EQUAL(e.isExcluded(digestBB), true); - BOOST_CHECK_EQUAL(e.isExcluded(digestBC), false); - BOOST_CHECK_EQUAL(e.isExcluded(name::Component("")), false); - BOOST_CHECK_EQUAL(e.isExcluded(name::Component("generic")), false); - - BOOST_CHECK_EQUAL(e.size(), 1); - std::vector enumerated; - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 1); - BOOST_CHECK_EQUAL(enumerated[0].fromInfinity, true); - BOOST_CHECK_EQUAL(enumerated[0].toInfinity, false); - BOOST_CHECK_EQUAL(enumerated[0].to, digestBB); -} - -BOOST_AUTO_TEST_CASE(BeforeGeneric) -{ - name::Component digest0 = makeComponent(0x00, true); - name::Component digest9 = makeComponent(0x99, true); - name::Component digestF = makeComponent(0xFF, true); - - Exclude e; - e.excludeBefore(name::Component("")); - BOOST_CHECK_EQUAL(e.isExcluded(digest0), true); - BOOST_CHECK_EQUAL(e.isExcluded(digest9), true); - BOOST_CHECK_EQUAL(e.isExcluded(digestF), true); - BOOST_CHECK_EQUAL(e.isExcluded(name::Component("")), true); - BOOST_CHECK_EQUAL(e.isExcluded(name::Component("generic")), false); -} - -BOOST_AUTO_TEST_CASE(AfterDigest) -{ - name::Component digestBA = makeComponent(0xBB, true, 0xBA); - name::Component digestBB = makeComponent(0xBB, true); - name::Component digestBC = makeComponent(0xBB, true, 0xBC); - - Exclude e; - e.excludeAfter(digestBB); - BOOST_CHECK_EQUAL(e.isExcluded(digestBA), false); - BOOST_CHECK_EQUAL(e.isExcluded(digestBB), true); - BOOST_CHECK_EQUAL(e.isExcluded(digestBC), true); - BOOST_CHECK_EQUAL(e.isExcluded(name::Component("")), true); - BOOST_CHECK_EQUAL(e.isExcluded(name::Component("generic")), true); - - BOOST_CHECK_EQUAL(e.size(), 1); - std::vector enumerated; - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 1); - BOOST_CHECK_EQUAL(enumerated[0].fromInfinity, false); - BOOST_CHECK_EQUAL(enumerated[0].from, digestBB); - BOOST_CHECK_EQUAL(enumerated[0].toInfinity, true); -} - -BOOST_AUTO_TEST_CASE(AfterDigestFF) -{ - name::Component digest00 = makeComponent(0x00, true); - name::Component digest99 = makeComponent(0x99, true); - name::Component digestFE = makeComponent(0xFF, true, 0xFE); - name::Component digestFF = makeComponent(0xFF, true); - - Exclude e; - e.excludeAfter(digestFF); - BOOST_CHECK_EQUAL(e.isExcluded(digest00), false); - BOOST_CHECK_EQUAL(e.isExcluded(digest99), false); - BOOST_CHECK_EQUAL(e.isExcluded(digestFE), false); - BOOST_CHECK_EQUAL(e.isExcluded(digestFF), true); - BOOST_CHECK_EQUAL(e.isExcluded(name::Component("")), true); - BOOST_CHECK_EQUAL(e.isExcluded(name::Component("generic")), true); -} - -BOOST_AUTO_TEST_CASE(AfterGeneric) -{ - name::Component digest0 = makeComponent(0x00, true); - name::Component digest9 = makeComponent(0x99, true); - name::Component digestF = makeComponent(0xFF, true); - - Exclude e; - e.excludeAfter(name::Component("")); - BOOST_CHECK_EQUAL(e.isExcluded(digest0), false); - BOOST_CHECK_EQUAL(e.isExcluded(digest9), false); - BOOST_CHECK_EQUAL(e.isExcluded(digestF), false); - BOOST_CHECK_EQUAL(e.isExcluded(name::Component("")), true); - BOOST_CHECK_EQUAL(e.isExcluded(name::Component("generic")), true); -} - -BOOST_AUTO_TEST_CASE(RangeDigest) -{ - name::Component digest0 = makeComponent(0x00, true); - name::Component digest7 = makeComponent(0x77, true); - name::Component digest8 = makeComponent(0x88, true); - name::Component digest9 = makeComponent(0x99, true); - name::Component digestF = makeComponent(0xFF, true); - - Exclude e; - e.excludeRange(digest7, digest9); - BOOST_CHECK_EQUAL(e.isExcluded(digest0), false); - BOOST_CHECK_EQUAL(e.isExcluded(digest7), true); - BOOST_CHECK_EQUAL(e.isExcluded(digest8), true); - BOOST_CHECK_EQUAL(e.isExcluded(digest9), true); - BOOST_CHECK_EQUAL(e.isExcluded(digestF), false); - BOOST_CHECK_EQUAL(e.isExcluded(name::Component("")), false); - BOOST_CHECK_EQUAL(e.isExcluded(name::Component("generic")), false); -} - -BOOST_AUTO_TEST_CASE(RangeDigestReverse) -{ - name::Component digest7 = makeComponent(0x77, true); - name::Component digest9 = makeComponent(0x99, true); - - Exclude e; - BOOST_CHECK_THROW(e.excludeRange(digest9, digest7), Exclude::Error); -} - -BOOST_AUTO_TEST_CASE(RangeDigestGeneric) -{ - name::Component digest0 = makeComponent(0x00, true); - name::Component digest7 = makeComponent(0x77, true); - name::Component digest9 = makeComponent(0x99, true); - name::Component digestF = makeComponent(0xFF, true); - - Exclude e; - e.excludeRange(digest9, name::Component("")); - BOOST_CHECK_EQUAL(e.isExcluded(digest0), false); - BOOST_CHECK_EQUAL(e.isExcluded(digest7), false); - BOOST_CHECK_EQUAL(e.isExcluded(digest9), true); - BOOST_CHECK_EQUAL(e.isExcluded(digestF), true); - BOOST_CHECK_EQUAL(e.isExcluded(name::Component("")), true); - BOOST_CHECK_EQUAL(e.isExcluded(name::Component("generic")), false); - - BOOST_CHECK_EQUAL(e.size(), 1); - std::vector enumerated; - std::copy(e.begin(), e.end(), std::back_inserter(enumerated)); - BOOST_REQUIRE_EQUAL(enumerated.size(), 1); - BOOST_CHECK_EQUAL(enumerated[0].fromInfinity, false); - BOOST_CHECK_EQUAL(enumerated[0].from, digest9); - BOOST_CHECK_EQUAL(enumerated[0].toInfinity, false); - BOOST_CHECK_EQUAL(enumerated[0].to, name::Component("")); -} - -BOOST_AUTO_TEST_CASE(RangeGenericDigest) -{ - name::Component digestF = makeComponent(0xFF, true); - - Exclude e; - BOOST_CHECK_THROW(e.excludeRange(name::Component(""), digestF), Exclude::Error); -} - -BOOST_AUTO_TEST_SUITE_END() // ImplicitDigest - -BOOST_AUTO_TEST_SUITE(WireCompare) // wireEncode, wireDecode, operator==, operator!= - -BOOST_AUTO_TEST_CASE(EqualityComparable) -{ - Exclude e1; - Exclude e2; - BOOST_CHECK_EQUAL(e1, e2); - - e1.excludeOne(name::Component("T")); - BOOST_CHECK_NE(e1, e2); - - e2.excludeOne(name::Component("D")); - BOOST_CHECK_NE(e1, e2); - - e2.clear(); - e2.excludeOne(name::Component("T")); - BOOST_CHECK_EQUAL(e1, e2); - - e2.clear(); - const uint8_t EXCLUDE[] = { 0x10, 0x15, 0x13, 0x00, 0x08, 0x01, 0x41, 0x08, 0x01, 0x42, - 0x08, 0x01, 0x43, 0x13, 0x00, 0x08, 0x01, 0x44, 0x08, 0x01, - 0x45, 0x13, 0x00 }; - e2.wireDecode(Block(EXCLUDE, sizeof(EXCLUDE))); - - e1.clear(); - e1.excludeBefore(name::Component("A")); - e1.excludeOne(name::Component("B")); - e1.excludeRange(name::Component("C"), name::Component("D")); - e1.excludeAfter(name::Component("E")); - BOOST_CHECK_EQUAL(e1, e2); -} - -BOOST_AUTO_TEST_CASE(Malformed) -{ - Exclude e1; - BOOST_CHECK_THROW(e1.wireEncode(), Exclude::Error); - - Exclude e2; - - // top-level TLV-TYPE is not tlv::Exclude - const uint8_t NON_EXCLUDE[] = { 0x01, 0x02, 0x13, 0x00 }; - BOOST_CHECK_THROW(e2.wireDecode(Block(NON_EXCLUDE, sizeof(NON_EXCLUDE))), - tlv::Error); - - // Exclude element is empty - const uint8_t EMPTY_EXCLUDE[] = { 0x10, 0x00 }; - BOOST_CHECK_THROW(e2.wireDecode(Block(EMPTY_EXCLUDE, sizeof(EMPTY_EXCLUDE))), - Exclude::Error); - - // Exclude element contains unknown element - const uint8_t UNKNOWN_COMP1[] = { 0x10, 0x02, 0xAA, 0x00 }; - BOOST_CHECK_THROW(e2.wireDecode(Block(UNKNOWN_COMP1, sizeof(UNKNOWN_COMP1))), - Exclude::Error); - - // Exclude element contains unknown element - const uint8_t UNKNOWN_COMP2[] = { 0x10, 0x05, 0x08, 0x01, 0x54, 0xAA, 0x00 }; - BOOST_CHECK_THROW(e2.wireDecode(Block(UNKNOWN_COMP2, sizeof(UNKNOWN_COMP2))), - Exclude::Error); - - // // - // const uint8_t ONLY_ANY[] = { 0x10, 0x02, 0x13, 0x00 }; - // BOOST_CHECK_THROW(e2.wireDecode(Block(ONLY_ANY, sizeof(ONLY_ANY))), - // Exclude::Error); - - // - const uint8_t ANY_ANY[] = { 0x10, 0x04, 0x13, 0x00, 0x13, 0x00 }; - BOOST_CHECK_THROW(e2.wireDecode(Block(ANY_ANY, sizeof(ANY_ANY))), - Exclude::Error); - - // // T - // const uint8_t ANY_COMPONENT_ANY[] = { 0x10, 0x07, 0x13, 0x00, 0x08, 0x01, 0x54, 0x13, 0x00 }; - // BOOST_CHECK_THROW(e2.wireDecode(Block(ANY_COMPONENT_ANY, sizeof(ANY_COMPONENT_ANY))), - // Exclude::Error); - - uint8_t WIRE[] = { - 0x10, 0x20, // Exclude - 0x01, 0x1E, // ImplicitSha256DigestComponent with incorrect length - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd - }; - - BOOST_CHECK_THROW(Exclude().wireDecode(Block(WIRE, sizeof(WIRE))), Exclude::Error); -} - -BOOST_AUTO_TEST_CASE(ImplicitSha256Digest) -{ - uint8_t WIRE[] = { - 0x10, 0x22, // Exclude - 0x01, 0x20, // ImplicitSha256DigestComponent - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd - }; - - Block block(WIRE, sizeof(WIRE)); - - Exclude exclude; - BOOST_CHECK_NO_THROW(exclude.wireDecode(block)); - BOOST_CHECK(exclude.wireEncode() == block); -} - -BOOST_AUTO_TEST_CASE(EmptyComponent) // Bug #2660 -{ - Exclude e1, e2; - - e1.excludeOne(name::Component()); - e2.excludeOne(name::Component("")); - - BOOST_CHECK_EQUAL(e1, e2); - BOOST_CHECK_EQUAL(e1.toUri(), e2.toUri()); - BOOST_CHECK(e1.wireEncode() == e2.wireEncode()); - - BOOST_CHECK_EQUAL("...", e1.toUri()); - - uint8_t WIRE[] {0x10, 0x02, 0x08, 0x00}; - BOOST_CHECK_EQUAL_COLLECTIONS(e1.wireEncode().begin(), e1.wireEncode().end(), - WIRE, WIRE + sizeof(WIRE)); - - Exclude e3(Block(WIRE, sizeof(WIRE))); - BOOST_CHECK_EQUAL(e1, e3); - BOOST_CHECK_EQUAL(e1.toUri(), e3.toUri()); -} - -BOOST_AUTO_TEST_SUITE_END() // WireCompare - -BOOST_AUTO_TEST_SUITE_END() // TestExclude - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/face.t.cpp b/tests/unit-tests/face.t.cpp deleted file mode 100644 index d547e33e9..000000000 --- a/tests/unit-tests/face.t.cpp +++ /dev/null @@ -1,787 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "face.hpp" -#include "lp/tags.hpp" -#include "security/key-chain.hpp" -#include "transport/tcp-transport.hpp" -#include "transport/unix-transport.hpp" -#include "util/dummy-client-face.hpp" -#include "util/scheduler.hpp" - -#include "boost-test.hpp" -#include "identity-management-time-fixture.hpp" -#include "key-chain-fixture.hpp" -#include "make-interest-data.hpp" - -namespace ndn { -namespace tests { - -using ndn::util::DummyClientFace; - -class FaceFixture : public IdentityManagementTimeFixture -{ -public: - explicit - FaceFixture(bool enableRegistrationReply = true) - : face(io, m_keyChain, {true, enableRegistrationReply}) - { - } - -public: - DummyClientFace face; -}; - -class FacesNoRegistrationReplyFixture : public FaceFixture -{ -public: - FacesNoRegistrationReplyFixture() - : FaceFixture(false) - { - } -}; - -BOOST_FIXTURE_TEST_SUITE(TestFace, FaceFixture) - -BOOST_AUTO_TEST_SUITE(Consumer) - -BOOST_AUTO_TEST_CASE(ExpressInterestData) -{ - size_t nData = 0; - face.expressInterest(Interest("/Hello/World", time::milliseconds(50)), - [&] (const Interest& i, const Data& d) { - BOOST_CHECK(i.getName().isPrefixOf(d.getName())); - BOOST_CHECK_EQUAL(i.getName(), "/Hello/World"); - ++nData; - }, - bind([] { BOOST_FAIL("Unexpected Nack"); }), - bind([] { BOOST_FAIL("Unexpected timeout"); })); - - advanceClocks(time::milliseconds(40)); - - face.receive(*makeData("/Bye/World/a")); - face.receive(*makeData("/Hello/World/a")); - - advanceClocks(time::milliseconds(50), 2); - - BOOST_CHECK_EQUAL(nData, 1); - BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); - BOOST_CHECK_EQUAL(face.sentData.size(), 0); - - size_t nTimeouts = 0; - face.expressInterest(Interest("/Hello/World/a/2", time::milliseconds(50)), - bind([]{}), - bind([]{}), - bind([&nTimeouts] { ++nTimeouts; })); - advanceClocks(time::milliseconds(200), 5); - BOOST_CHECK_EQUAL(nTimeouts, 1); -} - -BOOST_AUTO_TEST_CASE(ExpressInterestEmptyDataCallback) -{ - face.expressInterest(Interest("/Hello/World"), - nullptr, - bind([] { BOOST_FAIL("Unexpected Nack"); }), - bind([] { BOOST_FAIL("Unexpected timeout"); })); - advanceClocks(time::milliseconds(1)); - - BOOST_CHECK_NO_THROW(do { - face.receive(*makeData("/Hello/World/a")); - advanceClocks(time::milliseconds(1)); - } while (false)); -} - -BOOST_AUTO_TEST_CASE(DeprecatedExpressInterestData) -{ - size_t nData = 0; - face.expressInterest(Interest("/Hello/World", time::milliseconds(50)), - [&] (const Interest& i, Data& d) { - BOOST_CHECK(i.getName().isPrefixOf(d.getName())); - ++nData; - }, - bind([] { BOOST_FAIL("Unexpected timeout"); })); - - advanceClocks(time::milliseconds(40)); - - face.receive(*makeData("/Bye/World/a")); - face.receive(*makeData("/Hello/World/a")); - - advanceClocks(time::milliseconds(50), 2); - - BOOST_CHECK_EQUAL(nData, 1); - BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); - BOOST_CHECK_EQUAL(face.sentData.size(), 0); - - face.expressInterest(Interest("/Hello/World/a", time::milliseconds(50)), - [&] (const Interest& i, Data& d) { - BOOST_CHECK(i.getName().isPrefixOf(d.getName())); - ++nData; - }, - bind([] { BOOST_FAIL("Unexpected timeout"); })); - advanceClocks(time::milliseconds(40)); - face.receive(*makeData("/Hello/World/a/1/xxxxx")); - - advanceClocks(time::milliseconds(50), 2); - - BOOST_CHECK_EQUAL(nData, 2); - BOOST_CHECK_EQUAL(face.sentInterests.size(), 2); - BOOST_CHECK_EQUAL(face.sentData.size(), 0); -} - -BOOST_AUTO_TEST_CASE(ExpressInterestTimeout) -{ - size_t nTimeouts = 0; - face.expressInterest(Interest("/Hello/World", time::milliseconds(50)), - bind([] { BOOST_FAIL("Unexpected Data"); }), - bind([] { BOOST_FAIL("Unexpected Nack"); }), - [&nTimeouts] (const Interest& i) { - BOOST_CHECK_EQUAL(i.getName(), "/Hello/World"); - ++nTimeouts; - }); - - advanceClocks(time::milliseconds(200), 5); - - BOOST_CHECK_EQUAL(nTimeouts, 1); - BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); - BOOST_CHECK_EQUAL(face.sentData.size(), 0); - BOOST_CHECK_EQUAL(face.sentNacks.size(), 0); -} - -BOOST_AUTO_TEST_CASE(ExpressInterestEmptyTimeoutCallback) -{ - face.expressInterest(Interest("/Hello/World", time::milliseconds(50)), - bind([] { BOOST_FAIL("Unexpected Data"); }), - bind([] { BOOST_FAIL("Unexpected Nack"); }), - nullptr); - advanceClocks(time::milliseconds(40)); - - BOOST_CHECK_NO_THROW(do { - advanceClocks(time::milliseconds(6), 2); - } while (false)); -} - -BOOST_AUTO_TEST_CASE(DeprecatedExpressInterestTimeout) -{ - size_t nTimeouts = 0; - face.expressInterest(Interest("/Hello/World", time::milliseconds(50)), - bind([] { BOOST_FAIL("Unexpected data"); }), - bind([&nTimeouts] { ++nTimeouts; })); - - advanceClocks(time::milliseconds(200), 5); - - BOOST_CHECK_EQUAL(nTimeouts, 1); - BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); - BOOST_CHECK_EQUAL(face.sentData.size(), 0); -} - -BOOST_AUTO_TEST_CASE(ExpressInterestNack) -{ - size_t nNacks = 0; - - Interest interest("/Hello/World", time::milliseconds(50)); - - face.expressInterest(interest, - bind([] { BOOST_FAIL("Unexpected Data"); }), - [&] (const Interest& i, const lp::Nack& n) { - BOOST_CHECK(i.getName().isPrefixOf(n.getInterest().getName())); - BOOST_CHECK_EQUAL(i.getName(), "/Hello/World"); - BOOST_CHECK_EQUAL(n.getReason(), lp::NackReason::DUPLICATE); - ++nNacks; - }, - bind([] { BOOST_FAIL("Unexpected timeout"); })); - - advanceClocks(time::milliseconds(40)); - - face.receive(makeNack(face.sentInterests.at(0), lp::NackReason::DUPLICATE)); - - advanceClocks(time::milliseconds(50), 2); - - BOOST_CHECK_EQUAL(nNacks, 1); - BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); -} - -BOOST_AUTO_TEST_CASE(ExpressInterestEmptyNackCallback) -{ - face.expressInterest(Interest("/Hello/World"), - bind([] { BOOST_FAIL("Unexpected Data"); }), - nullptr, - bind([] { BOOST_FAIL("Unexpected timeout"); })); - advanceClocks(time::milliseconds(1)); - - BOOST_CHECK_NO_THROW(do { - face.receive(makeNack(face.sentInterests.at(0), lp::NackReason::DUPLICATE)); - advanceClocks(time::milliseconds(1)); - } while (false)); -} - -BOOST_AUTO_TEST_CASE(DeprecatedExpressInterestNack) -{ - size_t nTimeouts = 0; - face.expressInterest(Interest("/Hello/World", time::milliseconds(50)), - bind([] { BOOST_FAIL("Unexpected data"); }), - bind([&nTimeouts] { ++nTimeouts; })); - advanceClocks(time::milliseconds(1)); - - face.receive(makeNack(face.sentInterests.at(0), lp::NackReason::CONGESTION)); - advanceClocks(time::milliseconds(1)); - - BOOST_CHECK_EQUAL(nTimeouts, 1); - BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); - BOOST_CHECK_EQUAL(face.sentData.size(), 0); -} - -BOOST_AUTO_TEST_CASE(RemovePendingInterest) -{ - const PendingInterestId* interestId = - face.expressInterest(Interest("/Hello/World", time::milliseconds(50)), - bind([] { BOOST_FAIL("Unexpected data"); }), - bind([] { BOOST_FAIL("Unexpected nack"); }), - bind([] { BOOST_FAIL("Unexpected timeout"); })); - advanceClocks(time::milliseconds(10)); - - face.removePendingInterest(interestId); - advanceClocks(time::milliseconds(10)); - - face.receive(*makeData("/Hello/World/%21")); - advanceClocks(time::milliseconds(200), 5); - - // avoid "test case [...] did not check any assertions" message from Boost.Test - BOOST_CHECK(true); -} - -BOOST_AUTO_TEST_CASE(RemoveAllPendingInterests) -{ - face.expressInterest(Interest("/Hello/World/0", time::milliseconds(50)), - bind([] { BOOST_FAIL("Unexpected data"); }), - bind([] { BOOST_FAIL("Unexpected nack"); }), - bind([] { BOOST_FAIL("Unexpected timeout"); })); - - face.expressInterest(Interest("/Hello/World/1", time::milliseconds(50)), - bind([] { BOOST_FAIL("Unexpected data"); }), - bind([] { BOOST_FAIL("Unexpected nack"); }), - bind([] { BOOST_FAIL("Unexpected timeout"); })); - - advanceClocks(time::milliseconds(10)); - - face.removeAllPendingInterests(); - advanceClocks(time::milliseconds(10)); - - BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0); - - face.receive(*makeData("/Hello/World/0")); - face.receive(*makeData("/Hello/World/1")); - advanceClocks(time::milliseconds(200), 5); -} - -BOOST_AUTO_TEST_CASE(DestructionWithoutCancellingPendingInterests) // Bug #2518 -{ - { - DummyClientFace face2(io, m_keyChain); - face2.expressInterest(Interest("/Hello/World", time::milliseconds(50)), - bind([]{}), bind([]{})); - advanceClocks(time::milliseconds(50), 2); - } - - advanceClocks(time::milliseconds(50), 2); // should not crash - - // avoid "test case [...] did not check any assertions" message from Boost.Test - BOOST_CHECK(true); -} - -BOOST_AUTO_TEST_SUITE_END() // Consumer - -BOOST_AUTO_TEST_SUITE(Producer) - -BOOST_AUTO_TEST_CASE(PutData) -{ - BOOST_CHECK_EQUAL(face.sentData.size(), 0); - - Data data("/4g7xxcuEow/KFvK5Kf2m"); - signData(data); - face.put(data); - - lp::CachePolicy cachePolicy; - cachePolicy.setPolicy(lp::CachePolicyType::NO_CACHE); - data.setTag(make_shared(cachePolicy)); - data.setTag(make_shared(1)); - face.put(data); - - advanceClocks(time::milliseconds(10)); - BOOST_REQUIRE_EQUAL(face.sentData.size(), 2); - BOOST_CHECK(face.sentData[0].getTag() == nullptr); - BOOST_CHECK(face.sentData[0].getTag() == nullptr); - BOOST_CHECK(face.sentData[1].getTag() != nullptr); - BOOST_CHECK(face.sentData[1].getTag() != nullptr); -} - -BOOST_AUTO_TEST_CASE(PutNack) -{ - BOOST_CHECK_EQUAL(face.sentNacks.size(), 0); - - face.put(makeNack(Interest("/Hello/World", time::milliseconds(50)), lp::NackReason::NO_ROUTE)); - - advanceClocks(time::milliseconds(10)); - BOOST_CHECK_EQUAL(face.sentNacks.size(), 1); - - auto nack = makeNack(Interest("/another/prefix", time::milliseconds(50)), lp::NackReason::NO_ROUTE); - nack.setTag(make_shared(1)); - face.put(nack); - - advanceClocks(time::milliseconds(10)); - BOOST_REQUIRE_EQUAL(face.sentNacks.size(), 2); - BOOST_CHECK(face.sentNacks[0].getTag() == nullptr); - BOOST_CHECK(face.sentNacks[1].getTag() != nullptr); -} - -BOOST_AUTO_TEST_CASE(SetUnsetInterestFilter) -{ - size_t nInterests = 0; - size_t nRegs = 0; - const RegisteredPrefixId* regPrefixId = - face.setInterestFilter("/Hello/World", - bind([&nInterests] { ++nInterests; }), - bind([&nRegs] { ++nRegs; }), - bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); - advanceClocks(time::milliseconds(25), 4); - BOOST_CHECK_EQUAL(nRegs, 1); - BOOST_CHECK_EQUAL(nInterests, 0); - - face.receive(Interest("/Hello/World/%21")); - advanceClocks(time::milliseconds(25), 4); - - BOOST_CHECK_EQUAL(nRegs, 1); - BOOST_CHECK_EQUAL(nInterests, 1); - - face.receive(Interest("/Bye/World/%21")); - advanceClocks(time::milliseconds(10000), 10); - BOOST_CHECK_EQUAL(nInterests, 1); - - face.receive(Interest("/Hello/World/%21/2")); - advanceClocks(time::milliseconds(25), 4); - BOOST_CHECK_EQUAL(nInterests, 2); - - // removing filter - face.unsetInterestFilter(regPrefixId); - advanceClocks(time::milliseconds(25), 4); - - face.receive(Interest("/Hello/World/%21/3")); - BOOST_CHECK_EQUAL(nInterests, 2); - - face.unsetInterestFilter(static_cast(nullptr)); - advanceClocks(time::milliseconds(25), 4); - - face.unsetInterestFilter(static_cast(nullptr)); - advanceClocks(time::milliseconds(25), 4); -} - -BOOST_AUTO_TEST_CASE(SetInterestFilterEmptyInterestCallback) -{ - face.setInterestFilter("/A", nullptr); - advanceClocks(time::milliseconds(1)); - - BOOST_CHECK_NO_THROW(do { - face.receive(*makeInterest("/A/1")); - advanceClocks(time::milliseconds(1)); - } while (false)); -} - -BOOST_AUTO_TEST_CASE(SetUnsetInterestFilterWithoutSucessCallback) -{ - size_t nInterests = 0; - const RegisteredPrefixId* regPrefixId = - face.setInterestFilter("/Hello/World", - bind([&nInterests] { ++nInterests; }), - bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); - advanceClocks(time::milliseconds(25), 4); - BOOST_CHECK_EQUAL(nInterests, 0); - - face.receive(Interest("/Hello/World/%21")); - advanceClocks(time::milliseconds(25), 4); - - BOOST_CHECK_EQUAL(nInterests, 1); - - face.receive(Interest("/Bye/World/%21")); - advanceClocks(time::milliseconds(10000), 10); - BOOST_CHECK_EQUAL(nInterests, 1); - - face.receive(Interest("/Hello/World/%21/2")); - advanceClocks(time::milliseconds(25), 4); - BOOST_CHECK_EQUAL(nInterests, 2); - - // removing filter - face.unsetInterestFilter(regPrefixId); - advanceClocks(time::milliseconds(25), 4); - - face.receive(Interest("/Hello/World/%21/3")); - BOOST_CHECK_EQUAL(nInterests, 2); - - face.unsetInterestFilter(static_cast(nullptr)); - advanceClocks(time::milliseconds(25), 4); - - face.unsetInterestFilter(static_cast(nullptr)); - advanceClocks(time::milliseconds(25), 4); -} - -BOOST_FIXTURE_TEST_CASE(SetInterestFilterFail, FacesNoRegistrationReplyFixture) -{ - // don't enable registration reply - size_t nRegFailed = 0; - face.setInterestFilter("/Hello/World", - bind([] { BOOST_FAIL("Unexpected Interest"); }), - bind([] { BOOST_FAIL("Unexpected success of setInterestFilter"); }), - bind([&nRegFailed] { ++nRegFailed; })); - - advanceClocks(time::milliseconds(25), 4); - BOOST_CHECK_EQUAL(nRegFailed, 0); - - advanceClocks(time::milliseconds(2000), 5); - BOOST_CHECK_EQUAL(nRegFailed, 1); -} - -BOOST_FIXTURE_TEST_CASE(SetInterestFilterFailWithoutSuccessCallback, FacesNoRegistrationReplyFixture) -{ - // don't enable registration reply - size_t nRegFailed = 0; - face.setInterestFilter("/Hello/World", - bind([] { BOOST_FAIL("Unexpected Interest"); }), - bind([&nRegFailed] { ++nRegFailed; })); - - advanceClocks(time::milliseconds(25), 4); - BOOST_CHECK_EQUAL(nRegFailed, 0); - - advanceClocks(time::milliseconds(2000), 5); - BOOST_CHECK_EQUAL(nRegFailed, 1); -} - -BOOST_AUTO_TEST_CASE(RegisterUnregisterPrefix) -{ - size_t nRegSuccesses = 0; - const RegisteredPrefixId* regPrefixId = - face.registerPrefix("/Hello/World", - bind([&nRegSuccesses] { ++nRegSuccesses; }), - bind([] { BOOST_FAIL("Unexpected registerPrefix failure"); })); - - advanceClocks(time::milliseconds(25), 4); - BOOST_CHECK_EQUAL(nRegSuccesses, 1); - - size_t nUnregSuccesses = 0; - face.unregisterPrefix(regPrefixId, - bind([&nUnregSuccesses] { ++nUnregSuccesses; }), - bind([] { BOOST_FAIL("Unexpected unregisterPrefix failure"); })); - - advanceClocks(time::milliseconds(25), 4); - BOOST_CHECK_EQUAL(nUnregSuccesses, 1); -} - -BOOST_FIXTURE_TEST_CASE(RegisterUnregisterPrefixFail, FacesNoRegistrationReplyFixture) -{ - size_t nRegFailures = 0; - face.registerPrefix("/Hello/World", - bind([] { BOOST_FAIL("Unexpected registerPrefix success"); }), - bind([&nRegFailures] { ++nRegFailures; })); - - advanceClocks(time::milliseconds(5000), 20); - BOOST_CHECK_EQUAL(nRegFailures, 1); -} - -BOOST_AUTO_TEST_CASE(SimilarFilters) -{ - size_t nInInterests1 = 0; - face.setInterestFilter("/Hello/World", - bind([&nInInterests1] { ++nInInterests1; }), - nullptr, - bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); - - size_t nInInterests2 = 0; - face.setInterestFilter("/Hello", - bind([&nInInterests2] { ++nInInterests2; }), - nullptr, - bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); - - size_t nInInterests3 = 0; - face.setInterestFilter("/Los/Angeles/Lakers", - bind([&nInInterests3] { ++nInInterests3; }), - nullptr, - bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); - - advanceClocks(time::milliseconds(25), 4); - - face.receive(Interest("/Hello/World/%21")); - advanceClocks(time::milliseconds(25), 4); - - BOOST_CHECK_EQUAL(nInInterests1, 1); - BOOST_CHECK_EQUAL(nInInterests2, 1); - BOOST_CHECK_EQUAL(nInInterests3, 0); -} - -BOOST_AUTO_TEST_CASE(SetRegexFilterError) -{ - face.setInterestFilter(InterestFilter("/Hello/World", "<>?"), - [] (const Name&, const Interest&) { - BOOST_FAIL("InterestFilter::Error should have been triggered"); - }, - nullptr, - bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); - - advanceClocks(time::milliseconds(25), 4); - - BOOST_REQUIRE_THROW(face.receive(Interest("/Hello/World/XXX/b/c")), InterestFilter::Error); -} - -BOOST_AUTO_TEST_CASE(SetRegexFilter) -{ - size_t nInInterests = 0; - face.setInterestFilter(InterestFilter("/Hello/World", "<>?"), - bind([&nInInterests] { ++nInInterests; }), - nullptr, - bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); - - advanceClocks(time::milliseconds(25), 4); - - face.receive(Interest("/Hello/World/a")); // shouldn't match - BOOST_CHECK_EQUAL(nInInterests, 0); - - face.receive(Interest("/Hello/World/a/b")); // should match - BOOST_CHECK_EQUAL(nInInterests, 1); - - face.receive(Interest("/Hello/World/a/b/c")); // should match - BOOST_CHECK_EQUAL(nInInterests, 2); - - face.receive(Interest("/Hello/World/a/b/d")); // should not match - BOOST_CHECK_EQUAL(nInInterests, 2); -} - -BOOST_AUTO_TEST_CASE(SetRegexFilterAndRegister) -{ - size_t nInInterests = 0; - face.setInterestFilter(InterestFilter("/Hello/World", "<>?"), - bind([&nInInterests] { ++nInInterests; })); - - size_t nRegSuccesses = 0; - face.registerPrefix("/Hello/World", - bind([&nRegSuccesses] { ++nRegSuccesses; }), - bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); - - advanceClocks(time::milliseconds(25), 4); - BOOST_CHECK_EQUAL(nRegSuccesses, 1); - - face.receive(Interest("/Hello/World/a")); // shouldn't match - BOOST_CHECK_EQUAL(nInInterests, 0); - - face.receive(Interest("/Hello/World/a/b")); // should match - BOOST_CHECK_EQUAL(nInInterests, 1); - - face.receive(Interest("/Hello/World/a/b/c")); // should match - BOOST_CHECK_EQUAL(nInInterests, 2); - - face.receive(Interest("/Hello/World/a/b/d")); // should not match - BOOST_CHECK_EQUAL(nInInterests, 2); -} - -BOOST_FIXTURE_TEST_CASE(SetInterestFilterNoReg, FacesNoRegistrationReplyFixture) // Bug 2318 -{ - // This behavior is specific to DummyClientFace. - // Regular Face won't accept incoming packets until something is sent. - - int hit = 0; - face.setInterestFilter(Name("/"), bind([&hit] { ++hit; })); - face.processEvents(time::milliseconds(-1)); - - auto interest = make_shared("/A"); - face.receive(*interest); - face.processEvents(time::milliseconds(-1)); - - BOOST_CHECK_EQUAL(hit, 1); -} - -BOOST_AUTO_TEST_SUITE_END() // Producer - -BOOST_AUTO_TEST_SUITE(IoRoutines) - -BOOST_AUTO_TEST_CASE(ProcessEvents) -{ - face.processEvents(time::milliseconds(-1)); // io_service::reset()/poll() inside - - size_t nRegSuccesses = 0; - face.registerPrefix("/Hello/World", - bind([&nRegSuccesses] { ++nRegSuccesses; }), - bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); - - // io_service::poll() without reset - face.getIoService().poll(); - BOOST_CHECK_EQUAL(nRegSuccesses, 0); - - face.processEvents(time::milliseconds(-1)); // io_service::reset()/poll() inside - BOOST_CHECK_EQUAL(nRegSuccesses, 1); -} - -BOOST_AUTO_TEST_CASE(DestroyWithoutProcessEvents) // Bug 3248 -{ - auto face2 = make_unique(io); - face2.reset(); - - io.poll(); // should not crash - - // avoid "test case [...] did not check any assertions" message from Boost.Test - BOOST_CHECK(true); -} - -BOOST_AUTO_TEST_SUITE_END() // IoRoutines - -BOOST_AUTO_TEST_SUITE(Transport) - -using ndn::Transport; - -struct PibDirWithDefaultTpm -{ - const std::string PATH = "build/keys-with-default-tpm"; -}; - -BOOST_FIXTURE_TEST_CASE(FaceTransport, PibDirFixture) -{ - KeyChain keyChain; - boost::asio::io_service io; - - BOOST_CHECK(Face().getTransport() != nullptr); - - BOOST_CHECK(Face(shared_ptr()).getTransport() != nullptr); - BOOST_CHECK(Face(shared_ptr(), io).getTransport() != nullptr); - BOOST_CHECK(Face(shared_ptr(), io, keyChain).getTransport() != nullptr); - - auto transport = make_shared("localhost", "6363"); // no real io operations will be scheduled - BOOST_CHECK(Face(transport).getTransport() == transport); - BOOST_CHECK(Face(transport, io).getTransport() == transport); - BOOST_CHECK(Face(transport, io, keyChain).getTransport() == transport); -} - -class WithEnv : private IdentityManagementTimeFixture -{ -public: - WithEnv() - { - if (getenv("NDN_CLIENT_TRANSPORT") != nullptr) { - m_oldTransport = getenv("NDN_CLIENT_TRANSPORT"); - unsetenv("NDN_CLIENT_TRANSPORT"); - } - } - - void - configure(const std::string& faceUri) - { - setenv("NDN_CLIENT_TRANSPORT", faceUri.c_str(), true); - } - - ~WithEnv() - { - if (!m_oldTransport.empty()) { - setenv("NDN_CLIENT_TRANSPORT", m_oldTransport.c_str(), true); - } - else { - unsetenv("NDN_CLIENT_TRANSPORT"); - } - } - -private: - std::string m_oldTransport; -}; - -class WithConfig : private TestHomeFixture -{ -public: - void - configure(const std::string& faceUri) - { - createClientConf({"transport=" + faceUri}); - } -}; - -class WithEnvAndConfig : public WithEnv, public WithConfig -{ -}; - -typedef boost::mpl::vector ConfigOptions; - -BOOST_FIXTURE_TEST_CASE(NoConfig, WithEnvAndConfig) // fixture configures test HOME and PIB/TPM path -{ - shared_ptr face; - BOOST_REQUIRE_NO_THROW(face = make_shared()); - BOOST_CHECK(dynamic_pointer_cast(face->getTransport()) != nullptr); -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE(Unix, T, ConfigOptions, T) -{ - this->configure("unix://some/path"); - - shared_ptr face; - BOOST_REQUIRE_NO_THROW(face = make_shared()); - BOOST_CHECK(dynamic_pointer_cast(face->getTransport()) != nullptr); -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE(Tcp, T, ConfigOptions, T) -{ - this->configure("tcp://127.0.0.1:6000"); - - shared_ptr face; - BOOST_REQUIRE_NO_THROW(face = make_shared()); - BOOST_CHECK(dynamic_pointer_cast(face->getTransport()) != nullptr); -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE(WrongTransport, T, ConfigOptions, T) -{ - this->configure("wrong-transport:"); - - BOOST_CHECK_THROW(make_shared(), ConfigFile::Error); -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE(WrongUri, T, ConfigOptions, T) -{ - this->configure("wrong-uri"); - - BOOST_CHECK_THROW(make_shared(), ConfigFile::Error); -} - -BOOST_FIXTURE_TEST_CASE(EnvOverride, WithEnvAndConfig) -{ - this->WithEnv::configure("tcp://127.0.0.1:6000"); - this->WithConfig::configure("unix://some/path"); - - shared_ptr face; - BOOST_REQUIRE_NO_THROW(face = make_shared()); - BOOST_CHECK(dynamic_pointer_cast(face->getTransport()) != nullptr); -} - -BOOST_FIXTURE_TEST_CASE(ExplicitTransport, WithEnvAndConfig) -{ - this->WithEnv::configure("wrong-uri"); - this->WithConfig::configure("wrong-transport:"); - - auto transport = make_shared("unix://some/path"); - shared_ptr face; - BOOST_REQUIRE_NO_THROW(face = make_shared(transport)); - BOOST_CHECK(dynamic_pointer_cast(face->getTransport()) != nullptr); -} - -BOOST_AUTO_TEST_SUITE_END() // Transport - -BOOST_AUTO_TEST_SUITE_END() // TestFace - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/identity-management-time-fixture.hpp b/tests/unit-tests/identity-management-time-fixture.hpp deleted file mode 100644 index 3451b30c1..000000000 --- a/tests/unit-tests/identity-management-time-fixture.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_TESTS_UNIT_TESTS_IDENTITY_MANAGEMENT_TIME_FIXTURE_HPP -#define NDN_TESTS_UNIT_TESTS_IDENTITY_MANAGEMENT_TIME_FIXTURE_HPP - -#include "identity-management-fixture.hpp" -#include "unit-test-time-fixture.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 UnitTestTimeFixture - , public IdentityManagementFixture -{ -}; - -} // namespace tests -} // namespace ndn - -#endif // NDN_TESTS_UNIT_TESTS_IDENTITY_MANAGEMENT_TIME_FIXTURE_HPP diff --git a/tests/unit-tests/interest.t.cpp b/tests/unit-tests/interest.t.cpp deleted file mode 100644 index 240cc80a1..000000000 --- a/tests/unit-tests/interest.t.cpp +++ /dev/null @@ -1,1123 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "interest.hpp" -#include "interest-filter.hpp" -#include "data.hpp" -#include "security/signature-sha256-with-rsa.hpp" -#include "security/digest-sha256.hpp" -#include "security/key-chain.hpp" -#include "encoding/buffer-stream.hpp" - -#include "boost-test.hpp" -#include "identity-management-fixture.hpp" - -namespace ndn { -namespace tests { - -BOOST_FIXTURE_TEST_SUITE(TestInterest, IdentityManagementFixture) - -const uint8_t Interest1[] = { - 0x05, 0x59, // NDN Interest - 0x07, 0x14, // Name - 0x08, 0x5, // NameComponent - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x3, // NameComponent - 0x6e, 0x64, 0x6e, - 0x08, 0x6, // NameComponent - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x09, 0x37, // Selectors - 0x0d, 0x1, 0x1, // MinSuffix - 0x0e, 0x1, 0x1, // MaxSuffix - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x10, 0x14, // Exclude - 0x08, 0x4, // NameComponent - 0x61, 0x6c, 0x65, 0x78, - 0x08, 0x4, // NameComponent - 0x78, 0x78, 0x78, 0x78, - 0x13, 0x0, // Any - 0x08, 0x4, // NameComponent - 0x79, 0x79, 0x79, 0x79, - 0x11, 0x1, // ChildSelector - 0x1, - 0x0a, 0x4, // Nonce - 0x1, 0x0, 0x0, 0x00, - 0x0c, // InterestLifetime - 0x2, 0x3, 0xe8 -}; - -const uint8_t Interest2[] = { - 0x05, 0x59, // NDN Interest - 0x07, 0x14, // Name - 0x08, 0x5, // NameComponent - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x3, // NameComponent - 0x6e, 0x64, 0x6e, - 0x08, 0x6, // NameComponent - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x09, 0x37, // Selectors - 0x0d, 0x1, 0x1, // MinSuffix - 0x0e, 0x1, 0x1, // MaxSuffix - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x10, 0x14, // Exclude - 0x08, 0x4, // NameComponent - 0x61, 0x6c, 0x65, 0x78, - 0x08, 0x4, // NameComponent - 0x78, 0x78, 0x78, 0x78, - 0x13, 0x0, // Any - 0x08, 0x4, // NameComponent - 0x79, 0x79, 0x79, 0x79, - 0x11, 0x1, // ChildSelector - 0x1, - 0x0a, 0x4, // Nonce - 0x2, 0x0, 0x0, 0x00, - 0x0c, // InterestLifetime - 0x2, 0x3, 0xe8 -}; - -const uint8_t InterestWithLink[] = { - 0x05, 0xfb, // Interest - 0x07, 0x14, // Name - 0x08, 0x5, // NameComponent - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x3, // NameComponent - 0x6e, 0x64, 0x6e, - 0x08, 0x6, // NameComponent - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x0a, 0x4, // Nonce - 0x1, 0x0, 0x0, 0x00, - 0x06, 0xda, // Data - 0x07, 0x14, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x08, 0x06, - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x14, 0x07, // MetaInfo - 0x18, 0x01, // ContentType - 0x01, - 0x19, 0x02, // FreshnessPeriod - 0x27, 0x10, - 0x15, 0x1a, // Content - 0x1f, 0x0c, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x0a, - 0x07, 0x07, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x1f, 0x0a, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x14, - 0x07, 0x05, // Name - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x01, - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x17, 0x80, // SignatureValue - 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, - 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, - 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, - 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, - 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, - 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, - 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, - 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, - 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, - 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1, - 0x20, 0x01, // SelectedDelegation - 0x00 -}; - -const uint8_t LINK[] = { - 0x06, 0xda, // Data - 0x07, 0x14, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x08, 0x06, - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x14, 0x07, // MetaInfo - 0x18, 0x01, // ContentType - 0x01, - 0x19, 0x02, // FreshnessPeriod - 0x27, 0x10, - 0x15, 0x1a, // Content - 0x1f, 0x0c, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x0a, - 0x07, 0x07, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x1f, 0x0a, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x14, - 0x07, 0x05, // Name - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x01, - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x17, 0x80, // SignatureValue - 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, - 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, - 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, - 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, - 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, - 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, - 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, - 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, - 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, - 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1 -}; - -const uint8_t InterestWithLinkMissingContentType[] = { - 0x05, 0xf8, // Interest - 0x07, 0x14, // Name - 0x08, 0x5, // NameComponent - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x3, // NameComponent - 0x6e, 0x64, 0x6e, - 0x08, 0x6, // NameComponent - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x0a, 0x4, // Nonce - 0x1, 0x0, 0x0, 0x00, - 0x06, 0xd7, // Data - 0x07, 0x14, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x08, 0x06, - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x14, 0x04, // MetaInfo - 0x19, 0x02, // FreshnessPeriod - 0x27, 0x10, - 0x15, 0x1a, // Content - 0x1f, 0x0c, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x0a, - 0x07, 0x07, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x1f, 0x0a, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x14, - 0x07, 0x05, // Name - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x01, - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x17, 0x80, // SignatureValue - 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, - 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, - 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, - 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, - 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, - 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, - 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, - 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, - 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, - 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1, - 0x20, 0x01, // SelectedDelegation - 0x00 -}; - -const uint8_t InterestWithLinkNoMetaInfo[] = { - 0x05, 0xf2, // Interest - 0x07, 0x14, // Name - 0x08, 0x5, // NameComponent - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x3, // NameComponent - 0x6e, 0x64, 0x6e, - 0x08, 0x6, // NameComponent - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x0a, 0x4, // Nonce - 0x1, 0x0, 0x0, 0x00, - 0x06, 0xd1, // Data - 0x07, 0x14, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x08, 0x06, - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x15, 0x1a, // Content - 0x1f, 0x0c, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x0a, - 0x07, 0x07, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x1f, 0x0a, // LinkPreference - 0x1e, 0x01, // LinkPreference - 0x14, - 0x07, 0x05, // Name - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x01, - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x17, 0x80, // SignatureValue - 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, - 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, - 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, - 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, - 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, - 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, - 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, - 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, - 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, - 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1, - 0x20, 0x01, // SelectedDelegation - 0x00 -}; - -const uint8_t InterestWithLinkWrongContentType[] = { - 0x05, 0xfb, // Interest - 0x07, 0x14, // Name - 0x08, 0x5, // NameComponent - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x3, // NameComponent - 0x6e, 0x64, 0x6e, - 0x08, 0x6, // NameComponent - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x0a, 0x4, // Nonce - 0x1, 0x0, 0x0, 0x00, - 0x06, 0xda, // Data - 0x07, 0x14, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x08, 0x06, - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x14, 0x07, // MetaInfo - 0x18, 0x01, // ContentType - 0x00, - 0x19, 0x02, // FreshnessPeriod - 0x27, 0x10, - 0x15, 0x1a, // Content - 0x1f, 0x0c, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x0a, - 0x07, 0x07, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x1f, 0x0a, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x14, - 0x07, 0x05, // Name - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x01, - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x17, 0x80, // SignatureValue - 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, - 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, - 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, - 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, - 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, - 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, - 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, - 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, - 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, - 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1, - 0x20, 0x01, // SelectedDelegation - 0x00 -}; - -const uint8_t InterestWithSelectedDelegationButNoLink[] = { - 0x05, 0x1f, // Interest - 0x07, 0x14, // Name - 0x08, 0x5, // NameComponent - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x3, // NameComponent - 0x6e, 0x64, 0x6e, - 0x08, 0x6, // NameComponent - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x0a, 0x4, // Nonce - 0x1, 0x0, 0x0, 0x00, - 0x20, 0x01, // SelectedDelegation - 0x00 -}; - -const uint8_t InterestWithLinkNotNonIntegerSelectedDelegation[] = { - 0x05, 0xfb, // Interest - 0x07, 0x14, // Name - 0x08, 0x5, // NameComponent - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x3, // NameComponent - 0x6e, 0x64, 0x6e, - 0x08, 0x6, // NameComponent - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x0a, 0x4, // Nonce - 0x1, 0x0, 0x0, 0x00, - 0x06, 0xda, // Data - 0x07, 0x14, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x08, 0x06, - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x14, 0x07, // MetaInfo - 0x18, 0x01, // ContentType - 0x01, - 0x19, 0x02, // FreshnessPeriod - 0x27, 0x10, - 0x15, 0x1a, // Content - 0x1f, 0x0c, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x0a, - 0x07, 0x07, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x1f, 0x0a, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x14, - 0x07, 0x05, // Name - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x01, - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x17, 0x78, // SignatureValue - 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, - 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, - 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, - 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, - 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, - 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, - 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, - 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, - 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, - 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, - 0x20, 0x03, // SelectedDelegation - 0xAA, 0xAA, 0xAA -}; - -const uint8_t InterestWithLinkNonDecreasingOrder[] = { - 0x05, 0xfb, // Interest - 0x07, 0x14, // Name - 0x08, 0x5, // NameComponent - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x3, // NameComponent - 0x6e, 0x64, 0x6e, - 0x08, 0x6, // NameComponent - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x0a, 0x4, // Nonce - 0x1, 0x0, 0x0, 0x00, - 0x06, 0xda, // Data - 0x07, 0x14, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x08, 0x06, - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x14, 0x07, // MetaInfo - 0x18, 0x01, // ContentType - 0x01, - 0x19, 0x02, // FreshnessPeriod - 0x27, 0x10, - 0x15, 0x1a, // Content - 0x1f, 0x0c, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x14, - 0x07, 0x07, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x1f, 0x0a, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x0a, - 0x07, 0x05, // Name - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x01, - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x17, 0x80, // SignatureValue - 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, - 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, - 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, - 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, - 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, - 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, - 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, - 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, - 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, - 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1, - 0x20, 0x01, // SelectedDelegation - 0x01 -}; - -BOOST_AUTO_TEST_CASE(InterestEqualityChecks) -{ - // Interest ::= INTEREST-TYPE TLV-LENGTH - // Name - // Selectors? - // Nonce - // InterestLifetime? - // Link? - // SelectedDelegation? - - Interest a; - Interest b; - - // if nonce is not set, it will be set to a random value - a.setNonce(1); - b.setNonce(1); - - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - // check comparison on Name - a.setName("ndn:/A"); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setName("ndn:/B"); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setName("ndn:/A"); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - // check comparison on Selectors - a.setChildSelector(1); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setChildSelector(1); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - // check comparison on Nonce - a.setNonce(100); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setNonce(100); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - // check comparison on InterestLifetime - a.setInterestLifetime(time::seconds(10)); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setInterestLifetime(time::seconds(10)); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - a.setLink(Block(LINK, sizeof(LINK))); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setLink(Block(LINK, sizeof(LINK))); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - // Selected Delegation - BOOST_CHECK_EQUAL(a.hasSelectedDelegation(), false); - BOOST_CHECK_EQUAL(b.hasSelectedDelegation(), false); - - a.setSelectedDelegation(Name("/local")); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setSelectedDelegation(Name("/local")); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); -} - -BOOST_AUTO_TEST_CASE(SelectorsEqualityChecks) -{ - // Selectors ::= SELECTORS-TYPE TLV-LENGTH - // MinSuffixComponents? - // MaxSuffixComponents? - // PublisherPublicKeyLocator? - // Exclude? - // ChildSelector? - // MustBeFresh? - - Selectors a; - Selectors b; - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - // MinSuffixComponents - a.setMinSuffixComponents(1); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setMinSuffixComponents(2); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setMinSuffixComponents(1); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - // MaxSuffixComponents - a.setMaxSuffixComponents(10); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setMaxSuffixComponents(10); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - // PublisherPublicKeyLocator - a.setPublisherPublicKeyLocator(KeyLocator("/key/Locator/name")); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setPublisherPublicKeyLocator(KeyLocator("/key/Locator/name")); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - // Exclude - a.setExclude(Exclude().excludeOne(name::Component("exclude"))); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setExclude(Exclude().excludeOne(name::Component("exclude"))); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - // ChildSelector - a.setChildSelector(1); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setChildSelector(1); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - // MustBeFresh - a.setMustBeFresh(true); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setMustBeFresh(true); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); -} - -BOOST_AUTO_TEST_CASE(LinkObject) -{ - Link link1("test", {{100, "/test3"}, {20, "/test2"}, {10, "/test1"}}); - m_keyChain.sign(link1); - Block wire = link1.wireEncode(); - - Interest a; - BOOST_REQUIRE_NO_THROW(a.setLink(wire)); - - BOOST_REQUIRE_NO_THROW(a.getLink()); - - Link link2 = a.getLink(); - Name name = link2.getName(); - BOOST_CHECK_EQUAL(Name("test"), name); - BOOST_CHECK_EQUAL(a.hasLink(), true); - Link::DelegationSet delegations; - delegations = link2.getDelegations(); - - auto i = delegations.begin(); - BOOST_CHECK_EQUAL(std::get<0>(*i), 10); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test1")); - ++i; - BOOST_CHECK_EQUAL(std::get<0>(*i), 20); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test2")); - ++i; - BOOST_CHECK_EQUAL(std::get<0>(*i), 100); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test3")); - - a.setLink(Block(LINK, sizeof(LINK))); - BOOST_CHECK_EQUAL(a.getLink().getDelegations().size(), 2); - - a.unsetLink(); - BOOST_CHECK_EQUAL(a.hasLink(), false); -} - -BOOST_AUTO_TEST_CASE(SelectedDelegationChecks) -{ - Link link("test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}}); - m_keyChain.sign(link); - Block wire = link.wireEncode(); - - Interest a; - a.setLink(wire); - BOOST_CHECK_EQUAL(a.hasSelectedDelegation(), false); - - BOOST_REQUIRE_NO_THROW(a.setSelectedDelegation(Name("test2"))); - BOOST_CHECK_EQUAL(a.getSelectedDelegation(), Name("test2")); - - BOOST_REQUIRE_NO_THROW(a.setSelectedDelegation(uint32_t(2))); - BOOST_CHECK_EQUAL(a.getSelectedDelegation(), Name("test3")); - - a.unsetSelectedDelegation(); - BOOST_CHECK_EQUAL(a.hasSelectedDelegation(), false); -} - -BOOST_AUTO_TEST_CASE(EncodeDecodeWithLink) -{ - Link link1("test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}}); - m_keyChain.sign(link1); - Block wire = link1.wireEncode(); - - Interest a; - a.setName("/Test/Encode/Decode/With/Link"); - a.setChildSelector(1); - a.setNonce(100); - a.setInterestLifetime(time::seconds(10)); - a.setLink(wire); - - Block interestBlock = a.wireEncode(); - Interest b(interestBlock); - - BOOST_CHECK_EQUAL(a == b, true); - - Link link2 = b.getLink(); - Link::DelegationSet delegations; - delegations = link2.getDelegations(); - - auto i = delegations.begin(); - BOOST_CHECK_EQUAL(std::get<0>(*i), 10); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test1")); - ++i; - BOOST_CHECK_EQUAL(std::get<0>(*i), 20); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test2")); - ++i; - BOOST_CHECK_EQUAL(std::get<0>(*i), 100); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test3")); - -} - -BOOST_AUTO_TEST_CASE(DecodeInterestWithLink) -{ - Block interestBlock(InterestWithLink, sizeof(InterestWithLink)); - - ndn::Interest i; - BOOST_REQUIRE_NO_THROW(i.wireDecode(interestBlock)); - Link link = i.getLink(); - BOOST_CHECK_EQUAL(link.getName(), Name("/local/ndn/prefix")); - Link::DelegationSet delegations = link.getDelegations(); - - auto it = delegations.begin(); - BOOST_CHECK_EQUAL(std::get<0>(*it), 10); - BOOST_CHECK_EQUAL(std::get<1>(*it), Name("local")); - ++it; - BOOST_CHECK_EQUAL(std::get<0>(*it), 20); - BOOST_CHECK_EQUAL(std::get<1>(*it), Name("ndn")); - - BOOST_REQUIRE_NO_THROW(i.getSelectedDelegation()); - BOOST_CHECK_EQUAL(i.getSelectedDelegation(), Name("local")); -} - -BOOST_AUTO_TEST_CASE(DecodeInterestWithLinkNonDecreasingOrder) -{ - Block interestBlock(InterestWithLinkNonDecreasingOrder, - sizeof(InterestWithLinkNonDecreasingOrder)); - - ndn::Interest i; - BOOST_REQUIRE_NO_THROW(i.wireDecode(interestBlock)); - BOOST_REQUIRE_NO_THROW(i.getSelectedDelegation()); - BOOST_CHECK_EQUAL(i.getSelectedDelegation(), Name("ndn")); -} - -BOOST_AUTO_TEST_CASE(LinkObjectMissingContentType) -{ - Block interestBlock(InterestWithLinkMissingContentType, - sizeof(InterestWithLinkMissingContentType)); - - ndn::Interest i; - BOOST_REQUIRE_NO_THROW(i.wireDecode(interestBlock)); - BOOST_REQUIRE_THROW(i.getLink(), Link::Error); -} - -BOOST_AUTO_TEST_CASE(LinkObjectNoMetaInfo) -{ - Block interestBlock(InterestWithLinkNoMetaInfo, - sizeof(InterestWithLinkNoMetaInfo)); - - ndn::Interest i; - BOOST_REQUIRE_NO_THROW(i.wireDecode(interestBlock)); - BOOST_CHECK_THROW(i.getLink(), tlv::Error); - BOOST_CHECK_THROW(i.getLink(), tlv::Error); -} - -BOOST_AUTO_TEST_CASE(LinkObjectWrongContentType) -{ - Block interestBlock(InterestWithLinkWrongContentType, - sizeof(InterestWithLinkWrongContentType)); - - ndn::Interest i; - BOOST_REQUIRE_NO_THROW(i.wireDecode(interestBlock)); - BOOST_CHECK_THROW(i.getLink(), Link::Error); -} - -BOOST_AUTO_TEST_CASE(InterestContainingSelectedDelegationButNoLink) -{ - Block interestBlock(InterestWithSelectedDelegationButNoLink, - sizeof(InterestWithSelectedDelegationButNoLink)); - - ndn::Interest i; - BOOST_CHECK_THROW(i.wireDecode(interestBlock), Interest::Error); -} - -BOOST_AUTO_TEST_CASE(SelectedDelegationIsNotNonNegativeInteger) -{ - Block interestBlock(InterestWithLinkNotNonIntegerSelectedDelegation, - sizeof(InterestWithLinkNotNonIntegerSelectedDelegation)); - - ndn::Interest i; - BOOST_CHECK_THROW(i.wireDecode(interestBlock), tlv::Error); -} - -BOOST_AUTO_TEST_CASE(SelectedDelegationEqualToDelegationCount) -{ - Link link1("test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}}); - m_keyChain.sign(link1); - Block wire = link1.wireEncode(); - - Interest a; - a.setName("/Test/Encode/Decode/With/Link"); - a.setChildSelector(1); - a.setNonce(100); - a.setInterestLifetime(time::seconds(10)); - a.setLink(wire); - BOOST_CHECK_THROW(a.setSelectedDelegation(3), Interest::Error); -} - -BOOST_AUTO_TEST_CASE(SelectedDelegationGreaterThanDelegationCount) -{ - Link link1("test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}}); - m_keyChain.sign(link1); - Block wire = link1.wireEncode(); - - Interest a; - a.setName("/Test/Encode/Decode/With/Link"); - a.setChildSelector(1); - a.setNonce(100); - a.setInterestLifetime(time::seconds(10)); - a.setLink(wire); - BOOST_CHECK_THROW(a.setSelectedDelegation(4), Interest::Error); -} - -BOOST_AUTO_TEST_CASE(Decode) -{ - Block interestBlock(Interest1, sizeof(Interest1)); - - ndn::Interest i; - BOOST_REQUIRE_NO_THROW(i.wireDecode(interestBlock)); - - BOOST_CHECK_EQUAL(i.getName().toUri(), "/local/ndn/prefix"); - BOOST_CHECK_EQUAL(i.getInterestLifetime(), time::milliseconds(1000)); - BOOST_CHECK_EQUAL(i.getMinSuffixComponents(), 1); - BOOST_CHECK_EQUAL(i.getMaxSuffixComponents(), 1); - BOOST_CHECK_EQUAL(i.getPublisherPublicKeyLocator().getType(), - static_cast(KeyLocator::KeyLocator_Name)); - BOOST_CHECK_EQUAL(i.getPublisherPublicKeyLocator().getName(), "ndn:/test/key/locator"); - BOOST_CHECK_EQUAL(i.getChildSelector(), 1); - BOOST_CHECK_EQUAL(i.getMustBeFresh(), false); - BOOST_CHECK_EQUAL(i.getExclude().toUri(), "alex,xxxx,*,yyyy"); - BOOST_CHECK_EQUAL(i.getNonce(), 1U); - BOOST_CHECK_EQUAL(i.hasLink(), false); - BOOST_CHECK_EQUAL(i.hasSelectedDelegation(), false); -} - -BOOST_AUTO_TEST_CASE(DecodeFromStream) -{ - boost::iostreams::stream is( - reinterpret_cast(Interest1), sizeof(Interest1)); - - Block interestBlock = Block::fromStream(is); - - ndn::Interest i; - BOOST_REQUIRE_NO_THROW(i.wireDecode(interestBlock)); - - BOOST_CHECK_EQUAL(i.getName().toUri(), "/local/ndn/prefix"); - BOOST_CHECK_EQUAL(i.getInterestLifetime(), time::milliseconds(1000)); - BOOST_CHECK_EQUAL(i.getMinSuffixComponents(), 1); - BOOST_CHECK_EQUAL(i.getMaxSuffixComponents(), 1); - BOOST_CHECK_EQUAL(i.getChildSelector(), 1); - BOOST_CHECK_EQUAL(i.getMustBeFresh(), false); - BOOST_CHECK_EQUAL(i.getExclude().toUri(), "alex,xxxx,*,yyyy"); - BOOST_CHECK_EQUAL(i.getNonce(), 1U); - BOOST_CHECK_EQUAL(i.hasLink(), false); - BOOST_CHECK_EQUAL(i.hasSelectedDelegation(), false); -} - -BOOST_AUTO_TEST_CASE(Encode) -{ - ndn::Interest i(ndn::Name("/local/ndn/prefix")); - i.setInterestLifetime(time::milliseconds(1000)); - i.setMinSuffixComponents(1); - i.setMaxSuffixComponents(1); - i.setPublisherPublicKeyLocator(KeyLocator("ndn:/test/key/locator")); - i.setChildSelector(1); - i.setMustBeFresh(false); - Exclude exclude; - exclude - .excludeOne(name::Component("alex")) - .excludeRange(name::Component("xxxx"), name::Component("yyyy")); - i.setExclude(exclude); - i.setNonce(1); - - BOOST_CHECK_EQUAL(i.hasWire(), false); - const Block &wire = i.wireEncode(); - BOOST_CHECK_EQUAL(i.hasWire(), true); - - BOOST_CHECK_EQUAL_COLLECTIONS(Interest1, Interest1 + sizeof(Interest1), - wire.begin(), wire.end()); - - const uint8_t* originalWire = wire.wire(); - i.setNonce(2); - BOOST_CHECK_EQUAL(i.hasWire(), true); - BOOST_CHECK_EQUAL(originalWire, i.wireEncode().wire()); - BOOST_CHECK_EQUAL(i.hasWire(), true); - - BOOST_CHECK_EQUAL_COLLECTIONS(Interest2, Interest2 + sizeof(Interest2), - wire.begin(), wire.end()); - - std::ostringstream strStream; - BOOST_CHECK_NO_THROW(strStream << i); - - BOOST_CHECK_EQUAL(strStream.str(), - "/local/ndn/prefix?" - "ndn.MinSuffixComponents=1&ndn.MaxSuffixComponents=1&" - "ndn.ChildSelector=1&" - "ndn.InterestLifetime=1000&" - "ndn.Nonce=2&ndn.Exclude=alex,xxxx,*,yyyy"); - - i.refreshNonce(); - BOOST_CHECK_EQUAL(i.hasWire(), true); - BOOST_CHECK_EQUAL(originalWire, i.wireEncode().wire()); - BOOST_CHECK_NE(i.getNonce(), 2); -} - -BOOST_AUTO_TEST_CASE(DecodeEncode) // this test case to ensure that wireDecode resets all the fields -{ - Interest i1; - i1.setName("/test"); - i1.setMinSuffixComponents(100); - i1.setNonce(10); - i1.setInterestLifetime(time::seconds(10)); - i1.setLink(Block(LINK, sizeof(LINK))); - i1.setSelectedDelegation(0); - - Interest i2(i1.wireEncode()); - - BOOST_CHECK_EQUAL(i2.getName().toUri(), "/test"); - BOOST_CHECK_EQUAL(i2.getInterestLifetime(), time::seconds(10)); - BOOST_CHECK_EQUAL(i2.getMinSuffixComponents(), 100); - BOOST_CHECK_EQUAL(i2.getNonce(), 10); - BOOST_CHECK_EQUAL(i2.hasLink(), true); - BOOST_CHECK_EQUAL(i2.hasSelectedDelegation(), true); - - i2.wireDecode(Interest().wireEncode()); - - BOOST_CHECK_EQUAL(i2.getName().toUri(), "/"); - BOOST_CHECK_EQUAL(i2.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME); - BOOST_CHECK_EQUAL(i2.getMinSuffixComponents(), -1); - BOOST_WARN_NE(i2.getNonce(), 10); - BOOST_CHECK_EQUAL(i2.hasLink(), false); - BOOST_CHECK_EQUAL(i2.hasSelectedDelegation(), false); -} - -BOOST_AUTO_TEST_CASE(MatchesData) -{ - Interest interest; - interest.setName("ndn:/A") - .setMinSuffixComponents(2) - .setMaxSuffixComponents(2) - .setPublisherPublicKeyLocator(KeyLocator("ndn:/B")) - .setExclude(Exclude().excludeAfter(name::Component("J"))); - - Data data("ndn:/A/D"); - SignatureSha256WithRsa signature(KeyLocator("ndn:/B")); - data.setSignature(signature); - data.wireEncode(); - BOOST_CHECK_EQUAL(interest.matchesData(data), true); - - Data data1 = data; - data1.setName("ndn:/A"); // violates MinSuffixComponents - data1.wireEncode(); - BOOST_CHECK_EQUAL(interest.matchesData(data1), false); - - Interest interest1 = interest; - interest1.setMinSuffixComponents(1); - BOOST_CHECK_EQUAL(interest1.matchesData(data1), true); - - Data data2 = data; - data2.setName("ndn:/A/E/F"); // violates MaxSuffixComponents - data2.wireEncode(); - BOOST_CHECK_EQUAL(interest.matchesData(data2), false); - - Interest interest2 = interest; - interest2.setMaxSuffixComponents(3); - BOOST_CHECK_EQUAL(interest2.matchesData(data2), true); - - Data data3 = data; - SignatureSha256WithRsa signature3(KeyLocator("ndn:/G")); // violates PublisherPublicKeyLocator - data3.setSignature(signature3); - data3.wireEncode(); - BOOST_CHECK_EQUAL(interest.matchesData(data3), false); - - Interest interest3 = interest; - interest3.setPublisherPublicKeyLocator(KeyLocator("ndn:/G")); - BOOST_CHECK_EQUAL(interest3.matchesData(data3), true); - - Data data4 = data; - DigestSha256 signature4; // violates PublisherPublicKeyLocator - data4.setSignature(signature4); - data4.wireEncode(); - BOOST_CHECK_EQUAL(interest.matchesData(data4), false); - - Interest interest4 = interest; - interest4.setPublisherPublicKeyLocator(KeyLocator()); - BOOST_CHECK_EQUAL(interest4.matchesData(data4), true); - - Data data5 = data; - data5.setName("ndn:/A/J"); // violates Exclude - data5.wireEncode(); - BOOST_CHECK_EQUAL(interest.matchesData(data5), false); - - Interest interest5 = interest; - interest5.setExclude(Exclude().excludeAfter(name::Component("K"))); - BOOST_CHECK_EQUAL(interest5.matchesData(data5), true); - - Data data6 = data; - data6.setName("ndn:/H/I"); // violates Name - data6.wireEncode(); - BOOST_CHECK_EQUAL(interest.matchesData(data6), false); - - Data data7 = data; - data7.setName("ndn:/A/B"); - data7.wireEncode(); - - Interest interest7("/A/B/sha256digest=D548DECEFC4B880720DC9257A8D815E9DF4465E63742EE55C29133055DAA67C2"); - BOOST_CHECK_EQUAL(interest7.matchesData(data7), true); - - Interest interest7b("/A/B/sha256digest=0000000000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(interest7b.matchesData(data7), false); // violates implicit digest -} - -BOOST_AUTO_TEST_CASE(InterestFilterMatching) -{ - BOOST_CHECK_EQUAL(InterestFilter("/a").doesMatch("/a/b"), true); - BOOST_CHECK_EQUAL(InterestFilter("/a/b").doesMatch("/a/b"), true); - BOOST_CHECK_EQUAL(InterestFilter("/a/b/c").doesMatch("/a/b"), false); - - BOOST_CHECK_EQUAL(InterestFilter("/a", "").doesMatch("/a/b"), true); - BOOST_CHECK_EQUAL(InterestFilter("/a/b", "").doesMatch("/a/b"), false); - - BOOST_CHECK_EQUAL(InterestFilter("/a/b", "").doesMatch("/a/b/c/b"), false); - BOOST_CHECK_EQUAL(InterestFilter("/a/b", "<>*").doesMatch("/a/b/c/b"), true); - - BOOST_CHECK_EQUAL(InterestFilter("/a", "").doesMatch("/a/b/c/d"), false); - BOOST_CHECK_EQUAL(InterestFilter("/a", "<>*").doesMatch("/a/b/c/d"), true); - BOOST_CHECK_EQUAL(InterestFilter("/a", "<>*").doesMatch("/a/b"), true); - BOOST_CHECK_EQUAL(InterestFilter("/a", "<>+").doesMatch("/a/b"), false); - BOOST_CHECK_EQUAL(InterestFilter("/a", "<>+").doesMatch("/a/b/c"), true); -} - -BOOST_AUTO_TEST_SUITE_END() // TestInterest - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/key-locator.t.cpp b/tests/unit-tests/key-locator.t.cpp deleted file mode 100644 index 72e4d6622..000000000 --- a/tests/unit-tests/key-locator.t.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "key-locator.hpp" -#include "encoding/block-helpers.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace tests { - -BOOST_AUTO_TEST_SUITE(TestKeyLocator) - -BOOST_AUTO_TEST_CASE(TypeNone) -{ - KeyLocator a; - BOOST_CHECK_EQUAL(a.getType(), KeyLocator::KeyLocator_None); - BOOST_CHECK_THROW(a.getName(), KeyLocator::Error); - BOOST_CHECK_THROW(a.getKeyDigest(), KeyLocator::Error); - - Block wire; - BOOST_REQUIRE_NO_THROW(wire = a.wireEncode()); - - // These octets are obtained by the snippet below. - // This check is intended to detect unexpected encoding change in the future. - // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { - // printf("0x%02x, ", *it); - // } - static const uint8_t expected[] = { - 0x1c, 0x00 - }; - BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), - wire.begin(), wire.end()); - - BOOST_REQUIRE_NO_THROW(KeyLocator(wire)); - KeyLocator b(wire); - BOOST_CHECK(a == b); - BOOST_CHECK_EQUAL(b.getType(), KeyLocator::KeyLocator_None); - BOOST_CHECK_THROW(b.getName(), KeyLocator::Error); - BOOST_CHECK_THROW(b.getKeyDigest(), KeyLocator::Error); -} - -BOOST_AUTO_TEST_CASE(TypeName) -{ - KeyLocator a; - a.setName("/N"); - BOOST_CHECK_EQUAL(a.getType(), KeyLocator::KeyLocator_Name); - BOOST_CHECK_EQUAL(a.getName(), Name("/N")); - BOOST_CHECK_THROW(a.getKeyDigest(), KeyLocator::Error); - - Block wire; - BOOST_REQUIRE_NO_THROW(wire = a.wireEncode()); - - // These octets are obtained by the snippet below. - // This check is intended to detect unexpected encoding change in the future. - // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { - // printf("0x%02x, ", *it); - // } - static const uint8_t expected[] = { - 0x1c, 0x05, 0x07, 0x03, 0x08, 0x01, 0x4e - }; - BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), - wire.begin(), wire.end()); - - BOOST_REQUIRE_NO_THROW(KeyLocator(wire)); - KeyLocator b(wire); - BOOST_CHECK(a == b); - BOOST_CHECK_EQUAL(b.getType(), KeyLocator::KeyLocator_Name); - BOOST_CHECK_EQUAL(b.getName(), Name("/N")); - BOOST_CHECK_THROW(b.getKeyDigest(), KeyLocator::Error); -} - -BOOST_AUTO_TEST_CASE(TypeKeyDigest) -{ - char digestOctets[] = "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"; - ConstBufferPtr digestBuffer = make_shared(digestOctets, 8); - Block expectedDigestBlock = makeBinaryBlock(tlv::KeyDigest, digestOctets, 8); - - KeyLocator a; - a.setKeyDigest(digestBuffer); - BOOST_CHECK_EQUAL(a.getType(), KeyLocator::KeyLocator_KeyDigest); - BOOST_CHECK(a.getKeyDigest() == expectedDigestBlock); - BOOST_CHECK_THROW(a.getName(), KeyLocator::Error); - - Block wire; - BOOST_REQUIRE_NO_THROW(wire = a.wireEncode()); - - // These octets are obtained by the snippet below. - // This check is intended to detect unexpected encoding change in the future. - // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { - // printf("0x%02x, ", *it); - // } - static const uint8_t expected[] = { - 0x1c, 0x0a, 0x1d, 0x08, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd - }; - BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), - wire.begin(), wire.end()); - - BOOST_REQUIRE_NO_THROW(KeyLocator(wire)); - KeyLocator b(wire); - BOOST_CHECK(a == b); - BOOST_CHECK_EQUAL(b.getType(), KeyLocator::KeyLocator_KeyDigest); - BOOST_CHECK(b.getKeyDigest() == expectedDigestBlock); - BOOST_CHECK_THROW(b.getName(), KeyLocator::Error); -} - -BOOST_AUTO_TEST_CASE(Equality) -{ - KeyLocator a; - KeyLocator b; - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - a.setName("ndn:/A"); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setName("ndn:/B"); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setName("ndn:/A"); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - char digestOctets[] = "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"; - ConstBufferPtr digestBuffer = make_shared(digestOctets, 8); - - a.setKeyDigest(digestBuffer); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setKeyDigest(digestBuffer); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); -} - -BOOST_AUTO_TEST_CASE(UnknownType) -{ - static const uint8_t wireOctets[] = { - 0x1c, 0x03, 0x7f, 0x01, 0xcc - }; - Block wire(wireOctets, sizeof(wireOctets)); - BOOST_REQUIRE_NO_THROW(KeyLocator(wire)); - KeyLocator a(wire); - BOOST_CHECK_EQUAL(a.getType(), KeyLocator::KeyLocator_Unknown); - - KeyLocator b(wire); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - b.setName("/N"); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); -} - -BOOST_AUTO_TEST_SUITE_END() // TestKeyLocator - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/link.t.cpp b/tests/unit-tests/link.t.cpp deleted file mode 100644 index 38580366b..000000000 --- a/tests/unit-tests/link.t.cpp +++ /dev/null @@ -1,406 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "link.hpp" -#include "security/key-chain.hpp" -#include "security/v1/cryptopp.hpp" -#include "encoding/buffer-stream.hpp" - -#include "boost-test.hpp" -#include "identity-management-fixture.hpp" - -namespace ndn { -namespace tests { - -BOOST_AUTO_TEST_SUITE(TestLink) - -const uint8_t LinkTest[] = { -0x06, 0xda, // Data - 0x07, 0x14, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x08, 0x06, - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x14, 0x07, // MetaInfo - 0x18, 0x01, // ContentType - 0x01, - 0x19, 0x02, // FreshnessPeriod - 0x27, 0x10, - 0x15, 0x1a, // Content - 0x1f, 0x0c, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x0a, - 0x07, 0x07, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x1f, 0x0a, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x14, - 0x07, 0x05, // Name - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x01, - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x17, 0x80, // SignatureValue - 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, - 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, - 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, - 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, - 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, - 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, - 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, - 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, - 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, - 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1 -}; - -const uint8_t IncorrectContentTypeLink[] = { -0x06, 0xda, // Data - 0x07, 0x14, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x08, 0x06, - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x14, 0x07, // MetaInfo - 0x18, 0x01, // ContentType - 0x02, - 0x19, 0x02, // FreshnessPeriod - 0x27, 0x10, - 0x15, 0x1a, // Content - 0x1f, 0x0c, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x0a, - 0x07, 0x07, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x1f, 0x0a, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x14, - 0x07, 0x05, // Name - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x01, - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x17, 0x80, // SignatureValue - 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, - 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, - 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, - 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, - 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, - 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, - 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, - 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, - 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, - 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1 -}; - -const uint8_t MissingPreferenceLink[] = { -0x06, 0xd7, // Data - 0x07, 0x14, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x08, 0x06, - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x14, 0x07, // MetaInfo - 0x18, 0x01, // ContentType - 0x01, - 0x19, 0x02, // FreshnessPeriod - 0x27, 0x10, - 0x15, 0x17, // Content - 0x1f, 0x09, // LinkDelegation - 0x07, 0x07, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x1f, 0x0a, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x14, - 0x07, 0x05, // Name - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x01, - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x17, 0x80, // SignatureValue - 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, - 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, - 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, - 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, - 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, - 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, - 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, - 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, - 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, - 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1 -}; - -const uint8_t MissingNameLink[] = { -0x06, 0xd1, // Data - 0x07, 0x14, // Name - 0x08, 0x05, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x08, 0x06, - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x14, 0x07, // MetaInfo - 0x18, 0x01, // ContentType - 0x01, - 0x19, 0x02, // FreshnessPeriod - 0x27, 0x10, - 0x15, 0x11, // Content - 0x1f, 0x03, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x0a, - 0x1f, 0x0a, // LinkDelegation - 0x1e, 0x01, // LinkPreference - 0x14, - 0x07, 0x05, // Name - 0x08, 0x03, - 0x6e, 0x64, 0x6e, - 0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x01, - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x17, 0x80, // SignatureValue - 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, - 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, - 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, - 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, - 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, - 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, - 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, - 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, - 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, - 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1 -}; - -BOOST_AUTO_TEST_CASE(PairParsingCheck) -{ - Link link("test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}}); - BOOST_CHECK_EQUAL(link.getDelegations().size(), static_cast(3)); -} - -BOOST_AUTO_TEST_CASE(CheckInsertDelegation) -{ - Link link("test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}}); - - link.addDelegation(30, Name("test4")); - Link::DelegationSet delegations = link.getDelegations(); - int counter = 0; - for (auto i = delegations.begin(); i != delegations.end(); i++) { - counter++; - if (counter == 1) - { - BOOST_CHECK_EQUAL(std::get<0>(*i), 10); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test1")); - } - if (counter == 2) - { - BOOST_CHECK_EQUAL(std::get<0>(*i), 20); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test2")); - } - if (counter == 3) - { - BOOST_CHECK_EQUAL(std::get<0>(*i), 30); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test4")); - } - if (counter == 4) - { - BOOST_CHECK_EQUAL(std::get<0>(*i), 100); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test3")); - } - } -} - -BOOST_AUTO_TEST_CASE(CheckRemoveDelegation) -{ - Link link("test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}}); - - link.removeDelegation(Name("test2")); - Link::DelegationSet delegations = link.getDelegations(); - int counter = 0; - for (auto i = delegations.begin(); i != delegations.end(); i++) { - counter++; - if (counter == 1) - { - BOOST_CHECK_EQUAL(std::get<0>(*i), 10); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test1")); - } - if (counter == 2) - { - BOOST_CHECK_EQUAL(std::get<0>(*i), 100); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test3")); - } - } -} - -BOOST_FIXTURE_TEST_CASE(CheckEncodeDecode, IdentityManagementFixture) -{ - Link link1("test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}}); - m_keyChain.sign(link1); - Block wire = link1.wireEncode(); - - Link link2; - link2.wireDecode(wire); - Name name = link2.getName(); - BOOST_CHECK_EQUAL(Name("test"), name); - - Link::DelegationSet delegations; - delegations = link2.getDelegations(); - int counter = 0; - for (auto i = delegations.begin(); i != delegations.end(); i++) { - counter++; - if (counter == 1) - { - BOOST_CHECK_EQUAL(std::get<0>(*i), 10); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test1")); - } - if (counter == 2) - { - BOOST_CHECK_EQUAL(std::get<0>(*i), 20); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test2")); - } - if (counter == 3) - { - BOOST_CHECK_EQUAL(std::get<0>(*i), 100); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test3")); - } - } - - Link link3(wire); - name = link3.getName(); - BOOST_CHECK_EQUAL(Name("test"), name); - - delegations = link3.getDelegations(); - counter = 0; - for (auto i = delegations.begin(); i != delegations.end(); i++) { - counter++; - if (counter == 1) - { - BOOST_CHECK_EQUAL(std::get<0>(*i), 10); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test1")); - } - if (counter == 2) - { - BOOST_CHECK_EQUAL(std::get<0>(*i), 20); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test2")); - } - if (counter == 3) - { - BOOST_CHECK_EQUAL(std::get<0>(*i), 100); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test3")); - } - } -} - -BOOST_AUTO_TEST_CASE(Decode) -{ - Block linkBlock(LinkTest, sizeof(LinkTest)); - Link link(linkBlock); - BOOST_CHECK_EQUAL(link.getName(), Name("/local/ndn/prefix")); - Link::DelegationSet delegations = link.getDelegations(); - int counter = 0; - - for (auto i = delegations.begin(); i != delegations.end(); i++) { - counter++; - if (counter == 1) - { - BOOST_CHECK_EQUAL(std::get<0>(*i), 10); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("local")); - } - if (counter == 2) - { - BOOST_CHECK_EQUAL(std::get<0>(*i), 20); - BOOST_CHECK_EQUAL(std::get<1>(*i), Name("ndn")); - } - } -} - -BOOST_AUTO_TEST_CASE(CountDelegationFromWire) -{ - Block linkBlock(LinkTest, sizeof(LinkTest)); - BOOST_CHECK_EQUAL(Link::countDelegationsFromWire(linkBlock), 2); -} - -BOOST_AUTO_TEST_CASE(IncorrectContentType) -{ - Block linkBlock(IncorrectContentTypeLink, sizeof(IncorrectContentTypeLink)); - Link link; - BOOST_REQUIRE_THROW(link.wireDecode(linkBlock), Link::Error); -} - -BOOST_AUTO_TEST_CASE(MissingPreferenceEncoding) -{ - Block linkBlock(MissingPreferenceLink, sizeof(MissingPreferenceLink)); - Link link; - BOOST_REQUIRE_THROW(link.wireDecode(linkBlock), Link::Error); -} - -BOOST_AUTO_TEST_CASE(MissingNameEncoding) -{ - Block linkBlock(MissingNameLink, sizeof(MissingNameLink)); - Link link; - BOOST_REQUIRE_THROW(link.wireDecode(linkBlock), Link::Error); -} - -BOOST_AUTO_TEST_SUITE_END() // TestLink - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/lp/packet.t.cpp b/tests/unit-tests/lp/packet.t.cpp deleted file mode 100644 index 0a7f1d5a6..000000000 --- a/tests/unit-tests/lp/packet.t.cpp +++ /dev/null @@ -1,341 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "lp/packet.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace lp { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Lp) -BOOST_AUTO_TEST_SUITE(TestPacket) - -BOOST_AUTO_TEST_CASE(FieldAccess) -{ - Packet packet; - - BOOST_CHECK(!packet.has()); - BOOST_CHECK_EQUAL(0, packet.count()); - BOOST_CHECK_NO_THROW(packet.set(1234)); - BOOST_CHECK(packet.has()); - BOOST_CHECK_THROW(packet.add(5678), std::length_error); - BOOST_CHECK_EQUAL(1, packet.count()); - BOOST_CHECK_EQUAL(1234, packet.get(0)); - BOOST_CHECK_THROW(packet.get(1), std::out_of_range); - BOOST_CHECK_THROW(packet.remove(1), std::out_of_range); - BOOST_CHECK_NO_THROW(packet.remove(0)); - BOOST_CHECK_EQUAL(0, packet.count()); - BOOST_CHECK_NO_THROW(packet.add(832)); - std::vector fragIndexes; - BOOST_REQUIRE_NO_THROW(fragIndexes = packet.list()); - BOOST_CHECK_EQUAL(1, fragIndexes.size()); - BOOST_CHECK_EQUAL(832, fragIndexes.at(0)); - BOOST_CHECK_NO_THROW(packet.clear()); - BOOST_CHECK_EQUAL(0, packet.count()); -} - -/// \todo test field access methods with a REPEATABLE field - -BOOST_AUTO_TEST_CASE(EncodeFragment) -{ - static const uint8_t expectedBlock[] = { - 0x64, 0x08, // LpPacket - 0x51, 0x02, // Sequence - 0x03, 0xe8, - 0x50, 0x02, // Fragment - 0x03, 0xe8, - }; - - Buffer buf(2); - buf[0] = 0x03; - buf[1] = 0xe8; - - Packet packet; - BOOST_CHECK_NO_THROW(packet.add(std::make_pair(buf.begin(), buf.end()))); - BOOST_CHECK_NO_THROW(packet.add(1000)); - Block wire; - BOOST_CHECK_NO_THROW(wire = packet.wireEncode()); - BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock), - wire.begin(), wire.end()); -} - -BOOST_AUTO_TEST_CASE(EncodeSubTlv) -{ - static const uint8_t expectedBlock[] = { - 0x64, 0x09, // LpPacket - 0xfd, 0x03, 0x20, 0x05, // Nack - 0xfd, 0x03, 0x21, 0x01, // NackReason - 0x64, - }; - - NackHeader nack; - nack.setReason(NackReason::DUPLICATE); - - Packet packet; - BOOST_CHECK_NO_THROW(packet.add(nack)); - Block wire; - BOOST_REQUIRE_NO_THROW(wire = packet.wireEncode()); - BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock), - wire.begin(), wire.end()); -} - -BOOST_AUTO_TEST_CASE(EncodeSortOrder) -{ - static const uint8_t expectedBlock[] = { - 0x64, 0x0a, // LpPacket - 0x52, 0x01, // FragIndex - 0x00, - 0x53, 0x01, // FragCount - 0x01, - 0x50, 0x02, // Fragment - 0x03, 0xe8, - }; - - Buffer frag(2); - frag[0] = 0x03; - frag[1] = 0xe8; - - Packet packet; - BOOST_CHECK_NO_THROW(packet.add(std::make_pair(frag.begin(), frag.end()))); - BOOST_CHECK_NO_THROW(packet.add(0)); - BOOST_CHECK_NO_THROW(packet.add(1)); - Block wire; - BOOST_REQUIRE_NO_THROW(wire = packet.wireEncode()); - BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock), - wire.begin(), wire.end()); -} - -BOOST_AUTO_TEST_CASE(DecodeNormal) -{ - static const uint8_t inputBlock[] = { - 0x64, 0x0a, // LpPacket - 0x52, 0x01, // FragIndex - 0x00, - 0x53, 0x01, // FragCount - 0x01, - 0x50, 0x02, // Fragment - 0x03, 0xe8, - }; - - Packet packet; - Block wire(inputBlock, sizeof(inputBlock)); - BOOST_CHECK_NO_THROW(packet.wireDecode(wire)); - BOOST_CHECK_EQUAL(1, packet.count()); - BOOST_CHECK_EQUAL(1, packet.count()); - BOOST_CHECK_EQUAL(1, packet.count()); - Buffer::const_iterator first, last; - BOOST_REQUIRE_NO_THROW(std::tie(first, last) = packet.get(0)); - BOOST_CHECK_EQUAL(2, last - first); - BOOST_CHECK_EQUAL(0x03, *first); - BOOST_CHECK_EQUAL(0xe8, *(last - 1)); - BOOST_CHECK_EQUAL(0, packet.get(0)); - BOOST_CHECK_EQUAL(1, packet.get(0)); -} - -BOOST_AUTO_TEST_CASE(DecodeIdle) -{ - static const uint8_t inputBlock[] = { - 0x64, 0x06, // LpPacket - 0x52, 0x01, // FragIndex - 0x00, - 0x53, 0x01, // FragCount - 0x01, - }; - - Packet packet; - Block wire(inputBlock, sizeof(inputBlock)); - BOOST_CHECK_NO_THROW(packet.wireDecode(wire)); - BOOST_CHECK_EQUAL(0, packet.count()); - BOOST_CHECK_EQUAL(1, packet.count()); - BOOST_CHECK_EQUAL(1, packet.count()); - BOOST_CHECK_EQUAL(0, packet.get(0)); - BOOST_CHECK_EQUAL(1, packet.get(0)); -} - -BOOST_AUTO_TEST_CASE(DecodeFragment) -{ - static const uint8_t inputBlock[] = { - 0x64, 0x04, // LpPacket - 0x50, 0x02, // Fragment - 0x03, 0xe8, - }; - - Packet packet; - Block wire(inputBlock, sizeof(inputBlock)); - BOOST_CHECK_NO_THROW(packet.wireDecode(wire)); - BOOST_CHECK_EQUAL(1, packet.count()); - BOOST_CHECK_EQUAL(0, packet.count()); - Buffer::const_iterator first, last; - BOOST_REQUIRE_NO_THROW(std::tie(first, last) = packet.get(0)); - BOOST_CHECK_EQUAL(2, last - first); - BOOST_CHECK_EQUAL(0x03, *first); - BOOST_CHECK_EQUAL(0xe8, *(last - 1)); -} - -BOOST_AUTO_TEST_CASE(DecodeEmpty) -{ - static const uint8_t inputBlock[] = { - 0x64, 0x00, // LpPacket - }; - - Packet packet; - Block wire(inputBlock, sizeof(inputBlock)); - BOOST_CHECK_NO_THROW(packet.wireDecode(wire)); - BOOST_CHECK_EQUAL(0, packet.count()); - BOOST_CHECK_EQUAL(0, packet.count()); -} - -BOOST_AUTO_TEST_CASE(DecodeRepeatedNonRepeatableHeader) -{ - static const uint8_t inputBlock[] = { - 0x64, 0x06, // LpPacket - 0x52, 0x01, // FragIndex - 0x00, - 0x52, 0x01, // FragIndex - 0x01, - }; - - Packet packet; - Block wire(inputBlock, sizeof(inputBlock)); - BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error); -} - -BOOST_AUTO_TEST_CASE(DecodeRepeatedFragment) -{ - static const uint8_t inputBlock[] = { - 0x64, 0x08, // LpPacket - 0x50, 0x02, // Fragment - 0x03, 0xe8, - 0x50, 0x02, // Fragment - 0x03, 0xe9, - }; - - Packet packet; - Block wire(inputBlock, sizeof(inputBlock)); - BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error); -} - -BOOST_AUTO_TEST_CASE(DecodeWrongOrderAmongHeaders) -{ - static const uint8_t inputBlock[] = { - 0x64, 0x0a, // LpPacket - 0x53, 0x01, // FragCount - 0x01, - 0x52, 0x01, // FragIndex - 0x00, - 0x50, 0x02, // Fragment - 0x03, 0xe8, - }; - - Packet packet; - Block wire(inputBlock, sizeof(inputBlock)); - BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error); -} - -BOOST_AUTO_TEST_CASE(DecodeWrongOrderFragment) -{ - static const uint8_t inputBlock[] = { - 0x64, 0x0a, // LpPacket - 0x52, 0x01, // FragIndex - 0x00, - 0x50, 0x02, // Fragment - 0x03, 0xe8, - 0x53, 0x01, // FragCount - 0x01, - }; - - Packet packet; - Block wire(inputBlock, sizeof(inputBlock)); - BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error); -} - -BOOST_AUTO_TEST_CASE(DecodeIgnoredHeader) -{ - static const uint8_t inputBlock[] = { - 0x64, 0x0c, // LpPacket - 0x52, 0x01, // FragIndex - 0x00, - 0xfd, 0x03, 0x23, 0x01, // unknown TLV-TYPE 803 (ignored) - 0x02, - 0x50, 0x02, // Fragment - 0x03, 0xe8, - }; - - Packet packet; - Block wire(inputBlock, sizeof(inputBlock)); - BOOST_CHECK_NO_THROW(packet.wireDecode(wire)); - BOOST_CHECK_EQUAL(1, packet.count()); - BOOST_CHECK_EQUAL(1, packet.count()); -} - -BOOST_AUTO_TEST_CASE(DecodeUnrecognizedHeader) -{ - static const uint8_t inputBlock[] = { - 0x64, 0x0c, // LpPacket - 0x52, 0x01, // FragIndex - 0x00, - 0xfd, 0x03, 0x22, 0x01, // unknown TLV-TYPE 802 (cannot ignore) - 0x02, - 0x50, 0x02, // Fragment - 0x03, 0xe8, - }; - - Packet packet; - Block wire(inputBlock, sizeof(inputBlock)); - BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error); -} - -BOOST_AUTO_TEST_CASE(DecodeBareNetworkLayerPacket) -{ - static const uint8_t inputBlock[] = { - 0x05, 0x0a, // Interest - 0x07, 0x02, // Name - 0x03, 0xe8, - 0x0a, 0x04, // Nonce - 0x01, 0x02, 0x03, 0x04, - }; - - Packet packet; - Block wire(inputBlock, sizeof(inputBlock)); - BOOST_CHECK_NO_THROW(packet.wireDecode(wire)); - BOOST_CHECK_EQUAL(1, packet.count()); - - Block encoded; - BOOST_CHECK_NO_THROW(encoded = packet.wireEncode()); - BOOST_CHECK_EQUAL_COLLECTIONS(inputBlock, inputBlock + sizeof(inputBlock), - encoded.begin(), encoded.end()); -} - -BOOST_AUTO_TEST_CASE(DecodeUnrecognizedTlvType) -{ - Packet packet; - Block wire = encoding::makeEmptyBlock(ndn::tlv::Name); - BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error); -} - -BOOST_AUTO_TEST_SUITE_END() // TestPacket -BOOST_AUTO_TEST_SUITE_END() // Lp - -} // namespace tests -} // namespace lp -} // namespace ndn diff --git a/tests/unit-tests/make-interest-data.hpp b/tests/unit-tests/make-interest-data.hpp deleted file mode 100644 index 8dea8bf86..000000000 --- a/tests/unit-tests/make-interest-data.hpp +++ /dev/null @@ -1,111 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_TESTS_UNIT_TESTS_MAKE_INTEREST_DATA_HPP -#define NDN_TESTS_UNIT_TESTS_MAKE_INTEREST_DATA_HPP - -#include "interest.hpp" -#include "data.hpp" -#include "link.hpp" -#include "lp/nack.hpp" - -namespace ndn { -namespace tests { - -/** \brief create an Interest - * \param name Interest name - * \param nonce if non-zero, set Nonce to this value - * (useful for creating Nack with same Nonce) - */ -shared_ptr -makeInterest(const Name& name, uint32_t nonce = 0); - -/** \brief create a Data with fake signature - * \note Data may be modified afterwards without losing the fake signature. - * If a real signature is desired, sign again with KeyChain. - */ -shared_ptr -makeData(const Name& name); - -/** \brief add a fake signature to Data - */ -Data& -signData(Data& data); - -/** \brief add a fake signature to Data - */ -inline shared_ptr -signData(shared_ptr data) -{ - signData(*data); - return data; -} - -/** \brief create a Link object with fake signature - * \note Link may be modified afterwards without losing the fake signature. - * If a real signature is desired, sign again with KeyChain. - */ -shared_ptr -makeLink(const Name& name, std::initializer_list> delegations); - -/** \brief create a Nack - * \param interest Interest - * \param reason Nack reason - */ -lp::Nack -makeNack(const Interest& interest, lp::NackReason reason); - -/** \brief create a Nack - * \param name Interest name - * \param nonce Interest nonce - * \param reason Nack reason - */ -lp::Nack -makeNack(const Name& name, uint32_t nonce, lp::NackReason reason); - -/** \brief replace a name component - * \param[inout] name name - * \param index name component index - * \param a arguments to name::Component constructor - */ -template -void -setNameComponent(Name& name, ssize_t index, const A& ...a) -{ - Name name2 = name.getPrefix(index); - name2.append(name::Component(a...)); - name2.append(name.getSubName(name2.size())); - name = name2; -} - -template -void -setNameComponent(PKT& pkt, ssize_t index, const A& ...a) -{ - Name name = pkt.getName(); - setNameComponent(name, index, a...); - pkt.setName(name); -} - -} // namespace tests -} // namespace ndn - -#endif // NDN_TESTS_UNIT_TESTS_MAKE_INTEREST_DATA_HPP diff --git a/tests/unit-tests/meta-info.t.cpp b/tests/unit-tests/meta-info.t.cpp deleted file mode 100644 index 3fd8b3c32..000000000 --- a/tests/unit-tests/meta-info.t.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "meta-info.hpp" - -#include "data.hpp" -#include "security/key-chain.hpp" -#include "security/v1/cryptopp.hpp" -#include "encoding/buffer-stream.hpp" -#include "boost-test.hpp" - -namespace ndn { -namespace tests { - -BOOST_AUTO_TEST_SUITE(TestMetaInfo) - -const uint8_t MetaInfo1[] = {0x14, 0x04, 0x19, 0x02, 0x27, 0x10}; -const uint8_t MetaInfo2[] = {0x14, 0x14, 0x19, 0x02, 0x27, 0x10, 0x1a, 0x0e, 0x08, 0x0c, - 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x77, 0x6f, 0x72, 0x6c, - 0x64, 0x21}; -const uint8_t MetaInfo3[] = {0x14, 0x17, 0x18, 0x01, 0x01, 0x19, 0x02, 0x27, 0x10, 0x1a, - 0x0e, 0x08, 0x0c, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x77, - 0x6f, 0x72, 0x6c, 0x64, 0x21}; - -BOOST_AUTO_TEST_CASE(Encode) -{ - MetaInfo meta; - meta.setType(tlv::ContentType_Blob); - meta.setFreshnessPeriod(time::seconds(10)); - - BOOST_REQUIRE_NO_THROW(meta.wireEncode()); - BOOST_REQUIRE_EQUAL_COLLECTIONS(MetaInfo1, MetaInfo1+sizeof(MetaInfo1), - meta.wireEncode().begin(), meta.wireEncode().end()); - - meta.setFinalBlockId(name::Component("hello,world!")); - BOOST_REQUIRE_NO_THROW(meta.wireEncode()); - BOOST_REQUIRE_EQUAL_COLLECTIONS(MetaInfo2, MetaInfo2+sizeof(MetaInfo2), - meta.wireEncode().begin(), meta.wireEncode().end()); - - meta.setType(tlv::ContentType_Link); - BOOST_REQUIRE_NO_THROW(meta.wireEncode()); - BOOST_REQUIRE_EQUAL_COLLECTIONS(MetaInfo3, MetaInfo3+sizeof(MetaInfo3), - meta.wireEncode().begin(), meta.wireEncode().end()); -} - -BOOST_AUTO_TEST_CASE(Decode) -{ - MetaInfo meta(Block(MetaInfo1, sizeof(MetaInfo1))); - BOOST_CHECK_EQUAL(meta.getType(), static_cast(tlv::ContentType_Blob)); - BOOST_CHECK_EQUAL(meta.getFreshnessPeriod(), time::seconds(10)); - BOOST_CHECK_EQUAL(meta.getFinalBlockId(), name::Component()); - - meta.wireDecode(Block(MetaInfo2, sizeof(MetaInfo2))); - BOOST_CHECK_EQUAL(meta.getType(), static_cast(tlv::ContentType_Blob)); - BOOST_CHECK_EQUAL(meta.getFreshnessPeriod(), time::seconds(10)); - BOOST_CHECK_EQUAL(meta.getFinalBlockId(), name::Component("hello,world!")); - - meta.wireDecode(Block(MetaInfo3, sizeof(MetaInfo3))); - BOOST_CHECK_EQUAL(meta.getType(), static_cast(tlv::ContentType_Link)); - BOOST_CHECK_EQUAL(meta.getFreshnessPeriod(), time::seconds(10)); - BOOST_CHECK_EQUAL(meta.getFinalBlockId(), name::Component("hello,world!")); -} - -BOOST_AUTO_TEST_CASE(EqualityChecks) -{ - using namespace time; - - MetaInfo a; - MetaInfo b; - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - a.setFreshnessPeriod(seconds(10)); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setFreshnessPeriod(milliseconds(90000)); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setFreshnessPeriod(milliseconds(10000)); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); - - a.setType(10); - BOOST_CHECK_EQUAL(a == b, false); - BOOST_CHECK_EQUAL(a != b, true); - - b.setType(10); - BOOST_CHECK_EQUAL(a == b, true); - BOOST_CHECK_EQUAL(a != b, false); -} - -BOOST_AUTO_TEST_CASE(AppMetaInfo) -{ - MetaInfo info1; - info1.setType(196); - info1.setFreshnessPeriod(time::milliseconds(3600)); - info1.setFinalBlockId(name::Component("/att/final")); - - uint32_t ints[5] = {128, 129, 130, 131, 132}; - std::string ss[5] = {"h", "hello", "hello, world", "hello, world, alex", - "hello, world, alex, I am Xiaoke Jiang"}; - - for (int i = 0; i < 5; i++) { - uint32_t type = 128 + i * 10; - info1.addAppMetaInfo(makeNonNegativeIntegerBlock(type, ints[i])); - const std::string& s = ss[i]; - type += 5; - info1.addAppMetaInfo(makeStringBlock(type, s)); - } - - BOOST_CHECK(info1.findAppMetaInfo(252) == 0); - - info1.addAppMetaInfo(makeNonNegativeIntegerBlock(252, 1000)); - BOOST_CHECK(info1.findAppMetaInfo(252) != 0); - - info1.addAppMetaInfo(makeNonNegativeIntegerBlock(252, 1000)); - BOOST_CHECK(info1.findAppMetaInfo(252) != 0); - - info1.removeAppMetaInfo(252); - BOOST_CHECK(info1.findAppMetaInfo(252) != 0); - - info1.removeAppMetaInfo(252); - BOOST_CHECK(info1.findAppMetaInfo(252) == 0); - - // // These octets are obtained by the snippet below. - // // This check is intended to detect unexpected encoding change in the future. - // const Block& wire = info1.wireEncode(); - // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { - // printf("0x%02x, ", *it); - // } - - const uint8_t METAINFO[] = {0x14, 0x77, 0x18, 0x01, 0xc4, 0x19, 0x02, 0x0e, 0x10, 0x1a, 0x0c, - 0x08, 0x0a, 0x2f, 0x61, 0x74, 0x74, 0x2f, 0x66, 0x69, 0x6e, 0x61, - 0x6c, 0x80, 0x01, 0x80, 0x85, 0x01, 0x68, 0x8a, 0x01, 0x81, 0x8f, - 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x94, 0x01, 0x82, 0x99, 0x0c, - 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, - 0x64, 0x9e, 0x01, 0x83, 0xa3, 0x12, 0x68, 0x65, 0x6c, 0x6c, 0x6f, - 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2c, 0x20, 0x61, 0x6c, - 0x65, 0x78, 0xa8, 0x01, 0x84, 0xad, 0x25, 0x68, 0x65, 0x6c, 0x6c, - 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2c, 0x20, 0x61, - 0x6c, 0x65, 0x78, 0x2c, 0x20, 0x49, 0x20, 0x61, 0x6d, 0x20, 0x58, - 0x69, 0x61, 0x6f, 0x6b, 0x65, 0x20, 0x4a, 0x69, 0x61, 0x6e, 0x67}; - - BOOST_REQUIRE_EQUAL_COLLECTIONS(info1.wireEncode().begin(), info1.wireEncode().end(), - METAINFO, METAINFO + sizeof(METAINFO)); - - MetaInfo info2; - info2.wireDecode(Block(METAINFO, sizeof(METAINFO))); - - for (int i = 0; i < 5; i++) { - uint32_t tlvType = 128 + i * 10; - const Block* block = info2.findAppMetaInfo(tlvType); - BOOST_REQUIRE(block != 0); - BOOST_CHECK_EQUAL(readNonNegativeInteger(*block), ints[i]); - tlvType += 5; - - block = info2.findAppMetaInfo(tlvType); - BOOST_REQUIRE(block != 0); - - std::string s3 = std::string(reinterpret_cast(block->value()), - block->value_size()); - BOOST_CHECK_EQUAL(s3, ss[i]); - } -} - -BOOST_AUTO_TEST_CASE(AppMetaInfoTypeRange) -{ - MetaInfo info; - - BOOST_CHECK_NO_THROW(info.addAppMetaInfo(makeNonNegativeIntegerBlock(128, 1000))); - BOOST_CHECK_NO_THROW(info.addAppMetaInfo(makeNonNegativeIntegerBlock(252, 1000))); - - BOOST_CHECK_THROW(info.addAppMetaInfo(makeNonNegativeIntegerBlock(127, 1000)), MetaInfo::Error); - BOOST_CHECK_THROW(info.addAppMetaInfo(makeNonNegativeIntegerBlock(253, 1000)), MetaInfo::Error); -} - -BOOST_AUTO_TEST_SUITE_END() // TestMetaInfo - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/mgmt/dispatcher.t.cpp b/tests/unit-tests/mgmt/dispatcher.t.cpp deleted file mode 100644 index 76e5c6c96..000000000 --- a/tests/unit-tests/mgmt/dispatcher.t.cpp +++ /dev/null @@ -1,427 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "mgmt/dispatcher.hpp" -#include "mgmt/nfd/control-parameters.hpp" -#include "util/dummy-client-face.hpp" - -#include "boost-test.hpp" -#include "identity-management-fixture.hpp" -#include "../identity-management-time-fixture.hpp" -#include "../make-interest-data.hpp" - -namespace ndn { -namespace mgmt { -namespace tests { - -using namespace ndn::tests; - -BOOST_AUTO_TEST_SUITE(Mgmt) -BOOST_AUTO_TEST_SUITE(TestDispatcher) - -class DispatcherFixture : public IdentityManagementTimeFixture -{ -public: - DispatcherFixture() - : face(io, m_keyChain, {true, true}) - , dispatcher(face, m_keyChain, security::SigningInfo()) - , storage(dispatcher.m_storage) - { - } - -public: - util::DummyClientFace face; - mgmt::Dispatcher dispatcher; - util::InMemoryStorageFifo& storage; -}; - -class VoidParameters : public mgmt::ControlParameters -{ -public: - explicit - VoidParameters(const Block& wire) - { - wireDecode(wire); - } - - virtual Block - wireEncode() const final - { - return Block(128); - } - - virtual void - wireDecode(const Block& wire) final - { - if (wire.type() != 128) - throw tlv::Error("Expecting TLV type 128"); - } -}; - -static Authorization -makeTestAuthorization() -{ - return [] (const Name& prefix, - const Interest& interest, - const ControlParameters* params, - AcceptContinuation accept, - RejectContinuation reject) { - if (interest.getName()[-1] == name::Component("valid")) { - accept(""); - } - else { - if (interest.getName()[-1] == name::Component("silent")) { - reject(RejectReply::SILENT); - } - else { - reject(RejectReply::STATUS403); - } - } - }; -} - -BOOST_FIXTURE_TEST_CASE(Basic, DispatcherFixture) -{ - BOOST_CHECK_NO_THROW(dispatcher - .addControlCommand("test/1", makeAcceptAllAuthorization(), - bind([] { return true; }), - bind([]{}))); - BOOST_CHECK_NO_THROW(dispatcher - .addControlCommand("test/2", makeAcceptAllAuthorization(), - bind([] { return true; }), - bind([]{}))); - - BOOST_CHECK_THROW(dispatcher - .addControlCommand("test", makeAcceptAllAuthorization(), - bind([] { return true; }), - bind([]{})), - std::out_of_range); - - BOOST_CHECK_NO_THROW(dispatcher.addStatusDataset("status/1", - makeAcceptAllAuthorization(), bind([]{}))); - BOOST_CHECK_NO_THROW(dispatcher.addStatusDataset("status/2", - makeAcceptAllAuthorization(), bind([]{}))); - BOOST_CHECK_THROW(dispatcher.addStatusDataset("status", - makeAcceptAllAuthorization(), bind([]{})), - std::out_of_range); - - BOOST_CHECK_NO_THROW(dispatcher.addNotificationStream("stream/1")); - BOOST_CHECK_NO_THROW(dispatcher.addNotificationStream("stream/2")); - BOOST_CHECK_THROW(dispatcher.addNotificationStream("stream"), std::out_of_range); - - - BOOST_CHECK_NO_THROW(dispatcher.addTopPrefix("/root/1")); - BOOST_CHECK_NO_THROW(dispatcher.addTopPrefix("/root/2")); - BOOST_CHECK_THROW(dispatcher.addTopPrefix("/root"), std::out_of_range); - - BOOST_CHECK_THROW(dispatcher - .addControlCommand("test/3", makeAcceptAllAuthorization(), - bind([] { return true; }), - bind([]{})), - std::domain_error); - - BOOST_CHECK_THROW(dispatcher.addStatusDataset("status/3", - makeAcceptAllAuthorization(), bind([]{})), - std::domain_error); - - BOOST_CHECK_THROW(dispatcher.addNotificationStream("stream/3"), std::domain_error); -} - -BOOST_FIXTURE_TEST_CASE(AddRemoveTopPrefix, DispatcherFixture) -{ - std::map nCallbackCalled; - dispatcher - .addControlCommand("test/1", makeAcceptAllAuthorization(), - bind([] { return true; }), - bind([&nCallbackCalled] { ++nCallbackCalled["test/1"]; })); - - dispatcher - .addControlCommand("test/2", makeAcceptAllAuthorization(), - bind([] { return true; }), - bind([&nCallbackCalled] { ++nCallbackCalled["test/2"]; })); - - face.receive(*makeInterest("/root/1/test/1/%80%00")); - advanceClocks(time::milliseconds(1)); - BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 0); - BOOST_CHECK_EQUAL(nCallbackCalled["test/2"], 0); - - dispatcher.addTopPrefix("/root/1"); - advanceClocks(time::milliseconds(1)); - - face.receive(*makeInterest("/root/1/test/1/%80%00")); - advanceClocks(time::milliseconds(1)); - BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 1); - BOOST_CHECK_EQUAL(nCallbackCalled["test/2"], 0); - - face.receive(*makeInterest("/root/1/test/2/%80%00")); - advanceClocks(time::milliseconds(1)); - BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 1); - BOOST_CHECK_EQUAL(nCallbackCalled["test/2"], 1); - - face.receive(*makeInterest("/root/2/test/1/%80%00")); - face.receive(*makeInterest("/root/2/test/2/%80%00")); - advanceClocks(time::milliseconds(1)); - BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 1); - BOOST_CHECK_EQUAL(nCallbackCalled["test/2"], 1); - - dispatcher.addTopPrefix("/root/2"); - advanceClocks(time::milliseconds(1)); - - face.receive(*makeInterest("/root/1/test/1/%80%00")); - advanceClocks(time::milliseconds(1)); - BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 2); - - face.receive(*makeInterest("/root/2/test/1/%80%00")); - advanceClocks(time::milliseconds(1)); - BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 3); - - dispatcher.removeTopPrefix("/root/1"); - advanceClocks(time::milliseconds(1)); - - face.receive(*makeInterest("/root/1/test/1/%80%00")); - advanceClocks(time::milliseconds(1)); - BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 3); - - face.receive(*makeInterest("/root/2/test/1/%80%00")); - advanceClocks(time::milliseconds(1)); - BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 4); -} - -BOOST_FIXTURE_TEST_CASE(ControlCommand, DispatcherFixture) -{ - size_t nCallbackCalled = 0; - dispatcher - .addControlCommand("test", - makeTestAuthorization(), - bind([] { return true; }), - bind([&nCallbackCalled] { ++nCallbackCalled; })); - - dispatcher.addTopPrefix("/root"); - advanceClocks(time::milliseconds(1)); - face.sentData.clear(); - - face.receive(*makeInterest("/root/test/%80%00")); // returns 403 - face.receive(*makeInterest("/root/test/%80%00/invalid")); // returns 403 - face.receive(*makeInterest("/root/test/%80%00/silent")); // silently ignored - face.receive(*makeInterest("/root/test/.../invalid")); // silently ignored (wrong format) - face.receive(*makeInterest("/root/test/.../valid")); // silently ignored (wrong format) - advanceClocks(time::milliseconds(1), 20); - BOOST_CHECK_EQUAL(nCallbackCalled, 0); - BOOST_CHECK_EQUAL(face.sentData.size(), 2); - - BOOST_CHECK(face.sentData[0].getContentType() == tlv::ContentType_Blob); - BOOST_CHECK_EQUAL(ControlResponse(face.sentData[0].getContent().blockFromValue()).getCode(), 403); - BOOST_CHECK(face.sentData[1].getContentType() == tlv::ContentType_Blob); - BOOST_CHECK_EQUAL(ControlResponse(face.sentData[1].getContent().blockFromValue()).getCode(), 403); - - face.receive(*makeInterest("/root/test/%80%00/valid")); - advanceClocks(time::milliseconds(1), 10); - BOOST_CHECK_EQUAL(nCallbackCalled, 1); -} - -BOOST_FIXTURE_TEST_CASE(StatusDataset, DispatcherFixture) -{ - static Block smallBlock("\x81\x01\0x01", 3); - static Block largeBlock = [] () -> Block { - EncodingBuffer encoder; - for (size_t i = 0; i < 2500; ++i) { - encoder.prependByte(1); - } - encoder.prependVarNumber(2500); - encoder.prependVarNumber(129); - return encoder.block(); - }(); - - dispatcher.addStatusDataset("test/small", - makeTestAuthorization(), - [] (const Name& prefix, const Interest& interest, - StatusDatasetContext& context) { - context.append(smallBlock); - context.append(smallBlock); - context.append(smallBlock); - context.end(); - }); - - dispatcher.addStatusDataset("test/large", - makeTestAuthorization(), - [] (const Name& prefix, const Interest& interest, - StatusDatasetContext& context) { - context.append(largeBlock); - context.append(largeBlock); - context.append(largeBlock); - context.end(); - }); - - dispatcher.addStatusDataset("test/reject", - makeTestAuthorization(), - [] (const Name& prefix, const Interest& interest, - StatusDatasetContext& context) { - context.reject(); - }); - - dispatcher.addTopPrefix("/root"); - advanceClocks(time::milliseconds(1)); - face.sentData.clear(); - - face.receive(*makeInterest("/root/test/small/%80%00")); // returns 403 - face.receive(*makeInterest("/root/test/small/%80%00/invalid")); // returns 403 - face.receive(*makeInterest("/root/test/small/%80%00/silent")); // silently ignored - advanceClocks(time::milliseconds(1), 20); - BOOST_CHECK_EQUAL(face.sentData.size(), 2); - - BOOST_CHECK(face.sentData[0].getContentType() == tlv::ContentType_Blob); - BOOST_CHECK_EQUAL(ControlResponse(face.sentData[0].getContent().blockFromValue()).getCode(), 403); - BOOST_CHECK(face.sentData[1].getContentType() == tlv::ContentType_Blob); - BOOST_CHECK_EQUAL(ControlResponse(face.sentData[1].getContent().blockFromValue()).getCode(), 403); - - face.sentData.clear(); - - auto interestSmall = *makeInterest("/root/test/small/valid"); - face.receive(interestSmall); - advanceClocks(time::milliseconds(1), 10); - - // one data packet is generated and sent to both places - BOOST_CHECK_EQUAL(face.sentData.size(), 1); - BOOST_CHECK_EQUAL(storage.size(), 1); - - auto fetchedData = storage.find(interestSmall); - BOOST_REQUIRE(fetchedData != nullptr); - BOOST_CHECK(face.sentData[0].wireEncode() == fetchedData->wireEncode()); - - face.receive(*makeInterest(Name("/root/test/small/valid").appendVersion(10))); // should be ignored - face.receive(*makeInterest(Name("/root/test/small/valid").appendSegment(20))); // should be ignored - advanceClocks(time::milliseconds(1), 10); - BOOST_CHECK_EQUAL(face.sentData.size(), 1); - BOOST_CHECK_EQUAL(storage.size(), 1); - - Block content = face.sentData[0].getContent(); - BOOST_CHECK_NO_THROW(content.parse()); - - BOOST_CHECK_EQUAL(content.elements().size(), 3); - BOOST_CHECK(content.elements()[0] == smallBlock); - BOOST_CHECK(content.elements()[1] == smallBlock); - BOOST_CHECK(content.elements()[2] == smallBlock); - - storage.erase("/", true); // clear the storage - face.sentData.clear(); - face.receive(*makeInterest("/root/test/large/valid")); - advanceClocks(time::milliseconds(1), 10); - - // two data packets are generated, the first one will be sent to both places - // while the second one will only be inserted into the in-memory storage - BOOST_CHECK_EQUAL(face.sentData.size(), 1); - BOOST_CHECK_EQUAL(storage.size(), 2); - - // segment0 should be sent through the face - const auto& component = face.sentData[0].getName().at(-1); - BOOST_CHECK(component.isSegment()); - BOOST_CHECK_EQUAL(component.toSegment(), 0); - - std::vector dataInStorage; - std::copy(storage.begin(), storage.end(), std::back_inserter(dataInStorage)); - - // the Data sent through the face should be the same as the first Data in the storage - BOOST_CHECK_EQUAL(face.sentData[0].getName(), dataInStorage[0].getName()); - BOOST_CHECK(face.sentData[0].getContent() == dataInStorage[0].getContent()); - - content = [&dataInStorage] () -> Block { - EncodingBuffer encoder; - size_t valueLength = encoder.prependByteArray(dataInStorage[1].getContent().value(), - dataInStorage[1].getContent().value_size()); - valueLength += encoder.prependByteArray(dataInStorage[0].getContent().value(), - dataInStorage[0].getContent().value_size()); - encoder.prependVarNumber(valueLength); - encoder.prependVarNumber(tlv::Content); - return encoder.block(); - }(); - - BOOST_CHECK_NO_THROW(content.parse()); - BOOST_CHECK_EQUAL(content.elements().size(), 3); - BOOST_CHECK(content.elements()[0] == largeBlock); - BOOST_CHECK(content.elements()[1] == largeBlock); - BOOST_CHECK(content.elements()[2] == largeBlock); - - storage.erase("/", true);// clear the storage - face.sentData.clear(); - face.receive(*makeInterest("/root/test/reject/%80%00/valid")); // returns nack - advanceClocks(time::milliseconds(1)); - BOOST_CHECK_EQUAL(face.sentData.size(), 1); - BOOST_CHECK(face.sentData[0].getContentType() == tlv::ContentType_Nack); - BOOST_CHECK_EQUAL(ControlResponse(face.sentData[0].getContent().blockFromValue()).getCode(), 400); - BOOST_CHECK_EQUAL(storage.size(), 0); // the nack packet will not be inserted into the in-memory storage -} - -BOOST_FIXTURE_TEST_CASE(NotificationStream, DispatcherFixture) -{ - static Block block("\x82\x01\x02", 3); - - auto post = dispatcher.addNotificationStream("test"); - - post(block); - advanceClocks(time::milliseconds(1)); - BOOST_CHECK_EQUAL(face.sentData.size(), 0); - - dispatcher.addTopPrefix("/root"); - advanceClocks(time::milliseconds(1)); - face.sentData.clear(); - - post(block); - advanceClocks(time::milliseconds(1)); - BOOST_CHECK_EQUAL(face.sentData.size(), 1); - BOOST_CHECK_EQUAL(storage.size(), 1); - - post(block); - post(block); - post(block); - advanceClocks(time::milliseconds(1), 10); - - BOOST_CHECK_EQUAL(face.sentData.size(), 4); - BOOST_CHECK_EQUAL(face.sentData[0].getName(), "/root/test/%FE%00"); - BOOST_CHECK_EQUAL(face.sentData[1].getName(), "/root/test/%FE%01"); - BOOST_CHECK_EQUAL(face.sentData[2].getName(), "/root/test/%FE%02"); - BOOST_CHECK_EQUAL(face.sentData[3].getName(), "/root/test/%FE%03"); - - BOOST_CHECK(face.sentData[0].getContent().blockFromValue() == block); - BOOST_CHECK(face.sentData[1].getContent().blockFromValue() == block); - BOOST_CHECK(face.sentData[2].getContent().blockFromValue() == block); - BOOST_CHECK(face.sentData[3].getContent().blockFromValue() == block); - - // each version of notification will be sent to both places - std::vector dataInStorage; - std::copy(storage.begin(), storage.end(), std::back_inserter(dataInStorage)); - BOOST_CHECK_EQUAL(dataInStorage.size(), 4); - BOOST_CHECK_EQUAL(dataInStorage[0].getName(), "/root/test/%FE%00"); - BOOST_CHECK_EQUAL(dataInStorage[1].getName(), "/root/test/%FE%01"); - BOOST_CHECK_EQUAL(dataInStorage[2].getName(), "/root/test/%FE%02"); - BOOST_CHECK_EQUAL(dataInStorage[3].getName(), "/root/test/%FE%03"); - - BOOST_CHECK(dataInStorage[0].getContent().blockFromValue() == block); - BOOST_CHECK(dataInStorage[1].getContent().blockFromValue() == block); - BOOST_CHECK(dataInStorage[2].getContent().blockFromValue() == block); - BOOST_CHECK(dataInStorage[3].getContent().blockFromValue() == block); -} - -BOOST_AUTO_TEST_SUITE_END() // TestDispatcher -BOOST_AUTO_TEST_SUITE_END() // Mgmt - -} // namespace tests -} // namespace mgmt -} // namespace ndn diff --git a/tests/unit-tests/mgmt/nfd/channel-status.t.cpp b/tests/unit-tests/mgmt/nfd/channel-status.t.cpp deleted file mode 100644 index c682f5925..000000000 --- a/tests/unit-tests/mgmt/nfd/channel-status.t.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "mgmt/nfd/channel-status.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace nfd { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Mgmt) -BOOST_AUTO_TEST_SUITE(Nfd) -BOOST_AUTO_TEST_SUITE(TestChannelStatus) - -BOOST_AUTO_TEST_CASE(Encode) -{ - ChannelStatus status1; - status1 - .setLocalUri("udp4://192.168.2.1") - ; - - Block wire; - BOOST_REQUIRE_NO_THROW(wire = status1.wireEncode()); - - // These octets are obtained by the snippet below. - // This check is intended to detect unexpected encoding change in the future. - // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { - // printf("0x%02x, ", *it); - // } - static const uint8_t expected[] = { - 0x82, 0x14, 0x81, 0x12, 0x75, 0x64, 0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, - 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x32, 0x2e, 0x31 - }; - BOOST_REQUIRE_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), - wire.begin(), wire.end()); - - BOOST_REQUIRE_NO_THROW(ChannelStatus(wire)); - ChannelStatus status2(wire); - BOOST_CHECK_EQUAL(status1.getLocalUri(), status2.getLocalUri()); -} - -BOOST_AUTO_TEST_SUITE_END() // TestChannelStatus -BOOST_AUTO_TEST_SUITE_END() // Nfd -BOOST_AUTO_TEST_SUITE_END() // Mgmt - -} // namespace tests -} // namespace nfd -} // namespace ndn diff --git a/tests/unit-tests/mgmt/nfd/control-command.t.cpp b/tests/unit-tests/mgmt/nfd/control-command.t.cpp deleted file mode 100644 index d282acfa1..000000000 --- a/tests/unit-tests/mgmt/nfd/control-command.t.cpp +++ /dev/null @@ -1,381 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "mgmt/nfd/control-command.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace nfd { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Mgmt) -BOOST_AUTO_TEST_SUITE(Nfd) -BOOST_AUTO_TEST_SUITE(TestControlCommand) - -BOOST_AUTO_TEST_CASE(FaceCreate) -{ - FaceCreateCommand command; - - ControlParameters p1; - p1.setUri("tcp4://192.0.2.1") - .setFaceId(4); - BOOST_CHECK_THROW(command.validateRequest(p1), ControlCommand::ArgumentError); - BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError); - - ControlParameters p2; - p2.setName("ndn:/example"); - BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError); - BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); - - ControlParameters p3; - p3.setUri("tcp4://192.0.2.1") - .setFaceId(0); - BOOST_CHECK_THROW(command.validateResponse(p3), ControlCommand::ArgumentError); - - ControlParameters p4; - p4.setUri("tcp4://192.0.2.1") - .setFacePersistency(FACE_PERSISTENCY_PERSISTENT) - .setFlags(0x3) - .setMask(0x1); - BOOST_CHECK_NO_THROW(command.validateRequest(p4)); - - ControlParameters p5; - p5.setUri("tcp4://192.0.2.1") - .setFacePersistency(FACE_PERSISTENCY_PERSISTENT) - .setFlags(0x1); - BOOST_CHECK_THROW(command.validateRequest(p5), ControlCommand::ArgumentError); - - p4.unsetFacePersistency(); - BOOST_CHECK_NO_THROW(command.validateRequest(p4)); - command.applyDefaultsToRequest(p4); - BOOST_REQUIRE(p4.hasFacePersistency()); - BOOST_CHECK_EQUAL(p4.getFacePersistency(), FACE_PERSISTENCY_PERSISTENT); - - ControlParameters p6; - p6.setFaceId(4) - .setUri("tcp4://192.0.2.1") - .setFacePersistency(FACE_PERSISTENCY_PERSISTENT); - BOOST_CHECK_NO_THROW(command.validateResponse(p6)); - - ControlParameters p7; - p7.setUri("tcp4://192.0.2.1:6363"); - Name n7; - BOOST_CHECK_NO_THROW(n7 = command.getRequestName("/PREFIX", p7)); - BOOST_CHECK(Name("ndn:/PREFIX/faces/create").isPrefixOf(n7)); - - ControlParameters p8; - p8.setFaceId(5) - .setFacePersistency(FACE_PERSISTENCY_PERMANENT) - .setFlags(0x2); - BOOST_CHECK_NO_THROW(command.validateResponse(p8)); -} - -BOOST_AUTO_TEST_CASE(FaceUpdate) -{ - FaceUpdateCommand command; - - ControlParameters p1; - p1.setFaceId(0); - BOOST_CHECK_NO_THROW(command.validateRequest(p1)); - BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError); - - p1.setFaceId(1); - BOOST_CHECK_NO_THROW(command.validateRequest(p1)); - BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError); - command.applyDefaultsToRequest(p1); - BOOST_CHECK_EQUAL(p1.getFaceId(), 1); - - ControlParameters p2; - p2.setFaceId(1) - .setFacePersistency(FACE_PERSISTENCY_PERSISTENT) - .setFlagBit(BIT_LOCAL_FIELDS_ENABLED, false); - BOOST_CHECK_NO_THROW(command.validateRequest(p2)); - BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); // Mask forbidden but present - - // Flags without Mask - p2.unsetMask(); - BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError); - BOOST_CHECK_NO_THROW(command.validateResponse(p2)); - - p2.setFlagBit(BIT_LOCAL_FIELDS_ENABLED, false); - p2.unsetFaceId(); - BOOST_CHECK_NO_THROW(command.validateRequest(p2)); - - ControlParameters p3; - p3.setFaceId(1) - .setName("/ndn/name"); - BOOST_CHECK_THROW(command.validateRequest(p3), ControlCommand::ArgumentError); - BOOST_CHECK_THROW(command.validateResponse(p3), ControlCommand::ArgumentError); - - ControlParameters p4; - p4.setFaceId(1) - .setUri("tcp4://192.0.2.1"); - BOOST_CHECK_THROW(command.validateRequest(p4), ControlCommand::ArgumentError); - BOOST_CHECK_THROW(command.validateResponse(p4), ControlCommand::ArgumentError); - - ControlParameters p5; - BOOST_CHECK_NO_THROW(command.validateRequest(p5)); - BOOST_CHECK_THROW(command.validateResponse(p5), ControlCommand::ArgumentError); - BOOST_CHECK(!p5.hasFaceId()); - command.applyDefaultsToRequest(p5); - BOOST_REQUIRE(p5.hasFaceId()); - BOOST_CHECK_NO_THROW(command.validateRequest(p5)); - BOOST_CHECK_THROW(command.validateResponse(p5), ControlCommand::ArgumentError); - BOOST_CHECK_EQUAL(p5.getFaceId(), 0); -} - -BOOST_AUTO_TEST_CASE(FaceDestroy) -{ - FaceDestroyCommand command; - - ControlParameters p1; - p1.setUri("tcp4://192.0.2.1") - .setFaceId(4); - BOOST_CHECK_THROW(command.validateRequest(p1), ControlCommand::ArgumentError); - BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError); - - ControlParameters p2; - p2.setFaceId(0); - BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError); - BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); - - ControlParameters p3; - p3.setFaceId(6); - BOOST_CHECK_NO_THROW(command.validateRequest(p3)); - BOOST_CHECK_NO_THROW(command.validateResponse(p3)); - Name n3; - BOOST_CHECK_NO_THROW(n3 = command.getRequestName("/PREFIX", p3)); - BOOST_CHECK(Name("ndn:/PREFIX/faces/destroy").isPrefixOf(n3)); -} - -BOOST_AUTO_TEST_CASE(FaceEnableLocalControl) -{ - FaceEnableLocalControlCommand command; - - ControlParameters p1; - p1.setLocalControlFeature(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID); - BOOST_CHECK_NO_THROW(command.validateRequest(p1)); - BOOST_CHECK_NO_THROW(command.validateResponse(p1)); - Name n1; - BOOST_CHECK_NO_THROW(n1 = command.getRequestName("/PREFIX", p1)); - BOOST_CHECK(Name("ndn:/PREFIX/faces/enable-local-control").isPrefixOf(n1)); - - ControlParameters p2; - p2.setLocalControlFeature(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID) - .setFaceId(9); - BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError); - BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); - - ControlParameters p3; - p3.setLocalControlFeature(static_cast(666)); - BOOST_CHECK_THROW(command.validateRequest(p3), ControlCommand::ArgumentError); - BOOST_CHECK_THROW(command.validateResponse(p3), ControlCommand::ArgumentError); -} - -BOOST_AUTO_TEST_CASE(FaceDisableLocalControl) -{ - FaceDisableLocalControlCommand command; - - ControlParameters p1; - p1.setLocalControlFeature(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID); - BOOST_CHECK_NO_THROW(command.validateRequest(p1)); - BOOST_CHECK_NO_THROW(command.validateResponse(p1)); - Name n1; - BOOST_CHECK_NO_THROW(n1 = command.getRequestName("/PREFIX", p1)); - BOOST_CHECK(Name("ndn:/PREFIX/faces/disable-local-control").isPrefixOf(n1)); - - ControlParameters p2; - p2.setLocalControlFeature(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID) - .setFaceId(9); - BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError); - BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); - - ControlParameters p3; - p3.setLocalControlFeature(static_cast(666)); - BOOST_CHECK_THROW(command.validateRequest(p3), ControlCommand::ArgumentError); - BOOST_CHECK_THROW(command.validateResponse(p3), ControlCommand::ArgumentError); -} - -BOOST_AUTO_TEST_CASE(FibAddNextHop) -{ - FibAddNextHopCommand command; - - ControlParameters p1; - p1.setName("ndn:/") - .setFaceId(22); - BOOST_CHECK_NO_THROW(command.validateRequest(p1)); - BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError); - Name n1; - BOOST_CHECK_NO_THROW(n1 = command.getRequestName("/PREFIX", p1)); - BOOST_CHECK(Name("ndn:/PREFIX/fib/add-nexthop").isPrefixOf(n1)); - - ControlParameters p2; - p2.setName("ndn:/example") - .setFaceId(0) - .setCost(6); - BOOST_CHECK_NO_THROW(command.validateRequest(p2)); - BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); - - command.applyDefaultsToRequest(p1); - BOOST_REQUIRE(p1.hasCost()); - BOOST_CHECK_EQUAL(p1.getCost(), 0); - - p1.unsetFaceId(); - BOOST_CHECK_NO_THROW(command.validateRequest(p1)); - command.applyDefaultsToRequest(p1); - BOOST_REQUIRE(p1.hasFaceId()); - BOOST_CHECK_EQUAL(p1.getFaceId(), 0); -} - -BOOST_AUTO_TEST_CASE(FibRemoveNextHop) -{ - FibRemoveNextHopCommand command; - - ControlParameters p1; - p1.setName("ndn:/") - .setFaceId(22); - BOOST_CHECK_NO_THROW(command.validateRequest(p1)); - BOOST_CHECK_NO_THROW(command.validateResponse(p1)); - Name n1; - BOOST_CHECK_NO_THROW(n1 = command.getRequestName("/PREFIX", p1)); - BOOST_CHECK(Name("ndn:/PREFIX/fib/remove-nexthop").isPrefixOf(n1)); - - ControlParameters p2; - p2.setName("ndn:/example") - .setFaceId(0); - BOOST_CHECK_NO_THROW(command.validateRequest(p2)); - BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); - - p1.unsetFaceId(); - BOOST_CHECK_NO_THROW(command.validateRequest(p1)); - command.applyDefaultsToRequest(p1); - BOOST_REQUIRE(p1.hasFaceId()); - BOOST_CHECK_EQUAL(p1.getFaceId(), 0); -} - -BOOST_AUTO_TEST_CASE(StrategyChoiceSet) -{ - StrategyChoiceSetCommand command; - - ControlParameters p1; - p1.setName("ndn:/") - .setStrategy("ndn:/strategy/P"); - BOOST_CHECK_NO_THROW(command.validateRequest(p1)); - BOOST_CHECK_NO_THROW(command.validateResponse(p1)); - Name n1; - BOOST_CHECK_NO_THROW(n1 = command.getRequestName("/PREFIX", p1)); - BOOST_CHECK(Name("ndn:/PREFIX/strategy-choice/set").isPrefixOf(n1)); - - ControlParameters p2; - p2.setName("ndn:/example"); - BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError); - BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); -} - -BOOST_AUTO_TEST_CASE(StrategyChoiceUnset) -{ - StrategyChoiceUnsetCommand command; - - ControlParameters p1; - p1.setName("ndn:/example"); - BOOST_CHECK_NO_THROW(command.validateRequest(p1)); - BOOST_CHECK_NO_THROW(command.validateResponse(p1)); - Name n1; - BOOST_CHECK_NO_THROW(n1 = command.getRequestName("/PREFIX", p1)); - BOOST_CHECK(Name("ndn:/PREFIX/strategy-choice/unset").isPrefixOf(n1)); - - ControlParameters p2; - p2.setName("ndn:/example") - .setStrategy("ndn:/strategy/P"); - BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError); - BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); - - ControlParameters p3; - p3.setName("ndn:/"); - BOOST_CHECK_THROW(command.validateRequest(p3), ControlCommand::ArgumentError); - BOOST_CHECK_THROW(command.validateResponse(p3), ControlCommand::ArgumentError); -} - -BOOST_AUTO_TEST_CASE(RibRegister) -{ - RibRegisterCommand command; - - ControlParameters p1; - p1.setName("ndn:/"); - BOOST_CHECK_NO_THROW(command.validateRequest(p1)); - BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError); - Name n1; - BOOST_CHECK_NO_THROW(n1 = command.getRequestName("/PREFIX", p1)); - BOOST_CHECK(Name("ndn:/PREFIX/rib/register").isPrefixOf(n1)); - - command.applyDefaultsToRequest(p1); - BOOST_REQUIRE(p1.hasOrigin()); - BOOST_CHECK_EQUAL(p1.getOrigin(), static_cast(ROUTE_ORIGIN_APP)); - BOOST_REQUIRE(p1.hasCost()); - BOOST_CHECK_EQUAL(p1.getCost(), 0); - BOOST_REQUIRE(p1.hasFlags()); - BOOST_CHECK_EQUAL(p1.getFlags(), static_cast(ROUTE_FLAG_CHILD_INHERIT)); - BOOST_CHECK_EQUAL(p1.hasExpirationPeriod(), false); - - ControlParameters p2; - p2.setName("ndn:/example") - .setFaceId(2) - .setCost(6); - BOOST_CHECK_NO_THROW(command.validateRequest(p2)); - command.applyDefaultsToRequest(p2); - BOOST_CHECK_EQUAL(p2.hasExpirationPeriod(), false); - BOOST_CHECK_NO_THROW(command.validateResponse(p2)); -} - -BOOST_AUTO_TEST_CASE(RibUnregister) -{ - RibUnregisterCommand command; - - ControlParameters p1; - p1.setName("ndn:/") - .setFaceId(22) - .setOrigin(ROUTE_ORIGIN_STATIC); - BOOST_CHECK_NO_THROW(command.validateRequest(p1)); - BOOST_CHECK_NO_THROW(command.validateResponse(p1)); - Name n1; - BOOST_CHECK_NO_THROW(n1 = command.getRequestName("/PREFIX", p1)); - BOOST_CHECK(Name("ndn:/PREFIX/rib/unregister").isPrefixOf(n1)); - - ControlParameters p2; - p2.setName("ndn:/example") - .setFaceId(0) - .setOrigin(ROUTE_ORIGIN_APP); - BOOST_CHECK_NO_THROW(command.validateRequest(p2)); - BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); - - p2.unsetFaceId(); - BOOST_CHECK_NO_THROW(command.validateRequest(p2)); - BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); -} - -BOOST_AUTO_TEST_SUITE_END() // TestControlCommand -BOOST_AUTO_TEST_SUITE_END() // Nfd -BOOST_AUTO_TEST_SUITE_END() // Mgmt - -} // namespace tests -} // namespace nfd -} // namespace ndn diff --git a/tests/unit-tests/mgmt/nfd/control-parameters.t.cpp b/tests/unit-tests/mgmt/nfd/control-parameters.t.cpp deleted file mode 100644 index 7ef364e8a..000000000 --- a/tests/unit-tests/mgmt/nfd/control-parameters.t.cpp +++ /dev/null @@ -1,276 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "mgmt/nfd/control-parameters.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace nfd { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Mgmt) -BOOST_AUTO_TEST_SUITE(Nfd) -BOOST_AUTO_TEST_SUITE(TestControlParameters) - -BOOST_AUTO_TEST_CASE(FaceOptions) -{ - ControlParameters parameters; - parameters.setUri("tcp4://192.0.2.1:6363"); - parameters.setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT); - parameters.setFlags(1); - parameters.setMask(1); - Block wire = parameters.wireEncode(); - - ControlParameters decoded(wire); - BOOST_CHECK_EQUAL(decoded.getUri(), "tcp4://192.0.2.1:6363"); - BOOST_CHECK_EQUAL(decoded.getFacePersistency(), ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT); - BOOST_CHECK_EQUAL(decoded.getFlags(), 1); - BOOST_CHECK_EQUAL(decoded.getMask(), 1); - - BOOST_CHECK_EQUAL(decoded.hasName(), false); - BOOST_CHECK_EQUAL(decoded.hasFaceId(), false); - BOOST_CHECK_EQUAL(decoded.hasLocalControlFeature(), false); - BOOST_CHECK_EQUAL(decoded.hasOrigin(), false); - BOOST_CHECK_EQUAL(decoded.hasCost(), false); - BOOST_CHECK_EQUAL(decoded.hasStrategy(), false); - BOOST_CHECK_EQUAL(decoded.hasExpirationPeriod(), false); -} - -BOOST_AUTO_TEST_CASE(FaceLocalControlOptions) -{ - ControlParameters parameters; - parameters.setLocalControlFeature(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID); - - Block wire = parameters.wireEncode(); - - ControlParameters decoded(wire); - BOOST_CHECK_EQUAL(decoded.getLocalControlFeature(), LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID); - - BOOST_CHECK_EQUAL(decoded.hasName(), false); - BOOST_CHECK_EQUAL(decoded.hasFaceId(), false); - BOOST_CHECK_EQUAL(decoded.hasUri(), false); - BOOST_CHECK_EQUAL(decoded.hasOrigin(), false); - BOOST_CHECK_EQUAL(decoded.hasCost(), false); - BOOST_CHECK_EQUAL(decoded.hasFlags(), false); - BOOST_CHECK_EQUAL(decoded.hasStrategy(), false); - BOOST_CHECK_EQUAL(decoded.hasExpirationPeriod(), false); - BOOST_CHECK_EQUAL(decoded.hasFacePersistency(), false); -} - -BOOST_AUTO_TEST_CASE(FibOptions) -{ - ControlParameters parameters; - parameters.setName("ndn:/example") - .setFaceId(4) - .setCost(555); - - Block wire = parameters.wireEncode(); - - ControlParameters decoded(wire); - BOOST_CHECK_EQUAL(decoded.getName(), Name("ndn:/example")); - BOOST_CHECK_EQUAL(decoded.getFaceId(), 4); - BOOST_CHECK_EQUAL(decoded.getCost(), 555); - - BOOST_CHECK_EQUAL(decoded.hasUri(), false); - BOOST_CHECK_EQUAL(decoded.hasLocalControlFeature(), false); - BOOST_CHECK_EQUAL(decoded.hasOrigin(), false); - BOOST_CHECK_EQUAL(decoded.hasFlags(), false); - BOOST_CHECK_EQUAL(decoded.hasMask(), false); - BOOST_CHECK_EQUAL(decoded.hasStrategy(), false); - BOOST_CHECK_EQUAL(decoded.hasExpirationPeriod(), false); - BOOST_CHECK_EQUAL(decoded.hasFacePersistency(), false); -} - -BOOST_AUTO_TEST_CASE(StrategyChoiceOptions) -{ - ControlParameters parameters; - parameters.setName("ndn:/") - .setStrategy("ndn:/strategy/A"); - - Block wire = parameters.wireEncode(); - - ControlParameters decoded(wire); - BOOST_CHECK_EQUAL(decoded.getName(), Name("ndn:/")); - BOOST_CHECK_EQUAL(decoded.getStrategy(), Name("ndn:/strategy/A")); - - BOOST_CHECK_EQUAL(decoded.hasFaceId(), false); - BOOST_CHECK_EQUAL(decoded.hasUri(), false); - BOOST_CHECK_EQUAL(decoded.hasLocalControlFeature(), false); - BOOST_CHECK_EQUAL(decoded.hasOrigin(), false); - BOOST_CHECK_EQUAL(decoded.hasCost(), false); - BOOST_CHECK_EQUAL(decoded.hasFlags(), false); - BOOST_CHECK_EQUAL(decoded.hasMask(), false); - BOOST_CHECK_EQUAL(decoded.hasExpirationPeriod(), false); - BOOST_CHECK_EQUAL(decoded.hasFacePersistency(), false); -} - -BOOST_AUTO_TEST_CASE(RibOptions) -{ - ControlParameters parameters; - parameters.setName("ndn:/example") - .setFaceId(4) - .setOrigin(128) - .setCost(6) - .setFlags(0x01) - .setExpirationPeriod(time::milliseconds(1800000)); - - Block wire = parameters.wireEncode(); - - ControlParameters decoded(wire); - BOOST_CHECK_EQUAL(decoded.getName(), Name("ndn:/example")); - BOOST_CHECK_EQUAL(decoded.getFaceId(), 4); - BOOST_CHECK_EQUAL(decoded.getOrigin(), 128); - BOOST_CHECK_EQUAL(decoded.getCost(), 6); - BOOST_CHECK_EQUAL(decoded.getFlags(), 0x01); - BOOST_CHECK_EQUAL(decoded.getExpirationPeriod(), time::milliseconds(1800000)); - - BOOST_CHECK_EQUAL(decoded.hasUri(), false); - BOOST_CHECK_EQUAL(decoded.hasLocalControlFeature(), false); - BOOST_CHECK_EQUAL(decoded.hasMask(), false); - BOOST_CHECK_EQUAL(decoded.hasStrategy(), false); - BOOST_CHECK_EQUAL(decoded.hasFacePersistency(), false); -} - -BOOST_AUTO_TEST_CASE(FlagsAndMask) -{ - ControlParameters p; - - BOOST_CHECK(!p.hasFlags()); - BOOST_CHECK(!p.hasMask()); - BOOST_CHECK(!p.hasFlagBit(0)); - BOOST_CHECK(!p.getFlagBit(0)); - - // Set bit 2 to true (change Mask) - p.setFlagBit(2, true); - // 2^2 = 4 - BOOST_CHECK_EQUAL(p.getFlags(), 4); - BOOST_CHECK_EQUAL(p.getMask(), 4); - BOOST_CHECK(p.hasFlagBit(2)); - BOOST_CHECK(p.getFlagBit(2)); - BOOST_CHECK(!p.hasFlagBit(1)); - BOOST_CHECK(!p.getFlagBit(1)); - - // Set bit 3 to true (no change to Mask) - p.setFlagBit(3, true, false); - // 2^3 + 2^2 = 12 - BOOST_CHECK_EQUAL(p.getFlags(), 12); - // 2^2 = 4 - BOOST_CHECK_EQUAL(p.getMask(), 4); - BOOST_CHECK(!p.hasFlagBit(3)); - BOOST_CHECK(p.getFlagBit(3)); - BOOST_CHECK(p.hasFlagBit(2)); - BOOST_CHECK(p.getFlagBit(2)); - - // Set bit 1 to false (change Mask) - p.setFlagBit(1, false); - // 2^3 + 2^2 = 12 - BOOST_CHECK_EQUAL(p.getFlags(), 12); - // 2^2 + 2^1 = 6 - BOOST_CHECK_EQUAL(p.getMask(), 6); - BOOST_CHECK(!p.hasFlagBit(3)); - BOOST_CHECK(p.getFlagBit(3)); - BOOST_CHECK(p.hasFlagBit(2)); - BOOST_CHECK(p.getFlagBit(2)); - BOOST_CHECK(p.hasFlagBit(1)); - BOOST_CHECK(!p.getFlagBit(1)); - - // Set bit 2 to false (change Mask) - p.setFlagBit(2, false); - // 2^3 = 8 - BOOST_CHECK_EQUAL(p.getFlags(), 8); - // 2^2 + 2^1 = 6 - BOOST_CHECK_EQUAL(p.getMask(), 6); - BOOST_CHECK(!p.hasFlagBit(3)); - BOOST_CHECK(p.getFlagBit(3)); - BOOST_CHECK(p.hasFlagBit(2)); - BOOST_CHECK(!p.getFlagBit(2)); - BOOST_CHECK(p.hasFlagBit(1)); - BOOST_CHECK(!p.getFlagBit(1)); - - // Set bit 0 to true (change Mask) - p.setFlagBit(0, true); - // 2^3 + 2^0 = 9 - BOOST_CHECK_EQUAL(p.getFlags(), 9); - // 2^2 + 2^1 + 2^0 = 7 - BOOST_CHECK_EQUAL(p.getMask(), 7); - BOOST_CHECK(p.hasFlagBit(0)); - BOOST_CHECK(p.getFlagBit(0)); - - // Unset bit 0 - p.unsetFlagBit(0); - BOOST_REQUIRE(p.hasFlags()); - BOOST_REQUIRE(p.hasMask()); - // 2^3 + 2^0 = 9 - BOOST_CHECK_EQUAL(p.getFlags(), 9); - // 2^2 + 2^1 = 6 - BOOST_CHECK_EQUAL(p.getMask(), 6); - BOOST_CHECK(p.hasFlagBit(1)); - BOOST_CHECK(!p.hasFlagBit(0)); - BOOST_CHECK(p.getFlagBit(0)); - - // Unset bit 3 (already unset in Mask, so no change) - p.unsetFlagBit(3); - BOOST_REQUIRE(p.hasFlags()); - BOOST_REQUIRE(p.hasMask()); - // 2^3 + 2^0 = 9 - BOOST_CHECK_EQUAL(p.getFlags(), 9); - // 2^2 + 2^1 = 6 - BOOST_CHECK_EQUAL(p.getMask(), 6); - BOOST_CHECK(!p.hasFlagBit(3)); - BOOST_CHECK(p.getFlagBit(3)); - - // Unset bit 2 - p.unsetFlagBit(2); - BOOST_REQUIRE(p.hasFlags()); - BOOST_REQUIRE(p.hasMask()); - // 2^3 + 2^0 = 9 - BOOST_CHECK_EQUAL(p.getFlags(), 9); - // 2^1 = 2 - BOOST_CHECK_EQUAL(p.getMask(), 2); - BOOST_CHECK(!p.hasFlagBit(2)); - BOOST_CHECK(!p.getFlagBit(2)); - - // Unset bit 1 - // Flags and Mask fields will be deleted as Mask is now 0 - p.unsetFlagBit(1); - BOOST_CHECK(!p.hasFlags()); - BOOST_CHECK(!p.hasMask()); - BOOST_CHECK(!p.hasFlagBit(3)); - BOOST_CHECK(!p.getFlagBit(3)); - BOOST_CHECK(!p.hasFlagBit(2)); - BOOST_CHECK(!p.getFlagBit(2)); - BOOST_CHECK(!p.hasFlagBit(1)); - BOOST_CHECK(!p.getFlagBit(1)); - BOOST_CHECK(!p.hasFlagBit(0)); - BOOST_CHECK(!p.getFlagBit(0)); - - BOOST_CHECK_THROW(p.setFlagBit(64, true), std::out_of_range); - BOOST_CHECK_THROW(p.unsetFlagBit(64), std::out_of_range); -} - -BOOST_AUTO_TEST_SUITE_END() // TestControlParameters -BOOST_AUTO_TEST_SUITE_END() // Nfd -BOOST_AUTO_TEST_SUITE_END() // Mgmt - -} // namespace tests -} // namespace nfd -} // namespace ndn diff --git a/tests/unit-tests/mgmt/nfd/control-response.t.cpp b/tests/unit-tests/mgmt/nfd/control-response.t.cpp deleted file mode 100644 index 58fc3bc63..000000000 --- a/tests/unit-tests/mgmt/nfd/control-response.t.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "mgmt/nfd/control-response.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace nfd { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Mgmt) -BOOST_AUTO_TEST_SUITE(Nfd) -BOOST_AUTO_TEST_SUITE(TestControlResponse) - -const uint8_t TestControlResponse[] = {0x65, 0x17, - 0x66, 0x02, 0x01, 0x94, 0x67, 0x11, 0x4e, 0x6f, 0x74, - 0x68, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x6f, 0x74, 0x20, - 0x66, 0x6f, 0x75, 0x6e, 0x64}; - -// ControlResponse - -BOOST_AUTO_TEST_CASE(ControlResponseEncode) -{ - ControlResponse controlResponse(404, "Nothing not found"); - const Block &wire = controlResponse.wireEncode(); - - BOOST_REQUIRE_EQUAL_COLLECTIONS(TestControlResponse, - TestControlResponse+sizeof(TestControlResponse), - wire.begin(), wire.end()); -} - -BOOST_AUTO_TEST_CASE(ControlResponseDecode) -{ - ControlResponse controlResponse; - - BOOST_REQUIRE_NO_THROW(controlResponse.wireDecode(Block(TestControlResponse, - sizeof(TestControlResponse)))); - - BOOST_REQUIRE_EQUAL(controlResponse.getCode(), 404); - BOOST_REQUIRE_EQUAL(controlResponse.getText(), "Nothing not found"); -} - -BOOST_AUTO_TEST_SUITE_END() // TestControlResponse -BOOST_AUTO_TEST_SUITE_END() // Nfd -BOOST_AUTO_TEST_SUITE_END() // Mgmt - -} // namespace tests -} // namespace nfd -} // namespace ndn diff --git a/tests/unit-tests/mgmt/nfd/controller.t.cpp b/tests/unit-tests/mgmt/nfd/controller.t.cpp deleted file mode 100644 index 4d6b8a253..000000000 --- a/tests/unit-tests/mgmt/nfd/controller.t.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "mgmt/nfd/controller.hpp" -#include "mgmt/nfd/control-response.hpp" - -#include - -#include "controller-fixture.hpp" -#include "../../make-interest-data.hpp" - -namespace ndn { -namespace nfd { -namespace tests { - -using namespace ndn::tests; - -BOOST_AUTO_TEST_SUITE(Mgmt) -BOOST_AUTO_TEST_SUITE(Nfd) - -class CommandFixture : public ControllerFixture -{ -protected: - CommandFixture() - : succeedCallback(bind(&CommandFixture::succeed, this, _1)) - { - } - -private: - void - succeed(const ControlParameters& parameters) - { - succeeds.push_back(parameters); - } - -protected: - Controller::CommandSucceedCallback succeedCallback; - std::vector succeeds; -}; - -// This test suite focuses on ControlCommand functionality of Controller. -// Individual commands are tested in nfd-control-command.t.cpp -// StatusDataset functionality is tested in nfd-status-dataset.t.cpp -BOOST_FIXTURE_TEST_SUITE(TestController, CommandFixture) - -BOOST_AUTO_TEST_CASE(Success) -{ - ControlParameters parameters; - parameters.setUri("tcp4://192.0.2.1:6363"); - - BOOST_CHECK_NO_THROW(controller.start( - parameters, succeedCallback, commandFailCallback)); - this->advanceClocks(time::milliseconds(1)); - - BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1); - const Interest& requestInterest = face.sentInterests[0]; - - FaceCreateCommand command; - BOOST_CHECK(Name("/localhost/nfd/faces/create").isPrefixOf(requestInterest.getName())); - // 9 components: ndn:/localhost/nfd/faces/create// - BOOST_REQUIRE_EQUAL(requestInterest.getName().size(), 9); - ControlParameters request; - // 4th component: - BOOST_REQUIRE_NO_THROW(request.wireDecode(requestInterest.getName().at(4).blockFromValue())); - BOOST_CHECK_NO_THROW(command.validateRequest(request)); - BOOST_CHECK_EQUAL(request.getUri(), parameters.getUri()); - BOOST_CHECK_EQUAL(requestInterest.getInterestLifetime(), CommandOptions::DEFAULT_TIMEOUT); - - ControlParameters responseBody; - responseBody.setUri("tcp4://192.0.2.1:6363") - .setFaceId(22) - .setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT); - ControlResponse responsePayload(201, "created"); - responsePayload.setBody(responseBody.wireEncode()); - - auto responseData = makeData(requestInterest.getName()); - responseData->setContent(responsePayload.wireEncode()); - face.receive(*responseData); - - this->advanceClocks(time::milliseconds(1)); - - BOOST_CHECK_EQUAL(failCodes.size(), 0); - BOOST_REQUIRE_EQUAL(succeeds.size(), 1); - BOOST_CHECK_EQUAL(succeeds.back().getUri(), responseBody.getUri()); - BOOST_CHECK_EQUAL(succeeds.back().getFaceId(), responseBody.getFaceId()); -} - -BOOST_AUTO_TEST_CASE(SuccessNoCallback) -{ - ControlParameters parameters; - parameters.setUri("tcp4://192.0.2.1:6363"); - - controller.start(parameters, nullptr, commandFailCallback); - this->advanceClocks(time::milliseconds(1)); - - BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1); - const Interest& requestInterest = face.sentInterests[0]; - - ControlParameters responseBody; - responseBody.setUri("tcp4://192.0.2.1:6363") - .setFaceId(22) - .setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT); - ControlResponse responsePayload(201, "created"); - responsePayload.setBody(responseBody.wireEncode()); - - auto responseData = makeData(requestInterest.getName()); - responseData->setContent(responsePayload.wireEncode()); - face.receive(*responseData); - - BOOST_CHECK_NO_THROW(this->advanceClocks(time::milliseconds(1))); - - BOOST_CHECK_EQUAL(failCodes.size(), 0); -} - -BOOST_AUTO_TEST_CASE(OptionsPrefix) -{ - ControlParameters parameters; - parameters.setName("/ndn/com/example"); - parameters.setFaceId(400); - - CommandOptions options; - options.setPrefix("/localhop/net/example/router1/nfd"); - - BOOST_CHECK_NO_THROW(controller.start( - parameters, succeedCallback, commandFailCallback, options)); - this->advanceClocks(time::milliseconds(1)); - - BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1); - const Interest& requestInterest = face.sentInterests[0]; - - FaceCreateCommand command; - BOOST_CHECK(Name("/localhop/net/example/router1/nfd/rib/register").isPrefixOf( - requestInterest.getName())); -} - -BOOST_AUTO_TEST_CASE(InvalidRequest) -{ - ControlParameters parameters; - parameters.setName("ndn:/should-not-have-this-field"); - // Uri is missing - - BOOST_CHECK_THROW(controller.start( - parameters, succeedCallback, commandFailCallback), - ControlCommand::ArgumentError); -} - -BOOST_AUTO_TEST_CASE(ValidationFailure) -{ - this->setValidationResult(false); - - ControlParameters parameters; - parameters.setUri("tcp4://192.0.2.1:6363"); - - BOOST_CHECK_NO_THROW(controller.start( - parameters, succeedCallback, commandFailCallback)); - this->advanceClocks(time::milliseconds(1)); - - BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1); - const Interest& requestInterest = face.sentInterests[0]; - - ControlParameters responseBody; - responseBody.setUri("tcp4://192.0.2.1:6363") - .setFaceId(22) - .setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT); - ControlResponse responsePayload(201, "created"); - responsePayload.setBody(responseBody.wireEncode()); - - auto responseData = makeData(requestInterest.getName()); - responseData->setContent(responsePayload.wireEncode()); - face.receive(*responseData); - this->advanceClocks(time::milliseconds(1)); - - BOOST_CHECK_EQUAL(succeeds.size(), 0); - BOOST_REQUIRE_EQUAL(failCodes.size(), 1); - BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_VALIDATION); -} - -BOOST_AUTO_TEST_CASE(ErrorCode) -{ - ControlParameters parameters; - parameters.setUri("tcp4://192.0.2.1:6363"); - - BOOST_CHECK_NO_THROW(controller.start( - parameters, succeedCallback, commandFailCallback)); - this->advanceClocks(time::milliseconds(1)); - - BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1); - const Interest& requestInterest = face.sentInterests[0]; - - ControlResponse responsePayload(401, "Not Authenticated"); - - auto responseData = makeData(requestInterest.getName()); - responseData->setContent(responsePayload.wireEncode()); - face.receive(*responseData); - this->advanceClocks(time::milliseconds(1)); - - BOOST_CHECK_EQUAL(succeeds.size(), 0); - BOOST_REQUIRE_EQUAL(failCodes.size(), 1); - BOOST_CHECK_EQUAL(failCodes.back(), 401); -} - -BOOST_AUTO_TEST_CASE(InvalidResponse) -{ - ControlParameters parameters; - parameters.setUri("tcp4://192.0.2.1:6363"); - - BOOST_CHECK_NO_THROW(controller.start( - parameters, succeedCallback, commandFailCallback)); - this->advanceClocks(time::milliseconds(1)); - - BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1); - const Interest& requestInterest = face.sentInterests[0]; - - ControlParameters responseBody; - responseBody.setUri("tcp4://192.0.2.1:6363") - .setName("ndn:/should-not-have-this-field"); - // FaceId is missing - ControlResponse responsePayload(201, "created"); - responsePayload.setBody(responseBody.wireEncode()); - - auto responseData = makeData(requestInterest.getName()); - responseData->setContent(responsePayload.wireEncode()); - face.receive(*responseData); - this->advanceClocks(time::milliseconds(1)); - - BOOST_CHECK_EQUAL(succeeds.size(), 0); - BOOST_REQUIRE_EQUAL(failCodes.size(), 1); -} - -BOOST_AUTO_TEST_CASE(Nack) -{ - ControlParameters parameters; - parameters.setUri("tcp4://192.0.2.1:6363"); - - BOOST_CHECK_NO_THROW(controller.start( - parameters, succeedCallback, commandFailCallback)); - this->advanceClocks(time::milliseconds(1)); - - BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1); - const Interest& requestInterest = face.sentInterests[0]; - - auto responseNack = makeNack(requestInterest, lp::NackReason::NO_ROUTE); - face.receive(responseNack); - this->advanceClocks(time::milliseconds(1)); - - BOOST_REQUIRE_EQUAL(failCodes.size(), 1); - BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_NACK); -} - -BOOST_AUTO_TEST_CASE(Timeout) -{ - ControlParameters parameters; - parameters.setUri("tcp4://192.0.2.1:6363"); - - CommandOptions options; - options.setTimeout(time::milliseconds(50)); - - BOOST_CHECK_NO_THROW(controller.start( - parameters, succeedCallback, commandFailCallback, options)); - this->advanceClocks(time::milliseconds(1), 101); // Face's PIT granularity is 100ms - - BOOST_REQUIRE_EQUAL(failCodes.size(), 1); - BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_TIMEOUT); -} - -BOOST_AUTO_TEST_CASE(FailureNoCallback) -{ - ControlParameters parameters; - parameters.setUri("tcp4://192.0.2.1:6363"); - - CommandOptions options; - options.setTimeout(time::milliseconds(50)); - - controller.start(parameters, succeedCallback, nullptr, options); - BOOST_CHECK_NO_THROW(this->advanceClocks(time::milliseconds(100), 10)); - // timeout - - BOOST_CHECK_EQUAL(succeeds.size(), 0); -} - -BOOST_AUTO_TEST_SUITE_END() // TestController -BOOST_AUTO_TEST_SUITE_END() // Nfd -BOOST_AUTO_TEST_SUITE_END() // Mgmt - -} // namespace tests -} // namespace nfd -} // namespace ndn diff --git a/tests/unit-tests/mgmt/nfd/face-event-notification.t.cpp b/tests/unit-tests/mgmt/nfd/face-event-notification.t.cpp deleted file mode 100644 index 09f024bd7..000000000 --- a/tests/unit-tests/mgmt/nfd/face-event-notification.t.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "mgmt/nfd/face-event-notification.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace nfd { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Mgmt) -BOOST_AUTO_TEST_SUITE(Nfd) -BOOST_AUTO_TEST_SUITE(TestFaceEventNotification) - -BOOST_AUTO_TEST_CASE(Traits) -{ - FaceEventNotification notification; - - BOOST_CHECK_EQUAL(notification.getFaceScope(), FACE_SCOPE_NON_LOCAL); - BOOST_CHECK_EQUAL(notification.getFacePersistency(), FACE_PERSISTENCY_PERSISTENT); - BOOST_CHECK_EQUAL(notification.getLinkType(), LINK_TYPE_POINT_TO_POINT); - - notification.setFaceScope(FACE_SCOPE_LOCAL); - BOOST_CHECK_EQUAL(notification.getFaceScope(), FACE_SCOPE_LOCAL); - BOOST_CHECK_EQUAL(notification.getFacePersistency(), FACE_PERSISTENCY_PERSISTENT); - BOOST_CHECK_EQUAL(notification.getLinkType(), LINK_TYPE_POINT_TO_POINT); - - notification.setFacePersistency(FACE_PERSISTENCY_ON_DEMAND); - BOOST_CHECK_EQUAL(notification.getFaceScope(), FACE_SCOPE_LOCAL); - BOOST_CHECK_EQUAL(notification.getFacePersistency(), FACE_PERSISTENCY_ON_DEMAND); - BOOST_CHECK_EQUAL(notification.getLinkType(), LINK_TYPE_POINT_TO_POINT); - - notification.setFacePersistency(FACE_PERSISTENCY_PERMANENT); - BOOST_CHECK_EQUAL(notification.getFaceScope(), FACE_SCOPE_LOCAL); - BOOST_CHECK_EQUAL(notification.getFacePersistency(), FACE_PERSISTENCY_PERMANENT); - BOOST_CHECK_EQUAL(notification.getLinkType(), LINK_TYPE_POINT_TO_POINT); - - notification.setLinkType(LINK_TYPE_MULTI_ACCESS); - BOOST_CHECK_EQUAL(notification.getFaceScope(), FACE_SCOPE_LOCAL); - BOOST_CHECK_EQUAL(notification.getFacePersistency(), FACE_PERSISTENCY_PERMANENT); - BOOST_CHECK_EQUAL(notification.getLinkType(), LINK_TYPE_MULTI_ACCESS); -} - -BOOST_AUTO_TEST_CASE(EncodeCreated) -{ - FaceEventNotification notification1; - notification1.setKind(FACE_EVENT_CREATED) - .setFaceId(20) - .setRemoteUri("tcp4://192.0.2.1:55555") - .setLocalUri("tcp4://192.0.2.2:6363") - .setFaceScope(FACE_SCOPE_LOCAL) - .setFacePersistency(FACE_PERSISTENCY_ON_DEMAND) - .setLinkType(LINK_TYPE_MULTI_ACCESS) - .setFlags(0x3); - Block wire; - BOOST_REQUIRE_NO_THROW(wire = notification1.wireEncode()); - - // These octets are obtained by the snippet below. - // This check is intended to detect unexpected encoding change in the future. - // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { - // printf("0x%02x, ", *it); - // } - static const uint8_t expected[] = { - 0xc0, 0x41, 0xc1, 0x01, 0x01, 0x69, 0x01, 0x14, 0x72, 0x16, - 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, - 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x31, 0x3a, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x81, 0x15, 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, - 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x32, - 0x3a, 0x36, 0x33, 0x36, 0x33, 0x84, 0x01, 0x01, 0x85, 0x01, - 0x01, 0x86, 0x01, 0x01, 0x6c, 0x01, 0x03, - }; - BOOST_REQUIRE_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), - wire.begin(), wire.end()); - - BOOST_REQUIRE_NO_THROW(FaceEventNotification(wire)); - FaceEventNotification notification2(wire); - BOOST_CHECK_EQUAL(notification1.getKind(), notification2.getKind()); - BOOST_CHECK_EQUAL(notification1.getFaceId(), notification2.getFaceId()); - BOOST_CHECK_EQUAL(notification1.getRemoteUri(), notification2.getRemoteUri()); - BOOST_CHECK_EQUAL(notification1.getLocalUri(), notification2.getLocalUri()); - BOOST_CHECK_EQUAL(notification1.getFaceScope(), notification2.getFaceScope()); - BOOST_CHECK_EQUAL(notification1.getFacePersistency(), notification2.getFacePersistency()); - BOOST_CHECK_EQUAL(notification1.getLinkType(), notification2.getLinkType()); - BOOST_CHECK_EQUAL(notification1.getFlags(), notification2.getFlags()); - - std::ostringstream os; - os << notification2; - BOOST_CHECK_EQUAL(os.str(), "FaceEventNotification(" - "Kind: created, " - "FaceID: 20, " - "RemoteUri: tcp4://192.0.2.1:55555, " - "LocalUri: tcp4://192.0.2.2:6363, " - "FaceScope: local, " - "FacePersistency: on-demand, " - "LinkType: multi-access, " - "Flags: 0x3)"); -} - -BOOST_AUTO_TEST_CASE(EncodeDestroyed) -{ - FaceEventNotification notification1; - notification1.setKind(FACE_EVENT_DESTROYED) - .setFaceId(20) - .setRemoteUri("tcp4://192.0.2.1:55555") - .setLocalUri("tcp4://192.0.2.2:6363") - .setFaceScope(FACE_SCOPE_LOCAL) - .setFacePersistency(FACE_PERSISTENCY_ON_DEMAND) - .setLinkType(LINK_TYPE_MULTI_ACCESS) - .setFlags(0x4); - Block wire; - BOOST_REQUIRE_NO_THROW(wire = notification1.wireEncode()); - - // These octets are obtained by the snippet below. - // This check is intended to detect unexpected encoding change in the future. - // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { - // printf("0x%02x, ", *it); - // } - static const uint8_t expected[] = { - 0xc0, 0x41, 0xc1, 0x01, 0x02, 0x69, 0x01, 0x14, 0x72, 0x16, - 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, - 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x31, 0x3a, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x81, 0x15, 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, - 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x32, - 0x3a, 0x36, 0x33, 0x36, 0x33, 0x84, 0x01, 0x01, 0x85, 0x01, - 0x01, 0x86, 0x01, 0x01, 0x6c, 0x01, 0x04, - }; - BOOST_REQUIRE_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), - wire.begin(), wire.end()); - - BOOST_REQUIRE_NO_THROW(FaceEventNotification(wire)); - FaceEventNotification notification2(wire); - BOOST_CHECK_EQUAL(notification1.getKind(), notification2.getKind()); - BOOST_CHECK_EQUAL(notification1.getFaceId(), notification2.getFaceId()); - BOOST_CHECK_EQUAL(notification1.getRemoteUri(), notification2.getRemoteUri()); - BOOST_CHECK_EQUAL(notification1.getLocalUri(), notification2.getLocalUri()); - BOOST_CHECK_EQUAL(notification1.getFaceScope(), notification2.getFaceScope()); - BOOST_CHECK_EQUAL(notification1.getFacePersistency(), notification2.getFacePersistency()); - BOOST_CHECK_EQUAL(notification1.getLinkType(), notification2.getLinkType()); - BOOST_CHECK_EQUAL(notification1.getFlags(), notification2.getFlags()); - - std::ostringstream os; - os << notification2; - BOOST_CHECK_EQUAL(os.str(), "FaceEventNotification(" - "Kind: destroyed, " - "FaceID: 20, " - "RemoteUri: tcp4://192.0.2.1:55555, " - "LocalUri: tcp4://192.0.2.2:6363, " - "FaceScope: local, " - "FacePersistency: on-demand, " - "LinkType: multi-access, " - "Flags: 0x4)"); -} - -BOOST_AUTO_TEST_CASE(EncodeUp) -{ - FaceEventNotification notification1; - notification1.setKind(FACE_EVENT_UP) - .setFaceId(20) - .setRemoteUri("tcp4://192.0.2.1:55555") - .setLocalUri("tcp4://192.0.2.2:6363") - .setFaceScope(FACE_SCOPE_LOCAL) - .setFacePersistency(FACE_PERSISTENCY_ON_DEMAND) - .setLinkType(LINK_TYPE_MULTI_ACCESS) - .setFlags(0x05); - Block wire; - BOOST_REQUIRE_NO_THROW(wire = notification1.wireEncode()); - - // These octets are obtained by the snippet below. - // This check is intended to detect unexpected encoding change in the future. - // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { - // printf("0x%02x, ", *it); - // } - static const uint8_t expected[] = { - 0xc0, 0x41, 0xc1, 0x01, 0x03, 0x69, 0x01, 0x14, 0x72, 0x16, - 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, - 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x31, 0x3a, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x81, 0x15, 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, - 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x32, - 0x3a, 0x36, 0x33, 0x36, 0x33, 0x84, 0x01, 0x01, 0x85, 0x01, - 0x01, 0x86, 0x01, 0x01, 0x6c, 0x01, 0x05, - }; - BOOST_REQUIRE_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), - wire.begin(), wire.end()); - - BOOST_REQUIRE_NO_THROW(FaceEventNotification(wire)); - FaceEventNotification notification2(wire); - BOOST_CHECK_EQUAL(notification1.getKind(), notification2.getKind()); - BOOST_CHECK_EQUAL(notification1.getFaceId(), notification2.getFaceId()); - BOOST_CHECK_EQUAL(notification1.getRemoteUri(), notification2.getRemoteUri()); - BOOST_CHECK_EQUAL(notification1.getLocalUri(), notification2.getLocalUri()); - BOOST_CHECK_EQUAL(notification1.getFaceScope(), notification2.getFaceScope()); - BOOST_CHECK_EQUAL(notification1.getFacePersistency(), notification2.getFacePersistency()); - BOOST_CHECK_EQUAL(notification1.getLinkType(), notification2.getLinkType()); - - std::ostringstream os; - os << notification2; - BOOST_CHECK_EQUAL(os.str(), "FaceEventNotification(" - "Kind: up, " - "FaceID: 20, " - "RemoteUri: tcp4://192.0.2.1:55555, " - "LocalUri: tcp4://192.0.2.2:6363, " - "FaceScope: local, " - "FacePersistency: on-demand, " - "LinkType: multi-access, " - "Flags: 0x5)"); -} - -BOOST_AUTO_TEST_CASE(EncodeDown) -{ - FaceEventNotification notification1; - notification1.setKind(FACE_EVENT_DOWN) - .setFaceId(20) - .setRemoteUri("tcp4://192.0.2.1:55555") - .setLocalUri("tcp4://192.0.2.2:6363") - .setFaceScope(FACE_SCOPE_LOCAL) - .setFacePersistency(FACE_PERSISTENCY_ON_DEMAND) - .setLinkType(LINK_TYPE_MULTI_ACCESS) - .setFlags(0x06); - Block wire; - BOOST_REQUIRE_NO_THROW(wire = notification1.wireEncode()); - - // These octets are obtained by the snippet below. - // This check is intended to detect unexpected encoding change in the future. - // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { - // printf("0x%02x, ", *it); - // } - static const uint8_t expected[] = { - 0xc0, 0x41, 0xc1, 0x01, 0x04, 0x69, 0x01, 0x14, 0x72, 0x16, - 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, - 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x31, 0x3a, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x81, 0x15, 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, - 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x32, - 0x3a, 0x36, 0x33, 0x36, 0x33, 0x84, 0x01, 0x01, 0x85, 0x01, - 0x01, 0x86, 0x01, 0x01, 0x6c, 0x01, 0x06, - }; - BOOST_REQUIRE_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), - wire.begin(), wire.end()); - - BOOST_REQUIRE_NO_THROW(FaceEventNotification(wire)); - FaceEventNotification notification2(wire); - BOOST_CHECK_EQUAL(notification1.getKind(), notification2.getKind()); - BOOST_CHECK_EQUAL(notification1.getFaceId(), notification2.getFaceId()); - BOOST_CHECK_EQUAL(notification1.getRemoteUri(), notification2.getRemoteUri()); - BOOST_CHECK_EQUAL(notification1.getLocalUri(), notification2.getLocalUri()); - BOOST_CHECK_EQUAL(notification1.getFaceScope(), notification2.getFaceScope()); - BOOST_CHECK_EQUAL(notification1.getFacePersistency(), notification2.getFacePersistency()); - BOOST_CHECK_EQUAL(notification1.getLinkType(), notification2.getLinkType()); - - std::ostringstream os; - os << notification2; - BOOST_CHECK_EQUAL(os.str(), "FaceEventNotification(" - "Kind: down, " - "FaceID: 20, " - "RemoteUri: tcp4://192.0.2.1:55555, " - "LocalUri: tcp4://192.0.2.2:6363, " - "FaceScope: local, " - "FacePersistency: on-demand, " - "LinkType: multi-access, " - "Flags: 0x6)"); -} - -BOOST_AUTO_TEST_SUITE_END() // TestFaceEventNotification -BOOST_AUTO_TEST_SUITE_END() // Nfd -BOOST_AUTO_TEST_SUITE_END() // Mgmt - -} // namespace tests -} // namespace nfd -} // namespace ndn diff --git a/tests/unit-tests/mgmt/nfd/face-query-filter.t.cpp b/tests/unit-tests/mgmt/nfd/face-query-filter.t.cpp deleted file mode 100644 index 3871ce04a..000000000 --- a/tests/unit-tests/mgmt/nfd/face-query-filter.t.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "mgmt/nfd/face-query-filter.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace nfd { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Mgmt) -BOOST_AUTO_TEST_SUITE(Nfd) -BOOST_AUTO_TEST_SUITE(TestFaceQueryFilter) - -BOOST_AUTO_TEST_CASE(Encode) -{ - FaceQueryFilter filter1; - BOOST_CHECK_EQUAL(filter1.hasFaceId(), false); - BOOST_CHECK_EQUAL(filter1.hasUriScheme(), false); - BOOST_CHECK_EQUAL(filter1.hasRemoteUri(), false); - BOOST_CHECK_EQUAL(filter1.hasLocalUri(), false); - BOOST_CHECK_EQUAL(filter1.hasFaceScope(), false); - BOOST_CHECK_EQUAL(filter1.hasFacePersistency(), false); - BOOST_CHECK_EQUAL(filter1.hasLinkType(), false); - - filter1.setFaceId(100) - .setUriScheme("tcp4") - .setRemoteUri("tcp4://192.0.2.1:6363") - .setLocalUri("tcp4://192.0.2.2:55555") - .setFaceScope(FACE_SCOPE_LOCAL) - .setFacePersistency(FACE_PERSISTENCY_ON_DEMAND) - .setLinkType(LINK_TYPE_MULTI_ACCESS); - - Block wire; - BOOST_REQUIRE_NO_THROW(wire = filter1.wireEncode()); - - // These octets are obtained by the snippet below. - // This check is intended to detect unexpected encoding change in the future. - // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { - // printf("0x%02x, ", *it); - // } - static const uint8_t expected[] = { - 0x96, 0x41, 0x69, 0x01, 0x64, 0x83, 0x04, 0x74, 0x63, 0x70, - 0x34, 0x72, 0x15, 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, 0x2f, - 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x31, 0x3a, - 0x36, 0x33, 0x36, 0x33, 0x81, 0x16, 0x74, 0x63, 0x70, 0x34, - 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, - 0x2e, 0x32, 0x3a, 0x35, 0x35, 0x35, 0x35, 0x35, 0x84, 0x01, - 0x01, 0x85, 0x01, 0x01, 0x86, 0x01, 0x01, - }; - - BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), - wire.begin(), wire.end()); - - BOOST_REQUIRE_NO_THROW(FaceQueryFilter(wire)); - - FaceQueryFilter filter2(wire); - BOOST_CHECK_EQUAL(filter1.getFaceId(), filter2.getFaceId()); - BOOST_CHECK_EQUAL(filter1.getUriScheme(), filter2.getUriScheme()); - BOOST_CHECK_EQUAL(filter1.getRemoteUri(), filter2.getRemoteUri()); - BOOST_CHECK_EQUAL(filter1.getLocalUri(), filter2.getLocalUri()); - BOOST_CHECK_EQUAL(filter1.getFaceScope(), filter2.getFaceScope()); - BOOST_CHECK_EQUAL(filter1.getFacePersistency(), filter2.getFacePersistency()); - BOOST_CHECK_EQUAL(filter1.getLinkType(), filter2.getLinkType()); - - std::ostringstream os; - os << filter2; - BOOST_CHECK_EQUAL(os.str(), "FaceQueryFilter(FaceID: 100,\n" - "UriScheme: tcp4,\n" - "RemoteUri: tcp4://192.0.2.1:6363,\n" - "LocalUri: tcp4://192.0.2.2:55555,\n" - "FaceScope: local,\n" - "FacePersistency: on-demand,\n" - "LinkType: multi-access,\n" - ")"); -} - -BOOST_AUTO_TEST_SUITE_END() // TestFaceQueryFilter -BOOST_AUTO_TEST_SUITE_END() // Nfd -BOOST_AUTO_TEST_SUITE_END() // Mgmt - -} // namespace tests -} // namespace nfd -} // namespace ndn diff --git a/tests/unit-tests/mgmt/nfd/face-status.t.cpp b/tests/unit-tests/mgmt/nfd/face-status.t.cpp deleted file mode 100644 index 9f7118d97..000000000 --- a/tests/unit-tests/mgmt/nfd/face-status.t.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "mgmt/nfd/face-status.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace nfd { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Mgmt) -BOOST_AUTO_TEST_SUITE(Nfd) -BOOST_AUTO_TEST_SUITE(TestFaceStatus) - -BOOST_AUTO_TEST_CASE(Encode) -{ - FaceStatus status1; - status1.setFaceId(100) - .setRemoteUri("tcp4://192.0.2.1:6363") - .setLocalUri("tcp4://192.0.2.2:55555") - .setFaceScope(FACE_SCOPE_LOCAL) - .setFacePersistency(FACE_PERSISTENCY_ON_DEMAND) - .setLinkType(LINK_TYPE_MULTI_ACCESS) - .setExpirationPeriod(time::seconds(10)) - .setNInInterests(10) - .setNInDatas(200) - .setNInNacks(1) - .setNOutInterests(3000) - .setNOutDatas(4) - .setNOutNacks(2) - .setNInBytes(1329719163) - .setNOutBytes(999110448) - .setFlags(0x7); - - Block wire; - BOOST_REQUIRE_NO_THROW(wire = status1.wireEncode()); - - // These octets are obtained by the snippet below. - // This check is intended to detect unexpected encoding change in the future. - // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { - // printf("0x%02x, ", *it); - // } - static const uint8_t expected[] = { - 0x80, 0x61, 0x69, 0x01, 0x64, 0x72, 0x15, 0x74, 0x63, 0x70, - 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, - 0x32, 0x2e, 0x31, 0x3a, 0x36, 0x33, 0x36, 0x33, 0x81, 0x16, - 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, - 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x32, 0x3a, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x6d, 0x02, 0x27, 0x10, 0x84, 0x01, 0x01, 0x85, - 0x01, 0x01, 0x86, 0x01, 0x01, 0x90, 0x01, 0x0a, 0x91, 0x01, - 0xc8, 0x97, 0x01, 0x01, 0x92, 0x02, 0x0b, 0xb8, 0x93, 0x01, - 0x04, 0x98, 0x01, 0x02, 0x94, 0x04, 0x4f, 0x41, 0xe7, 0x7b, - 0x95, 0x04, 0x3b, 0x8d, 0x37, 0x30, 0x6c, 0x01, 0x07, - }; - BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), - wire.begin(), wire.end()); - - BOOST_REQUIRE_NO_THROW(FaceStatus(wire)); - FaceStatus status2(wire); - BOOST_CHECK_EQUAL(status1.getFaceId(), status2.getFaceId()); - BOOST_CHECK_EQUAL(status1.getRemoteUri(), status2.getRemoteUri()); - BOOST_CHECK_EQUAL(status1.getLocalUri(), status2.getLocalUri()); - BOOST_CHECK_EQUAL(status1.getFaceScope(), status2.getFaceScope()); - BOOST_CHECK_EQUAL(status1.getFacePersistency(), status2.getFacePersistency()); - BOOST_CHECK_EQUAL(status1.getLinkType(), status2.getLinkType()); - BOOST_CHECK_EQUAL(status1.getNInInterests(), status2.getNInInterests()); - BOOST_CHECK_EQUAL(status1.getNInDatas(), status2.getNInDatas()); - BOOST_CHECK_EQUAL(status1.getNInNacks(), status2.getNInNacks()); - BOOST_CHECK_EQUAL(status1.getNOutInterests(), status2.getNOutInterests()); - BOOST_CHECK_EQUAL(status1.getNOutDatas(), status2.getNOutDatas()); - BOOST_CHECK_EQUAL(status1.getNOutNacks(), status2.getNOutNacks()); - BOOST_CHECK_EQUAL(status1.getNInBytes(), status2.getNInBytes()); - BOOST_CHECK_EQUAL(status1.getNOutBytes(), status2.getNOutBytes()); - BOOST_CHECK_EQUAL(status1.getFlags(), status2.getFlags()); - - std::ostringstream os; - os << status2; - BOOST_CHECK_EQUAL(os.str(), "FaceStatus(FaceID: 100,\n" - "RemoteUri: tcp4://192.0.2.1:6363,\n" - "LocalUri: tcp4://192.0.2.2:55555,\n" - "ExpirationPeriod: 10000 milliseconds,\n" - "FaceScope: local,\n" - "FacePersistency: on-demand,\n" - "LinkType: multi-access,\n" - "Flags: 0x7,\n" - "Counters: { Interests: {in: 10, out: 3000},\n" - " Data: {in: 200, out: 4},\n" - " Nack: {in: 1, out: 2},\n" - " bytes: {in: 1329719163, out: 999110448} }\n" - ")"); -} - -BOOST_AUTO_TEST_CASE(FlagBit) -{ - FaceStatus status; - status.setFlags(0x7); - BOOST_CHECK_EQUAL(status.getFlags(), 0x7); - - BOOST_CHECK(status.getFlagBit(0)); - BOOST_CHECK(status.getFlagBit(1)); - BOOST_CHECK(status.getFlagBit(2)); - BOOST_CHECK(!status.getFlagBit(3)); - - status.setFlagBit(3, true); - BOOST_CHECK_EQUAL(status.getFlags(), 0xf); - BOOST_CHECK(status.getFlagBit(3)); - - status.setFlagBit(1, false); - BOOST_CHECK_EQUAL(status.getFlags(), 0xd); - BOOST_CHECK(!status.getFlagBit(1)); -} - -BOOST_AUTO_TEST_SUITE_END() // TestFaceStatus -BOOST_AUTO_TEST_SUITE_END() // Nfd -BOOST_AUTO_TEST_SUITE_END() // Mgmt - -} // namespace tests -} // namespace nfd -} // namespace ndn diff --git a/tests/unit-tests/mgmt/nfd/fib-entry.t.cpp b/tests/unit-tests/mgmt/nfd/fib-entry.t.cpp deleted file mode 100644 index 7723974d2..000000000 --- a/tests/unit-tests/mgmt/nfd/fib-entry.t.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "mgmt/nfd/fib-entry.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace nfd { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Mgmt) -BOOST_AUTO_TEST_SUITE(Nfd) -BOOST_AUTO_TEST_SUITE(TestFibEntry) - -const uint8_t TestNextHopRecord[] = -{ - 0x81, 0x06, 0x69, 0x01, 0x0a, 0x6a, 0x01, 0xc8 -}; - -const uint8_t TestFibEntryNoNextHops[] = -{ - 0x80, 0x15, 0x07, 0x13, 0x08, 0x04, 0x74, 0x68, 0x69, 0x73, - 0x08, 0x02, 0x69, 0x73, 0x08, 0x01, 0x61, 0x08, 0x04, 0x74, - 0x65, 0x73, 0x74 -}; - -const uint8_t TestFibEntry[] = -{ - 0x80, 0x38, 0x07, 0x13, 0x08, 0x04, 0x74, 0x68, 0x69, 0x73, 0x08, 0x02, 0x69, 0x73, 0x08, 0x01, - 0x61, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x81, 0x06, 0x69, 0x01, 0x0a, 0x6a, 0x01, 0xc8, 0x81, - 0x07, 0x69, 0x01, 0x14, 0x6a, 0x02, 0x01, 0x2c, 0x81, 0x07, 0x69, 0x01, 0x1e, 0x6a, 0x02, 0x01, - 0x90, 0x81, 0x07, 0x69, 0x01, 0x28, 0x6a, 0x02, 0x01, 0xf4 -}; - -BOOST_AUTO_TEST_CASE(TestNextHopRecordEncode) -{ - NextHopRecord record; - record.setFaceId(10); - record.setCost(200); - - const Block& wire = record.wireEncode(); - BOOST_REQUIRE_EQUAL_COLLECTIONS(TestNextHopRecord, - TestNextHopRecord + sizeof(TestNextHopRecord), - wire.begin(), wire.end()); - -} - -BOOST_AUTO_TEST_CASE(TestNextHopRecordDecode) -{ - NextHopRecord record; - - BOOST_REQUIRE_NO_THROW(record.wireDecode(Block(TestNextHopRecord, - sizeof(TestNextHopRecord)))); - BOOST_REQUIRE_EQUAL(record.getFaceId(), 10); - BOOST_REQUIRE_EQUAL(record.getCost(), 200); -} - -BOOST_AUTO_TEST_CASE(TestFibEntryNoNextHopEncode) -{ - FibEntry entry; - entry.setPrefix("/this/is/a/test"); - - const Block& wire = entry.wireEncode(); - BOOST_REQUIRE_EQUAL_COLLECTIONS(TestFibEntryNoNextHops, - TestFibEntryNoNextHops + sizeof(TestFibEntryNoNextHops), - wire.begin(), wire.end()); -} - -BOOST_AUTO_TEST_CASE(TestFibEntryNoNextHopsDecode) -{ - FibEntry entry; - BOOST_REQUIRE_NO_THROW(entry.wireDecode(Block(TestFibEntryNoNextHops, - sizeof(TestFibEntryNoNextHops)))); - - BOOST_REQUIRE_EQUAL(entry.getPrefix(), "/this/is/a/test"); - BOOST_REQUIRE(entry.getNextHopRecords().empty()); -} - -BOOST_AUTO_TEST_CASE(TestFibEntryEncode) -{ - FibEntry entry; - entry.setPrefix("/this/is/a/test"); - - std::list records; - - for (int i = 1; i < 4; i++) - { - NextHopRecord record; - record.setFaceId(i * 10); - record.setCost((i * 100) + 100); - records.push_back(record); - } - - entry.setNextHopRecords(records.begin(), records.end()); - - NextHopRecord oneMore; - oneMore.setFaceId(40); - oneMore.setCost(500); - - entry.addNextHopRecord(oneMore); - - const Block& wire = entry.wireEncode(); - BOOST_CHECK_EQUAL_COLLECTIONS(TestFibEntry, - TestFibEntry + sizeof(TestFibEntry), - wire.begin(), wire.end()); - - // std::ofstream of("out.tmp"); - // of.write((const char*)entry.wireEncode().wire(), - // entry.wireEncode().size()); -} - -BOOST_AUTO_TEST_CASE(TestFibEntryDecode) -{ - FibEntry entry; - BOOST_REQUIRE_NO_THROW(entry.wireDecode(Block(TestFibEntry, - sizeof(TestFibEntry)))); - - std::list records = entry.getNextHopRecords(); - - BOOST_CHECK_EQUAL(entry.getPrefix(), "/this/is/a/test"); - BOOST_CHECK_EQUAL(entry.getNextHopRecords().size(), 4); - - size_t value = 1; - - for (std::list::const_iterator i = records.begin(); - i != records.end(); - ++i) - { - BOOST_CHECK_EQUAL(i->getFaceId(), value * 10); - BOOST_CHECK_EQUAL(i->getCost(), (value * 100) + 100); - ++value; - } -} - -BOOST_AUTO_TEST_SUITE_END() // TestFibEntry -BOOST_AUTO_TEST_SUITE_END() // Nfd -BOOST_AUTO_TEST_SUITE_END() // Mgmt - -} // namespace tests -} // namespace nfd -} // namespace ndn diff --git a/tests/unit-tests/mgmt/nfd/forwarder-status.t.cpp b/tests/unit-tests/mgmt/nfd/forwarder-status.t.cpp deleted file mode 100644 index b7aefa0fe..000000000 --- a/tests/unit-tests/mgmt/nfd/forwarder-status.t.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "mgmt/nfd/forwarder-status.hpp" -#include "data.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace nfd { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Mgmt) -BOOST_AUTO_TEST_SUITE(Nfd) -BOOST_AUTO_TEST_SUITE(TestForwarderStatus) - -BOOST_AUTO_TEST_CASE(Encode) -{ - ForwarderStatus status1; - status1.setNfdVersion("0.2.0-65-g75ab6b7"); - status1.setStartTimestamp(time::fromUnixTimestamp(time::milliseconds(375193249325LL))); - status1.setCurrentTimestamp(time::fromUnixTimestamp(time::milliseconds(886109034272LL))); - status1.setNNameTreeEntries(1849943160); - status1.setNFibEntries(621739748); - status1.setNPitEntries(482129741); - status1.setNMeasurementsEntries(1771725298); - status1.setNCsEntries(1264968688); - status1.setNInInterests(612811615); - status1.setNInDatas(1843576050); - status1.setNInNacks(1234); - status1.setNOutInterests(952144445); - status1.setNOutDatas(138198826); - status1.setNOutNacks(4321); - - Block wire; - BOOST_REQUIRE_NO_THROW(wire = status1.wireEncode()); - - // These octets are obtained by the snippet below. - // This check is intended to detect unexpected encoding change in the future. - //for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { - // printf("0x%02x, ", *it); - //} - static const uint8_t expected[] = { - 0x15, 0x65, 0x80, 0x11, 0x30, 0x2e, 0x32, 0x2e, 0x30, 0x2d, 0x36, 0x35, - 0x2d, 0x67, 0x37, 0x35, 0x61, 0x62, 0x36, 0x62, 0x37, 0x81, 0x08, 0x00, - 0x00, 0x00, 0x57, 0x5b, 0x42, 0xa6, 0x2d, 0x82, 0x08, 0x00, 0x00, 0x00, - 0xce, 0x50, 0x36, 0xd7, 0x20, 0x83, 0x04, 0x6e, 0x43, 0xe4, 0x78, 0x84, - 0x04, 0x25, 0x0e, 0xfe, 0xe4, 0x85, 0x04, 0x1c, 0xbc, 0xb7, 0x4d, 0x86, - 0x04, 0x69, 0x9a, 0x61, 0xf2, 0x87, 0x04, 0x4b, 0x65, 0xe3, 0xf0, 0x90, - 0x04, 0x24, 0x86, 0xc3, 0x5f, 0x91, 0x04, 0x6d, 0xe2, 0xbc, 0xf2, 0x97, - 0x02, 0x04, 0xd2, 0x92, 0x04, 0x38, 0xc0, 0x92, 0x3d, 0x93, 0x04, 0x08, - 0x3c, 0xbf, 0x2a, 0x98, 0x02, 0x10, 0xe1, - }; - BOOST_REQUIRE_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), - wire.begin(), wire.end()); - - Data data; - data.setContent(wire); - - BOOST_REQUIRE_NO_THROW(ForwarderStatus(data.getContent())); - ForwarderStatus status2(data.getContent()); - BOOST_CHECK_EQUAL(status1.getNfdVersion(), status2.getNfdVersion()); - BOOST_CHECK_EQUAL(status1.getStartTimestamp(), status2.getStartTimestamp()); - BOOST_CHECK_EQUAL(status1.getCurrentTimestamp(), status2.getCurrentTimestamp()); - BOOST_CHECK_EQUAL(status1.getNNameTreeEntries(), status2.getNNameTreeEntries()); - BOOST_CHECK_EQUAL(status1.getNFibEntries(), status2.getNFibEntries()); - BOOST_CHECK_EQUAL(status1.getNPitEntries(), status2.getNPitEntries()); - BOOST_CHECK_EQUAL(status1.getNMeasurementsEntries(), status2.getNMeasurementsEntries()); - BOOST_CHECK_EQUAL(status1.getNCsEntries(), status2.getNCsEntries()); - BOOST_CHECK_EQUAL(status1.getNInInterests(), status2.getNInInterests()); - BOOST_CHECK_EQUAL(status1.getNInDatas(), status2.getNInDatas()); - BOOST_CHECK_EQUAL(status1.getNInNacks(), status2.getNInNacks()); - BOOST_CHECK_EQUAL(status1.getNOutInterests(), status2.getNOutInterests()); - BOOST_CHECK_EQUAL(status1.getNOutDatas(), status2.getNOutDatas()); - BOOST_CHECK_EQUAL(status1.getNOutNacks(), status2.getNOutNacks()); -} - -BOOST_AUTO_TEST_SUITE_END() // TestForwarderStatus -BOOST_AUTO_TEST_SUITE_END() // Nfd -BOOST_AUTO_TEST_SUITE_END() // Mgmt - -} // namespace tests -} // namespace nfd -} // namespace ndn diff --git a/tests/unit-tests/mgmt/nfd/rib-entry.t.cpp b/tests/unit-tests/mgmt/nfd/rib-entry.t.cpp deleted file mode 100644 index 415be29cd..000000000 --- a/tests/unit-tests/mgmt/nfd/rib-entry.t.cpp +++ /dev/null @@ -1,347 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "mgmt/nfd/rib-entry.hpp" -#include "mgmt/nfd/control-command.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace nfd { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Mgmt) -BOOST_AUTO_TEST_SUITE(Nfd) -BOOST_AUTO_TEST_SUITE(TestRibEntry) - -const uint8_t RouteData[] = -{ - 0x81, 0x10, 0x69, 0x01, 0x01, 0x6f, 0x01, 0x80, 0x6a, 0x01, 0x64, 0x6c, 0x01, 0x02, - 0x6d, 0x02, 0x27, 0x10 -}; - -const uint8_t RouteInfiniteExpirationPeriod[] = -{ - 0x81, 0x0C, 0x69, 0x01, 0x01, 0x6f, 0x01, 0x80, 0x6a, 0x01, 0x64, 0x6c, 0x01, 0x02 -}; - -const uint8_t RibEntryData[] = -{ - // Header + Name - 0x80, 0x34, 0x07, 0x0e, 0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, - 0x08, 0x05, 0x77, 0x6f, 0x72, 0x6c, 0x64, - // Route - 0x81, 0x10, 0x69, 0x01, 0x01, 0x6f, 0x01, 0x80, 0x6a, 0x01, 0x64, 0x6c, 0x01, 0x02, - 0x6d, 0x02, 0x27, 0x10, - // Route - 0x81, 0x10, 0x69, 0x01, 0x02, 0x6f, 0x01, 0x00, 0x6a, 0x01, 0x20, 0x6c, 0x01, 0x01, - 0x6d, 0x02, 0x13, 0x88 -}; - -const uint8_t RibEntryInfiniteExpirationPeriod[] = -{ - // Header + Name - 0x80, 0x30, 0x07, 0x0e, 0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, - 0x08, 0x05, 0x77, 0x6f, 0x72, 0x6c, 0x64, - // Route - 0x81, 0x10, 0x69, 0x01, 0x01, 0x6f, 0x01, 0x80, 0x6a, 0x01, 0x64, 0x6c, 0x01, 0x02, - 0x6d, 0x02, 0x27, 0x10, - // Route with no ExpirationPeriod - 0x81, 0x0C, 0x69, 0x01, 0x02, 0x6f, 0x01, 0x00, 0x6a, 0x01, 0x20, 0x6c, 0x01, 0x01, -}; - -BOOST_AUTO_TEST_CASE(RouteEncode) -{ - Route route; - route.setFaceId(1); - route.setOrigin(128); - route.setCost(100); - route.setFlags(ndn::nfd::ROUTE_FLAG_CAPTURE); - route.setExpirationPeriod(time::milliseconds(10000)); - - const Block& wire = route.wireEncode(); - - BOOST_REQUIRE_EQUAL_COLLECTIONS(RouteData, - RouteData + sizeof(RouteData), - wire.begin(), wire.end()); -} - -BOOST_AUTO_TEST_CASE(RouteDecode) -{ - Route route; - - BOOST_REQUIRE_NO_THROW(route.wireDecode(Block(RouteData, sizeof(RouteData)))); - - BOOST_REQUIRE_EQUAL(route.getFaceId(), 1); - BOOST_REQUIRE_EQUAL(route.getOrigin(), 128); - BOOST_REQUIRE_EQUAL(route.getCost(), 100); - BOOST_REQUIRE_EQUAL(route.getFlags(), static_cast(ndn::nfd::ROUTE_FLAG_CAPTURE)); - BOOST_REQUIRE_EQUAL(route.getExpirationPeriod(), time::milliseconds(10000)); - BOOST_REQUIRE_EQUAL(route.hasInfiniteExpirationPeriod(), false); -} - -BOOST_AUTO_TEST_CASE(RouteInfiniteExpirationPeriodEncode) -{ - Route route; - route.setFaceId(1); - route.setOrigin(128); - route.setCost(100); - route.setFlags(ndn::nfd::ROUTE_FLAG_CAPTURE); - route.setExpirationPeriod(Route::INFINITE_EXPIRATION_PERIOD); - - const Block& wire = route.wireEncode(); - - BOOST_REQUIRE_EQUAL_COLLECTIONS(RouteInfiniteExpirationPeriod, - RouteInfiniteExpirationPeriod + sizeof(RouteInfiniteExpirationPeriod), - wire.begin(), wire.end()); -} - -BOOST_AUTO_TEST_CASE(RouteInfiniteExpirationPeriodDecode) -{ - Route route; - - BOOST_REQUIRE_NO_THROW(route.wireDecode(Block(RouteInfiniteExpirationPeriod, - sizeof(RouteInfiniteExpirationPeriod)))); - - BOOST_REQUIRE_EQUAL(route.getFaceId(), 1); - BOOST_REQUIRE_EQUAL(route.getOrigin(), 128); - BOOST_REQUIRE_EQUAL(route.getCost(), 100); - BOOST_REQUIRE_EQUAL(route.getFlags(), static_cast(ndn::nfd::ROUTE_FLAG_CAPTURE)); - BOOST_REQUIRE_EQUAL(route.getExpirationPeriod(), Route::INFINITE_EXPIRATION_PERIOD); - BOOST_REQUIRE_EQUAL(route.hasInfiniteExpirationPeriod(), true); -} - -BOOST_AUTO_TEST_CASE(RouteOutputStream) -{ - Route route; - route.setFaceId(1); - route.setOrigin(128); - route.setCost(100); - route.setFlags(ndn::nfd::ROUTE_FLAG_CAPTURE); - route.setExpirationPeriod(time::milliseconds(10000)); - - std::ostringstream os; - os << route; - - BOOST_CHECK_EQUAL(os.str(), "Route(FaceId: 1, Origin: 128, Cost: 100, " - "Flags: 2, ExpirationPeriod: 10000 milliseconds)"); -} - -BOOST_AUTO_TEST_CASE(RibEntryEncode) -{ - RibEntry entry; - entry.setName("/hello/world"); - - Route route1; - route1.setFaceId(1); - route1.setOrigin(128); - route1.setCost(100); - route1.setFlags(ndn::nfd::ROUTE_FLAG_CAPTURE); - route1.setExpirationPeriod(time::milliseconds(10000)); - entry.addRoute(route1); - - Route route2; - route2.setFaceId(2); - route2.setOrigin(0); - route2.setCost(32); - route2.setFlags(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT); - route2.setExpirationPeriod(time::milliseconds(5000)); - entry.addRoute(route2); - - const Block& wire = entry.wireEncode(); - - BOOST_CHECK_EQUAL_COLLECTIONS(RibEntryData, - RibEntryData + sizeof(RibEntryData), - wire.begin(), wire.end()); -} - -BOOST_AUTO_TEST_CASE(RibEntryDecode) -{ - RibEntry entry; - BOOST_REQUIRE_NO_THROW(entry.wireDecode(Block(RibEntryData, - sizeof(RibEntryData)))); - - BOOST_CHECK_EQUAL(entry.getName(), "/hello/world"); - BOOST_CHECK_EQUAL(entry.getRoutes().size(), 2); - - std::list routes = entry.getRoutes(); - - std::list::const_iterator it = routes.begin(); - BOOST_CHECK_EQUAL(it->getFaceId(), 1); - BOOST_CHECK_EQUAL(it->getOrigin(), 128); - BOOST_CHECK_EQUAL(it->getCost(), 100); - BOOST_CHECK_EQUAL(it->getFlags(), static_cast(ndn::nfd::ROUTE_FLAG_CAPTURE)); - BOOST_CHECK_EQUAL(it->getExpirationPeriod(), time::milliseconds(10000)); - BOOST_CHECK_EQUAL(it->hasInfiniteExpirationPeriod(), false); - - ++it; - BOOST_CHECK_EQUAL(it->getFaceId(), 2); - BOOST_CHECK_EQUAL(it->getOrigin(), 0); - BOOST_CHECK_EQUAL(it->getCost(), 32); - BOOST_CHECK_EQUAL(it->getFlags(), static_cast(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT)); - BOOST_CHECK_EQUAL(it->getExpirationPeriod(), time::milliseconds(5000)); - BOOST_CHECK_EQUAL(it->hasInfiniteExpirationPeriod(), false); -} - -BOOST_AUTO_TEST_CASE(RibEntryInfiniteExpirationPeriodEncode) -{ - RibEntry entry; - entry.setName("/hello/world"); - - Route route1; - route1.setFaceId(1); - route1.setOrigin(128); - route1.setCost(100); - route1.setFlags(ndn::nfd::ROUTE_FLAG_CAPTURE); - route1.setExpirationPeriod(time::milliseconds(10000)); - entry.addRoute(route1); - - Route route2; - route2.setFaceId(2); - route2.setOrigin(0); - route2.setCost(32); - route2.setFlags(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT); - route2.setExpirationPeriod(Route::INFINITE_EXPIRATION_PERIOD); - entry.addRoute(route2); - - const Block& wire = entry.wireEncode(); - - BOOST_CHECK_EQUAL_COLLECTIONS(RibEntryInfiniteExpirationPeriod, - RibEntryInfiniteExpirationPeriod + - sizeof(RibEntryInfiniteExpirationPeriod), - wire.begin(), wire.end()); -} - -BOOST_AUTO_TEST_CASE(RibEntryInfiniteExpirationPeriodDecode) -{ - RibEntry entry; - BOOST_REQUIRE_NO_THROW(entry.wireDecode(Block(RibEntryInfiniteExpirationPeriod, - sizeof(RibEntryInfiniteExpirationPeriod)))); - - BOOST_CHECK_EQUAL(entry.getName(), "/hello/world"); - BOOST_CHECK_EQUAL(entry.getRoutes().size(), 2); - - std::list routes = entry.getRoutes(); - - std::list::const_iterator it = routes.begin(); - BOOST_CHECK_EQUAL(it->getFaceId(), 1); - BOOST_CHECK_EQUAL(it->getOrigin(), 128); - BOOST_CHECK_EQUAL(it->getCost(), 100); - BOOST_CHECK_EQUAL(it->getFlags(), static_cast(ndn::nfd::ROUTE_FLAG_CAPTURE)); - BOOST_CHECK_EQUAL(it->getExpirationPeriod(), time::milliseconds(10000)); - BOOST_CHECK_EQUAL(it->hasInfiniteExpirationPeriod(), false); - - ++it; - BOOST_CHECK_EQUAL(it->getFaceId(), 2); - BOOST_CHECK_EQUAL(it->getOrigin(), 0); - BOOST_CHECK_EQUAL(it->getCost(), 32); - BOOST_CHECK_EQUAL(it->getFlags(), static_cast(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT)); - BOOST_CHECK_EQUAL(it->getExpirationPeriod(), Route::INFINITE_EXPIRATION_PERIOD); - BOOST_CHECK_EQUAL(it->hasInfiniteExpirationPeriod(), true); -} - -BOOST_AUTO_TEST_CASE(RibEntryClear) -{ - RibEntry entry; - entry.setName("/hello/world"); - - Route route1; - route1.setFaceId(1); - route1.setOrigin(128); - route1.setCost(100); - route1.setFlags(ndn::nfd::ROUTE_FLAG_CAPTURE); - route1.setExpirationPeriod(time::milliseconds(10000)); - entry.addRoute(route1); - BOOST_REQUIRE_EQUAL(entry.getRoutes().size(), 1); - - std::list routes = entry.getRoutes(); - - std::list::const_iterator it = routes.begin(); - BOOST_CHECK_EQUAL(it->getFaceId(), 1); - BOOST_CHECK_EQUAL(it->getOrigin(), 128); - BOOST_CHECK_EQUAL(it->getCost(), 100); - BOOST_CHECK_EQUAL(it->getFlags(), static_cast(ndn::nfd::ROUTE_FLAG_CAPTURE)); - BOOST_CHECK_EQUAL(it->getExpirationPeriod(), time::milliseconds(10000)); - BOOST_CHECK_EQUAL(it->hasInfiniteExpirationPeriod(), false); - - entry.clearRoutes(); - BOOST_CHECK_EQUAL(entry.getRoutes().size(), 0); - - Route route2; - route2.setFaceId(2); - route2.setOrigin(0); - route2.setCost(32); - route2.setFlags(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT); - route2.setExpirationPeriod(Route::INFINITE_EXPIRATION_PERIOD); - entry.addRoute(route2); - BOOST_REQUIRE_EQUAL(entry.getRoutes().size(), 1); - - routes = entry.getRoutes(); - - it = routes.begin(); - BOOST_CHECK_EQUAL(it->getFaceId(), 2); - BOOST_CHECK_EQUAL(it->getOrigin(), 0); - BOOST_CHECK_EQUAL(it->getCost(), 32); - BOOST_CHECK_EQUAL(it->getFlags(), static_cast(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT)); - BOOST_CHECK_EQUAL(it->getExpirationPeriod(), Route::INFINITE_EXPIRATION_PERIOD); - BOOST_CHECK_EQUAL(it->hasInfiniteExpirationPeriod(), true); -} - -BOOST_AUTO_TEST_CASE(RibEntryOutputStream) -{ - RibEntry entry; - entry.setName("/hello/world"); - - Route route1; - route1.setFaceId(1); - route1.setOrigin(128); - route1.setCost(100); - route1.setFlags(ndn::nfd::ROUTE_FLAG_CAPTURE); - route1.setExpirationPeriod(time::milliseconds(10000)); - entry.addRoute(route1); - - Route route2; - route2.setFaceId(2); - route2.setOrigin(0); - route2.setCost(32); - route2.setFlags(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT); - route2.setExpirationPeriod(Route::INFINITE_EXPIRATION_PERIOD); - entry.addRoute(route2); - - std::ostringstream os; - os << entry; - - BOOST_CHECK_EQUAL(os.str(), "RibEntry{\n" - " Name: /hello/world\n" - " Route(FaceId: 1, Origin: 128, Cost: 100, " - "Flags: 2, ExpirationPeriod: 10000 milliseconds)\n" - " Route(FaceId: 2, Origin: 0, Cost: 32, " - "Flags: 1, ExpirationPeriod: Infinity)\n" - "}"); -} - -BOOST_AUTO_TEST_SUITE_END() // TestRibEntry -BOOST_AUTO_TEST_SUITE_END() // Nfd -BOOST_AUTO_TEST_SUITE_END() // Mgmt - -} // namespace tests -} // namespace nfd -} // namespace ndn diff --git a/tests/unit-tests/mgmt/nfd/strategy-choice.t.cpp b/tests/unit-tests/mgmt/nfd/strategy-choice.t.cpp deleted file mode 100644 index 4fca73789..000000000 --- a/tests/unit-tests/mgmt/nfd/strategy-choice.t.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "mgmt/nfd/strategy-choice.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace nfd { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Mgmt) -BOOST_AUTO_TEST_SUITE(Nfd) -BOOST_AUTO_TEST_SUITE(TestStrategyChoice) - -BOOST_AUTO_TEST_CASE(Encode) -{ - StrategyChoice strategyChoice1; - strategyChoice1 - .setName("/hello/world") - .setStrategy("/some/non/existing/strategy/name") - ; - - Block wire; - BOOST_REQUIRE_NO_THROW(wire = strategyChoice1.wireEncode()); - - // These octets are obtained by the snippet below. - // This check is intended to detect unexpected encoding change in the future. - // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { - // printf("0x%02x, ", *it); - // } - static const uint8_t expected[] = { - 0x80, 0x39, 0x07, 0x0e, 0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x08, 0x05, 0x77, - 0x6f, 0x72, 0x6c, 0x64, 0x6b, 0x27, 0x07, 0x25, 0x08, 0x04, 0x73, 0x6f, 0x6d, 0x65, - 0x08, 0x03, 0x6e, 0x6f, 0x6e, 0x08, 0x08, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, - 0x67, 0x08, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x08, 0x04, 0x6e, - 0x61, 0x6d, 0x65 - }; - BOOST_REQUIRE_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), - wire.begin(), wire.end()); - - BOOST_REQUIRE_NO_THROW(StrategyChoice(wire)); - StrategyChoice strategyChoice2(wire); - BOOST_CHECK_EQUAL(strategyChoice1.getName(), strategyChoice2.getName()); - BOOST_CHECK_EQUAL(strategyChoice1.getStrategy(), strategyChoice2.getStrategy()); -} - -BOOST_AUTO_TEST_SUITE_END() // TestStrategyChoice -BOOST_AUTO_TEST_SUITE_END() // Nfd -BOOST_AUTO_TEST_SUITE_END() // Mgmt - -} // namespace tests -} // namespace nfd -} // namespace ndn diff --git a/tests/unit-tests/name-component.t.cpp b/tests/unit-tests/name-component.t.cpp deleted file mode 100644 index 8a99b2fe4..000000000 --- a/tests/unit-tests/name-component.t.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "name-component.hpp" - -#include "boost-test.hpp" -#include - -namespace ndn { -namespace tests { - -BOOST_AUTO_TEST_SUITE(TestNameComponent) - -static const uint8_t NAME_COMPONENT_WIRE[] = { - 0x08, 0x03, // NameComponent - 0x6e, 0x64, 0x6e}; - -static const uint8_t NAME_COMPONENT2_WIRE[] = { - 0x08, 0x20, // ImplicitSha256DigestComponent - 0x28, 0xba, 0xd4, 0xb5, 0x27, 0x5b, 0xd3, 0x92, - 0xdb, 0xb6, 0x70, 0xc7, 0x5c, 0xf0, 0xb6, 0x6f, - 0x13, 0xf7, 0x94, 0x2b, 0x21, 0xe8, 0x0f, 0x55, - 0xc0, 0xe8, 0x6b, 0x37, 0x47, 0x53, 0xa5, 0x49 }; - -static const uint8_t DIGEST_COMPONENT_WIRE[] = { - 0x01, 0x20, // ImplicitSha256DigestComponent - 0x28, 0xba, 0xd4, 0xb5, 0x27, 0x5b, 0xd3, 0x92, - 0xdb, 0xb6, 0x70, 0xc7, 0x5c, 0xf0, 0xb6, 0x6f, - 0x13, 0xf7, 0x94, 0x2b, 0x21, 0xe8, 0x0f, 0x55, - 0xc0, 0xe8, 0x6b, 0x37, 0x47, 0x53, 0xa5, 0x48 }; - -static const uint8_t DIGEST_COMPONENT2_WIRE[] = { - 0x01, 0x20, // ImplicitSha256DigestComponent - 0x28, 0xba, 0xd4, 0xb5, 0x27, 0x5b, 0xd3, 0x92, - 0xdb, 0xb6, 0x70, 0xc7, 0x5c, 0xf0, 0xb6, 0x6f, - 0x13, 0xf7, 0x94, 0x2b, 0x21, 0xe8, 0x0f, 0x55, - 0xc0, 0xe8, 0x6b, 0x37, 0x47, 0x53, 0xa5, 0x49 }; - -static const uint8_t INVALID_COMPONENT_WIRE[] = { - 0x07, 0x03, // unknown component type - 0x6e, 0x64, 0x6e}; - -BOOST_AUTO_TEST_SUITE(Decode) - -BOOST_AUTO_TEST_CASE(Generic) -{ - Block block(NAME_COMPONENT_WIRE, sizeof(NAME_COMPONENT_WIRE)); - name::Component comp; - BOOST_REQUIRE_NO_THROW(comp.wireDecode(block)); - BOOST_CHECK_EQUAL(comp.toUri(), "ndn"); -} - -BOOST_AUTO_TEST_CASE(Digest) -{ - Block block(DIGEST_COMPONENT_WIRE, sizeof(DIGEST_COMPONENT_WIRE)); - name::Component comp; - BOOST_REQUIRE_NO_THROW(comp.wireDecode(block)); - BOOST_REQUIRE_EQUAL(comp.toUri(), "sha256digest=28bad4b5275bd392dbb670c75cf0b66f" - "13f7942b21e80f55c0e86b374753a548"); -} - -BOOST_AUTO_TEST_CASE(Invalid) -{ - Block block(INVALID_COMPONENT_WIRE, sizeof(INVALID_COMPONENT_WIRE)); - name::Component comp; - BOOST_REQUIRE_THROW(comp.wireDecode(block), name::Component::Error); -} - -BOOST_AUTO_TEST_SUITE_END() // Decode - -BOOST_AUTO_TEST_SUITE(Compare) - -BOOST_AUTO_TEST_CASE(Generic) -{ - name::Component compD("D"); - name::Component compD2("D"); - name::Component compF("F"); - name::Component compAA("AA"); - - BOOST_CHECK_EQUAL(compD == compD2, true); - BOOST_CHECK_EQUAL(compD != compD2, false); - BOOST_CHECK_EQUAL(compD < compD2, false); - BOOST_CHECK_EQUAL(compD <= compD2, true); - BOOST_CHECK_EQUAL(compD > compD2, false); - BOOST_CHECK_EQUAL(compD >= compD2, true); - - BOOST_CHECK_EQUAL(compD == compF, false); - BOOST_CHECK_EQUAL(compD != compF, true); - BOOST_CHECK_EQUAL(compD < compF, true); - BOOST_CHECK_EQUAL(compD <= compF, true); - BOOST_CHECK_EQUAL(compD > compF, false); - BOOST_CHECK_EQUAL(compD >= compF, false); - - BOOST_CHECK_EQUAL(compF == compAA, false); - BOOST_CHECK_EQUAL(compF != compAA, true); - BOOST_CHECK_EQUAL(compF < compAA, true); - BOOST_CHECK_EQUAL(compF <= compAA, true); - BOOST_CHECK_EQUAL(compF > compAA, false); - BOOST_CHECK_EQUAL(compF >= compAA, false); -} - -BOOST_AUTO_TEST_CASE(ZeroLength) -{ - name::Component comp0(""); - BOOST_REQUIRE_EQUAL(comp0.value_size(), 0); - - BOOST_CHECK_EQUAL(comp0, comp0); - BOOST_CHECK_EQUAL(comp0, name::Component("")); - BOOST_CHECK_LT(comp0, name::Component("A")); - BOOST_CHECK_LE(comp0, name::Component("A")); - BOOST_CHECK_NE(comp0, name::Component("A")); - BOOST_CHECK_GT(name::Component("A"), comp0); - BOOST_CHECK_GE(name::Component("A"), comp0); -} - -BOOST_AUTO_TEST_CASE(Digest) -{ - name::Component digest1(Block(DIGEST_COMPONENT_WIRE, sizeof(DIGEST_COMPONENT_WIRE))); - name::Component digest1b(Block(DIGEST_COMPONENT_WIRE, sizeof(DIGEST_COMPONENT_WIRE))); - name::Component digest2(Block(DIGEST_COMPONENT2_WIRE, sizeof(DIGEST_COMPONENT2_WIRE))); - name::Component generic0; - name::Component generic2(Block(NAME_COMPONENT2_WIRE, sizeof(NAME_COMPONENT2_WIRE))); - - BOOST_CHECK_EQUAL(digest1 == digest1b, true); - BOOST_CHECK_EQUAL(digest1 != digest1b, false); - BOOST_CHECK_EQUAL(digest1 < digest1b, false); - BOOST_CHECK_EQUAL(digest1 <= digest1b, true); - BOOST_CHECK_EQUAL(digest1 > digest1b, false); - BOOST_CHECK_EQUAL(digest1 >= digest1b, true); - - BOOST_CHECK_EQUAL(digest1 == digest2, false); - BOOST_CHECK_EQUAL(digest1 != digest2, true); - BOOST_CHECK_EQUAL(digest1 < digest2, true); - BOOST_CHECK_EQUAL(digest1 <= digest2, true); - BOOST_CHECK_EQUAL(digest1 > digest2, false); - BOOST_CHECK_EQUAL(digest1 >= digest2, false); - - BOOST_CHECK_EQUAL(digest1 == generic0, false); - BOOST_CHECK_EQUAL(digest1 != generic0, true); - BOOST_CHECK_EQUAL(digest1 < generic0, true); - BOOST_CHECK_EQUAL(digest1 <= generic0, true); - BOOST_CHECK_EQUAL(digest1 > generic0, false); - BOOST_CHECK_EQUAL(digest1 >= generic0, false); - - BOOST_CHECK_EQUAL(digest2 == generic2, false); - BOOST_CHECK_EQUAL(digest2 != generic2, true); - BOOST_CHECK_EQUAL(digest2 < generic2, true); - BOOST_CHECK_EQUAL(digest2 <= generic2, true); - BOOST_CHECK_EQUAL(digest2 > generic2, false); - BOOST_CHECK_EQUAL(digest2 >= generic2, false); -} - -BOOST_AUTO_TEST_SUITE_END() // Compare - -BOOST_AUTO_TEST_SUITE(CreateFromIterators) // Bug 2490 - -typedef boost::mpl::vector< - std::vector, - std::list, - std::vector, - std::list -> ContainerTypes; - -BOOST_AUTO_TEST_CASE_TEMPLATE(ZeroOctet, T, ContainerTypes) -{ - T bytes; - name::Component c(bytes.begin(), bytes.end()); - BOOST_CHECK_EQUAL(c.value_size(), 0); - BOOST_CHECK_EQUAL(c.size(), 2); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(OneOctet, T, ContainerTypes) -{ - T bytes{1}; - name::Component c(bytes.begin(), bytes.end()); - BOOST_CHECK_EQUAL(c.value_size(), 1); - BOOST_CHECK_EQUAL(c.size(), 3); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(FourOctets, T, ContainerTypes) -{ - T bytes{1, 2, 3, 4}; - name::Component c(bytes.begin(), bytes.end()); - BOOST_CHECK_EQUAL(c.value_size(), 4); - BOOST_CHECK_EQUAL(c.size(), 6); -} - -BOOST_AUTO_TEST_SUITE_END() // CreateFromIterators - -BOOST_AUTO_TEST_SUITE_END() // TestNameComponent - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/name.t.cpp b/tests/unit-tests/name.t.cpp deleted file mode 100644 index a49a9c4ac..000000000 --- a/tests/unit-tests/name.t.cpp +++ /dev/null @@ -1,509 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "name.hpp" - -#include "boost-test.hpp" -#include -#include -#include - -namespace ndn { -namespace tests { - -BOOST_AUTO_TEST_SUITE(TestName) - -static const uint8_t TestName[] = { - 0x7, 0x14, // Name - 0x8, 0x5, // NameComponent - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x8, 0x3, // NameComponent - 0x6e, 0x64, 0x6e, - 0x8, 0x6, // NameComponent - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78 -}; - -const uint8_t Name1[] = {0x7, 0x7, // Name - 0x8, 0x5, // NameComponent - 0x6c, 0x6f, 0x63, 0x61, 0x6c}; - -const uint8_t Name2[] = {0x7, 0xc, // Name - 0x8, 0x5, // NameComponent - 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x8, 0x3, // NameComponent - 0x6e, 0x64, 0x6e}; - -BOOST_AUTO_TEST_CASE(Basic) -{ - Name name("/hello/world"); - - BOOST_CHECK_NO_THROW(name.at(0)); - BOOST_CHECK_NO_THROW(name.at(1)); - BOOST_CHECK_NO_THROW(name.at(-1)); - BOOST_CHECK_NO_THROW(name.at(-2)); - - BOOST_CHECK_THROW(name.at(2), Name::Error); - BOOST_CHECK_THROW(name.at(-3), Name::Error); -} - -BOOST_AUTO_TEST_CASE(Encode) -{ - Name name("/local/ndn/prefix"); - - const Block &wire = name.wireEncode(); - - // for (Buffer::const_iterator i = wire.begin(); - // i != wire.end(); - // ++i) - // { - // std::ios::fmtflags saveFlags = std::cout.flags(std::ios::hex); - - // if (i != wire.begin()) - // std::cout << ", "; - // std::cout << "0x" << static_cast(*i); - - // std::cout.flags(saveFlags); - // } - // std::cout << std::endl; - - BOOST_CHECK_EQUAL_COLLECTIONS(TestName, TestName+sizeof(TestName), - wire.begin(), wire.end()); -} - - -BOOST_AUTO_TEST_CASE(Decode) -{ - Block block(TestName, sizeof(TestName)); - - Name name(block); - - BOOST_CHECK_EQUAL(name.toUri(), "/local/ndn/prefix"); -} - -BOOST_AUTO_TEST_CASE(AppendsAndMultiEncode) -{ - Name name("/local"); - - BOOST_CHECK_EQUAL_COLLECTIONS(name.wireEncode().begin(), name.wireEncode().end(), - Name1, Name1 + sizeof(Name1)); - - name.append("ndn"); - - BOOST_CHECK_EQUAL_COLLECTIONS(name.wireEncode().begin(), name.wireEncode().end(), - Name2, Name2 + sizeof(Name2)); - - name.append("prefix"); - BOOST_CHECK_EQUAL_COLLECTIONS(name.wireEncode().begin(), name.wireEncode().end(), - TestName, TestName+sizeof(TestName)); -} - -BOOST_AUTO_TEST_CASE(ZeroLengthComponent) -{ - static const uint8_t compOctets[] {0x08, 0x00}; - Block compBlock(compOctets, sizeof(compOctets)); - name::Component comp; - BOOST_REQUIRE_NO_THROW(comp.wireDecode(compBlock)); - BOOST_CHECK_EQUAL(comp.value_size(), 0); - - static const uint8_t nameOctets[] {0x07, 0x08, 0x08, 0x01, 0x41, 0x08, 0x00, 0x08, 0x01, 0x42}; - Block nameBlock(nameOctets, sizeof(nameOctets)); - static const std::string nameUri("/A/.../B"); - Name name; - BOOST_REQUIRE_NO_THROW(name.wireDecode(nameBlock)); - BOOST_CHECK_EQUAL(name.toUri(), nameUri); - Block nameEncoded = name.wireEncode(); - BOOST_CHECK(nameEncoded == nameBlock); - - Name name2; - BOOST_REQUIRE_NO_THROW(name2 = Name(nameUri)); - BOOST_CHECK_EQUAL(name2.toUri(), nameUri); - Block name2Encoded = name2.wireEncode(); - BOOST_CHECK(name2Encoded == nameBlock); -} - -BOOST_AUTO_TEST_CASE(AppendNumber) -{ - Name name; - for (uint32_t i = 0; i < 10; i++) - { - name.appendNumber(i); - } - - BOOST_CHECK_EQUAL(name.size(), 10); - - for (uint32_t i = 0; i < 10; i++) - { - BOOST_CHECK_EQUAL(name[i].toNumber(), i); - } -} - -class Numeric -{ -public: - typedef std::list, - function, - function, - Name/*expected*/, - uint64_t/*value*/, - function > > Dataset; - - Numeric() - { - dataset.push_back(boost::make_tuple(bind(&name::Component::fromNumberWithMarker, - 0xAA, _1), - bind(&name::Component::toNumberWithMarker, _1, 0xAA), - bind(&Name::appendNumberWithMarker, _1, 0xAA, _2), - Name("/%AA%03%E8"), - 1000, - bind(&name::Component::isNumberWithMarker, _1, 0xAA))); - dataset.push_back(boost::make_tuple(&name::Component::fromSegment, - bind(&name::Component::toSegment, _1), - bind(&Name::appendSegment, _1, _2), - Name("/%00%27%10"), - 10000, - bind(&name::Component::isSegment, _1))); - dataset.push_back(boost::make_tuple(&name::Component::fromSegmentOffset, - bind(&name::Component::toSegmentOffset, _1), - bind(&Name::appendSegmentOffset, _1, _2), - Name("/%FB%00%01%86%A0"), - 100000, - bind(&name::Component::isSegmentOffset, _1))); - dataset.push_back(boost::make_tuple(&name::Component::fromVersion, - bind(&name::Component::toVersion, _1), - bind(static_cast( - &Name::appendVersion), _1, _2), - Name("/%FD%00%0FB%40"), - 1000000, - bind(&name::Component::isVersion, _1))); - dataset.push_back(boost::make_tuple(&name::Component::fromSequenceNumber, - bind(&name::Component::toSequenceNumber, _1), - bind(&Name::appendSequenceNumber, _1, _2), - Name("/%FE%00%98%96%80"), - 10000000, - bind(&name::Component::isSequenceNumber, _1))); - } - - Dataset dataset; -}; - -class Timestamp -{ -public: - typedef std::list, - function, - function, - Name/*expected*/, - time::system_clock::TimePoint/*value*/, - function > > Dataset; - Timestamp() - { - dataset.push_back(boost::make_tuple(&name::Component::fromTimestamp, - ndn::bind(&name::Component::toTimestamp, _1), - ndn::bind(&Name::appendTimestamp, _1, _2), - Name("/%FC%00%04%7BE%E3%1B%00%00"), - time::getUnixEpoch() + time::days(14600/*40 years*/), - bind(&name::Component::isTimestamp, _1))); - } - - Dataset dataset; -}; - -typedef boost::mpl::vector ConventionsDatasets; - -BOOST_FIXTURE_TEST_CASE_TEMPLATE(NamingConventions, T, ConventionsDatasets, T) -{ - // // These octets are obtained by the snippet below. - // // This check is intended to detect unexpected encoding change in the future. - // for (typename T::Dataset::const_iterator it = this->dataset.begin(); - // it != this->dataset.end(); ++it) { - // Name name; - // name.append(it->template get<0>()(it->template get<4>())); - // std::cout << name << std::endl; - // } - - name::Component invalidComponent1; - name::Component invalidComponent2("1234567890"); - - for (typename T::Dataset::const_iterator it = this->dataset.begin(); - it != this->dataset.end(); ++it) { - const Name& expected = it->template get<3>(); - BOOST_TEST_MESSAGE("Check " << expected[0].toUri()); - - BOOST_CHECK_EQUAL(expected[0].isGeneric(), true); - - name::Component actualComponent = it->template get<0>()(it->template get<4>()); - BOOST_CHECK_EQUAL(actualComponent, expected[0]); - - Name actualName; - it->template get<2>()(actualName, it->template get<4>()); - BOOST_CHECK_EQUAL(actualName, expected); - - BOOST_CHECK_EQUAL(it->template get<5>()(expected[0]), true); - BOOST_REQUIRE_NO_THROW(it->template get<1>()(expected[0])); - BOOST_CHECK_EQUAL(it->template get<1>()(expected[0]), it->template get<4>()); - - BOOST_CHECK_EQUAL(it->template get<5>()(invalidComponent1), false); - BOOST_CHECK_EQUAL(it->template get<5>()(invalidComponent2), false); - - BOOST_REQUIRE_THROW(it->template get<1>()(invalidComponent1), name::Component::Error); - BOOST_REQUIRE_THROW(it->template get<1>()(invalidComponent2), name::Component::Error); - } -} - -BOOST_AUTO_TEST_CASE(GetSuccessor) -{ - BOOST_CHECK_EQUAL(Name("ndn:/%00%01/%01%02").getSuccessor(), Name("ndn:/%00%01/%01%03")); - BOOST_CHECK_EQUAL(Name("ndn:/%00%01/%01%FF").getSuccessor(), Name("ndn:/%00%01/%02%00")); - BOOST_CHECK_EQUAL(Name("ndn:/%00%01/%FF%FF").getSuccessor(), Name("ndn:/%00%01/%00%00%00")); - BOOST_CHECK_EQUAL(Name().getSuccessor(), Name("ndn:/%00")); -} - -BOOST_AUTO_TEST_CASE(Markers) -{ - Name name; - uint64_t number; - - BOOST_REQUIRE_NO_THROW(number = name.appendSegment(30923).at(-1).toSegment()); - BOOST_CHECK_EQUAL(number, 30923); - - BOOST_REQUIRE_NO_THROW(number = name.appendSegmentOffset(589).at(-1).toSegmentOffset()); - BOOST_CHECK_EQUAL(number, 589); - - BOOST_REQUIRE_NO_THROW(number = name.appendVersion().at(-1).toVersion()); - - BOOST_REQUIRE_NO_THROW(number = name.appendVersion(25912).at(-1).toVersion()); - BOOST_CHECK_EQUAL(number, 25912); - - const time::system_clock::TimePoint tp = time::system_clock::now(); - time::system_clock::TimePoint tp2; - BOOST_REQUIRE_NO_THROW(tp2 = name.appendTimestamp(tp).at(-1).toTimestamp()); - BOOST_CHECK_LE(std::abs(time::duration_cast(tp2 - tp).count()), 1); - - BOOST_REQUIRE_NO_THROW(number = name.appendSequenceNumber(11676).at(-1).toSequenceNumber()); - BOOST_CHECK_EQUAL(number, 11676); -} - -BOOST_AUTO_TEST_CASE(UnorderedMap) -{ - std::unordered_map map; - Name name1("/1"); - Name name2("/2"); - Name name3("/3"); - map[name1] = 1; - map[name2] = 2; - map[name3] = 3; - - BOOST_CHECK_EQUAL(map[name1], 1); - BOOST_CHECK_EQUAL(map[name2], 2); - BOOST_CHECK_EQUAL(map[name3], 3); -} - -BOOST_AUTO_TEST_CASE(ImplicitSha256Digest) -{ - Name n; - - static const uint8_t DIGEST[] = {0x28, 0xba, 0xd4, 0xb5, 0x27, 0x5b, 0xd3, 0x92, - 0xdb, 0xb6, 0x70, 0xc7, 0x5c, 0xf0, 0xb6, 0x6f, - 0x13, 0xf7, 0x94, 0x2b, 0x21, 0xe8, 0x0f, 0x55, - 0xc0, 0xe8, 0x6b, 0x37, 0x47, 0x53, 0xa5, 0x48, - 0x00, 0x00}; - - BOOST_REQUIRE_NO_THROW(n.appendImplicitSha256Digest(DIGEST, 32)); - BOOST_REQUIRE_NO_THROW(n.appendImplicitSha256Digest(make_shared(DIGEST, 32))); - BOOST_CHECK_EQUAL(n.get(0), n.get(1)); - - BOOST_REQUIRE_THROW(n.appendImplicitSha256Digest(DIGEST, 34), name::Component::Error); - BOOST_REQUIRE_THROW(n.appendImplicitSha256Digest(DIGEST, 30), name::Component::Error); - - n.append(DIGEST, 32); - BOOST_CHECK_LT(n.get(0), n.get(2)); - BOOST_CHECK_EQUAL_COLLECTIONS(n.get(0).value_begin(), n.get(0).value_end(), - n.get(2).value_begin(), n.get(2).value_end()); - - n.append(DIGEST + 1, 32); - BOOST_CHECK_LT(n.get(0), n.get(3)); - - n.append(DIGEST + 2, 32); - BOOST_CHECK_LT(n.get(0), n.get(4)); - - BOOST_CHECK_EQUAL(n.get(0).toUri(), "sha256digest=" - "28bad4b5275bd392dbb670c75cf0b66f13f7942b21e80f55c0e86b374753a548"); - - BOOST_CHECK_EQUAL(n.get(0).isImplicitSha256Digest(), true); - BOOST_CHECK_EQUAL(n.get(2).isImplicitSha256Digest(), false); - - BOOST_CHECK_THROW(Name("/hello/sha256digest=hmm"), name::Component::Error); - - Name n2; - // check canonical URI encoding (lower case) - BOOST_CHECK_NO_THROW(n2 = Name("/hello/sha256digest=" - "28bad4b5275bd392dbb670c75cf0b66f13f7942b21e80f55c0e86b374753a548")); - BOOST_CHECK_EQUAL(n.get(0), n2.get(1)); - - // will accept hex value in upper case too - BOOST_CHECK_NO_THROW(n2 = Name("/hello/sha256digest=" - "28BAD4B5275BD392DBB670C75CF0B66F13F7942B21E80F55C0E86B374753A548")); - BOOST_CHECK_EQUAL(n.get(0), n2.get(1)); - - // this is not valid sha256digest component, will be treated as generic component - BOOST_CHECK_NO_THROW(n2 = Name("/hello/SHA256DIGEST=" - "28BAD4B5275BD392DBB670C75CF0B66F13F7942B21E80F55C0E86B374753A548")); - BOOST_CHECK_NE(n.get(0), n2.get(1)); - BOOST_CHECK(n2.get(1).isGeneric()); -} - -BOOST_AUTO_TEST_CASE(Compare) -{ - BOOST_CHECK_EQUAL(Name("/A") .compare(Name("/A")), 0); - BOOST_CHECK_EQUAL(Name("/A") .compare(Name("/A")), 0); - BOOST_CHECK_LT (Name("/A") .compare(Name("/B")), 0); - BOOST_CHECK_GT (Name("/B") .compare(Name("/A")), 0); - BOOST_CHECK_LT (Name("/A") .compare(Name("/AA")), 0); - BOOST_CHECK_GT (Name("/AA") .compare(Name("/A")), 0); - BOOST_CHECK_LT (Name("/A") .compare(Name("/A/C")), 0); - BOOST_CHECK_GT (Name("/A/C").compare(Name("/A")), 0); - - BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/A")), 0); - BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/A")), 0); - BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/B")), 0); - BOOST_CHECK_GT (Name("/Z/B/Y") .compare(1, 1, Name("/A")), 0); - BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/AA")), 0); - BOOST_CHECK_GT (Name("/Z/AA/Y") .compare(1, 1, Name("/A")), 0); - BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/A/C")), 0); - BOOST_CHECK_GT (Name("/Z/A/C/Y").compare(1, 2, Name("/A")), 0); - - BOOST_CHECK_EQUAL(Name("/Z/A") .compare(1, Name::npos, Name("/A")), 0); - BOOST_CHECK_EQUAL(Name("/Z/A") .compare(1, Name::npos, Name("/A")), 0); - BOOST_CHECK_LT (Name("/Z/A") .compare(1, Name::npos, Name("/B")), 0); - BOOST_CHECK_GT (Name("/Z/B") .compare(1, Name::npos, Name("/A")), 0); - BOOST_CHECK_LT (Name("/Z/A") .compare(1, Name::npos, Name("/AA")), 0); - BOOST_CHECK_GT (Name("/Z/AA") .compare(1, Name::npos, Name("/A")), 0); - BOOST_CHECK_LT (Name("/Z/A") .compare(1, Name::npos, Name("/A/C")), 0); - BOOST_CHECK_GT (Name("/Z/A/C").compare(1, Name::npos, Name("/A")), 0); - - BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/X/A/W"), 1, 1), 0); - BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/X/A/W"), 1, 1), 0); - BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/B/W"), 1, 1), 0); - BOOST_CHECK_GT (Name("/Z/B/Y") .compare(1, 1, Name("/X/A/W"), 1, 1), 0); - BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/AA/W"), 1, 1), 0); - BOOST_CHECK_GT (Name("/Z/AA/Y") .compare(1, 1, Name("/X/A/W"), 1, 1), 0); - BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/A/C/W"), 1, 2), 0); - BOOST_CHECK_GT (Name("/Z/A/C/Y").compare(1, 2, Name("/X/A/W"), 1, 1), 0); - - BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/X/A"), 1), 0); - BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/X/A"), 1), 0); - BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/B"), 1), 0); - BOOST_CHECK_GT (Name("/Z/B/Y") .compare(1, 1, Name("/X/A"), 1), 0); - BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/AA"), 1), 0); - BOOST_CHECK_GT (Name("/Z/AA/Y") .compare(1, 1, Name("/X/A"), 1), 0); - BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/A/C"), 1), 0); - BOOST_CHECK_GT (Name("/Z/A/C/Y").compare(1, 2, Name("/X/A"), 1), 0); -} - -BOOST_AUTO_TEST_CASE(NameWithSpaces) -{ - Name name("/ hello\t/\tworld \r\n"); - - BOOST_CHECK_EQUAL("/hello/world", name); - BOOST_CHECK_THROW(Name("/hello//world"), name::Component::Error); -} - -BOOST_AUTO_TEST_CASE(Append) -{ - PartialName toAppend("/and"); - PartialName toAppend1("/beyond"); - { - Name name("/hello/world"); - BOOST_CHECK_EQUAL("/hello/world/hello/world", name.append(name)); - BOOST_CHECK_EQUAL("/hello/world/hello/world", name); - } - { - Name name("/hello/world"); - BOOST_CHECK_EQUAL("/hello/world/and", name.append(toAppend)); - } - { - Name name("/hello/world"); - BOOST_CHECK_EQUAL("/hello/world/and/beyond", name.append(toAppend).append(toAppend1)); - } -} - -BOOST_AUTO_TEST_CASE(SubName) -{ - Name name("/hello/world"); - - BOOST_CHECK_EQUAL("/hello/world", name.getSubName(0)); - BOOST_CHECK_EQUAL("/world", name.getSubName(1)); - BOOST_CHECK_EQUAL("/hello/", name.getSubName(0, 1)); -} - -BOOST_AUTO_TEST_CASE(SubNameNegativeIndex) -{ - Name name("/first/second/third/last"); - - BOOST_CHECK_EQUAL("/last", name.getSubName(-1)); - BOOST_CHECK_EQUAL("/third/last", name.getSubName(-2)); - BOOST_CHECK_EQUAL("/second", name.getSubName(-3, 1)); -} - -BOOST_AUTO_TEST_CASE(SubNameOutOfRangeIndexes) -{ - Name name("/first/second/last"); - // No length - BOOST_CHECK_EQUAL("/first/second/last", name.getSubName(-10)); - BOOST_CHECK_EQUAL("/", name.getSubName(10)); - - // Starting after the max position - BOOST_CHECK_EQUAL("/", name.getSubName(10, 1)); - BOOST_CHECK_EQUAL("/", name.getSubName(10, 10)); - - // Not enough components - BOOST_CHECK_EQUAL("/second/last", name.getSubName(1, 10)); - BOOST_CHECK_EQUAL("/last", name.getSubName(-1, 10)); - - // Start before first - BOOST_CHECK_EQUAL("/first/second", name.getSubName(-10, 2)); - BOOST_CHECK_EQUAL("/first/second/last", name.getSubName(-10, 10)); -} - -BOOST_AUTO_TEST_CASE(DeepCopy) -{ - Name n1("/hello/world"); - Name n2 = n1.deepCopy(); - - BOOST_CHECK_EQUAL(n1, n2); - BOOST_CHECK_NE(&n1.wireEncode(), &n2.wireEncode()); - - EncodingBuffer buffer(1024, 0); - n1.wireEncode(buffer); - Name n3(buffer.block()); - - BOOST_CHECK_EQUAL(n1, n3); - BOOST_CHECK_EQUAL(n3.wireEncode().getBuffer()->size(), 1024); - n3 = n3.deepCopy(); - - BOOST_CHECK_LT(n3.wireEncode().size(), 1024); - BOOST_CHECK_EQUAL(n3.wireEncode().getBuffer()->size(), n3.wireEncode().size()); -} - -BOOST_AUTO_TEST_SUITE_END() // TestName - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/network-configuration-detector.hpp b/tests/unit-tests/network-configuration-detector.hpp deleted file mode 100644 index 95d2aa862..000000000 --- a/tests/unit-tests/network-configuration-detector.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_TESTS_NETWORK_CONFIGURATION_DETECTOR_HPP -#define NDN_TESTS_NETWORK_CONFIGURATION_DETECTOR_HPP - -#define SKIP_IF_IPV4_UNAVAILABLE() \ - do { \ - if (!NetworkConfigurationDetector::hasIpv4()) { \ - BOOST_WARN_MESSAGE(false, "skipping assertions that require IPv4 support"); \ - return; \ - } \ - } while (false) - -#define SKIP_IF_IPV6_UNAVAILABLE() \ - do { \ - if (!NetworkConfigurationDetector::hasIpv6()) { \ - BOOST_WARN_MESSAGE(false, "skipping assertions that require IPv6 support"); \ - return; \ - } \ - } while (false) - -namespace ndn { -namespace tests { - -class NetworkConfigurationDetector -{ -public: - static bool - hasIpv4(); - - static bool - hasIpv6(); - -private: - static void - detect(); - -private: - static bool m_isInitialized; - static bool m_hasIpv4; - static bool m_hasIpv6; -}; - -} // namespace tests -} // namespace ndn - -#endif // NDN_TESTS_NETWORK_CONFIGURATION_DETECTOR_HPP diff --git a/tests/unit-tests/security/certificate-cache-ttl.t.cpp b/tests/unit-tests/security/certificate-cache-ttl.t.cpp deleted file mode 100644 index 2bf11f4a1..000000000 --- a/tests/unit-tests/security/certificate-cache-ttl.t.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/certificate-cache-ttl.hpp" -#include "face.hpp" -#include "util/time-unit-test-clock.hpp" - -#include "boost-test.hpp" -#include "../unit-test-time-fixture.hpp" - -namespace ndn { -namespace security { -namespace tests { - -using namespace ndn::tests; - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(TestCertificateCacheTtl) - -class CertificateCacheFixture : public UnitTestTimeFixture -{ -public: - CertificateCacheFixture() - : scheduler(io) - , cache(make_shared(ref(io), time::seconds(1))) - { - cert1 = make_shared(); - Name certName1("/tmp/KEY/ksk-1/ID-CERT/1"); - cert1->setName(certName1); - cert1->setFreshnessPeriod(time::milliseconds(500)); - - cert2 = make_shared(); - Name certName2("/tmp/KEY/ksk-2/ID-CERT/2"); - cert2->setName(certName2); - cert2->setFreshnessPeriod(time::milliseconds(1000)); - - name1 = certName1.getPrefix(-1); - name2 = certName2.getPrefix(-1); - } - -public: - Scheduler scheduler; - - shared_ptr cache; - - shared_ptr cert1; - shared_ptr cert2; - - Name name1; - Name name2; -}; - -BOOST_FIXTURE_TEST_CASE(Expiration, CertificateCacheFixture) -{ - cache->insertCertificate(cert1); - cache->insertCertificate(cert2); - - advanceClocks(time::nanoseconds(1)); - BOOST_CHECK_EQUAL(cache->getSize(), 2); - - scheduler.scheduleEvent(time::milliseconds(200), [&] { - BOOST_CHECK_EQUAL(cache->getSize(), 2); - BOOST_CHECK_EQUAL(static_cast(cache->getCertificate(name1)), true); - BOOST_CHECK_EQUAL(static_cast(cache->getCertificate(name2)), true); - }); - - advanceClocks(time::milliseconds(200)); - - // cert1 should removed from the cache - scheduler.scheduleEvent(time::milliseconds(700), [&] { - BOOST_CHECK_EQUAL(static_cast(cache->getCertificate(name1)), false); - BOOST_CHECK_EQUAL(static_cast(cache->getCertificate(name2)), true); - }); - - advanceClocks(time::milliseconds(700)); - BOOST_CHECK_EQUAL(cache->getSize(), 1); - - advanceClocks(time::milliseconds(700)); - BOOST_CHECK_EQUAL(cache->getSize(), 0); -} - -BOOST_FIXTURE_TEST_CASE(TtlRefresh, CertificateCacheFixture) -{ - cache->insertCertificate(cert1); // 500ms - - advanceClocks(time::nanoseconds(1)); - BOOST_CHECK_EQUAL(cache->getSize(), 1); - - advanceClocks(time::milliseconds(400)); - BOOST_CHECK_EQUAL(cache->getSize(), 1); - - // Refresh certificate in cache - cache->insertCertificate(cert1); // +500ms - - advanceClocks(time::nanoseconds(1)); - BOOST_CHECK_EQUAL(cache->getSize(), 1); - - advanceClocks(time::milliseconds(400)); - BOOST_CHECK_EQUAL(cache->getSize(), 1); - - advanceClocks(time::milliseconds(200)); - BOOST_CHECK_EQUAL(cache->getSize(), 0); -} - -BOOST_FIXTURE_TEST_CASE(Reset, CertificateCacheFixture) -{ - cache->insertCertificate(cert1); - cache->insertCertificate(cert2); - - advanceClocks(time::nanoseconds(1)); - BOOST_CHECK_EQUAL(cache->getSize(), 2); - - cache->reset(); - - advanceClocks(time::nanoseconds(1)); - BOOST_CHECK_EQUAL(cache->getSize(), 0); -} - -BOOST_AUTO_TEST_SUITE_END() // TestCertificateCacheTtl -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/certificate-container.t.cpp b/tests/unit-tests/security/certificate-container.t.cpp deleted file mode 100644 index 6ff8499d6..000000000 --- a/tests/unit-tests/security/certificate-container.t.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/certificate-container.hpp" -#include "security/pib.hpp" -#include "security/pib-memory.hpp" - -#include "boost-test.hpp" -#include "pib-data-fixture.hpp" - -namespace ndn { -namespace security { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(TestCertificateContainer) - -BOOST_FIXTURE_TEST_CASE(TestCertificateContainer, PibDataFixture) -{ - auto pibImpl = make_shared(); - Pib pib("pib-memory", "", pibImpl); - - Identity identity1 = pib.addIdentity(id1); - Key key11 = identity1.addKey(id1Key1, id1Key1Name.get(-1)); - key11.addCertificate(id1Key1Cert1); - key11.addCertificate(id1Key1Cert2); - - CertificateContainer container = key11.getCertificates(); - BOOST_CHECK_EQUAL(container.size(), 2); - BOOST_CHECK(container.find(id1Key1Cert1.getName()) != container.end()); - BOOST_CHECK(container.find(id1Key1Cert2.getName()) != container.end()); - - std::set certNames; - certNames.insert(id1Key1Cert1.getName()); - certNames.insert(id1Key1Cert2.getName()); - - CertificateContainer::const_iterator it = container.begin(); - std::set::const_iterator testIt = certNames.begin(); - BOOST_CHECK_EQUAL((*it).getName(), *testIt); - it++; - testIt++; - BOOST_CHECK_EQUAL((*it).getName(), *testIt); - ++it; - testIt++; - BOOST_CHECK(it == container.end()); - - size_t count = 0; - testIt = certNames.begin(); - for (const auto& cert : container) { - BOOST_CHECK_EQUAL(cert.getName(), *testIt); - testIt++; - count++; - } - BOOST_CHECK_EQUAL(count, 2); -} - -BOOST_AUTO_TEST_SUITE_END() // TestCertificateContainer -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/command-interest-validator.t.cpp b/tests/unit-tests/security/command-interest-validator.t.cpp deleted file mode 100644 index f31f3a3ab..000000000 --- a/tests/unit-tests/security/command-interest-validator.t.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/command-interest-validator.hpp" -#include "security/signing-helpers.hpp" - -#include "boost-test.hpp" -#include "dummy-validator.hpp" -#include "../identity-management-time-fixture.hpp" -#include "../make-interest-data.hpp" - -#include - -namespace ndn { -namespace security { -namespace tests { - -using namespace ndn::tests; - -class CommandInterestValidatorFixture : public IdentityManagementTimeFixture -{ -protected: - CommandInterestValidatorFixture() - { - this->initialize(CommandInterestValidator::Options{}); - } - - void - initialize(const CommandInterestValidator::Options& options) - { - auto inner = make_unique(); - this->inner = inner.get(); - this->validator = make_unique(std::move(inner), options); - } - - Name - makeIdentity(uint64_t identity) - { - Name name("/localhost/CommandInterestValidatorIdentity"); - name.appendSequenceNumber(identity); - BOOST_REQUIRE(m_keyChain.doesIdentityExist(name) || this->addIdentity(name)); - return name; - } - - shared_ptr - makeCommandInterest(uint64_t identity = 0) - { - auto interest = makeInterest("/CommandInterestPrefix"); - m_keyChain.sign(*interest, signingByIdentity(makeIdentity(identity))); - BOOST_TEST_MESSAGE("makeCommandInterest " << interest->getName()); - return interest; - } - - /** \brief check that validator accepts interest - * \param interest to be validated - */ - void - assertAccept(const Interest& interest) - { - BOOST_TEST_MESSAGE("assertAccept " << interest.getName()); - int nAccepts = 0; - validator->validate(interest, - [&nAccepts] (const shared_ptr&) { ++nAccepts; }, - [] (const shared_ptr&, const std::string& msg) { - BOOST_ERROR("validation request should succeed but fails with: " << msg); - }); - BOOST_CHECK_EQUAL(nAccepts, 1); - } - - /** \brief check that validator rejects interest - * \param interest to be validated - * \param error if not NONE, further check the error code matches \p error - * if NONE, error code is not checked - */ - void - assertReject(const Interest& interest, CommandInterestValidator::ErrorCode error) - { - BOOST_TEST_MESSAGE("assertReject " << interest.getName()); - int nRejects = 0; - validator->validate(interest, - [] (const shared_ptr&) { - BOOST_ERROR("validation request should fail but succeeds"); - }, - [&nRejects, error] (const shared_ptr&, const std::string& msg) { - ++nRejects; - if (error != CommandInterestValidator::ErrorCode::NONE) { - BOOST_CHECK_EQUAL(msg, boost::lexical_cast(error)); - } - }); - BOOST_CHECK_EQUAL(nRejects, 1); - } - -protected: - DummyValidator* inner; - unique_ptr validator; -}; - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_FIXTURE_TEST_SUITE(TestCommandInterestValidator, CommandInterestValidatorFixture) - -BOOST_AUTO_TEST_SUITE(Accepts) - -BOOST_AUTO_TEST_CASE(Basic) -{ - auto i1 = makeCommandInterest(); - assertAccept(*i1); - - advanceClocks(time::milliseconds(5)); - auto i2 = makeCommandInterest(); - assertAccept(*i2); - - advanceClocks(time::seconds(2)); - auto i3 = makeCommandInterest(); - assertAccept(*i3); -} - -BOOST_AUTO_TEST_CASE(DataPassthru) -{ - auto d1 = makeData("/data"); - int nAccepts = 0; - validator->validate(*d1, - [&nAccepts] (const shared_ptr&) { ++nAccepts; }, - [] (const shared_ptr&, const std::string& msg) { - BOOST_ERROR("validation request should succeed but fails with: " << msg); - }); - BOOST_CHECK_EQUAL(nAccepts, 1); -} - -BOOST_AUTO_TEST_SUITE_END() // Accepts - -BOOST_AUTO_TEST_SUITE(Rejects) - -BOOST_AUTO_TEST_CASE(NameTooShort) -{ - auto i1 = makeInterest("/name/too/short"); - assertReject(*i1, CommandInterestValidator::ErrorCode::NAME_TOO_SHORT); -} - -BOOST_AUTO_TEST_CASE(BadTimestamp) -{ - auto i1 = makeCommandInterest(); - setNameComponent(*i1, signed_interest::POS_TIMESTAMP, "not-timestamp"); - assertReject(*i1, CommandInterestValidator::ErrorCode::BAD_TIMESTAMP); -} - -BOOST_AUTO_TEST_CASE(BadSigInfo) -{ - auto i1 = makeCommandInterest(); - setNameComponent(*i1, signed_interest::POS_SIG_INFO, "not-SignatureInfo"); - assertReject(*i1, CommandInterestValidator::ErrorCode::BAD_SIG_INFO); -} - -BOOST_AUTO_TEST_CASE(MissingKeyLocator) -{ - auto i1 = makeCommandInterest(); - SignatureInfo sigInfo; - setNameComponent(*i1, signed_interest::POS_SIG_INFO, - sigInfo.wireEncode().begin(), sigInfo.wireEncode().end()); - assertReject(*i1, CommandInterestValidator::ErrorCode::MISSING_KEY_LOCATOR); -} - -BOOST_AUTO_TEST_CASE(BadKeyLocatorType) -{ - auto i1 = makeCommandInterest(); - KeyLocator kl; - kl.setKeyDigest(makeBinaryBlock(tlv::KeyDigest, "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD", 8)); - SignatureInfo sigInfo; - sigInfo.setKeyLocator(kl); - setNameComponent(*i1, signed_interest::POS_SIG_INFO, - sigInfo.wireEncode().begin(), sigInfo.wireEncode().end()); - assertReject(*i1, CommandInterestValidator::ErrorCode::BAD_KEY_LOCATOR_TYPE); -} - -BOOST_AUTO_TEST_CASE(BadCertName) -{ - auto i1 = makeCommandInterest(); - KeyLocator kl; - kl.setName("/bad/cert/name"); - SignatureInfo sigInfo; - sigInfo.setKeyLocator(kl); - setNameComponent(*i1, signed_interest::POS_SIG_INFO, - sigInfo.wireEncode().begin(), sigInfo.wireEncode().end()); - assertReject(*i1, CommandInterestValidator::ErrorCode::BAD_CERT_NAME); -} - -BOOST_AUTO_TEST_CASE(InnerReject) -{ - inner->setResult(false); - auto i1 = makeCommandInterest(); - assertReject(*i1, CommandInterestValidator::ErrorCode::NONE); -} - -BOOST_AUTO_TEST_CASE(TimestampOutOfGracePositive) -{ - CommandInterestValidator::Options options; - options.gracePeriod = time::seconds(15); - initialize(options); - - auto i1 = makeCommandInterest(); // signed at 0s - advanceClocks(time::seconds(16)); // verifying at +16s - assertReject(*i1, CommandInterestValidator::ErrorCode::TIMESTAMP_OUT_OF_GRACE); - - auto i2 = makeCommandInterest(); // signed at +16s - assertAccept(*i2); // verifying at +16s -} - -BOOST_AUTO_TEST_CASE(TimestampOutOfGraceNegative) -{ - CommandInterestValidator::Options options; - options.gracePeriod = time::seconds(15); - initialize(options); - - auto i1 = makeCommandInterest(); // signed at 0s - advanceClocks(time::seconds(1)); - auto i2 = makeCommandInterest(); // signed at +1s - advanceClocks(time::seconds(1)); - auto i3 = makeCommandInterest(); // signed at +2s - - systemClock->advance(time::seconds(-18)); // verifying at -16s - assertReject(*i1, CommandInterestValidator::ErrorCode::TIMESTAMP_OUT_OF_GRACE); - - // CommandInterestValidator should not remember i1's timestamp - assertReject(*i2, CommandInterestValidator::ErrorCode::TIMESTAMP_OUT_OF_GRACE); - - // CommandInterestValidator should not remember i2's timestamp, and should treat i3 as initial - advanceClocks(time::seconds(18)); // verifying at +2s - assertAccept(*i3); -} - -BOOST_AUTO_TEST_CASE(TimestampReorderEqual) -{ - auto i1 = makeCommandInterest(); // signed at 0s - assertAccept(*i1); - - auto i2 = makeCommandInterest(); // signed at 0s - setNameComponent(*i2, signed_interest::POS_TIMESTAMP, - i1->getName()[signed_interest::POS_TIMESTAMP]); - assertReject(*i2, CommandInterestValidator::ErrorCode::TIMESTAMP_REORDER); - - advanceClocks(time::seconds(2)); - auto i3 = makeCommandInterest(); // signed at +2s - assertAccept(*i3); -} - -BOOST_AUTO_TEST_CASE(TimestampReorderNegative) -{ - auto i2 = makeCommandInterest(); // signed at 0ms - advanceClocks(time::milliseconds(200)); - auto i3 = makeCommandInterest(); // signed at +200ms - advanceClocks(time::milliseconds(900)); - auto i1 = makeCommandInterest(); // signed at +1100ms - advanceClocks(time::milliseconds(300)); - auto i4 = makeCommandInterest(); // signed at +1400ms - - systemClock->advance(time::milliseconds(-300)); // verifying at +1100ms - assertAccept(*i1); - - systemClock->advance(time::milliseconds(-1100)); // verifying at 0ms - assertReject(*i2, CommandInterestValidator::ErrorCode::TIMESTAMP_REORDER); - - // CommandInterestValidator should not remember i2's timestamp - advanceClocks(time::milliseconds(200)); // verifying at +200ms - assertReject(*i3, CommandInterestValidator::ErrorCode::TIMESTAMP_REORDER); - - advanceClocks(time::milliseconds(1200)); // verifying at 1400ms - assertAccept(*i4); -} - -BOOST_AUTO_TEST_SUITE_END() // Rejects - -BOOST_AUTO_TEST_SUITE(Options) - -typedef boost::mpl::vector< - boost::mpl::int_<0>, - boost::mpl::int_<-1> -> GraceNonPositiveValues; - -BOOST_AUTO_TEST_CASE_TEMPLATE(GraceNonPositive, VALUE, GraceNonPositiveValues) -{ - CommandInterestValidator::Options options; - options.gracePeriod = time::seconds(VALUE::value); - initialize(options); - - auto i1 = makeCommandInterest(1); // signed at 0ms - auto i2 = makeCommandInterest(2); // signed at 0ms - for (auto interest : {i1, i2}) { - setNameComponent(*interest, signed_interest::POS_TIMESTAMP, - name::Component::fromNumber(time::toUnixTimestamp(time::system_clock::now()).count())); - } // ensure timestamps are exactly 0ms - - assertAccept(*i1); // verifying at 0ms - - advanceClocks(time::milliseconds(1)); - assertReject(*i2, CommandInterestValidator::ErrorCode::TIMESTAMP_OUT_OF_GRACE); // verifying at 1ms -} - -BOOST_AUTO_TEST_CASE(TimestampsLimited) -{ - CommandInterestValidator::Options options; - options.gracePeriod = time::seconds(15); - options.maxTimestamps = 3; - initialize(options); - - auto i1 = makeCommandInterest(1); - auto i2 = makeCommandInterest(2); - auto i3 = makeCommandInterest(3); - auto i00 = makeCommandInterest(0); // signed at 0s - advanceClocks(time::seconds(1)); - auto i01 = makeCommandInterest(0); // signed at 1s - advanceClocks(time::seconds(1)); - auto i02 = makeCommandInterest(0); // signed at 2s - - assertAccept(*i00); - assertAccept(*i02); - assertAccept(*i1); - assertAccept(*i2); - assertAccept(*i3); // forgets identity 0 - assertAccept(*i01); // accepted despite timestamp is reordered, because record has been evicted -} - -BOOST_AUTO_TEST_CASE(TimestampsUnlimited) -{ - CommandInterestValidator::Options options; - options.gracePeriod = time::seconds(15); - options.maxTimestamps = -1; - initialize(options); - - auto i1 = makeCommandInterest(0); // signed at 0s - advanceClocks(time::seconds(1)); - for (int identity = 0; identity < 20; ++identity) { - auto i2 = makeCommandInterest(identity); // signed at +1s - assertAccept(*i2); - } - assertReject(*i1, CommandInterestValidator::ErrorCode::TIMESTAMP_REORDER); -} - -BOOST_AUTO_TEST_CASE(TimestampsDisabled) -{ - CommandInterestValidator::Options options; - options.gracePeriod = time::seconds(15); - options.maxTimestamps = 0; - initialize(options); - - auto i1 = makeCommandInterest(); // signed at 0s - advanceClocks(time::seconds(1)); - auto i2 = makeCommandInterest(); // signed at +1s - assertAccept(*i2); - - assertAccept(*i1); // accepted despite timestamp is reordered, because record isn't kept -} - -BOOST_AUTO_TEST_CASE(TtlLimited) -{ - CommandInterestValidator::Options options; - options.gracePeriod = time::seconds(120); - options.timestampTtl = time::seconds(300); - initialize(options); - - auto i1 = makeCommandInterest(); // signed at 0s - advanceClocks(time::seconds(240)); - auto i2 = makeCommandInterest(); // signed at +240s - advanceClocks(time::seconds(120)); - auto i3 = makeCommandInterest(); // signed at +360s - - systemClock->advance(time::seconds(-360)); // rewind system clock to 0s - assertAccept(*i1); - assertAccept(*i3); - - advanceClocks(time::seconds(30), time::seconds(301)); // advance steady clock by 301s, and system clock to +301s - assertAccept(*i2); // accepted despite timestamp is reordered, because record has been expired -} - -BOOST_AUTO_TEST_CASE(TtlZero) -{ - CommandInterestValidator::Options options; - options.gracePeriod = time::seconds(15); - options.timestampTtl = time::seconds::zero(); - initialize(options); - - auto i1 = makeCommandInterest(); // signed at 0s - advanceClocks(time::seconds(1)); - auto i2 = makeCommandInterest(); // signed at +1s - assertAccept(*i2); - - assertAccept(*i1); // accepted despite timestamp is reordered, because record has been expired -} - -BOOST_AUTO_TEST_SUITE_END() // Options - -BOOST_AUTO_TEST_SUITE_END() // TestCommandInterestValidator -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/conf/checker.t.cpp b/tests/unit-tests/security/conf/checker.t.cpp deleted file mode 100644 index 5ba5ad856..000000000 --- a/tests/unit-tests/security/conf/checker.t.cpp +++ /dev/null @@ -1,440 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/conf/checker.hpp" -#include "security/key-chain.hpp" - -#include "boost-test.hpp" -#include "identity-management-fixture.hpp" - -namespace ndn { -namespace security { -namespace conf { -namespace tests { - -using namespace ndn::tests; - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(Conf) -BOOST_FIXTURE_TEST_SUITE(TestChecker, IdentityManagementFixture) - -BOOST_AUTO_TEST_CASE(CustomizedCheckerTest1) -{ - using security::conf::CustomizedChecker; - using security::conf::KeyLocatorChecker; - using security::conf::RelationKeyLocatorNameChecker; - - Name identity("/SecurityTestConfChecker/CustomizedCheckerTest1"); - BOOST_REQUIRE(addIdentity(identity, RsaKeyParams())); - Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity); - - Name identity2("/SecurityTestConfChecker/CustomizedCheckerTest1Wrong"); - BOOST_REQUIRE(addIdentity(identity2, RsaKeyParams())); - Name certName2 = m_keyChain.getDefaultCertificateNameForIdentity(identity2); - - Name packetName("/SecurityTestConfChecker/CustomizedCheckerTest1/Data"); - shared_ptr data1 = make_shared(packetName); - m_keyChain.sign(*data1, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity)); - - shared_ptr data2 = make_shared(packetName); - m_keyChain.sign(*data2, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity2)); - - shared_ptr interest1 = make_shared(packetName); - m_keyChain.sign(*interest1, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity)); - - shared_ptr interest2 = make_shared(packetName); - m_keyChain.sign(*interest2, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity2)); - - int8_t result = 0; - - - shared_ptr keyLocatorCheckerEqual1 = - make_shared(certName.getPrefix(-1), - KeyLocatorChecker::RELATION_EQUAL); - CustomizedChecker checker1(tlv::SignatureSha256WithRsa, keyLocatorCheckerEqual1); - - result = checker1.check(*data1); - BOOST_CHECK_EQUAL(result, 0); - - result = checker1.check(*data2); - BOOST_CHECK_EQUAL(result, -1); - - result = checker1.check(*interest1); - BOOST_CHECK_EQUAL(result, 0); - - result = checker1.check(*interest2); - BOOST_CHECK_EQUAL(result, -1); - - - shared_ptr keyLocatorCheckerEqual2 = - make_shared(identity, - KeyLocatorChecker::RELATION_EQUAL); - CustomizedChecker checker2(tlv::SignatureSha256WithRsa, keyLocatorCheckerEqual2); - - result = checker2.check(*data1); - BOOST_CHECK_EQUAL(result, -1); - - result = checker2.check(*interest1); - BOOST_CHECK_EQUAL(result, -1); - - - shared_ptr keyLocatorCheckerPrefix1 = - make_shared(certName.getPrefix(-1), - KeyLocatorChecker::RELATION_IS_PREFIX_OF); - CustomizedChecker checker3(tlv::SignatureSha256WithRsa, keyLocatorCheckerPrefix1); - - result = checker3.check(*data1); - BOOST_CHECK_EQUAL(result, 0); - - result = checker3.check(*data2); - BOOST_CHECK_EQUAL(result, -1); - - - shared_ptr keyLocatorCheckerPrefix2 = - make_shared(identity, - KeyLocatorChecker::RELATION_IS_PREFIX_OF); - CustomizedChecker checker4(tlv::SignatureSha256WithRsa, keyLocatorCheckerPrefix2); - - result = checker4.check(*data1); - BOOST_CHECK_EQUAL(result, 0); - - result = checker4.check(*data2); - BOOST_CHECK_EQUAL(result, -1); - - - shared_ptr keyLocatorCheckerStrict1 = - make_shared(certName.getPrefix(-1), - KeyLocatorChecker::RELATION_IS_STRICT_PREFIX_OF); - CustomizedChecker checker5(tlv::SignatureSha256WithRsa, keyLocatorCheckerStrict1); - - result = checker5.check(*data1); - BOOST_CHECK_EQUAL(result, -1); - - result = checker5.check(*data2); - BOOST_CHECK_EQUAL(result, -1); - - shared_ptr keyLocatorCheckerStrict2 = - make_shared(identity, - KeyLocatorChecker::RELATION_IS_STRICT_PREFIX_OF); - CustomizedChecker checker6(tlv::SignatureSha256WithRsa, keyLocatorCheckerStrict2); - - result = checker6.check(*data1); - BOOST_CHECK_EQUAL(result, 0); - - result = checker6.check(*data2); - BOOST_CHECK_EQUAL(result, -1); -} - -BOOST_AUTO_TEST_CASE(CustomizedCheckerTest2) -{ - using security::conf::CustomizedChecker; - using security::conf::KeyLocatorChecker; - using security::conf::RegexKeyLocatorNameChecker; - - Name identity("/SecurityTestConfChecker/CustomizedCheckerTest2"); - BOOST_REQUIRE(addIdentity(identity, RsaKeyParams())); - Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity); - - Name identity2("/SecurityTestConfChecker/CustomizedCheckerTest2Wrong"); - BOOST_REQUIRE(addIdentity(identity2, RsaKeyParams())); - Name certName2 = m_keyChain.getDefaultCertificateNameForIdentity(identity2); - - Name packetName("/SecurityTestConfChecker/CustomizedCheckerTest2/Data"); - shared_ptr data1 = make_shared(packetName); - m_keyChain.sign(*data1, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity)); - - shared_ptr data2 = make_shared(packetName); - m_keyChain.sign(*data2, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity2)); - - shared_ptr interest1 = make_shared(packetName); - m_keyChain.sign(*interest1, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity)); - - shared_ptr interest2 = make_shared(packetName); - m_keyChain.sign(*interest2, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity2)); - - int8_t result = 0; - - - shared_ptr keyLocatorCheckerRegex1 = - make_shared( - Regex("^")); - CustomizedChecker checker1(tlv::SignatureSha256WithRsa, keyLocatorCheckerRegex1); - - result = checker1.check(*data1); - BOOST_CHECK_EQUAL(result, 0); - - result = checker1.check(*data2); - BOOST_CHECK_EQUAL(result, -1); - - result = checker1.check(*interest1); - BOOST_CHECK_EQUAL(result, 0); - - result = checker1.check(*interest2); - BOOST_CHECK_EQUAL(result, -1); -} - -BOOST_AUTO_TEST_CASE(CustomizedCheckerTest3) -{ - using security::conf::CustomizedChecker; - using security::conf::KeyLocatorChecker; - using security::conf::RegexKeyLocatorNameChecker; - - Name identity("/SecurityTestConfChecker/CustomizedCheckerTest3"); - BOOST_REQUIRE(addIdentity(identity, EcdsaKeyParams())); - Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity); - - Name identity2("/SecurityTestConfChecker/CustomizedCheckerTest3Wrong"); - BOOST_REQUIRE(addIdentity(identity2, EcdsaKeyParams())); - Name certName2 = m_keyChain.getDefaultCertificateNameForIdentity(identity2); - - Name packetName("/SecurityTestConfChecker/CustomizedCheckerTest3/Data"); - shared_ptr data1 = make_shared(packetName); - m_keyChain.sign(*data1, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity)); - - shared_ptr data2 = make_shared(packetName); - m_keyChain.sign(*data2, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity2)); - - shared_ptr interest1 = make_shared(packetName); - m_keyChain.sign(*interest1, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity)); - - shared_ptr interest2 = make_shared(packetName); - m_keyChain.sign(*interest2, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity2)); - - int8_t result = 0; - - - shared_ptr keyLocatorCheckerRegex1 = - make_shared( - Regex("^")); - CustomizedChecker checker1(tlv::SignatureSha256WithEcdsa, keyLocatorCheckerRegex1); - - result = checker1.check(*data1); - BOOST_CHECK_EQUAL(result, 0); - - result = checker1.check(*data2); - BOOST_CHECK_EQUAL(result, -1); - - result = checker1.check(*interest1); - BOOST_CHECK_EQUAL(result, 0); - - result = checker1.check(*interest2); - BOOST_CHECK_EQUAL(result, -1); - - - CustomizedChecker checker2(tlv::SignatureSha256WithRsa, keyLocatorCheckerRegex1); - - result = checker2.check(*data1); - BOOST_CHECK_EQUAL(result, -1); -} - -BOOST_AUTO_TEST_CASE(HierarchicalCheckerTest1) -{ - using security::conf::HierarchicalChecker; - - Name identity("/SecurityTestConfChecker/HierarchicalCheckerTest1"); - BOOST_REQUIRE(addIdentity(identity, EcdsaKeyParams())); - Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity); - - Name identity2("/SecurityTestConfChecker/HierarchicalCheckerTest1/Data"); - BOOST_REQUIRE(addIdentity(identity2, RsaKeyParams())); - Name certName2 = m_keyChain.getDefaultCertificateNameForIdentity(identity2); - - Name packetName("/SecurityTestConfChecker/HierarchicalCheckerTest1/Data"); - Name packetName2("/SecurityTestConfChecker"); - Name packetName3("/SecurityTestConfChecker/HierarchicalCheckerTest1"); - - shared_ptr data1 = make_shared(packetName); - m_keyChain.sign(*data1, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity)); - - shared_ptr data2 = make_shared(packetName2); - m_keyChain.sign(*data2, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity)); - - shared_ptr data3 = make_shared(packetName3); - m_keyChain.sign(*data3, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity)); - - shared_ptr data4 = make_shared(packetName); - m_keyChain.sign(*data4, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity2)); - - shared_ptr data5 = make_shared(packetName2); - m_keyChain.sign(*data5, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity2)); - - shared_ptr data6 = make_shared(packetName3); - m_keyChain.sign(*data6, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity2)); - - int8_t result = 0; - - HierarchicalChecker checker1(tlv::SignatureSha256WithEcdsa); - - result = checker1.check(*data1); - BOOST_CHECK_EQUAL(result, 0); - - result = checker1.check(*data2); - BOOST_CHECK_EQUAL(result, -1); - - result = checker1.check(*data3); - BOOST_CHECK_EQUAL(result, 0); - - result = checker1.check(*data4); - BOOST_CHECK_EQUAL(result, -1); - - result = checker1.check(*data5); - BOOST_CHECK_EQUAL(result, -1); - - result = checker1.check(*data6); - BOOST_CHECK_EQUAL(result, -1); - - - HierarchicalChecker checker2(tlv::SignatureSha256WithRsa); - - result = checker2.check(*data1); - BOOST_CHECK_EQUAL(result, -1); - - result = checker2.check(*data2); - BOOST_CHECK_EQUAL(result, -1); - - result = checker2.check(*data3); - BOOST_CHECK_EQUAL(result, -1); - - result = checker2.check(*data4); - BOOST_CHECK_EQUAL(result, 0); - - result = checker2.check(*data5); - BOOST_CHECK_EQUAL(result, -1); - - result = checker2.check(*data6); - BOOST_CHECK_EQUAL(result, -1); -} - -BOOST_AUTO_TEST_CASE(FixedSignerCheckerTest1) -{ - using security::conf::FixedSignerChecker; - - Name identity("/SecurityTestConfChecker/FixedSignerCheckerTest1"); - BOOST_REQUIRE(addIdentity(identity, EcdsaKeyParams())); - Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity); - shared_ptr cert1 = m_keyChain.getCertificate(certName); - - Name identity2("/SecurityTestConfChecker/FixedSignerCheckerTest1Wrong"); - BOOST_REQUIRE(addIdentity(identity2, RsaKeyParams())); - Name certName2 = m_keyChain.getDefaultCertificateNameForIdentity(identity2); - shared_ptr cert2 = m_keyChain.getCertificate(certName2); - - Name packetName("/Test/Data"); - - shared_ptr data1 = make_shared(packetName); - m_keyChain.sign(*data1, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity)); - - shared_ptr data2 = make_shared(packetName); - m_keyChain.sign(*data2, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity2)); - - std::vector > certSet1; - certSet1.push_back(cert1); - - std::vector > certSet2; - certSet2.push_back(cert2); - - - int8_t result = 0; - - FixedSignerChecker checker1(tlv::SignatureSha256WithEcdsa, certSet1); - - result = checker1.check(*data1); - BOOST_CHECK_EQUAL(result, 1); - - result = checker1.check(*data2); - BOOST_CHECK_EQUAL(result, -1); - - - FixedSignerChecker checker2(tlv::SignatureSha256WithRsa, certSet1); - - result = checker2.check(*data1); - BOOST_CHECK_EQUAL(result, -1); - - result = checker2.check(*data2); - BOOST_CHECK_EQUAL(result, -1); - - - FixedSignerChecker checker3(tlv::SignatureSha256WithEcdsa, certSet2); - - result = checker3.check(*data1); - BOOST_CHECK_EQUAL(result, -1); - - result = checker3.check(*data2); - BOOST_CHECK_EQUAL(result, -1); - - - FixedSignerChecker checker4(tlv::SignatureSha256WithRsa, certSet2); - - result = checker4.check(*data1); - BOOST_CHECK_EQUAL(result, -1); - - result = checker4.check(*data2); - BOOST_CHECK_EQUAL(result, 1); -} - -BOOST_AUTO_TEST_SUITE_END() // TestChecker -BOOST_AUTO_TEST_SUITE_END() // Conf -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace conf -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/config-file-readme.txt b/tests/unit-tests/security/config-file-readme.txt deleted file mode 100644 index 44e5f61d6..000000000 --- a/tests/unit-tests/security/config-file-readme.txt +++ /dev/null @@ -1,11 +0,0 @@ -In test, we set a test-specific "HOME", which cause OS X keychain look for the -default keychain of a "different" user. If the default keychain does not exist, -all subsequent calls to OS X keychain will fail. User interaction (such as -specifying password) is required to create a keychain. However, user interaction -is not feasible in automated tests. - -This problem is caused by the OS X system assumption that one user must have a -login keychain, which is also the user's default keychain, because a user -account is always created with a login keychain as default. Thus OS X system -infers a user according to the HOME env, and did not expect user to change the -HOME env in normal use. diff --git a/tests/unit-tests/security/digest-sha256.t.cpp b/tests/unit-tests/security/digest-sha256.t.cpp deleted file mode 100644 index cbac8e2df..000000000 --- a/tests/unit-tests/security/digest-sha256.t.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/digest-sha256.hpp" -#include "security/key-chain.hpp" -#include "security/validator.hpp" -#include "util/string-helper.hpp" - -#include "identity-management-fixture.hpp" -#include "boost-test.hpp" - -namespace ndn { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_FIXTURE_TEST_SUITE(TestDigestSha256, IdentityManagementFixture) - -BOOST_AUTO_TEST_CASE(Sha256) -{ - char content[6] = "1234\n"; - ConstBufferPtr buf = crypto::computeSha256Digest(reinterpret_cast(content), 5); - - BOOST_CHECK_EQUAL(toHex(buf->buf(), buf->size(), false), - "a883dafc480d466ee04e0d6da986bd78eb1fdd2178d04693723da3a8f95d42f4"); -} - -BOOST_AUTO_TEST_CASE(DataSignature) -{ - Name name("/TestSignatureSha/Basic"); - Data testData(name); - char content[5] = "1234"; - testData.setContent(reinterpret_cast(content), 5); - - m_keyChain.sign(testData, security::SigningInfo(security::SigningInfo::SIGNER_TYPE_SHA256)); - - testData.wireEncode(); - - DigestSha256 sig(testData.getSignature()); - - BOOST_CHECK(Validator::verifySignature(testData, sig)); - - BOOST_CHECK_THROW(sig.getKeyLocator(), ndn::SignatureInfo::Error); -} - -BOOST_AUTO_TEST_CASE(InterestSignature) -{ - Name name("/SecurityTestDigestSha256/InterestSignature/Interest1"); - Interest testInterest(name); - - m_keyChain.sign(testInterest, security::SigningInfo(security::SigningInfo::SIGNER_TYPE_SHA256)); - testInterest.wireEncode(); - const Name& signedName = testInterest.getName(); - - Signature signature(signedName[signed_interest::POS_SIG_INFO].blockFromValue(), - signedName[signed_interest::POS_SIG_VALUE].blockFromValue()); - DigestSha256 sig(signature); - BOOST_CHECK(Validator::verifySignature(testInterest, sig)); -} - -BOOST_AUTO_TEST_SUITE_END() // TestDigestSha256 -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/security/dummy-keychain.cpp b/tests/unit-tests/security/dummy-keychain.cpp deleted file mode 100644 index c17311760..000000000 --- a/tests/unit-tests/security/dummy-keychain.cpp +++ /dev/null @@ -1,393 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "dummy-keychain.hpp" -#include "encoding/buffer-stream.hpp" -#include "util/io.hpp" -#include - -namespace ndn { -namespace security { - -static const uint8_t DUMMY_CERT[] = - "Bv0C8Ac4CAVkdW1teQgDa2V5CANLRVkIEWtzay0xNDE4NjAwMzkxMDUwCAdJRC1D" - "RVJUCAn9AAABSkssIl4UAxgBAhX9AXMwggFvMCIYDzIwMTQxMjE0MjMzOTUxWhgP" - "MjAzNDEyMDkyMzM5NTFaMCUwIwYDVQQpExwvZHVtbXkva2V5L2tzay0xNDE4NjAw" - "MzkxMDUwMIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAxUfhv54Jdgeq" - "0wmQ/ru9ew/ByCKcQawaZT9Xm9o/sMahwQ9IbNx2Dz4Jkelaxra7+DI0QP3pYctv" - "Ykn/jwq5y3cO0LJQB+kf/7FtSKG9qBEv8aqq5hDVteBUKiyUXqDmQzbe+mTcJ9Yd" - "D7siF1dhrjnM3KL1xpcXu3QaV5m/I6cKVwYrJxp3JKr6k5pHhxJlPIyUu7oU3kFW" - "7bHq2uq4ec9gBXCKwA64IVYVQm1GVDk+V0wr7pw9qD6QNa7eMzrCME6vfM0deSiU" - "a4TovUJDQFDsM287kYm3tZu7iuJzmOC63tl4YZdyqyOgnqSrUGE1soNHfLokI13H" - "hSwxok7nuQIBERY0GwEBHC8HLQgFZHVtbXkIA2tleQgDS0VZCBFrc2stMTQxODYw" - "MDM5MTA1MAgHSUQtQ0VSVBf9AQBLLJoQt9HE93NI3Mv1JCb3ezBCWMwTDnZA+XQV" - "UgVSvISJfU/lo2sne0SfGp4KsUhj206CDpuh3q0Th5gKSJeysy/bv66V2m2G8aDn" - "OkJ7Ut+2o/QnFpIMJz+oZf2f9Z0Pchocmkv8y4Fj02t8HCuFO1ekEvOcocZvWbKy" - "HX+P0OdefPzSC535/rsNHXTzgPsoV+yb13vrm4wPeqPPBs+scQYneIFKkRkGE5PU" - "pkncAMBN6iWgmSA2RcjcbmT6utCjJTqWviX1XPQtHoF/hBGC0D/TtQDgwVGGibXB" - "zb+klRHvCC/uUIfjU2HrE705kaw8btPhTP5/PMe8YKkk+hjh"; - -static const uint8_t DUMMY_SIGNATURE[] = - {0x17, 0xfd, 0x01, 0x00, 0x93, 0x15, 0x09, 0x49, 0x79, 0x9e, 0xb7, 0x9c, 0xd3, 0xc1, 0xbf, 0x61, - 0x89, 0xd5, 0xd9, 0xca, 0xf2, 0xb0, 0x14, 0xae, 0x72, 0x7c, 0x1f, 0x8f, 0xf5, 0xb1, 0x70, 0xd6, - 0x9b, 0x8f, 0xf8, 0xd7, 0x2d, 0xbc, 0x92, 0x6f, 0x7d, 0x77, 0x96, 0x46, 0xea, 0xd4, 0x7d, 0x90, - 0xbc, 0x7a, 0xeb, 0xe2, 0x03, 0x93, 0xb1, 0xd2, 0x62, 0xec, 0x9d, 0xff, 0x9c, 0x9c, 0x2a, 0x14, - 0x7d, 0x23, 0xca, 0x29, 0x3d, 0x15, 0x1a, 0x40, 0x42, 0x2c, 0x59, 0x33, 0x8a, 0xf7, 0xc0, 0x6b, - 0xc4, 0x9c, 0xf3, 0xc4, 0x99, 0xa4, 0x1a, 0x60, 0xf5, 0x28, 0x7d, 0x4c, 0xef, 0x43, 0x7d, 0xbd, - 0x7d, 0x00, 0x51, 0xee, 0x41, 0xf5, 0x25, 0x80, 0xce, 0xe6, 0x64, 0x4f, 0x75, 0x54, 0xf3, 0xb2, - 0x99, 0x9a, 0x0f, 0x93, 0x9a, 0x28, 0x1d, 0xfe, 0x12, 0x8a, 0xe0, 0xc1, 0x02, 0xeb, 0xa4, 0x35, - 0x52, 0x88, 0xac, 0x44, 0x1a, 0x44, 0x82, 0x97, 0x4f, 0x5f, 0xa8, 0xd8, 0x9f, 0x67, 0x38, 0xa8, - 0x64, 0xb6, 0x62, 0x99, 0xbd, 0x96, 0x3c, 0xf5, 0x86, 0x09, 0x5c, 0x97, 0x6b, 0x8f, 0xae, 0xe0, - 0x60, 0xe7, 0x23, 0x98, 0x6a, 0xee, 0xc1, 0xb0, 0x14, 0xbe, 0x46, 0x2c, 0xfb, 0xa7, 0x27, 0x73, - 0xe4, 0xf3, 0x26, 0x33, 0xba, 0x99, 0xd4, 0x01, 0x38, 0xa8, 0xf2, 0x9e, 0x87, 0xe0, 0x71, 0x0b, - 0x25, 0x44, 0x07, 0x35, 0x88, 0xab, 0x67, 0x27, 0x56, 0x0e, 0xb5, 0xb5, 0xe8, 0x27, 0xb4, 0x49, - 0xdc, 0xb8, 0x48, 0x31, 0xff, 0x99, 0x48, 0xab, 0x11, 0xb4, 0xa0, 0xdf, 0x8a, 0x6d, 0xff, 0x43, - 0x69, 0x32, 0xa7, 0xbc, 0x63, 0x9d, 0x0f, 0xe0, 0x95, 0x34, 0x36, 0x25, 0x4b, 0x3e, 0x36, 0xbd, - 0x81, 0x91, 0x0b, 0x91, 0x9f, 0x3a, 0x04, 0xa2, 0x44, 0x28, 0x19, 0xa1, 0x38, 0x21, 0x4f, 0x25, - 0x59, 0x8a, 0x48, 0xc2}; - -const std::string DummyPublicInfo::SCHEME = "pib-dummy"; -const std::string DummyTpm::SCHEME = "tpm-dummy"; - -NDN_CXX_KEYCHAIN_REGISTER_PIB(DummyPublicInfo, "pib-dummy", "dummy"); -NDN_CXX_KEYCHAIN_REGISTER_TPM(DummyTpm, "tpm-dummy", "dummy"); - -typedef DummyPublicInfo DummyPublicInfo2; -typedef DummyTpm DummyTpm2; - -NDN_CXX_KEYCHAIN_REGISTER_PIB(DummyPublicInfo2, "pib-dummy2"); -NDN_CXX_KEYCHAIN_REGISTER_TPM(DummyTpm2, "tpm-dummy2"); - -DummyPublicInfo::DummyPublicInfo(const std::string& locator) - : SecPublicInfo(locator) -{ -} - -bool -DummyPublicInfo::doesIdentityExist(const Name& identityName) -{ - return true; -} - -void -DummyPublicInfo::addIdentity(const Name& identityName) -{ -} - -bool -DummyPublicInfo::revokeIdentity() -{ - return true; -} - -bool -DummyPublicInfo::doesPublicKeyExist(const Name& keyName) -{ - return true; -} - -void -DummyPublicInfo::addKey(const Name& keyName, const v1::PublicKey& publicKey) -{ -} - -shared_ptr -DummyPublicInfo::getPublicKey(const Name& keyName) -{ - static shared_ptr publicKey = nullptr; - if (publicKey == nullptr) { - typedef boost::iostreams::stream ArrayStream; - ArrayStream is(reinterpret_cast(DUMMY_CERT), sizeof(DUMMY_CERT)); - auto cert = io::load(is, io::NO_ENCODING); - publicKey = make_shared(cert->getPublicKeyInfo()); - } - - return publicKey; -} - -KeyType -DummyPublicInfo::getPublicKeyType(const Name& keyName) -{ - return KeyType::RSA; -} - -bool -DummyPublicInfo::doesCertificateExist(const Name& certificateName) -{ - return true; -} - -void -DummyPublicInfo::addCertificate(const v1::IdentityCertificate& certificate) -{ -} - -shared_ptr -DummyPublicInfo::getCertificate(const Name& certificateName) -{ - static shared_ptr cert = nullptr; - if (cert == nullptr) { - typedef boost::iostreams::stream ArrayStream; - ArrayStream is(reinterpret_cast(DUMMY_CERT), sizeof(DUMMY_CERT)); - cert = io::load(is); - } - - return cert; -} - -Name -DummyPublicInfo::getDefaultIdentity() -{ - return "/dummy/key"; -} - -Name -DummyPublicInfo::getDefaultKeyNameForIdentity(const Name& identityName) -{ - return "/dummy/key/ksk-1418600391050"; -} - -Name -DummyPublicInfo::getDefaultCertificateNameForKey(const Name& keyName) -{ - return "/dummy/key/KEY/ksk-1418600391050/ID-CERT/%FD%00%00%01JK%2C%22%5E"; -} - -void -DummyPublicInfo::getAllIdentities(std::vector& nameList, bool isDefault) -{ - if (isDefault) { - nameList.push_back("/dummy"); - } -} - -void -DummyPublicInfo::getAllKeyNames(std::vector& nameList, bool isDefault) -{ - if (isDefault) { - nameList.push_back("/dummy/key/ksk-1418600391050"); - } -} - -void -DummyPublicInfo::getAllKeyNamesOfIdentity(const Name& identity, std::vector& nameList, - bool isDefault) -{ - if (isDefault) { - nameList.push_back("/dummy/key/ksk-1418600391050"); - } -} - -void -DummyPublicInfo::getAllCertificateNames(std::vector& nameList, bool isDefault) -{ - if (isDefault) { - nameList.push_back("/dummy/key/KEY/ksk-1418600391050/ID-CERT/%FD%00%00%01JK%2C%22%5E"); - } -} - -void -DummyPublicInfo::getAllCertificateNamesOfKey(const Name& keyName, std::vector& nameList, - bool isDefault) -{ - if (isDefault) { - nameList.push_back("/dummy/key/KEY/ksk-1418600391050/ID-CERT/%FD%00%00%01JK%2C%22%5E"); - } -} - -void -DummyPublicInfo::deleteCertificateInfo(const Name& certificateName) -{ -} - -void -DummyPublicInfo::deletePublicKeyInfo(const Name& keyName) -{ -} - -void -DummyPublicInfo::deleteIdentityInfo(const Name& identity) -{ -} - -void -DummyPublicInfo::setDefaultIdentityInternal(const Name& identityName) -{ -} - -void -DummyPublicInfo::setDefaultKeyNameForIdentityInternal(const Name& keyName) -{ -} - -void -DummyPublicInfo::setDefaultCertificateNameForKeyInternal(const Name& certificateName) -{ -} - -void -DummyPublicInfo::setTpmLocator(const std::string& tpmLocator) -{ - m_tpmLocator = tpmLocator; -} - -std::string -DummyPublicInfo::getTpmLocator() -{ - return m_tpmLocator; -} - -std::string -DummyPublicInfo::getScheme() -{ - return DummyPublicInfo::SCHEME; -} - -////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// - -DummyTpm::DummyTpm(const std::string& locator) - : SecTpm(locator) -{ -} - -void -DummyTpm::setTpmPassword(const uint8_t* password, size_t passwordLength) -{ -} - -void -DummyTpm::resetTpmPassword() -{ -} - -void -DummyTpm::setInTerminal(bool inTerminal) -{ -} - -bool -DummyTpm::getInTerminal() const -{ - return false; -} - -bool -DummyTpm::isLocked() -{ - return false; -} - -bool -DummyTpm::unlockTpm(const char* password, size_t passwordLength, bool usePassword) -{ - return true; -} - -void -DummyTpm::generateKeyPairInTpm(const Name& keyName, const KeyParams& params) -{ -} - -void -DummyTpm::deleteKeyPairInTpm(const Name& keyName) -{ -} - -shared_ptr -DummyTpm::getPublicKeyFromTpm(const Name& keyName) -{ - return nullptr; -} - -Block -DummyTpm::signInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, - DigestAlgorithm digestAlgorithm) -{ - return Block(DUMMY_SIGNATURE, sizeof(DUMMY_SIGNATURE)); -} - -ConstBufferPtr -DummyTpm::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, - bool isSymmetric) -{ - BOOST_THROW_EXCEPTION(Error("Not supported")); -} - -ConstBufferPtr -DummyTpm::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, - bool isSymmetric) -{ - BOOST_THROW_EXCEPTION(Error("Not supported")); -} - -void -DummyTpm::generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params) -{ -} - -bool -DummyTpm::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass) -{ - return true; -} - -bool -DummyTpm::generateRandomBlock(uint8_t* res, size_t size) -{ - return false; -} - -void -DummyTpm::addAppToAcl(const Name& keyName, KeyClass keyClass, const std::string& appPath, - AclType acl) -{ -} - -ConstBufferPtr -DummyTpm::exportPrivateKeyPkcs8FromTpm(const Name& keyName) -{ - BOOST_THROW_EXCEPTION(Error("Not supported")); -} - -bool -DummyTpm::importPrivateKeyPkcs8IntoTpm(const Name& keyName, const uint8_t* buffer, - size_t bufferSize) -{ - return false; -} - -bool -DummyTpm::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buffer, size_t bufferSize) -{ - return false; -} - -std::string -DummyTpm::getScheme() -{ - return DummyTpm::SCHEME; -} - -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/dummy-keychain.hpp b/tests/unit-tests/security/dummy-keychain.hpp deleted file mode 100644 index 7d5682e6d..000000000 --- a/tests/unit-tests/security/dummy-keychain.hpp +++ /dev/null @@ -1,203 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_TESTS_SECURITY_DUMMY_KEYCHAIN_HPP -#define NDN_TESTS_SECURITY_DUMMY_KEYCHAIN_HPP - -#include "security/key-chain.hpp" - -namespace ndn { -namespace security { - -class DummyPublicInfo : public SecPublicInfo -{ -public: - explicit - DummyPublicInfo(const std::string& locator); - - virtual bool - doesIdentityExist(const Name& identityName); - - virtual void - addIdentity(const Name& identityName); - - virtual bool - revokeIdentity(); - - virtual bool - doesPublicKeyExist(const Name& keyName); - - virtual void - addKey(const Name& keyName, const v1::PublicKey& publicKey); - - virtual shared_ptr - getPublicKey(const Name& keyName); - - virtual KeyType - getPublicKeyType(const Name& keyName); - - virtual bool - doesCertificateExist(const Name& certificateName); - - virtual void - addCertificate(const v1::IdentityCertificate& certificate); - - virtual shared_ptr - getCertificate(const Name& certificateName); - - virtual Name - getDefaultIdentity(); - - virtual Name - getDefaultKeyNameForIdentity(const Name& identityName); - - virtual Name - getDefaultCertificateNameForKey(const Name& keyName); - - virtual void - getAllIdentities(std::vector& nameList, bool isDefault); - - virtual void - getAllKeyNames(std::vector& nameList, bool isDefault); - - virtual void - getAllKeyNamesOfIdentity(const Name& identity, std::vector& nameList, bool isDefault); - - virtual void - getAllCertificateNames(std::vector& nameList, bool isDefault); - - virtual void - getAllCertificateNamesOfKey(const Name& keyName, std::vector& nameList, bool isDefault); - - virtual void - deleteCertificateInfo(const Name& certificateName); - - virtual void - deletePublicKeyInfo(const Name& keyName); - - virtual void - deleteIdentityInfo(const Name& identity); - - virtual void - setTpmLocator(const std::string& tpmLocator); - - virtual std::string - getTpmLocator(); - -protected: - virtual void - setDefaultIdentityInternal(const Name& identityName); - - virtual void - setDefaultKeyNameForIdentityInternal(const Name& keyName); - - virtual void - setDefaultCertificateNameForKeyInternal(const Name& certificateName); - - virtual std::string - getScheme(); - -public: - static const std::string SCHEME; - -private: - std::string m_tpmLocator; -}; - -////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// - -class DummyTpm : public SecTpm -{ -public: - explicit - DummyTpm(const std::string& locator); - - virtual void - setTpmPassword(const uint8_t* password, size_t passwordLength); - - virtual void - resetTpmPassword(); - - virtual void - setInTerminal(bool inTerminal); - - virtual bool - getInTerminal() const; - - virtual bool - isLocked(); - - virtual bool - unlockTpm(const char* password, size_t passwordLength, bool usePassword); - - virtual void - generateKeyPairInTpm(const Name& keyName, const KeyParams& params); - - virtual void - deleteKeyPairInTpm(const Name& keyName); - - virtual shared_ptr - getPublicKeyFromTpm(const Name& keyName); - - virtual Block - signInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, - DigestAlgorithm digestAlgorithm); - - virtual ConstBufferPtr - decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric); - - virtual ConstBufferPtr - encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric); - - virtual void - generateSymmetricKeyInTpm(const Name& keyName, const KeyParams& params); - - virtual bool - doesKeyExistInTpm(const Name& keyName, KeyClass keyClass); - - virtual bool - generateRandomBlock(uint8_t* res, size_t size); - - virtual void - addAppToAcl(const Name& keyName, KeyClass keyClass, const std::string& appPath, AclType acl); - - virtual std::string - getScheme(); - -protected: - virtual ConstBufferPtr - exportPrivateKeyPkcs8FromTpm(const Name& keyName); - - virtual bool - importPrivateKeyPkcs8IntoTpm(const Name& keyName, const uint8_t* buffer, size_t bufferSize); - - virtual bool - importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buffer, size_t bufferSize); - -public: - static const std::string SCHEME; -}; - -} // namespace security -} // namespace ndn - -#endif // NDN_TESTS_SECURITY_DUMMY_KEYCHAIN_HPP diff --git a/tests/unit-tests/security/identity-container.t.cpp b/tests/unit-tests/security/identity-container.t.cpp deleted file mode 100644 index c2c1c0ed2..000000000 --- a/tests/unit-tests/security/identity-container.t.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/identity-container.hpp" -#include "security/pib.hpp" -#include "security/pib-memory.hpp" - -#include "boost-test.hpp" -#include "pib-data-fixture.hpp" - -namespace ndn { -namespace security { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(TestIdentityContainer) - -BOOST_FIXTURE_TEST_CASE(Basic, PibDataFixture) -{ - auto pibImpl = make_shared(); - Pib pib("pib-memory", "", pibImpl); - - Identity identity1 = pib.addIdentity(id1); - Identity identity2 = pib.addIdentity(id2); - - IdentityContainer container = pib.getIdentities(); - BOOST_CHECK_EQUAL(container.size(), 2); - BOOST_CHECK(container.find(id1) != container.end()); - BOOST_CHECK(container.find(id2) != container.end()); - - std::set idNames; - idNames.insert(id1); - idNames.insert(id2); - - IdentityContainer::const_iterator it = container.begin(); - std::set::const_iterator testIt = idNames.begin(); - BOOST_CHECK_EQUAL((*it).getName(), *testIt); - it++; - testIt++; - BOOST_CHECK_EQUAL((*it).getName(), *testIt); - ++it; - testIt++; - BOOST_CHECK(it == container.end()); - - size_t count = 0; - testIt = idNames.begin(); - for (const auto& identity : container) { - BOOST_CHECK_EQUAL(identity.getName(), *testIt); - testIt++; - count++; - } - BOOST_CHECK_EQUAL(count, 2); -} - -BOOST_AUTO_TEST_SUITE_END() // TestIdentityContainer -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/identity-management-fixture.t.cpp b/tests/unit-tests/security/identity-management-fixture.t.cpp deleted file mode 100644 index 81dcfe520..000000000 --- a/tests/unit-tests/security/identity-management-fixture.t.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "identity-management-fixture.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_FIXTURE_TEST_SUITE(TestIdentityManagementFixture, IdentityManagementFixture) - -BOOST_AUTO_TEST_CASE(Tmp) -{ - Name identity("/tmp/identity"); - BOOST_REQUIRE(addIdentity(identity)); - Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity); - BOOST_REQUIRE_EQUAL(certName.empty(), false); - BOOST_REQUIRE_NO_THROW(m_keyChain.getCertificate(certName)); -} - -BOOST_AUTO_TEST_SUITE_END() // TestIdentityManagementFixture -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/security/identity.t.cpp b/tests/unit-tests/security/identity.t.cpp deleted file mode 100644 index 5e04d4c1e..000000000 --- a/tests/unit-tests/security/identity.t.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/identity.hpp" -#include "security/pib.hpp" -#include "security/pib-memory.hpp" - -#include "boost-test.hpp" -#include "pib-data-fixture.hpp" - -namespace ndn { -namespace security { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_FIXTURE_TEST_SUITE(TestIdentity, PibDataFixture) - -BOOST_AUTO_TEST_CASE(ValidityChecking) -{ - // identity - Identity id; - - BOOST_CHECK_EQUAL(static_cast(id), false); - BOOST_CHECK_EQUAL(!id, true); - - if (id) - BOOST_CHECK(false); - else - BOOST_CHECK(true); - - auto pibImpl = make_shared(); - id = Identity(id1, pibImpl, true); - - BOOST_CHECK_EQUAL(static_cast(id), true); - BOOST_CHECK_EQUAL(!id, false); - - if (id) - BOOST_CHECK(true); - else - BOOST_CHECK(false); -} - -BOOST_AUTO_TEST_CASE(KeyOperations) -{ - auto pibImpl = make_shared(); - - Identity identity1(id1, pibImpl, true); - - BOOST_CHECK_THROW(identity1.getKey(id1Key1Name.get(-1)), Pib::Error); - Key key11 = identity1.addKey(id1Key1, id1Key1Name.get(-1)); - BOOST_CHECK_NO_THROW(identity1.getKey(id1Key1Name.get(-1))); - identity1.removeKey(id1Key1Name.get(-1)); - BOOST_CHECK_THROW(identity1.getKey(id1Key1Name.get(-1)), Pib::Error); - - BOOST_CHECK_THROW(identity1.getDefaultKey(), Pib::Error); - BOOST_REQUIRE_THROW(identity1.setDefaultKey(id1Key1Name.get(-1)), Pib::Error); - BOOST_REQUIRE_NO_THROW(identity1.setDefaultKey(id1Key1, id1Key1Name.get(-1))); - BOOST_REQUIRE_NO_THROW(identity1.getDefaultKey()); - BOOST_CHECK_EQUAL(identity1.getDefaultKey().getKeyId(), id1Key1Name.get(-1)); - identity1.removeKey(id1Key1Name.get(-1)); - BOOST_CHECK_THROW(identity1.getKey(id1Key1Name.get(-1)), Pib::Error); - BOOST_CHECK_THROW(identity1.getDefaultKey(), Pib::Error); -} - -BOOST_AUTO_TEST_SUITE_END() // TestIdentity -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/key-chain.t.cpp b/tests/unit-tests/security/key-chain.t.cpp deleted file mode 100644 index 8009daa0d..000000000 --- a/tests/unit-tests/security/key-chain.t.cpp +++ /dev/null @@ -1,426 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/key-chain.hpp" -#include "security/validator.hpp" -#include "security/signing-helpers.hpp" - -#include "boost-test.hpp" -#include "dummy-keychain.hpp" -#include "../test-home-env-saver.hpp" -#include "key-chain-fixture.hpp" -#include "identity-management-fixture.hpp" - -#include -#include -#include - -namespace ndn { -namespace security { -namespace tests { - -using namespace ndn::tests; - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_FIXTURE_TEST_SUITE(TestKeyChain, TestHomeEnvSaver) - -template -class TestHomeAndPibFixture : public TestHomeFixture -{ -public: - TestHomeAndPibFixture() - { - unsetenv("NDN_CLIENT_PIB"); - unsetenv("NDN_CLIENT_TPM"); - } -}; - -struct PibPathSqlite3File -{ - const std::string PATH = "build/keys-sqlite3-file/"; -}; - -BOOST_FIXTURE_TEST_CASE(ConstructorNormalConfig, TestHomeAndPibFixture) -{ - createClientConf({"pib=pib-sqlite3:%PATH%", "tpm=tpm-file:%PATH%"}); - - BOOST_REQUIRE_NO_THROW(KeyChain()); - - KeyChain keyChain; - BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-sqlite3:" + m_pibDir); - BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-file:" + m_pibDir); - BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-file:" + m_pibDir); -} - -struct PibPathSqlite3Empty -{ - const std::string PATH = "build/keys-sqlite3-empty/"; -}; - -BOOST_FIXTURE_TEST_CASE(ConstructorEmptyConfig, TestHomeAndPibFixture) -{ - createClientConf({"pib=pib-sqlite3:%PATH%"}); - -#if defined(NDN_CXX_HAVE_OSX_SECURITY) - std::string oldHOME; - if (std::getenv("OLD_HOME")) - oldHOME = std::getenv("OLD_HOME"); - - std::string HOME; - if (std::getenv("HOME")) - HOME = std::getenv("HOME"); - - if (!oldHOME.empty()) - setenv("HOME", oldHOME.c_str(), true); - else - unsetenv("HOME"); -#endif - - BOOST_REQUIRE_NO_THROW(KeyChain()); - KeyChain keyChain; - BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-sqlite3:" + m_pibDir); - -#if defined(NDN_CXX_HAVE_OSX_SECURITY) - BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-osxkeychain:"); - BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-osxkeychain:"); -#else - BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-file:"); - BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-file:"); -#endif - -#if defined(NDN_CXX_HAVE_OSX_SECURITY) - if (!HOME.empty()) - setenv("HOME", HOME.c_str(), true); - else - unsetenv("HOME"); -#endif -} - -struct PibPathEmptyFile -{ - const std::string PATH = "build/keys-empty-file/"; -}; - -BOOST_FIXTURE_TEST_CASE(ConstructorEmpty2Config, TestHomeAndPibFixture) -{ - createClientConf({"tpm=tpm-file:%PATH%"}); - - BOOST_REQUIRE_NO_THROW(KeyChain()); - - KeyChain keyChain; - BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-sqlite3:"); - BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-file:" + m_pibDir); - BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-file:" + m_pibDir); -} - -BOOST_FIXTURE_TEST_CASE(ConstructorMalConfig, TestHomeAndPibFixture) -{ - createClientConf({"pib=lord", "tpm=ring"}); - - BOOST_REQUIRE_THROW(KeyChain(), KeyChain::Error); // Wrong configuration. Error expected. -} - -BOOST_FIXTURE_TEST_CASE(ConstructorMal2Config, TestHomeAndPibFixture) -{ - createClientConf({"pib=pib-sqlite3:%PATH%", "tpm=just-wrong"}); - BOOST_REQUIRE_THROW(KeyChain(), KeyChain::Error); // Wrong configuration. Error expected. -} - -BOOST_FIXTURE_TEST_CASE(ExportIdentity, IdentityManagementFixture) -{ - Name identity("/TestKeyChain/ExportIdentity/"); - identity.appendVersion(); - addIdentity(identity); - - shared_ptr exported = m_keyChain.exportIdentity(identity, "1234"); - - Block block = exported->wireEncode(); - - Name keyName = m_keyChain.getDefaultKeyNameForIdentity(identity); - Name certName = m_keyChain.getDefaultCertificateNameForKey(keyName); - - m_keyChain.deleteIdentity(identity); - - BOOST_CHECK_EQUAL(m_keyChain.doesIdentityExist(identity), false); - BOOST_CHECK_EQUAL(m_keyChain.doesPublicKeyExist(keyName), false); - BOOST_CHECK_EQUAL(m_keyChain.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), false); - BOOST_CHECK_EQUAL(m_keyChain.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), false); - BOOST_CHECK_EQUAL(m_keyChain.doesCertificateExist(certName), false); - - SecuredBag imported; - imported.wireDecode(block); - m_keyChain.importIdentity(imported, "1234"); - - BOOST_CHECK(m_keyChain.doesIdentityExist(identity)); - BOOST_CHECK(m_keyChain.doesPublicKeyExist(keyName)); - BOOST_CHECK(m_keyChain.doesKeyExistInTpm(keyName, KeyClass::PRIVATE)); - BOOST_CHECK(m_keyChain.doesKeyExistInTpm(keyName, KeyClass::PUBLIC)); - BOOST_CHECK(m_keyChain.doesCertificateExist(certName)); -} - -BOOST_FIXTURE_TEST_CASE(PrepareIdentityCertificate, IdentityManagementFixture) -{ - Name identity("/TestKeyChain/PrepareIdentityCertificate/"); - identity.appendVersion(); - addIdentity(identity); - - std::vector subjectDescription; - Name lowerIdentity = identity; - lowerIdentity.append("Lower").appendVersion(); - Name lowerKeyName = m_keyChain.generateRsaKeyPair(lowerIdentity, true); - shared_ptr idCert = - m_keyChain.prepareUnsignedIdentityCertificate(lowerKeyName, identity, - time::system_clock::now(), - time::system_clock::now() + time::days(365), - subjectDescription); - BOOST_CHECK(static_cast(idCert)); - BOOST_CHECK_EQUAL(idCert->getName().getPrefix(5), - Name().append(identity).append("KEY").append("Lower")); - BOOST_CHECK(idCert->getFreshnessPeriod() >= time::milliseconds::zero()); - - shared_ptr idCert11 = - m_keyChain.prepareUnsignedIdentityCertificate(lowerKeyName, identity, - time::system_clock::now(), - time::system_clock::now() + time::days(365), - subjectDescription, - lowerIdentity); - BOOST_CHECK(static_cast(idCert11)); - BOOST_CHECK_EQUAL(idCert11->getName().getPrefix(6), - Name().append(lowerIdentity).append("KEY")); - - Name anotherIdentity("/TestKeyChain/PrepareIdentityCertificate/Another/"); - anotherIdentity.appendVersion(); - Name anotherKeyName = m_keyChain.generateRsaKeyPair(anotherIdentity, true); - shared_ptr idCert2 = - m_keyChain.prepareUnsignedIdentityCertificate(anotherKeyName, identity, - time::system_clock::now(), - time::system_clock::now() + time::days(365), - subjectDescription); - BOOST_CHECK(static_cast(idCert2)); - BOOST_CHECK_EQUAL(idCert2->getName().getPrefix(5), Name().append(anotherIdentity).append("KEY")); - - - Name wrongKeyName1; - shared_ptr idCert3 = - m_keyChain.prepareUnsignedIdentityCertificate(wrongKeyName1, identity, - time::system_clock::now(), - time::system_clock::now() + time::days(365), - subjectDescription); - BOOST_CHECK_EQUAL(static_cast(idCert3), false); - - - Name wrongKeyName2("/TestKeyChain/PrepareIdentityCertificate"); - shared_ptr idCert4 = - m_keyChain.prepareUnsignedIdentityCertificate(wrongKeyName2, identity, - time::system_clock::now(), - time::system_clock::now() + time::days(365), - subjectDescription); - BOOST_CHECK_EQUAL(static_cast(idCert4), false); - - - Name wrongKeyName3("/TestKeyChain/PrepareIdentityCertificate/ksk-1234"); - shared_ptr idCert5 = - m_keyChain.prepareUnsignedIdentityCertificate(wrongKeyName3, identity, - time::system_clock::now(), - time::system_clock::now() + time::days(365), - subjectDescription); - BOOST_CHECK_EQUAL(static_cast(idCert5), false); -} - -BOOST_FIXTURE_TEST_CASE(Delete, IdentityManagementFixture) -{ - Name identity("/TestSecPublicInfoSqlite3/Delete"); - identity.appendVersion(); - - Name certName1; - BOOST_REQUIRE_NO_THROW(certName1 = m_keyChain.createIdentity(identity)); - - Name keyName1 = v1::IdentityCertificate::certificateNameToPublicKeyName(certName1); - Name keyName2; - BOOST_REQUIRE_NO_THROW(keyName2 = m_keyChain.generateRsaKeyPairAsDefault(identity)); - - shared_ptr cert2; - BOOST_REQUIRE_NO_THROW(cert2 = m_keyChain.selfSign(keyName2)); - Name certName2 = cert2->getName(); - BOOST_REQUIRE_NO_THROW(m_keyChain.addCertificateAsKeyDefault(*cert2)); - - Name keyName3; - BOOST_REQUIRE_NO_THROW(keyName3 = m_keyChain.generateRsaKeyPairAsDefault(identity)); - - shared_ptr cert3; - BOOST_REQUIRE_NO_THROW(cert3 = m_keyChain.selfSign(keyName3)); - Name certName3 = cert3->getName(); - BOOST_REQUIRE_NO_THROW(m_keyChain.addCertificateAsKeyDefault(*cert3)); - shared_ptr cert4; - BOOST_REQUIRE_NO_THROW(cert4 = m_keyChain.selfSign(keyName3)); - Name certName4 = cert4->getName(); - BOOST_REQUIRE_NO_THROW(m_keyChain.addCertificateAsKeyDefault(*cert4)); - shared_ptr cert5; - BOOST_REQUIRE_NO_THROW(cert5 = m_keyChain.selfSign(keyName3)); - Name certName5 = cert5->getName(); - BOOST_REQUIRE_NO_THROW(m_keyChain.addCertificateAsKeyDefault(*cert5)); - - BOOST_CHECK_EQUAL(m_keyChain.doesIdentityExist(identity), true); - BOOST_CHECK_EQUAL(m_keyChain.doesPublicKeyExist(keyName1), true); - BOOST_CHECK_EQUAL(m_keyChain.doesPublicKeyExist(keyName2), true); - BOOST_CHECK_EQUAL(m_keyChain.doesPublicKeyExist(keyName3), true); - BOOST_CHECK_EQUAL(m_keyChain.doesCertificateExist(certName1), true); - BOOST_CHECK_EQUAL(m_keyChain.doesCertificateExist(certName2), true); - BOOST_CHECK_EQUAL(m_keyChain.doesCertificateExist(certName3), true); - BOOST_CHECK_EQUAL(m_keyChain.doesCertificateExist(certName4), true); - BOOST_CHECK_EQUAL(m_keyChain.doesCertificateExist(certName5), true); - - BOOST_REQUIRE_NO_THROW(m_keyChain.deleteCertificate(certName5)); - BOOST_CHECK_EQUAL(m_keyChain.doesCertificateExist(certName5), false); - BOOST_CHECK_EQUAL(m_keyChain.doesCertificateExist(certName3), true); - BOOST_CHECK_EQUAL(m_keyChain.doesCertificateExist(certName4), true); - BOOST_CHECK_EQUAL(m_keyChain.doesPublicKeyExist(keyName3), true); - - BOOST_REQUIRE_NO_THROW(m_keyChain.deleteKey(keyName3)); - BOOST_CHECK_EQUAL(m_keyChain.doesCertificateExist(certName4), false); - BOOST_CHECK_EQUAL(m_keyChain.doesCertificateExist(certName3), false); - BOOST_CHECK_EQUAL(m_keyChain.doesPublicKeyExist(keyName3), false); - BOOST_CHECK_EQUAL(m_keyChain.doesPublicKeyExist(keyName2), true); - BOOST_CHECK_EQUAL(m_keyChain.doesPublicKeyExist(keyName1), true); - BOOST_CHECK_EQUAL(m_keyChain.doesIdentityExist(identity), true); - - BOOST_REQUIRE_NO_THROW(m_keyChain.deleteIdentity(identity)); - BOOST_CHECK_EQUAL(m_keyChain.doesCertificateExist(certName2), false); - BOOST_CHECK_EQUAL(m_keyChain.doesPublicKeyExist(keyName2), false); - BOOST_CHECK_EQUAL(m_keyChain.doesCertificateExist(certName1), false); - BOOST_CHECK_EQUAL(m_keyChain.doesPublicKeyExist(keyName1), false); - BOOST_CHECK_EQUAL(m_keyChain.doesIdentityExist(identity), false); -} - -BOOST_AUTO_TEST_CASE(KeyChainWithCustomTpmAndPib) -{ - BOOST_REQUIRE_NO_THROW((KeyChain("pib-dummy", "tpm-dummy"))); - BOOST_REQUIRE_NO_THROW((KeyChain("pib-dummy2", "tpm-dummy2"))); - BOOST_REQUIRE_NO_THROW((KeyChain("dummy", "dummy"))); - BOOST_REQUIRE_NO_THROW((KeyChain("dummy:", "dummy:"))); - BOOST_REQUIRE_NO_THROW((KeyChain("dummy:/something", "dummy:/something"))); - - KeyChain keyChain("dummy", "dummy"); - BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-dummy:"); - BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-dummy:"); - BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-dummy:"); - BOOST_CHECK_EQUAL(keyChain.getDefaultIdentity(), "/dummy/key"); -} - -BOOST_FIXTURE_TEST_CASE(GeneralSigningInterface, IdentityManagementFixture) -{ - Name id("/id"); - Name certName = m_keyChain.createIdentity(id); - shared_ptr idCert = m_keyChain.getCertificate(certName); - Name keyName = idCert->getPublicKeyName(); - m_keyChain.setDefaultIdentity(id); - - Name id2("/id2"); - Name cert2Name = m_keyChain.createIdentity(id2); - shared_ptr id2Cert = m_keyChain.getCertificate(cert2Name); - - // SigningInfo is set to default - Data data1("/data1"); - m_keyChain.sign(data1); - BOOST_CHECK(Validator::verifySignature(data1, idCert->getPublicKeyInfo())); - BOOST_CHECK_EQUAL(data1.getSignature().getKeyLocator().getName(), certName.getPrefix(-1)); - - Interest interest1("/interest1"); - m_keyChain.sign(interest1); - BOOST_CHECK(Validator::verifySignature(interest1, idCert->getPublicKeyInfo())); - SignatureInfo sigInfo1(interest1.getName()[-2].blockFromValue()); - BOOST_CHECK_EQUAL(sigInfo1.getKeyLocator().getName(), certName.getPrefix(-1)); - - // SigningInfo is set to Identity - Data data2("/data2"); - m_keyChain.sign(data2, SigningInfo(SigningInfo::SIGNER_TYPE_ID, id2)); - BOOST_CHECK(Validator::verifySignature(data2, id2Cert->getPublicKeyInfo())); - BOOST_CHECK_EQUAL(data2.getSignature().getKeyLocator().getName(), cert2Name.getPrefix(-1)); - - Interest interest2("/interest2"); - m_keyChain.sign(interest2, SigningInfo(SigningInfo::SIGNER_TYPE_ID, id2)); - BOOST_CHECK(Validator::verifySignature(interest2, id2Cert->getPublicKeyInfo())); - SignatureInfo sigInfo2(interest2.getName()[-2].blockFromValue()); - BOOST_CHECK_EQUAL(sigInfo2.getKeyLocator().getName(), cert2Name.getPrefix(-1)); - - // SigningInfo is set to Key - Data data3("/data3"); - m_keyChain.sign(data3, SigningInfo(SigningInfo::SIGNER_TYPE_KEY, keyName)); - BOOST_CHECK(Validator::verifySignature(data3, idCert->getPublicKeyInfo())); - BOOST_CHECK_EQUAL(data3.getSignature().getKeyLocator().getName(), certName.getPrefix(-1)); - - Interest interest3("/interest3"); - m_keyChain.sign(interest3); - BOOST_CHECK(Validator::verifySignature(interest3, idCert->getPublicKeyInfo())); - SignatureInfo sigInfo3(interest1.getName()[-2].blockFromValue()); - BOOST_CHECK_EQUAL(sigInfo3.getKeyLocator().getName(), certName.getPrefix(-1)); - - // SigningInfo is set to Cert - Data data4("/data4"); - m_keyChain.sign(data4, SigningInfo(SigningInfo::SIGNER_TYPE_CERT, certName)); - BOOST_CHECK(Validator::verifySignature(data4, idCert->getPublicKeyInfo())); - BOOST_CHECK_EQUAL(data4.getSignature().getKeyLocator().getName(), certName.getPrefix(-1)); - - Interest interest4("/interest4"); - m_keyChain.sign(interest4, SigningInfo(SigningInfo::SIGNER_TYPE_CERT, certName)); - BOOST_CHECK(Validator::verifySignature(interest4, idCert->getPublicKeyInfo())); - SignatureInfo sigInfo4(interest4.getName()[-2].blockFromValue()); - BOOST_CHECK_EQUAL(sigInfo4.getKeyLocator().getName(), certName.getPrefix(-1)); - - - // SigningInfo is set to DigestSha256 - Data data5("/data5"); - m_keyChain.sign(data5, SigningInfo(SigningInfo::SIGNER_TYPE_SHA256)); - BOOST_CHECK(Validator::verifySignature(data5, DigestSha256(data5.getSignature()))); - - Interest interest5("/interest4"); - m_keyChain.sign(interest5, SigningInfo(SigningInfo::SIGNER_TYPE_SHA256)); - BOOST_CHECK(Validator::verifySignature(interest5, - DigestSha256(Signature(interest5.getName()[-2].blockFromValue(), - interest5.getName()[-1].blockFromValue())))); -} - -BOOST_FIXTURE_TEST_CASE(EcdsaSigningByIdentityNoCert, IdentityManagementFixture) -{ - Data data("/test/data"); - - Name nonExistingIdentity = Name("/non-existing/identity").appendVersion(); - - BOOST_CHECK_NO_THROW(m_keyChain.sign(data, signingByIdentity(nonExistingIdentity))); - BOOST_CHECK_EQUAL(data.getSignature().getType(), - KeyChain::getSignatureType(KeyChain::DEFAULT_KEY_PARAMS.getKeyType(), - DigestAlgorithm::SHA256)); - BOOST_CHECK(nonExistingIdentity.isPrefixOf(data.getSignature().getKeyLocator().getName())); - - Name ecdsaIdentity = Name("/ndn/test/ecdsa").appendVersion(); - Name ecdsaKeyName = m_keyChain.generateEcdsaKeyPairAsDefault(ecdsaIdentity, false, 256); - BOOST_CHECK_NO_THROW(m_keyChain.sign(data, signingByIdentity(ecdsaIdentity))); - BOOST_CHECK_EQUAL(data.getSignature().getType(), - KeyChain::getSignatureType(EcdsaKeyParams().getKeyType(), DigestAlgorithm::SHA256)); - BOOST_CHECK(ecdsaIdentity.isPrefixOf(data.getSignature().getKeyLocator().getName())); -} - -BOOST_AUTO_TEST_SUITE_END() // TestKeyChain -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/key-container.t.cpp b/tests/unit-tests/security/key-container.t.cpp deleted file mode 100644 index 817a84f49..000000000 --- a/tests/unit-tests/security/key-container.t.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/key-container.hpp" -#include "security/pib.hpp" -#include "security/pib-memory.hpp" - -#include "boost-test.hpp" -#include "pib-data-fixture.hpp" - -namespace ndn { -namespace security { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(TestKeyContainer) - -BOOST_FIXTURE_TEST_CASE(Basic, PibDataFixture) -{ - auto pibImpl = make_shared(); - Pib pib("pib-memory", "", pibImpl); - - Identity identity1 = pib.addIdentity(id1); - - Key key11 = identity1.addKey(id1Key1, id1Key1Name.get(-1)); - Key key12 = identity1.addKey(id1Key2, id1Key2Name.get(-1)); - - KeyContainer container = identity1.getKeys(); - BOOST_CHECK_EQUAL(container.size(), 2); - BOOST_CHECK(container.find(id1Key1Name.get(-1)) != container.end()); - BOOST_CHECK(container.find(id1Key2Name.get(-1)) != container.end()); - - std::set keyNames; - keyNames.insert(id1Key1Name.get(-1)); - keyNames.insert(id1Key2Name.get(-1)); - - KeyContainer::const_iterator it = container.begin(); - std::set::const_iterator testIt = keyNames.begin(); - BOOST_CHECK_EQUAL((*it).getKeyId(), *testIt); - it++; - testIt++; - BOOST_CHECK_EQUAL((*it).getKeyId(), *testIt); - ++it; - testIt++; - BOOST_CHECK(it == container.end()); - - size_t count = 0; - testIt = keyNames.begin(); - for (const auto& key : container) { - BOOST_CHECK_EQUAL(key.getIdentity(), id1); - BOOST_CHECK_EQUAL(key.getKeyId(), *testIt); - testIt++; - count++; - } - BOOST_CHECK_EQUAL(count, 2); -} - -BOOST_AUTO_TEST_SUITE_END() // TestKeyContainer -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/key-params.t.cpp b/tests/unit-tests/security/key-params.t.cpp deleted file mode 100644 index a1fefa4b7..000000000 --- a/tests/unit-tests/security/key-params.t.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/key-params.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(TestKeyParams) - -BOOST_AUTO_TEST_CASE(Rsa) -{ - RsaKeyParams params; - BOOST_CHECK_EQUAL(params.getKeyType(), KeyType::RSA); - BOOST_CHECK_EQUAL(params.getKeySize(), 2048); - - RsaKeyParams params2(1024); - BOOST_CHECK_EQUAL(params2.getKeyType(), KeyType::RSA); - BOOST_CHECK_EQUAL(params2.getKeySize(), 1024); - - RsaKeyParams params3(3); - BOOST_CHECK_EQUAL(params3.getKeyType(), KeyType::RSA); - BOOST_CHECK_EQUAL(params3.getKeySize(), 2048); -} - -BOOST_AUTO_TEST_CASE(Ecdsa) -{ - EcdsaKeyParams params; - BOOST_CHECK_EQUAL(params.getKeyType(), KeyType::EC); - BOOST_CHECK_EQUAL(params.getKeySize(), 256); - - EcdsaKeyParams params2(384); - BOOST_CHECK_EQUAL(params2.getKeyType(), KeyType::EC); - BOOST_CHECK_EQUAL(params2.getKeySize(), 384); - - EcdsaKeyParams params3(3); - BOOST_CHECK_EQUAL(params3.getKeyType(), KeyType::EC); - BOOST_CHECK_EQUAL(params3.getKeySize(), 256); -} - -BOOST_AUTO_TEST_CASE(Aes) -{ - AesKeyParams params; - BOOST_CHECK_EQUAL(params.getKeyType(), KeyType::AES); - BOOST_CHECK_EQUAL(params.getKeySize(), 64); - - AesKeyParams params2(128); - BOOST_CHECK_EQUAL(params2.getKeyType(), KeyType::AES); - BOOST_CHECK_EQUAL(params2.getKeySize(), 128); - - AesKeyParams params3(256); - BOOST_CHECK_EQUAL(params3.getKeyType(), KeyType::AES); - BOOST_CHECK_EQUAL(params3.getKeySize(), 256); - - AesKeyParams params4(4); - BOOST_CHECK_EQUAL(params4.getKeyType(), KeyType::AES); - BOOST_CHECK_EQUAL(params4.getKeySize(), 64); -} - -BOOST_AUTO_TEST_CASE(Error) -{ - EcdsaKeyParams params; - BOOST_REQUIRE_THROW((RsaKeyParams(params)), KeyParams::Error); - - AesKeyParams params2; - BOOST_REQUIRE_THROW((RsaKeyParams(params2)), KeyParams::Error); -} - -BOOST_AUTO_TEST_SUITE_END() // TestKeyParams -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/security/key.t.cpp b/tests/unit-tests/security/key.t.cpp deleted file mode 100644 index 7d9ddc132..000000000 --- a/tests/unit-tests/security/key.t.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/key.hpp" -#include "security/pib.hpp" -#include "security/pib-memory.hpp" - -#include "boost-test.hpp" -#include "pib-data-fixture.hpp" - -namespace ndn { -namespace security { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_FIXTURE_TEST_SUITE(TestKey, PibDataFixture) - -BOOST_AUTO_TEST_CASE(ValidityChecking) -{ - // key - Key key; - - BOOST_CHECK_EQUAL(static_cast(key), false); - BOOST_CHECK_EQUAL(!key, true); - - if (key) - BOOST_CHECK(false); - else - BOOST_CHECK(true); - - auto pibImpl = make_shared(); - key = Key(id1, id1Key1Name.get(-1), id1Key1, pibImpl); - - BOOST_CHECK_EQUAL(static_cast(key), true); - BOOST_CHECK_EQUAL(!key, false); - - if (key) - BOOST_CHECK(true); - else - BOOST_CHECK(false); -} - -BOOST_AUTO_TEST_CASE(CertificateOperations) -{ - auto pibImpl = make_shared(); - - Key key11(id1, id1Key1Name.get(-1), id1Key1, pibImpl); - - BOOST_CHECK_THROW(key11.getCertificate(id1Key1Cert1.getName()), Pib::Error); - key11.addCertificate(id1Key1Cert1); - BOOST_CHECK_NO_THROW(key11.getCertificate(id1Key1Cert1.getName())); - key11.removeCertificate(id1Key1Cert1.getName()); - BOOST_CHECK_THROW(key11.getCertificate(id1Key1Cert1.getName()), Pib::Error); - - BOOST_CHECK_THROW(key11.getDefaultCertificate(), Pib::Error); - BOOST_REQUIRE_THROW(key11.setDefaultCertificate(id1Key1Cert1.getName()), Pib::Error); - BOOST_REQUIRE_NO_THROW(key11.setDefaultCertificate(id1Key1Cert1)); - BOOST_REQUIRE_NO_THROW(key11.getDefaultCertificate()); - - const v1::IdentityCertificate& defaultCert = key11.getDefaultCertificate(); - BOOST_CHECK_EQUAL_COLLECTIONS(defaultCert.wireEncode().wire(), - defaultCert.wireEncode().wire() + defaultCert.wireEncode().size(), - id1Key1Cert1.wireEncode().wire(), - id1Key1Cert1.wireEncode().wire() + id1Key1Cert1.wireEncode().size()); - - key11.removeCertificate(id1Key1Cert1.getName()); - BOOST_CHECK_THROW(key11.getCertificate(id1Key1Cert1.getName()), Pib::Error); - BOOST_CHECK_THROW(key11.getDefaultCertificate(), Pib::Error); -} - -BOOST_AUTO_TEST_SUITE_END() // TestKey -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/pib-data-fixture.cpp b/tests/unit-tests/security/pib-data-fixture.cpp deleted file mode 100644 index 18b2cfb0a..000000000 --- a/tests/unit-tests/security/pib-data-fixture.cpp +++ /dev/null @@ -1,340 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "pib-data-fixture.hpp" - -/** - * The test data can be generated with a TestCertDataGenerator defined as below: - * - * TestCertDataGenerator g; - * - * g.printTestDataForId(Name("/pib/interface/id/1")); - * g.printTestDataForId(Name("/pib/interface/id/2")); - * - * class TestCertDataGenerator : public IdentityManagementTimeFixture - * { - * public: - * void - * printTestDataForId(const Name& id) - * { - * addIdentity(id, EcdsaKeyParams()); - * - * Name key1Name = m_keyChain.getDefaultKeyNameForIdentity(id); - * shared_ptr key1 = m_keyChain.getPublicKey(key1Name); - * printBytes(key1->get()); - * - * Name key1Cert1Name = m_keyChain.getDefaultCertificateNameForKey(key1Name); - * shared_ptr key1Cert1 = m_keyChain.getCertificate(key1Cert1Name); - * printBytes(key1Cert1->wireEncode()); - * - * Name key2Name = m_keyChain.generateEcdsaKeyPair(id, true); - * shared_ptr key2 = m_keyChain.getPublicKey(key2Name); - * printBytes(key2->get()); - * - * shared_ptr key2Cert1 = m_keyChain.selfSign(key2Name); - * printBytes(key2Cert1->wireEncode()); - * - * advanceClocks(time::seconds(20)); - * - * shared_ptr key1Cert2 = m_keyChain.selfSign(key1Name); - * printBytes(key1Cert2->wireEncode()); - * - * shared_ptr key2Cert2 = m_keyChain.selfSign(key2Name); - * printBytes(key2Cert2->wireEncode()); - * } - * - * void - * printBytes(const Block& block) - * { - * printBytes(block.wire(), block.size()); - * } - * - * void - * printBytes(const Buffer& buffer) - * { - * printBytes(buffer.buf(), buffer.size()); - * } - * - * void - * printBytes(const uint8_t* buf, size_t size) - * { - * using namespace CryptoPP; - * - * std::string hex = toHex(buf, size); - * - * for (int i = 0; i < hex.size(); i++) { - * if (i % 40 == 0) - * std::cout << std::endl; - * - * std::cout << "0x" << hex[i]; - * std::cout << hex[++i]; - * - * if ((i + 1) != hex.size()) - * std::cout << ", "; - * } - * std::cout << std::endl; - * } - * }; - */ - -const uint8_t ID1_KEY1[] = { - 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, - 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xFF, 0xF9, 0x1E, 0x85, 0x6C, 0x29, 0x5F, 0x98, 0xB1, 0x2E, 0xD5, 0x3D, 0xCA, - 0xE2, 0x00, 0x52, 0x7A, 0x55, 0x93, 0x96, 0xD1, 0x7F, 0x03, 0x20, 0x25, 0xA7, 0xE5, 0xB8, 0xF8, 0x5D, 0xF0, 0x2E, 0x3E, - 0x60, 0x40, 0x19, 0x73, 0x00, 0x4F, 0x5A, 0xA7, 0x66, 0xFB, 0x38, 0xE6, 0xEB, 0xD5, 0xA4, 0x32, 0x1F, 0x5F, 0xC6, 0x7D, - 0x4B, 0xD4, 0xBB, 0x1E, 0x15, 0x29, 0x3E, 0x40, 0x22, 0x4E, 0xE7 -}; - -const uint8_t ID1_KEY1_CERT1[] = { - 0x06, 0xFD, 0x01, 0x88, 0x07, 0x43, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, - 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x31, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x11, 0x6B, 0x73, 0x6B, 0x2D, - 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, 0x34, 0x31, 0x33, 0x32, 0x30, 0x30, 0x30, 0x08, 0x07, 0x49, 0x44, 0x2D, 0x43, 0x45, - 0x52, 0x54, 0x08, 0x09, 0xFD, 0x00, 0x00, 0x01, 0x49, 0x9D, 0x59, 0x8C, 0xA0, 0x14, 0x03, 0x18, 0x01, 0x02, 0x15, 0xB2, - 0x30, 0x81, 0xAF, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31, 0x34, 0x31, 0x31, 0x31, 0x31, 0x30, 0x35, 0x33, 0x35, 0x33, - 0x32, 0x5A, 0x18, 0x0F, 0x32, 0x30, 0x33, 0x34, 0x31, 0x31, 0x30, 0x36, 0x30, 0x35, 0x33, 0x35, 0x33, 0x32, 0x5A, 0x30, - 0x2E, 0x30, 0x2C, 0x06, 0x03, 0x55, 0x04, 0x29, 0x13, 0x25, 0x2F, 0x70, 0x69, 0x62, 0x2F, 0x69, 0x6E, 0x74, 0x65, 0x72, - 0x66, 0x61, 0x63, 0x65, 0x2F, 0x69, 0x64, 0x2F, 0x31, 0x2F, 0x6B, 0x73, 0x6B, 0x2D, 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, - 0x34, 0x31, 0x33, 0x32, 0x30, 0x30, 0x30, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, - 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xFF, 0xF9, 0x1E, 0x85, 0x6C, 0x29, - 0x5F, 0x98, 0xB1, 0x2E, 0xD5, 0x3D, 0xCA, 0xE2, 0x00, 0x52, 0x7A, 0x55, 0x93, 0x96, 0xD1, 0x7F, 0x03, 0x20, 0x25, 0xA7, - 0xE5, 0xB8, 0xF8, 0x5D, 0xF0, 0x2E, 0x3E, 0x60, 0x40, 0x19, 0x73, 0x00, 0x4F, 0x5A, 0xA7, 0x66, 0xFB, 0x38, 0xE6, 0xEB, - 0xD5, 0xA4, 0x32, 0x1F, 0x5F, 0xC6, 0x7D, 0x4B, 0xD4, 0xBB, 0x1E, 0x15, 0x29, 0x3E, 0x40, 0x22, 0x4E, 0xE7, 0x16, 0x3F, - 0x1B, 0x01, 0x03, 0x1C, 0x3A, 0x07, 0x38, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, - 0x61, 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x31, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x11, 0x6B, 0x73, 0x6B, - 0x2D, 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, 0x34, 0x31, 0x33, 0x32, 0x30, 0x30, 0x30, 0x08, 0x07, 0x49, 0x44, 0x2D, 0x43, - 0x45, 0x52, 0x54, 0x17, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xAE, 0x85, 0xB6, 0xDE, 0x1B, 0x3B, 0xC0, 0x46, 0x93, 0xEF, - 0x49, 0x26, 0x98, 0x4B, 0x20, 0x77, 0xAB, 0xF6, 0x83, 0x41, 0x72, 0x1D, 0x99, 0xBE, 0x85, 0xC9, 0xC8, 0xA6, 0x14, 0x50, - 0xA6, 0x3E, 0x02, 0x20, 0x5A, 0xC6, 0x1F, 0xF7, 0x72, 0xB4, 0x3A, 0xA1, 0x1D, 0x5E, 0xF7, 0xF3, 0x3C, 0x83, 0xF7, 0xD8, - 0x27, 0x13, 0x65, 0x4D, 0x5D, 0x1A, 0x23, 0x5F, 0xA9, 0xFC, 0x53, 0x22, 0x86, 0xBD, 0x92, 0x01 -}; - -const uint8_t ID1_KEY1_CERT2[] = { - 0x06, 0xFD, 0x01, 0x88, 0x07, 0x43, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, - 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x31, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x11, 0x6B, 0x73, 0x6B, 0x2D, - 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, 0x34, 0x31, 0x33, 0x32, 0x30, 0x30, 0x30, 0x08, 0x07, 0x49, 0x44, 0x2D, 0x43, 0x45, - 0x52, 0x54, 0x08, 0x09, 0xFD, 0x00, 0x00, 0x01, 0x49, 0x9D, 0x59, 0xB3, 0xB0, 0x14, 0x03, 0x18, 0x01, 0x02, 0x15, 0xB2, - 0x30, 0x81, 0xAF, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31, 0x34, 0x31, 0x31, 0x31, 0x31, 0x30, 0x35, 0x33, 0x35, 0x34, - 0x32, 0x5A, 0x18, 0x0F, 0x32, 0x30, 0x33, 0x34, 0x31, 0x31, 0x30, 0x36, 0x30, 0x35, 0x33, 0x35, 0x34, 0x32, 0x5A, 0x30, - 0x2E, 0x30, 0x2C, 0x06, 0x03, 0x55, 0x04, 0x29, 0x13, 0x25, 0x2F, 0x70, 0x69, 0x62, 0x2F, 0x69, 0x6E, 0x74, 0x65, 0x72, - 0x66, 0x61, 0x63, 0x65, 0x2F, 0x69, 0x64, 0x2F, 0x31, 0x2F, 0x6B, 0x73, 0x6B, 0x2D, 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, - 0x34, 0x31, 0x33, 0x32, 0x30, 0x30, 0x30, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, - 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xFF, 0xF9, 0x1E, 0x85, 0x6C, 0x29, - 0x5F, 0x98, 0xB1, 0x2E, 0xD5, 0x3D, 0xCA, 0xE2, 0x00, 0x52, 0x7A, 0x55, 0x93, 0x96, 0xD1, 0x7F, 0x03, 0x20, 0x25, 0xA7, - 0xE5, 0xB8, 0xF8, 0x5D, 0xF0, 0x2E, 0x3E, 0x60, 0x40, 0x19, 0x73, 0x00, 0x4F, 0x5A, 0xA7, 0x66, 0xFB, 0x38, 0xE6, 0xEB, - 0xD5, 0xA4, 0x32, 0x1F, 0x5F, 0xC6, 0x7D, 0x4B, 0xD4, 0xBB, 0x1E, 0x15, 0x29, 0x3E, 0x40, 0x22, 0x4E, 0xE7, 0x16, 0x3F, - 0x1B, 0x01, 0x03, 0x1C, 0x3A, 0x07, 0x38, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, - 0x61, 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x31, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x11, 0x6B, 0x73, 0x6B, - 0x2D, 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, 0x34, 0x31, 0x33, 0x32, 0x30, 0x30, 0x30, 0x08, 0x07, 0x49, 0x44, 0x2D, 0x43, - 0x45, 0x52, 0x54, 0x17, 0x47, 0x30, 0x45, 0x02, 0x20, 0x12, 0xA8, 0xF5, 0x30, 0xE1, 0x57, 0xD1, 0x39, 0xB2, 0x46, 0x0A, - 0x82, 0x58, 0x8A, 0xCD, 0xB3, 0x6F, 0x2F, 0x1B, 0xB8, 0x6A, 0x99, 0xAB, 0x0C, 0xB2, 0xB7, 0xE2, 0x01, 0xE4, 0xD8, 0xC8, - 0x9C, 0x02, 0x21, 0x00, 0xDA, 0xCD, 0x11, 0x28, 0x96, 0xC6, 0xB6, 0x31, 0x6E, 0xDF, 0xCA, 0x79, 0xDE, 0x26, 0x44, 0xCA, - 0x09, 0x74, 0xF1, 0xB1, 0x7C, 0x9B, 0xFA, 0x67, 0x22, 0x55, 0x18, 0xA5, 0x05, 0x48, 0x7D, 0x65 -}; - -const uint8_t ID1_KEY2[] = { - 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, - 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xC2, 0xE0, 0xEC, 0xC7, 0xED, 0x65, 0xDE, 0x0A, 0x46, 0xCE, 0x38, 0xC2, 0x68, - 0x77, 0x4F, 0xE3, 0xE1, 0xDF, 0x37, 0x7D, 0xA3, 0x56, 0x0D, 0xF9, 0x66, 0x43, 0x37, 0x60, 0x42, 0x7E, 0x96, 0x93, 0x7E, - 0x35, 0xA0, 0xD5, 0xC8, 0x59, 0x8F, 0x36, 0x85, 0x11, 0xBF, 0xFA, 0x85, 0x1A, 0x7B, 0x61, 0xE6, 0xEB, 0xD1, 0x46, 0x99, - 0x67, 0x6B, 0xDB, 0x83, 0x26, 0x1F, 0x75, 0x7A, 0x93, 0xA2, 0xAE -}; - -const uint8_t ID1_KEY2_CERT1[] = { - 0x06, 0xFD, 0x01, 0x88, 0x07, 0x43, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, - 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x31, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x11, 0x6B, 0x73, 0x6B, 0x2D, - 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, 0x34, 0x31, 0x35, 0x32, 0x30, 0x30, 0x30, 0x08, 0x07, 0x49, 0x44, 0x2D, 0x43, 0x45, - 0x52, 0x54, 0x08, 0x09, 0xFD, 0x00, 0x00, 0x01, 0x49, 0x9D, 0x59, 0xDA, 0xC0, 0x14, 0x03, 0x18, 0x01, 0x02, 0x15, 0xB2, - 0x30, 0x81, 0xAF, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31, 0x34, 0x31, 0x31, 0x31, 0x31, 0x30, 0x35, 0x33, 0x35, 0x35, - 0x32, 0x5A, 0x18, 0x0F, 0x32, 0x30, 0x33, 0x34, 0x31, 0x31, 0x30, 0x36, 0x30, 0x35, 0x33, 0x35, 0x35, 0x32, 0x5A, 0x30, - 0x2E, 0x30, 0x2C, 0x06, 0x03, 0x55, 0x04, 0x29, 0x13, 0x25, 0x2F, 0x70, 0x69, 0x62, 0x2F, 0x69, 0x6E, 0x74, 0x65, 0x72, - 0x66, 0x61, 0x63, 0x65, 0x2F, 0x69, 0x64, 0x2F, 0x31, 0x2F, 0x6B, 0x73, 0x6B, 0x2D, 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, - 0x34, 0x31, 0x35, 0x32, 0x30, 0x30, 0x30, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, - 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xC2, 0xE0, 0xEC, 0xC7, 0xED, 0x65, - 0xDE, 0x0A, 0x46, 0xCE, 0x38, 0xC2, 0x68, 0x77, 0x4F, 0xE3, 0xE1, 0xDF, 0x37, 0x7D, 0xA3, 0x56, 0x0D, 0xF9, 0x66, 0x43, - 0x37, 0x60, 0x42, 0x7E, 0x96, 0x93, 0x7E, 0x35, 0xA0, 0xD5, 0xC8, 0x59, 0x8F, 0x36, 0x85, 0x11, 0xBF, 0xFA, 0x85, 0x1A, - 0x7B, 0x61, 0xE6, 0xEB, 0xD1, 0x46, 0x99, 0x67, 0x6B, 0xDB, 0x83, 0x26, 0x1F, 0x75, 0x7A, 0x93, 0xA2, 0xAE, 0x16, 0x3F, - 0x1B, 0x01, 0x03, 0x1C, 0x3A, 0x07, 0x38, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, - 0x61, 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x31, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x11, 0x6B, 0x73, 0x6B, - 0x2D, 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, 0x34, 0x31, 0x35, 0x32, 0x30, 0x30, 0x30, 0x08, 0x07, 0x49, 0x44, 0x2D, 0x43, - 0x45, 0x52, 0x54, 0x17, 0x47, 0x30, 0x45, 0x02, 0x20, 0x24, 0x26, 0x28, 0xA1, 0xD2, 0xCA, 0x46, 0xDB, 0x15, 0x5A, 0xB8, - 0x15, 0x58, 0x3B, 0x1C, 0xEC, 0xDF, 0x9E, 0xF9, 0x35, 0x32, 0x61, 0x0B, 0xC3, 0x9B, 0xA2, 0x1F, 0x05, 0xAA, 0x04, 0xE4, - 0x40, 0x02, 0x21, 0x00, 0xEA, 0x37, 0xA3, 0x1E, 0xD6, 0x20, 0x73, 0xD8, 0x55, 0xE6, 0x62, 0xB1, 0x23, 0xBC, 0x32, 0x08, - 0x1A, 0x0F, 0x4B, 0x94, 0xBE, 0x28, 0xCE, 0xE7, 0x0A, 0x8A, 0xB4, 0xD5, 0xEA, 0x8D, 0x20, 0x95 -}; - -const uint8_t ID1_KEY2_CERT2[] = { - 0x06, 0xFD, 0x01, 0x88, 0x07, 0x43, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, - 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x31, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x11, 0x6B, 0x73, 0x6B, 0x2D, - 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, 0x34, 0x31, 0x35, 0x32, 0x30, 0x30, 0x30, 0x08, 0x07, 0x49, 0x44, 0x2D, 0x43, 0x45, - 0x52, 0x54, 0x08, 0x09, 0xFD, 0x00, 0x00, 0x01, 0x49, 0x9D, 0x5A, 0x01, 0xD0, 0x14, 0x03, 0x18, 0x01, 0x02, 0x15, 0xB2, - 0x30, 0x81, 0xAF, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31, 0x34, 0x31, 0x31, 0x31, 0x31, 0x30, 0x35, 0x33, 0x36, 0x30, - 0x32, 0x5A, 0x18, 0x0F, 0x32, 0x30, 0x33, 0x34, 0x31, 0x31, 0x30, 0x36, 0x30, 0x35, 0x33, 0x36, 0x30, 0x32, 0x5A, 0x30, - 0x2E, 0x30, 0x2C, 0x06, 0x03, 0x55, 0x04, 0x29, 0x13, 0x25, 0x2F, 0x70, 0x69, 0x62, 0x2F, 0x69, 0x6E, 0x74, 0x65, 0x72, - 0x66, 0x61, 0x63, 0x65, 0x2F, 0x69, 0x64, 0x2F, 0x31, 0x2F, 0x6B, 0x73, 0x6B, 0x2D, 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, - 0x34, 0x31, 0x35, 0x32, 0x30, 0x30, 0x30, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, - 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xC2, 0xE0, 0xEC, 0xC7, 0xED, 0x65, - 0xDE, 0x0A, 0x46, 0xCE, 0x38, 0xC2, 0x68, 0x77, 0x4F, 0xE3, 0xE1, 0xDF, 0x37, 0x7D, 0xA3, 0x56, 0x0D, 0xF9, 0x66, 0x43, - 0x37, 0x60, 0x42, 0x7E, 0x96, 0x93, 0x7E, 0x35, 0xA0, 0xD5, 0xC8, 0x59, 0x8F, 0x36, 0x85, 0x11, 0xBF, 0xFA, 0x85, 0x1A, - 0x7B, 0x61, 0xE6, 0xEB, 0xD1, 0x46, 0x99, 0x67, 0x6B, 0xDB, 0x83, 0x26, 0x1F, 0x75, 0x7A, 0x93, 0xA2, 0xAE, 0x16, 0x3F, - 0x1B, 0x01, 0x03, 0x1C, 0x3A, 0x07, 0x38, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, - 0x61, 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x31, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x11, 0x6B, 0x73, 0x6B, - 0x2D, 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, 0x34, 0x31, 0x35, 0x32, 0x30, 0x30, 0x30, 0x08, 0x07, 0x49, 0x44, 0x2D, 0x43, - 0x45, 0x52, 0x54, 0x17, 0x47, 0x30, 0x45, 0x02, 0x20, 0x3B, 0x82, 0xAE, 0xFD, 0x8B, 0x6D, 0xBA, 0x1D, 0x77, 0x70, 0x86, - 0xAB, 0xF1, 0x37, 0x38, 0x90, 0x04, 0x83, 0x33, 0xF8, 0xF2, 0x2C, 0xD6, 0x50, 0x32, 0x19, 0xEA, 0xD6, 0xBB, 0x40, 0x58, - 0x8F, 0x02, 0x21, 0x00, 0x93, 0x01, 0x54, 0x5C, 0x8C, 0x60, 0x81, 0x89, 0xBE, 0x5E, 0x42, 0x31, 0x39, 0xF8, 0x12, 0xFD, - 0x31, 0x48, 0xB0, 0x96, 0x41, 0x40, 0x98, 0x68, 0xF9, 0x7C, 0x01, 0x94, 0xD0, 0xA3, 0xF3, 0xC7 -}; - -const uint8_t ID2_KEY1[] = { - 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, - 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xA4, 0x25, 0xDB, 0xB0, 0xD7, 0xC6, 0x0D, 0xC6, 0x95, 0x97, 0x79, 0xFA, 0xE3, - 0xC7, 0x90, 0xFB, 0x97, 0xAF, 0xCE, 0xDB, 0xC3, 0x50, 0x99, 0x1E, 0x39, 0xF5, 0x9A, 0xB6, 0xC9, 0x37, 0x1A, 0xE5, 0x0A, - 0x56, 0xE0, 0x0C, 0x0D, 0x81, 0xC7, 0x29, 0xE4, 0x69, 0x06, 0xD1, 0x4A, 0x14, 0x75, 0x05, 0x95, 0xBE, 0xE7, 0x01, 0x45, - 0x3C, 0xA7, 0x99, 0x09, 0x05, 0x9F, 0x65, 0x9A, 0xA5, 0x9C, 0xD5 -}; - -const uint8_t ID2_KEY1_CERT1[] = { - 0x06, 0xFD, 0x01, 0x89, 0x07, 0x43, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, - 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x32, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x11, 0x6B, 0x73, 0x6B, 0x2D, - 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, 0x34, 0x31, 0x33, 0x32, 0x30, 0x30, 0x30, 0x08, 0x07, 0x49, 0x44, 0x2D, 0x43, 0x45, - 0x52, 0x54, 0x08, 0x09, 0xFD, 0x00, 0x00, 0x01, 0x49, 0x9D, 0x59, 0x8C, 0xA0, 0x14, 0x03, 0x18, 0x01, 0x02, 0x15, 0xB2, - 0x30, 0x81, 0xAF, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31, 0x34, 0x31, 0x31, 0x31, 0x31, 0x30, 0x35, 0x33, 0x35, 0x33, - 0x32, 0x5A, 0x18, 0x0F, 0x32, 0x30, 0x33, 0x34, 0x31, 0x31, 0x30, 0x36, 0x30, 0x35, 0x33, 0x35, 0x33, 0x32, 0x5A, 0x30, - 0x2E, 0x30, 0x2C, 0x06, 0x03, 0x55, 0x04, 0x29, 0x13, 0x25, 0x2F, 0x70, 0x69, 0x62, 0x2F, 0x69, 0x6E, 0x74, 0x65, 0x72, - 0x66, 0x61, 0x63, 0x65, 0x2F, 0x69, 0x64, 0x2F, 0x32, 0x2F, 0x6B, 0x73, 0x6B, 0x2D, 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, - 0x34, 0x31, 0x33, 0x32, 0x30, 0x30, 0x30, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, - 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xA4, 0x25, 0xDB, 0xB0, 0xD7, 0xC6, - 0x0D, 0xC6, 0x95, 0x97, 0x79, 0xFA, 0xE3, 0xC7, 0x90, 0xFB, 0x97, 0xAF, 0xCE, 0xDB, 0xC3, 0x50, 0x99, 0x1E, 0x39, 0xF5, - 0x9A, 0xB6, 0xC9, 0x37, 0x1A, 0xE5, 0x0A, 0x56, 0xE0, 0x0C, 0x0D, 0x81, 0xC7, 0x29, 0xE4, 0x69, 0x06, 0xD1, 0x4A, 0x14, - 0x75, 0x05, 0x95, 0xBE, 0xE7, 0x01, 0x45, 0x3C, 0xA7, 0x99, 0x09, 0x05, 0x9F, 0x65, 0x9A, 0xA5, 0x9C, 0xD5, 0x16, 0x3F, - 0x1B, 0x01, 0x03, 0x1C, 0x3A, 0x07, 0x38, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, - 0x61, 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x32, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x11, 0x6B, 0x73, 0x6B, - 0x2D, 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, 0x34, 0x31, 0x33, 0x32, 0x30, 0x30, 0x30, 0x08, 0x07, 0x49, 0x44, 0x2D, 0x43, - 0x45, 0x52, 0x54, 0x17, 0x48, 0x30, 0x46, 0x02, 0x21, 0x00, 0xC4, 0x40, 0x87, 0xA7, 0xAA, 0xA7, 0x12, 0xE2, 0x7C, 0xE2, - 0xA8, 0x27, 0x66, 0xCF, 0x45, 0x3E, 0x3D, 0xEC, 0x2C, 0x5C, 0x03, 0xD6, 0xB0, 0xD6, 0x5E, 0xE8, 0xB7, 0x03, 0x9C, 0x38, - 0x75, 0xEA, 0x02, 0x21, 0x00, 0x8D, 0xF3, 0x9E, 0xC0, 0x18, 0xBD, 0xA1, 0x2B, 0xDB, 0x3D, 0xE0, 0x34, 0x14, 0x34, 0x65, - 0x23, 0x37, 0x6E, 0x3C, 0xC0, 0xC4, 0x2F, 0xED, 0xBB, 0x9B, 0xB2, 0xEC, 0x2A, 0x96, 0xE6, 0xD2, 0x98 -}; - -const uint8_t ID2_KEY1_CERT2[] = { - 0x06, 0xFD, 0x01, 0x88, 0x07, 0x43, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, - 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x32, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x11, 0x6B, 0x73, 0x6B, 0x2D, - 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, 0x34, 0x31, 0x33, 0x32, 0x30, 0x30, 0x30, 0x08, 0x07, 0x49, 0x44, 0x2D, 0x43, 0x45, - 0x52, 0x54, 0x08, 0x09, 0xFD, 0x00, 0x00, 0x01, 0x49, 0x9D, 0x59, 0xB3, 0xB0, 0x14, 0x03, 0x18, 0x01, 0x02, 0x15, 0xB2, - 0x30, 0x81, 0xAF, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31, 0x34, 0x31, 0x31, 0x31, 0x31, 0x30, 0x35, 0x33, 0x35, 0x34, - 0x32, 0x5A, 0x18, 0x0F, 0x32, 0x30, 0x33, 0x34, 0x31, 0x31, 0x30, 0x36, 0x30, 0x35, 0x33, 0x35, 0x34, 0x32, 0x5A, 0x30, - 0x2E, 0x30, 0x2C, 0x06, 0x03, 0x55, 0x04, 0x29, 0x13, 0x25, 0x2F, 0x70, 0x69, 0x62, 0x2F, 0x69, 0x6E, 0x74, 0x65, 0x72, - 0x66, 0x61, 0x63, 0x65, 0x2F, 0x69, 0x64, 0x2F, 0x32, 0x2F, 0x6B, 0x73, 0x6B, 0x2D, 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, - 0x34, 0x31, 0x33, 0x32, 0x30, 0x30, 0x30, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, - 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xA4, 0x25, 0xDB, 0xB0, 0xD7, 0xC6, - 0x0D, 0xC6, 0x95, 0x97, 0x79, 0xFA, 0xE3, 0xC7, 0x90, 0xFB, 0x97, 0xAF, 0xCE, 0xDB, 0xC3, 0x50, 0x99, 0x1E, 0x39, 0xF5, - 0x9A, 0xB6, 0xC9, 0x37, 0x1A, 0xE5, 0x0A, 0x56, 0xE0, 0x0C, 0x0D, 0x81, 0xC7, 0x29, 0xE4, 0x69, 0x06, 0xD1, 0x4A, 0x14, - 0x75, 0x05, 0x95, 0xBE, 0xE7, 0x01, 0x45, 0x3C, 0xA7, 0x99, 0x09, 0x05, 0x9F, 0x65, 0x9A, 0xA5, 0x9C, 0xD5, 0x16, 0x3F, - 0x1B, 0x01, 0x03, 0x1C, 0x3A, 0x07, 0x38, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, - 0x61, 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x32, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x11, 0x6B, 0x73, 0x6B, - 0x2D, 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, 0x34, 0x31, 0x33, 0x32, 0x30, 0x30, 0x30, 0x08, 0x07, 0x49, 0x44, 0x2D, 0x43, - 0x45, 0x52, 0x54, 0x17, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xAA, 0xFE, 0x76, 0xBE, 0x2C, 0x4D, 0xDA, 0x41, 0x27, 0x93, - 0x11, 0x70, 0xEE, 0x33, 0x57, 0x37, 0xA2, 0x54, 0x01, 0x97, 0x82, 0x16, 0xB5, 0x8A, 0xFD, 0xE2, 0x5F, 0x2E, 0x05, 0x0A, - 0xF5, 0xE6, 0x02, 0x20, 0x4F, 0xEF, 0x85, 0xC6, 0x91, 0xF3, 0x55, 0x2C, 0x4E, 0x98, 0x81, 0xD7, 0xF0, 0x63, 0x36, 0x91, - 0xB3, 0x88, 0x9D, 0x99, 0x7E, 0x49, 0xD5, 0x72, 0x7F, 0x6F, 0x92, 0xCF, 0x0A, 0x56, 0xA6, 0xF9 -}; - -const uint8_t ID2_KEY2[] = { - 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, - 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x6C, 0x49, 0x20, 0x7E, 0x59, 0xAF, 0x48, 0x1C, 0x9B, 0xCB, 0x67, 0xD4, 0x6F, - 0x43, 0x9D, 0xD8, 0xB5, 0x36, 0xDB, 0x72, 0xDA, 0x37, 0x55, 0x4B, 0x8C, 0x69, 0x17, 0x87, 0xF6, 0x06, 0xAB, 0x06, 0x70, - 0x91, 0xBE, 0x02, 0x79, 0xB1, 0x14, 0x9C, 0xD0, 0x0B, 0x92, 0xD5, 0xC4, 0xF1, 0xEC, 0x23, 0x90, 0x95, 0xCB, 0x7D, 0x59, - 0x62, 0x3B, 0x30, 0xFE, 0xCF, 0x05, 0xBE, 0x04, 0xC9, 0x78, 0x5C -}; - -const uint8_t ID2_KEY2_CERT1[] = { - 0x06, 0xFD, 0x01, 0x89, 0x07, 0x43, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, - 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x32, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x11, 0x6B, 0x73, 0x6B, 0x2D, - 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, 0x34, 0x31, 0x35, 0x32, 0x30, 0x30, 0x30, 0x08, 0x07, 0x49, 0x44, 0x2D, 0x43, 0x45, - 0x52, 0x54, 0x08, 0x09, 0xFD, 0x00, 0x00, 0x01, 0x49, 0x9D, 0x59, 0xDA, 0xC0, 0x14, 0x03, 0x18, 0x01, 0x02, 0x15, 0xB2, - 0x30, 0x81, 0xAF, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31, 0x34, 0x31, 0x31, 0x31, 0x31, 0x30, 0x35, 0x33, 0x35, 0x35, - 0x32, 0x5A, 0x18, 0x0F, 0x32, 0x30, 0x33, 0x34, 0x31, 0x31, 0x30, 0x36, 0x30, 0x35, 0x33, 0x35, 0x35, 0x32, 0x5A, 0x30, - 0x2E, 0x30, 0x2C, 0x06, 0x03, 0x55, 0x04, 0x29, 0x13, 0x25, 0x2F, 0x70, 0x69, 0x62, 0x2F, 0x69, 0x6E, 0x74, 0x65, 0x72, - 0x66, 0x61, 0x63, 0x65, 0x2F, 0x69, 0x64, 0x2F, 0x32, 0x2F, 0x6B, 0x73, 0x6B, 0x2D, 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, - 0x34, 0x31, 0x35, 0x32, 0x30, 0x30, 0x30, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, - 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x6C, 0x49, 0x20, 0x7E, 0x59, 0xAF, - 0x48, 0x1C, 0x9B, 0xCB, 0x67, 0xD4, 0x6F, 0x43, 0x9D, 0xD8, 0xB5, 0x36, 0xDB, 0x72, 0xDA, 0x37, 0x55, 0x4B, 0x8C, 0x69, - 0x17, 0x87, 0xF6, 0x06, 0xAB, 0x06, 0x70, 0x91, 0xBE, 0x02, 0x79, 0xB1, 0x14, 0x9C, 0xD0, 0x0B, 0x92, 0xD5, 0xC4, 0xF1, - 0xEC, 0x23, 0x90, 0x95, 0xCB, 0x7D, 0x59, 0x62, 0x3B, 0x30, 0xFE, 0xCF, 0x05, 0xBE, 0x04, 0xC9, 0x78, 0x5C, 0x16, 0x3F, - 0x1B, 0x01, 0x03, 0x1C, 0x3A, 0x07, 0x38, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, - 0x61, 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x32, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x11, 0x6B, 0x73, 0x6B, - 0x2D, 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, 0x34, 0x31, 0x35, 0x32, 0x30, 0x30, 0x30, 0x08, 0x07, 0x49, 0x44, 0x2D, 0x43, - 0x45, 0x52, 0x54, 0x17, 0x48, 0x30, 0x46, 0x02, 0x21, 0x00, 0xB6, 0x8E, 0x31, 0xFB, 0x08, 0x34, 0xF3, 0x1C, 0xB5, 0x09, - 0x7D, 0xD4, 0x17, 0x45, 0xC7, 0x6A, 0x81, 0xEE, 0x6F, 0x16, 0x76, 0xEE, 0xDC, 0x44, 0xB4, 0xD7, 0x1A, 0xD5, 0x61, 0x57, - 0x80, 0xBD, 0x02, 0x21, 0x00, 0xF7, 0xDB, 0xDF, 0x89, 0xBC, 0xE8, 0x28, 0x26, 0xF8, 0xEE, 0x74, 0x2B, 0x9C, 0xF0, 0x7F, - 0xB8, 0x3A, 0xEE, 0xBF, 0x1F, 0x51, 0x14, 0x6A, 0x8F, 0x2E, 0x5A, 0x60, 0xD8, 0x45, 0x87, 0x62, 0x51 -}; - -const uint8_t ID2_KEY2_CERT2[] = { - 0x06, 0xFD, 0x01, 0x89, 0x07, 0x43, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, - 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x32, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x11, 0x6B, 0x73, 0x6B, 0x2D, - 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, 0x34, 0x31, 0x35, 0x32, 0x30, 0x30, 0x30, 0x08, 0x07, 0x49, 0x44, 0x2D, 0x43, 0x45, - 0x52, 0x54, 0x08, 0x09, 0xFD, 0x00, 0x00, 0x01, 0x49, 0x9D, 0x5A, 0x01, 0xD0, 0x14, 0x03, 0x18, 0x01, 0x02, 0x15, 0xB2, - 0x30, 0x81, 0xAF, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31, 0x34, 0x31, 0x31, 0x31, 0x31, 0x30, 0x35, 0x33, 0x36, 0x30, - 0x32, 0x5A, 0x18, 0x0F, 0x32, 0x30, 0x33, 0x34, 0x31, 0x31, 0x30, 0x36, 0x30, 0x35, 0x33, 0x36, 0x30, 0x32, 0x5A, 0x30, - 0x2E, 0x30, 0x2C, 0x06, 0x03, 0x55, 0x04, 0x29, 0x13, 0x25, 0x2F, 0x70, 0x69, 0x62, 0x2F, 0x69, 0x6E, 0x74, 0x65, 0x72, - 0x66, 0x61, 0x63, 0x65, 0x2F, 0x69, 0x64, 0x2F, 0x32, 0x2F, 0x6B, 0x73, 0x6B, 0x2D, 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, - 0x34, 0x31, 0x35, 0x32, 0x30, 0x30, 0x30, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, - 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x6C, 0x49, 0x20, 0x7E, 0x59, 0xAF, - 0x48, 0x1C, 0x9B, 0xCB, 0x67, 0xD4, 0x6F, 0x43, 0x9D, 0xD8, 0xB5, 0x36, 0xDB, 0x72, 0xDA, 0x37, 0x55, 0x4B, 0x8C, 0x69, - 0x17, 0x87, 0xF6, 0x06, 0xAB, 0x06, 0x70, 0x91, 0xBE, 0x02, 0x79, 0xB1, 0x14, 0x9C, 0xD0, 0x0B, 0x92, 0xD5, 0xC4, 0xF1, - 0xEC, 0x23, 0x90, 0x95, 0xCB, 0x7D, 0x59, 0x62, 0x3B, 0x30, 0xFE, 0xCF, 0x05, 0xBE, 0x04, 0xC9, 0x78, 0x5C, 0x16, 0x3F, - 0x1B, 0x01, 0x03, 0x1C, 0x3A, 0x07, 0x38, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, - 0x61, 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x32, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x11, 0x6B, 0x73, 0x6B, - 0x2D, 0x31, 0x34, 0x31, 0x35, 0x36, 0x38, 0x34, 0x31, 0x35, 0x32, 0x30, 0x30, 0x30, 0x08, 0x07, 0x49, 0x44, 0x2D, 0x43, - 0x45, 0x52, 0x54, 0x17, 0x48, 0x30, 0x46, 0x02, 0x21, 0x00, 0x9E, 0xA1, 0x49, 0xCB, 0x99, 0xB8, 0xB9, 0xD0, 0x86, 0x93, - 0xB1, 0x5A, 0xD5, 0xAE, 0x2D, 0x32, 0xE8, 0xC1, 0x3F, 0x9E, 0x35, 0x7A, 0x45, 0xD7, 0x2F, 0x79, 0xE3, 0x76, 0x04, 0xCD, - 0x66, 0x70, 0x02, 0x21, 0x00, 0x99, 0x04, 0x0A, 0x35, 0x3B, 0x53, 0x1B, 0x13, 0x14, 0xAC, 0xB5, 0x8E, 0x6F, 0x1A, 0x72, - 0x2C, 0x3D, 0x86, 0xCF, 0xF6, 0x8D, 0x2F, 0x13, 0x60, 0x28, 0xB1, 0x13, 0xFE, 0x49, 0x3B, 0xA4, 0xAD -}; - -namespace ndn { -namespace security { - -PibDataFixture::PibDataFixture() - : id1("/pib/interface/id/1") - , id2("/pib/interface/id/2") - , id1Key1Name("/pib/interface/id/1/ksk-1415684132000") - , id1Key2Name("/pib/interface/id/1/ksk-1415684152000") - , id2Key1Name("/pib/interface/id/2/ksk-1415684132000") - , id2Key2Name("/pib/interface/id/2/ksk-1415684152000") - , id1Key1(ID1_KEY1, sizeof(ID1_KEY1)) - , id1Key2(ID1_KEY2, sizeof(ID1_KEY2)) - , id2Key1(ID2_KEY1, sizeof(ID2_KEY1)) - , id2Key2(ID2_KEY2, sizeof(ID2_KEY2)) - , id1Key1Cert1(Block(ID1_KEY1_CERT1, sizeof(ID1_KEY1_CERT1))) - , id1Key1Cert2(Block(ID1_KEY1_CERT2, sizeof(ID1_KEY1_CERT2))) - , id1Key2Cert1(Block(ID1_KEY2_CERT1, sizeof(ID1_KEY2_CERT1))) - , id1Key2Cert2(Block(ID1_KEY2_CERT2, sizeof(ID1_KEY2_CERT2))) - , id2Key1Cert1(Block(ID2_KEY1_CERT1, sizeof(ID2_KEY1_CERT1))) - , id2Key1Cert2(Block(ID2_KEY1_CERT2, sizeof(ID2_KEY1_CERT2))) - , id2Key2Cert1(Block(ID2_KEY2_CERT1, sizeof(ID2_KEY2_CERT1))) - , id2Key2Cert2(Block(ID2_KEY2_CERT2, sizeof(ID2_KEY2_CERT2))) -{ -} - -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/pib-data-fixture.hpp b/tests/unit-tests/security/pib-data-fixture.hpp deleted file mode 100644 index 5e92dd1b1..000000000 --- a/tests/unit-tests/security/pib-data-fixture.hpp +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_TESTS_SECURITY_PIB_DATA_FIXTURE_HPP -#define NDN_TESTS_SECURITY_PIB_DATA_FIXTURE_HPP - -#include "security/v1/identity-certificate.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace security { - -class PibDataFixture -{ -public: - PibDataFixture(); - -public: - Name id1; - Name id2; - - Name id1Key1Name; - Name id1Key2Name; - Name id2Key1Name; - Name id2Key2Name; - - v1::PublicKey id1Key1; - v1::PublicKey id1Key2; - v1::PublicKey id2Key1; - v1::PublicKey id2Key2; - - v1::IdentityCertificate id1Key1Cert1; - v1::IdentityCertificate id1Key1Cert2; - v1::IdentityCertificate id1Key2Cert1; - v1::IdentityCertificate id1Key2Cert2; - v1::IdentityCertificate id2Key1Cert1; - v1::IdentityCertificate id2Key1Cert2; - v1::IdentityCertificate id2Key2Cert1; - v1::IdentityCertificate id2Key2Cert2; -}; - -} // namespace security -} // namespace ndn - -#endif // NDN_TESTS_SECURITY_PIB_DATA_FIXTURE_HPP diff --git a/tests/unit-tests/security/pib-impl.t.cpp b/tests/unit-tests/security/pib-impl.t.cpp deleted file mode 100644 index d86a95d56..000000000 --- a/tests/unit-tests/security/pib-impl.t.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/pib-memory.hpp" -#include "security/pib-sqlite3.hpp" -#include "security/pib.hpp" - -#include "boost-test.hpp" -#include "pib-data-fixture.hpp" - -#include -#include - -namespace ndn { -namespace security { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(TestPibImpl) - -class PibMemoryWrapper -{ -public: - PibMemory impl; -}; - -class PibSqlite3Wrapper -{ -public: - PibSqlite3Wrapper() - : tmpPath(boost::filesystem::path(UNIT_TEST_CONFIG_PATH) / "DbTest") - , impl(tmpPath.c_str()) - { - } - - ~PibSqlite3Wrapper() - { - boost::filesystem::remove_all(tmpPath); - } - -public: - boost::filesystem::path tmpPath; - PibSqlite3 impl; -}; - -typedef boost::mpl::list PibImpls; - -BOOST_FIXTURE_TEST_CASE_TEMPLATE(IdentityManagement, T, PibImpls, PibDataFixture) -{ - T wrapper; - PibImpl& pibImpl = wrapper.impl; - - // no default setting, throw Error - BOOST_CHECK_THROW(pibImpl.getDefaultIdentity(), Pib::Error); - - // check id1, which should not exist - BOOST_CHECK_EQUAL(pibImpl.hasIdentity(id1), false); - - // add id1, should be default - pibImpl.addIdentity(id1); - BOOST_CHECK_EQUAL(pibImpl.hasIdentity(id1), true); - BOOST_CHECK_NO_THROW(pibImpl.getDefaultIdentity()); - BOOST_CHECK_EQUAL(pibImpl.getDefaultIdentity(), id1); - - // add id2, should not be default - pibImpl.addIdentity(id2); - BOOST_CHECK_EQUAL(pibImpl.hasIdentity(id2), true); - BOOST_CHECK_EQUAL(pibImpl.getDefaultIdentity(), id1); - - // set id2 explicitly as default - pibImpl.setDefaultIdentity(id2); - BOOST_CHECK_EQUAL(pibImpl.getDefaultIdentity(), id2); - - // remove id2, should not have default identity - pibImpl.removeIdentity(id2); - BOOST_CHECK_EQUAL(pibImpl.hasIdentity(id2), false); - BOOST_CHECK_THROW(pibImpl.getDefaultIdentity(), Pib::Error); - - // add id2 again, should be default - pibImpl.addIdentity(id2); - BOOST_CHECK_EQUAL(pibImpl.getDefaultIdentity(), id2); - - // get all identities, should contain id1 and id2 - std::set idNames = pibImpl.getIdentities(); - BOOST_CHECK_EQUAL(idNames.size(), 2); - BOOST_CHECK_EQUAL(idNames.count(id1), 1); - BOOST_CHECK_EQUAL(idNames.count(id2), 1); -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE(KeyManagement, T, PibImpls, PibDataFixture) -{ - T wrapper; - PibImpl& pibImpl = wrapper.impl; - - // no default setting, throw Error - BOOST_CHECK_THROW(pibImpl.getDefaultKeyOfIdentity(id1), Pib::Error); - - // check id1Key1, should not exist, neither should id1. - BOOST_CHECK_EQUAL(pibImpl.hasKey(id1, id1Key1Name.get(-1)), false); - BOOST_CHECK_EQUAL(pibImpl.hasIdentity(id1), false); - - // add id1Key1, should be default, id1 should be added implicitly - pibImpl.addKey(id1, id1Key1Name.get(-1), id1Key1); - BOOST_CHECK_EQUAL(pibImpl.hasKey(id1, id1Key1Name.get(-1)), true); - BOOST_CHECK_EQUAL(pibImpl.hasIdentity(id1), true); - const v1::PublicKey& keyBits = pibImpl.getKeyBits(id1, id1Key1Name.get(-1)); - BOOST_CHECK_EQUAL_COLLECTIONS(keyBits.get().buf(), keyBits.get().buf() + keyBits.get().size(), - id1Key1.get().buf(), id1Key1.get().buf() + id1Key1.get().size()); - BOOST_CHECK_NO_THROW(pibImpl.getDefaultKeyOfIdentity(id1)); - BOOST_CHECK_EQUAL(pibImpl.getDefaultKeyOfIdentity(id1), id1Key1Name.get(-1)); - - // add id1Key2, should not be default - pibImpl.addKey(id1, id1Key2Name.get(-1), id1Key2); - BOOST_CHECK_EQUAL(pibImpl.hasKey(id1, id1Key2Name.get(-1)), true); - BOOST_CHECK_EQUAL(pibImpl.getDefaultKeyOfIdentity(id1), id1Key1Name.get(-1)); - - // set id1Key2 explicitly as default - pibImpl.setDefaultKeyOfIdentity(id1, id1Key2Name.get(-1)); - BOOST_CHECK_EQUAL(pibImpl.getDefaultKeyOfIdentity(id1), id1Key2Name.get(-1)); - - // set a non-existing key as default, throw Error - BOOST_CHECK_THROW(pibImpl.setDefaultKeyOfIdentity(id1, name::Component("non-existing")), - Pib::Error); - - // remove id1Key2, should not have default key - pibImpl.removeKey(id1, id1Key2Name.get(-1)); - BOOST_CHECK_EQUAL(pibImpl.hasKey(id1, id1Key2Name.get(-1)), false); - BOOST_CHECK_THROW(pibImpl.getKeyBits(id1, id1Key2Name.get(-1)), Pib::Error); - BOOST_CHECK_THROW(pibImpl.getDefaultKeyOfIdentity(id1), Pib::Error); - - // add id1Key2 back, should be default - pibImpl.addKey(id1, id1Key2Name.get(-1), id1Key2); - BOOST_CHECK_NO_THROW(pibImpl.getKeyBits(id1, id1Key2Name.get(-1))); - BOOST_CHECK_EQUAL(pibImpl.getDefaultKeyOfIdentity(id1), id1Key2Name.get(-1)); - - // get all the keys: id1Key1 and id1Key2 - std::set keyNames = pibImpl.getKeysOfIdentity(id1); - BOOST_CHECK_EQUAL(keyNames.size(), 2); - BOOST_CHECK_EQUAL(keyNames.count(id1Key1Name.get(-1)), 1); - BOOST_CHECK_EQUAL(keyNames.count(id1Key2Name.get(-1)), 1); - - // remove id1, should remove all the keys - pibImpl.removeIdentity(id1); - keyNames = pibImpl.getKeysOfIdentity(id1); - BOOST_CHECK_EQUAL(keyNames.size(), 0); -} - -BOOST_FIXTURE_TEST_CASE_TEMPLATE(CertificateManagement, T, PibImpls, PibDataFixture) -{ - T wrapper; - PibImpl& pibImpl = wrapper.impl; - - // no default setting, throw Error - BOOST_CHECK_THROW(pibImpl.getDefaultCertificateOfKey(id1, id1Key1Name.get(-1)), Pib::Error); - - // check id1Key1Cert1, should not exist, neither should id1 and id1Key1 - BOOST_CHECK_EQUAL(pibImpl.hasCertificate(id1Key1Cert1.getName()), false); - BOOST_CHECK_EQUAL(pibImpl.hasIdentity(id1), false); - BOOST_CHECK_EQUAL(pibImpl.hasKey(id1, id1Key1Name.get(-1)), false); - - // add id1Key1Cert1, should be default, id1 and id1Key1 should be added implicitly - pibImpl.addCertificate(id1Key1Cert1); - BOOST_CHECK_EQUAL(pibImpl.hasCertificate(id1Key1Cert1.getName()), true); - BOOST_CHECK_EQUAL(pibImpl.hasIdentity(id1), true); - BOOST_CHECK_EQUAL(pibImpl.hasKey(id1, id1Key1Name.get(-1)), true); - const v1::IdentityCertificate& cert = pibImpl.getCertificate(id1Key1Cert1.getName()); - BOOST_CHECK_EQUAL_COLLECTIONS(cert.wireEncode().wire(), - cert.wireEncode().wire() + cert.wireEncode().size(), - id1Key1Cert1.wireEncode().wire(), - id1Key1Cert1.wireEncode().wire() + id1Key1Cert1.wireEncode().size()); - BOOST_CHECK_NO_THROW(pibImpl.getDefaultCertificateOfKey(id1, id1Key1Name.get(-1))); - BOOST_CHECK_EQUAL(pibImpl.getDefaultCertificateOfKey(id1, id1Key1Name.get(-1)), id1Key1Cert1); - - // add id1Key1Cert2, should not be default - pibImpl.addCertificate(id1Key1Cert2); - BOOST_CHECK_EQUAL(pibImpl.hasCertificate(id1Key1Cert2.getName()), true); - BOOST_CHECK_EQUAL(pibImpl.getDefaultCertificateOfKey(id1, id1Key1Name.get(-1)), id1Key1Cert1); - - // set id1Key1Cert2 explicitly as default - pibImpl.setDefaultCertificateOfKey(id1, id1Key1Name.get(-1), id1Key1Cert2.getName()); - BOOST_CHECK_EQUAL(pibImpl.getDefaultCertificateOfKey(id1, id1Key1Name.get(-1)), id1Key1Cert2); - - // set a non-existing cert as default, throw Error - BOOST_CHECK_THROW(pibImpl.setDefaultCertificateOfKey(id1, id1Key1Name.get(-1), Name("/non-existing")), - Pib::Error); - - // remove id1Key1Cert2, should not have default cert - pibImpl.removeCertificate(id1Key1Cert2.getName()); - BOOST_CHECK_EQUAL(pibImpl.hasCertificate(id1Key1Cert2.getName()), false); - BOOST_CHECK_THROW(pibImpl.getCertificate(id1Key1Cert2.getName()), Pib::Error); - BOOST_CHECK_THROW(pibImpl.getDefaultCertificateOfKey(id1, id1Key1Name.get(-1)), Pib::Error); - - // add id1Key1Cert2, should be default - pibImpl.addCertificate(id1Key1Cert2); - BOOST_CHECK_NO_THROW(pibImpl.getCertificate(id1Key1Cert1.getName())); - BOOST_CHECK_EQUAL(pibImpl.getDefaultCertificateOfKey(id1, id1Key1Name.get(-1)), id1Key1Cert2); - - // get all certificates: id1Key1Cert1 and id1Key1Cert2 - std::set certNames = pibImpl.getCertificatesOfKey(id1, id1Key1Name.get(-1)); - BOOST_CHECK_EQUAL(certNames.size(), 2); - BOOST_CHECK_EQUAL(certNames.count(id1Key1Cert1.getName()), 1); - BOOST_CHECK_EQUAL(certNames.count(id1Key1Cert2.getName()), 1); - - // remove id1Key1, should remove all the certs - pibImpl.removeKey(id1, id1Key1Name.get(-1)); - certNames = pibImpl.getCertificatesOfKey(id1, id1Key1Name.get(-1)); - BOOST_CHECK_EQUAL(certNames.size(), 0); -} - -BOOST_AUTO_TEST_SUITE_END() // TestPibImpl -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/pib-memory.t.cpp b/tests/unit-tests/security/pib-memory.t.cpp deleted file mode 100644 index 74dde3fec..000000000 --- a/tests/unit-tests/security/pib-memory.t.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/pib-memory.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace security { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(TestPibMemory) - -// most functionalities are tested in pib-impl.t.cpp - -BOOST_AUTO_TEST_CASE(TpmLocatorManagement) -{ - PibMemory pibImpl; - - BOOST_CHECK_EQUAL(pibImpl.getTpmLocator(), "tpm-memory:"); - BOOST_CHECK_THROW(pibImpl.setTpmLocator(""), PibImpl::Error); -} - -BOOST_AUTO_TEST_SUITE_END() // TestPibMemory -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/pib-sqlite3.t.cpp b/tests/unit-tests/security/pib-sqlite3.t.cpp deleted file mode 100644 index 656900eb0..000000000 --- a/tests/unit-tests/security/pib-sqlite3.t.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/pib-sqlite3.hpp" -#include "security/pib.hpp" - -#include "boost-test.hpp" - -#include - -namespace ndn { -namespace security { -namespace tests { - -class PibSqlite3TestFixture -{ -public: - PibSqlite3TestFixture() - : m_path(boost::filesystem::path(UNIT_TEST_CONFIG_PATH) / "DbTest") - , impl(m_path.c_str()) - { - } - - ~PibSqlite3TestFixture() - { - boost::filesystem::remove_all(m_path); - } - -private: - boost::filesystem::path m_path; - -public: - PibSqlite3 impl; -}; - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_FIXTURE_TEST_SUITE(TestPibSqlite3, PibSqlite3TestFixture) - -// most functionalities are tested in pib-impl.t.cpp - -const uint8_t SELF_SIGNED_ECDSA_CERT[] = { -0x06, 0xfd, 0x01, 0x5b, 0x07, 0x33, 0x08, 0x05, 0x65, 0x63, 0x64, 0x73, 0x61, 0x08, 0x03, -0x4b, 0x45, 0x59, 0x08, 0x11, 0x6b, 0x73, 0x6b, 0x2d, 0x31, 0x34, 0x31, 0x36, 0x35, 0x39, -0x34, 0x35, 0x35, 0x32, 0x38, 0x32, 0x37, 0x08, 0x07, 0x49, 0x44, 0x2d, 0x43, 0x45, 0x52, -0x54, 0x08, 0x09, 0xfd, 0x00, 0x00, 0x01, 0x49, 0xd3, 0x9d, 0x78, 0x00, 0x14, 0x03, 0x18, -0x01, 0x02, 0x15, 0xa5, 0x30, 0x81, 0xa2, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x34, -0x31, 0x31, 0x32, 0x31, 0x31, 0x38, 0x32, 0x39, 0x31, 0x32, 0x5a, 0x18, 0x0f, 0x32, 0x30, -0x33, 0x34, 0x31, 0x31, 0x31, 0x36, 0x31, 0x38, 0x32, 0x39, 0x31, 0x32, 0x5a, 0x30, 0x21, -0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x29, 0x13, 0x18, 0x2f, 0x65, 0x63, 0x64, 0x73, 0x61, -0x2f, 0x6b, 0x73, 0x6b, 0x2d, 0x31, 0x34, 0x31, 0x36, 0x35, 0x39, 0x34, 0x35, 0x35, 0x32, -0x38, 0x32, 0x37, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, -0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, -0x83, 0xe5, 0x81, 0x19, 0xd9, 0xfa, 0x64, 0x40, 0xad, 0x7c, 0x93, 0xfc, 0x15, 0x90, 0x6b, -0x38, 0x1e, 0xc5, 0xca, 0xb1, 0x6b, 0x0b, 0x1f, 0x64, 0xbf, 0x48, 0xaa, 0xd0, 0x91, 0x5c, -0x24, 0xd6, 0x78, 0x40, 0xfd, 0x95, 0x5d, 0x54, 0x64, 0xe1, 0x2d, 0x0e, 0x98, 0x66, 0x1d, -0x7a, 0xb0, 0x61, 0x17, 0x05, 0x26, 0x13, 0x63, 0x25, 0x7c, 0xda, 0x87, 0x11, 0xc9, 0x67, -0xcd, 0x12, 0x05, 0xf0, 0x16, 0x2f, 0x1b, 0x01, 0x03, 0x1c, 0x2a, 0x07, 0x28, 0x08, 0x05, -0x65, 0x63, 0x64, 0x73, 0x61, 0x08, 0x03, 0x4b, 0x45, 0x59, 0x08, 0x11, 0x6b, 0x73, 0x6b, -0x2d, 0x31, 0x34, 0x31, 0x36, 0x35, 0x39, 0x34, 0x35, 0x35, 0x32, 0x38, 0x32, 0x37, 0x08, -0x07, 0x49, 0x44, 0x2d, 0x43, 0x45, 0x52, 0x54, 0x17, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, -0x9b, 0xae, 0xf4, 0x87, 0x55, 0xaa, 0x78, 0xbf, 0x00, 0xff, 0x1a, 0xbe, 0x90, 0x46, 0x6e, -0xdd, 0xe6, 0x3b, 0x44, 0xfd, 0x41, 0x04, 0x86, 0xcc, 0x6a, 0x8b, 0x5a, 0x25, 0xbb, 0xf1, -0x55, 0xcd, 0x02, 0x20, 0x0e, 0x67, 0xd8, 0x86, 0xe8, 0x7c, 0x90, 0x3c, 0x13, 0xfd, 0x36, -0x9c, 0xbc, 0xa1, 0xc3, 0x7c, 0xe0, 0x0c, 0x6d, 0x64, 0xac, 0xdb, 0x69, 0x99, 0xde, 0x80, -0x35, 0x3f, 0xf4, 0x6a, 0xcd, 0x6f -}; - -BOOST_AUTO_TEST_CASE(TpmTest) -{ - Block selfSignedCertBlock(SELF_SIGNED_ECDSA_CERT, sizeof(SELF_SIGNED_ECDSA_CERT)); - v1::IdentityCertificate cert; - cert.wireDecode(selfSignedCertBlock); - Name identity = cert.getPublicKeyName().getPrefix(-1); - name::Component keyId = cert.getPublicKeyName().get(-1); - Name certName = cert.getName(); - - // Basic getting and setting - BOOST_REQUIRE_THROW(impl.getTpmLocator(), Pib::Error); - impl.setTpmLocator("tpmLocator"); - BOOST_CHECK_EQUAL(impl.getTpmLocator(), "tpmLocator"); - - // Add cert, and do not change tpmLocator - impl.addCertificate(cert); - BOOST_CHECK(impl.hasIdentity(identity)); - BOOST_CHECK(impl.hasKey(identity, keyId)); - BOOST_CHECK(impl.hasCertificate(certName)); - - // Set tpmLocator with the existing value, nothing should change. - impl.setTpmLocator("tpmLocator"); - BOOST_CHECK(impl.hasIdentity(identity)); - BOOST_CHECK(impl.hasKey(identity, keyId)); - BOOST_CHECK(impl.hasCertificate(certName)); - - // Change tpmLocator and ensure the pib is reset - impl.setTpmLocator("newTpmLocator"); - BOOST_CHECK_EQUAL(impl.getTpmLocator(), "newTpmLocator"); - - BOOST_CHECK_EQUAL(impl.getIdentities().size(), 0); - BOOST_CHECK_EQUAL(impl.getKeysOfIdentity(identity).size(), 0); - BOOST_CHECK_EQUAL(impl.getCertificatesOfKey(identity, keyId).size(), 0); -} - -BOOST_AUTO_TEST_SUITE_END() // TestPibSqlite3 -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/pib.t.cpp b/tests/unit-tests/security/pib.t.cpp deleted file mode 100644 index be617acaa..000000000 --- a/tests/unit-tests/security/pib.t.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/pib.hpp" -#include "security/pib-memory.hpp" - -#include "boost-test.hpp" -#include "pib-data-fixture.hpp" - -namespace ndn { -namespace security { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_FIXTURE_TEST_SUITE(TestPib, PibDataFixture) - -BOOST_AUTO_TEST_CASE(ValidityChecking) -{ - auto pibImpl = make_shared(); - Pib pib("pib-memory", "", pibImpl); - - Identity id = pib.addIdentity(id1); - - BOOST_CHECK_EQUAL(bool(id), true); - BOOST_CHECK_EQUAL(!id, false); - - if (id) - BOOST_CHECK(true); - else - BOOST_CHECK(false); - - // key - Key key = id.addKey(id1Key1, id1Key1Name.get(-1)); - - BOOST_CHECK_EQUAL(bool(key), true); - BOOST_CHECK_EQUAL(!key, false); - - if (key) - BOOST_CHECK(true); - else - BOOST_CHECK(false); -} - -BOOST_AUTO_TEST_CASE(IdentityOperations) -{ - auto pibImpl = make_shared(); - Pib pib("pib-memory", "", pibImpl); - - BOOST_CHECK_THROW(pib.getIdentity(id1), Pib::Error); - Identity identity1 = pib.addIdentity(id1); - BOOST_CHECK_NO_THROW(pib.getIdentity(id1)); - pib.removeIdentity(id1); - BOOST_CHECK_THROW(pib.getIdentity(id1), Pib::Error); - - BOOST_CHECK_THROW(pib.getDefaultIdentity(), Pib::Error); - BOOST_REQUIRE_NO_THROW(pib.setDefaultIdentity(id1)); - BOOST_REQUIRE_NO_THROW(pib.getDefaultIdentity()); - BOOST_CHECK_EQUAL(pib.getDefaultIdentity().getName(), id1); - pib.removeIdentity(id1); - BOOST_CHECK_THROW(pib.getIdentity(id1), Pib::Error); - BOOST_CHECK_THROW(pib.getDefaultIdentity(), Pib::Error); -} - -BOOST_AUTO_TEST_SUITE_END() // TestPib -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/sec-public-info-sqlite3.t.cpp b/tests/unit-tests/security/sec-public-info-sqlite3.t.cpp deleted file mode 100644 index 245babc9d..000000000 --- a/tests/unit-tests/security/sec-public-info-sqlite3.t.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/sec-public-info-sqlite3.hpp" -#include "security/key-chain.hpp" -#include "security/v1/cryptopp.hpp" -#include "encoding/buffer-stream.hpp" -#include "util/time.hpp" - -#include "boost-test.hpp" - -#include -#include - -namespace ndn { -namespace security { -namespace tests { - -class PibTmpPathFixture -{ -public: - PibTmpPathFixture() - { - boost::system::error_code error; - tmpPath = boost::filesystem::temp_directory_path(error); - BOOST_REQUIRE(boost::system::errc::success == error.value()); - tmpPath /= boost::lexical_cast(random::generateWord32()); - } - - ~PibTmpPathFixture() - { - boost::filesystem::remove_all(tmpPath); - } - -public: - boost::filesystem::path tmpPath; -}; - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(TestSecPublicInfoSqlite3) - -const std::string RSA_DER("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuFoDcNtffwbfFix64fw0\ -hI2tKMkFrc6Ex7yw0YLMK9vGE8lXOyBl/qXabow6RCz+GldmFN6E2Qhm1+AX3Zm5\ -sj3H53/HPtzMefvMQ9X7U+lK8eNMWawpRzvBh4/36VrK/awlkNIVIQ9aXj6q6BVe\ -zL+zWT/WYemLq/8A1/hHWiwCtfOH1xQhGqWHJzeSgwIgOOrzxTbRaCjhAb1u2TeV\ -yx/I9H/DV+AqSHCaYbB92HDcDN0kqwSnUf5H1+osE9MR5DLBLhXdSiULSgxT3Or/\ -y2QgsgUK59WrjhlVMPEiHHRs15NZJbL1uQFXjgScdEarohcY3dilqotineFZCeN8\ -DwIDAQAB"); -const std::string ECDSA_DER("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENZpqkPJDj8uhSpffOiCbvSYMLsGB\ -1Eo/WU6mrexjGvduQXjqwon/eSHFI6EgHZk8L9KfiV5XVtVsk2g5wIpJVg=="); - -BOOST_FIXTURE_TEST_CASE(Basic, PibTmpPathFixture) -{ - SecPublicInfoSqlite3 pib(tmpPath.generic_string()); - - BOOST_CHECK(pib.doesTableExist("Identity")); - BOOST_CHECK(pib.doesTableExist("Key")); - BOOST_CHECK(pib.doesTableExist("Certificate")); -} - -BOOST_FIXTURE_TEST_CASE(TpmLocatorTest, PibTmpPathFixture) -{ - SecPublicInfoSqlite3 pib(tmpPath.generic_string()); - - BOOST_REQUIRE_THROW(pib.getTpmLocator(), SecPublicInfo::Error); - pib.addIdentity("/test/id1"); - BOOST_CHECK(pib.doesIdentityExist("/test/id1")); - - // Pib does not have tpmInfo set yet, setTpmInfo simply set the tpmInfo. - std::string tpmLocator("tpm-file:"); - tpmLocator.append((tmpPath / "tpm").generic_string()); - pib.setTpmLocator(tpmLocator); - BOOST_CHECK(pib.doesIdentityExist("/test/id1")); - - BOOST_REQUIRE_NO_THROW(pib.getTpmLocator()); - BOOST_CHECK_EQUAL(tpmLocator, pib.getTpmLocator()); - - // Pib has tpmInfo set, set a different tpmInfo will reset Pib content. - std::string tpmLocator3("tpm-osxkeychain:"); - pib.setTpmLocator(tpmLocator3); - BOOST_CHECK(!pib.doesIdentityExist("/test/id1")); -} - -BOOST_AUTO_TEST_CASE(KeyTypeRsa) -{ - using namespace CryptoPP; - - OBufferStream os; - StringSource ss(reinterpret_cast(RSA_DER.c_str()), RSA_DER.size(), - true, new Base64Decoder(new FileSink(os))); - - shared_ptr rsaKey; - BOOST_REQUIRE_NO_THROW(rsaKey = make_shared(os.buf()->buf(), os.buf()->size())); - Name rsaKeyName("/TestSecPublicInfoSqlite3/KeyType/RSA/ksk-123"); - SecPublicInfoSqlite3 pib; - pib.addKey(rsaKeyName, *rsaKey); - - BOOST_CHECK_EQUAL(KeyType::RSA, pib.getPublicKeyType(rsaKeyName)); - - pib.deleteIdentityInfo(Name("/TestSecPublicInfoSqlite3/KeyType/RSA")); -} - -BOOST_AUTO_TEST_CASE(KeyTypeEcdsa) -{ - using namespace CryptoPP; - - OBufferStream os; - StringSource ss(reinterpret_cast(ECDSA_DER.c_str()), ECDSA_DER.size(), - true, new Base64Decoder(new FileSink(os))); - - shared_ptr ecdsaKey; - BOOST_REQUIRE_NO_THROW(ecdsaKey = make_shared(os.buf()->buf(), os.buf()->size())); - Name ecdsaKeyName("/TestSecPublicInfoSqlite3/KeyType/ECDSA/ksk-123"); - SecPublicInfoSqlite3 pib; - pib.addKey(ecdsaKeyName, *ecdsaKey); - - BOOST_CHECK_EQUAL(KeyType::EC, pib.getPublicKeyType(ecdsaKeyName)); - pib.deleteIdentityInfo(Name("/TestSecPublicInfoSqlite3/KeyType/ECDSA")); -} - -BOOST_AUTO_TEST_CASE(KeyTypeNonExistent) -{ - Name nullKeyName("/TestSecPublicInfoSqlite3/KeyType/Null"); - SecPublicInfoSqlite3 pib; - - BOOST_CHECK_EQUAL(KeyType::NONE, pib.getPublicKeyType(nullKeyName)); -} - -BOOST_AUTO_TEST_SUITE_END() // TestSecPublicInfoSqlite3 -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/sec-rule-relative.t.cpp b/tests/unit-tests/security/sec-rule-relative.t.cpp deleted file mode 100644 index 21f805e4a..000000000 --- a/tests/unit-tests/security/sec-rule-relative.t.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/sec-rule-relative.hpp" -#include "identity-management-fixture.hpp" - -namespace ndn { -namespace security { -namespace tests { - -using namespace ndn::tests; - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_FIXTURE_TEST_SUITE(TestSecRuleRelative, IdentityManagementFixture) - -BOOST_AUTO_TEST_CASE(Basic) -{ - Name rsaIdentity("/SecurityTestSecRule/Basic/Rsa"); - BOOST_REQUIRE(addIdentity(rsaIdentity, RsaKeyParams())); - Name ecdsaIdentity("/SecurityTestSecRule/Basic/Ecdsa"); - BOOST_REQUIRE(addIdentity(ecdsaIdentity, EcdsaKeyParams())); - - Name dataName("SecurityTestSecRule/Basic"); - Data rsaData(dataName); - m_keyChain.sign(rsaData, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - rsaIdentity)); - Data ecdsaData(dataName); - m_keyChain.sign(ecdsaData, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - ecdsaIdentity)); - Data sha256Data(dataName); - m_keyChain.sign(sha256Data, security::SigningInfo(security::SigningInfo::SIGNER_TYPE_SHA256)); - - SecRuleRelative rule("^()$", - "^()<><><>$", - "==", "\\1", "\\1", true); - BOOST_CHECK(rule.satisfy(rsaData)); - BOOST_CHECK(rule.satisfy(ecdsaData)); - BOOST_CHECK_EQUAL(rule.satisfy(sha256Data), false); - - BOOST_CHECK(rule.matchSignerName(rsaData)); - BOOST_CHECK(rule.matchSignerName(ecdsaData)); - BOOST_CHECK_EQUAL(rule.matchSignerName(sha256Data), false); -} - -BOOST_AUTO_TEST_SUITE_END() // TestSecRuleRelative -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/sec-rule-specific.t.cpp b/tests/unit-tests/security/sec-rule-specific.t.cpp deleted file mode 100644 index e69d0eecd..000000000 --- a/tests/unit-tests/security/sec-rule-specific.t.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/sec-rule-specific.hpp" -#include "security/key-chain.hpp" -#include "identity-management-fixture.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace security { -namespace tests { - -using namespace ndn::tests; - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_FIXTURE_TEST_SUITE(TestSecRuleSpecific, IdentityManagementFixture) - -BOOST_AUTO_TEST_CASE(Basic) -{ - Name rsaIdentity("/SecurityTestSecRule/Basic/Rsa"); - BOOST_REQUIRE(addIdentity(rsaIdentity, RsaKeyParams())); - Name ecdsaIdentity("/SecurityTestSecRule/Basic/Ecdsa"); - BOOST_REQUIRE(addIdentity(ecdsaIdentity, EcdsaKeyParams())); - - Name dataName("SecurityTestSecRule/Basic"); - Data rsaData(dataName); - m_keyChain.sign(rsaData, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - rsaIdentity)); - Data ecdsaData(dataName); - m_keyChain.sign(ecdsaData, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - ecdsaIdentity)); - Data sha256Data(dataName); - m_keyChain.sign(sha256Data, security::SigningInfo(security::SigningInfo::SIGNER_TYPE_SHA256)); - - shared_ptr dataRegex = - make_shared("^$"); - shared_ptr signerRegex = - make_shared("^<><><>$"); - - SecRuleSpecific rule(dataRegex, signerRegex); - BOOST_CHECK(rule.satisfy(rsaData)); - BOOST_CHECK(rule.satisfy(ecdsaData)); - BOOST_CHECK_EQUAL(rule.satisfy(sha256Data), false); - - BOOST_CHECK(rule.matchSignerName(rsaData)); - BOOST_CHECK(rule.matchSignerName(ecdsaData)); - BOOST_CHECK_EQUAL(rule.matchSignerName(sha256Data), false); -} - -BOOST_AUTO_TEST_SUITE_END() // TestSecRuleSpecific -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/sec-tpm-file.t.cpp b/tests/unit-tests/security/sec-tpm-file.t.cpp deleted file mode 100644 index 68671e852..000000000 --- a/tests/unit-tests/security/sec-tpm-file.t.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/sec-tpm-file.hpp" -#include "security/key-chain.hpp" -#include "security/v1/cryptopp.hpp" -#include "util/time.hpp" - -#include "boost-test.hpp" - -#include -#include - -namespace ndn { -namespace security { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(TestSecTpmFile) - -BOOST_AUTO_TEST_CASE(Delete) -{ - SecTpmFile tpm; - - Name keyName("/TestSecTpmFile/Delete/ksk-" + - boost::lexical_cast(time::toUnixTimestamp(time::system_clock::now()))); - RsaKeyParams params(2048); - BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params)); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), true); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), true); - - tpm.deleteKeyPairInTpm(keyName); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), false); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), false); -} - -BOOST_AUTO_TEST_CASE(SignVerify) -{ - SecTpmFile tpm; - - Name keyName("/TestSecTpmFile/SignVerify/ksk-" + - boost::lexical_cast(time::toUnixTimestamp(time::system_clock::now()))); - RsaKeyParams params(2048); - BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params)); - - Data data("/tmp/test/1"); - const uint8_t content[] = {0x01, 0x02, 0x03, 0x04}; - - Block sigBlock; - BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content), - keyName, DigestAlgorithm::SHA256)); - shared_ptr publicKey; - BOOST_CHECK_NO_THROW(publicKey = tpm.getPublicKeyFromTpm(keyName)); - - try - { - using namespace CryptoPP; - - RSA::PublicKey rsaPublicKey; - ByteQueue queue; - queue.Put(reinterpret_cast(publicKey->get().buf()), publicKey->get().size()); - rsaPublicKey.Load(queue); - - RSASS::Verifier verifier(rsaPublicKey); - bool result = verifier.VerifyMessage(content, sizeof(content), - sigBlock.value(), sigBlock.value_size()); - - BOOST_CHECK_EQUAL(result, true); - } - catch (CryptoPP::Exception& e) - { - BOOST_CHECK(false); - } - - tpm.deleteKeyPairInTpm(keyName); -} - -BOOST_AUTO_TEST_CASE(RandomGenerator) -{ - SecTpmFile tpm; - - constexpr size_t scale = 1000; - constexpr size_t size = 256 * scale; - auto block = unique_ptr{new uint8_t[size]}; - tpm.generateRandomBlock(block.get(), size); - - std::map counter; - for (size_t i = 0; i < size; i++) { - counter[block[i]] += 1; - } - - double dev = 0.0; - for (uint8_t i = 0; i < 255; i++) { - dev += static_cast((counter[i] - scale) * (counter[i] - scale)) / (scale * scale); - } - dev /= 256; - - BOOST_CHECK_CLOSE(dev, 0.001, 100); -} - -BOOST_AUTO_TEST_CASE(ImportExportKey) -{ - using namespace CryptoPP; - - std::string imported = -"MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIIJzwsbTIVqgCAggAMBQGCCqG" -"SIb3DQMHBAiEsSKdgGkCEQSCBMjaYsEeHM/EPzGNDAPaSxE1ASKxjyNkXEVPQbtGx/ju1PlQ" -"QakTCzPpia8ziVGihrVfuacHrxxbLh+ufNZtbVVsv9kGQL2g15BN2Nic8VqyTxplKrduFkEb" -"eOipqu627gb6eTsrSj7kubXfs/w9OAdhRZFaEc7I/S6rcPUaDai4i3O03VuvuTOrzZL/unhD" -"CDzOa3pr2aUQlO/5Pck6GbSYL1/4aW/fB7djZrZAjsGPTqIYpPa16oWlrzsILQ4650Zlvdn8" -"feh6elTrA4qy6RljZfhIHxzGAeuGbVVLT7zavs01y+QE88sxPpeZ0RGtlVxCYp+xoB5hOO/x" -"Xm3n0r+HVIaBV9rHLuUSUiHVAtzwuOj/XKh7YBNXeF58lcv8Npsx10etrPuV5hRQelYirKo1" -"QbT+Aq7sLdWI09eGClDHjvRgw54lCFEUAVUFLxhBnzfVUfw/UiR2SheixH+c7cY3gOOvSMQh" -"1oL9Omii4S6yhzfbD3hRN/wBKC0NgiIOLRR+Ti0mEEbTxYQrVcHC9rpRcnr1fFAiQvOXrOw0" -"HyxsbnOeYpoURgLJmUyItPi09xUMCHwUPZ/sI6aG5eRqVUGgcYaQib7MBbGG/D2PlWaKZx1w" -"iEYtYUI7rrc7Qc2ltp4i1u46ZLtSOxUi8kM7qK2Yp1AOtcWFlGn0XBXpGsHanZRzs8KzfDjQ" -"OPmRIuFXFmuJweqUGmg6c8P3wHYueenB4oowYELYaDwmmV96obXMG5hbsKne5kcem875d6K+" -"hL2QzjAl+na4tUZyXYXDdUO2lgTT8IItujBn6c+b8vDcZ24NcYyWPHHb16J4uvKi/6Zb245g" -"/N0NC6hB43KE+2F0BH0eyXRzCnen6AjF8nvx/wgYrXsFlsU47P8gaL1e7V6QECkY4vIk6//b" -"LINmpcgZoAv23fgjvYYTMfS/IyPsooS5DJarbHzbsgAWOuqP2ewYulrKqLi0vaUyoErRedQC" -"8J5p9c4KF56++ameiwxbyKnDynHIIFCOM8eamLnDH4VvU9E2mtfZxmi8kWDWx/NhKEK9zbQv" -"WuaGDpOysgPK4myTp2QGQNQDvBB92gMcrVTcY//3OGHSXeJrkUfDKLOUDyz7ROghEt1vpRTL" -"j9Xdbm/01O/0MLBqyXDY119b1qAVVY7Y2CxRIRFdw2V76INWNIwPi46t/VUGwMBGmEux8S8+" -"79Mv7UyGhKvSUr88pWCS1KdSz1HhN1VWjDvyXPyg96+SecpZMwXCdkUCLdLdD3/8rJLt7wS5" -"3K5/1V4sacds8GHx7NckhQ/KV0VDlUEFuaOCS4Sd3XXetXs4IFSqtKH+Rn0jX7d8Igcw7X2b" -"eaV1gxOVquDEwLDT5+wXURw96ahq0caL/4YfoBUQIOQ6HGtPTWJz1Yax0pGu9F30VEY/ObrK" -"L/B6peJKfqhQGJ+MObqOiP6yHBZH75EImLAkksSVmREdNVjwWkz9D9vzPoAnmP8sQ3/NZarB" -"Ak+ynQjc19t+CCecPrS2Tlh0cJZkHRiGFF7J5a3ci7yBvg3HfD86AXMRBQuSG1UG8TrzC6BK" -"+qIQ8DWecQwBMZ3nv/Flo2Fejd/G4/wWe6ObMytC5SB8pJNOq9ri0Ff6Zh3rPrwaSv1PPgFJ" -"GOw="; - - std::string decoded; - BOOST_CHECK_NO_THROW(StringSource source(imported, - true, - new Base64Decoder(new StringSink(decoded)))); - - SecTpmFile tpm; - - Name keyName("/TestSecTpmFile/ImportKey/ksk-" + - boost::lexical_cast(time::toUnixTimestamp(time::system_clock::now()))); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), false); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), false); - - BOOST_REQUIRE_NO_THROW( - tpm.importPrivateKeyPkcs5IntoTpm(keyName, - reinterpret_cast(decoded.c_str()), - decoded.size(), - "1234")); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), true); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), true); - - shared_ptr publicKey; - BOOST_CHECK_NO_THROW(publicKey = tpm.getPublicKeyFromTpm(keyName)); - - const uint8_t content[] = {0x01, 0x02, 0x03, 0x04}; - Block sigBlock; - BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content), - keyName, DigestAlgorithm::SHA256)); - - try - { - using namespace CryptoPP; - - RSA::PublicKey rsaPublicKey; - ByteQueue queue; - queue.Put(reinterpret_cast(publicKey->get().buf()), publicKey->get().size()); - rsaPublicKey.Load(queue); - - RSASS::Verifier verifier(rsaPublicKey); - bool isVerified = verifier.VerifyMessage(content, sizeof(content), - sigBlock.value(), sigBlock.value_size()); - - BOOST_CHECK_EQUAL(isVerified, true); - } - catch (CryptoPP::Exception& e) - { - BOOST_CHECK(false); - } - - ConstBufferPtr exported; - BOOST_CHECK_NO_THROW(exported = tpm.exportPrivateKeyPkcs5FromTpm(keyName, "5678")); - - tpm.deleteKeyPairInTpm(keyName); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), false); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), false); - - BOOST_REQUIRE(tpm.importPrivateKeyPkcs5IntoTpm(keyName, exported->buf(), exported->size(), - "5678")); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), true); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), true); - - const uint8_t content2[] = {0x05, 0x06, 0x07, 0x08}; - Block sigBlock2; - BOOST_CHECK_NO_THROW(sigBlock2 = tpm.signInTpm(content2, sizeof(content2), - keyName, DigestAlgorithm::SHA256)); - - try - { - using namespace CryptoPP; - - RSA::PublicKey rsaPublicKey; - ByteQueue queue; - queue.Put(reinterpret_cast(publicKey->get().buf()), publicKey->get().size()); - rsaPublicKey.Load(queue); - - RSASS::Verifier verifier(rsaPublicKey); - bool isVerified = verifier.VerifyMessage(content2, sizeof(content2), - sigBlock2.value(), sigBlock2.value_size()); - - BOOST_CHECK_EQUAL(isVerified, true); - } - catch (CryptoPP::Exception& e) - { - BOOST_CHECK(false); - } - - tpm.deleteKeyPairInTpm(keyName); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), false); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), false); -} - -BOOST_AUTO_TEST_CASE(EcdsaSigning) -{ - SecTpmFile tpm; - - Name keyName("/TestSecTpmFile/EcdsaSigning/ksk-" + - boost::lexical_cast(time::toUnixTimestamp(time::system_clock::now()))); - EcdsaKeyParams params; - BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params)); - - Data data("/TestSecTpmFile/EcdsaSigning/Data/1"); - const uint8_t content[] = {0x01, 0x02, 0x03, 0x04}; - - Block sigBlock; - BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content), - keyName, DigestAlgorithm::SHA256)); - - shared_ptr pubkeyPtr; - BOOST_CHECK_NO_THROW(pubkeyPtr = tpm.getPublicKeyFromTpm(keyName)); - - try - { - using namespace CryptoPP; - - ECDSA::PublicKey publicKey; - ByteQueue queue; - queue.Put(reinterpret_cast(pubkeyPtr->get().buf()), pubkeyPtr->get().size()); - publicKey.Load(queue); - - uint8_t buffer[64]; - size_t usedSize = DSAConvertSignatureFormat(buffer, 64, DSA_P1363, - sigBlock.value(), sigBlock.value_size(), DSA_DER); - - ECDSA::Verifier verifier(publicKey); - bool result = verifier.VerifyMessage(content, sizeof(content), - buffer, usedSize); - - BOOST_CHECK_EQUAL(result, true); - } - catch (CryptoPP::Exception& e) - { - BOOST_CHECK(false); - } - - tpm.deleteKeyPairInTpm(keyName); -} - - -BOOST_AUTO_TEST_CASE(ImportExportEcdsaKey) -{ - using namespace CryptoPP; - - std::string imported = - "MIGMMEAGCSqGSIb3DQEFDTAzMBsGCSqGSIb3DQEFDDAOBAhqkJiLfzFWtQICCAAw" - "FAYIKoZIhvcNAwcECJ1HLtP8OZC6BEgNv9OH2mZdbkxvqTVlRBkUqPbbP3580OG6" - "f0htqWSRppcb4IEKYfuPt2qPCYKL2GcAN2pU3eJqhiM7LFTSFaxgBRFozzIwusk="; - - std::string decoded; - BOOST_CHECK_NO_THROW(StringSource source(imported, - true, - new Base64Decoder(new StringSink(decoded)))); - - SecTpmFile tpm; - - Name keyName("/TestSecTpmFile/ImportExportEcdsaKey/ksk-" + - boost::lexical_cast(time::toUnixTimestamp(time::system_clock::now()))); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), false); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), false); - - BOOST_REQUIRE_NO_THROW( - tpm.importPrivateKeyPkcs5IntoTpm(keyName, - reinterpret_cast(decoded.c_str()), - decoded.size(), - "5678")); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), true); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), true); - - shared_ptr publicKey; - BOOST_CHECK_NO_THROW(publicKey = tpm.getPublicKeyFromTpm(keyName)); - - const uint8_t content[] = {0x01, 0x02, 0x03, 0x04}; - Block sigBlock; - BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content), - keyName, DigestAlgorithm::SHA256)); - - try - { - using namespace CryptoPP; - - ECDSA::PublicKey ecdsaPublicKey; - ByteQueue queue; - queue.Put(reinterpret_cast(publicKey->get().buf()), publicKey->get().size()); - ecdsaPublicKey.Load(queue); - - uint8_t buffer[64]; - size_t usedSize = DSAConvertSignatureFormat(buffer, 64, DSA_P1363, - sigBlock.value(), sigBlock.value_size(), DSA_DER); - - ECDSA::Verifier verifier(ecdsaPublicKey); - bool isVerified = verifier.VerifyMessage(content, sizeof(content), - buffer, usedSize); - - BOOST_CHECK_EQUAL(isVerified, true); - } - catch (CryptoPP::Exception& e) - { - BOOST_CHECK(false); - } - - ConstBufferPtr exported; - BOOST_CHECK_NO_THROW(exported = tpm.exportPrivateKeyPkcs5FromTpm(keyName, "1234")); - - tpm.deleteKeyPairInTpm(keyName); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), false); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), false); - - BOOST_REQUIRE(tpm.importPrivateKeyPkcs5IntoTpm(keyName, exported->buf(), exported->size(), - "1234")); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), true); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), true); - - const uint8_t content2[] = {0x05, 0x06, 0x07, 0x08}; - Block sigBlock2; - BOOST_CHECK_NO_THROW(sigBlock2 = tpm.signInTpm(content2, sizeof(content2), - keyName, DigestAlgorithm::SHA256)); - - try - { - using namespace CryptoPP; - - ECDSA::PublicKey ecdsaPublicKey; - ByteQueue queue; - queue.Put(reinterpret_cast(publicKey->get().buf()), publicKey->get().size()); - ecdsaPublicKey.Load(queue); - - uint8_t buffer[64]; - size_t usedSize = DSAConvertSignatureFormat(buffer, 64, DSA_P1363, - sigBlock2.value(), sigBlock2.value_size(), - DSA_DER); - - ECDSA::Verifier verifier(ecdsaPublicKey); - bool isVerified = verifier.VerifyMessage(content2, sizeof(content2), - buffer, usedSize); - - BOOST_CHECK_EQUAL(isVerified, true); - - } - catch (CryptoPP::Exception& e) - { - BOOST_CHECK(false); - } - - tpm.deleteKeyPairInTpm(keyName); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), false); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), false); -} - -BOOST_AUTO_TEST_SUITE_END() // TestSecTpmFile -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/sec-tpm-osx.t.cpp b/tests/unit-tests/security/sec-tpm-osx.t.cpp deleted file mode 100644 index 65ea5c3ad..000000000 --- a/tests/unit-tests/security/sec-tpm-osx.t.cpp +++ /dev/null @@ -1,368 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/sec-tpm-osx.hpp" -#include "security/v1/cryptopp.hpp" -#include "util/time.hpp" - -#include "boost-test.hpp" - -#include -#include - -namespace ndn { -namespace security { -namespace tests { - -class OsxKeyChainTestFixture -{ -public: - OsxKeyChainTestFixture() - { - std::string oldHOME; - if (std::getenv("OLD_HOME")) - oldHOME = std::getenv("OLD_HOME"); - - if (std::getenv("HOME")) - m_HOME = std::getenv("HOME"); - - if (!oldHOME.empty()) - setenv("HOME", oldHOME.c_str(), 1); - else - unsetenv("HOME"); - } - - ~OsxKeyChainTestFixture() - { - if (!m_HOME.empty()) - setenv("HOME", m_HOME.c_str(), 1); - else - unsetenv("HOME"); - } - -protected: - std::string m_HOME; -}; - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_FIXTURE_TEST_SUITE(TestSecTpmOsx, OsxKeyChainTestFixture) - -BOOST_AUTO_TEST_CASE(Delete) -{ - SecTpmOsx tpm; - - Name keyName("/TestSecTpmOsx/Delete/ksk-" + - boost::lexical_cast( - time::toUnixTimestamp(time::system_clock::now()).count())); - RsaKeyParams params(2048); - BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params)); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), true); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), true); - - tpm.deleteKeyPairInTpm(keyName); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), false); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), false); -} - -BOOST_AUTO_TEST_CASE(SignVerify) -{ - SecTpmOsx tpm; - - Name keyName("/TestSecTpmOsx/SignVerify/ksk-" + - boost::lexical_cast( - time::toUnixTimestamp(time::system_clock::now()).count())); - RsaKeyParams params(2048); - BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params)); - - Data data("/TestSecTpmOsx/SignVaerify/Data/1"); - const uint8_t content[] = {0x01, 0x02, 0x03, 0x04}; - - Block sigBlock; - BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content), - keyName, DigestAlgorithm::SHA256)); - - shared_ptr publicKey; - BOOST_CHECK_NO_THROW(publicKey = tpm.getPublicKeyFromTpm(keyName)); - try - { - using namespace CryptoPP; - - RSA::PublicKey rsaPublicKey; - ByteQueue queue; - queue.Put(reinterpret_cast(publicKey->get().buf()), publicKey->get().size()); - rsaPublicKey.Load(queue); - - RSASS::Verifier verifier(rsaPublicKey); - bool isVerified = verifier.VerifyMessage(content, sizeof(content), - sigBlock.value(), sigBlock.value_size()); - - BOOST_CHECK_EQUAL(isVerified, true); - } - catch (CryptoPP::Exception& e) - { - BOOST_CHECK(false); - } - - tpm.deleteKeyPairInTpm(keyName); -} - -BOOST_AUTO_TEST_CASE(RandomGenerator) -{ - SecTpmOsx tpm; - - size_t scale = 1000; - size_t size = 256 * scale; - uint8_t* block = new uint8_t[size]; - tpm.generateRandomBlock(block, size); - - std::map counter; - for (size_t i = 0; i < size; i++) - { - counter[block[i]] += 1; - } - - float dev = 0.0; - for (size_t i = 0; i != 255; i++) - { - dev += ((counter[i] - scale) * (counter[i] - scale)) * 1.0 / (scale * scale); - } - - BOOST_CHECK_CLOSE(dev / 256, 0.001, 100); - -} - -BOOST_AUTO_TEST_CASE(ExportImportKey) -{ - using namespace CryptoPP; - - SecTpmOsx tpm; - - Name keyName("/TestSecTpmOsx/ExportImportKey/ksk-" + - boost::lexical_cast( - time::toUnixTimestamp(time::system_clock::now()).count())); - - RsaKeyParams params(2048); - BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params)); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), true); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), true); - - ConstBufferPtr exported; - BOOST_CHECK_NO_THROW(exported = tpm.exportPrivateKeyPkcs5FromTpm(keyName, "1234")); - shared_ptr publicKey; - BOOST_REQUIRE_NO_THROW(publicKey = tpm.getPublicKeyFromTpm(keyName)); - - tpm.deleteKeyPairInTpm(keyName); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), false); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), false); - - BOOST_REQUIRE(tpm.importPrivateKeyPkcs5IntoTpm(keyName, - exported->buf(), exported->size(), - "1234")); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), true); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), true); - - const uint8_t content[] = {0x01, 0x02, 0x03, 0x04}; - Block sigBlock; - BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content), - keyName, DigestAlgorithm::SHA256)); - - try - { - using namespace CryptoPP; - - RSA::PublicKey rsaPublicKey; - ByteQueue queue; - queue.Put(reinterpret_cast(publicKey->get().buf()), publicKey->get().size()); - rsaPublicKey.Load(queue); - - RSASS::Verifier verifier(rsaPublicKey); - bool isVerified = verifier.VerifyMessage(content, sizeof(content), - sigBlock.value(), sigBlock.value_size()); - - BOOST_CHECK_EQUAL(isVerified, true); - } - catch (CryptoPP::Exception& e) - { - BOOST_CHECK(false); - } - - tpm.deleteKeyPairInTpm(keyName); - // This is some problem related to Mac OS Key chain. - // On OSX 10.8, we cannot delete imported keys, but there is no such problem on OSX 10.9. -#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED -#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_9 - BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE) == false); - BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC) == false); -#endif -#endif -} - -BOOST_AUTO_TEST_CASE(NonExistingKey) -{ - using namespace CryptoPP; - - SecTpmOsx tpm; - - Name keyName("/TestSecTpmOsx/NonExistingKey"); - - BOOST_REQUIRE_THROW(tpm.getPublicKeyFromTpm(keyName), SecTpmOsx::Error); - - const uint8_t content[] = {0x01, 0x02, 0x03, 0x04}; - BOOST_REQUIRE_THROW(tpm.signInTpm(content, sizeof(content), keyName, DigestAlgorithm::SHA256), - SecTpmOsx::Error); - - BOOST_REQUIRE_THROW(tpm.signInTpm(0, 1, keyName, DigestAlgorithm::SHA256), - SecTpmOsx::Error); -} - -BOOST_AUTO_TEST_CASE(EcdsaSigning) -{ - SecTpmOsx tpm; - - Name keyName("/TestSecTpmOsx/EcdsaSigning/ksk-" + - boost::lexical_cast(time::toUnixTimestamp(time::system_clock::now()))); - EcdsaKeyParams params; - BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params)); - - Data data("/TestSecTpmOsx/EcdsaSigning/Data/1"); - const uint8_t content[] = {0x01, 0x02, 0x03, 0x04}; - - Block sigBlock; - BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content), - keyName, DigestAlgorithm::SHA256)); - - shared_ptr pubkeyPtr; - BOOST_CHECK_NO_THROW(pubkeyPtr = tpm.getPublicKeyFromTpm(keyName)); - - try - { - using namespace CryptoPP; - - ECDSA::PublicKey publicKey; - ByteQueue queue; - queue.Put(reinterpret_cast(pubkeyPtr->get().buf()), pubkeyPtr->get().size()); - publicKey.Load(queue); - - uint8_t buffer[64]; - size_t usedSize = DSAConvertSignatureFormat(buffer, 64, DSA_P1363, - sigBlock.value(), sigBlock.value_size(), DSA_DER); - - ECDSA::Verifier verifier(publicKey); - bool result = verifier.VerifyMessage(content, sizeof(content), - buffer, usedSize); - - BOOST_CHECK_EQUAL(result, true); - } - catch (CryptoPP::Exception& e) - { - BOOST_CHECK(false); - } - - tpm.deleteKeyPairInTpm(keyName); -} - - -BOOST_AUTO_TEST_CASE(ExportImportEcdsaKey) -{ - using namespace CryptoPP; - - SecTpmOsx tpm; - - Name keyName("/TestSecTpmOsx/ExportImportEcdsaKey/ksk-" + - boost::lexical_cast( - time::toUnixTimestamp(time::system_clock::now()).count())); - - EcdsaKeyParams params; - BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params)); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), true); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), true); - - ConstBufferPtr exported; - BOOST_CHECK_NO_THROW(exported = tpm.exportPrivateKeyPkcs5FromTpm(keyName, "1234")); - - shared_ptr publicKey; - BOOST_REQUIRE_NO_THROW(publicKey = tpm.getPublicKeyFromTpm(keyName)); - - tpm.deleteKeyPairInTpm(keyName); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), false); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), false); - - BOOST_REQUIRE(tpm.importPrivateKeyPkcs5IntoTpm(keyName, - exported->buf(), exported->size(), - "1234")); - - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC), true); - BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE), true); - - const uint8_t content[] = {0x01, 0x02, 0x03, 0x04}; - Block sigBlock; - BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content), - keyName, DigestAlgorithm::SHA256)); - - try - { - using namespace CryptoPP; - - ECDSA::PublicKey ecdsaPublicKey; - ByteQueue queue; - queue.Put(reinterpret_cast(publicKey->get().buf()), publicKey->get().size()); - ecdsaPublicKey.Load(queue); - - uint8_t buffer[64]; - size_t usedSize = DSAConvertSignatureFormat(buffer, 64, DSA_P1363, - sigBlock.value(), sigBlock.value_size(), - DSA_DER); - - ECDSA::Verifier verifier(ecdsaPublicKey); - bool isVerified = verifier.VerifyMessage(content, sizeof(content), - buffer, usedSize); - - BOOST_CHECK_EQUAL(isVerified, true); - } - catch (CryptoPP::Exception& e) - { - BOOST_CHECK(false); - } - - tpm.deleteKeyPairInTpm(keyName); - // This is some problem related to Mac OS Key chain. - // On OSX 10.8, we cannot delete imported keys, but there is no such problem on OSX 10.9. -#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED -#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_9 - BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KeyClass::PRIVATE) == false); - BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KeyClass::PUBLIC) == false); -#endif -#endif -} - -BOOST_AUTO_TEST_SUITE_END() // TestSecTpmOsx -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/signature-sha256-with-ecdsa.t.cpp b/tests/unit-tests/security/signature-sha256-with-ecdsa.t.cpp deleted file mode 100644 index 448734b06..000000000 --- a/tests/unit-tests/security/signature-sha256-with-ecdsa.t.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/signature-sha256-with-ecdsa.hpp" -#include "security/key-chain.hpp" -#include "security/validator.hpp" -#include "util/scheduler.hpp" - -#include "boost-test.hpp" -#include "../identity-management-time-fixture.hpp" - -namespace ndn { -namespace tests { - -class SignatureSha256EcdsaTimeFixture : public IdentityManagementTimeFixture -{ -public: - SignatureSha256EcdsaTimeFixture() - : scheduler(io) - { - } - -public: - Scheduler scheduler; -}; - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_FIXTURE_TEST_SUITE(TestSignatureSha256WithEcdsa, SignatureSha256EcdsaTimeFixture) - -const uint8_t sigInfo[] = { -0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x03, - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72 -}; - -const uint8_t sigValue[] = { -0x17, 0x40, // SignatureValue - 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, - 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, - 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, - 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, - 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b -}; - - -BOOST_AUTO_TEST_CASE(Decoding) -{ - Block sigInfoBlock(sigInfo, sizeof(sigInfo)); - Block sigValueBlock(sigValue, sizeof(sigValue)); - - Signature sig(sigInfoBlock, sigValueBlock); - BOOST_CHECK_NO_THROW(SignatureSha256WithEcdsa(sig)); - BOOST_CHECK_NO_THROW(sig.getKeyLocator()); -} - -BOOST_AUTO_TEST_CASE(Encoding) -{ - Name name("/test/key/locator"); - KeyLocator keyLocator(name); - - SignatureSha256WithEcdsa sig(keyLocator); - - BOOST_CHECK_NO_THROW(sig.getKeyLocator()); - - const Block& encodeSigInfoBlock = sig.getInfo(); - - Block sigInfoBlock(sigInfo, sizeof(sigInfo)); - - BOOST_CHECK_EQUAL_COLLECTIONS(sigInfoBlock.wire(), - sigInfoBlock.wire() + sigInfoBlock.size(), - encodeSigInfoBlock.wire(), - encodeSigInfoBlock.wire() + encodeSigInfoBlock.size()); - - sig.setKeyLocator(Name("/test/another/key/locator")); - - const Block& encodeSigInfoBlock2 = sig.getInfo(); - BOOST_CHECK(sigInfoBlock != encodeSigInfoBlock2); -} - -BOOST_AUTO_TEST_CASE(DataSignature) -{ - Name identityName("/SecurityTestSignatureSha256WithEcdsa/DataSignature"); - BOOST_REQUIRE(addIdentity(identityName, EcdsaKeyParams())); - shared_ptr publicKey; - BOOST_REQUIRE_NO_THROW(publicKey = m_keyChain.getPublicKeyFromTpm( - m_keyChain.getDefaultKeyNameForIdentity(identityName))); - - Data testData("/SecurityTestSignatureSha256WithEcdsa/DataSignature/Data1"); - char content[5] = "1234"; - testData.setContent(reinterpret_cast(content), 5); - BOOST_CHECK_NO_THROW(m_keyChain.sign(testData, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identityName))); - Block dataBlock(testData.wireEncode().wire(), testData.wireEncode().size()); - - Data testData2; - testData2.wireDecode(dataBlock); - BOOST_CHECK(Validator::verifySignature(testData2, *publicKey)); -} - -BOOST_AUTO_TEST_CASE(InterestSignature) -{ - Name identityName("/SecurityTestSignatureSha256WithEcdsa/InterestSignature"); - BOOST_REQUIRE(addIdentity(identityName, EcdsaKeyParams())); - shared_ptr publicKey; - BOOST_REQUIRE_NO_THROW(publicKey = m_keyChain.getPublicKeyFromTpm( - m_keyChain.getDefaultKeyNameForIdentity(identityName))); - - - Interest interest("/SecurityTestSignatureSha256WithEcdsa/InterestSignature/Interest1"); - Interest interest11("/SecurityTestSignatureSha256WithEcdsa/InterestSignature/Interest1"); - - scheduler.scheduleEvent(time::milliseconds(100), [&] { - BOOST_CHECK_NO_THROW(m_keyChain.sign(interest, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identityName))); - }); - - advanceClocks(time::milliseconds(100)); - scheduler.scheduleEvent(time::milliseconds(100), [&] { - BOOST_CHECK_NO_THROW(m_keyChain.sign(interest11, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identityName))); - }); - - advanceClocks(time::milliseconds(100)); - - time::system_clock::TimePoint timestamp1 = - time::fromUnixTimestamp( - time::milliseconds(interest.getName().get(signed_interest::POS_TIMESTAMP).toNumber())); - - time::system_clock::TimePoint timestamp2 = - time::fromUnixTimestamp( - time::milliseconds(interest11.getName().get(signed_interest::POS_TIMESTAMP).toNumber())); - - BOOST_CHECK_EQUAL(time::milliseconds(100), (timestamp2 - timestamp1)); - - uint64_t nonce1 = interest.getName().get(signed_interest::POS_RANDOM_VAL).toNumber(); - uint64_t nonce2 = interest11.getName().get(signed_interest::POS_RANDOM_VAL).toNumber(); - BOOST_WARN_NE(nonce1, nonce2); - - Block interestBlock(interest.wireEncode().wire(), interest.wireEncode().size()); - - Interest interest2; - interest2.wireDecode(interestBlock); - BOOST_CHECK(Validator::verifySignature(interest2, *publicKey)); -} - -BOOST_AUTO_TEST_SUITE_END() // TestSignatureSha256WithEcdsa -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/security/signature-sha256-with-rsa.t.cpp b/tests/unit-tests/security/signature-sha256-with-rsa.t.cpp deleted file mode 100644 index 75fc6be36..000000000 --- a/tests/unit-tests/security/signature-sha256-with-rsa.t.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/signature-sha256-with-rsa.hpp" -#include "security/key-chain.hpp" -#include "security/validator.hpp" -#include "util/scheduler.hpp" - -#include "boost-test.hpp" -#include "../identity-management-time-fixture.hpp" - -namespace ndn { -namespace tests { - -class SignatureSha256RsaTimeFixture : public IdentityManagementTimeFixture -{ -public: - SignatureSha256RsaTimeFixture() - : scheduler(io) - { - } - -public: - Scheduler scheduler; -}; - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_FIXTURE_TEST_SUITE(TestSignatureSha256WithRsa, SignatureSha256RsaTimeFixture) - -const uint8_t sigInfo[] = { -0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x01, - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72 -}; - -const uint8_t sigValue[] = { -0x17, 0x80, // SignatureValue - 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, - 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, - 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, - 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, - 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, - 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, - 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, - 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, - 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, - 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1 -}; - - -BOOST_AUTO_TEST_CASE(Decoding) -{ - Block sigInfoBlock(sigInfo, sizeof(sigInfo)); - Block sigValueBlock(sigValue, sizeof(sigValue)); - - Signature sig(sigInfoBlock, sigValueBlock); - BOOST_CHECK_NO_THROW(SignatureSha256WithRsa(sig)); - BOOST_CHECK_NO_THROW(sig.getKeyLocator()); -} - -BOOST_AUTO_TEST_CASE(Encoding) -{ - Name name("/test/key/locator"); - KeyLocator keyLocator(name); - - SignatureSha256WithRsa sig(keyLocator); - - BOOST_CHECK_NO_THROW(sig.getKeyLocator()); - - const Block& encodeSigInfoBlock = sig.getInfo(); - - Block sigInfoBlock(sigInfo, sizeof(sigInfo)); - - BOOST_CHECK_EQUAL_COLLECTIONS(sigInfoBlock.wire(), - sigInfoBlock.wire() + sigInfoBlock.size(), - encodeSigInfoBlock.wire(), - encodeSigInfoBlock.wire() + encodeSigInfoBlock.size()); - - sig.setKeyLocator(Name("/test/another/key/locator")); - - const Block& encodeSigInfoBlock2 = sig.getInfo(); - BOOST_CHECK(sigInfoBlock != encodeSigInfoBlock2); -} - -BOOST_AUTO_TEST_CASE(DataSignature) -{ - Name identityName("/SecurityTestSignatureSha256WithRsa/DataSignature"); - BOOST_REQUIRE(addIdentity(identityName, RsaKeyParams())); - shared_ptr publicKey; - BOOST_REQUIRE_NO_THROW(publicKey = m_keyChain.getPublicKeyFromTpm( - m_keyChain.getDefaultKeyNameForIdentity(identityName))); - - Data testData("/SecurityTestSignatureSha256WithRsa/DataSignature/Data1"); - char content[5] = "1234"; - testData.setContent(reinterpret_cast(content), 5); - BOOST_CHECK_NO_THROW(m_keyChain.sign(testData, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identityName))); - Block dataBlock(testData.wireEncode().wire(), testData.wireEncode().size()); - - Data testData2; - testData2.wireDecode(dataBlock); - BOOST_CHECK(Validator::verifySignature(testData2, *publicKey)); -} - -BOOST_AUTO_TEST_CASE(InterestSignature) -{ - Name identityName("/SecurityTestSignatureSha256WithRsa/InterestSignature"); - BOOST_REQUIRE(addIdentity(identityName, RsaKeyParams())); - shared_ptr publicKey; - BOOST_REQUIRE_NO_THROW(publicKey = m_keyChain.getPublicKeyFromTpm( - m_keyChain.getDefaultKeyNameForIdentity(identityName))); - - Interest interest("/SecurityTestSignatureSha256WithRsa/InterestSignature/Interest1"); - Interest interest11("/SecurityTestSignatureSha256WithRsa/InterestSignature/Interest1"); - - scheduler.scheduleEvent(time::milliseconds(100), [&] { - BOOST_CHECK_NO_THROW(m_keyChain.sign(interest, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identityName))); - }); - - advanceClocks(time::milliseconds(100)); - scheduler.scheduleEvent(time::milliseconds(100), [&] { - BOOST_CHECK_NO_THROW(m_keyChain.sign(interest11, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identityName))); - }); - - advanceClocks(time::milliseconds(100)); - - time::system_clock::TimePoint timestamp1 = - time::fromUnixTimestamp( - time::milliseconds(interest.getName().get(signed_interest::POS_TIMESTAMP).toNumber())); - - time::system_clock::TimePoint timestamp2 = - time::fromUnixTimestamp( - time::milliseconds(interest11.getName().get(signed_interest::POS_TIMESTAMP).toNumber())); - - BOOST_CHECK_EQUAL(time::milliseconds(100), (timestamp2 - timestamp1)); - - uint64_t nonce1 = interest.getName().get(signed_interest::POS_RANDOM_VAL).toNumber(); - uint64_t nonce2 = interest11.getName().get(signed_interest::POS_RANDOM_VAL).toNumber(); - BOOST_WARN_NE(nonce1, nonce2); - - Block interestBlock(interest.wireEncode().wire(), interest.wireEncode().size()); - - Interest interest2; - interest2.wireDecode(interestBlock); - BOOST_CHECK(Validator::verifySignature(interest2, *publicKey)); -} - -BOOST_AUTO_TEST_SUITE_END() // TestSignatureSha256WithRsa -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/security/signing-info.t.cpp b/tests/unit-tests/security/signing-info.t.cpp deleted file mode 100644 index e7e1447ea..000000000 --- a/tests/unit-tests/security/signing-info.t.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/signing-info.hpp" -#include "security/key-chain.hpp" - -#include "boost-test.hpp" - -#include -#include - -namespace ndn { -namespace security { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(TestSigningInfo) - -BOOST_AUTO_TEST_CASE(Basic) -{ - Name id("/my-identity"); - Name key("/my-key"); - Name cert("/my-cert"); - - SigningInfo info; - - BOOST_CHECK_EQUAL(info.getSignerType(), SigningInfo::SIGNER_TYPE_NULL); - BOOST_CHECK_EQUAL(info.getSignerName(), SigningInfo::EMPTY_NAME); - BOOST_CHECK_EQUAL(info.getDigestAlgorithm(), DigestAlgorithm::SHA256); - - const SignatureInfo& sigInfo = info.getSignatureInfo(); - BOOST_CHECK_EQUAL(sigInfo.getSignatureType(), -1); - BOOST_CHECK_EQUAL(sigInfo.hasKeyLocator(), false); - - info.setSigningIdentity(id); - BOOST_CHECK_EQUAL(info.getSignerType(), SigningInfo::SIGNER_TYPE_ID); - BOOST_CHECK_EQUAL(info.getSignerName(), id); - BOOST_CHECK_EQUAL(info.getDigestAlgorithm(), DigestAlgorithm::SHA256); - - SigningInfo infoId(SigningInfo::SIGNER_TYPE_ID, id); - BOOST_CHECK_EQUAL(infoId.getSignerType(), SigningInfo::SIGNER_TYPE_ID); - BOOST_CHECK_EQUAL(infoId.getSignerName(), id); - BOOST_CHECK_EQUAL(infoId.getDigestAlgorithm(), DigestAlgorithm::SHA256); - - info.setSigningKeyName(key); - BOOST_CHECK_EQUAL(info.getSignerType(), SigningInfo::SIGNER_TYPE_KEY); - BOOST_CHECK_EQUAL(info.getSignerName(), key); - BOOST_CHECK_EQUAL(info.getDigestAlgorithm(), DigestAlgorithm::SHA256); - - SigningInfo infoKey(SigningInfo::SIGNER_TYPE_KEY, key); - BOOST_CHECK_EQUAL(infoKey.getSignerType(), SigningInfo::SIGNER_TYPE_KEY); - BOOST_CHECK_EQUAL(infoKey.getSignerName(), key); - BOOST_CHECK_EQUAL(infoKey.getDigestAlgorithm(), DigestAlgorithm::SHA256); - - info.setSigningCertName(cert); - BOOST_CHECK_EQUAL(info.getSignerType(), SigningInfo::SIGNER_TYPE_CERT); - BOOST_CHECK_EQUAL(info.getSignerName(), cert); - BOOST_CHECK_EQUAL(info.getDigestAlgorithm(), DigestAlgorithm::SHA256); - - SigningInfo infoCert(SigningInfo::SIGNER_TYPE_CERT, cert); - BOOST_CHECK_EQUAL(infoCert.getSignerType(), SigningInfo::SIGNER_TYPE_CERT); - BOOST_CHECK_EQUAL(infoCert.getSignerName(), cert); - BOOST_CHECK_EQUAL(infoCert.getDigestAlgorithm(), DigestAlgorithm::SHA256); - - info.setSha256Signing(); - BOOST_CHECK_EQUAL(info.getSignerType(), SigningInfo::SIGNER_TYPE_SHA256); - BOOST_CHECK_EQUAL(info.getSignerName(), SigningInfo::EMPTY_NAME); - BOOST_CHECK_EQUAL(info.getDigestAlgorithm(), DigestAlgorithm::SHA256); - - SigningInfo infoSha(SigningInfo::SIGNER_TYPE_SHA256); - BOOST_CHECK_EQUAL(infoSha.getSignerType(), SigningInfo::SIGNER_TYPE_SHA256); - BOOST_CHECK_EQUAL(infoSha.getSignerName(), SigningInfo::EMPTY_NAME); - BOOST_CHECK_EQUAL(infoSha.getDigestAlgorithm(), DigestAlgorithm::SHA256); -} - -BOOST_AUTO_TEST_CASE(CustomSignatureInfo) -{ - SigningInfo info1; - BOOST_CHECK(info1.getSignatureInfo() == SignatureInfo()); - - SignatureInfo si; - si.setKeyLocator(Name("ndn:/test/key/locator")); - info1.setSignatureInfo(si); - - BOOST_CHECK(info1.getSignatureInfo() == si); - - SigningInfo info2(SigningInfo::SIGNER_TYPE_NULL, SigningInfo::EMPTY_NAME, si); - BOOST_CHECK(info2.getSignatureInfo() == si); -} - -BOOST_AUTO_TEST_CASE(FromString) -{ - SigningInfo infoDefault(""); - BOOST_CHECK_EQUAL(infoDefault.getSignerType(), SigningInfo::SIGNER_TYPE_NULL); - BOOST_CHECK_EQUAL(infoDefault.getSignerName(), SigningInfo::EMPTY_NAME); - BOOST_CHECK_EQUAL(infoDefault.getDigestAlgorithm(), DigestAlgorithm::SHA256); - - SigningInfo infoId("id:/my-identity"); - BOOST_CHECK_EQUAL(infoId.getSignerType(), SigningInfo::SIGNER_TYPE_ID); - BOOST_CHECK_EQUAL(infoId.getSignerName(), "/my-identity"); - BOOST_CHECK_EQUAL(infoId.getDigestAlgorithm(), DigestAlgorithm::SHA256); - - SigningInfo infoKey("key:/my-key"); - BOOST_CHECK_EQUAL(infoKey.getSignerType(), SigningInfo::SIGNER_TYPE_KEY); - BOOST_CHECK_EQUAL(infoKey.getSignerName(), "/my-key"); - BOOST_CHECK_EQUAL(infoKey.getDigestAlgorithm(), DigestAlgorithm::SHA256); - - SigningInfo infoCert("cert:/my-cert"); - BOOST_CHECK_EQUAL(infoCert.getSignerType(), SigningInfo::SIGNER_TYPE_CERT); - BOOST_CHECK_EQUAL(infoCert.getSignerName(), "/my-cert"); - BOOST_CHECK_EQUAL(infoCert.getDigestAlgorithm(), DigestAlgorithm::SHA256); - - SigningInfo infoSha("id:/localhost/identity/digest-sha256"); - BOOST_CHECK_EQUAL(infoSha.getSignerType(), SigningInfo::SIGNER_TYPE_SHA256); - BOOST_CHECK_EQUAL(infoSha.getSignerName(), SigningInfo::EMPTY_NAME); - BOOST_CHECK_EQUAL(infoSha.getDigestAlgorithm(), DigestAlgorithm::SHA256); -} - -BOOST_AUTO_TEST_CASE(ToString) -{ - // We can't use lexical_cast due to Boost Bug 6298. - std::stringstream ss; - ss << SigningInfo(); - BOOST_CHECK_EQUAL(ss.str(), ""); - - BOOST_CHECK_EQUAL(boost::lexical_cast( - SigningInfo(SigningInfo::SIGNER_TYPE_ID, "/my-identity")), "id:/my-identity"); - BOOST_CHECK_EQUAL(boost::lexical_cast( - SigningInfo(SigningInfo::SIGNER_TYPE_KEY, "/my-key")), "key:/my-key"); - BOOST_CHECK_EQUAL(boost::lexical_cast( - SigningInfo(SigningInfo::SIGNER_TYPE_CERT, "/my-cert")), "cert:/my-cert"); - BOOST_CHECK_EQUAL(boost::lexical_cast( - SigningInfo(SigningInfo::SIGNER_TYPE_SHA256)), - "id:/localhost/identity/digest-sha256"); -} - -BOOST_AUTO_TEST_SUITE_END() // TestSigningInfo -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/transform/block-cipher.t.cpp b/tests/unit-tests/security/transform/block-cipher.t.cpp deleted file mode 100644 index 82f5d393c..000000000 --- a/tests/unit-tests/security/transform/block-cipher.t.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/transform/block-cipher.hpp" -#include "security/transform/buffer-source.hpp" -#include "security/transform/stream-sink.hpp" -#include "encoding/buffer-stream.hpp" -#include - -#include "boost-test.hpp" - -namespace ndn { -namespace security { -namespace transform { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(Transform) -BOOST_AUTO_TEST_SUITE(TestBlockCipher) - -BOOST_AUTO_TEST_CASE(AesCbc) -{ - uint8_t key[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - - uint8_t plainText[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - - uint8_t iv[] = { - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 - }; - - /* - * Cipher text can be generated using: - * - * { - * using namespace CryptoPP; - * CBC_Mode::Encryption aes(key, sizeof(key), iv); - * StringSource(plainText, sizeof(plainText), true, - * new StreamTransformationFilter(aes, - * new HexEncoder(new FileSink(std::cerr), false))); - * } - */ - uint8_t cipherText[] = { - 0x07, 0x4d, 0x32, 0x68, 0xc3, 0x40, 0x64, 0x43, - 0x1e, 0x66, 0x4c, 0x25, 0x66, 0x42, 0x0f, 0x59, - 0x0a, 0x51, 0x19, 0x07, 0x67, 0x5c, 0x0e, 0xfa, - 0xa6, 0x8c, 0xbb, 0xaf, 0xfd, 0xea, 0x47, 0xd4, - 0xc7, 0x2c, 0x12, 0x34, 0x79, 0xde, 0xec, 0xc8, - 0x75, 0x33, 0x8f, 0x6b, 0xd6, 0x55, 0xf3, 0xfa - }; - - // encrypt - OBufferStream os; - bufferSource(plainText, sizeof(plainText)) >> - blockCipher(BlockCipherAlgorithm::AES_CBC, - CipherOperator::ENCRYPT, - key, sizeof(key), iv, sizeof(iv)) >> streamSink(os); - - ConstBufferPtr buf = os.buf(); - BOOST_CHECK_EQUAL_COLLECTIONS(cipherText, cipherText + sizeof(cipherText), - buf->begin(), buf->end()); - - // decrypt - OBufferStream os2; - bufferSource(cipherText, sizeof(cipherText)) >> - blockCipher(BlockCipherAlgorithm::AES_CBC, - CipherOperator::DECRYPT, - key, sizeof(key), iv, sizeof(iv)) >> streamSink(os2); - - ConstBufferPtr buf2 = os2.buf(); - BOOST_CHECK_EQUAL_COLLECTIONS(plainText, plainText + sizeof(plainText), - buf2->begin(), buf2->end()); -} - -BOOST_AUTO_TEST_SUITE_END() // TestBlockCipher -BOOST_AUTO_TEST_SUITE_END() // Transform -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace transform -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/transform/digest-filter.t.cpp b/tests/unit-tests/security/transform/digest-filter.t.cpp deleted file mode 100644 index c6e296fba..000000000 --- a/tests/unit-tests/security/transform/digest-filter.t.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/transform/buffer-source.hpp" -#include "security/transform/step-source.hpp" -#include "security/transform/digest-filter.hpp" -#include "security/transform/stream-sink.hpp" -#include "encoding/buffer-stream.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace security { -namespace transform { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(Transform) -BOOST_AUTO_TEST_SUITE(TestDigestFilter) - -BOOST_AUTO_TEST_CASE(Basic) -{ - uint8_t in[128] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - - uint8_t out[] = { - 0x3e, 0x14, 0xfd, 0x66, 0x9a, 0x79, 0x80, 0x65, - 0xc4, 0x0d, 0x61, 0xf8, 0x6a, 0xc7, 0x98, 0x29, - 0xc0, 0x6b, 0x90, 0x8f, 0xbb, 0x19, 0xa0, 0x85, - 0xf7, 0xfa, 0x7b, 0x2d, 0xd6, 0x8c, 0xd5, 0xa3 - }; - - OBufferStream os; - bufferSource(in, sizeof(in)) >> digestFilter(DigestAlgorithm::SHA256) >> streamSink(os); - - ConstBufferPtr buf = os.buf(); - BOOST_CHECK_EQUAL_COLLECTIONS(out, out + sizeof(out), buf->begin(), buf->end()); -} - -BOOST_AUTO_TEST_CASE(StepByStep) -{ - uint8_t in[128] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - - uint8_t out[] = { - 0x3e, 0x14, 0xfd, 0x66, 0x9a, 0x79, 0x80, 0x65, - 0xc4, 0x0d, 0x61, 0xf8, 0x6a, 0xc7, 0x98, 0x29, - 0xc0, 0x6b, 0x90, 0x8f, 0xbb, 0x19, 0xa0, 0x85, - 0xf7, 0xfa, 0x7b, 0x2d, 0xd6, 0x8c, 0xd5, 0xa3 - }; - - StepSource source; - OBufferStream os; - source >> digestFilter(DigestAlgorithm::SHA256) >> streamSink(os); - source.write(in, 32); - source.write(in + 32, 1); - source.write(in + 33, 2); - source.write(in + 35, 3); - source.write(in + 38, 26); - source.write(in + 64, 64); - source.end(); - - ConstBufferPtr buf = os.buf(); - BOOST_CHECK_EQUAL_COLLECTIONS(out, out + sizeof(out), buf->begin(), buf->end()); -} - -BOOST_AUTO_TEST_CASE(EmptyInput) -{ - uint8_t out[] = { - 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, - 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, - 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, - 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 - }; - - OBufferStream os; - StepSource source; - source >> digestFilter(DigestAlgorithm::SHA256) >> streamSink(os); - source.end(); - - ConstBufferPtr buf = os.buf(); - BOOST_CHECK_EQUAL_COLLECTIONS(out, out + sizeof(out), buf->begin(), buf->end()); -} - -BOOST_AUTO_TEST_CASE(Error) -{ - OBufferStream os; - BOOST_REQUIRE_THROW(stepSource() >> digestFilter(DigestAlgorithm::NONE) >> streamSink(os), - transform::Error); -} - -BOOST_AUTO_TEST_SUITE_END() // TestDigestFilter -BOOST_AUTO_TEST_SUITE_END() // Transform -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace transform -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/transform/hmac-filter.t.cpp b/tests/unit-tests/security/transform/hmac-filter.t.cpp deleted file mode 100644 index ccb5feb0e..000000000 --- a/tests/unit-tests/security/transform/hmac-filter.t.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/transform/buffer-source.hpp" -#include "security/transform/step-source.hpp" -#include "security/transform/hmac-filter.hpp" -#include "security/transform/stream-sink.hpp" -#include "encoding/buffer-stream.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace security { -namespace transform { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(Transform) -BOOST_AUTO_TEST_SUITE(TestHmacFilter) - -BOOST_AUTO_TEST_CASE(Basic) -{ - uint8_t key[16] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - - uint8_t data[16] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - - uint8_t digest[32] = { - 0x9f, 0x3a, 0xa2, 0x88, 0x26, 0xb3, 0x74, 0x85, - 0xca, 0x05, 0x01, 0x4d, 0x71, 0x42, 0xb3, 0xea, - 0x3f, 0xfb, 0xda, 0x5a, 0x35, 0xbf, 0xd2, 0x0f, - 0x2f, 0x9c, 0x8f, 0xcc, 0x6d, 0x30, 0x48, 0x54 - }; - - OBufferStream os; - bufferSource(data, sizeof(data)) >> hmacFilter(DigestAlgorithm::SHA256, key, sizeof(key)) >> streamSink(os); - - ConstBufferPtr buf = os.buf(); - BOOST_CHECK_EQUAL_COLLECTIONS(digest, digest + sizeof(digest), buf->begin(), buf->end()); -} - -BOOST_AUTO_TEST_CASE(StepByStep) -{ - uint8_t key[16] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - - uint8_t data[16] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - - uint8_t digest[32] = { - 0x9f, 0x3a, 0xa2, 0x88, 0x26, 0xb3, 0x74, 0x85, - 0xca, 0x05, 0x01, 0x4d, 0x71, 0x42, 0xb3, 0xea, - 0x3f, 0xfb, 0xda, 0x5a, 0x35, 0xbf, 0xd2, 0x0f, - 0x2f, 0x9c, 0x8f, 0xcc, 0x6d, 0x30, 0x48, 0x54 - }; - - OBufferStream os; - StepSource source; - source >> hmacFilter(DigestAlgorithm::SHA256, key, sizeof(key)) >> streamSink(os); - source.write(data, 1); - source.write(data + 1, 2); - source.write(data + 3, 3); - source.write(data + 6, 4); - source.write(data + 10, 5); - source.write(data + 15, 1); - source.end(); - - ConstBufferPtr buf = os.buf(); - BOOST_CHECK_EQUAL_COLLECTIONS(digest, digest + sizeof(digest), buf->begin(), buf->end()); -} - -BOOST_AUTO_TEST_CASE(EmptyInput) -{ - uint8_t key[16] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - - uint8_t digest[32] = { - 0x07, 0xEF, 0xF8, 0xB3, 0x26, 0xB7, 0x79, 0x8C, - 0x9C, 0xCF, 0xCB, 0xDB, 0xE5, 0x79, 0x48, 0x9A, - 0xC7, 0x85, 0xA7, 0x99, 0x5A, 0x04, 0x61, 0x8B, - 0x1A, 0x28, 0x13, 0xC2, 0x67, 0x44, 0x77, 0x7D - }; - - OBufferStream os; - StepSource source; - source >> hmacFilter(DigestAlgorithm::SHA256, key, sizeof(key)) >> streamSink(os); - source.end(); - - ConstBufferPtr buf = os.buf(); - BOOST_CHECK_EQUAL_COLLECTIONS(digest, digest + sizeof(digest), buf->begin(), buf->end()); -} - -BOOST_AUTO_TEST_CASE(Error) -{ - uint8_t key[16] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - - OBufferStream os; - BOOST_REQUIRE_THROW(stepSource() >> hmacFilter(DigestAlgorithm::NONE, key, sizeof(key)) >> streamSink(os), - transform::Error); -} - -BOOST_AUTO_TEST_SUITE_END() // TestHmacFilter -BOOST_AUTO_TEST_SUITE_END() // Transform -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace transform -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/transform/private-key.t.cpp b/tests/unit-tests/security/transform/private-key.t.cpp deleted file mode 100644 index 6531a707f..000000000 --- a/tests/unit-tests/security/transform/private-key.t.cpp +++ /dev/null @@ -1,427 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/transform/private-key.hpp" -#include "security/transform.hpp" -#include "security/key-params.hpp" -#include "encoding/buffer-stream.hpp" -#include - -#include -#include "boost-test.hpp" - -namespace ndn { -namespace security { -namespace transform { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(Transform) -BOOST_AUTO_TEST_SUITE(TestPrivateKey) - -class RsaKeyTestData -{ -public: - RsaKeyTestData() - { - privateKeyPkcs1 = - "MIIEpAIBAAKCAQEAw0WM1/WhAxyLtEqsiAJgWDZWuzkYpeYVdeeZcqRZzzfRgBQT\n" - "sNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobws3iigohnM9yTK+KKiayPhIAm/+5H\n" - "GT6SgFJhYhqo1/upWdueojil6RP4/AgavHhopxlAVbk6G9VdVnlQcQ5Zv0OcGi73\n" - "c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9gZwIL5PuE9BiO6I39cL9z7EK1SfZh\n" - "OWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA9rH58ynaAix0tcR/nBMRLUX+e3rU\n" - "RHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0ywIDAQABAoIBADQkckOIl4IZMUTn\n" - "W8LFv6xOdkJwMKC8G6bsPRFbyY+HvC2TLt7epSvfS+f4AcYWaOPcDu2E49vt2sNr\n" - "cASly8hgwiRRAB3dHH9vcsboiTo8bi2RFvMqvjv9w3tK2yMxVDtmZamzrrnaV3YV\n" - "Q+5nyKo2F/PMDjQ4eUAKDOzjhBuKHsZBTFnA1MFNI+UKj5X4Yp64DFmKlxTX/U2b\n" - "wzVywo5hzx2Uhw51jmoLls4YUvMJXD0wW5ZtYRuPogXvXb/of9ef/20/wU11WFKg\n" - "Xb4gfR8zUXaXS1sXcnVm3+24vIs9dApUwykuoyjOqxWqcHRec2QT2FxVGkFEraze\n" - "CPa4rMECgYEA5Y8CywomIcTgerFGFCeMHJr8nQGqY2V/owFb3k9maczPnC9p4a9R\n" - "c5szLxA9FMYFxurQZMBWSEG2JS1HR2mnjigx8UKjYML/A+rvvjZOMe4M6Sy2ggh4\n" - "SkLZKpWTzjTe07ByM/j5v/SjNZhWAG7sw4/LmPGRQkwJv+KZhGojuOkCgYEA2cOF\n" - "T6cJRv6kvzTz9S0COZOVm+euJh/BXp7oAsAmbNfOpckPMzqHXy8/wpdKl6AAcB57\n" - "OuztlNfV1D7qvbz7JuRlYwQ0cEfBgbZPcz1p18HHDXhwn57ZPb8G33Yh9Omg0HNA\n" - "Imb4LsVuSqxA6NwSj7cpRekgTedrhLFPJ+Ydb5MCgYEAsM3Q7OjILcIg0t6uht9e\n" - "vrlwTsz1mtCV2co2I6crzdj9HeI2vqf1KAElDt6G7PUHhglcr/yjd8uEqmWRPKNX\n" - "ddnnfVZB10jYeP/93pac6z/Zmc3iU4yKeUe7U10ZFf0KkiiYDQd59CpLef/2XScS\n" - "HB0oRofnxRQjfjLc4muNT+ECgYEAlcDk06MOOTly+F8lCc1bA1dgAmgwFd2usDBd\n" - "Y07a3e0HGnGLN3Kfl7C5i0tZq64HvxLnMd2vgLVxQlXGPpdQrC1TH+XLXg+qnlZO\n" - "ivSH7i0/gx75bHvj75eH1XK65V8pDVDEoSPottllAIs21CxLw3N1ObOZWJm2EfmR\n" - "cuHICmsCgYAtFJ1idqMoHxES3mlRpf2JxyQudP3SCm2WpGmqVzhRYInqeatY5sUd\n" - "lPLHm/p77RT7EyxQHTlwn8FJPuM/4ZH1rQd/vB+Y8qAtYJCexDMsbvLW+Js+VOvk\n" - "jweEC0nrcL31j9mF0vz5E6tfRu4hhJ6L4yfWs0gSejskeVB/w8QY4g==\n"; - - privateKeyPkcs8 = - "MIIFCzA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIOKYJXvB6p8kCAggA\n" - "MBEGBSsOAwIHBAiQgMK8kQXTyASCBMjeNiKYYw5/yHgs9BfSGrpqvV0LkkgMQNUW\n" - "R4ZY8fuNjZynd+PxDuw2pyrv1Yv3jc+tupwUehZEzYOnGd53wQAuLO+Z0TBgRFN7\n" - "Lhk+AxlT7hu0xaB3ZpJ/uvWpgEJHsq/aB/GYgyzXcQo2AiqzERVpMCWJVmE1L977\n" - "CHwJmLm5mxclVLYp1UK5lkIBFu/M4nPavmNmYNUU1LOrXRo56TlJ2kUp8gQyQI1P\n" - "VPxi4chmlsr/OnQ2d1eZN+euFm0CS+yP+LFgI9ZqdyH1w+J43SXdHDzauVcZp7oa\n" - "Kw24OrhHfolLAnQIECXEJYeT7tZmhC4O9V6B18PFVyxWnEU4eFNpFE8kYSmm8Um2\n" - "buvDKI71q43hm23moYT9uIM1f4M8UkoOliJGrlf4xgEcmDuokEX01PdOq1gc4nvG\n" - "0DCwDI9cOsyn8cxhk9UVtFgzuG/seuznxIv1F5H0hzYOyloStXxRisJES0kgByBt\n" - "FFTfyoFKRrmCjRIygwVKUSkSDR0DlQS5ZLvQyIswnSQFwxAHqfvoSL4dB9UAIAQ+\n" - "ALVF1maaHgptbL6Ifqf0GFCv0hdNCVNDNCdy8R+S6nEYE+YdYSIdT1L88KD5PjU3\n" - "YY/CMnxhTncMaT4acPO1UUYuSGRZ/JL6E0ihoqIU+bqUgLSHNzhPySPfN9uqN61Y\n" - "HFBtxeEPWKU0f/JPkRBMmZdMI1/OVmA3QHSRBydI+CQN8no2gZRFoVbHTkG8IMpE\n" - "1fiDJpwFkpzIv/JPiTSE7DeBH5NJk1bgu7TcuZfa4unyAqss0UuLnXzS06TppkUj\n" - "QGft0g8VPW56eli6B4xrSzzuvAdbrxsVfxdmtHPyYxLb3/UG1g4x/H/yULhx7x9P\n" - "iI6cw6JUE+8bwJV2ZIlHXXHO+wUp/gCFJ6MHo9wkR1QvnHP2ClJAzBm9OvYnUx2Y\n" - "SX0HxEowW8BkhxOF184LEmxeua0yyZUqCdrYmErp7x9EY/LhD1zBwH8OGRa0qzmR\n" - "VKxAPKihkb9OgxcUKbvKePx3k2cQ7fbCUspGPm4Kn1zwMgRAZ4fz/o8Lnwc8MSY3\n" - "lPWnmLTFu420SRH2g9N0o/r195hiZ5cc+KfF4pwZWKbEbKFk/UfXA9vmOi7BBtDJ\n" - "RWshOINhzMU6Ij3KuaEpHni1HoHjw0SQ97ow2x/aB8k2QC28tbsa49lD2KKJku6b\n" - "2Or89adwFKqMgS2IXfXMXs/iG5EFLYN6r8e40Dn5f1vJfRLJl03XByIfT2n92pw3\n" - "fP7muOIKLUsEKjOrmn94NwMlfeW13oQHEH2KjPOWFS/tyJHDdVU+of4COH5yg59a\n" - "TZqFkOTGeliE1O+6sfF9fRuVxFUF3D8Hpr0JIjdc6+3RgIlGsXc8BwiSjDSI2XW+\n" - "vo75/2zPU9t8OeXEIJk2CQGyqLwUJ6dyi/yDRrvZAgjrUvbpcxydnBAHrLbLUGXJ\n" - "aEHH2tjEtnTqVyTchr1yHoupcFOCkA0dAA66XqwcssQxJiMGrWTpCbgd9mrTXQaZ\n" - "U7afFN1jpO78tgBQUUpImXdHLLsqdN5tefqjileZGZ9x3/C6TNAfDwYJdsicNNn5\n" - "y+JVsbltfLWlJxb9teb3dtQiFlJ7ofprLJnJVqI/Js8lozY+KaxV2vtbZkcD4dM=\n"; - - publicKeyPkcs8 = - "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw0WM1/WhAxyLtEqsiAJg\n" - "WDZWuzkYpeYVdeeZcqRZzzfRgBQTsNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobw\n" - "s3iigohnM9yTK+KKiayPhIAm/+5HGT6SgFJhYhqo1/upWdueojil6RP4/AgavHho\n" - "pxlAVbk6G9VdVnlQcQ5Zv0OcGi73c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9g\n" - "ZwIL5PuE9BiO6I39cL9z7EK1SfZhOWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA\n" - "9rH58ynaAix0tcR/nBMRLUX+e3rURHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0\n" - "ywIDAQAB\n"; - } - -public: - std::string privateKeyPkcs1; - std::string privateKeyPkcs8; - std::string publicKeyPkcs8; -}; - -class EcdsaKeyTestData -{ -public: - EcdsaKeyTestData() - { - privateKeyPkcs1 = - "MIIBaAIBAQQgRxwcbzK9RV6AHYFsDcykI86o3M/a1KlJn0z8PcLMBZOggfowgfcC\n" - "AQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA////////////////\n" - "MFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57Pr\n" - "vVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEE\n" - "axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54W\n" - "K84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8\n" - "YyVRAgEBoUQDQgAEaG4WJuDAt0QkEM4t29KDUdzkQlMPGrqWzkWhgt9OGnwc6O7A\n" - "ZLPSrDyhwyrKS7XLRXml5DisQ93RvByll32y8A==\n"; - - privateKeyPkcs8 = - "MIIBwzA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIVHkBzLGtDvICAggA\n" - "MBEGBSsOAwIHBAhk6g9eI3toNwSCAYDd+LWPDBTrKV7vUyxTvDbpUd0eXfh73DKA\n" - "MHkdHuVmhpmpBbsF9XvaFuL8J/1xi1Yl2XGw8j3WyrprD2YEhl/+zKjNbdTDJmNO\n" - "SlomuwWb5AVCJ9reT94zIXKCnexUcyBFS7ep+P4dwuef0VjzprjfmnAZHrP+u594\n" - "ELHpKwi0ZpQLtcJjjud13bn43vbXb+aU7jmPV5lU2XP8TxaQJiYIibNEh1Y3TZGr\n" - "akJormYvhaYbiZkKLHQ9AvQMEjhoIW5WCB3q+tKZUKTzcQpjNnf9FOTeKN3jk3Kd\n" - "2OmibPZcbMJdgCD/nRVn1cBo7Hjn3IMjgtszQHtEUphOQiAkOJUnKmy9MTYqtcNN\n" - "6cuFItbu4QvbVwailgdUjOYwIJCmIxExlPV0ohS24pFGsO03Yn7W8rBB9VWENYmG\n" - "HkZIbGsHv7O9Wy7fv+FJgZkjeti0807IsNXSJl8LUK0ZIhAR7OU8uONWMsbHdQnk\n" - "q1HB1ZKa52ugACl7g/DF9b7CoSAjFeE=\n"; - - publicKeyPkcs8 = - "MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\n" - "AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////\n" - "///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd\n" - "NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5\n" - "RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n" - "//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABGhuFibgwLdEJBDOLdvSg1Hc\n" - "5EJTDxq6ls5FoYLfThp8HOjuwGSz0qw8ocMqyku1y0V5peQ4rEPd0bwcpZd9svA=\n"; - } - -public: - std::string privateKeyPkcs1; - std::string privateKeyPkcs8; - std::string publicKeyPkcs8; -}; - -typedef boost::mpl::list KeyTestDataSets; - -void -checkPkcs8Encoding(ConstBufferPtr encoding, const std::string& password, ConstBufferPtr pkcs1) -{ - PrivateKey sKey; - BOOST_REQUIRE_NO_THROW(sKey.loadPkcs8(encoding->buf(), encoding->size(), - password.c_str(), password.size())); - OBufferStream os; - BOOST_REQUIRE_NO_THROW(sKey.savePkcs1(os)); - ConstBufferPtr keyPkcs1Str = os.buf(); - BOOST_CHECK_EQUAL_COLLECTIONS(pkcs1->begin(), pkcs1->end(), keyPkcs1Str->begin(), keyPkcs1Str->end()); -} - -void -checkPkcs8Base64Encoding(ConstBufferPtr encoding, const std::string& password, ConstBufferPtr pkcs1) -{ - OBufferStream os; - bufferSource(*encoding) >> base64Decode() >> streamSink(os); - - checkPkcs8Encoding(os.buf(), password, pkcs1); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(SaveLoad, T, KeyTestDataSets) -{ - T dataSet; - - const uint8_t* sKeyPkcs1Base64 = reinterpret_cast(dataSet.privateKeyPkcs1.c_str()); - size_t sKeyPkcs1Base64Len = dataSet.privateKeyPkcs1.size(); - - OBufferStream os; - bufferSource(sKeyPkcs1Base64, sKeyPkcs1Base64Len) >> base64Decode() >> streamSink(os); - ConstBufferPtr sKeyPkcs1Buf = os.buf(); - const uint8_t* sKeyPkcs1 = sKeyPkcs1Buf->buf(); - size_t sKeyPkcs1Len = sKeyPkcs1Buf->size(); - - // load key in base64 encoded pkcs1 format - PrivateKey sKey; - BOOST_REQUIRE_NO_THROW(sKey.loadPkcs1Base64(sKeyPkcs1Base64, sKeyPkcs1Base64Len)); - - std::stringstream ss2(dataSet.privateKeyPkcs1); - PrivateKey sKey2; - BOOST_REQUIRE_NO_THROW(sKey2.loadPkcs1Base64(ss2)); - - // load key in pkcs1 format - PrivateKey sKey3; - BOOST_REQUIRE_NO_THROW(sKey3.loadPkcs1(sKeyPkcs1, sKeyPkcs1Len)); - - std::stringstream ss4; - ss4.write(reinterpret_cast(sKeyPkcs1), sKeyPkcs1Len); - PrivateKey sKey4; - BOOST_REQUIRE_NO_THROW(sKey4.loadPkcs1(ss4)); - - // save key in base64 encoded pkcs1 format - OBufferStream os2; - BOOST_REQUIRE_NO_THROW(sKey.savePkcs1Base64(os2)); - ConstBufferPtr keyPkcs1Base64Str = os2.buf(); - BOOST_CHECK_EQUAL_COLLECTIONS(sKeyPkcs1Base64, sKeyPkcs1Base64 + sKeyPkcs1Base64Len, - keyPkcs1Base64Str->begin(), keyPkcs1Base64Str->end()); - - // save key in pkcs1 format - OBufferStream os3; - BOOST_REQUIRE_NO_THROW(sKey.savePkcs1(os3)); - ConstBufferPtr keyPkcs1Str = os3.buf(); - BOOST_CHECK_EQUAL_COLLECTIONS(sKeyPkcs1, sKeyPkcs1 + sKeyPkcs1Len, - keyPkcs1Str->begin(), keyPkcs1Str->end()); - - - - const uint8_t* sKeyPkcs8Base64 = reinterpret_cast(dataSet.privateKeyPkcs8.c_str()); - size_t sKeyPkcs8Base64Len = dataSet.privateKeyPkcs8.size(); - - OBufferStream os4; - bufferSource(sKeyPkcs8Base64, sKeyPkcs8Base64Len) >> base64Decode() >> streamSink(os4); - ConstBufferPtr sKeyPkcs8Buf = os4.buf(); - const uint8_t* sKeyPkcs8 = sKeyPkcs8Buf->buf(); - size_t sKeyPkcs8Len = sKeyPkcs8Buf->size(); - - std::string password("password"); - std::string wrongpw("wrongpw"); - auto pwCallback = [&] (char* buf, size_t size, int rwflag) -> int { - std::copy(password.begin(), password.end(), buf); - return password.size(); - }; - - - // load key in base64 encoded pkcs8 format - PrivateKey sKey5; - BOOST_REQUIRE_NO_THROW(sKey5.loadPkcs8Base64(sKeyPkcs8Base64, sKeyPkcs8Base64Len, - password.c_str(), password.size())); - - PrivateKey sKey6; - BOOST_REQUIRE_NO_THROW(sKey6.loadPkcs8Base64(sKeyPkcs8Base64, sKeyPkcs8Base64Len, pwCallback)); - - std::stringstream ss7(dataSet.privateKeyPkcs8); - PrivateKey sKey7; - BOOST_REQUIRE_NO_THROW(sKey7.loadPkcs8Base64(ss7, password.c_str(), password.size())); - - std::stringstream ss8(dataSet.privateKeyPkcs8); - PrivateKey sKey8; - BOOST_REQUIRE_NO_THROW(sKey8.loadPkcs8Base64(ss8, pwCallback)); - - // load key in pkcs8 format - PrivateKey sKey9; - BOOST_REQUIRE_NO_THROW(sKey9.loadPkcs8(sKeyPkcs8, sKeyPkcs8Len, - password.c_str(), password.size())); - - PrivateKey sKey10; - BOOST_REQUIRE_NO_THROW(sKey10.loadPkcs8(sKeyPkcs8, sKeyPkcs8Len, pwCallback)); - - std::stringstream ss11; - ss11.write(reinterpret_cast(sKeyPkcs8), sKeyPkcs8Len); - PrivateKey sKey11; - BOOST_REQUIRE_NO_THROW(sKey11.loadPkcs8(ss11, password.c_str(), password.size())); - - std::stringstream ss12; - ss12.write(reinterpret_cast(sKeyPkcs8), sKeyPkcs8Len); - PrivateKey sKey12; - BOOST_REQUIRE_NO_THROW(sKey12.loadPkcs8(ss12, pwCallback)); - - // load key using wrong password, Error is expected. - PrivateKey sKey13; - BOOST_REQUIRE_THROW(sKey13.loadPkcs8Base64(sKeyPkcs8Base64, sKeyPkcs8Base64Len, wrongpw.c_str(), wrongpw.size()), - PrivateKey::Error); - - // save key in base64 encoded pkcs8 format - OBufferStream os14; - BOOST_REQUIRE_NO_THROW(sKey.savePkcs8Base64(os14, password.c_str(), password.size())); - ConstBufferPtr encoded14 = os14.buf(); - checkPkcs8Base64Encoding(encoded14, password, sKeyPkcs1Buf); - - OBufferStream os15; - BOOST_REQUIRE_NO_THROW(sKey.savePkcs8Base64(os15, pwCallback)); - ConstBufferPtr encoded15 = os15.buf(); - checkPkcs8Base64Encoding(encoded15, password, sKeyPkcs1Buf); - - // save key in pkcs8 format - OBufferStream os16; - BOOST_REQUIRE_NO_THROW(sKey.savePkcs8(os16, password.c_str(), password.size())); - ConstBufferPtr encoded16 = os16.buf(); - checkPkcs8Encoding(encoded16, password, sKeyPkcs1Buf); - - OBufferStream os17; - BOOST_REQUIRE_NO_THROW(sKey.savePkcs8(os17, pwCallback)); - ConstBufferPtr encoded17 = os17.buf(); - checkPkcs8Encoding(encoded17, password, sKeyPkcs1Buf); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(DerivePublicKey, T, KeyTestDataSets) -{ - T dataSet; - - const uint8_t* sKeyPkcs1Base64 = reinterpret_cast(dataSet.privateKeyPkcs1.c_str()); - size_t sKeyPkcs1Base64Len = dataSet.privateKeyPkcs1.size(); - - PrivateKey sKey; - BOOST_REQUIRE_NO_THROW(sKey.loadPkcs1Base64(sKeyPkcs1Base64, sKeyPkcs1Base64Len)); - - // derive public key and compare - ConstBufferPtr pKeyBits= sKey.derivePublicKey(); - OBufferStream os; - bufferSource(dataSet.publicKeyPkcs8) >> base64Decode() >> streamSink(os); - BOOST_CHECK_EQUAL_COLLECTIONS(pKeyBits->begin(), pKeyBits->end(), - os.buf()->begin(), os.buf()->end()); -} - -BOOST_AUTO_TEST_CASE(RsaDecryption) -{ - RsaKeyTestData dataSet; - - PrivateKey sKey; - sKey.loadPkcs1Base64(reinterpret_cast(dataSet.privateKeyPkcs1.c_str()), - dataSet.privateKeyPkcs1.size()); - - const uint8_t plainText[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 - }; - - const std::string cipherTextBase64 = - "i2XNpZ2JbLa4JmBTdDrGmsd4/0C+p+BSCpW3MuPBNe5uChQ0eRO1dvjTnEqwSECY\n" - "38en9JZwcyb0It/TSFNXHlq+Z1ZpffnjIJxQR9HcgwvwQJh6WRH0vu38tvGkGuNv\n" - "60Rdn85hqSy1CikmXCeWXL9yCqeqcP21R94G/T3FuA+c1FtFko8KOzCwvrTXMO6n\n" - "5PNsqlLXabSGr+jz4EwOsSCgPkiDf9U6tXoSPRA2/YvqFQdaiUXIVlomESvaqqZ8\n" - "FxPs2BON0lobM8gT+xdzbRKofp+rNjNK+5uWyeOnXJwzCszh17cdJl2BH1dZwaVD\n" - "PmTiSdeDQXZ94U5boDQ4Aw==\n"; - - OBufferStream os; - bufferSource(cipherTextBase64) >> base64Decode() >> streamSink(os); - - ConstBufferPtr decryptText = sKey.decrypt(os.buf()->buf(), os.buf()->size()); - - BOOST_CHECK_EQUAL_COLLECTIONS(plainText, plainText + sizeof(plainText), - decryptText->begin(), decryptText->end()); -} - -BOOST_AUTO_TEST_CASE(RsaEncryption) -{ - RsaKeyTestData dataSet; - - PublicKey pKey; - pKey.loadPkcs8Base64(reinterpret_cast(dataSet.publicKeyPkcs8.c_str()), - dataSet.publicKeyPkcs8.size()); - - PrivateKey sKey; - sKey.loadPkcs1Base64(reinterpret_cast(dataSet.privateKeyPkcs1.c_str()), - dataSet.privateKeyPkcs1.size()); - - const uint8_t plainText[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 - }; - - ConstBufferPtr cipherText = pKey.encrypt(plainText, sizeof(plainText)); - ConstBufferPtr decryptText = sKey.decrypt(cipherText->buf(), cipherText->size()); - - BOOST_CHECK_EQUAL_COLLECTIONS(plainText, plainText + sizeof(plainText), - decryptText->begin(), decryptText->end()); -} - -typedef boost::mpl::list TestKeyParams; - -BOOST_AUTO_TEST_CASE_TEMPLATE(GenerateKey, T, TestKeyParams) -{ - BOOST_REQUIRE_NO_THROW(generatePrivateKey(T())); - - unique_ptr sKey = generatePrivateKey(T()); - PublicKey pKey; - ConstBufferPtr pKeyBits = sKey->derivePublicKey(); - pKey.loadPkcs8(pKeyBits->buf(), pKeyBits->size()); - - uint8_t data[] = {0x01, 0x02, 0x03, 0x04}; - - OBufferStream os; - BOOST_REQUIRE_NO_THROW(bufferSource(data, sizeof(data)) >> - signerFilter(DigestAlgorithm::SHA256, *sKey) >> - streamSink(os)); - - ConstBufferPtr sig = os.buf(); - bool result = false; - BOOST_REQUIRE_NO_THROW(bufferSource(data, sizeof(data)) >> - verifierFilter(DigestAlgorithm::SHA256, pKey, sig->buf(), sig->size()) >> - boolSink(result)); - - BOOST_CHECK(result); - - - unique_ptr sKey2 = generatePrivateKey(T()); - - OBufferStream os1; - sKey->savePkcs1(os1); - ConstBufferPtr key1Pkcs1 = os1.buf(); - - OBufferStream os2; - sKey2->savePkcs1(os2); - ConstBufferPtr key2Pkcs1 = os2.buf(); - - BOOST_CHECK(*key1Pkcs1 != *key2Pkcs1); -} - -BOOST_AUTO_TEST_SUITE_END() // TestPrivateKey -BOOST_AUTO_TEST_SUITE_END() // Transform -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace transform -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/transform/public-key.t.cpp b/tests/unit-tests/security/transform/public-key.t.cpp deleted file mode 100644 index 1009bd94b..000000000 --- a/tests/unit-tests/security/transform/public-key.t.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/transform/public-key.hpp" -#include "security/transform/buffer-source.hpp" -#include "security/transform/base64-decode.hpp" -#include "security/transform/stream-sink.hpp" -#include "encoding/buffer-stream.hpp" - -#include -#include "boost-test.hpp" - -namespace ndn { -namespace security { -namespace transform { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(Transform) -BOOST_AUTO_TEST_SUITE(TestPublicKey) - -class RsaPublicKeyTestData -{ -public: - RsaPublicKeyTestData() - { - publicKeyPkcs8 = - "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw0WM1/WhAxyLtEqsiAJg\n" - "WDZWuzkYpeYVdeeZcqRZzzfRgBQTsNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobw\n" - "s3iigohnM9yTK+KKiayPhIAm/+5HGT6SgFJhYhqo1/upWdueojil6RP4/AgavHho\n" - "pxlAVbk6G9VdVnlQcQ5Zv0OcGi73c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9g\n" - "ZwIL5PuE9BiO6I39cL9z7EK1SfZhOWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA\n" - "9rH58ynaAix0tcR/nBMRLUX+e3rURHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0\n" - "ywIDAQAB\n"; - } - -public: - std::string publicKeyPkcs8; -}; - -class EcdsaPublicKeyTestData -{ -public: - EcdsaPublicKeyTestData() - { - publicKeyPkcs8 = - "MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\n" - "AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////\n" - "///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd\n" - "NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5\n" - "RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n" - "//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABGhuFibgwLdEJBDOLdvSg1Hc\n" - "5EJTDxq6ls5FoYLfThp8HOjuwGSz0qw8ocMqyku1y0V5peQ4rEPd0bwcpZd9svA=\n"; - } - -public: - std::string publicKeyPkcs8; -}; - -typedef boost::mpl::list PublicKeyTestDataSets; - -BOOST_AUTO_TEST_CASE_TEMPLATE(SaveLoad, T, PublicKeyTestDataSets) -{ - T dataSet; - - const uint8_t* pKeyPkcs8Base64 = reinterpret_cast(dataSet.publicKeyPkcs8.c_str()); - size_t pKeyPkcs8Base64Len = dataSet.publicKeyPkcs8.size(); - - OBufferStream os; - bufferSource(pKeyPkcs8Base64, pKeyPkcs8Base64Len) >> base64Decode() >> streamSink(os); - ConstBufferPtr pKeyPkcs8Buf = os.buf(); - const uint8_t* pKeyPkcs8 = pKeyPkcs8Buf->buf(); - size_t pKeyPkcs8Len = pKeyPkcs8Buf->size(); - - PublicKey pKey1; - BOOST_REQUIRE_NO_THROW(pKey1.loadPkcs8Base64(pKeyPkcs8Base64, pKeyPkcs8Base64Len)); - - std::stringstream ss2(dataSet.publicKeyPkcs8); - PublicKey pKey2; - BOOST_REQUIRE_NO_THROW(pKey2.loadPkcs8Base64(ss2)); - - PublicKey pKey3; - BOOST_REQUIRE_NO_THROW(pKey3.loadPkcs8(pKeyPkcs8, pKeyPkcs8Len)); - - std::stringstream ss4; - ss4.write(reinterpret_cast(pKeyPkcs8), pKeyPkcs8Len); - PublicKey pKey4; - BOOST_REQUIRE_NO_THROW(pKey4.loadPkcs8(ss4)); - - OBufferStream os5; - BOOST_REQUIRE_NO_THROW(pKey1.savePkcs8Base64(os5)); - BOOST_CHECK_EQUAL_COLLECTIONS(pKeyPkcs8Base64, pKeyPkcs8Base64 + pKeyPkcs8Base64Len, - os5.buf()->begin(), os5.buf()->end()); - - OBufferStream os6; - BOOST_REQUIRE_NO_THROW(pKey1.savePkcs8(os6)); - BOOST_CHECK_EQUAL_COLLECTIONS(pKeyPkcs8, pKeyPkcs8 + pKeyPkcs8Len, - os6.buf()->begin(), os6.buf()->end()); -} - -BOOST_AUTO_TEST_SUITE_END() // TestPublicKey -BOOST_AUTO_TEST_SUITE_END() // Transform -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace transform -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/transform/signer-filter.t.cpp b/tests/unit-tests/security/transform/signer-filter.t.cpp deleted file mode 100644 index dc173e30e..000000000 --- a/tests/unit-tests/security/transform/signer-filter.t.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/transform/signer-filter.hpp" -#include "security/transform.hpp" -#include "encoding/buffer-stream.hpp" - -// TODO: remove CryptoPP dependency -#include "security/v1/cryptopp.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace security { -namespace transform { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(Transform) -BOOST_AUTO_TEST_SUITE(TestSignerFilter) - -BOOST_AUTO_TEST_CASE(Rsa) -{ - std::string publicKeyPkcs8 = - "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw0WM1/WhAxyLtEqsiAJg\n" - "WDZWuzkYpeYVdeeZcqRZzzfRgBQTsNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobw\n" - "s3iigohnM9yTK+KKiayPhIAm/+5HGT6SgFJhYhqo1/upWdueojil6RP4/AgavHho\n" - "pxlAVbk6G9VdVnlQcQ5Zv0OcGi73c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9g\n" - "ZwIL5PuE9BiO6I39cL9z7EK1SfZhOWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA\n" - "9rH58ynaAix0tcR/nBMRLUX+e3rURHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0\n" - "ywIDAQAB\n"; - - std::string privateKeyPkcs1 = - "MIIEpAIBAAKCAQEAw0WM1/WhAxyLtEqsiAJgWDZWuzkYpeYVdeeZcqRZzzfRgBQT\n" - "sNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobws3iigohnM9yTK+KKiayPhIAm/+5H\n" - "GT6SgFJhYhqo1/upWdueojil6RP4/AgavHhopxlAVbk6G9VdVnlQcQ5Zv0OcGi73\n" - "c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9gZwIL5PuE9BiO6I39cL9z7EK1SfZh\n" - "OWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA9rH58ynaAix0tcR/nBMRLUX+e3rU\n" - "RHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0ywIDAQABAoIBADQkckOIl4IZMUTn\n" - "W8LFv6xOdkJwMKC8G6bsPRFbyY+HvC2TLt7epSvfS+f4AcYWaOPcDu2E49vt2sNr\n" - "cASly8hgwiRRAB3dHH9vcsboiTo8bi2RFvMqvjv9w3tK2yMxVDtmZamzrrnaV3YV\n" - "Q+5nyKo2F/PMDjQ4eUAKDOzjhBuKHsZBTFnA1MFNI+UKj5X4Yp64DFmKlxTX/U2b\n" - "wzVywo5hzx2Uhw51jmoLls4YUvMJXD0wW5ZtYRuPogXvXb/of9ef/20/wU11WFKg\n" - "Xb4gfR8zUXaXS1sXcnVm3+24vIs9dApUwykuoyjOqxWqcHRec2QT2FxVGkFEraze\n" - "CPa4rMECgYEA5Y8CywomIcTgerFGFCeMHJr8nQGqY2V/owFb3k9maczPnC9p4a9R\n" - "c5szLxA9FMYFxurQZMBWSEG2JS1HR2mnjigx8UKjYML/A+rvvjZOMe4M6Sy2ggh4\n" - "SkLZKpWTzjTe07ByM/j5v/SjNZhWAG7sw4/LmPGRQkwJv+KZhGojuOkCgYEA2cOF\n" - "T6cJRv6kvzTz9S0COZOVm+euJh/BXp7oAsAmbNfOpckPMzqHXy8/wpdKl6AAcB57\n" - "OuztlNfV1D7qvbz7JuRlYwQ0cEfBgbZPcz1p18HHDXhwn57ZPb8G33Yh9Omg0HNA\n" - "Imb4LsVuSqxA6NwSj7cpRekgTedrhLFPJ+Ydb5MCgYEAsM3Q7OjILcIg0t6uht9e\n" - "vrlwTsz1mtCV2co2I6crzdj9HeI2vqf1KAElDt6G7PUHhglcr/yjd8uEqmWRPKNX\n" - "ddnnfVZB10jYeP/93pac6z/Zmc3iU4yKeUe7U10ZFf0KkiiYDQd59CpLef/2XScS\n" - "HB0oRofnxRQjfjLc4muNT+ECgYEAlcDk06MOOTly+F8lCc1bA1dgAmgwFd2usDBd\n" - "Y07a3e0HGnGLN3Kfl7C5i0tZq64HvxLnMd2vgLVxQlXGPpdQrC1TH+XLXg+qnlZO\n" - "ivSH7i0/gx75bHvj75eH1XK65V8pDVDEoSPottllAIs21CxLw3N1ObOZWJm2EfmR\n" - "cuHICmsCgYAtFJ1idqMoHxES3mlRpf2JxyQudP3SCm2WpGmqVzhRYInqeatY5sUd\n" - "lPLHm/p77RT7EyxQHTlwn8FJPuM/4ZH1rQd/vB+Y8qAtYJCexDMsbvLW+Js+VOvk\n" - "jweEC0nrcL31j9mF0vz5E6tfRu4hhJ6L4yfWs0gSejskeVB/w8QY4g==\n"; - - uint8_t data[] = {0x01, 0x02, 0x03, 0x04}; - - OBufferStream os1; - bufferSource(publicKeyPkcs8) >> base64Decode() >> streamSink(os1); - ConstBufferPtr publicKeyBuffer = os1.buf(); - - PrivateKey sKey; - sKey.loadPkcs1Base64(reinterpret_cast(privateKeyPkcs1.c_str()), - privateKeyPkcs1.size()); - - OBufferStream os3; - bufferSource(data, sizeof(data)) >> signerFilter(DigestAlgorithm::SHA256, sKey) >> streamSink(os3); - ConstBufferPtr sig = os3.buf(); - - // TODO: remove CryptoPP dependency - { - using namespace CryptoPP; - - CryptoPP::RSA::PublicKey publicKey; - - ByteQueue keyQueue1; - keyQueue1.LazyPut(publicKeyBuffer->buf(), publicKeyBuffer->size()); - publicKey.Load(keyQueue1); - - // For signature, openssl only support pkcs1v15 padding. - RSASS::Verifier verifier(publicKey); - BOOST_CHECK(verifier.VerifyMessage(data, sizeof(data), sig->buf(), sig->size())); - } -} - -BOOST_AUTO_TEST_CASE(Ecdsa) -{ - std::string privateKeyPkcs1 = - "MIIBaAIBAQQgRxwcbzK9RV6AHYFsDcykI86o3M/a1KlJn0z8PcLMBZOggfowgfcC\n" - "AQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA////////////////\n" - "MFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57Pr\n" - "vVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEE\n" - "axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54W\n" - "K84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8\n" - "YyVRAgEBoUQDQgAEaG4WJuDAt0QkEM4t29KDUdzkQlMPGrqWzkWhgt9OGnwc6O7A\n" - "ZLPSrDyhwyrKS7XLRXml5DisQ93RvByll32y8A==\n"; - - std::string publicKeyPkcs8 = - "MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\n" - "AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////\n" - "///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd\n" - "NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5\n" - "RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n" - "//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABGhuFibgwLdEJBDOLdvSg1Hc\n" - "5EJTDxq6ls5FoYLfThp8HOjuwGSz0qw8ocMqyku1y0V5peQ4rEPd0bwcpZd9svA=\n"; - - uint8_t data[] = {0x01, 0x02, 0x03, 0x04}; - - OBufferStream os1; - bufferSource(publicKeyPkcs8) >> base64Decode() >> streamSink(os1); - ConstBufferPtr publicKeyBuffer = os1.buf(); - - PrivateKey sKey; - sKey.loadPkcs1Base64(reinterpret_cast(privateKeyPkcs1.c_str()), - privateKeyPkcs1.size()); - - OBufferStream os3; - bufferSource(data, sizeof(data)) >> signerFilter(DigestAlgorithm::SHA256, sKey) >> streamSink(os3); - ConstBufferPtr sig = os3.buf(); - - // TODO: remove CryptoPP dependency - { - using namespace CryptoPP; - - ECDSA::PublicKey publicKey; - ByteQueue keyQueue1; - keyQueue1.LazyPut(publicKeyBuffer->buf(), publicKeyBuffer->size()); - publicKey.Load(keyQueue1); - - // For signature, openssl only support pkcs1v15 padding. - ECDSA::Verifier verifier(publicKey); - - uint8_t buffer[64]; - size_t usedSize = DSAConvertSignatureFormat(buffer, sizeof(buffer), DSA_P1363, - sig->buf(), sig->size(), DSA_DER); - BOOST_CHECK(verifier.VerifyMessage(data, sizeof(data), buffer, usedSize)); - } -} - -BOOST_AUTO_TEST_SUITE_END() // TestSignerFilter -BOOST_AUTO_TEST_SUITE_END() // Transform -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace transform -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/transform/verifier-filter.t.cpp b/tests/unit-tests/security/transform/verifier-filter.t.cpp deleted file mode 100644 index cd496dfee..000000000 --- a/tests/unit-tests/security/transform/verifier-filter.t.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/transform/verifier-filter.hpp" -#include "security/transform.hpp" -#include "encoding/buffer-stream.hpp" - -// TODO: remove CryptoPP dependency -#include "security/v1/cryptopp.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace security { -namespace transform { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(Transform) -BOOST_AUTO_TEST_SUITE(TestVerifierFilter) - -BOOST_AUTO_TEST_CASE(Rsa) -{ - std::string publicKeyPkcs8 = - "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw0WM1/WhAxyLtEqsiAJg\n" - "WDZWuzkYpeYVdeeZcqRZzzfRgBQTsNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobw\n" - "s3iigohnM9yTK+KKiayPhIAm/+5HGT6SgFJhYhqo1/upWdueojil6RP4/AgavHho\n" - "pxlAVbk6G9VdVnlQcQ5Zv0OcGi73c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9g\n" - "ZwIL5PuE9BiO6I39cL9z7EK1SfZhOWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA\n" - "9rH58ynaAix0tcR/nBMRLUX+e3rURHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0\n" - "ywIDAQAB\n"; - - std::string privateKeyPkcs8 = - "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDDRYzX9aEDHIu0\n" - "SqyIAmBYNla7ORil5hV155lypFnPN9GAFBOw2jNLm3gefBNmHDBdsfuTdA3SRFNX\n" - "zbpehvCzeKKCiGcz3JMr4oqJrI+EgCb/7kcZPpKAUmFiGqjX+6lZ256iOKXpE/j8\n" - "CBq8eGinGUBVuTob1V1WeVBxDlm/Q5waLvdz4SdgP9iBRFgZKeBSL9ieyHvv2nZT\n" - "r3+172BnAgvk+4T0GI7ojf1wv3PsQrVJ9mE5a8N7+oftiEP8EfBxaK3wWNHDDWCX\n" - "BFVMmwD2sfnzKdoCLHS1xH+cExEtRf57etREeDpRtKMlt1v2qYozV9MYcpTMv/mk\n" - "wbq4FTTLAgMBAAECggEANCRyQ4iXghkxROdbwsW/rE52QnAwoLwbpuw9EVvJj4e8\n" - "LZMu3t6lK99L5/gBxhZo49wO7YTj2+3aw2twBKXLyGDCJFEAHd0cf29yxuiJOjxu\n" - "LZEW8yq+O/3De0rbIzFUO2ZlqbOuudpXdhVD7mfIqjYX88wONDh5QAoM7OOEG4oe\n" - "xkFMWcDUwU0j5QqPlfhinrgMWYqXFNf9TZvDNXLCjmHPHZSHDnWOaguWzhhS8wlc\n" - "PTBblm1hG4+iBe9dv+h/15//bT/BTXVYUqBdviB9HzNRdpdLWxdydWbf7bi8iz10\n" - "ClTDKS6jKM6rFapwdF5zZBPYXFUaQUStrN4I9riswQKBgQDljwLLCiYhxOB6sUYU\n" - "J4wcmvydAapjZX+jAVveT2ZpzM+cL2nhr1FzmzMvED0UxgXG6tBkwFZIQbYlLUdH\n" - "aaeOKDHxQqNgwv8D6u++Nk4x7gzpLLaCCHhKQtkqlZPONN7TsHIz+Pm/9KM1mFYA\n" - "buzDj8uY8ZFCTAm/4pmEaiO46QKBgQDZw4VPpwlG/qS/NPP1LQI5k5Wb564mH8Fe\n" - "nugCwCZs186lyQ8zOodfLz/Cl0qXoABwHns67O2U19XUPuq9vPsm5GVjBDRwR8GB\n" - "tk9zPWnXwccNeHCfntk9vwbfdiH06aDQc0AiZvguxW5KrEDo3BKPtylF6SBN52uE\n" - "sU8n5h1vkwKBgQCwzdDs6MgtwiDS3q6G316+uXBOzPWa0JXZyjYjpyvN2P0d4ja+\n" - "p/UoASUO3obs9QeGCVyv/KN3y4SqZZE8o1d12ed9VkHXSNh4//3elpzrP9mZzeJT\n" - "jIp5R7tTXRkV/QqSKJgNB3n0Kkt5//ZdJxIcHShGh+fFFCN+Mtzia41P4QKBgQCV\n" - "wOTTow45OXL4XyUJzVsDV2ACaDAV3a6wMF1jTtrd7QcacYs3cp+XsLmLS1mrrge/\n" - "Eucx3a+AtXFCVcY+l1CsLVMf5cteD6qeVk6K9IfuLT+DHvlse+Pvl4fVcrrlXykN\n" - "UMShI+i22WUAizbULEvDc3U5s5lYmbYR+ZFy4cgKawKBgC0UnWJ2oygfERLeaVGl\n" - "/YnHJC50/dIKbZakaapXOFFgiep5q1jmxR2U8seb+nvtFPsTLFAdOXCfwUk+4z/h\n" - "kfWtB3+8H5jyoC1gkJ7EMyxu8tb4mz5U6+SPB4QLSetwvfWP2YXS/PkTq19G7iGE\n" - "novjJ9azSBJ6OyR5UH/DxBji\n"; - - uint8_t data[] = {0x01, 0x02, 0x03, 0x04}; - - OBufferStream os1; - bufferSource(publicKeyPkcs8) >> base64Decode() >> streamSink(os1); - ConstBufferPtr publicKeyBuffer = os1.buf(); - - OBufferStream os2; - bufferSource(privateKeyPkcs8) >> base64Decode() >> streamSink(os2); - ConstBufferPtr privateKeyBuffer = os2.buf(); - - // TODO: remove CryptoPP dependency - ConstBufferPtr sig; - { - CryptoPP::RSA::PrivateKey privateKey; - CryptoPP::ByteQueue keyQueue; - keyQueue.LazyPut(privateKeyBuffer->buf(), privateKeyBuffer->size()); - privateKey.Load(keyQueue); - - CryptoPP::RSASS::Signer signer(privateKey); - - CryptoPP::AutoSeededRandomPool rng; - OBufferStream os; - CryptoPP::StringSource(data, sizeof(data), true, - new CryptoPP::SignerFilter(rng, signer, new CryptoPP::FileSink(os))); - - sig = os.buf(); - } - - PublicKey pKey; - bool result = false; - pKey.loadPkcs8(publicKeyBuffer->buf(), publicKeyBuffer->size()); - bufferSource(data, sizeof(data)) >> - verifierFilter(DigestAlgorithm::SHA256, pKey, sig->buf(), sig->size()) >> boolSink(result); - - BOOST_CHECK_EQUAL(result, true); -} - -BOOST_AUTO_TEST_CASE(Ecdsa) -{ - std::string privateKeyPkcs8 = - "MIIBeQIBADCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAAB\n" - "AAAAAAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA\n" - "///////////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMV\n" - "AMSdNgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg\n" - "9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8A\n" - "AAAA//////////+85vqtpxeehPO5ysL8YyVRAgEBBG0wawIBAQQgRxwcbzK9RV6A\n" - "HYFsDcykI86o3M/a1KlJn0z8PcLMBZOhRANCAARobhYm4MC3RCQQzi3b0oNR3ORC\n" - "Uw8aupbORaGC304afBzo7sBks9KsPKHDKspLtctFeaXkOKxD3dG8HKWXfbLw\n"; - - std::string publicKeyPkcs8 = - "MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\n" - "AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////\n" - "///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd\n" - "NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5\n" - "RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n" - "//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABGhuFibgwLdEJBDOLdvSg1Hc\n" - "5EJTDxq6ls5FoYLfThp8HOjuwGSz0qw8ocMqyku1y0V5peQ4rEPd0bwcpZd9svA=\n"; - - uint8_t data[] = {0x01, 0x02, 0x03, 0x04}; - - OBufferStream os1; - bufferSource(publicKeyPkcs8) >> base64Decode() >> streamSink(os1); - ConstBufferPtr publicKeyBuffer = os1.buf(); - - OBufferStream os2; - bufferSource(privateKeyPkcs8) >> base64Decode() >> streamSink(os2); - ConstBufferPtr privateKeyBuffer = os2.buf(); - - // TODO: remove CryptoPP dependency - ConstBufferPtr sig; - { - CryptoPP::ECDSA::PrivateKey privateKey; - CryptoPP::ByteQueue keyQueue; - keyQueue.LazyPut(privateKeyBuffer->buf(), privateKeyBuffer->size()); - privateKey.Load(keyQueue); - CryptoPP::ECDSA::Signer signer(privateKey); - - CryptoPP::AutoSeededRandomPool rng; - OBufferStream os; - CryptoPP::StringSource(data, sizeof(data), true, - new CryptoPP::SignerFilter(rng, signer, new CryptoPP::FileSink(os))); - - uint8_t buf[200]; - size_t bufSize = DSAConvertSignatureFormat(buf, sizeof(buf), CryptoPP::DSA_DER, - os.buf()->buf(), os.buf()->size(), - CryptoPP::DSA_P1363); - sig = make_shared(buf, bufSize); - } - - PublicKey pKey; - bool result = false; - pKey.loadPkcs8(publicKeyBuffer->buf(), publicKeyBuffer->size()); - bufferSource(data, sizeof(data)) >> - verifierFilter(DigestAlgorithm::SHA256, pKey, sig->buf(), sig->size()) >> boolSink(result); - - BOOST_CHECK_EQUAL(result, true); -} - -BOOST_AUTO_TEST_SUITE_END() // TestVerifierFilter -BOOST_AUTO_TEST_SUITE_END() // Transform -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace transform -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/v1/certificate.t.cpp b/tests/unit-tests/security/v1/certificate.t.cpp deleted file mode 100644 index 043a1fb8e..000000000 --- a/tests/unit-tests/security/v1/certificate.t.cpp +++ /dev/null @@ -1,389 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/v1/certificate.hpp" -#include "security/v1/public-key.hpp" - -#include "security/key-chain.hpp" - -#include "security/v1/cryptopp.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace security { -namespace v1 { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(V1) -BOOST_AUTO_TEST_SUITE(TestCertificate) - -using namespace CryptoPP; - -const uint8_t PUBLIC_KEY[] = { - 0x30, 0x81, 0x9d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, - 0x01, 0x05, 0x00, 0x03, 0x81, 0x8b, 0x00, 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e, - 0x06, 0x3e, 0x47, 0x85, 0xb2, 0x34, 0x37, 0xaa, 0x85, 0x47, 0xac, 0x03, 0x24, 0x83, 0xb5, - 0x9c, 0xa8, 0x05, 0x3a, 0x24, 0x1e, 0xeb, 0x89, 0x01, 0xbb, 0xe9, 0x9b, 0xb2, 0xc3, 0x22, - 0xac, 0x68, 0xe3, 0xf0, 0x6c, 0x02, 0xce, 0x68, 0xa6, 0xc4, 0xd0, 0xa7, 0x06, 0x90, 0x9c, - 0xaa, 0x1b, 0x08, 0x1d, 0x8b, 0x43, 0x9a, 0x33, 0x67, 0x44, 0x6d, 0x21, 0xa3, 0x1b, 0x88, - 0x9a, 0x97, 0x5e, 0x59, 0xc4, 0x15, 0x0b, 0xd9, 0x2c, 0xbd, 0x51, 0x07, 0x61, 0x82, 0xad, - 0xc1, 0xb8, 0xd7, 0xbf, 0x9b, 0xcf, 0x7d, 0x24, 0xc2, 0x63, 0xf3, 0x97, 0x17, 0xeb, 0xfe, - 0x62, 0x25, 0xba, 0x5b, 0x4d, 0x8a, 0xc2, 0x7a, 0xbd, 0x43, 0x8a, 0x8f, 0xb8, 0xf2, 0xf1, - 0xc5, 0x6a, 0x30, 0xd3, 0x50, 0x8c, 0xc8, 0x9a, 0xdf, 0xef, 0xed, 0x35, 0xe7, 0x7a, 0x62, - 0xea, 0x76, 0x7c, 0xbb, 0x08, 0x26, 0xc7, 0x02, 0x01, 0x11 -}; - -const uint8_t CERT[] = { - 0x30, 0x81, 0xff, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x33, 0x31, 0x32, 0x32, 0x36, - 0x32, 0x33, 0x32, 0x32, 0x35, 0x34, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x33, 0x31, 0x32, - 0x32, 0x36, 0x32, 0x33, 0x32, 0x32, 0x35, 0x34, 0x5a, 0x30, 0x12, 0x30, 0x10, 0x06, 0x03, - 0x55, 0x04, 0x29, 0x13, 0x09, 0x54, 0x45, 0x53, 0x54, 0x20, 0x4e, 0x41, 0x4d, 0x45, 0x30, - 0x81, 0x9d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, - 0x05, 0x00, 0x03, 0x81, 0x8b, 0x00, 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e, 0x06, - 0x3e, 0x47, 0x85, 0xb2, 0x34, 0x37, 0xaa, 0x85, 0x47, 0xac, 0x03, 0x24, 0x83, 0xb5, 0x9c, - 0xa8, 0x05, 0x3a, 0x24, 0x1e, 0xeb, 0x89, 0x01, 0xbb, 0xe9, 0x9b, 0xb2, 0xc3, 0x22, 0xac, - 0x68, 0xe3, 0xf0, 0x6c, 0x02, 0xce, 0x68, 0xa6, 0xc4, 0xd0, 0xa7, 0x06, 0x90, 0x9c, 0xaa, - 0x1b, 0x08, 0x1d, 0x8b, 0x43, 0x9a, 0x33, 0x67, 0x44, 0x6d, 0x21, 0xa3, 0x1b, 0x88, 0x9a, - 0x97, 0x5e, 0x59, 0xc4, 0x15, 0x0b, 0xd9, 0x2c, 0xbd, 0x51, 0x07, 0x61, 0x82, 0xad, 0xc1, - 0xb8, 0xd7, 0xbf, 0x9b, 0xcf, 0x7d, 0x24, 0xc2, 0x63, 0xf3, 0x97, 0x17, 0xeb, 0xfe, 0x62, - 0x25, 0xba, 0x5b, 0x4d, 0x8a, 0xc2, 0x7a, 0xbd, 0x43, 0x8a, 0x8f, 0xb8, 0xf2, 0xf1, 0xc5, - 0x6a, 0x30, 0xd3, 0x50, 0x8c, 0xc8, 0x9a, 0xdf, 0xef, 0xed, 0x35, 0xe7, 0x7a, 0x62, 0xea, - 0x76, 0x7c, 0xbb, 0x08, 0x26, 0xc7, 0x02, 0x01, 0x11, 0x30, 0x25, 0x30, 0x23, 0x06, 0x06, - 0x2b, 0x06, 0x01, 0x05, 0x20, 0x01, 0x01, 0x01, 0xff, 0x04, 0x16, 0x30, 0x14, 0x04, 0x0c, - 0x2f, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2f, 0x6b, 0x69, 0x74, 0x74, 0x79, 0x02, 0x01, 0x00, - 0x02, 0x01, 0x0a -}; - -const std::string CERT_INFO = - "Certificate name:\n" - " /\n" - "Validity:\n" - " NotBefore: 20131226T232254\n" - " NotAfter: 20131226T232254\n" - "Subject Description:\n" - " 2.5.4.41: TEST NAME\n" - "Public key bits: (RSA)\n" - " MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCeBj5HhbI0N6qFR6wDJIO1nKgF\n" - " OiQe64kBu+mbssMirGjj8GwCzmimxNCnBpCcqhsIHYtDmjNnRG0hoxuImpdeWcQV\n" - " C9ksvVEHYYKtwbjXv5vPfSTCY/OXF+v+YiW6W02Kwnq9Q4qPuPLxxWow01CMyJrf\n" - " 7+0153pi6nZ8uwgmxwIB\n" - "Signature Information:\n" - " Signature Type: Unknown Signature Type\n"; - -BOOST_AUTO_TEST_CASE(Encode) -{ - Certificate certificate; - - // validity - // not before 12/26/2013 @ 11:22pm - certificate.setNotBefore(time::fromUnixTimestamp(time::milliseconds(1388100174000LL))); - // not after 12/26/2013 @ 11:22pm - certificate.setNotAfter(time::fromUnixTimestamp(time::milliseconds(1388100174000LL))); - - // subject - certificate.addSubjectDescription(CertificateSubjectDescription(oid::ATTRIBUTE_NAME, - "TEST NAME")); - - // publicKeyInfo - PublicKey key(PUBLIC_KEY, sizeof(PUBLIC_KEY)); - certificate.setPublicKeyInfo(key); - - // extensions - BOOST_REQUIRE_NO_THROW({ - std::string extenstionValue; - StringSink sink(extenstionValue); - DERSequenceEncoder seq(sink); - { - std::string name("/hello/kitty"); - DEREncodeOctetString(seq, reinterpret_cast(name.c_str()), name.size()); - // trustClass - DEREncodeUnsigned(seq, 0); - // trustLevel - DEREncodeUnsigned(seq, 10); - } - seq.MessageEnd(); - - //create a randome extension - certificate.addExtension(CertificateExtension(Oid("1.3.6.1.5.32.1"), true, - reinterpret_cast(extenstionValue.c_str()), - extenstionValue.size())); - }); - // RSA::PublicKey p; - // StringSource source(T, sizeof(T), true); - // p.Load(source); - - BOOST_REQUIRE_NO_THROW(certificate.encode()); - - // ofstream of("cert.out"); - // of.write((const char*certificate.getContent().value(), certificate.getContent().value_size()); - - // const Block &wire = i.wireEncode(); - BOOST_REQUIRE_EQUAL_COLLECTIONS(CERT, CERT+sizeof(CERT), - certificate.getContent().value_begin(), - certificate.getContent().value_end()); - - std::ostringstream os; - os << certificate; - std::string info(os.str()); - - BOOST_CHECK_EQUAL(CERT_INFO, info); -} - -const unsigned char REAL_CERT[] = { - 0x30, 0x82, 0x01, 0x63, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x33, 0x31, 0x31, 0x30, - 0x31, 0x31, 0x37, 0x31, 0x31, 0x32, 0x32, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x34, 0x31, - 0x31, 0x30, 0x31, 0x31, 0x37, 0x31, 0x31, 0x32, 0x32, 0x5a, 0x30, 0x19, 0x30, 0x17, 0x06, - 0x03, 0x55, 0x04, 0x29, 0x13, 0x10, 0x4e, 0x44, 0x4e, 0x20, 0x54, 0x65, 0x73, 0x74, 0x62, - 0x65, 0x64, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x82, 0x01, 0x20, 0x30, 0x0d, 0x06, 0x09, - 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0d, - 0x00, 0x30, 0x82, 0x01, 0x08, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd3, 0xac, 0x7e, 0x7a, 0x5c, - 0x33, 0x58, 0x21, 0xda, 0xe0, 0x8d, 0xdb, 0xca, 0xb6, 0x02, 0x30, 0x02, 0x15, 0xc5, 0x0a, - 0x51, 0x54, 0xbb, 0x8e, 0x5e, 0x9d, 0x21, 0xf8, 0x14, 0xbe, 0xe4, 0x63, 0x60, 0x31, 0x53, - 0xe2, 0xef, 0xee, 0x34, 0xa3, 0x8c, 0xd2, 0x24, 0x6f, 0xa4, 0x89, 0x4f, 0x02, 0x20, 0x7d, - 0x66, 0xb6, 0x3f, 0x11, 0x40, 0x0c, 0xc1, 0x5f, 0xd8, 0x45, 0x23, 0x95, 0x40, 0xc8, 0xe0, - 0xbc, 0x9d, 0x2f, 0x03, 0xf1, 0x83, 0x9f, 0x07, 0x0b, 0x76, 0xc9, 0x10, 0xd9, 0x3e, 0x0b, - 0x75, 0x13, 0x93, 0xe9, 0xc9, 0x85, 0x01, 0x88, 0x36, 0x2e, 0xab, 0xfc, 0xe6, 0x24, 0x32, - 0xfc, 0xc6, 0x3c, 0x40, 0x97, 0x1a, 0xcc, 0xcd, 0x53, 0xaa, 0x0f, 0xfb, 0xa3, 0xfe, 0xf9, - 0x24, 0x70, 0x13, 0x3f, 0x4f, 0x5b, 0x7d, 0x43, 0xaa, 0x75, 0x0a, 0x94, 0x72, 0xab, 0xe1, - 0x8c, 0x45, 0xb5, 0x78, 0x10, 0x01, 0xef, 0x1f, 0xb3, 0x05, 0x6f, 0xa6, 0xc3, 0xac, 0x7f, - 0x6d, 0xf0, 0x31, 0xc4, 0x83, 0xb3, 0x4f, 0x50, 0x26, 0x92, 0x40, 0x1a, 0xdd, 0xec, 0xfb, - 0xcb, 0xef, 0x63, 0xfe, 0x41, 0xd8, 0x8d, 0x1f, 0xdc, 0xec, 0xfc, 0x48, 0x95, 0xcc, 0x09, - 0x1e, 0x30, 0x6e, 0x22, 0x9e, 0x24, 0x97, 0x2e, 0xe6, 0x0c, 0xdf, 0x3d, 0x20, 0x32, 0xaa, - 0x9c, 0xc9, 0x45, 0x14, 0xaf, 0xaa, 0xf5, 0x17, 0xd2, 0x01, 0x98, 0x33, 0xbe, 0x2a, 0x9f, - 0x7b, 0x9d, 0x98, 0x7c, 0x54, 0x22, 0xfe, 0x72, 0x72, 0x04, 0xc3, 0x2c, 0xc0, 0x14, 0x0b, - 0xa9, 0x40, 0x7e, 0x46, 0xa1, 0x75, 0x16, 0x1a, 0x27, 0x9e, 0xf2, 0x82, 0x96, 0xc0, 0x7d, - 0xaf, 0x18, 0x75, 0xfb, 0xbb, 0xab, 0x16, 0x66, 0xc0, 0xa9, 0xd7, 0x93, 0x4c, 0x48, 0x6d, - 0xce, 0x0b, 0x88, 0xd4, 0x21, 0x93, 0x84, 0x89, 0x55, 0x05, 0xd5, 0x02, 0x01, 0x11 -}; - -const std::string REAL_CERT_INFO = "Certificate name:\n" - " /tmp\n" - "Validity:\n" - " NotBefore: 20131101T171122\n" - " NotAfter: 20141101T171122\n" - "Subject Description:\n" - " 2.5.4.41: NDN Testbed Root\n" - "Public key bits: (RSA)\n" - " MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA06x+elwzWCHa4I3byrYC\n" - " MAIVxQpRVLuOXp0h+BS+5GNgMVPi7+40o4zSJG+kiU8CIH1mtj8RQAzBX9hFI5VA\n" - " yOC8nS8D8YOfBwt2yRDZPgt1E5PpyYUBiDYuq/zmJDL8xjxAlxrMzVOqD/uj/vkk\n" - " cBM/T1t9Q6p1CpRyq+GMRbV4EAHvH7MFb6bDrH9t8DHEg7NPUCaSQBrd7PvL72P+\n" - " QdiNH9zs/EiVzAkeMG4iniSXLuYM3z0gMqqcyUUUr6r1F9IBmDO+Kp97nZh8VCL+\n" - " cnIEwyzAFAupQH5GoXUWGiee8oKWwH2vGHX7u6sWZsCp15NMSG3OC4jUIZOEiVUF\n" - " 1QIB\n" - "Signature Information:\n" - " Signature Type: Unknown Signature Type\n"; - -const uint8_t SELF_SIGNED_ECDSA_CERT[] = { - 0x06, 0xfd, 0x01, 0x5b, 0x07, 0x33, 0x08, 0x05, 0x65, 0x63, 0x64, 0x73, 0x61, 0x08, 0x03, - 0x4b, 0x45, 0x59, 0x08, 0x11, 0x6b, 0x73, 0x6b, 0x2d, 0x31, 0x34, 0x31, 0x36, 0x35, 0x39, - 0x34, 0x35, 0x35, 0x32, 0x38, 0x32, 0x37, 0x08, 0x07, 0x49, 0x44, 0x2d, 0x43, 0x45, 0x52, - 0x54, 0x08, 0x09, 0xfd, 0x00, 0x00, 0x01, 0x49, 0xd3, 0x9d, 0x78, 0x00, 0x14, 0x03, 0x18, - 0x01, 0x02, 0x15, 0xa5, 0x30, 0x81, 0xa2, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x34, - 0x31, 0x31, 0x32, 0x31, 0x31, 0x38, 0x32, 0x39, 0x31, 0x32, 0x5a, 0x18, 0x0f, 0x32, 0x30, - 0x33, 0x34, 0x31, 0x31, 0x31, 0x36, 0x31, 0x38, 0x32, 0x39, 0x31, 0x32, 0x5a, 0x30, 0x21, - 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x29, 0x13, 0x18, 0x2f, 0x65, 0x63, 0x64, 0x73, 0x61, - 0x2f, 0x6b, 0x73, 0x6b, 0x2d, 0x31, 0x34, 0x31, 0x36, 0x35, 0x39, 0x34, 0x35, 0x35, 0x32, - 0x38, 0x32, 0x37, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, - 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, - 0x83, 0xe5, 0x81, 0x19, 0xd9, 0xfa, 0x64, 0x40, 0xad, 0x7c, 0x93, 0xfc, 0x15, 0x90, 0x6b, - 0x38, 0x1e, 0xc5, 0xca, 0xb1, 0x6b, 0x0b, 0x1f, 0x64, 0xbf, 0x48, 0xaa, 0xd0, 0x91, 0x5c, - 0x24, 0xd6, 0x78, 0x40, 0xfd, 0x95, 0x5d, 0x54, 0x64, 0xe1, 0x2d, 0x0e, 0x98, 0x66, 0x1d, - 0x7a, 0xb0, 0x61, 0x17, 0x05, 0x26, 0x13, 0x63, 0x25, 0x7c, 0xda, 0x87, 0x11, 0xc9, 0x67, - 0xcd, 0x12, 0x05, 0xf0, 0x16, 0x2f, 0x1b, 0x01, 0x03, 0x1c, 0x2a, 0x07, 0x28, 0x08, 0x05, - 0x65, 0x63, 0x64, 0x73, 0x61, 0x08, 0x03, 0x4b, 0x45, 0x59, 0x08, 0x11, 0x6b, 0x73, 0x6b, - 0x2d, 0x31, 0x34, 0x31, 0x36, 0x35, 0x39, 0x34, 0x35, 0x35, 0x32, 0x38, 0x32, 0x37, 0x08, - 0x07, 0x49, 0x44, 0x2d, 0x43, 0x45, 0x52, 0x54, 0x17, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, - 0x9b, 0xae, 0xf4, 0x87, 0x55, 0xaa, 0x78, 0xbf, 0x00, 0xff, 0x1a, 0xbe, 0x90, 0x46, 0x6e, - 0xdd, 0xe6, 0x3b, 0x44, 0xfd, 0x41, 0x04, 0x86, 0xcc, 0x6a, 0x8b, 0x5a, 0x25, 0xbb, 0xf1, - 0x55, 0xcd, 0x02, 0x20, 0x0e, 0x67, 0xd8, 0x86, 0xe8, 0x7c, 0x90, 0x3c, 0x13, 0xfd, 0x36, - 0x9c, 0xbc, 0xa1, 0xc3, 0x7c, 0xe0, 0x0c, 0x6d, 0x64, 0xac, 0xdb, 0x69, 0x99, 0xde, 0x80, - 0x35, 0x3f, 0xf4, 0x6a, 0xcd, 0x6f -}; - -const std::string SELF_SIGNED_ECDSA_CERT_INFO = - "Certificate name:\n" - " /ecdsa/KEY/ksk-1416594552827/ID-CERT/%FD%00%00%01I%D3%9Dx%00\n" - "Validity:\n" - " NotBefore: 20141121T182912\n" - " NotAfter: 20341116T182912\n" - "Subject Description:\n" - " 2.5.4.41: /ecdsa/ksk-1416594552827\n" - "Public key bits: (ECDSA)\n" - " MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEg+WBGdn6ZECtfJP8FZBrOB7FyrFr\n" - " Cx9kv0iq0JFcJNZ4QP2VXVRk4S0OmGYderBhFwUmE2MlfNqHEclnzRIF\n" - "Signature Information:\n" - " Signature Type: SignatureSha256WithEcdsa\n" - " Key Locator: (Self-Signed) /ecdsa/KEY/ksk-1416594552827/ID-CERT\n"; - -const uint8_t RSA_CERT[] = { - 0x06, 0xfd, 0x02, 0xd7, 0x07, 0x38, 0x08, 0x03, 0x6e, 0x64, 0x6e, 0x08, 0x03, 0x4b, 0x45, - 0x59, 0x08, 0x05, 0x73, 0x69, 0x74, 0x65, 0x31, 0x08, 0x11, 0x6b, 0x73, 0x6b, 0x2d, 0x31, - 0x34, 0x31, 0x36, 0x34, 0x32, 0x35, 0x33, 0x37, 0x37, 0x30, 0x39, 0x34, 0x08, 0x07, 0x49, - 0x44, 0x2d, 0x43, 0x45, 0x52, 0x54, 0x08, 0x09, 0xfd, 0x00, 0x00, 0x01, 0x49, 0xc9, 0x8b, - 0x2e, 0x73, 0x14, 0x03, 0x18, 0x01, 0x02, 0x15, 0xfd, 0x01, 0x61, 0x30, 0x82, 0x01, 0x5d, - 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x34, 0x31, 0x31, 0x31, 0x39, 0x31, 0x39, 0x33, - 0x33, 0x30, 0x32, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x35, 0x31, 0x31, 0x31, 0x39, 0x31, - 0x39, 0x33, 0x33, 0x30, 0x32, 0x5a, 0x30, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x29, - 0x13, 0x0a, 0x2f, 0x6e, 0x64, 0x6e, 0x2f, 0x73, 0x69, 0x74, 0x65, 0x31, 0x30, 0x82, 0x01, - 0x20, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, - 0x00, 0x03, 0x82, 0x01, 0x0d, 0x00, 0x30, 0x82, 0x01, 0x08, 0x02, 0x82, 0x01, 0x01, 0x00, - 0xb6, 0x54, 0x7e, 0xe8, 0xf2, 0x91, 0x7d, 0xc1, 0x6d, 0xcb, 0x25, 0x44, 0x97, 0x90, 0xdc, - 0x78, 0x15, 0x0e, 0xef, 0xb5, 0xe7, 0xfd, 0x09, 0x2c, 0xf8, 0xd5, 0x9c, 0x2f, 0xe5, 0xa6, - 0xae, 0x9d, 0x7e, 0x95, 0x2d, 0xfc, 0xc7, 0xc3, 0x43, 0x46, 0xb0, 0x6f, 0x53, 0xcd, 0xcd, - 0x6a, 0x29, 0x1d, 0x95, 0xa1, 0x62, 0xcd, 0xa9, 0xf2, 0xf8, 0xe2, 0xfa, 0x8b, 0x5d, 0xfe, - 0xa1, 0x2b, 0x15, 0x3f, 0x7f, 0x71, 0xe6, 0x3e, 0xb9, 0xb1, 0x29, 0xd1, 0x22, 0x6f, 0x56, - 0xdf, 0xb6, 0x85, 0xaf, 0xd4, 0xb3, 0x67, 0x8b, 0x94, 0xb8, 0x83, 0xcb, 0x72, 0x86, 0xc4, - 0xf2, 0x86, 0xb2, 0x7c, 0x94, 0xbc, 0x38, 0x7b, 0x8c, 0x92, 0x86, 0x36, 0x83, 0x0e, 0x11, - 0x8c, 0x95, 0x49, 0xff, 0xcc, 0x16, 0x62, 0xdb, 0x55, 0x40, 0x7f, 0xc8, 0x8d, 0xe4, 0x3f, - 0x87, 0x02, 0x87, 0xaf, 0xf6, 0x2f, 0x8a, 0x7d, 0x74, 0x10, 0xd3, 0xbb, 0xa3, 0xfe, 0x5a, - 0x7b, 0x8f, 0x56, 0x09, 0x8b, 0x49, 0x46, 0x9f, 0x7d, 0x55, 0xa3, 0x4a, 0xe8, 0x22, 0x7b, - 0x80, 0x8a, 0x6f, 0xde, 0x9f, 0xfb, 0x2f, 0xeb, 0xf7, 0x29, 0x8a, 0x38, 0x67, 0x41, 0xae, - 0x21, 0x7a, 0xe3, 0x7b, 0x96, 0x1a, 0x90, 0x35, 0x7d, 0x04, 0xaa, 0x4d, 0x9f, 0xe6, 0xd6, - 0x00, 0x17, 0x4e, 0x02, 0x34, 0x6c, 0x56, 0x3a, 0x81, 0x3c, 0xb4, 0x7f, 0x98, 0x48, 0x22, - 0xa0, 0x9f, 0x53, 0x35, 0xf9, 0x4e, 0xae, 0x8f, 0xc3, 0xfa, 0x0b, 0x93, 0xd4, 0x55, 0x78, - 0x05, 0xb0, 0x40, 0x44, 0x48, 0x74, 0xb7, 0x9b, 0x2d, 0x65, 0xf0, 0x3d, 0x2e, 0x87, 0x2b, - 0x48, 0x29, 0x12, 0x85, 0xf0, 0xaf, 0xc4, 0xdc, 0x73, 0xce, 0x18, 0x8b, 0xd9, 0x4c, 0x60, - 0x15, 0x51, 0xae, 0x47, 0x1e, 0x2b, 0x54, 0xde, 0xf6, 0xba, 0x77, 0x30, 0x5d, 0x68, 0x9a, - 0xfb, 0x02, 0x01, 0x11, 0x16, 0x2d, 0x1b, 0x01, 0x01, 0x1c, 0x28, 0x07, 0x26, 0x08, 0x03, - 0x6e, 0x64, 0x6e, 0x08, 0x03, 0x4b, 0x45, 0x59, 0x08, 0x11, 0x6b, 0x73, 0x6b, 0x2d, 0x31, - 0x34, 0x31, 0x36, 0x34, 0x32, 0x35, 0x32, 0x39, 0x35, 0x35, 0x34, 0x36, 0x08, 0x07, 0x49, - 0x44, 0x2d, 0x43, 0x45, 0x52, 0x54, 0x17, 0xfd, 0x01, 0x00, 0x26, 0x40, 0xbc, 0xf0, 0x28, - 0x12, 0x69, 0x94, 0x11, 0x13, 0xff, 0x47, 0x2c, 0x6b, 0x12, 0xdd, 0xfa, 0x60, 0x92, 0xe9, - 0x59, 0x10, 0x98, 0xd8, 0x11, 0x2a, 0xf0, 0x25, 0xb0, 0x03, 0xb2, 0xda, 0xd3, 0xb6, 0xa9, - 0xfb, 0x8b, 0xc3, 0x6f, 0xfb, 0xb4, 0x93, 0x9b, 0x24, 0x9f, 0x7e, 0x63, 0x8a, 0x37, 0xea, - 0x88, 0x74, 0xac, 0x0c, 0x04, 0x5b, 0xa2, 0x39, 0x0c, 0xa1, 0x9e, 0x0e, 0xa2, 0xd6, 0x74, - 0xca, 0xc4, 0x92, 0x64, 0x9f, 0xc2, 0x68, 0x56, 0xef, 0xc5, 0x11, 0xe8, 0x7a, 0xf3, 0x21, - 0xde, 0x88, 0x40, 0x70, 0x2b, 0x44, 0xe0, 0xcb, 0x3b, 0x33, 0xc6, 0x53, 0x65, 0x70, 0x56, - 0x08, 0xe2, 0x22, 0x70, 0x9e, 0xe0, 0x38, 0x18, 0xa8, 0x7c, 0x7d, 0x09, 0x15, 0xac, 0xf1, - 0x44, 0x63, 0x5d, 0xd5, 0x59, 0xf4, 0xeb, 0x60, 0x6c, 0x6e, 0x77, 0x36, 0x20, 0x2a, 0xe2, - 0xd1, 0x2d, 0xa1, 0x7d, 0xd4, 0x6d, 0x29, 0x2d, 0x88, 0xde, 0x9e, 0xf8, 0x64, 0x41, 0x6a, - 0xeb, 0x9f, 0x3b, 0x52, 0x06, 0xb1, 0x94, 0x09, 0x3b, 0xc9, 0xba, 0xa0, 0x05, 0x31, 0x2d, - 0x49, 0x17, 0x5b, 0xc1, 0x62, 0xf5, 0x19, 0xce, 0x27, 0x7b, 0xe8, 0x4b, 0xeb, 0x80, 0x36, - 0xf3, 0xd7, 0xe9, 0x59, 0x22, 0x50, 0x5a, 0x14, 0xb0, 0x1a, 0xa5, 0x6b, 0x33, 0xb2, 0x83, - 0x72, 0x11, 0xf4, 0xd5, 0xd2, 0x32, 0x93, 0x94, 0xb6, 0x8d, 0xed, 0xcd, 0xce, 0x54, 0x79, - 0xe8, 0xc3, 0x3c, 0xa8, 0xc6, 0x71, 0xa7, 0x61, 0xba, 0x70, 0x44, 0x94, 0xc9, 0xfc, 0xd0, - 0x20, 0x00, 0x87, 0xdc, 0xf3, 0x3c, 0x47, 0x1b, 0x4f, 0x91, 0x4c, 0xc7, 0x49, 0xb7, 0xe4, - 0xe3, 0x84, 0xb7, 0x82, 0x52, 0xec, 0x91, 0xa9, 0x28, 0x38, 0x2d, 0x48, 0x89, 0xc7, 0xcf, - 0xfa, 0x63, 0x0b, 0xf0, 0x62, 0x51, 0xac, 0xe9, 0xdb, 0xfd, 0x1c -}; - -const std::string RSA_CERT_INFO = - "Certificate name:\n" - " /ndn/KEY/site1/ksk-1416425377094/ID-CERT/%FD%00%00%01I%C9%8B.s\n" - "Validity:\n" - " NotBefore: 20141119T193302\n" - " NotAfter: 20151119T193302\n" - "Subject Description:\n" - " 2.5.4.41: /ndn/site1\n" - "Public key bits: (RSA)\n" - " MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAtlR+6PKRfcFtyyVEl5Dc\n" - " eBUO77Xn/Qks+NWcL+Wmrp1+lS38x8NDRrBvU83NaikdlaFizany+OL6i13+oSsV\n" - " P39x5j65sSnRIm9W37aFr9SzZ4uUuIPLcobE8oayfJS8OHuMkoY2gw4RjJVJ/8wW\n" - " YttVQH/IjeQ/hwKHr/Yvin10ENO7o/5ae49WCYtJRp99VaNK6CJ7gIpv3p/7L+v3\n" - " KYo4Z0GuIXrje5YakDV9BKpNn+bWABdOAjRsVjqBPLR/mEgioJ9TNflOro/D+guT\n" - " 1FV4BbBAREh0t5stZfA9LocrSCkShfCvxNxzzhiL2UxgFVGuRx4rVN72uncwXWia\n" - " +wIB\n" - "Signature Information:\n" - " Signature Type: SignatureSha256WithRsa\n" - " Key Locator: (Name) /ndn/KEY/ksk-1416425295546/ID-CERT\n"; - -BOOST_AUTO_TEST_CASE(Decode) -{ - ndn::Data data("/tmp"); - data.setContent(REAL_CERT, sizeof(REAL_CERT)); - - Certificate certificate(data); - - std::ostringstream os; - os << certificate; - std::string info(os.str()); - - BOOST_CHECK_EQUAL(REAL_CERT_INFO, info); - - - ndn::Block selfSignedCertBlock(SELF_SIGNED_ECDSA_CERT, sizeof(SELF_SIGNED_ECDSA_CERT)); - Certificate selfSignedCert; - selfSignedCert.wireDecode(selfSignedCertBlock); - - std::ostringstream selfSignedCertOs; - selfSignedCertOs << selfSignedCert; - std::string selfSignedCertInfo(selfSignedCertOs.str()); - - BOOST_CHECK_EQUAL(SELF_SIGNED_ECDSA_CERT_INFO, selfSignedCertInfo); - - - ndn::Block rsaCertBlock(RSA_CERT, sizeof(RSA_CERT)); - Certificate rsaCert; - rsaCert.wireDecode(rsaCertBlock); - - std::ostringstream rsaCertOs; - rsaCertOs << rsaCert; - std::string rsaCertInfo(rsaCertOs.str()); - - BOOST_CHECK_EQUAL(RSA_CERT_INFO, rsaCertInfo); -} - -const uint8_t WRONG_CERT[] = { // first byte is wrong and an error will be thrown out - 0x31, 0x82, 0x01, 0x63, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x33, 0x31, 0x31, 0x30, - 0x31, 0x31, 0x37, 0x31, 0x31, 0x32, 0x32, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x34, 0x31, - 0x31, 0x30, 0x31, 0x31, 0x37, 0x31, 0x31, 0x32, 0x32, 0x5a, 0x30, 0x19, 0x30, 0x17, 0x06, - 0x03, 0x55, 0x04, 0x29, 0x13, 0x10, 0x4e, 0x44, 0x4e, 0x20, 0x54, 0x65, 0x73, 0x74, 0x62, - 0x65, 0x64, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x82, 0x01, 0x20, 0x30, 0x0d, 0x06, 0x09, - 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0d, - 0x00, 0x30, 0x82, 0x01, 0x08, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd3, 0xac, 0x7e, 0x7a, 0x5c, - 0x33, 0x58, 0x21, 0xda, 0xe0, 0x8d, 0xdb, 0xca, 0xb6, 0x02, 0x30, 0x02, 0x15, 0xc5, 0x0a, - 0x51, 0x54, 0xbb, 0x8e, 0x5e, 0x9d, 0x21, 0xf8, 0x14, 0xbe, 0xe4, 0x63, 0x60, 0x31, 0x53, - 0xe2, 0xef, 0xee, 0x34, 0xa3, 0x8c, 0xd2, 0x24, 0x6f, 0xa4, 0x89, 0x4f, 0x02, 0x20, 0x7d, - 0x66, 0xb6, 0x3f, 0x11, 0x40, 0x0c, 0xc1, 0x5f, 0xd8, 0x45, 0x23, 0x95, 0x40, 0xc8, 0xe0, - 0xbc, 0x9d, 0x2f, 0x03, 0xf1, 0x83, 0x9f, 0x07, 0x0b, 0x76, 0xc9, 0x10, 0xd9, 0x3e, 0x0b, - 0x75, 0x13, 0x93, 0xe9, 0xc9, 0x85, 0x01, 0x88, 0x36, 0x2e, 0xab, 0xfc, 0xe6, 0x24, 0x32, - 0xfc, 0xc6, 0x3c, 0x40, 0x97, 0x1a, 0xcc, 0xcd, 0x53, 0xaa, 0x0f, 0xfb, 0xa3, 0xfe, 0xf9, - 0x24, 0x70, 0x13, 0x3f, 0x4f, 0x5b, 0x7d, 0x43, 0xaa, 0x75, 0x0a, 0x94, 0x72, 0xab, 0xe1, - 0x8c, 0x45, 0xb5, 0x78, 0x10, 0x01, 0xef, 0x1f, 0xb3, 0x05, 0x6f, 0xa6, 0xc3, 0xac, 0x7f, - 0x6d, 0xf0, 0x31, 0xc4, 0x83, 0xb3, 0x4f, 0x50, 0x26, 0x92, 0x40, 0x1a, 0xdd, 0xec, 0xfb, - 0xcb, 0xef, 0x63, 0xfe, 0x41, 0xd8, 0x8d, 0x1f, 0xdc, 0xec, 0xfc, 0x48, 0x95, 0xcc, 0x09, - 0x1e, 0x30, 0x6e, 0x22, 0x9e, 0x24, 0x97, 0x2e, 0xe6, 0x0c, 0xdf, 0x3d, 0x20, 0x32, 0xaa, - 0x9c, 0xc9, 0x45, 0x14, 0xaf, 0xaa, 0xf5, 0x17, 0xd2, 0x01, 0x98, 0x33, 0xbe, 0x2a, 0x9f, - 0x7b, 0x9d, 0x98, 0x7c, 0x54, 0x22, 0xfe, 0x72, 0x72, 0x04, 0xc3, 0x2c, 0xc0, 0x14, 0x0b, - 0xa9, 0x40, 0x7e, 0x46, 0xa1, 0x75, 0x16, 0x1a, 0x27, 0x9e, 0xf2, 0x82, 0x96, 0xc0, 0x7d, - 0xaf, 0x18, 0x75, 0xfb, 0xbb, 0xab, 0x16, 0x66, 0xc0, 0xa9, 0xd7, 0x93, 0x4c, 0x48, 0x6d, - 0xce, 0x0b, 0x88, 0xd4, 0x21, 0x93, 0x84, 0x89, 0x55, 0x05, 0xd5, 0x02, 0x01, 0x11 -}; - -BOOST_AUTO_TEST_CASE(DecodeError) -{ - ndn::Data data("/tmp"); - data.setContent(WRONG_CERT, sizeof(WRONG_CERT)); - - BOOST_CHECK_THROW(Certificate certificate(data), Certificate::Error); -} - -BOOST_AUTO_TEST_SUITE_END() // TestCertificate -BOOST_AUTO_TEST_SUITE_END() // V1 -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace v1 -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/v1/public-key.t.cpp b/tests/unit-tests/security/v1/public-key.t.cpp deleted file mode 100644 index 53df40c64..000000000 --- a/tests/unit-tests/security/v1/public-key.t.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/v1/public-key.hpp" -#include "security/v1/cryptopp.hpp" -#include "encoding/buffer-stream.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace security { -namespace v1 { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_AUTO_TEST_SUITE(V1) -BOOST_AUTO_TEST_SUITE(TestPublicKey) - -const std::string RSA_DER("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuFoDcNtffwbfFix64fw0\ -hI2tKMkFrc6Ex7yw0YLMK9vGE8lXOyBl/qXabow6RCz+GldmFN6E2Qhm1+AX3Zm5\ -sj3H53/HPtzMefvMQ9X7U+lK8eNMWawpRzvBh4/36VrK/awlkNIVIQ9aXj6q6BVe\ -zL+zWT/WYemLq/8A1/hHWiwCtfOH1xQhGqWHJzeSgwIgOOrzxTbRaCjhAb1u2TeV\ -yx/I9H/DV+AqSHCaYbB92HDcDN0kqwSnUf5H1+osE9MR5DLBLhXdSiULSgxT3Or/\ -y2QgsgUK59WrjhlVMPEiHHRs15NZJbL1uQFXjgScdEarohcY3dilqotineFZCeN8\ -DwIDAQAB"); - -const uint8_t RSA_DER_KEY_DIGEST[] = { - 0x1d, 0x20, - 0x58, 0x72, 0x4c, 0xf7, 0x36, 0x3d, 0xee, 0x4a, - 0x5c, 0x5b, 0x39, 0x44, 0x2d, 0xf6, 0x1a, 0x24, - 0xda, 0x13, 0xac, 0xab, 0x70, 0xf7, 0x74, 0x40, - 0x5a, 0x44, 0xfe, 0xc0, 0xc9, 0x26, 0x58, 0x74 -}; - -const std::string ECDSA_DER("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENZpqkPJDj8uhSpffOiCbvSYMLsGB\ -1Eo/WU6mrexjGvduQXjqwon/eSHFI6EgHZk8L9KfiV5XVtVsk2g5wIpJVg=="); - -const uint8_t ECDSA_DER_KEY_DIGEST[] = { - 0x1d, 0x20, - 0xaf, 0x82, 0x3f, 0xfc, 0xdc, 0x85, 0xb2, 0xa4, - 0xc8, 0xf5, 0x3b, 0x1a, 0xf8, 0xec, 0x4a, 0x55, - 0x97, 0x55, 0x19, 0x3f, 0x54, 0xdd, 0xd0, 0xfd, - 0xb5, 0x9d, 0x80, 0x65, 0x80, 0x6b, 0x4b, 0x63 -}; - -BOOST_AUTO_TEST_CASE(Rsa) -{ - using namespace CryptoPP; - - OBufferStream os; - StringSource ss(reinterpret_cast(RSA_DER.c_str()), RSA_DER.size(), - true, new Base64Decoder(new FileSink(os))); - - shared_ptr publicKey; - BOOST_REQUIRE_NO_THROW(publicKey = shared_ptr(new PublicKey(os.buf()->buf(), - os.buf()->size()))); - - BOOST_CHECK_EQUAL(publicKey->getKeyType(), KeyType::RSA); - - Block digestBlock(RSA_DER_KEY_DIGEST, sizeof(RSA_DER_KEY_DIGEST)); - const Block& digest = publicKey->computeDigest(); - BOOST_CHECK_EQUAL_COLLECTIONS(digestBlock.wire(), - digestBlock.wire() + digestBlock.size(), - digest.wire(), - digest.wire() + digest.size()); -} - -BOOST_AUTO_TEST_CASE(Ecdsa) -{ - using namespace CryptoPP; - - OBufferStream os; - StringSource ss(reinterpret_cast(ECDSA_DER.c_str()), ECDSA_DER.size(), - true, new Base64Decoder(new FileSink(os))); - - shared_ptr publicKey; - BOOST_REQUIRE_NO_THROW(publicKey = shared_ptr(new PublicKey(os.buf()->buf(), - os.buf()->size()))); - - BOOST_CHECK_EQUAL(publicKey->getKeyType(), KeyType::EC); - - Block digestBlock(ECDSA_DER_KEY_DIGEST, sizeof(ECDSA_DER_KEY_DIGEST)); - const Block& digest = publicKey->computeDigest(); - BOOST_CHECK_EQUAL_COLLECTIONS(digestBlock.wire(), - digestBlock.wire() + digestBlock.size(), - digest.wire(), - digest.wire() + digest.size()); -} - -BOOST_AUTO_TEST_SUITE_END() // TestPublicKey -BOOST_AUTO_TEST_SUITE_END() // V1 -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace v1 -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/validator-config.t.cpp b/tests/unit-tests/security/validator-config.t.cpp deleted file mode 100644 index e3f2f99eb..000000000 --- a/tests/unit-tests/security/validator-config.t.cpp +++ /dev/null @@ -1,1494 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/validator-config.hpp" - -#include "security/key-chain.hpp" -#include "security/signing-helpers.hpp" -#include "util/io.hpp" -#include "util/scheduler.hpp" -#include "util/dummy-client-face.hpp" - -#include - -#include "identity-management-fixture.hpp" -#include "../identity-management-time-fixture.hpp" -#include "../make-interest-data.hpp" -#include "boost-test.hpp" - -namespace ndn { -namespace security { -namespace tests { - -using namespace ndn::tests; - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_FIXTURE_TEST_SUITE(TestValidatorConfig, IdentityManagementFixture) - -BOOST_AUTO_TEST_CASE(NameFilter) -{ - Name identity("/TestValidatorConfig/NameFilter"); - identity.appendVersion(); - BOOST_REQUIRE(saveIdentityCertificate(identity, "trust-anchor-1.cert", true)); - Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity); - - Name dataName1("/simple/equal"); - shared_ptr data1 = make_shared(dataName1); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(identity))); - - Name dataName2("/simple/different"); - shared_ptr data2 = make_shared(dataName2); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(identity))); - - std::string CONFIG_1 = - "rule\n" - "{\n" - " id \"Simple Rule\"\n" - " for data\n" - " filter" - " {\n" - " type name\n" - " name /simple/equal\n" - " relation equal\n" - " }\n" - " checker\n" - " {\n" - " type customized\n" - " sig-type rsa-sha256\n" - " key-locator\n" - " {\n" - " type name\n" - " name "; - - std::string CONFIG_2 = - "\n" - " relation equal\n" - " }\n" - " }\n" - "}\n" - "trust-anchor\n" - "{\n" - " type file\n" - " file-name \"trust-anchor-1.cert\"\n" - "}\n"; - const std::string CONFIG = CONFIG_1 + certName.getPrefix(-1).toUri() + CONFIG_2; - - const boost::filesystem::path CONFIG_PATH = - (boost::filesystem::current_path() / std::string("unit-test-nfd.conf")); - - Face face(nullptr, m_keyChain); - ValidatorConfig validator(face); - validator.load(CONFIG, CONFIG_PATH.c_str()); - - validator.validate(*data1, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - validator.validate(*data2, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); -} - -BOOST_AUTO_TEST_CASE(NameFilter2) -{ - Name identity("/TestValidatorConfig/NameFilter2"); - identity.appendVersion(); - BOOST_REQUIRE(saveIdentityCertificate(identity, "trust-anchor-2.cert", true)); - Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity); - - Name dataName1("/simple/isPrefixOf"); - shared_ptr data1 = make_shared(dataName1); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(identity))); - - Name dataName2("/simple/notPrefixOf"); - shared_ptr data2 = make_shared(dataName2); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(identity))); - - Name dataName3("/simple/isPrefixOf/anotherLevel"); - shared_ptr data3 = make_shared(dataName3); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data3, security::signingByIdentity(identity))); - - std::string CONFIG_1 = - "rule\n" - "{\n" - " id \"Simple2 Rule\"\n" - " for data\n" - " filter" - " {\n" - " type name\n" - " name /simple/isPrefixOf\n" - " relation is-prefix-of\n" - " }\n" - " checker\n" - " {\n" - " type customized\n" - " sig-type rsa-sha256\n" - " key-locator\n" - " {\n" - " type name\n" - " name "; - - std::string CONFIG_2 = - "\n" - " relation equal\n" - " }\n" - " }\n" - "}\n" - "trust-anchor\n" - "{\n" - " type file\n" - " file-name \"trust-anchor-2.cert\"\n" - "}\n"; - const std::string CONFIG = CONFIG_1 + certName.getPrefix(-1).toUri() + CONFIG_2; - - const boost::filesystem::path CONFIG_PATH = - (boost::filesystem::current_path() / std::string("unit-test-nfd.conf")); - - Face face(nullptr, m_keyChain); - ValidatorConfig validator(face); - validator.load(CONFIG, CONFIG_PATH.c_str()); - - validator.validate(*data1, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - validator.validate(*data2, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); - - validator.validate(*data3, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); -} - -BOOST_AUTO_TEST_CASE(NameFilter3) -{ - Name identity("/TestValidatorConfig/NameFilter3"); - identity.appendVersion(); - BOOST_REQUIRE(saveIdentityCertificate(identity, "trust-anchor-3.cert", true)); - Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity); - - Name dataName1("/simple/isStrictPrefixOf"); - shared_ptr data1 = make_shared(dataName1); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(identity))); - - Name dataName2("/simple"); - shared_ptr data2 = make_shared(dataName2); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(identity))); - - Name dataName3("/simple/isStrictPrefixOf/anotherLevel"); - shared_ptr data3 = make_shared(dataName3); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data3, security::signingByIdentity(identity))); - - std::string CONFIG_1 = - "rule\n" - "{\n" - " id \"Simple3 Rule\"\n" - " for data\n" - " filter" - " {\n" - " type name\n" - " name /simple/isStrictPrefixOf\n" - " relation is-strict-prefix-of\n" - " }\n" - " checker\n" - " {\n" - " type customized\n" - " sig-type rsa-sha256\n" - " key-locator\n" - " {\n" - " type name\n" - " name "; - - std::string CONFIG_2 = - "\n" - " relation equal\n" - " }\n" - " }\n" - "}\n" - "trust-anchor\n" - "{\n" - " type file\n" - " file-name \"trust-anchor-3.cert\"\n" - "}\n"; - const std::string CONFIG = CONFIG_1 + certName.getPrefix(-1).toUri() + CONFIG_2; - - const boost::filesystem::path CONFIG_PATH = - (boost::filesystem::current_path() / std::string("unit-test-nfd.conf")); - - Face face(nullptr, m_keyChain); - ValidatorConfig validator(face); - validator.load(CONFIG, CONFIG_PATH.c_str()); - - validator.validate(*data1, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); - - validator.validate(*data2, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); - - validator.validate(*data3, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); -} - -BOOST_AUTO_TEST_CASE(NameFilter4) -{ - Name identity("/TestValidatorConfig/NameFilter4"); - identity.appendVersion(); - BOOST_REQUIRE(saveIdentityCertificate(identity, "trust-anchor-4.cert", true)); - Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity); - - Name dataName1("/simple/regex"); - shared_ptr data1 = make_shared(dataName1); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(identity))); - - Name dataName2("/simple/regex-wrong"); - shared_ptr data2 = make_shared(dataName2); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(identity))); - - Name dataName3("/simple/regex/correct"); - shared_ptr data3 = make_shared(dataName3); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data3, security::signingByIdentity(identity))); - - std::string CONFIG_1 = - "rule\n" - "{\n" - " id \"Simple3 Rule\"\n" - " for data\n" - " filter" - " {\n" - " type name\n" - " regex ^\n" - " }\n" - " checker\n" - " {\n" - " type customized\n" - " sig-type rsa-sha256\n" - " key-locator\n" - " {\n" - " type name\n" - " name "; - - std::string CONFIG_2 = - "\n" - " relation equal\n" - " }\n" - " }\n" - "}\n" - "trust-anchor\n" - "{\n" - " type file\n" - " file-name \"trust-anchor-4.cert\"\n" - "}\n"; - const std::string CONFIG = CONFIG_1 + certName.getPrefix(-1).toUri() + CONFIG_2; - - const boost::filesystem::path CONFIG_PATH = - (boost::filesystem::current_path() / std::string("unit-test-nfd.conf")); - - Face face(nullptr, m_keyChain); - ValidatorConfig validator(face); - validator.load(CONFIG, CONFIG_PATH.c_str()); - - validator.validate(*data1, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - validator.validate(*data2, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); - - validator.validate(*data3, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); -} - -BOOST_AUTO_TEST_CASE(KeyLocatorNameChecker1) -{ - Name identity("/TestValidatorConfig/KeyLocatorNameChecker1"); - identity.appendVersion(); - BOOST_REQUIRE(saveIdentityCertificate(identity, "trust-anchor-5.cert", true)); - - Name dataName1 = identity; - dataName1.append("1"); - shared_ptr data1 = make_shared(dataName1); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(identity))); - - Name dataName2 = identity; - shared_ptr data2 = make_shared(dataName2); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(identity))); - - Name dataName3("/TestValidatorConfig/KeyLocatorNameChecker1"); - shared_ptr data3 = make_shared(dataName3); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data3, security::signingByIdentity(identity))); - - const std::string CONFIG = - "rule\n" - "{\n" - " id \"Simple3 Rule\"\n" - " for data\n" - " checker\n" - " {\n" - " type customized\n" - " sig-type rsa-sha256\n" - " key-locator\n" - " {\n" - " type name\n" - " hyper-relation\n" - " {\n" - " k-regex ^([^]*)(<>*)<>$\n" - " k-expand \\\\1\\\\2\n" - " h-relation is-strict-prefix-of\n" - " p-regex ^(<>*)$\n" - " p-expand \\\\1\n" - " }\n" - " }\n" - " }\n" - "}\n" - "trust-anchor\n" - "{\n" - " type file\n" - " file-name \"trust-anchor-5.cert\"\n" - "}\n"; - const boost::filesystem::path CONFIG_PATH = - (boost::filesystem::current_path() / std::string("unit-test-nfd.conf")); - - Face face(nullptr, m_keyChain); - ValidatorConfig validator(face); - validator.load(CONFIG, CONFIG_PATH.c_str()); - - validator.validate(*data1, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - validator.validate(*data2, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); - - validator.validate(*data3, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); -} - -BOOST_AUTO_TEST_CASE(FixedSignerChecker) -{ - Name identity("/TestValidatorConfig/FixedSignerChecker"); - - Name identity1 = identity; - identity1.append("1").appendVersion(); - BOOST_REQUIRE(saveIdentityCertificate(identity1, "trust-anchor-7.cert", true)); - - Name identity2 = identity; - identity2.append("2").appendVersion(); - BOOST_REQUIRE_NO_THROW(addIdentity(identity2)); - - Name dataName1 = identity; - dataName1.append("data").appendVersion(); - shared_ptr data1 = make_shared(dataName1); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(identity1))); - - Name dataName2 = identity; - dataName2.append("data").appendVersion(); - shared_ptr data2 = make_shared(dataName2); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(identity2))); - - Name interestName("/TestValidatorConfig/FixedSignerChecker/fakeSigInfo/fakeSigValue"); - shared_ptr interest = make_shared(interestName); - - const std::string CONFIG = - "rule\n" - "{\n" - " id \"FixedSignerChecker Data Rule\"\n" - " for data\n" - " filter" - " {\n" - " type name\n" - " name /TestValidatorConfig/FixedSignerChecker\n" - " relation is-strict-prefix-of\n" - " }\n" - " checker\n" - " {\n" - " type fixed-signer\n" - " sig-type rsa-sha256\n" - " signer\n" - " {\n" - " type file\n" - " file-name \"trust-anchor-7.cert\"\n" - " }\n" - " }\n" - "}\n" - "rule\n" - "{\n" - " id \"FixedSignerChecker Interest Rule\"\n" - " for interest\n" - " filter" - " {\n" - " type name\n" - " name /TestValidatorConfig/FixedSignerChecker\n" - " relation is-strict-prefix-of\n" - " }\n" - " checker\n" - " {\n" - " type fixed-signer\n" - " sig-type rsa-sha256\n" - " signer\n" - " {\n" - " type file\n" - " file-name \"trust-anchor-7.cert\"\n" - " }\n" - " }\n" - "}\n"; - const boost::filesystem::path CONFIG_PATH = - (boost::filesystem::current_path() / std::string("unit-test-nfd.conf")); - - Face face(nullptr, m_keyChain); - ValidatorConfig validator(face); - validator.load(CONFIG, CONFIG_PATH.c_str()); - - validator.validate(*data1, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - validator.validate(*data2, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); - - validator.validate(*interest, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); -} - -BOOST_AUTO_TEST_CASE(MultiCheckers) -{ - Name identity1("/TestValidatorConfig/MultiCheckers/"); - identity1.appendVersion(); - BOOST_REQUIRE(saveIdentityCertificate(identity1, "trust-anchor-multi-1.cert", true)); - - Name identity2("/TestValidatorConfig/"); - identity2.appendVersion(); - BOOST_REQUIRE(saveIdentityCertificate(identity2, "trust-anchor-multi-2.cert", true)); - - const std::string CONFIG = - "rule\n" - "{\n" - " id \"Simple Rule01\"\n" - " for data\n" - " filter" - " {\n" - " type name\n" - " name /\n" - " relation is-prefix-of\n" - " }\n" - " checker\n" // checker 1, signer should have prefix /TestValidatorConfig/MultiCheckers - " {\n" - " type customized\n" - " sig-type rsa-sha256\n" - " key-locator\n" - " {\n" - " type name\n" - " name /TestValidatorConfig/MultiCheckers/\n" - " relation is-prefix-of\n" - " }\n" - " }\n" - " checker\n" // checker 2, data should have same prefix of its signer - " {\n" - " type hierarchical\n" - " sig-type rsa-sha256\n" - " }\n" - " checker\n" // checker 3, the signer should be identity1 - " {\n" - " type fixed-signer\n" - " sig-type rsa-sha256\n" - " signer\n" - " {\n" - " type file\n" - " file-name \"trust-anchor-multi-1.cert\"\n" - " }\n" - " }\n" - "}\n"; - - const boost::filesystem::path CONFIG_PATH = - (boost::filesystem::current_path() / std::string("unit-test-multicheckers.conf")); - - ValidatorConfig validator; - validator.load(CONFIG, CONFIG_PATH.c_str()); - conf::Checker& checker0 = *validator.m_dataRules.front()->m_checkers[0]; - conf::Checker& checker1 = *validator.m_dataRules.front()->m_checkers[1]; - conf::Checker& checker2 = *validator.m_dataRules.front()->m_checkers[2]; - - auto data1 = makeData(Name(identity1).append("Test")); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(identity1))); - BOOST_CHECK_EQUAL(checker0.check(*data1), 0); - BOOST_CHECK_EQUAL(checker1.check(*data1), 0); - BOOST_CHECK_EQUAL(checker2.check(*data1), 1); - - auto data2 = makeData(Name(identity2).append("Data2")); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(identity2))); - BOOST_CHECK_EQUAL(checker0.check(*data2), -1); - BOOST_CHECK_EQUAL(checker1.check(*data2), 0); - BOOST_CHECK_EQUAL(checker2.check(*data2), -1); - - auto data3 = makeData(Name(identity2).append("Data3")); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data3, security::signingByIdentity(identity1))); - BOOST_CHECK_EQUAL(checker0.check(*data3), 0); - BOOST_CHECK_EQUAL(checker1.check(*data3), -1); - BOOST_CHECK_EQUAL(checker2.check(*data3), 1); - - auto data4 = makeData("/Data4"); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data4, security::signingByIdentity(identity2))); - BOOST_CHECK_EQUAL(checker0.check(*data4), -1); - BOOST_CHECK_EQUAL(checker1.check(*data4), -1); - BOOST_CHECK_EQUAL(checker2.check(*data4), -1); - - int count = 0; - validator.validate(*data1, - [&] (const shared_ptr&) { - BOOST_CHECK(true); - count++; - }, - [] (const shared_ptr&, const std::string& str) { BOOST_CHECK(false); }); - - validator.validate(*data2, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [&] (const shared_ptr&, const std::string& str) { - BOOST_CHECK(true); - count++; - }); - - validator.validate(*data3, - [&] (const shared_ptr&) { - BOOST_CHECK(true); - count++; - }, - [] (const shared_ptr&, const std::string& str) { BOOST_CHECK(false); }); - - validator.validate(*data4, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [&] (const shared_ptr&, const std::string& str) { - BOOST_CHECK(true); - count++; - }); - - BOOST_CHECK_EQUAL(count, 4); -} - -BOOST_AUTO_TEST_CASE(Reset) -{ - Name root("/TestValidatorConfig/Reload"); - BOOST_REQUIRE(saveIdentityCertificate(root, "trust-anchor-8.cert", true)); - - Face face(nullptr, m_keyChain); - - const std::string CONFIG = - "rule\n" - "{\n" - " id \"NRD Prefix Registration Command Rule\"\n" - " for interest\n" - " filter\n" - " {\n" - " type name\n" - " regex ^[]<>$\n" - " }\n" - " checker\n" - " {\n" - " type customized\n" - " sig-type rsa-sha256\n" - " key-locator\n" - " {\n" - " type name\n" - " regex ^[^]*<>*$\n" - " }\n" - " }\n" - "}\n" - "rule\n" - "{\n" - " id \"Testbed Hierarchy Rule\"\n" - " for data\n" - " filter\n" - " {\n" - " type name\n" - " regex ^[^]*<>*<>$\n" - " }\n" - " checker\n" - " {\n" - " type hierarchical\n" - " sig-type rsa-sha256\n" - " }\n" - "}\n" - "trust-anchor\n" - "{\n" - " type file\n" - " file-name \"trust-anchor-8.cert\"\n" - "}\n"; - const boost::filesystem::path CONFIG_PATH = - (boost::filesystem::current_path() / std::string("unit-test-nfd.conf")); - - shared_ptr validator = shared_ptr(new ValidatorConfig(face)); - - validator->load(CONFIG, CONFIG_PATH.c_str()); - BOOST_CHECK_EQUAL(validator->isEmpty(), false); - - validator->reset(); - BOOST_CHECK(validator->isEmpty()); -} - -BOOST_AUTO_TEST_CASE(TrustAnchorWildcard) -{ - Name identity("/TestValidatorConfig/Wildcard"); - identity.appendVersion(); - BOOST_REQUIRE_NO_THROW(addIdentity(identity)); - - Name dataName1("/any/data"); - shared_ptr data1 = make_shared(dataName1); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(identity))); - - std::string CONFIG = - "trust-anchor\n" - "{\n" - " type any\n" - "}\n"; - - const boost::filesystem::path CONFIG_PATH = - (boost::filesystem::current_path() / std::string("unit-test-nfd.conf")); - - Face face(nullptr, m_keyChain); - ValidatorConfig validator(face); - validator.load(CONFIG, CONFIG_PATH.c_str()); - - validator.validate(*data1, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); -} - -BOOST_AUTO_TEST_CASE(SignedInterestTest) -{ - Name identity("/TestValidatorConfig/SignedInterestTest"); - - Name identity1 = identity; - identity1.appendVersion(); - BOOST_REQUIRE(saveIdentityCertificate(identity1, "trust-anchor-9.cert", true)); - - Name interestName("/TestValidatorConfig/SignedInterestTest"); - Name interestName1 = interestName; - interestName1.append("1"); - shared_ptr interest1 = make_shared(interestName1); - Name interestName2 = interestName; - interestName2.append("2"); - shared_ptr interest2 = make_shared(interestName2); - - BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest1, security::signingByIdentity(identity1))); - usleep(10000); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest2, security::signingByIdentity(identity1))); - - const std::string CONFIG = - "rule\n" - "{\n" - " id \"FixedSignerChecker Interest Rule\"\n" - " for interest\n" - " filter" - " {\n" - " type name\n" - " name /TestValidatorConfig/SignedInterestTest\n" - " relation is-strict-prefix-of\n" - " }\n" - " checker\n" - " {\n" - " type fixed-signer\n" - " sig-type rsa-sha256\n" - " signer\n" - " {\n" - " type file\n" - " file-name \"trust-anchor-9.cert\"\n" - " }\n" - " }\n" - "}\n"; - const boost::filesystem::path CONFIG_PATH = - (boost::filesystem::current_path() / std::string("unit-test-nfd.conf")); - - Face face(nullptr, m_keyChain); - ValidatorConfig validator(face); - validator.load(CONFIG, CONFIG_PATH.c_str()); - - validator.validate(*interest1, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - validator.validate(*interest2, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - validator.validate(*interest1, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); -} - - -BOOST_AUTO_TEST_CASE(MaxKeyTest) -{ - Name identity("/TestValidatorConfig/MaxKeyTest"); - - Name identity1 = identity; - identity1.append("Key1"); - BOOST_REQUIRE(saveIdentityCertificate(identity1, "trust-anchor-10-1.cert", true)); - - Name identity2 = identity; - identity2.append("Key2"); - BOOST_REQUIRE(saveIdentityCertificate(identity2, "trust-anchor-10-2.cert", true)); - - Name identity3 = identity; - identity3.append("Key3"); - BOOST_REQUIRE(saveIdentityCertificate(identity3, "trust-anchor-10-3.cert", true)); - - - Name interestName("/TestValidatorConfig/MaxKeyTest"); - Name interestName1 = interestName; - interestName1.append("1"); - shared_ptr interest1 = make_shared(interestName1); - Name interestName2 = interestName; - interestName2.append("2"); - shared_ptr interest2 = make_shared(interestName2); - Name interestName3 = interestName; - interestName3.append("3"); - shared_ptr interest3 = make_shared(interestName3); - - BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest1, security::signingByIdentity(identity1))); - usleep(10000); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest2, security::signingByIdentity(identity2))); - usleep(10000); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest3, security::signingByIdentity(identity3))); - - const std::string CONFIG = - "rule\n" - "{\n" - " id \"FixedSignerChecker Interest Rule\"\n" - " for interest\n" - " filter" - " {\n" - " type name\n" - " name /TestValidatorConfig/MaxKeyTest\n" - " relation is-strict-prefix-of\n" - " }\n" - " checker\n" - " {\n" - " type fixed-signer\n" - " sig-type rsa-sha256\n" - " signer\n" - " {\n" - " type file\n" - " file-name \"trust-anchor-10-1.cert\"\n" - " }\n" - " signer\n" - " {\n" - " type file\n" - " file-name \"trust-anchor-10-2.cert\"\n" - " }\n" - " signer\n" - " {\n" - " type file\n" - " file-name \"trust-anchor-10-3.cert\"\n" - " }\n" - " }\n" - "}\n"; - const boost::filesystem::path CONFIG_PATH = - (boost::filesystem::current_path() / std::string("unit-test-nfd.conf")); - - Face face(nullptr, m_keyChain); - ValidatorConfig validator(face, - ValidatorConfig::DEFAULT_CERTIFICATE_CACHE, - ValidatorConfig::DEFAULT_GRACE_INTERVAL, - 10, - 2, // Two keys can be tracked - time::seconds(1)); // TTL is set to 1 sec - validator.load(CONFIG, CONFIG_PATH.c_str()); - - validator.validate(*interest1, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - validator.validate(*interest2, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - validator.validate(*interest1, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); - - validator.validate(*interest3, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - // Should succeed because identity1's key has been cleaned up due to space limit. - validator.validate(*interest1, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); -} - -BOOST_AUTO_TEST_CASE(MaxKeyTest2) -{ - Name identity("/TestValidatorConfig/MaxKeyTest"); - - Name identity1 = identity; - identity1.append("Key1"); - BOOST_REQUIRE(saveIdentityCertificate(identity1, "trust-anchor-10-1.cert", true)); - - Name identity2 = identity; - identity2.append("Key2"); - BOOST_REQUIRE(saveIdentityCertificate(identity2, "trust-anchor-10-2.cert", true)); - - Name identity3 = identity; - identity3.append("Key3"); - BOOST_REQUIRE(saveIdentityCertificate(identity3, "trust-anchor-10-3.cert", true)); - - Name identity4 = identity; - identity4.append("Key4"); - BOOST_REQUIRE(saveIdentityCertificate(identity4, "trust-anchor-10-4.cert", true)); - - - Name interestName("/TestValidatorConfig/MaxKeyTest"); - Name interestName1 = interestName; - interestName1.append("1"); - shared_ptr interest1 = make_shared(interestName1); - Name interestName2 = interestName; - interestName2.append("2"); - shared_ptr interest2 = make_shared(interestName2); - Name interestName3 = interestName; - interestName3.append("3"); - shared_ptr interest3 = make_shared(interestName3); - Name interestName4 = interestName; - interestName4.append("4"); - shared_ptr interest4 = make_shared(interestName4); - - BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest1, security::signingByIdentity(identity1))); - usleep(10000); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest2, security::signingByIdentity(identity2))); - usleep(10000); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest3, security::signingByIdentity(identity3))); - usleep(10000); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest4, security::signingByIdentity(identity4))); - - const std::string CONFIG = - "rule\n" - "{\n" - " id \"FixedSignerChecker Interest Rule\"\n" - " for interest\n" - " filter" - " {\n" - " type name\n" - " name /TestValidatorConfig/MaxKeyTest\n" - " relation is-strict-prefix-of\n" - " }\n" - " checker\n" - " {\n" - " type fixed-signer\n" - " sig-type rsa-sha256\n" - " signer\n" - " {\n" - " type file\n" - " file-name \"trust-anchor-10-1.cert\"\n" - " }\n" - " signer\n" - " {\n" - " type file\n" - " file-name \"trust-anchor-10-2.cert\"\n" - " }\n" - " signer\n" - " {\n" - " type file\n" - " file-name \"trust-anchor-10-3.cert\"\n" - " }\n" - " signer\n" - " {\n" - " type file\n" - " file-name \"trust-anchor-10-4.cert\"\n" - " }\n" - " }\n" - "}\n"; - const boost::filesystem::path CONFIG_PATH = - (boost::filesystem::current_path() / std::string("unit-test-nfd.conf")); - - Face face(nullptr, m_keyChain); - ValidatorConfig validator(face, - ValidatorConfig::DEFAULT_CERTIFICATE_CACHE, - ValidatorConfig::DEFAULT_GRACE_INTERVAL, - 10, - 3, // Three keys can be tracked - time::seconds(1)); // TTL is set to 1 sec - validator.load(CONFIG, CONFIG_PATH.c_str()); - - validator.validate(*interest1, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - validator.validate(*interest2, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - validator.validate(*interest3, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - validator.validate(*interest1, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); - - validator.validate(*interest2, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); - - validator.validate(*interest3, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); - - sleep(2); - - validator.validate(*interest4, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - // Should succeed because identity1 and identity2's key has been cleaned up due to ttl limit. - validator.validate(*interest1, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - validator.validate(*interest2, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - validator.validate(*interest3, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); -} - -BOOST_AUTO_TEST_CASE(FixedSignerChecker2) -{ - Name rsaIdentity("/TestValidatorConfig/FixedSignerChecker2/Rsa"); - BOOST_REQUIRE(addIdentity(rsaIdentity)); - Name rsaCertName = m_keyChain.getDefaultCertificateNameForIdentity(rsaIdentity); - - Name ecdsaIdentity("/TestValidatorConfig/FixedSignerChecker2/Ecdsa"); - BOOST_REQUIRE(addIdentity(ecdsaIdentity, EcdsaKeyParams())); - BOOST_REQUIRE(saveIdentityCertificate(ecdsaIdentity, "trust-anchor-11.cert")); - - Name dataName("/TestValidatorConfig/FixedSignerChecker2"); - shared_ptr dataRsa = make_shared(dataName); - m_keyChain.sign(*dataRsa, security::signingByIdentity(rsaIdentity)); - shared_ptr dataEcdsa = make_shared(dataName); - m_keyChain.sign(*dataEcdsa, security::signingByIdentity(ecdsaIdentity)); - - shared_ptr interestRsa = make_shared(dataName); - m_keyChain.sign(*interestRsa, security::signingByIdentity(rsaIdentity)); - shared_ptr interestEcdsa = make_shared(dataName); - m_keyChain.sign(*interestEcdsa, security::signingByIdentity(ecdsaIdentity)); - - const std::string CONFIG = - "rule\n" - "{\n" - " id \"FixedSignerChecker Data Rule\"\n" - " for data\n" - " filter" - " {\n" - " type name\n" - " name /TestValidatorConfig/FixedSignerChecker2\n" - " relation equal\n" - " }\n" - " checker\n" - " {\n" - " type fixed-signer\n" - " sig-type ecdsa-sha256\n" - " signer\n" - " {\n" - " type file\n" - " file-name \"trust-anchor-11.cert\"\n" - " }\n" - " }\n" - "}\n" - "rule\n" - "{\n" - " id \"FixedSignerChecker Interest Rule\"\n" - " for interest\n" - " filter" - " {\n" - " type name\n" - " name /TestValidatorConfig/FixedSignerChecker2\n" - " relation equal\n" - " }\n" - " checker\n" - " {\n" - " type fixed-signer\n" - " sig-type ecdsa-sha256\n" - " signer\n" - " {\n" - " type file\n" - " file-name \"trust-anchor-11.cert\"\n" - " }\n" - " }\n" - "}\n"; - const boost::filesystem::path CONFIG_PATH = - (boost::filesystem::current_path() / std::string("unit-test.conf")); - - Face face(nullptr, m_keyChain); - ValidatorConfig validator(face); - validator.load(CONFIG, CONFIG_PATH.c_str()); - - validator.validate(*dataEcdsa, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - validator.validate(*dataRsa, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); - - validator.validate(*interestEcdsa, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - validator.validate(*interestRsa, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); -} - - -struct FacesFixture : public IdentityManagementTimeFixture -{ - FacesFixture() - : face1(io, m_keyChain, {true, true}) - , face2(io, m_keyChain, {true, true}) - , readInterestOffset1(0) - , readDataOffset1(0) - , readInterestOffset2(0) - , readDataOffset2(0) - { - } - - bool - passPacket() - { - bool hasPassed = false; - - checkFace(face1.sentInterests, readInterestOffset1, face2, hasPassed); - checkFace(face1.sentData, readDataOffset1, face2, hasPassed); - checkFace(face2.sentInterests, readInterestOffset2, face1, hasPassed); - checkFace(face2.sentData, readDataOffset2, face1, hasPassed); - - return hasPassed; - } - - template - void - checkFace(std::vector& receivedPackets, - size_t& readPacketOffset, - util::DummyClientFace& receiver, - bool& hasPassed) - { - while (receivedPackets.size() > readPacketOffset) { - receiver.receive(receivedPackets[readPacketOffset]); - readPacketOffset++; - hasPassed = true; - } - } - - ~FacesFixture() - { - } - -public: - util::DummyClientFace face1; - util::DummyClientFace face2; - - size_t readInterestOffset1; - size_t readDataOffset1; - size_t readInterestOffset2; - size_t readDataOffset2; -}; - -BOOST_FIXTURE_TEST_CASE(HierarchicalChecker, FacesFixture) -{ - std::vector subjectDescription; - - Name root("/TestValidatorConfig"); - BOOST_REQUIRE(saveIdentityCertificate(root, "trust-anchor-6.cert", true)); - - - Name sld("/TestValidatorConfig/HierarchicalChecker"); - BOOST_REQUIRE(addIdentity(sld)); - advanceClocks(time::milliseconds(100)); - Name sldKeyName = m_keyChain.generateRsaKeyPairAsDefault(sld, true); - shared_ptr sldCert = - m_keyChain.prepareUnsignedIdentityCertificate(sldKeyName, - root, - time::system_clock::now(), - time::system_clock::now() + time::days(7300), - subjectDescription); - m_keyChain.sign(*sldCert, security::signingByIdentity(root)); - m_keyChain.addCertificateAsIdentityDefault(*sldCert); - - Name nld("/TestValidatorConfig/HierarchicalChecker/NextLevel"); - BOOST_REQUIRE(addIdentity(nld)); - advanceClocks(time::milliseconds(100)); - Name nldKeyName = m_keyChain.generateRsaKeyPairAsDefault(nld, true); - shared_ptr nldCert = - m_keyChain.prepareUnsignedIdentityCertificate(nldKeyName, - sld, - time::system_clock::now(), - time::system_clock::now() + time::days(7300), - subjectDescription); - m_keyChain.sign(*nldCert, security::signingByIdentity(sld)); - m_keyChain.addCertificateAsIdentityDefault(*nldCert); - - face1.setInterestFilter(sldCert->getName().getPrefix(-1), - [&] (const InterestFilter&, const Interest&) { face1.put(*sldCert); }, - RegisterPrefixSuccessCallback(), - [] (const Name&, const std::string&) {}); - - face1.setInterestFilter(nldCert->getName().getPrefix(-1), - [&] (const InterestFilter&, const Interest&) { face1.put(*nldCert); }, - RegisterPrefixSuccessCallback(), - [] (const Name&, const std::string&) {}); - - Name dataName1 = nld; - dataName1.append("data1"); - shared_ptr data1 = make_shared(dataName1); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(nld))); - - Name dataName2("/ConfValidatorTest"); - dataName2.append("data1"); - shared_ptr data2 = make_shared(dataName2); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(nld))); - - const std::string CONFIG = - "rule\n" - "{\n" - " id \"Simple3 Rule\"\n" - " for data\n" - " checker\n" - " {\n" - " type hierarchical\n" - " sig-type rsa-sha256\n" - " }\n" - "}\n" - "trust-anchor\n" - "{\n" - " type file\n" - " file-name \"trust-anchor-6.cert\"\n" - "}\n"; - const boost::filesystem::path CONFIG_PATH = - (boost::filesystem::current_path() / std::string("unit-test-nfd.conf")); - - - auto validator = make_shared(&face2); - validator->load(CONFIG, CONFIG_PATH.c_str()); - - advanceClocks(time::milliseconds(2), 100); - validator->validate(*data1, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - do { - advanceClocks(time::milliseconds(2), 10); - } while (passPacket()); - - validator->validate(*data2, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); - - do { - advanceClocks(time::milliseconds(2), 10); - } while (passPacket()); -} - -BOOST_FIXTURE_TEST_CASE(Nrd, FacesFixture) -{ - advanceClocks(time::nanoseconds(1)); - - std::vector subjectDescription; - - Name root("/TestValidatorConfig"); - BOOST_REQUIRE(saveIdentityCertificate(root, "trust-anchor-8.cert", true)); - - - Name sld("/TestValidatorConfig/Nrd-1"); - BOOST_REQUIRE(addIdentity(sld)); - advanceClocks(time::milliseconds(100)); - Name sldKeyName = m_keyChain.generateRsaKeyPairAsDefault(sld, true); - shared_ptr sldCert = - m_keyChain.prepareUnsignedIdentityCertificate(sldKeyName, - root, - time::system_clock::now(), - time::system_clock::now() + time::days(7300), - subjectDescription); - m_keyChain.sign(*sldCert, security::signingByIdentity(root)); - m_keyChain.addCertificateAsIdentityDefault(*sldCert); - - Name nld("/TestValidatorConfig/Nrd-1/Nrd-2"); - BOOST_REQUIRE(addIdentity(nld)); - advanceClocks(time::milliseconds(100)); - Name nldKeyName = m_keyChain.generateRsaKeyPairAsDefault(nld, true); - shared_ptr nldCert = - m_keyChain.prepareUnsignedIdentityCertificate(nldKeyName, - sld, - time::system_clock::now(), - time::system_clock::now() + time::days(7300), - subjectDescription); - m_keyChain.sign(*nldCert, security::signingByIdentity(sld)); - m_keyChain.addCertificateAsIdentityDefault(*nldCert); - - face1.setInterestFilter(sldCert->getName().getPrefix(-1), - [&] (const InterestFilter&, const Interest&) { face1.put(*sldCert); }, - RegisterPrefixSuccessCallback(), - [] (const Name&, const std::string&) {}); - - face1.setInterestFilter(nldCert->getName().getPrefix(-1), - [&] (const InterestFilter&, const Interest&) { face1.put(*nldCert); }, - RegisterPrefixSuccessCallback(), - [] (const Name&, const std::string&) {}); - - advanceClocks(time::milliseconds(10)); - Name interestName1("/localhost/nrd/register/option"); - shared_ptr interest1 = make_shared(interestName1); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest1, security::signingByIdentity(nld))); - - advanceClocks(time::milliseconds(10)); - Name interestName2("/localhost/nrd/non-register"); - shared_ptr interest2 = make_shared(interestName2); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest2, security::signingByIdentity(nld))); - - advanceClocks(time::milliseconds(10)); - Name interestName3("/localhost/nrd/register/option"); - shared_ptr interest3 = make_shared(interestName3); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*interest3, security::signingByIdentity(root))); - - advanceClocks(time::milliseconds(10)); - Name interestName4("/localhost/nrd/register/option/timestamp/nonce/fakeSigInfo/fakeSigValue"); - shared_ptr interest4 = make_shared(interestName4); - - const std::string CONFIG = - "rule\n" - "{\n" - " id \"NRD Prefix Registration Command Rule\"\n" - " for interest\n" - " filter\n" - " {\n" - " type name\n" - " regex ^[]<>$\n" - " }\n" - " checker\n" - " {\n" - " type customized\n" - " sig-type rsa-sha256\n" - " key-locator\n" - " {\n" - " type name\n" - " regex ^[^]*<>*$\n" - " }\n" - " }\n" - "}\n" - "rule\n" - "{\n" - " id \"Testbed Hierarchy Rule\"\n" - " for data\n" - " filter\n" - " {\n" - " type name\n" - " regex ^[^]*<>*<>$\n" - " }\n" - " checker\n" - " {\n" - " type hierarchical\n" - " sig-type rsa-sha256\n" - " }\n" - "}\n" - "trust-anchor\n" - "{\n" - " type file\n" - " file-name \"trust-anchor-8.cert\"\n" - "}\n"; - const boost::filesystem::path CONFIG_PATH = - (boost::filesystem::current_path() / std::string("unit-test-nfd.conf")); - - auto validator = make_shared(&face2); - validator->load(CONFIG, CONFIG_PATH.c_str()); - - advanceClocks(time::milliseconds(2), 100); - - // should succeed - validator->validate(*interest1, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - do { - advanceClocks(time::milliseconds(2), 10); - } while (passPacket()); - - // should fail - validator->validate(*interest2, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); - - do { - advanceClocks(time::milliseconds(2), 10); - } while (passPacket()); - - // should succeed - validator->validate(*interest3, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - - do { - advanceClocks(time::milliseconds(2), 10); - } while (passPacket()); - - // should fail - validator->validate(*interest4, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); - - do { - advanceClocks(time::milliseconds(2), 10); - } while (passPacket()); -} - -struct DirTestFixture : public IdentityManagementTimeFixture -{ - DirTestFixture() - : face(io, m_keyChain, {true, true}) - , validator(&face, ValidatorConfig::DEFAULT_CERTIFICATE_CACHE, - ValidatorConfig::DEFAULT_GRACE_INTERVAL, 0) - { - certDirPath = (boost::filesystem::current_path() / std::string("test-cert-dir")); - boost::filesystem::create_directory(certDirPath); - - firstCertPath = (boost::filesystem::current_path() / - std::string("test-cert-dir") / - std::string("trust-anchor-1.cert")); - - secondCertPath = (boost::filesystem::current_path() / - std::string("test-cert-dir") / - std::string("trust-anchor-2.cert")); - - firstIdentity = Name("/TestValidatorConfig/Dir/First"); - BOOST_REQUIRE(addIdentity(firstIdentity)); - Name firstCertName = m_keyChain.getDefaultCertificateNameForIdentity(firstIdentity); - firstCert = m_keyChain.getCertificate(firstCertName); - io::save(*firstCert, firstCertPath.string()); - - secondIdentity = Name("/TestValidatorConfig/Dir/Second"); - BOOST_REQUIRE(addIdentity(secondIdentity)); - Name secondCertName = m_keyChain.getDefaultCertificateNameForIdentity(secondIdentity); - secondCert = m_keyChain.getCertificate(secondCertName); - } - - ~DirTestFixture() - { - boost::filesystem::remove_all(certDirPath); - } - -public: - boost::filesystem::path certDirPath; - boost::filesystem::path firstCertPath; - boost::filesystem::path secondCertPath; - - Name firstIdentity; - Name secondIdentity; - - shared_ptr firstCert; - shared_ptr secondCert; - - util::DummyClientFace face; - ValidatorConfig validator; -}; - -BOOST_FIXTURE_TEST_CASE(TrustAnchorDir, DirTestFixture) -{ - advanceClocks(time::milliseconds(10)); - - Name dataName1("/any/data/1"); - shared_ptr data1 = make_shared(dataName1); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data1, security::signingByIdentity(firstIdentity))); - - Name dataName2("/any/data/2"); - shared_ptr data2 = make_shared(dataName2); - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data2, security::signingByIdentity(secondIdentity))); - - std::string CONFIG = - "rule\n" - "{\n" - " id \"Any Rule\"\n" - " for data\n" - " filter\n" - " {\n" - " type name\n" - " regex ^<>*$\n" - " }\n" - " checker\n" - " {\n" - " type customized\n" - " sig-type rsa-sha256\n" - " key-locator\n" - " {\n" - " type name\n" - " regex ^<>*$\n" - " }\n" - " }\n" - "}\n" - "trust-anchor\n" - "{\n" - " type dir\n" - " dir test-cert-dir\n" - " refresh 1s\n" - "}\n"; - - const boost::filesystem::path CONFIG_PATH = - (boost::filesystem::current_path() / std::string("unit-test-nfd.conf")); - - validator.load(CONFIG, CONFIG_PATH.c_str()); - - advanceClocks(time::milliseconds(10), 20); - validator.validate(*data1, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - advanceClocks(time::milliseconds(10), 20); - - validator.validate(*data2, - [] (const shared_ptr&) { BOOST_CHECK(false); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(true); }); - advanceClocks(time::milliseconds(10), 20); - - io::save(*secondCert, secondCertPath.string()); - advanceClocks(time::milliseconds(10), 200); - - validator.validate(*data1, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - advanceClocks(time::milliseconds(10), 20); - - validator.validate(*data2, - [] (const shared_ptr&) { BOOST_CHECK(true); }, - [] (const shared_ptr&, const std::string&) { BOOST_CHECK(false); }); - advanceClocks(time::milliseconds(10), 20); -} - -BOOST_AUTO_TEST_SUITE_END() // TestValidatorConfig -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/security/validator.t.cpp b/tests/unit-tests/security/validator.t.cpp deleted file mode 100644 index 65c509592..000000000 --- a/tests/unit-tests/security/validator.t.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "security/validator-null.hpp" -#include "security/key-chain.hpp" - -#include "boost-test.hpp" -#include "identity-management-fixture.hpp" -#include "../make-interest-data.hpp" - -namespace ndn { -namespace security { -namespace tests { - -using namespace ndn::tests; - -BOOST_AUTO_TEST_SUITE(Security) -BOOST_FIXTURE_TEST_SUITE(TestValidator, IdentityManagementFixture) - -void -onValidated(const shared_ptr& data) -{ - BOOST_CHECK(true); -} - -void -onValidationFailed(const shared_ptr& data, const std::string& failureInfo) -{ - BOOST_CHECK(false); -} - -BOOST_AUTO_TEST_CASE(Null) -{ - Name identity("/TestValidator/Null"); - identity.appendVersion(); - BOOST_REQUIRE(addIdentity(identity, RsaKeyParams())); - - Name dataName = identity; - dataName.append("1"); - shared_ptr data = make_shared(dataName); - - BOOST_CHECK_NO_THROW(m_keyChain.sign(*data, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity))); - - ValidatorNull validator; - - // data must be a shared pointer - validator.validate(*data, - bind(&onValidated, _1), - bind(&onValidationFailed, _1, _2)); -} - -const uint8_t ecdsaSigInfo[] = { -0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x03, - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72 -}; - -const uint8_t ecdsaSigValue[] = { -0x17, 0x40, // SignatureValue - 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, - 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, - 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, - 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, - 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b -}; - -BOOST_AUTO_TEST_CASE(RsaSignatureVerification) -{ - Name identity("/TestValidator/RsaSignatureVerification"); - BOOST_REQUIRE(addIdentity(identity, RsaKeyParams())); - Name keyName = m_keyChain.getDefaultKeyNameForIdentity(identity); - shared_ptr publicKey = m_keyChain.getPublicKey(keyName); - - Name identity2("/TestValidator/RsaSignatureVerification/id2"); - BOOST_REQUIRE(addIdentity(identity2, RsaKeyParams())); - Name keyName2 = m_keyChain.getDefaultKeyNameForIdentity(identity2); - shared_ptr publicKey2 = m_keyChain.getPublicKey(keyName2); - - Data data("/TestData/1"); - BOOST_CHECK_NO_THROW(m_keyChain.sign(data, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity))); - BOOST_CHECK_EQUAL(Validator::verifySignature(data, *publicKey), true); - BOOST_CHECK_EQUAL(Validator::verifySignature(data, *publicKey2), false); - - Interest interest("/TestInterest/1"); - BOOST_CHECK_NO_THROW(m_keyChain.sign(interest, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity))); - BOOST_CHECK_EQUAL(Validator::verifySignature(interest, *publicKey), true); - BOOST_CHECK_EQUAL(Validator::verifySignature(interest, *publicKey2), false); - - Data wrongData("/TestData/2"); - Block ecdsaSigInfoBlock(ecdsaSigInfo, sizeof(ecdsaSigInfo)); - Block ecdsaSigValueBlock(ecdsaSigValue, sizeof(ecdsaSigValue)); - Signature ecdsaSig(ecdsaSigInfoBlock, ecdsaSigValueBlock); - wrongData.setSignature(ecdsaSig); - BOOST_CHECK_EQUAL(Validator::verifySignature(wrongData, *publicKey), false); -} - -const uint8_t rsaSigInfo[] = { -0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x01, - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72 -}; - -const uint8_t rsaSigValue[] = { -0x17, 0x80, // SignatureValue - 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, - 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, - 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, - 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, - 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, - 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, - 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, - 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, - 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, - 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1 -}; - - -BOOST_AUTO_TEST_CASE(EcdsaSignatureVerification) -{ - Name identity("/TestValidator/EcdsaSignatureVerification"); - BOOST_REQUIRE(addIdentity(identity, EcdsaKeyParams())); - Name keyName = m_keyChain.getDefaultKeyNameForIdentity(identity); - shared_ptr publicKey = m_keyChain.getPublicKey(keyName); - - Name identity2("/TestValidator/EcdsaSignatureVerification/id2"); - BOOST_REQUIRE(addIdentity(identity2, EcdsaKeyParams())); - Name keyName2 = m_keyChain.getDefaultKeyNameForIdentity(identity2); - shared_ptr publicKey2 = m_keyChain.getPublicKey(keyName2); - - - Data data("/TestData/1"); - BOOST_CHECK_NO_THROW(m_keyChain.sign(data, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity))); - BOOST_CHECK_EQUAL(Validator::verifySignature(data, *publicKey), true); - BOOST_CHECK_EQUAL(Validator::verifySignature(data, *publicKey2), false); - - Interest interest("/TestInterest/1"); - BOOST_CHECK_NO_THROW(m_keyChain.sign(interest, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - identity))); - BOOST_CHECK_EQUAL(Validator::verifySignature(interest, *publicKey), true); - BOOST_CHECK_EQUAL(Validator::verifySignature(interest, *publicKey2), false); - - Data wrongData("/TestData/2"); - Block rsaSigInfoBlock(rsaSigInfo, sizeof(rsaSigInfo)); - Block rsaSigValueBlock(rsaSigValue, sizeof(rsaSigValue)); - Signature rsaSig(rsaSigInfoBlock, rsaSigValueBlock); - wrongData.setSignature(rsaSig); - BOOST_CHECK_EQUAL(Validator::verifySignature(wrongData, *publicKey), false); -} - -BOOST_AUTO_TEST_CASE(EcdsaSignatureVerification2) -{ - Name ecdsaIdentity("/SecurityTestValidator/EcdsaSignatureVerification2/ecdsa"); - BOOST_REQUIRE(addIdentity(ecdsaIdentity, EcdsaKeyParams())); - Name ecdsaCertName = m_keyChain.getDefaultCertificateNameForIdentity(ecdsaIdentity); - shared_ptr ecdsaCert = m_keyChain.getCertificate(ecdsaCertName); - - Name rsaIdentity("/SecurityTestValidator/EcdsaSignatureVerification2/rsa"); - BOOST_REQUIRE(addIdentity(rsaIdentity, RsaKeyParams())); - Name rsaCertName = m_keyChain.getDefaultCertificateNameForIdentity(rsaIdentity); - shared_ptr rsaCert = m_keyChain.getCertificate(rsaCertName); - - Name packetName("/Test/Packet/Name"); - - shared_ptr testDataRsa = make_shared(packetName); - m_keyChain.sign(*testDataRsa, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - rsaIdentity)); - shared_ptr testDataEcdsa = make_shared(packetName); - m_keyChain.sign(*testDataEcdsa, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - ecdsaIdentity)); - shared_ptr testInterestRsa = make_shared(packetName); - m_keyChain.sign(*testInterestRsa, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - rsaIdentity)); - shared_ptr testInterestEcdsa = make_shared(packetName); - m_keyChain.sign(*testInterestEcdsa, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_ID, - ecdsaIdentity)); - - BOOST_CHECK(Validator::verifySignature(*ecdsaCert, ecdsaCert->getPublicKeyInfo())); - BOOST_CHECK_EQUAL(Validator::verifySignature(*ecdsaCert, rsaCert->getPublicKeyInfo()), false); - BOOST_CHECK_EQUAL(Validator::verifySignature(*rsaCert, ecdsaCert->getPublicKeyInfo()), false); - BOOST_CHECK(Validator::verifySignature(*rsaCert, rsaCert->getPublicKeyInfo())); - - BOOST_CHECK(Validator::verifySignature(*testDataEcdsa, ecdsaCert->getPublicKeyInfo())); - BOOST_CHECK_EQUAL(Validator::verifySignature(*testDataEcdsa, rsaCert->getPublicKeyInfo()), false); - BOOST_CHECK_EQUAL(Validator::verifySignature(*testDataRsa, ecdsaCert->getPublicKeyInfo()), false); - BOOST_CHECK(Validator::verifySignature(*testDataRsa, rsaCert->getPublicKeyInfo())); - - BOOST_CHECK(Validator::verifySignature(*testInterestEcdsa, ecdsaCert->getPublicKeyInfo())); - BOOST_CHECK_EQUAL(Validator::verifySignature(*testInterestEcdsa, rsaCert->getPublicKeyInfo()), - false); - BOOST_CHECK_EQUAL(Validator::verifySignature(*testInterestRsa, ecdsaCert->getPublicKeyInfo()), - false); - BOOST_CHECK(Validator::verifySignature(*testInterestRsa, rsaCert->getPublicKeyInfo())); -} - -BOOST_AUTO_TEST_CASE(MalformedInterestSigInfo) -{ - auto interest = make_shared("/prefix"); - m_keyChain.sign(*interest); - - setNameComponent(*interest, signed_interest::POS_SIG_INFO, "not-SignatureInfo"); - - v1::PublicKey pubkey = m_keyChain.getDefaultCertificate()->getPublicKeyInfo(); - BOOST_CHECK_EQUAL(Validator::verifySignature(*interest, pubkey), false); -} - -BOOST_AUTO_TEST_CASE(MalformedInterestSigValue) -{ - auto interest = make_shared("/prefix"); - m_keyChain.sign(*interest); - - setNameComponent(*interest, signed_interest::POS_SIG_VALUE, "bad-signature-bits"); - - v1::PublicKey pubkey = m_keyChain.getDefaultCertificate()->getPublicKeyInfo(); - BOOST_CHECK_EQUAL(Validator::verifySignature(*interest, pubkey), false); -} - -BOOST_AUTO_TEST_SUITE_END() // TestValidator -BOOST_AUTO_TEST_SUITE_END() // Security - -} // namespace tests -} // namespace security -} // namespace ndn diff --git a/tests/unit-tests/util/backports.t.cpp b/tests/unit-tests/util/backports.t.cpp deleted file mode 100644 index 6d8dfd28d..000000000 --- a/tests/unit-tests/util/backports.t.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/backports.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_AUTO_TEST_SUITE(TestBackports) - -BOOST_AUTO_TEST_CASE(MakeUnique) -{ - std::unique_ptr v0 = make_unique(); - std::unique_ptr v1 = make_unique(1728); - BOOST_CHECK_EQUAL(*v0, 0); - BOOST_CHECK_EQUAL(*v1, 1728); - - auto str = make_unique("meow"); - BOOST_CHECK_EQUAL(*str, "meow"); - - class Movable - { - public: - Movable() - : value(42) - { - } - - Movable(const Movable&) = delete; - Movable(Movable&&) = default; - - public: - int value; - }; - - class Container - { - public: - explicit - Container(Movable m) - : m(std::move(m)) - { - } - - public: - Movable m; - }; - - Movable m; - auto ptr = make_unique(std::move(m)); - BOOST_CHECK_EQUAL(ptr->m.value, 42); -} - -BOOST_AUTO_TEST_CASE(Clamp) -{ - int x = clamp(5, 1, 10); - BOOST_CHECK_EQUAL(x, 5); - - x = clamp(-5, 1, 10); - BOOST_CHECK_EQUAL(x, 1); - - x = clamp(15, 1, 10); - BOOST_CHECK_EQUAL(x, 10); - - x = clamp(5, 10, 1, std::greater()); - BOOST_CHECK_EQUAL(x, 5); - - x = clamp(-5, 10, 1, std::greater()); - BOOST_CHECK_EQUAL(x, 1); - - x = clamp(15, 10, 1, std::greater()); - BOOST_CHECK_EQUAL(x, 10); -} - -BOOST_AUTO_TEST_SUITE(Optional) - -BOOST_AUTO_TEST_CASE(Construct) -{ - optional o1; - BOOST_CHECK_EQUAL(static_cast(o1), false); - - optional o2(1); - BOOST_CHECK_EQUAL(static_cast(o2), true); - BOOST_CHECK_EQUAL(o2.value(), 1); - - optional o3(o2); - BOOST_CHECK_EQUAL(static_cast(o3), true); - BOOST_CHECK_EQUAL(static_cast(o2), true); - BOOST_CHECK_EQUAL(o3.value(), 1); - - optional> o4(in_place, 41, 42); - BOOST_CHECK_EQUAL(static_cast(o4), true); - BOOST_CHECK_EQUAL(o4.value().first, 41); - BOOST_CHECK_EQUAL(o4.value().second, 42); -} - -BOOST_AUTO_TEST_CASE(Assign) -{ - optional o1; - BOOST_CHECK_EQUAL(static_cast(o1), false); - - optional o2(2); - o1 = o2; - BOOST_CHECK_EQUAL(static_cast(o1), true); - BOOST_CHECK_EQUAL(o1.value(), 2); - - o1 = nullopt; - BOOST_CHECK_EQUAL(static_cast(o1), false); - - o1 = 18763; - BOOST_CHECK_EQUAL(static_cast(o1), true); - BOOST_CHECK_EQUAL(o1.value(), 18763); -} - -BOOST_AUTO_TEST_CASE(Access) -{ - optional o1(1); - BOOST_CHECK_EQUAL(*o1, 1); - - optional o2("abc"); - BOOST_CHECK_EQUAL(o2->size(), 3); -} - -BOOST_AUTO_TEST_CASE(HasValue) -{ - optional o1; - BOOST_CHECK_EQUAL(static_cast(o1), false); - BOOST_CHECK_EQUAL(!o1, true); - if (o1) { - BOOST_ERROR("o1 should evaluate to false"); - } - - optional o2(1); - BOOST_CHECK_EQUAL(static_cast(o2), true); - BOOST_CHECK_EQUAL(!o2, false); - if (o2) { - } - else { - BOOST_ERROR("o2 should evaluate to true"); - } -} - -BOOST_AUTO_TEST_CASE(Value) -{ - optional o1; - BOOST_CHECK_THROW(o1.value(), bad_optional_access); - - optional o2(2); - BOOST_CHECK_NO_THROW(o2.value()); -} - -BOOST_AUTO_TEST_CASE(ValueOr) -{ - optional o1; - BOOST_CHECK_EQUAL(o1.value_or(3.0), 3); - - optional o2(2); - BOOST_CHECK_EQUAL(o2.value_or(3.0), 2); -} - -BOOST_AUTO_TEST_CASE(Swap) -{ - optional o1; - optional o2(2); - - o1.swap(o2); - BOOST_CHECK_EQUAL(static_cast(o1), true); - BOOST_CHECK_EQUAL(o1.value(), 2); - BOOST_CHECK_EQUAL(static_cast(o2), false); -} - -BOOST_AUTO_TEST_CASE(Emplace) -{ - optional> o1; - o1.emplace(11, 12); - BOOST_CHECK_EQUAL(static_cast(o1), true); - BOOST_CHECK_EQUAL(o1.value().first, 11); - BOOST_CHECK_EQUAL(o1.value().second, 12); -} - -BOOST_AUTO_TEST_CASE(Compare) -{ - optional o0a; - optional o0b; - optional o1a(1); - optional o1b(1); - optional o2(2); - - BOOST_CHECK_EQUAL(o0a == o0b, true); - BOOST_CHECK_EQUAL(o0a != o0b, false); - BOOST_CHECK_EQUAL(o0a < o0b, false); - BOOST_CHECK_EQUAL(o0a <= o0b, true); - BOOST_CHECK_EQUAL(o0a > o0b, false); - BOOST_CHECK_EQUAL(o0a >= o0b, true); - - BOOST_CHECK_EQUAL(o1a == o1b, true); - BOOST_CHECK_EQUAL(o1a != o1b, false); - BOOST_CHECK_EQUAL(o1a < o1b, false); - BOOST_CHECK_EQUAL(o1a <= o1b, true); - BOOST_CHECK_EQUAL(o1a > o1b, false); - BOOST_CHECK_EQUAL(o1a >= o1b, true); - - BOOST_CHECK_EQUAL(o0a == o1a, false); - BOOST_CHECK_EQUAL(o0a != o1a, true); - BOOST_CHECK_EQUAL(o0a < o1a, true); - BOOST_CHECK_EQUAL(o0a <= o1a, true); - BOOST_CHECK_EQUAL(o0a > o1a, false); - BOOST_CHECK_EQUAL(o0a >= o1a, false); - - BOOST_CHECK_EQUAL(o1a == o0a, false); - BOOST_CHECK_EQUAL(o1a != o0a, true); - BOOST_CHECK_EQUAL(o1a < o0a, false); - BOOST_CHECK_EQUAL(o1a <= o0a, false); - BOOST_CHECK_EQUAL(o1a > o0a, true); - BOOST_CHECK_EQUAL(o1a >= o0a, true); - - BOOST_CHECK_EQUAL(o1a == o2, false); - BOOST_CHECK_EQUAL(o1a != o2, true); - BOOST_CHECK_EQUAL(o1a < o2, true); - BOOST_CHECK_EQUAL(o1a <= o2, true); - BOOST_CHECK_EQUAL(o1a > o2, false); - BOOST_CHECK_EQUAL(o1a >= o2, false); - - BOOST_CHECK_EQUAL(o2 == o1a, false); - BOOST_CHECK_EQUAL(o2 != o1a, true); - BOOST_CHECK_EQUAL(o2 < o1a, false); - BOOST_CHECK_EQUAL(o2 <= o1a, false); - BOOST_CHECK_EQUAL(o2 > o1a, true); - BOOST_CHECK_EQUAL(o2 >= o1a, true); -} - -BOOST_AUTO_TEST_CASE(MakeOptional) -{ - auto o1 = make_optional(1); - static_assert(std::is_same>::value, "o1 must be optional"); - BOOST_CHECK_EQUAL(static_cast(o1), true); - BOOST_CHECK_EQUAL(o1.value(), 1); - - auto o2 = make_optional>(21, 22); - static_assert(std::is_same>>::value, - "o2 must be optional>"); - BOOST_CHECK_EQUAL(static_cast(o2), true); - BOOST_CHECK_EQUAL(o2.value().first, 21); - BOOST_CHECK_EQUAL(o2.value().second, 22); -} - -BOOST_AUTO_TEST_SUITE_END() // Optional - -BOOST_AUTO_TEST_SUITE_END() // TestBackports -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/util/crypto.t.cpp b/tests/unit-tests/util/crypto.t.cpp deleted file mode 100644 index 9bf9f592e..000000000 --- a/tests/unit-tests/util/crypto.t.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/crypto.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace crypto { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_AUTO_TEST_SUITE(TestCrypto) - -BOOST_AUTO_TEST_CASE(Basic) -{ - const std::string testString = "Hello, world!"; - ConstBufferPtr result; - BOOST_CHECK_NO_THROW(result = computeSha256Digest(reinterpret_cast(testString.data()), - testString.size())); - - BOOST_CHECK_EQUAL(result->size(), SHA256_DIGEST_SIZE); - - const uint8_t expectedSha256[] = {0x31, 0x5f, 0x5b, 0xdb, 0x76, 0xd0, 0x78, 0xc4, - 0x3b, 0x8a, 0xc0, 0x06, 0x4e, 0x4a, 0x01, 0x64, - 0x61, 0x2b, 0x1f, 0xce, 0x77, 0xc8, 0x69, 0x34, - 0x5b, 0xfc, 0x94, 0xc7, 0x58, 0x94, 0xed, 0xd3}; - BOOST_CHECK_EQUAL_COLLECTIONS(result->begin(), result->end(), - expectedSha256, expectedSha256 + sizeof(expectedSha256)); -} - -BOOST_AUTO_TEST_SUITE_END() // TestCrypto -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace tests -} // namespace crypto -} // namespace ndn diff --git a/tests/unit-tests/util/digest.t.cpp b/tests/unit-tests/util/digest.t.cpp deleted file mode 100644 index 25f75dda4..000000000 --- a/tests/unit-tests/util/digest.t.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/digest.hpp" -#include "util/crypto.hpp" -#include "util/string-helper.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace util { -namespace test { - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_AUTO_TEST_SUITE(TestDigest) - -BOOST_AUTO_TEST_CASE(Sha256Digest) -{ - uint8_t origin[4] = {0x01, 0x02, 0x03, 0x04}; - ConstBufferPtr digest1 = crypto::computeSha256Digest(origin, 4); - - Sha256 statefulSha256; - statefulSha256.update(origin, 1); - statefulSha256.update(origin + 1, 1); - statefulSha256.update(origin + 2, 1); - statefulSha256.update(origin + 3, 1); - ConstBufferPtr digest2 = statefulSha256.computeDigest(); - - BOOST_CHECK_EQUAL_COLLECTIONS(digest1->buf(), - digest1->buf() + digest1->size(), - digest2->buf(), - digest2->buf() + digest2->size()); -} - -BOOST_AUTO_TEST_CASE(Compute) -{ - std::string input = "Hello, World!"; - ConstBufferPtr digest1 = crypto::computeSha256Digest(reinterpret_cast(input.data()), - input.size()); - - Sha256 hashObject; - hashObject << input; - BOOST_CHECK_EQUAL(hashObject.toString(), "DFFD6021BB2BD5B0AF676290809EC3A53191DD81C7F70A4B28688A362182986F"); - ConstBufferPtr digest2 = hashObject.computeDigest(); - BOOST_CHECK_EQUAL_COLLECTIONS(digest1->buf(), - digest1->buf() + digest1->size(), - digest2->buf(), - digest2->buf() + digest2->size()); - -} - -BOOST_AUTO_TEST_CASE(ConstructFromStream) -{ - std::string input = "Hello, World!"; - ConstBufferPtr digest1 = crypto::computeSha256Digest(reinterpret_cast(input.data()), - input.size()); - - std::istringstream is(input); - Sha256 hashObject(is); - BOOST_CHECK_EQUAL(hashObject.toString(), "DFFD6021BB2BD5B0AF676290809EC3A53191DD81C7F70A4B28688A362182986F"); - ConstBufferPtr digest2 = hashObject.computeDigest(); - BOOST_CHECK_EQUAL_COLLECTIONS(digest1->buf(), - digest1->buf() + digest1->size(), - digest2->buf(), - digest2->buf() + digest2->size()); -} - -BOOST_AUTO_TEST_CASE(Compare) -{ - uint8_t origin[4] = {0x01, 0x02, 0x03, 0x04}; - - Sha256 digest; - digest.update(origin, 4); - digest.computeDigest(); - - Sha256 digest2; - digest2.update(origin, 1); - digest2.update(origin + 1, 1); - digest2.update(origin + 2, 1); - digest2.update(origin + 3, 1); - digest2.computeDigest(); - - BOOST_CHECK(digest == digest2); - BOOST_CHECK_EQUAL(digest != digest2, false); -} - -BOOST_AUTO_TEST_CASE(OperatorDigest) -{ - uint8_t origin[32] = {0x94, 0xEE, 0x05, 0x93, 0x35, 0xE5, 0x87, 0xE5, - 0x01, 0xCC, 0x4B, 0xF9, 0x06, 0x13, 0xE0, 0x81, - 0x4F, 0x00, 0xA7, 0xB0, 0x8B, 0xC7, 0xC6, 0x48, - 0xFD, 0x86, 0x5A, 0x2A, 0xF6, 0xA2, 0x2C, 0xC2}; - ConstBufferPtr digest1 = crypto::computeSha256Digest(origin, 32); - - std::string str("TEST"); - Sha256 metaDigest; - metaDigest << str; - - Sha256 statefulSha256; - statefulSha256 << metaDigest; - ConstBufferPtr digest2 = statefulSha256.computeDigest(); - - BOOST_CHECK_EQUAL_COLLECTIONS(digest1->buf(), - digest1->buf() + digest1->size(), - digest2->buf(), - digest2->buf() + digest2->size()); -} - -BOOST_AUTO_TEST_CASE(OperatorString) -{ - uint8_t origin[4] = {0x54, 0x45, 0x53, 0x54}; - ConstBufferPtr digest1 = crypto::computeSha256Digest(origin, 4); - - std::string str("TEST"); - Sha256 statefulSha256; - statefulSha256 << str; - ConstBufferPtr digest2 = statefulSha256.computeDigest(); - - BOOST_CHECK_EQUAL_COLLECTIONS(digest1->buf(), - digest1->buf() + digest1->size(), - digest2->buf(), - digest2->buf() + digest2->size()); -} - -BOOST_AUTO_TEST_CASE(OperatorBlock) -{ - uint8_t origin[] = { - 0x16, 0x1b, // SignatureInfo - 0x1b, 0x01, // SignatureType - 0x01, // Sha256WithRsa - 0x1c, 0x16, // KeyLocator - 0x07, 0x14, // Name - 0x08, 0x04, - 0x74, 0x65, 0x73, 0x74, - 0x08, 0x03, - 0x6b, 0x65, 0x79, - 0x08, 0x07, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72 - }; - ConstBufferPtr digest1 = crypto::computeSha256Digest(origin, sizeof(origin)); - - Sha256 statefulSha256; - Block block(origin, sizeof(origin)); - statefulSha256 << block; - ConstBufferPtr digest2 = statefulSha256.computeDigest(); - - BOOST_CHECK_EQUAL_COLLECTIONS(digest1->buf(), - digest1->buf() + digest1->size(), - digest2->buf(), - digest2->buf() + digest2->size()); -} - -BOOST_AUTO_TEST_CASE(OperatorUint64t) -{ - uint64_t origin[4] = {1, 2, 3, 4}; - ConstBufferPtr digest1 = crypto::computeSha256Digest(reinterpret_cast(origin), 32); - - Sha256 statefulSha256; - statefulSha256 << origin[0]; - statefulSha256 << origin[1]; - statefulSha256 << origin[2]; - statefulSha256 << origin[3]; - ConstBufferPtr digest2 = statefulSha256.computeDigest(); - - BOOST_CHECK_EQUAL_COLLECTIONS(digest1->buf(), - digest1->buf() + digest1->size(), - digest2->buf(), - digest2->buf() + digest2->size()); -} - -BOOST_AUTO_TEST_CASE(Error) -{ - uint64_t origin = 256; - - Sha256 digest; - BOOST_CHECK(digest.empty()); - - digest << origin; - - BOOST_CHECK_NO_THROW(digest.computeDigest()); - BOOST_CHECK_THROW(digest << origin, Sha256::Error); - - digest.reset(); -} - -BOOST_AUTO_TEST_CASE(ComputeDigest) -{ - uint8_t origin[4] = {0x01, 0x02, 0x03, 0x04}; - ConstBufferPtr digest1 = crypto::computeSha256Digest(origin, 4); - - ConstBufferPtr digest2 = Sha256::computeDigest(origin, 4); - - BOOST_CHECK_EQUAL_COLLECTIONS(digest1->buf(), - digest1->buf() + digest1->size(), - digest2->buf(), - digest2->buf() + digest2->size()); -} - -BOOST_AUTO_TEST_CASE(Print) -{ - uint8_t origin[32] = {0x94, 0xEE, 0x05, 0x93, 0x35, 0xE5, 0x87, 0xE5, - 0x01, 0xCC, 0x4B, 0xF9, 0x06, 0x13, 0xE0, 0x81, - 0x4F, 0x00, 0xA7, 0xB0, 0x8B, 0xC7, 0xC6, 0x48, - 0xFD, 0x86, 0x5A, 0x2A, 0xF6, 0xA2, 0x2C, 0xC2}; - - std::string hexString = toHex(origin, 32); - - std::string str("TEST"); - Sha256 digest; - digest << str; - - std::ostringstream os; - os << digest; - - BOOST_CHECK_EQUAL(os.str(), hexString); - BOOST_CHECK_EQUAL(digest.toString(), hexString); -} - -BOOST_AUTO_TEST_SUITE_END() // TestDigest -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace test -} // namespace util -} // namespace ndn diff --git a/tests/unit-tests/util/dns.t.cpp b/tests/unit-tests/util/dns.t.cpp deleted file mode 100644 index e76d5938c..000000000 --- a/tests/unit-tests/util/dns.t.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/dns.hpp" - -#include "boost-test.hpp" -#include "../network-configuration-detector.hpp" - -#include - -namespace ndn { -namespace util { -namespace tests { - -using boost::asio::ip::address_v4; -using boost::asio::ip::address_v6; - -using ndn::tests::NetworkConfigurationDetector; - -class DnsFixture -{ -public: - DnsFixture() - : m_nFailures(0) - , m_nSuccesses(0) - { - } - - void - onSuccess(const dns::IpAddress& resolvedAddress, - const dns::IpAddress& expectedAddress, - bool isValid, - bool shouldCheckAddress = false) - { - ++m_nSuccesses; - - if (!isValid) { - BOOST_FAIL("Resolved to " + resolvedAddress.to_string() + ", but should have failed"); - } - - BOOST_CHECK_EQUAL(resolvedAddress.is_v4(), expectedAddress.is_v4()); - - // checking address is not deterministic and should be enabled only - // if only one IP address will be returned by resolution - if (shouldCheckAddress) { - BOOST_CHECK_EQUAL(resolvedAddress, expectedAddress); - } - } - - void - onFailure(bool isValid) - { - ++m_nFailures; - - if (!isValid) { - BOOST_FAIL("Resolution should not have failed"); - } - - BOOST_CHECK_MESSAGE(true, "Resolution failed as expected"); - } - -protected: - uint32_t m_nFailures; - uint32_t m_nSuccesses; - boost::asio::io_service m_ioService; -}; - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_FIXTURE_TEST_SUITE(TestDns, DnsFixture) - -BOOST_AUTO_TEST_CASE(Asynchronous) -{ - if (!NetworkConfigurationDetector::hasIpv4() && !NetworkConfigurationDetector::hasIpv6()) { - BOOST_WARN_MESSAGE(false, "skipping assertions that require either IPv4 or IPv6 support"); - return; - } - - dns::asyncResolve("nothost.nothost.nothost.arpa", - bind(&DnsFixture::onSuccess, this, _1, - dns::IpAddress(address_v4()), false, false), - bind(&DnsFixture::onFailure, this, true), - m_ioService); // should fail - m_ioService.run(); - - BOOST_CHECK_EQUAL(m_nFailures, 1); - BOOST_CHECK_EQUAL(m_nSuccesses, 0); -} - -BOOST_AUTO_TEST_CASE(AsynchronousV4) -{ - SKIP_IF_IPV4_UNAVAILABLE(); - - dns::asyncResolve("192.0.2.1", - bind(&DnsFixture::onSuccess, this, _1, - dns::IpAddress(address_v4::from_string("192.0.2.1")), - true, true), - bind(&DnsFixture::onFailure, this, false), - m_ioService); - m_ioService.run(); - - BOOST_CHECK_EQUAL(m_nFailures, 0); - BOOST_CHECK_EQUAL(m_nSuccesses, 1); -} - -BOOST_AUTO_TEST_CASE(AsynchronousV6) -{ - SKIP_IF_IPV6_UNAVAILABLE(); - - dns::asyncResolve("ipv6.google.com", // only IPv6 address should be available - bind(&DnsFixture::onSuccess, this, _1, - dns::IpAddress(address_v6()), true, false), - bind(&DnsFixture::onFailure, this, false), - m_ioService); - - dns::asyncResolve("2001:db8:3f9:0:3025:ccc5:eeeb:86d3", - bind(&DnsFixture::onSuccess, this, _1, - dns::IpAddress(address_v6:: - from_string("2001:db8:3f9:0:3025:ccc5:eeeb:86d3")), - true, true), - bind(&DnsFixture::onFailure, this, false), - m_ioService); - m_ioService.run(); - - BOOST_CHECK_EQUAL(m_nFailures, 0); - BOOST_CHECK_EQUAL(m_nSuccesses, 2); -} - -BOOST_AUTO_TEST_CASE(AsynchronousV4AndV6) -{ - SKIP_IF_IPV4_UNAVAILABLE(); - SKIP_IF_IPV6_UNAVAILABLE(); - - dns::asyncResolve("www.named-data.net", - bind(&DnsFixture::onSuccess, this, _1, - dns::IpAddress(address_v4()), true, false), - bind(&DnsFixture::onFailure, this, false), - m_ioService, - dns::Ipv4Only()); - - dns::asyncResolve("a.root-servers.net", - bind(&DnsFixture::onSuccess, this, _1, - dns::IpAddress(address_v4()), true, false), - bind(&DnsFixture::onFailure, this, false), - m_ioService, - dns::Ipv4Only()); // request IPv4 address - - dns::asyncResolve("a.root-servers.net", - bind(&DnsFixture::onSuccess, this, _1, - dns::IpAddress(address_v6()), true, false), - bind(&DnsFixture::onFailure, this, false), - m_ioService, - dns::Ipv6Only()); // request IPv6 address - - dns::asyncResolve("ipv6.google.com", // only IPv6 address should be available - bind(&DnsFixture::onSuccess, this, _1, - dns::IpAddress(address_v6()), true, false), - bind(&DnsFixture::onFailure, this, false), - m_ioService, - dns::Ipv6Only()); - - dns::asyncResolve("ipv6.google.com", // only IPv6 address should be available - bind(&DnsFixture::onSuccess, this, _1, - dns::IpAddress(address_v6()), false, false), - bind(&DnsFixture::onFailure, this, true), // should fail - m_ioService, - dns::Ipv4Only()); - m_ioService.run(); - - BOOST_CHECK_EQUAL(m_nFailures, 1); - BOOST_CHECK_EQUAL(m_nSuccesses, 4); -} - -BOOST_AUTO_TEST_CASE(Synchronous) -{ - if (!NetworkConfigurationDetector::hasIpv4() && !NetworkConfigurationDetector::hasIpv6()) { - BOOST_WARN_MESSAGE(false, "skipping assertions that require either IPv4 or IPv6 support"); - return; - } - dns::IpAddress address; - BOOST_CHECK_NO_THROW(address = dns::syncResolve("www.named-data.net", m_ioService)); - - BOOST_CHECK(address.is_v4() || address.is_v6()); -} - -BOOST_AUTO_TEST_SUITE_END() // TestDns -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace tests -} // namespace util -} // namespace ndn diff --git a/tests/unit-tests/util/dummy-client-face.t.cpp b/tests/unit-tests/util/dummy-client-face.t.cpp deleted file mode 100644 index 2e7368d11..000000000 --- a/tests/unit-tests/util/dummy-client-face.t.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/dummy-client-face.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace util { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_AUTO_TEST_SUITE(TestDummyClientFace) - -BOOST_AUTO_TEST_CASE(ProcessEventsOverride) -{ - bool isOverrideInvoked = false; - auto override = [&] (time::milliseconds timeout) { - isOverrideInvoked = true; - BOOST_CHECK_EQUAL(timeout, time::milliseconds(200)); - }; - - DummyClientFace face({false, false, override}); - face.processEvents(time::milliseconds(200)); - BOOST_CHECK(isOverrideInvoked); -} - -BOOST_AUTO_TEST_SUITE_END() // TestDummyClientFace -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace tests -} // namespace util -} // namespace ndn diff --git a/tests/unit-tests/util/face-uri.t.cpp b/tests/unit-tests/util/face-uri.t.cpp deleted file mode 100644 index 6cf52d971..000000000 --- a/tests/unit-tests/util/face-uri.t.cpp +++ /dev/null @@ -1,523 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California, - * Arizona Board of Regents, - * Colorado State University, - * University Pierre & Marie Curie, Sorbonne University, - * Washington University in St. Louis, - * Beijing Institute of Technology, - * The University of Memphis. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/face-uri.hpp" - -#include "boost-test.hpp" -#include "../network-configuration-detector.hpp" - -namespace ndn { -namespace util { -namespace tests { - -using ndn::tests::NetworkConfigurationDetector; - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_AUTO_TEST_SUITE(TestFaceUri) - -class CanonizeFixture : noncopyable -{ -protected: - CanonizeFixture() - : m_nPending(0) - { - } - - void - addTest(const std::string& request, bool shouldSucceed, const std::string& expectedUri); - - void - runTests() - { - m_io.run(); - BOOST_CHECK_EQUAL(m_nPending, 0); - } - -private: - class CanonizeTestCase - { - public: - CanonizeTestCase(const std::string& request, - bool shouldSucceed, const std::string& expectedUri) - : m_shouldSucceed(shouldSucceed) - , m_expectedUri(expectedUri) - , m_message(request + " should " + (shouldSucceed ? "succeed" : "fail")) - , m_isCompleted(false) - { - } - - public: - bool m_shouldSucceed; - std::string m_expectedUri; - std::string m_message; - bool m_isCompleted; - }; - - // tc is a shared_ptr passed by value, because this function can take ownership - void - onCanonizeSuccess(shared_ptr tc, const FaceUri& canonicalUri) - { - BOOST_CHECK(!tc->m_isCompleted); - tc->m_isCompleted = true; - --m_nPending; - - BOOST_CHECK_MESSAGE(tc->m_shouldSucceed, tc->m_message); - BOOST_CHECK_EQUAL(tc->m_expectedUri, canonicalUri.toString()); - } - - // tc is a shared_ptr passed by value, because this function can take ownership - void - onCanonizeFailure(shared_ptr tc, const std::string& reason) - { - BOOST_CHECK(!tc->m_isCompleted); - tc->m_isCompleted = true; - --m_nPending; - - BOOST_CHECK_MESSAGE(!tc->m_shouldSucceed, tc->m_message); - } - -private: - boost::asio::io_service m_io; - ssize_t m_nPending; -}; - -void -CanonizeFixture::addTest(const std::string& request, - bool shouldSucceed, const std::string& expectedUri) -{ - ++m_nPending; - auto tc = make_shared(request, shouldSucceed, expectedUri); - - FaceUri uri(request); - uri.canonize(bind(&CanonizeFixture::onCanonizeSuccess, this, tc, _1), - bind(&CanonizeFixture::onCanonizeFailure, this, tc, _1), - m_io, time::seconds(10)); -} - -BOOST_AUTO_TEST_CASE(ParseInternal) -{ - FaceUri uri; - - BOOST_CHECK(uri.parse("internal://")); - BOOST_CHECK_EQUAL(uri.getScheme(), "internal"); - BOOST_CHECK_EQUAL(uri.getHost(), ""); - BOOST_CHECK_EQUAL(uri.getPort(), ""); - BOOST_CHECK_EQUAL(uri.getPath(), ""); - - BOOST_CHECK_EQUAL(uri.parse("internal:"), false); - BOOST_CHECK_EQUAL(uri.parse("internal:/"), false); -} - -BOOST_AUTO_TEST_CASE(ParseUdp) -{ - BOOST_CHECK_NO_THROW(FaceUri("udp://hostname:6363")); - BOOST_CHECK_THROW(FaceUri("udp//hostname:6363"), FaceUri::Error); - BOOST_CHECK_THROW(FaceUri("udp://hostname:port"), FaceUri::Error); - - FaceUri uri; - BOOST_CHECK_EQUAL(uri.parse("udp//hostname:6363"), false); - - BOOST_CHECK(uri.parse("udp://hostname:80")); - BOOST_CHECK_EQUAL(uri.getScheme(), "udp"); - BOOST_CHECK_EQUAL(uri.getHost(), "hostname"); - BOOST_CHECK_EQUAL(uri.getPort(), "80"); - BOOST_CHECK_EQUAL(uri.getPath(), ""); - - BOOST_CHECK(uri.parse("udp4://192.0.2.1:20")); - BOOST_CHECK_EQUAL(uri.getScheme(), "udp4"); - BOOST_CHECK_EQUAL(uri.getHost(), "192.0.2.1"); - BOOST_CHECK_EQUAL(uri.getPort(), "20"); - BOOST_CHECK_EQUAL(uri.getPath(), ""); - - BOOST_CHECK(uri.parse("udp6://[2001:db8:3f9:0::1]:6363")); - BOOST_CHECK_EQUAL(uri.getScheme(), "udp6"); - BOOST_CHECK_EQUAL(uri.getHost(), "2001:db8:3f9:0::1"); - BOOST_CHECK_EQUAL(uri.getPort(), "6363"); - BOOST_CHECK_EQUAL(uri.getPath(), ""); - - BOOST_CHECK(uri.parse("udp6://[2001:db8:3f9:0:3025:ccc5:eeeb:86d3]:6363")); - BOOST_CHECK_EQUAL(uri.getScheme(), "udp6"); - BOOST_CHECK_EQUAL(uri.getHost(), "2001:db8:3f9:0:3025:ccc5:eeeb:86d3"); - BOOST_CHECK_EQUAL(uri.getPort(), "6363"); - BOOST_CHECK_EQUAL(uri.getPath(), ""); - - BOOST_CHECK_EQUAL(uri.parse("udp6://[2001:db8:3f9:0:3025:ccc5:eeeb:86dg]:6363"), false); - - using namespace boost::asio; - ip::udp::endpoint endpoint4(ip::address_v4::from_string("192.0.2.1"), 7777); - BOOST_REQUIRE_NO_THROW(FaceUri(endpoint4)); - BOOST_CHECK_EQUAL(FaceUri(endpoint4).toString(), "udp4://192.0.2.1:7777"); - - ip::udp::endpoint endpoint6(ip::address_v6::from_string("2001:DB8::1"), 7777); - BOOST_REQUIRE_NO_THROW(FaceUri(endpoint6)); - BOOST_CHECK_EQUAL(FaceUri(endpoint6).toString(), "udp6://[2001:db8::1]:7777"); -} - -BOOST_FIXTURE_TEST_CASE(CheckCanonicalUdp, CanonizeFixture) -{ - BOOST_CHECK_EQUAL(FaceUri::canCanonize("udp"), true); - BOOST_CHECK_EQUAL(FaceUri::canCanonize("udp4"), true); - BOOST_CHECK_EQUAL(FaceUri::canCanonize("udp6"), true); - - BOOST_CHECK_EQUAL(FaceUri("udp4://192.0.2.1:6363").isCanonical(), true); - BOOST_CHECK_EQUAL(FaceUri("udp://192.0.2.1:6363").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("udp4://192.0.2.1").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("udp4://192.0.2.1:6363/").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("udp6://[2001:db8::1]:6363").isCanonical(), true); - BOOST_CHECK_EQUAL(FaceUri("udp6://[2001:db8::01]:6363").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("udp://example.net:6363").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("udp4://example.net:6363").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("udp6://example.net:6363").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("udp4://224.0.23.170:56363").isCanonical(), true); -} - -BOOST_FIXTURE_TEST_CASE(CanonizeUdpV4, CanonizeFixture) -{ - SKIP_IF_IPV4_UNAVAILABLE(); - - // IPv4 unicast - addTest("udp4://192.0.2.1:6363", true, "udp4://192.0.2.1:6363"); - addTest("udp://192.0.2.2:6363", true, "udp4://192.0.2.2:6363"); - addTest("udp4://192.0.2.3", true, "udp4://192.0.2.3:6363"); - addTest("udp4://192.0.2.4:6363/", true, "udp4://192.0.2.4:6363"); - addTest("udp4://192.0.2.5:9695", true, "udp4://192.0.2.5:9695"); - addTest("udp4://192.0.2.666:6363", false, ""); - addTest("udp4://google-public-dns-a.google.com", true, "udp4://8.8.8.8:6363"); - addTest("udp4://invalid.invalid", false, ""); - - // IPv4 multicast - addTest("udp4://224.0.23.170:56363", true, "udp4://224.0.23.170:56363"); - addTest("udp4://224.0.23.170", true, "udp4://224.0.23.170:56363"); - addTest("udp4://all-routers.mcast.net:56363", true, "udp4://224.0.0.2:56363"); - - runTests(); -} - -BOOST_FIXTURE_TEST_CASE(CanonizeUdpV6, CanonizeFixture) -{ - SKIP_IF_IPV6_UNAVAILABLE(); - - // IPv6 unicast - addTest("udp6://[2001:db8::1]:6363", true, "udp6://[2001:db8::1]:6363"); - addTest("udp://[2001:db8::1]:6363", true, "udp6://[2001:db8::1]:6363"); - addTest("udp6://[2001:db8::01]:6363", true, "udp6://[2001:db8::1]:6363"); - addTest("udp6://google-public-dns-a.google.com", true, "udp6://[2001:4860:4860::8888]:6363"); - addTest("udp6://invalid.invalid", false, ""); - addTest("udp://invalid.invalid", false, ""); - - // IPv6 multicast - addTest("udp6://[ff02::2]:56363", true, "udp6://[ff02::2]:56363"); - addTest("udp6://[ff02::2]", true, "udp6://[ff02::2]:56363"); - - runTests(); -} - -BOOST_AUTO_TEST_CASE(ParseTcp) -{ - FaceUri uri; - - BOOST_CHECK(uri.parse("tcp://random.host.name")); - BOOST_CHECK_EQUAL(uri.getScheme(), "tcp"); - BOOST_CHECK_EQUAL(uri.getHost(), "random.host.name"); - BOOST_CHECK_EQUAL(uri.getPort(), ""); - BOOST_CHECK_EQUAL(uri.getPath(), ""); - - BOOST_CHECK_EQUAL(uri.parse("tcp://192.0.2.1:"), false); - BOOST_CHECK_EQUAL(uri.parse("tcp://[::zzzz]"), false); - - using namespace boost::asio; - ip::tcp::endpoint endpoint4(ip::address_v4::from_string("192.0.2.1"), 7777); - BOOST_REQUIRE_NO_THROW(FaceUri(endpoint4)); - BOOST_CHECK_EQUAL(FaceUri(endpoint4).toString(), "tcp4://192.0.2.1:7777"); - - BOOST_REQUIRE_NO_THROW(FaceUri(endpoint4, "wsclient")); - BOOST_CHECK_EQUAL(FaceUri(endpoint4, "wsclient").toString(), "wsclient://192.0.2.1:7777"); - - ip::tcp::endpoint endpoint6(ip::address_v6::from_string("2001:DB8::1"), 7777); - BOOST_REQUIRE_NO_THROW(FaceUri(endpoint6)); - BOOST_CHECK_EQUAL(FaceUri(endpoint6).toString(), "tcp6://[2001:db8::1]:7777"); -} - -BOOST_FIXTURE_TEST_CASE(CheckCanonicalTcp, CanonizeFixture) -{ - BOOST_CHECK_EQUAL(FaceUri::canCanonize("tcp"), true); - BOOST_CHECK_EQUAL(FaceUri::canCanonize("tcp4"), true); - BOOST_CHECK_EQUAL(FaceUri::canCanonize("tcp6"), true); - - BOOST_CHECK_EQUAL(FaceUri("tcp4://192.0.2.1:6363").isCanonical(), true); - BOOST_CHECK_EQUAL(FaceUri("tcp://192.0.2.1:6363").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("tcp4://192.0.2.1").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("tcp4://192.0.2.1:6363/").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("tcp6://[2001:db8::1]:6363").isCanonical(), true); - BOOST_CHECK_EQUAL(FaceUri("tcp6://[2001:db8::01]:6363").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("tcp://example.net:6363").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("tcp4://example.net:6363").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("tcp6://example.net:6363").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("tcp4://224.0.23.170:56363").isCanonical(), false); -} - -BOOST_FIXTURE_TEST_CASE(CanonizeTcpV4, CanonizeFixture) -{ - SKIP_IF_IPV4_UNAVAILABLE(); - - // IPv4 unicast - addTest("tcp4://192.0.2.1:6363", true, "tcp4://192.0.2.1:6363"); - addTest("tcp://192.0.2.2:6363", true, "tcp4://192.0.2.2:6363"); - addTest("tcp4://192.0.2.3", true, "tcp4://192.0.2.3:6363"); - addTest("tcp4://192.0.2.4:6363/", true, "tcp4://192.0.2.4:6363"); - addTest("tcp4://192.0.2.5:9695", true, "tcp4://192.0.2.5:9695"); - addTest("tcp4://192.0.2.666:6363", false, ""); - addTest("tcp4://google-public-dns-a.google.com", true, "tcp4://8.8.8.8:6363"); - addTest("tcp4://invalid.invalid", false, ""); - - // IPv4 multicast - addTest("tcp4://224.0.23.170:56363", false, ""); - addTest("tcp4://224.0.23.170", false, ""); - addTest("tcp4://all-routers.mcast.net:56363", false, ""); - - runTests(); -} - -BOOST_FIXTURE_TEST_CASE(CanonizeTcpV6, CanonizeFixture) -{ - SKIP_IF_IPV6_UNAVAILABLE(); - - // IPv6 unicast - addTest("tcp6://[2001:db8::1]:6363", true, "tcp6://[2001:db8::1]:6363"); - addTest("tcp://[2001:db8::1]:6363", true, "tcp6://[2001:db8::1]:6363"); - addTest("tcp6://[2001:db8::01]:6363", true, "tcp6://[2001:db8::1]:6363"); - addTest("tcp6://google-public-dns-a.google.com", true, "tcp6://[2001:4860:4860::8888]:6363"); - addTest("tcp6://invalid.invalid", false, ""); - addTest("tcp://invalid.invalid", false, ""); - - // IPv6 multicast - addTest("tcp6://[ff02::2]:56363", false, ""); - addTest("tcp6://[ff02::2]", false, ""); - - runTests(); -} - -BOOST_AUTO_TEST_CASE(ParseUnix) -{ - FaceUri uri; - - BOOST_CHECK(uri.parse("unix:///var/run/example.sock")); - BOOST_CHECK_EQUAL(uri.getScheme(), "unix"); - BOOST_CHECK_EQUAL(uri.getHost(), ""); - BOOST_CHECK_EQUAL(uri.getPort(), ""); - BOOST_CHECK_EQUAL(uri.getPath(), "/var/run/example.sock"); - - //BOOST_CHECK_EQUAL(uri.parse("unix://var/run/example.sock"), false); - // This is not a valid unix:/ URI, but the parse would treat "var" as host - -#ifdef HAVE_UNIX_SOCKETS - using namespace boost::asio; - local::stream_protocol::endpoint endpoint("/var/run/example.sock"); - BOOST_REQUIRE_NO_THROW(FaceUri(endpoint)); - BOOST_CHECK_EQUAL(FaceUri(endpoint).toString(), "unix:///var/run/example.sock"); -#endif // HAVE_UNIX_SOCKETS -} - -BOOST_AUTO_TEST_CASE(ParseFd) -{ - FaceUri uri; - - BOOST_CHECK(uri.parse("fd://6")); - BOOST_CHECK_EQUAL(uri.getScheme(), "fd"); - BOOST_CHECK_EQUAL(uri.getHost(), "6"); - BOOST_CHECK_EQUAL(uri.getPort(), ""); - BOOST_CHECK_EQUAL(uri.getPath(), ""); - - int fd = 21; - BOOST_REQUIRE_NO_THROW(FaceUri::fromFd(fd)); - BOOST_CHECK_EQUAL(FaceUri::fromFd(fd).toString(), "fd://21"); -} - -BOOST_AUTO_TEST_CASE(ParseEther) -{ - FaceUri uri; - - BOOST_CHECK(uri.parse("ether://[08:00:27:01:dd:01]")); - BOOST_CHECK_EQUAL(uri.getScheme(), "ether"); - BOOST_CHECK_EQUAL(uri.getHost(), "08:00:27:01:dd:01"); - BOOST_CHECK_EQUAL(uri.getPort(), ""); - BOOST_CHECK_EQUAL(uri.getPath(), ""); - - BOOST_CHECK_EQUAL(uri.parse("ether://[08:00:27:zz:dd:01]"), false); - - ethernet::Address address = ethernet::Address::fromString("33:33:01:01:01:01"); - BOOST_REQUIRE_NO_THROW(FaceUri(address)); - BOOST_CHECK_EQUAL(FaceUri(address).toString(), "ether://[33:33:01:01:01:01]"); -} - -BOOST_FIXTURE_TEST_CASE(CanonizeEther, CanonizeFixture) -{ - BOOST_CHECK_EQUAL(FaceUri::canCanonize("ether"), true); - - BOOST_CHECK_EQUAL(FaceUri("ether://[08:00:27:01:01:01]").isCanonical(), true); - BOOST_CHECK_EQUAL(FaceUri("ether://[08:00:27:1:1:1]").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("ether://[08:00:27:01:01:01]/").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("ether://[33:33:01:01:01:01]").isCanonical(), true); - - addTest("ether://[08:00:27:01:01:01]", true, "ether://[08:00:27:01:01:01]"); - addTest("ether://[08:00:27:1:1:1]", true, "ether://[08:00:27:01:01:01]"); - addTest("ether://[08:00:27:01:01:01]/", true, "ether://[08:00:27:01:01:01]"); - addTest("ether://[33:33:01:01:01:01]", true, "ether://[33:33:01:01:01:01]"); - - runTests(); -} - -BOOST_AUTO_TEST_CASE(ParseDev) -{ - FaceUri uri; - - BOOST_CHECK(uri.parse("dev://eth0")); - BOOST_CHECK_EQUAL(uri.getScheme(), "dev"); - BOOST_CHECK_EQUAL(uri.getHost(), "eth0"); - BOOST_CHECK_EQUAL(uri.getPort(), ""); - BOOST_CHECK_EQUAL(uri.getPath(), ""); - - std::string ifname = "en1"; - BOOST_REQUIRE_NO_THROW(FaceUri::fromDev(ifname)); - BOOST_CHECK_EQUAL(FaceUri::fromDev(ifname).toString(), "dev://en1"); -} - -BOOST_AUTO_TEST_CASE(ParseUdpDev) -{ - FaceUri uri; - - BOOST_CHECK(uri.parse("udp4+dev://eth0:7777")); - BOOST_CHECK_EQUAL(uri.getScheme(), "udp4+dev"); - BOOST_CHECK_EQUAL(uri.getHost(), "eth0"); - BOOST_CHECK_EQUAL(uri.getPort(), "7777"); - BOOST_CHECK_EQUAL(uri.getPath(), ""); - - BOOST_CHECK(uri.parse("udp6+dev://eth1:7777")); - BOOST_CHECK_EQUAL(uri.getScheme(), "udp6+dev"); - BOOST_CHECK_EQUAL(uri.getHost(), "eth1"); - BOOST_CHECK_EQUAL(uri.getPort(), "7777"); - BOOST_CHECK_EQUAL(uri.getPath(), ""); - - BOOST_CHECK(uri.parse("abc+efg://eth0")); - BOOST_CHECK(!uri.parse("abc+://eth0")); - BOOST_CHECK(!uri.parse("+abc://eth0")); - - using namespace boost::asio; - - ip::udp::endpoint endpoint4(ip::udp::v4(), 7777); - BOOST_REQUIRE_NO_THROW(FaceUri::fromUdpDev(endpoint4, "en1")); - BOOST_CHECK_EQUAL(FaceUri::fromUdpDev(endpoint4, "en1").toString(), "udp4+dev://en1:7777"); - - ip::udp::endpoint endpoint6(ip::udp::v6(), 7777); - BOOST_REQUIRE_NO_THROW(FaceUri::fromUdpDev(endpoint6, "en2")); - BOOST_CHECK_EQUAL(FaceUri::fromUdpDev(endpoint6, "en2").toString(), "udp6+dev://en2:7777"); -} - -BOOST_FIXTURE_TEST_CASE(CanonizeUdpDev, CanonizeFixture) -{ - BOOST_CHECK_EQUAL(FaceUri("udp4+dev://eth0:7777").isCanonical(), true); - BOOST_CHECK_EQUAL(FaceUri("udp6+dev://eth1:7777").isCanonical(), true); - BOOST_CHECK_EQUAL(FaceUri("udp+dev://eth1:7777").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("udp6+dev://eth1").isCanonical(), false); - - addTest("udp4+dev://en0:7777", true, "udp4+dev://en0:7777"); - addTest("udp6+dev://en0:7777", true, "udp6+dev://en0:7777"); - addTest("udp+dev://en1:7777", false, ""); - addTest("udp6+dev://en2", false, ""); -} - -BOOST_AUTO_TEST_CASE(CanonizeEmptyCallback) -{ - boost::asio::io_service io; - - // unsupported scheme - FaceUri("null://").canonize(FaceUri::CanonizeSuccessCallback(), - FaceUri::CanonizeFailureCallback(), - io, time::milliseconds(1)); - - // cannot resolve - FaceUri("udp://192.0.2.333").canonize(FaceUri::CanonizeSuccessCallback(), - FaceUri::CanonizeFailureCallback(), - io, time::milliseconds(1)); - - // already canonical - FaceUri("udp4://192.0.2.1:6363").canonize(FaceUri::CanonizeSuccessCallback(), - FaceUri::CanonizeFailureCallback(), - io, time::milliseconds(1)); - - // need DNS resolution - FaceUri("udp://192.0.2.1:6363").canonize(FaceUri::CanonizeSuccessCallback(), - FaceUri::CanonizeFailureCallback(), - io, time::milliseconds(1)); - - io.run(); // should not crash - - // avoid "test case [...] did not check any assertions" message from Boost.Test - BOOST_CHECK(true); -} - -BOOST_FIXTURE_TEST_CASE(CanonizeUnsupported, CanonizeFixture) -{ - BOOST_CHECK_EQUAL(FaceUri::canCanonize("internal"), false); - BOOST_CHECK_EQUAL(FaceUri::canCanonize("null"), false); - BOOST_CHECK_EQUAL(FaceUri::canCanonize("unix"), false); - BOOST_CHECK_EQUAL(FaceUri::canCanonize("fd"), false); - BOOST_CHECK_EQUAL(FaceUri::canCanonize("dev"), false); - - BOOST_CHECK_EQUAL(FaceUri("internal://").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("null://").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("unix:///var/run/nfd.sock").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("fd://0").isCanonical(), false); - BOOST_CHECK_EQUAL(FaceUri("dev://eth1").isCanonical(), false); - - addTest("internal://", false, ""); - addTest("null://", false, ""); - addTest("unix:///var/run/nfd.sock", false, ""); - addTest("fd://0", false, ""); - addTest("dev://eth1", false, ""); - - runTests(); -} - -BOOST_AUTO_TEST_CASE(Bug1635) -{ - FaceUri uri; - - BOOST_CHECK(uri.parse("wsclient://[::ffff:76.90.11.239]:56366")); - BOOST_CHECK_EQUAL(uri.getScheme(), "wsclient"); - BOOST_CHECK_EQUAL(uri.getHost(), "76.90.11.239"); - BOOST_CHECK_EQUAL(uri.getPort(), "56366"); - BOOST_CHECK_EQUAL(uri.getPath(), ""); - BOOST_CHECK_EQUAL(uri.toString(), "wsclient://76.90.11.239:56366"); -} - -BOOST_AUTO_TEST_SUITE_END() // TestFaceUri -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace tests -} // namespace util -} // namespace ndn diff --git a/tests/unit-tests/util/in-memory-storage-common.t.cpp b/tests/unit-tests/util/in-memory-storage-common.t.cpp deleted file mode 100644 index e6a3ab7c2..000000000 --- a/tests/unit-tests/util/in-memory-storage-common.t.cpp +++ /dev/null @@ -1,1061 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/in-memory-storage-persistent.hpp" -#include "util/in-memory-storage-fifo.hpp" -#include "util/in-memory-storage-lfu.hpp" -#include "util/in-memory-storage-lru.hpp" -#include "security/key-chain.hpp" - -#include "boost-test.hpp" -#include "../make-interest-data.hpp" -#include "../unit-test-time-fixture.hpp" - -#include - -namespace ndn { -namespace util { -namespace tests { - -using namespace ndn::tests; - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_AUTO_TEST_SUITE(TestInMemoryStorage) -BOOST_AUTO_TEST_SUITE(Common) - -using InMemoryStorages = boost::mpl::list; - -BOOST_AUTO_TEST_CASE_TEMPLATE(Insertion, T, InMemoryStorages) -{ - T ims; - - ims.insert(*makeData("/a")); - ims.insert(*makeData("/b")); - ims.insert(*makeData("/c")); - ims.insert(*makeData("/d")); - - BOOST_CHECK_EQUAL(ims.size(), 4); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(Insertion2, T, InMemoryStorages) -{ - T ims; - - Name name("/a"); - - uint32_t content1 = 1; - shared_ptr data1 = makeData(name); - data1->setFreshnessPeriod(time::milliseconds(99999)); - data1->setContent(reinterpret_cast(&content1), sizeof(content1)); - signData(data1); - ims.insert(*data1); - - uint32_t content2 = 2; - shared_ptr data2 = makeData(name); - data2->setFreshnessPeriod(time::milliseconds(99999)); - data2->setContent(reinterpret_cast(&content2), sizeof(content2)); - signData(data2); - ims.insert(*data2); - - BOOST_CHECK_EQUAL(ims.size(), 2); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(DuplicateInsertion, T, InMemoryStorages) -{ - T ims; - - shared_ptr data0 = makeData("/insert/smth"); - ims.insert(*data0); - - shared_ptr data = makeData("/insert/duplicate"); - ims.insert(*data); - - ims.insert(*data); - BOOST_CHECK_EQUAL(ims.size(), 2); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(DuplicateInsertion2, T, InMemoryStorages) -{ - T ims; - - shared_ptr data = makeData("/insert/duplicate"); - ims.insert(*data); - - ims.insert(*data); - BOOST_CHECK_EQUAL(ims.size(), 1); - - shared_ptr data2 = makeData("/insert/original"); - ims.insert(*data2); - BOOST_CHECK_EQUAL(ims.size(), 2); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndFind, T, InMemoryStorages) -{ - T ims; - - Name name("/insert/and/find"); - - shared_ptr data = makeData(name); - ims.insert(*data); - - shared_ptr interest = makeInterest(name); - - shared_ptr found = ims.find(*interest); - BOOST_CHECK(found != nullptr); - BOOST_CHECK_EQUAL(data->getName(), found->getName()); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndNotFind, T, InMemoryStorages) -{ - T ims; - - Name name("/insert/and/find"); - shared_ptr data = makeData(name); - ims.insert(*data); - - Name name2("/not/find"); - shared_ptr interest = makeInterest(name2); - - shared_ptr found = ims.find(*interest); - - BOOST_CHECK_EQUAL(found.get(), static_cast(0)); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndFindByName, T, InMemoryStorages) -{ - T ims; - - Name name("/insert/and/find"); - - shared_ptr data = makeData(name); - ims.insert(*data); - - shared_ptr found = ims.find(name); - BOOST_CHECK(found != nullptr); - BOOST_CHECK_EQUAL(data->getName(), found->getName()); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndFindByFullName, T, InMemoryStorages) -{ - T ims; - - Name name("/insert/and/find"); - - shared_ptr data = makeData(name); - ims.insert(*data); - - shared_ptr found = ims.find(data->getFullName()); - BOOST_CHECK(found != nullptr); - BOOST_CHECK_EQUAL(data->getFullName(), found->getFullName()); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndNotFindByName, T, InMemoryStorages) -{ - T ims; - - Name name("/insert/and/find"); - shared_ptr data = makeData(name); - ims.insert(*data); - - Name name2("/not/find"); - - shared_ptr found = ims.find(name2); - BOOST_CHECK(found == nullptr); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndNotFindByFullName, T, InMemoryStorages) -{ - T ims; - - Name name("/a"); - uint32_t content1 = 1; - shared_ptr data1 = makeData(name); - data1->setContent(reinterpret_cast(&content1), sizeof(content1)); - signData(data1); - ims.insert(*data1); - - uint32_t content2 = 2; - shared_ptr data2 = makeData(name); - data2->setContent(reinterpret_cast(&content2), sizeof(content2)); - signData(data2); - - shared_ptr found = ims.find(data2->getFullName()); - BOOST_CHECK(found == nullptr); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndEraseByName, T, InMemoryStorages) -{ - T ims; - - Name name("/insertandremovebyname"); - - uint32_t content1 = 1; - shared_ptr data1 = makeData(name); - data1->setFreshnessPeriod(time::milliseconds(99999)); - data1->setContent(reinterpret_cast(&content1), sizeof(content1)); - signData(data1); - ims.insert(*data1); - - uint32_t content2 = 2; - shared_ptr data2 = makeData(name); - data2->setFreshnessPeriod(time::milliseconds(99999)); - data2->setContent(reinterpret_cast(&content2), sizeof(content2)); - signData(data2); - ims.insert(*data2); - - shared_ptr data3 = makeData("/insertandremovebyname/1"); - ims.insert(*data3); - - shared_ptr data4 = makeData("/insertandremovebyname/2"); - ims.insert(*data4); - - BOOST_CHECK_EQUAL(ims.size(), 4); - - ims.erase(data1->getFullName(), false); - BOOST_CHECK_EQUAL(ims.size(), 3); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndEraseByPrefix, T, InMemoryStorages) -{ - T ims; - - shared_ptr data = makeData("/a"); - ims.insert(*data); - - shared_ptr data2 = makeData("/b"); - ims.insert(*data2); - - shared_ptr data3 = makeData("/c"); - ims.insert(*data3); - - shared_ptr data4 = makeData("/d"); - ims.insert(*data4); - - shared_ptr data5 = makeData("/c/c/1/2/3/4/5/6"); - ims.insert(*data5); - - shared_ptr data6 = makeData("/c/c/1/2/3"); - ims.insert(*data6); - - shared_ptr data7 = makeData("/c/c/1"); - ims.insert(*data7); - - BOOST_CHECK_EQUAL(ims.size(), 7); - - Name name("/c"); - ims.erase(name); - BOOST_CHECK_EQUAL(ims.size(), 3); - BOOST_CHECK_EQUAL(ims.getCapacity(), 5); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(DigestCalculation, T, InMemoryStorages) -{ - shared_ptr data = makeData("/digest/compute"); - - ndn::ConstBufferPtr digest1 = ndn::crypto::computeSha256Digest(data->wireEncode().wire(), - data->wireEncode().size()); - BOOST_CHECK_EQUAL(digest1->size(), 32); - - InMemoryStorageEntry* entry = new InMemoryStorageEntry(); - entry->setData(*data); - - BOOST_CHECK_EQUAL_COLLECTIONS(digest1->begin(), digest1->end(), - entry->getFullName()[-1].value_begin(), - entry->getFullName()[-1].value_end()); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(Iterator, T, InMemoryStorages) -{ - T ims; - - BOOST_CONCEPT_ASSERT((boost::InputIterator)); - - for (int i = 0; i < 10; i++) { - std::ostringstream convert; - convert << i; - Name name("/" + convert.str()); - shared_ptr data = makeData(name); - ims.insert(*data); - } - - InMemoryStorage::const_iterator it = ims.begin(); - InMemoryStorage::const_iterator tmp1 = it; - BOOST_REQUIRE(tmp1 == it); - InMemoryStorage::const_iterator tmp2 = tmp1++; - BOOST_REQUIRE(tmp2 != tmp1); - tmp2 = ++tmp1; - BOOST_REQUIRE(tmp2 == tmp1); - - int i = 0; - for (;it != ims.end(); it++) { - std::ostringstream convert; - convert << i; - Name name("/" + convert.str()); - BOOST_CHECK_EQUAL(it->getName(), name); - BOOST_CHECK_EQUAL((*it).getName(), name); - i++; - } -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(InsertCanonical, T, InMemoryStorages) -{ - T ims; - - shared_ptr data = makeData("/a"); - ims.insert(*data); - - shared_ptr data2 = makeData("/b"); - ims.insert(*data2); - - shared_ptr data3 = makeData("/c"); - ims.insert(*data3); - - shared_ptr data4 = makeData("/d"); - ims.insert(*data4); - - shared_ptr data5 = makeData("/c/c/1/2/3/4/5/6"); - ims.insert(*data5); - - shared_ptr data6 = makeData("/c/c/1/2/3"); - ims.insert(*data6); - - shared_ptr data7 = makeData("/c/c/1"); - ims.insert(*data7); - - // avoid "test case [...] did not check any assertions" message from Boost.Test - BOOST_CHECK(true); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(EraseCanonical, T, InMemoryStorages) -{ - T ims; - - shared_ptr data = makeData("/a"); - ims.insert(*data); - - shared_ptr data2 = makeData("/b"); - ims.insert(*data2); - - shared_ptr data3 = makeData("/c"); - ims.insert(*data3); - - shared_ptr data4 = makeData("/d"); - ims.insert(*data4); - - shared_ptr data5 = makeData("/c/c/1/2/3/4/5/6"); - ims.insert(*data5); - - shared_ptr data6 = makeData("/c/c/1/2/3"); - ims.insert(*data6); - - shared_ptr data7 = makeData("/c/c/1"); - ims.insert(*data7); - - ndn::ConstBufferPtr digest1 = ndn::crypto::computeSha256Digest(data->wireEncode().wire(), - data->wireEncode().size()); - - Name name("/a"); - ims.erase(name); - BOOST_CHECK_EQUAL(ims.size(), 6); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(ImplicitDigestSelector, T, InMemoryStorages) -{ - T ims; - - Name name("/digest/works"); - shared_ptr data = makeData(name); - ims.insert(*data); - - shared_ptr data2 = makeData("/a"); - ims.insert(*data2); - - shared_ptr data3 = makeData("/z/z/z"); - ims.insert(*data3); - - ndn::ConstBufferPtr digest1 = ndn::crypto::computeSha256Digest(data->wireEncode().wire(), - data->wireEncode().size()); - - shared_ptr interest = makeInterest(""); - interest->setName(Name(name).appendImplicitSha256Digest(digest1->buf(), digest1->size())); - interest->setMinSuffixComponents(0); - interest->setMaxSuffixComponents(0); - - shared_ptr found = ims.find(*interest); - BOOST_REQUIRE(found != nullptr); - BOOST_CHECK_EQUAL(found->getName(), name); - - shared_ptr interest2 = makeInterest(""); - uint8_t digest2[32] = {0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1}; - interest2->setName(Name(name).appendImplicitSha256Digest(digest2, 32)); - interest2->setMinSuffixComponents(0); - interest2->setMaxSuffixComponents(0); - - shared_ptr notfound = ims.find(*interest2); - BOOST_CHECK(notfound == nullptr); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(ChildSelector, T, InMemoryStorages) -{ - T ims; - - shared_ptr data = makeData("/a"); - ims.insert(*data); - - shared_ptr data2 = makeData("/b"); - ims.insert(*data2); - - shared_ptr data4 = makeData("/d"); - ims.insert(*data4); - - shared_ptr data5 = makeData("/c/c"); - ims.insert(*data5); - - shared_ptr data6 = makeData("/c/f"); - ims.insert(*data6); - - shared_ptr data7 = makeData("/c/n"); - ims.insert(*data7); - - shared_ptr interest = makeInterest("/c"); - interest->setChildSelector(1); - - shared_ptr found = ims.find(*interest); - BOOST_CHECK_EQUAL(found->getName(), "/c/n"); - - shared_ptr interest2 = makeInterest("/c"); - interest2->setChildSelector(0); - - shared_ptr found2 = ims.find(*interest2); - BOOST_CHECK_EQUAL(found2->getName(), "/c/c"); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(ChildSelector2, T, InMemoryStorages) -{ - T ims; - - shared_ptr data = makeData("/a/b/1"); - ims.insert(*data); - - shared_ptr data2 = makeData("/a/b/2"); - ims.insert(*data2); - - shared_ptr data3 = makeData("/a/z/1"); - ims.insert(*data3); - - shared_ptr data4 = makeData("/a/z/2"); - ims.insert(*data4); - - shared_ptr interest = makeInterest("/a"); - interest->setChildSelector(1); - - shared_ptr found = ims.find(*interest); - BOOST_CHECK_EQUAL(found->getName(), "/a/z/1"); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(PublisherKeySelector, T, InMemoryStorages) -{ - T ims; - - Name name("/insert/withkey"); - shared_ptr data = makeData(name); - ims.insert(*data); - - shared_ptr interest = makeInterest(name); - Name keyName("/somewhere/key"); - - ndn::KeyLocator locator(keyName); - interest->setPublisherPublicKeyLocator(locator); - - shared_ptr found = ims.find(*interest); - BOOST_CHECK(found == nullptr); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(PublisherKeySelector2, T, InMemoryStorages) -{ - T ims; - Name name("/insert/withkey"); - shared_ptr data = makeData(name); - ims.insert(*data); - - Name name2("/insert/withkey2"); - shared_ptr data2 = make_shared(name2); - - Name keyName("/somewhere/key"); - const ndn::KeyLocator locator(keyName); - - ndn::SignatureSha256WithRsa fakeSignature; - fakeSignature.setValue(makeEmptyBlock(tlv::SignatureValue)); - - fakeSignature.setKeyLocator(locator); - data2->setSignature(fakeSignature); - data2->wireEncode(); - - ims.insert(*data2); - - shared_ptr interest = makeInterest(name2); - interest->setPublisherPublicKeyLocator(locator); - - shared_ptr found = ims.find(*interest); - BOOST_CHECK(found != nullptr); - BOOST_CHECK_EQUAL(found->getName(), data2->getName()); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(MinMaxComponentsSelector, T, InMemoryStorages) -{ - T ims; - - shared_ptr data = makeData("/a"); - ims.insert(*data); - - shared_ptr data2 = makeData("/b"); - ims.insert(*data2); - - shared_ptr data4 = makeData("/d"); - ims.insert(*data4); - - shared_ptr data5 = makeData("/c/c/1/2/3/4/5/6"); - ims.insert(*data5); - - shared_ptr data6 = makeData("/c/c/6/7/8/9"); - ims.insert(*data6); - - shared_ptr data7 = makeData("/c/c/1/2/3"); - ims.insert(*data7); - - shared_ptr data8 = makeData("/c/c/1"); - ims.insert(*data8); - - shared_ptr interest = makeInterest("/c/c"); - interest->setMinSuffixComponents(3); - interest->setChildSelector(0); - - shared_ptr found = ims.find(*interest); - BOOST_CHECK_EQUAL(found->getName(), "/c/c/1/2/3"); - - shared_ptr interest2 = makeInterest("/c/c"); - interest2->setMinSuffixComponents(4); - interest2->setChildSelector(1); - - shared_ptr found2 = ims.find(*interest2); - BOOST_CHECK_EQUAL(found2->getName(), "/c/c/6/7/8/9"); - - shared_ptr interest3 = makeInterest("/c/c"); - interest3->setMaxSuffixComponents(2); - interest3->setChildSelector(1); - - shared_ptr found3 = ims.find(*interest3); - BOOST_CHECK_EQUAL(found3->getName(), "/c/c/1"); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(ExcludeSelector, T, InMemoryStorages) -{ - T ims; - - shared_ptr data = makeData("/a"); - ims.insert(*data); - - shared_ptr data2 = makeData("/b"); - ims.insert(*data2); - - shared_ptr data3 = makeData("/c/a"); - ims.insert(*data3); - - shared_ptr data4 = makeData("/d"); - ims.insert(*data4); - - shared_ptr data5 = makeData("/c/c"); - ims.insert(*data5); - - shared_ptr data6 = makeData("/c/f"); - ims.insert(*data6); - - shared_ptr data7 = makeData("/c/n"); - ims.insert(*data7); - - shared_ptr interest = makeInterest("/c"); - interest->setChildSelector(1); - Exclude e; - e.excludeOne (Name::Component("n")); - interest->setExclude(e); - - shared_ptr found = ims.find(*interest); - BOOST_CHECK_EQUAL(found->getName(), "/c/f"); - - shared_ptr interest2 = makeInterest("/c"); - interest2->setChildSelector(0); - - Exclude e2; - e2.excludeOne (Name::Component("a")); - interest2->setExclude(e2); - - shared_ptr found2 = ims.find(*interest2); - BOOST_CHECK_EQUAL(found2->getName(), "/c/c"); - - shared_ptr interest3 = makeInterest("/c"); - interest3->setChildSelector(0); - - Exclude e3; - e3.excludeOne (Name::Component("c")); - interest3->setExclude(e3); - - shared_ptr found3 = ims.find(*interest3); - BOOST_CHECK_EQUAL(found3->getName(), "/c/a"); -} - -using InMemoryStoragesLimited = boost::mpl::list; - -BOOST_AUTO_TEST_CASE_TEMPLATE(SetCapacity, T, InMemoryStoragesLimited) -{ - T ims; - - ims.setCapacity(3); - ims.insert(*makeData("/1")); - ims.insert(*makeData("/2")); - ims.insert(*makeData("/3")); - BOOST_CHECK_EQUAL(ims.size(), 3); - - ims.setCapacity(2); - BOOST_CHECK_EQUAL(ims.size(), 2); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(GetLimit, T, InMemoryStoragesLimited) -{ - T ims(10000); - - BOOST_CHECK_EQUAL(ims.getLimit(), 10000); - - T ims2(4); - - BOOST_CHECK_EQUAL(ims2.getLimit(), 4); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndDouble, T, InMemoryStoragesLimited) -{ - T ims(40); - - for (int i = 0; i < 11; i++) { - std::ostringstream convert; - convert << i; - Name name("/" + convert.str()); - shared_ptr data = makeData(name); - data->setFreshnessPeriod(time::milliseconds(5000)); - signData(data); - ims.insert(*data); - } - - BOOST_CHECK_EQUAL(ims.size(), 11); - - BOOST_CHECK_EQUAL(ims.getCapacity(), 20); -} - -BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndEvict, T, InMemoryStoragesLimited) -{ - T ims(2); - - Name name("/insert/1"); - shared_ptr data = makeData(name); - ims.insert(*data); - - Name name2("/insert/2"); - shared_ptr data2 = makeData(name2); - ims.insert(*data2); - - Name name3("/insert/3"); - shared_ptr data3 = makeData(name3); - ims.insert(*data3); - - BOOST_CHECK_EQUAL(ims.size(), 2); - - shared_ptr interest = makeInterest(name); - shared_ptr found = ims.find(*interest); - BOOST_CHECK(found == nullptr); -} - -///as Find function is implemented at the base case, therefore testing for one derived class is -///sufficient for all -class FindFixture : public ndn::tests::UnitTestTimeFixture -{ -protected: - FindFixture() - : m_ims(io) - { - } - - Name - insert(uint32_t id, const Name& name, - const time::milliseconds& freshWindow = InMemoryStorage::INFINITE_WINDOW) - { - shared_ptr data = makeData(name); - data->setFreshnessPeriod(time::milliseconds(99999)); - data->setContent(reinterpret_cast(&id), sizeof(id)); - signData(data); - - m_ims.insert(*data, freshWindow); - - return data->getFullName(); - } - - Interest& - startInterest(const Name& name) - { - m_interest = makeInterest(name); - return *m_interest; - } - - uint32_t - find() - { - shared_ptr found = m_ims.find(*m_interest); - if (found == 0) { - return 0; - } - const Block& content = found->getContent(); - if (content.value_size() != sizeof(uint32_t)) { - return 0; - } - return *reinterpret_cast(content.value()); - } - -protected: - InMemoryStoragePersistent m_ims; - shared_ptr m_interest; -}; - -BOOST_FIXTURE_TEST_SUITE(Find, FindFixture) - -BOOST_AUTO_TEST_CASE(EmptyDataName) -{ - insert(1, "ndn:/"); - - startInterest("ndn:/"); - BOOST_CHECK_EQUAL(find(), 1); -} - -BOOST_AUTO_TEST_CASE(EmptyInterestName) -{ - insert(1, "ndn:/A"); - - startInterest("ndn:/"); - BOOST_CHECK_EQUAL(find(), 1); -} - -BOOST_AUTO_TEST_CASE(ExactName) -{ - insert(1, "ndn:/"); - insert(2, "ndn:/A"); - insert(3, "ndn:/A/B"); - insert(4, "ndn:/A/C"); - insert(5, "ndn:/D"); - - startInterest("ndn:/A"); - BOOST_CHECK_EQUAL(find(), 2); -} - -BOOST_AUTO_TEST_CASE(FullName) -{ - Name n1 = insert(1, "ndn:/A"); - Name n2 = insert(2, "ndn:/A"); - - startInterest(n1); - BOOST_CHECK_EQUAL(find(), 1); - - startInterest(n2); - BOOST_CHECK_EQUAL(find(), 2); -} - -BOOST_AUTO_TEST_CASE(Leftmost) -{ - insert(1, "ndn:/A"); - insert(2, "ndn:/B/p/1"); - insert(3, "ndn:/B/p/2"); - insert(4, "ndn:/B/q/1"); - insert(5, "ndn:/B/q/2"); - insert(6, "ndn:/C"); - - startInterest("ndn:/B"); - BOOST_CHECK_EQUAL(find(), 2); -} - -BOOST_AUTO_TEST_CASE(Rightmost) -{ - insert(1, "ndn:/A"); - insert(2, "ndn:/B/p/1"); - insert(3, "ndn:/B/p/2"); - insert(4, "ndn:/B/q/1"); - insert(5, "ndn:/B/q/2"); - insert(6, "ndn:/C"); - - startInterest("ndn:/B") - .setChildSelector(1); - BOOST_CHECK_EQUAL(find(), 4); -} - -BOOST_AUTO_TEST_CASE(MinSuffixComponents) -{ - insert(1, "ndn:/"); - insert(2, "ndn:/A"); - insert(3, "ndn:/B/1"); - insert(4, "ndn:/C/1/2"); - insert(5, "ndn:/D/1/2/3"); - insert(6, "ndn:/E/1/2/3/4"); - - startInterest("ndn:/") - .setMinSuffixComponents(0); - BOOST_CHECK_EQUAL(find(), 1); - - startInterest("ndn:/") - .setMinSuffixComponents(1); - BOOST_CHECK_EQUAL(find(), 1); - - startInterest("ndn:/") - .setMinSuffixComponents(2); - BOOST_CHECK_EQUAL(find(), 2); - - startInterest("ndn:/") - .setMinSuffixComponents(3); - BOOST_CHECK_EQUAL(find(), 3); - - startInterest("ndn:/") - .setMinSuffixComponents(4); - BOOST_CHECK_EQUAL(find(), 4); - - startInterest("ndn:/") - .setMinSuffixComponents(5); - BOOST_CHECK_EQUAL(find(), 5); - - startInterest("ndn:/") - .setMinSuffixComponents(6); - BOOST_CHECK_EQUAL(find(), 6); - - startInterest("ndn:/") - .setMinSuffixComponents(7); - BOOST_CHECK_EQUAL(find(), 0); -} - -BOOST_AUTO_TEST_CASE(MaxSuffixComponents) -{ - insert(1, "ndn:/"); - insert(2, "ndn:/A"); - insert(3, "ndn:/B/2"); - insert(4, "ndn:/C/2/3"); - insert(5, "ndn:/D/2/3/4"); - insert(6, "ndn:/E/2/3/4/5"); - - startInterest("ndn:/") - .setChildSelector(1) - .setMaxSuffixComponents(0); - BOOST_CHECK_EQUAL(find(), 0); - - startInterest("ndn:/") - .setChildSelector(1) - .setMaxSuffixComponents(1); - BOOST_CHECK_EQUAL(find(), 1); - - startInterest("ndn:/") - .setChildSelector(1) - .setMaxSuffixComponents(2); - BOOST_CHECK_EQUAL(find(), 2); - - startInterest("ndn:/") - .setChildSelector(1) - .setMaxSuffixComponents(3); - BOOST_CHECK_EQUAL(find(), 3); - - startInterest("ndn:/") - .setChildSelector(1) - .setMaxSuffixComponents(4); - BOOST_CHECK_EQUAL(find(), 4); - - startInterest("ndn:/") - .setChildSelector(1) - .setMaxSuffixComponents(5); - BOOST_CHECK_EQUAL(find(), 5); - - startInterest("ndn:/") - .setChildSelector(1) - .setMaxSuffixComponents(6); - BOOST_CHECK_EQUAL(find(), 6); - - startInterest("ndn:/") - .setChildSelector(1) - .setMaxSuffixComponents(7); - BOOST_CHECK_EQUAL(find(), 6); -} - -BOOST_AUTO_TEST_CASE(DigestOrder) -{ - insert(1, "ndn:/A"); - insert(2, "ndn:/A"); - // We don't know which comes first, but there must be some order - - startInterest("ndn:/A") - .setChildSelector(0); - uint32_t leftmost = find(); - - startInterest("ndn:/A") - .setChildSelector(1); - uint32_t rightmost = find(); - - BOOST_CHECK_NE(leftmost, rightmost); -} - -BOOST_AUTO_TEST_CASE(DigestExclude) -{ - insert(1, "ndn:/A"); - Name n2 = insert(2, "ndn:/A"); - insert(3, "ndn:/A/B"); - - uint8_t digest00[ndn::crypto::SHA256_DIGEST_SIZE]; - std::fill_n(digest00, sizeof(digest00), 0x00); - uint8_t digestFF[ndn::crypto::SHA256_DIGEST_SIZE]; - std::fill_n(digestFF, sizeof(digestFF), 0xFF); - - Exclude excludeDigest; - excludeDigest.excludeRange( - name::Component::fromImplicitSha256Digest(digest00, sizeof(digest00)), - name::Component::fromImplicitSha256Digest(digestFF, sizeof(digestFF))); - - startInterest("ndn:/A") - .setChildSelector(0) - .setExclude(excludeDigest); - BOOST_CHECK_EQUAL(find(), 3); - - startInterest("ndn:/A") - .setChildSelector(1) - .setExclude(excludeDigest); - BOOST_CHECK_EQUAL(find(), 3); - - Exclude excludeGeneric; - excludeGeneric.excludeAfter(name::Component(static_cast(nullptr), 0)); - - startInterest("ndn:/A") - .setChildSelector(0) - .setExclude(excludeGeneric); - int found1 = find(); - BOOST_CHECK(found1 == 1 || found1 == 2); - - startInterest("ndn:/A") - .setChildSelector(1) - .setExclude(excludeGeneric); - int found2 = find(); - BOOST_CHECK(found2 == 1 || found2 == 2); - - Exclude exclude2 = excludeGeneric; - exclude2.excludeOne(n2.get(-1)); - - startInterest("ndn:/A") - .setChildSelector(0) - .setExclude(exclude2); - BOOST_CHECK_EQUAL(find(), 1); - - startInterest("ndn:/A") - .setChildSelector(1) - .setExclude(exclude2); - BOOST_CHECK_EQUAL(find(), 1); -} - -BOOST_AUTO_TEST_CASE(MustBeFresh) -{ - Name data1Name = insert(1, "ndn:/A/1", time::milliseconds(500)); - insert(2, "ndn:/A/2", time::milliseconds(2500)); - insert(3, "ndn:/A/3", time::milliseconds(3500)); - insert(4, "ndn:/A/4", time::milliseconds(1500)); - - // @0s, all Data are fresh - startInterest("ndn:/A/1") - .setMustBeFresh(true); - BOOST_CHECK_EQUAL(find(), 1); - - startInterest("ndn:/A/1") - .setMustBeFresh(false); - BOOST_CHECK_EQUAL(find(), 1); - - startInterest("ndn:/A") - .setMustBeFresh(true) - .setChildSelector(0); - BOOST_CHECK_EQUAL(find(), 1); - - startInterest("ndn:/A") - .setMustBeFresh(true) - .setChildSelector(1); - BOOST_CHECK_EQUAL(find(), 4); - - advanceClocks(time::milliseconds(1000)); - // @1s, /A/1 is stale - startInterest("ndn:/A/1") - .setMustBeFresh(true); - BOOST_CHECK_EQUAL(find(), 0); - startInterest("ndn:/A/1") - .setMustBeFresh(false); - BOOST_CHECK_EQUAL(find(), 1); - - // MustBeFresh is ignored when full Name is specified - startInterest(data1Name) - .setMustBeFresh(true); - BOOST_CHECK_EQUAL(find(), 1); - - startInterest("ndn:/A") - .setMustBeFresh(true) - .setChildSelector(0); - BOOST_CHECK_EQUAL(find(), 2); - startInterest("ndn:/A") - .setMustBeFresh(false) - .setChildSelector(0); - BOOST_CHECK_EQUAL(find(), 1); - - advanceClocks(time::milliseconds(1000)); - // @2s, /A/1 and /A/4 are stale - startInterest("ndn:/A") - .setMustBeFresh(true) - .setChildSelector(1); - BOOST_CHECK_EQUAL(find(), 3); - startInterest("ndn:/A") - .setMustBeFresh(false) - .setChildSelector(1); - BOOST_CHECK_EQUAL(find(), 4); - - advanceClocks(time::milliseconds(2000)); - // @4s, all Data are stale - startInterest("ndn:/A") - .setMustBeFresh(true) - .setChildSelector(0); - BOOST_CHECK_EQUAL(find(), 0); - startInterest("ndn:/A") - .setMustBeFresh(true) - .setChildSelector(1); - BOOST_CHECK_EQUAL(find(), 0); -} - -BOOST_AUTO_TEST_SUITE_END() // Find -BOOST_AUTO_TEST_SUITE_END() // Common -BOOST_AUTO_TEST_SUITE_END() // TestInMemoryStorage -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace tests -} // namespace util -} // namespace ndn diff --git a/tests/unit-tests/util/in-memory-storage-fifo.t.cpp b/tests/unit-tests/util/in-memory-storage-fifo.t.cpp deleted file mode 100644 index 4404b519a..000000000 --- a/tests/unit-tests/util/in-memory-storage-fifo.t.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/in-memory-storage-fifo.hpp" -#include "security/key-chain.hpp" - -#include "boost-test.hpp" -#include "../make-interest-data.hpp" - -namespace ndn { -namespace util { -namespace tests { - -using namespace ndn::tests; - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_AUTO_TEST_SUITE(TestInMemoryStorage) -BOOST_AUTO_TEST_SUITE(Fifo) - -BOOST_AUTO_TEST_CASE(ArrivalQueue) -{ - InMemoryStorageFifo ims; - - ims.insert(*makeData("/1")); - ims.insert(*makeData("/2")); - ims.insert(*makeData("/3")); - - ims.evictItem(); - BOOST_CHECK_EQUAL(ims.size(), 2); - - shared_ptr interest = makeInterest("/1"); - shared_ptr found = ims.find(*interest); - BOOST_CHECK(found == nullptr); -} - -BOOST_AUTO_TEST_CASE(ArrivalQueue2) -{ - InMemoryStorageFifo ims; - - ims.insert(*makeData("/1")); - ims.insert(*makeData("/2")); - ims.insert(*makeData("/3")); - - ims.evictItem(); - BOOST_CHECK_EQUAL(ims.size(), 2); - - shared_ptr interest1 = makeInterest("/1"); - shared_ptr found1 = ims.find(*interest1); - BOOST_CHECK(found1 == nullptr); - - ims.insert(*makeData("/4")); - - ims.evictItem(); - BOOST_CHECK_EQUAL(ims.size(), 2); - - shared_ptr interest2 = makeInterest("/2"); - shared_ptr found2 = ims.find(*interest2); - BOOST_CHECK(found2 == nullptr); -} - -BOOST_AUTO_TEST_SUITE_END() // Fifo -BOOST_AUTO_TEST_SUITE_END() // TestInMemoryStorage -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace tests -} // namespace util -} // namespace ndn diff --git a/tests/unit-tests/util/in-memory-storage-persistent.t.cpp b/tests/unit-tests/util/in-memory-storage-persistent.t.cpp deleted file mode 100644 index af33ab3e0..000000000 --- a/tests/unit-tests/util/in-memory-storage-persistent.t.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/in-memory-storage-persistent.hpp" -#include "security/key-chain.hpp" - -#include "boost-test.hpp" -#include "../make-interest-data.hpp" - -namespace ndn { -namespace util { -namespace tests { - -using namespace ndn::tests; - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_AUTO_TEST_SUITE(TestInMemoryStorage) -BOOST_AUTO_TEST_SUITE(Persistent) - -BOOST_AUTO_TEST_CASE(GetLimit) -{ - InMemoryStoragePersistent ims; - - BOOST_CHECK_EQUAL(ims.getLimit(), -1); -} - -BOOST_AUTO_TEST_CASE(InsertAndDouble) -{ - InMemoryStoragePersistent ims; - - for(int i = 0; i < 11; i++) { - std::ostringstream convert; - convert << i; - Name name("/" + convert.str()); - shared_ptr data = makeData(name); - data->setFreshnessPeriod(time::milliseconds(5000)); - signData(data); - ims.insert(*data); - } - - BOOST_CHECK_EQUAL(ims.size(), 11); - - BOOST_CHECK_EQUAL(ims.getCapacity(), 20); -} - -BOOST_AUTO_TEST_SUITE_END() // Persistent -BOOST_AUTO_TEST_SUITE_END() // TestInMemoryStorage -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace tests -} // namespace util -} // namespace ndn diff --git a/tests/unit-tests/util/io.t.cpp b/tests/unit-tests/util/io.t.cpp deleted file mode 100644 index 8ffab078d..000000000 --- a/tests/unit-tests/util/io.t.cpp +++ /dev/null @@ -1,289 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/io.hpp" -#include "security/key-chain.hpp" - -#include "boost-test.hpp" -#include "identity-management-fixture.hpp" -#include -#include - -namespace ndn { -namespace tests { - -class IoFixture -{ -protected: - IoFixture() - : filepath(boost::filesystem::path(UNIT_TEST_CONFIG_PATH) /= "TestIo") - , filename(filepath.string()) - { - boost::filesystem::create_directories(filepath.parent_path()); - } - - ~IoFixture() - { - boost::system::error_code ec; - boost::filesystem::remove(filepath, ec); // ignore error - } - - /** \brief create a directory at filename, so that it's neither readable nor writable as a file - */ - void - mkdir() const - { - boost::filesystem::create_directory(filepath); - } - - template - Container - readFile() const - { - Container container; - std::ifstream fs(filename, std::ios_base::binary); - char ch; - while (fs.get(ch)) { - container.push_back(static_cast(ch)); - } - return container; - } - - template - void - writeFile(const Container& content) const - { - std::ofstream fs(filename, std::ios_base::binary); - for (CharT ch : content) { - fs.put(static_cast(ch)); - } - fs.close(); - BOOST_REQUIRE_MESSAGE(fs, "error writing file"); - } - -protected: - const boost::filesystem::path filepath; - const std::string filename; -}; - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_FIXTURE_TEST_SUITE(TestIo, IoFixture) - -class EncodableType -{ -public: - Block - wireEncode() const - { - if (shouldThrow) { - BOOST_THROW_EXCEPTION(tlv::Error("encode error")); - } - - // block will be 0xAA, 0x01, 0xDD - return makeNonNegativeIntegerBlock(0xAA, 0xDD); - } - -public: - bool shouldThrow = false; -}; - -template -class DecodableTypeTpl -{ -public: - DecodableTypeTpl() = default; - - explicit - DecodableTypeTpl(const Block& block) - { - this->wireDecode(block); - } - - void - wireDecode(const Block& block) - { - if (m_shouldThrow) { - BOOST_THROW_EXCEPTION(tlv::Error("decode error")); - } - - // block must be 0xBB, 0x01, 0xEE - BOOST_CHECK_EQUAL(block.type(), 0xBB); - BOOST_REQUIRE_EQUAL(block.value_size(), 1); - BOOST_CHECK_EQUAL(block.value()[0], 0xEE); - } - -private: - bool m_shouldThrow = SHOULD_THROW; -}; - -typedef DecodableTypeTpl DecodableType; -typedef DecodableTypeTpl DecodableTypeThrow; - -BOOST_AUTO_TEST_CASE(LoadNoEncoding) -{ - this->writeFile>({0xBB, 0x01, 0xEE}); - shared_ptr decoded = io::load(filename, io::NO_ENCODING); - BOOST_CHECK(decoded != nullptr); -} - -BOOST_AUTO_TEST_CASE(LoadBase64) -{ - this->writeFile("uwHu\n"); // printf '\xBB\x01\xEE' | base64 - shared_ptr decoded = io::load(filename, io::BASE64); - BOOST_CHECK(decoded != nullptr); -} - -BOOST_AUTO_TEST_CASE(LoadBase64Newline64) -{ - this->writeFile( - "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n" - "AAAAAAAAAAAA\n"); - // printf '\x08\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 - // \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 - // \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 - // \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | base64 - shared_ptr decoded = io::load(filename, io::BASE64); - BOOST_CHECK(decoded != nullptr); -} - -BOOST_AUTO_TEST_CASE(LoadBase64Newline32) -{ - this->writeFile( - "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n" - "AAAAAAAAAAAA\n"); - shared_ptr decoded = io::load(filename, io::BASE64); - BOOST_CHECK(decoded != nullptr); -} - -BOOST_AUTO_TEST_CASE(LoadBase64NewlineEnd) -{ - this->writeFile( - "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"); - shared_ptr decoded = io::load(filename, io::BASE64); - BOOST_CHECK(decoded != nullptr); -} - -BOOST_AUTO_TEST_CASE(LoadBase64NoNewline) -{ - this->writeFile( - "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); - shared_ptr decoded = io::load(filename, io::BASE64); - BOOST_CHECK(decoded != nullptr); -} - -BOOST_AUTO_TEST_CASE(LoadHex) -{ - this->writeFile("BB01EE"); - shared_ptr decoded = io::load(filename, io::HEX); - BOOST_CHECK(decoded != nullptr); -} - -BOOST_AUTO_TEST_CASE(LoadException) -{ - this->writeFile>({0xBB, 0x01, 0xEE}); - shared_ptr decoded; - BOOST_CHECK_NO_THROW(decoded = io::load(filename, io::NO_ENCODING)); - BOOST_CHECK(decoded == nullptr); -} - -BOOST_AUTO_TEST_CASE(LoadNotHex) -{ - this->writeFile("not-hex"); - shared_ptr decoded; - BOOST_CHECK_NO_THROW(decoded = io::load(filename, io::HEX)); - BOOST_CHECK(decoded == nullptr); -} - -BOOST_AUTO_TEST_CASE(LoadFileNotReadable) -{ - shared_ptr decoded; - BOOST_CHECK_NO_THROW(decoded = io::load(filename, io::NO_ENCODING)); - BOOST_CHECK(decoded == nullptr); -} - -BOOST_AUTO_TEST_CASE(SaveNoEncoding) -{ - EncodableType encoded; - BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::NO_ENCODING)); - auto content = this->readFile>(); - uint8_t expected[] = {0xAA, 0x01, 0xDD}; - BOOST_CHECK_EQUAL_COLLECTIONS(content.begin(), content.end(), - expected, expected + sizeof(expected)); -} - -BOOST_AUTO_TEST_CASE(SaveBase64) -{ - EncodableType encoded; - BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::BASE64)); - auto content = this->readFile(); - BOOST_CHECK_EQUAL(content, "qgHd\n"); // printf '\xAA\x01\xDD' | base64 -} - -BOOST_AUTO_TEST_CASE(SaveHex) -{ - EncodableType encoded; - BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::HEX)); - auto content = this->readFile(); - BOOST_CHECK_EQUAL(content, "AA01DD"); -} - -BOOST_AUTO_TEST_CASE(SaveException) -{ - EncodableType encoded; - encoded.shouldThrow = true; - BOOST_CHECK_THROW(io::save(encoded, filename, io::NO_ENCODING), io::Error); -} - -BOOST_AUTO_TEST_CASE(SaveFileNotWritable) -{ - this->mkdir(); - EncodableType encoded; - encoded.shouldThrow = true; - BOOST_CHECK_THROW(io::save(encoded, filename, io::NO_ENCODING), io::Error); -} - -class IdCertFixture : public IoFixture - , public IdentityManagementFixture -{ -}; - -BOOST_FIXTURE_TEST_CASE(IdCert, IdCertFixture) -{ - Name identity("/TestIo/IdCert"); - identity.appendVersion(); - BOOST_REQUIRE(addIdentity(identity, RsaKeyParams())); - Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity); - shared_ptr idCert; - BOOST_REQUIRE_NO_THROW(idCert = m_keyChain.getCertificate(certName)); - - io::save(*idCert, filename); - shared_ptr readCert = io::load(filename); - - BOOST_REQUIRE(readCert != nullptr); - BOOST_CHECK_EQUAL(idCert->getName(), readCert->getName()); -} - -BOOST_AUTO_TEST_SUITE_END() // TestIo -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/util/logging.t.cpp b/tests/unit-tests/util/logging.t.cpp deleted file mode 100644 index f47b5a990..000000000 --- a/tests/unit-tests/util/logging.t.cpp +++ /dev/null @@ -1,426 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/logging.hpp" -#include "util/logger.hpp" - -#include "boost-test.hpp" -#include -#include "../unit-test-time-fixture.hpp" - -namespace ndn { -namespace util { -namespace tests { - -using namespace ndn::tests; -using boost::test_tools::output_test_stream; - -void -logFromModule1(); - -void -logFromModule2(); - -void -logFromNewLogger(const std::string& moduleName) -{ - // clang complains -Wreturn-stack-address on OSX-10.9 if Logger is allocated on stack - auto loggerPtr = make_unique(moduleName); - Logger& logger = *loggerPtr; - - auto getNdnCxxLogger = [&logger] () -> Logger& { return logger; }; - NDN_LOG_TRACE("trace" << moduleName); - NDN_LOG_DEBUG("debug" << moduleName); - NDN_LOG_INFO("info" << moduleName); - NDN_LOG_WARN("warn" << moduleName); - NDN_LOG_ERROR("error" << moduleName); - NDN_LOG_FATAL("fatal" << moduleName); - - BOOST_CHECK(Logging::get().removeLogger(logger)); -} - -const time::system_clock::Duration LOG_SYSTIME = time::microseconds(1468108800311239LL); -const std::string LOG_SYSTIME_STR = "1468108800.311239"; - -class LoggingFixture : public UnitTestTimeFixture -{ -protected: - explicit - LoggingFixture() - : m_oldLevels(Logging::get().getLevels()) - , m_oldDestination(Logging::get().getDestination()) - { - this->systemClock->setNow(LOG_SYSTIME); - Logging::get().resetLevels(); - Logging::setDestination(os); - } - - ~LoggingFixture() - { - Logging::setLevel(m_oldLevels); - Logging::setDestination(m_oldDestination); - } - -protected: - output_test_stream os; - -private: - std::string m_oldLevels; - shared_ptr m_oldDestination; -}; - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_FIXTURE_TEST_SUITE(TestLogging, LoggingFixture) - -BOOST_AUTO_TEST_SUITE(Severity) - -BOOST_AUTO_TEST_CASE(None) -{ - Logging::setLevel("Module1", LogLevel::NONE); - logFromModule1(); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" - )); -} - -BOOST_AUTO_TEST_CASE(Error) -{ - Logging::setLevel("Module1", LogLevel::ERROR); - logFromModule1(); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" - )); -} - -BOOST_AUTO_TEST_CASE(Warn) -{ - Logging::setLevel("Module1", LogLevel::WARN); - logFromModule1(); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" + - LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" - )); -} - -BOOST_AUTO_TEST_CASE(Info) -{ - Logging::setLevel("Module1", LogLevel::INFO); - logFromModule1(); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " INFO: [Module1] info1\n" + - LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" + - LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" - )); -} - -BOOST_AUTO_TEST_CASE(Debug) -{ - Logging::setLevel("Module1", LogLevel::DEBUG); - logFromModule1(); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " DEBUG: [Module1] debug1\n" + - LOG_SYSTIME_STR + " INFO: [Module1] info1\n" + - LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" + - LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" - )); -} - -BOOST_AUTO_TEST_CASE(Trace) -{ - Logging::setLevel("Module1", LogLevel::TRACE); - logFromModule1(); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " TRACE: [Module1] trace1\n" + - LOG_SYSTIME_STR + " DEBUG: [Module1] debug1\n" + - LOG_SYSTIME_STR + " INFO: [Module1] info1\n" + - LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" + - LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" - )); -} - -BOOST_AUTO_TEST_CASE(All) -{ - Logging::setLevel("Module1", LogLevel::ALL); - logFromModule1(); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " TRACE: [Module1] trace1\n" + - LOG_SYSTIME_STR + " DEBUG: [Module1] debug1\n" + - LOG_SYSTIME_STR + " INFO: [Module1] info1\n" + - LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" + - LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" - )); -} - -BOOST_AUTO_TEST_SUITE_END() // Severity - -BOOST_AUTO_TEST_CASE(SameNameLoggers) -{ - Logging::setLevel("Module1", LogLevel::WARN); - logFromModule1(); - logFromNewLogger("Module1"); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" + - LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + - LOG_SYSTIME_STR + " WARNING: [Module1] warnModule1\n" + - LOG_SYSTIME_STR + " ERROR: [Module1] errorModule1\n" + - LOG_SYSTIME_STR + " FATAL: [Module1] fatalModule1\n" - )); -} - -BOOST_AUTO_TEST_CASE(LateRegistration) -{ - BOOST_CHECK_NO_THROW(Logging::setLevel("Module3", LogLevel::DEBUG)); - logFromNewLogger("Module3"); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " DEBUG: [Module3] debugModule3\n" + - LOG_SYSTIME_STR + " INFO: [Module3] infoModule3\n" + - LOG_SYSTIME_STR + " WARNING: [Module3] warnModule3\n" + - LOG_SYSTIME_STR + " ERROR: [Module3] errorModule3\n" + - LOG_SYSTIME_STR + " FATAL: [Module3] fatalModule3\n" - )); -} - -BOOST_AUTO_TEST_SUITE(DefaultSeverity) - -BOOST_AUTO_TEST_CASE(Unset) -{ - logFromModule1(); - logFromModule2(); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + - LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" - )); -} - -BOOST_AUTO_TEST_CASE(NoOverride) -{ - Logging::setLevel("*", LogLevel::WARN); - logFromModule1(); - logFromModule2(); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" + - LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + - LOG_SYSTIME_STR + " WARNING: [Module2] warn2\n" + - LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" + - LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" - )); -} - -BOOST_AUTO_TEST_CASE(Override) -{ - Logging::setLevel("*", LogLevel::WARN); - Logging::setLevel("Module2", LogLevel::DEBUG); - logFromModule1(); - logFromModule2(); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" + - LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + - LOG_SYSTIME_STR + " DEBUG: [Module2] debug2\n" + - LOG_SYSTIME_STR + " INFO: [Module2] info2\n" + - LOG_SYSTIME_STR + " WARNING: [Module2] warn2\n" + - LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" + - LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" - )); -} - -BOOST_AUTO_TEST_SUITE_END() // DefaultSeverity - -BOOST_AUTO_TEST_SUITE(SeverityConfig) - -BOOST_AUTO_TEST_CASE(SetEmpty) -{ - Logging::setLevel(""); - BOOST_CHECK_EQUAL(Logging::get().getLevels(), ""); - logFromModule1(); - logFromModule2(); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + - LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" - )); -} - -BOOST_AUTO_TEST_CASE(SetDefault) -{ - Logging::setLevel("*=WARN"); - BOOST_CHECK_EQUAL(Logging::get().getLevels(), "*=WARN"); - logFromModule1(); - logFromModule2(); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" + - LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + - LOG_SYSTIME_STR + " WARNING: [Module2] warn2\n" + - LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" + - LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" - )); -} - -BOOST_AUTO_TEST_CASE(SetModule) -{ - Logging::setLevel("Module1=ERROR"); - BOOST_CHECK_EQUAL(Logging::get().getLevels(), "Module1=ERROR"); - logFromModule1(); - logFromModule2(); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + - LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" - )); -} - -BOOST_AUTO_TEST_CASE(SetOverride) -{ - Logging::setLevel("*=WARN:Module2=DEBUG"); - BOOST_CHECK_EQUAL(Logging::get().getLevels(), "*=WARN:Module2=DEBUG"); - logFromModule1(); - logFromModule2(); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" + - LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + - LOG_SYSTIME_STR + " DEBUG: [Module2] debug2\n" + - LOG_SYSTIME_STR + " INFO: [Module2] info2\n" + - LOG_SYSTIME_STR + " WARNING: [Module2] warn2\n" + - LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" + - LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" - )); -} - -BOOST_AUTO_TEST_CASE(SetTwice) -{ - Logging::setLevel("*=WARN"); - Logging::setLevel("Module2=DEBUG"); - BOOST_CHECK_EQUAL(Logging::get().getLevels(), "*=WARN:Module2=DEBUG"); - logFromModule1(); - logFromModule2(); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" + - LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + - LOG_SYSTIME_STR + " DEBUG: [Module2] debug2\n" + - LOG_SYSTIME_STR + " INFO: [Module2] info2\n" + - LOG_SYSTIME_STR + " WARNING: [Module2] warn2\n" + - LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" + - LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" - )); -} - -BOOST_AUTO_TEST_CASE(Reset) -{ - Logging::setLevel("Module2=DEBUG"); - Logging::setLevel("*=ERROR"); - BOOST_CHECK_EQUAL(Logging::get().getLevels(), "*=ERROR"); - logFromModule1(); - logFromModule2(); - - Logging::flush(); - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + - LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" + - LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" - )); -} - -BOOST_AUTO_TEST_CASE(Malformed) -{ - BOOST_CHECK_THROW(Logging::setLevel("Module1=INVALID-LEVEL"), std::invalid_argument); - BOOST_CHECK_THROW(Logging::setLevel("Module1-MISSING-EQUAL-SIGN"), std::invalid_argument); -} - -BOOST_AUTO_TEST_SUITE_END() // SeverityConfig - -BOOST_AUTO_TEST_CASE(ChangeDestination) -{ - logFromModule1(); - - auto os2 = make_shared(); - Logging::setDestination(os2); - weak_ptr os2weak(os2); - os2.reset(); - - logFromModule2(); - - Logging::flush(); - os2 = os2weak.lock(); - BOOST_REQUIRE(os2 != nullptr); - - BOOST_CHECK(os.is_equal( - LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" - )); - BOOST_CHECK(os2->is_equal( - LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" - )); - - os2.reset(); - Logging::setDestination(os); - BOOST_CHECK(os2weak.expired()); -} - -BOOST_AUTO_TEST_SUITE_END() // TestLogging -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace tests -} // namespace util -} // namespace ndn diff --git a/tests/unit-tests/util/notification-stream.t.cpp b/tests/unit-tests/util/notification-stream.t.cpp deleted file mode 100644 index 8ec6c6f9b..000000000 --- a/tests/unit-tests/util/notification-stream.t.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016, Regents of the University of California, - * Arizona Board of Regents, - * Colorado State University, - * University Pierre & Marie Curie, Sorbonne University, - * Washington University in St. Louis, - * Beijing Institute of Technology, - * The University of Memphis - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/notification-stream.hpp" -#include "simple-notification.hpp" -#include "util/dummy-client-face.hpp" - -#include "boost-test.hpp" -#include "../identity-management-time-fixture.hpp" - -namespace ndn { -namespace util { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_FIXTURE_TEST_SUITE(TestNotificationStream, ndn::tests::IdentityManagementTimeFixture) - -BOOST_AUTO_TEST_CASE(Post) -{ - DummyClientFace face(io, m_keyChain); - util::NotificationStream notificationStream(face, - "/localhost/nfd/NotificationStreamTest", m_keyChain); - - SimpleNotification event1("msg1"); - notificationStream.postNotification(event1); - - advanceClocks(time::milliseconds(1)); - - BOOST_REQUIRE_EQUAL(face.sentData.size(), 1); - BOOST_CHECK_EQUAL(face.sentData[0].getName(), - "/localhost/nfd/NotificationStreamTest/%FE%00"); - SimpleNotification decoded1; - BOOST_CHECK_NO_THROW(decoded1.wireDecode(face.sentData[0].getContent().blockFromValue())); - BOOST_CHECK_EQUAL(decoded1.getMessage(), "msg1"); - - SimpleNotification event2("msg2"); - notificationStream.postNotification(event2); - - advanceClocks(time::milliseconds(1)); - - BOOST_REQUIRE_EQUAL(face.sentData.size(), 2); - BOOST_CHECK_EQUAL(face.sentData[1].getName(), - "/localhost/nfd/NotificationStreamTest/%FE%01"); - SimpleNotification decoded2; - BOOST_CHECK_NO_THROW(decoded2.wireDecode(face.sentData[1].getContent().blockFromValue())); - BOOST_CHECK_EQUAL(decoded2.getMessage(), "msg2"); -} - -BOOST_AUTO_TEST_SUITE_END() // TestNotificationStream -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace tests -} // namespace util -} // namespace ndn diff --git a/tests/unit-tests/util/random.t.cpp b/tests/unit-tests/util/random.t.cpp deleted file mode 100644 index 62949b676..000000000 --- a/tests/unit-tests/util/random.t.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/random.hpp" - -#include "boost-test.hpp" -#include -#include "security/detail/openssl.hpp" - -#include - -namespace ndn { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_AUTO_TEST_SUITE(TestRandom) - -class PseudoRandomWord32 -{ -public: - static uint32_t - generate() - { - return random::generateWord32(); - } -}; - -class PseudoRandomWord64 -{ -public: - static uint64_t - generate() - { - return random::generateWord64(); - } -}; - -class SecureRandomWord32 -{ -public: - static uint32_t - generate() - { - return random::generateSecureWord32(); - } -}; - -class SecureRandomWord64 -{ -public: - static uint64_t - generate() - { - return random::generateSecureWord64(); - } -}; - -typedef boost::mpl::vector RandomGenerators; - - -static double -getDeviation(const std::vector& counts, size_t size) -{ - // Kolmogorov-Smirnov Goodness-of-Fit Test - // http://www.itl.nist.gov/div898/handbook/eda/section3/eda35g.htm - - std::vector edf(counts.size(), 0.0); - double probability = 0.0; - for (size_t i = 0; i < counts.size(); i++) { - probability += 1.0 * counts[i] / size; - edf[i] = probability; - } - - double t = 0.0; - for (size_t i = 0; i < counts.size(); i++) { - t = std::max(t, std::abs(edf[i] - (i * 1.0 / counts.size()))); - } - - return t; -} - - -BOOST_AUTO_TEST_CASE_TEMPLATE(GoodnessOfFit, RandomGenerator, RandomGenerators) -{ - const size_t MAX_BINS = 32; - const uint32_t MAX_ITERATIONS = 35; - - std::vector counts(MAX_BINS, 0); - - for (uint32_t i = 0; i < MAX_ITERATIONS; i++) { - counts[RandomGenerator::generate() % MAX_BINS]++; - } - - // Check if it is uniform distribution with confidence 0.95 - // http://dlc.erieri.com/onlinetextbook/index.cfm?fuseaction=textbook.appendix&FileName=Table7 - BOOST_WARN_LE(getDeviation(counts, MAX_ITERATIONS), 0.230); -} - -BOOST_AUTO_TEST_CASE(GenerateRandomBytes) -{ - // Kolmogorov-Smirnov Goodness-of-Fit Test - // http://www.itl.nist.gov/div898/handbook/eda/section3/eda35g.htm - - uint8_t buf[1024] = {0}; - random::generateSecureBytes(buf, sizeof(buf)); - - std::vector counts(256, 0); - - for (size_t i = 0; i < sizeof(buf); i++) { - counts[buf[i]]++; - } - - // Check if it is uniform distribution with confidence 0.95 - // http://dlc.erieri.com/onlinetextbook/index.cfm?fuseaction=textbook.appendix&FileName=Table7 - BOOST_WARN_LE(getDeviation(counts, sizeof(buf)), 0.230); -} - -// This fixture uses OpenSSL routines to set a dummy random generator that always fails -class FailRandMethodFixture -{ -public: - FailRandMethodFixture() - : m_dummyRandMethod{&FailRandMethodFixture::seed, - &FailRandMethodFixture::bytes, - &FailRandMethodFixture::cleanup, - &FailRandMethodFixture::add, - &FailRandMethodFixture::pseudorand, - &FailRandMethodFixture::status} - { - m_origRandMethod = RAND_get_rand_method(); - RAND_set_rand_method(&m_dummyRandMethod); - } - - ~FailRandMethodFixture() - { - RAND_set_rand_method(m_origRandMethod); - } - -private: // RAND_METHOD callbacks -#if OPENSSL_VERSION_NUMBER < 0x1010000fL - static void - seed(const void* buf, int num) - { - } -#else - static int - seed(const void* buf, int num) - { - return 0; - } -#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL - - static int - bytes(unsigned char *buf, int num) - { - return 0; - } - - static void - cleanup() - { - } - -#if OPENSSL_VERSION_NUMBER < 0x1010000fL - static void - add(const void *buf, int num, double entropy) - { - } -#else - static int - add(const void *buf, int num, double entropy) - { - return 0; - } -#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL - - static int - pseudorand(unsigned char *buf, int num) - { - return 0; - } - - static int - status() - { - return 0; - } - -private: - const RAND_METHOD* m_origRandMethod; - RAND_METHOD m_dummyRandMethod; -}; - -BOOST_FIXTURE_TEST_CASE(Error, FailRandMethodFixture) -{ - uint8_t buf[1024] = {0}; - BOOST_CHECK_THROW(random::generateSecureBytes(buf, sizeof(buf)), std::runtime_error); -} - -BOOST_AUTO_TEST_SUITE_END() // TestRandom -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace tests -} // namespace ndn diff --git a/tests/unit-tests/util/scheduler.t.cpp b/tests/unit-tests/util/scheduler.t.cpp deleted file mode 100644 index 8189f0135..000000000 --- a/tests/unit-tests/util/scheduler.t.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/scheduler.hpp" -#include "util/scheduler-scoped-event-id.hpp" - -#include "boost-test.hpp" -#include "../unit-test-time-fixture.hpp" -#include - -namespace ndn { -namespace util { -namespace scheduler { -namespace tests { - -using namespace ndn::tests; - -class SchedulerFixture : public UnitTestTimeFixture -{ -public: - SchedulerFixture() - : scheduler(io) - { - } - -public: - Scheduler scheduler; -}; - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_FIXTURE_TEST_SUITE(TestScheduler, SchedulerFixture) - -BOOST_AUTO_TEST_SUITE(General) - -BOOST_AUTO_TEST_CASE(Events) -{ - size_t count1 = 0; - size_t count2 = 0; - - scheduler.scheduleEvent(time::milliseconds(500), [&] { - ++count1; - BOOST_CHECK_EQUAL(count2, 1); - }); - - EventId i = scheduler.scheduleEvent(time::seconds(1), [&] { - BOOST_ERROR("This event should not have been fired"); - }); - scheduler.cancelEvent(i); - - scheduler.scheduleEvent(time::milliseconds(250), [&] { - BOOST_CHECK_EQUAL(count1, 0); - ++count2; - }); - - i = scheduler.scheduleEvent(time::milliseconds(50), [&] { - BOOST_ERROR("This event should not have been fired"); - }); - scheduler.cancelEvent(i); - - advanceClocks(time::milliseconds(25), time::milliseconds(1000)); - BOOST_CHECK_EQUAL(count1, 1); - BOOST_CHECK_EQUAL(count2, 1); -} - -BOOST_AUTO_TEST_CASE(CallbackException) -{ - class MyException : public std::exception - { - }; - scheduler.scheduleEvent(time::milliseconds(10), [] { BOOST_THROW_EXCEPTION(MyException()); }); - - bool isCallbackInvoked = false; - scheduler.scheduleEvent(time::milliseconds(20), [&isCallbackInvoked] { isCallbackInvoked = true; }); - - BOOST_CHECK_THROW(this->advanceClocks(time::milliseconds(6), 2), MyException); - this->advanceClocks(time::milliseconds(6), 2); - BOOST_CHECK(isCallbackInvoked); -} - -BOOST_AUTO_TEST_CASE(CancelEmptyEvent) -{ - EventId i; - scheduler.cancelEvent(i); - - // avoid "test case [...] did not check any assertions" message from Boost.Test - BOOST_CHECK(true); -} - -BOOST_AUTO_TEST_CASE(SelfCancel) -{ - EventId selfEventId; - selfEventId = scheduler.scheduleEvent(time::milliseconds(100), [&] { - scheduler.cancelEvent(selfEventId); - }); - - BOOST_REQUIRE_NO_THROW(advanceClocks(time::milliseconds(100), 10)); -} - -class SelfRescheduleFixture : public SchedulerFixture -{ -public: - SelfRescheduleFixture() - : count(0) - { - } - - void - reschedule() - { - EventId eventId = scheduler.scheduleEvent(time::milliseconds(100), - bind(&SelfRescheduleFixture::reschedule, this)); - scheduler.cancelEvent(selfEventId); - selfEventId = eventId; - - if (count < 5) - count++; - else - scheduler.cancelEvent(selfEventId); - } - - void - reschedule2() - { - scheduler.cancelEvent(selfEventId); - - if (count < 5) { - selfEventId = scheduler.scheduleEvent(time::milliseconds(100), - bind(&SelfRescheduleFixture::reschedule2, this)); - count++; - } - } - - void - reschedule3() - { - scheduler.cancelEvent(selfEventId); - - scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; }); - scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; }); - scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; }); - scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; }); - scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; }); - scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; }); - } - -public: - EventId selfEventId; - size_t count; -}; - -BOOST_FIXTURE_TEST_CASE(Reschedule, SelfRescheduleFixture) -{ - selfEventId = scheduler.scheduleEvent(time::seconds(0), - bind(&SelfRescheduleFixture::reschedule, this)); - - BOOST_REQUIRE_NO_THROW(advanceClocks(time::milliseconds(50), time::milliseconds(1000))); - - BOOST_CHECK_EQUAL(count, 5); -} - -BOOST_FIXTURE_TEST_CASE(Reschedule2, SelfRescheduleFixture) -{ - selfEventId = scheduler.scheduleEvent(time::seconds(0), - bind(&SelfRescheduleFixture::reschedule2, this)); - - BOOST_REQUIRE_NO_THROW(advanceClocks(time::milliseconds(50), time::milliseconds(1000))); - - BOOST_CHECK_EQUAL(count, 5); -} - -BOOST_FIXTURE_TEST_CASE(Reschedule3, SelfRescheduleFixture) -{ - selfEventId = scheduler.scheduleEvent(time::seconds(0), - bind(&SelfRescheduleFixture::reschedule3, this)); - - BOOST_REQUIRE_NO_THROW(advanceClocks(time::milliseconds(50), time::milliseconds(1000))); - - BOOST_CHECK_EQUAL(count, 6); -} - -class CancelAllFixture : public SchedulerFixture -{ -public: - CancelAllFixture() - : count(0) - { - } - - void - event() - { - ++count; - - scheduler.scheduleEvent(time::seconds(1), [&] { event(); }); - } - -public: - uint32_t count; -}; - -BOOST_FIXTURE_TEST_CASE(CancelAll, CancelAllFixture) -{ - scheduler.scheduleEvent(time::milliseconds(500), [&] { scheduler.cancelAllEvents(); }); - - scheduler.scheduleEvent(time::seconds(1), [&] { event(); }); - - scheduler.scheduleEvent(time::seconds(3), [] { - BOOST_ERROR("This event should have been cancelled" ); - }); - - advanceClocks(time::milliseconds(100), 100); - - BOOST_CHECK_EQUAL(count, 0); -} - -BOOST_AUTO_TEST_CASE(CancelAllWithScopedEventId) // Bug 3691 -{ - Scheduler sched(io); - ScopedEventId eid(sched); - eid = sched.scheduleEvent(time::milliseconds(10), []{}); - sched.cancelAllEvents(); - eid.cancel(); // should not crash - - // avoid "test case [...] did not check any assertions" message from Boost.Test - BOOST_CHECK(true); -} - -BOOST_AUTO_TEST_SUITE_END() // General - -BOOST_AUTO_TEST_SUITE(EventId) - -using scheduler::EventId; - -BOOST_AUTO_TEST_CASE(ConstructEmpty) -{ - EventId eid; - eid = nullptr; - - // avoid "test case [...] did not check any assertions" message from Boost.Test - BOOST_CHECK(true); -} - -BOOST_AUTO_TEST_CASE(Compare) -{ - EventId eid, eid2; - BOOST_CHECK_EQUAL(eid == eid2, true); - BOOST_CHECK_EQUAL(eid != eid2, false); - BOOST_CHECK_EQUAL(eid == nullptr, true); - BOOST_CHECK_EQUAL(eid != nullptr, false); - - eid = scheduler.scheduleEvent(time::milliseconds(10), []{}); - BOOST_CHECK_EQUAL(eid == eid2, false); - BOOST_CHECK_EQUAL(eid != eid2, true); - BOOST_CHECK_EQUAL(eid == nullptr, false); - BOOST_CHECK_EQUAL(eid != nullptr, true); - - eid2 = eid; - BOOST_CHECK_EQUAL(eid == eid2, true); - BOOST_CHECK_EQUAL(eid != eid2, false); - - eid2 = scheduler.scheduleEvent(time::milliseconds(10), []{}); - BOOST_CHECK_EQUAL(eid == eid2, false); - BOOST_CHECK_EQUAL(eid != eid2, true); -} - -BOOST_AUTO_TEST_CASE(Valid) -{ - EventId eid; - BOOST_CHECK_EQUAL(static_cast(eid), false); - BOOST_CHECK_EQUAL(!eid, true); - - eid = scheduler.scheduleEvent(time::milliseconds(10), []{}); - BOOST_CHECK_EQUAL(static_cast(eid), true); - BOOST_CHECK_EQUAL(!eid, false); - - EventId eid2 = eid; - scheduler.cancelEvent(eid2); - BOOST_CHECK_EQUAL(static_cast(eid), false); - BOOST_CHECK_EQUAL(!eid, true); - BOOST_CHECK_EQUAL(static_cast(eid2), false); - BOOST_CHECK_EQUAL(!eid2, true); -} - -BOOST_AUTO_TEST_CASE(DuringCallback) -{ - EventId eid; - EventId eid2 = scheduler.scheduleEvent(time::milliseconds(20), []{}); - - bool isCallbackInvoked = false; - eid = scheduler.scheduleEvent(time::milliseconds(10), [this, &eid, &eid2, &isCallbackInvoked] { - isCallbackInvoked = true; - - // eid is "expired" during callback execution - BOOST_CHECK_EQUAL(static_cast(eid), false); - BOOST_CHECK_EQUAL(!eid, true); - BOOST_CHECK_EQUAL(eid == eid2, false); - BOOST_CHECK_EQUAL(eid != eid2, true); - BOOST_CHECK_EQUAL(eid == nullptr, true); - BOOST_CHECK_EQUAL(eid != nullptr, false); - - scheduler.cancelEvent(eid2); - BOOST_CHECK_EQUAL(eid == eid2, true); - BOOST_CHECK_EQUAL(eid != eid2, false); - }); - this->advanceClocks(time::milliseconds(6), 2); - BOOST_CHECK(isCallbackInvoked); -} - -BOOST_AUTO_TEST_CASE(Reset) -{ - bool isCallbackInvoked = false; - EventId eid = scheduler.scheduleEvent(time::milliseconds(10), - [&isCallbackInvoked]{ isCallbackInvoked = true; }); - eid.reset(); - BOOST_CHECK_EQUAL(!eid, true); - BOOST_CHECK_EQUAL(eid == nullptr, true); - - this->advanceClocks(time::milliseconds(6), 2); - BOOST_CHECK(isCallbackInvoked); -} - -BOOST_AUTO_TEST_CASE(ToString) -{ - std::string nullString = boost::lexical_cast(shared_ptr()); - - EventId eid; - BOOST_CHECK_EQUAL(boost::lexical_cast(eid), nullString); - - eid = scheduler.scheduleEvent(time::milliseconds(10), []{}); - BOOST_TEST_MESSAGE("eid=" << eid); - BOOST_CHECK_NE(boost::lexical_cast(eid), nullString); -} - -BOOST_AUTO_TEST_SUITE_END() // EventId - -BOOST_AUTO_TEST_SUITE(ScopedEventId) - -using scheduler::ScopedEventId; - -BOOST_AUTO_TEST_CASE(Destruct) -{ - int hit = 0; - { - ScopedEventId se(scheduler); - se = scheduler.scheduleEvent(time::milliseconds(10), [&] { ++hit; }); - } // se goes out of scope - this->advanceClocks(time::milliseconds(1), 15); - BOOST_CHECK_EQUAL(hit, 0); -} - -BOOST_AUTO_TEST_CASE(Assign) -{ - int hit1 = 0, hit2 = 0; - ScopedEventId se1(scheduler); - se1 = scheduler.scheduleEvent(time::milliseconds(10), [&] { ++hit1; }); - se1 = scheduler.scheduleEvent(time::milliseconds(10), [&] { ++hit2; }); - this->advanceClocks(time::milliseconds(1), 15); - BOOST_CHECK_EQUAL(hit1, 0); - BOOST_CHECK_EQUAL(hit2, 1); -} - -BOOST_AUTO_TEST_CASE(Release) -{ - int hit = 0; - { - ScopedEventId se(scheduler); - se = scheduler.scheduleEvent(time::milliseconds(10), [&] { ++hit; }); - se.release(); - } // se goes out of scope - this->advanceClocks(time::milliseconds(1), 15); - BOOST_CHECK_EQUAL(hit, 1); -} - -BOOST_AUTO_TEST_CASE(Move) -{ - int hit = 0; - unique_ptr se2; - { - ScopedEventId se(scheduler); - se = scheduler.scheduleEvent(time::milliseconds(10), [&] { ++hit; }); - se2.reset(new ScopedEventId(std::move(se))); - } // se goes out of scope - this->advanceClocks(time::milliseconds(1), 15); - BOOST_CHECK_EQUAL(hit, 1); -} - -BOOST_AUTO_TEST_SUITE_END() // ScopedEventId - -BOOST_AUTO_TEST_SUITE_END() // TestScheduler -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace tests -} // namespace scheduler -} // namespace util -} // namespace ndn diff --git a/tests/unit-tests/util/segment-fetcher.t.cpp b/tests/unit-tests/util/segment-fetcher.t.cpp deleted file mode 100644 index 462e759cb..000000000 --- a/tests/unit-tests/util/segment-fetcher.t.cpp +++ /dev/null @@ -1,438 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/segment-fetcher.hpp" -#include "security/validator-null.hpp" -#include "../../dummy-validator.hpp" -#include "data.hpp" -#include "encoding/block.hpp" - -#include "boost-test.hpp" -#include "util/dummy-client-face.hpp" -#include "security/key-chain.hpp" -#include "lp/nack-header.hpp" -#include "../identity-management-time-fixture.hpp" -#include "../make-interest-data.hpp" - -namespace ndn { -namespace util { -namespace tests { - -using namespace ndn::tests; - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_AUTO_TEST_SUITE(TestSegmentFetcher) - -class Fixture : public IdentityManagementTimeFixture -{ -public: - Fixture() - : face(io, m_keyChain) - , nErrors(0) - , nData(0) - , dataSize(0) - { - } - - shared_ptr - makeDataSegment(const Name& baseName, uint64_t segment, bool isFinal) - { - const uint8_t buffer[] = "Hello, world!"; - - auto data = make_shared(Name(baseName).appendSegment(segment)); - data->setContent(buffer, sizeof(buffer)); - - if (isFinal) { - data->setFinalBlockId(data->getName()[-1]); - } - data = signData(data); - - return data; - } - - void - onError(uint32_t errorCode) - { - ++nErrors; - lastError = errorCode; - } - - void - onComplete(const ConstBufferPtr& data) - { - ++nData; - dataSize = data->size(); - dataString = std::string(reinterpret_cast(data->get())); - } - - void - nackLastInterest(lp::NackReason nackReason) - { - const Interest& lastInterest = face.sentInterests.back(); - lp::Nack nack = makeNack(lastInterest, nackReason); - face.receive(nack); - advanceClocks(time::milliseconds(10)); - } - -public: - DummyClientFace face; - - uint32_t nErrors; - uint32_t lastError; - uint32_t nData; - size_t dataSize; - std::string dataString; -}; - -BOOST_FIXTURE_TEST_CASE(Timeout, Fixture) -{ - ValidatorNull nullValidator; - SegmentFetcher::fetch(face, Interest("/hello/world", time::milliseconds(100)), - nullValidator, - bind(&Fixture::onComplete, this, _1), - bind(&Fixture::onError, this, _1)); - - advanceClocks(time::milliseconds(1)); - BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1); - - const Interest& interest = face.sentInterests[0]; - BOOST_CHECK_EQUAL(interest.getName(), "/hello/world"); - BOOST_CHECK_EQUAL(interest.getMustBeFresh(), true); - BOOST_CHECK_EQUAL(interest.getChildSelector(), 1); - - advanceClocks(time::milliseconds(98)); - BOOST_CHECK_EQUAL(nErrors, 0); - BOOST_CHECK_EQUAL(nData, 0); - BOOST_CHECK_EQUAL(face.sentData.size(), 0); - - advanceClocks(time::milliseconds(1), 2); - BOOST_CHECK_EQUAL(nErrors, 1); - BOOST_CHECK_EQUAL(lastError, static_cast(SegmentFetcher::INTEREST_TIMEOUT)); - BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1); - BOOST_CHECK_EQUAL(face.sentData.size(), 0); -} - - -BOOST_FIXTURE_TEST_CASE(Basic, Fixture) -{ - ValidatorNull nullValidator; - SegmentFetcher::fetch(face, Interest("/hello/world", time::seconds(1000)), - nullValidator, - bind(&Fixture::onComplete, this, _1), - bind(&Fixture::onError, this, _1)); - - advanceClocks(time::milliseconds(10)); - - face.receive(*makeDataSegment("/hello/world/version0", 0, true)); - advanceClocks(time::milliseconds(10)); - - BOOST_CHECK_EQUAL(nErrors, 0); - BOOST_CHECK_EQUAL(nData, 1); - - BOOST_CHECK_EQUAL(dataSize, 14); - - const uint8_t buffer[] = "Hello, world!"; - std::string bufferString = std::string(reinterpret_cast(buffer)); - - BOOST_CHECK_EQUAL(dataString, bufferString); - - BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1); - BOOST_CHECK_EQUAL(face.sentData.size(), 0); - - const Interest& interest = face.sentInterests[0]; - BOOST_CHECK_EQUAL(interest.getName(), "/hello/world"); - BOOST_CHECK_EQUAL(interest.getMustBeFresh(), true); - BOOST_CHECK_EQUAL(interest.getChildSelector(), 1); -} - -BOOST_FIXTURE_TEST_CASE(NoSegmentInData, Fixture) -{ - ValidatorNull nullValidator; - SegmentFetcher::fetch(face, Interest("/hello/world", time::seconds(1000)), - nullValidator, - bind(&Fixture::onComplete, this, _1), - bind(&Fixture::onError, this, _1)); - - advanceClocks(time::milliseconds(10)); - - const uint8_t buffer[] = "Hello, world!"; - - shared_ptr data = makeData("/hello/world/version0/no-segment"); - - data->setContent(buffer, sizeof(buffer)); - - face.receive(*data); - advanceClocks(time::milliseconds(10)); - - BOOST_CHECK_EQUAL(nErrors, 1); - BOOST_CHECK_EQUAL(lastError, static_cast(SegmentFetcher::DATA_HAS_NO_SEGMENT)); - BOOST_CHECK_EQUAL(nData, 0); -} - -BOOST_FIXTURE_TEST_CASE(SegmentValidationFailure, Fixture) -{ - DummyRejectValidator rejectValidator; - SegmentFetcher::fetch(face, Interest("/hello/world", time::seconds(1000)), - rejectValidator, - bind(&Fixture::onComplete, this, _1), - bind(&Fixture::onError, this, _1)); - - advanceClocks(time::milliseconds(10)); - face.receive(*makeDataSegment("/hello/world/version0", 0, true)); - advanceClocks(time::milliseconds(10)); - - BOOST_CHECK_EQUAL(nErrors, 1); - BOOST_CHECK_EQUAL(lastError, static_cast(SegmentFetcher::SEGMENT_VALIDATION_FAIL)); - BOOST_CHECK_EQUAL(nData, 0); -} - -BOOST_FIXTURE_TEST_CASE(Triple, Fixture) -{ - ValidatorNull nullValidator; - SegmentFetcher::fetch(face, Interest("/hello/world", time::seconds(1000)), - nullValidator, - bind(&Fixture::onComplete, this, _1), - bind(&Fixture::onError, this, _1)); - - advanceClocks(time::milliseconds(10)); - face.receive(*makeDataSegment("/hello/world/version0", 0, false)); - - advanceClocks(time::milliseconds(10)); - face.receive(*makeDataSegment("/hello/world/version0", 1, false)); - - advanceClocks(time::milliseconds(10)); - face.receive(*makeDataSegment("/hello/world/version0", 2, true)); - - advanceClocks(time::milliseconds(10)); - - BOOST_CHECK_EQUAL(nErrors, 0); - BOOST_CHECK_EQUAL(nData, 1); - - BOOST_CHECK_EQUAL(dataSize, 42); - - BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 3); - BOOST_CHECK_EQUAL(face.sentData.size(), 0); - - { - const Interest& interest = face.sentInterests[0]; - BOOST_CHECK_EQUAL(interest.getName(), "/hello/world"); - BOOST_CHECK_EQUAL(interest.getMustBeFresh(), true); - BOOST_CHECK_EQUAL(interest.getChildSelector(), 1); - } - - { - const Interest& interest = face.sentInterests[1]; - BOOST_CHECK_EQUAL(interest.getName(), "/hello/world/version0/%00%01"); - BOOST_CHECK_EQUAL(interest.getMustBeFresh(), false); - BOOST_CHECK_EQUAL(interest.getChildSelector(), 0); - } - - { - const Interest& interest = face.sentInterests[2]; - BOOST_CHECK_EQUAL(interest.getName(), "/hello/world/version0/%00%02"); - BOOST_CHECK_EQUAL(interest.getMustBeFresh(), false); - BOOST_CHECK_EQUAL(interest.getChildSelector(), 0); - } -} - -BOOST_FIXTURE_TEST_CASE(TripleWithInitialSegmentFetching, Fixture) -{ - ValidatorNull nullValidator; - SegmentFetcher::fetch(face, Interest("/hello/world", time::seconds(1000)), - nullValidator, - bind(&Fixture::onComplete, this, _1), - bind(&Fixture::onError, this, _1)); - - advanceClocks(time::milliseconds(10)); - face.receive(*makeDataSegment("/hello/world/version0", 1, false)); - - advanceClocks(time::milliseconds(10)); - face.receive(*makeDataSegment("/hello/world/version0", 0, false)); - - advanceClocks(time::milliseconds(10)); - face.receive(*makeDataSegment("/hello/world/version0", 1, false)); - - advanceClocks(time::milliseconds(10)); - face.receive(*makeDataSegment("/hello/world/version0", 2, true)); - - advanceClocks(time::milliseconds(10)); - - BOOST_CHECK_EQUAL(nErrors, 0); - BOOST_CHECK_EQUAL(nData, 1); - - BOOST_CHECK_EQUAL(dataSize, 42); - - BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 4); - BOOST_CHECK_EQUAL(face.sentData.size(), 0); - - { - const Interest& interest = face.sentInterests[0]; - BOOST_CHECK_EQUAL(interest.getName(), "/hello/world"); - BOOST_CHECK_EQUAL(interest.getMustBeFresh(), true); - BOOST_CHECK_EQUAL(interest.getChildSelector(), 1); - } - - { - const Interest& interest = face.sentInterests[1]; - BOOST_CHECK_EQUAL(interest.getName(), "/hello/world/version0/%00%00"); - BOOST_CHECK_EQUAL(interest.getMustBeFresh(), false); - BOOST_CHECK_EQUAL(interest.getChildSelector(), 0); - } - - { - const Interest& interest = face.sentInterests[2]; - BOOST_CHECK_EQUAL(interest.getName(), "/hello/world/version0/%00%01"); - BOOST_CHECK_EQUAL(interest.getMustBeFresh(), false); - BOOST_CHECK_EQUAL(interest.getChildSelector(), 0); - } - - { - const Interest& interest = face.sentInterests[3]; - BOOST_CHECK_EQUAL(interest.getName(), "/hello/world/version0/%00%02"); - BOOST_CHECK_EQUAL(interest.getMustBeFresh(), false); - BOOST_CHECK_EQUAL(interest.getChildSelector(), 0); - } -} - -BOOST_FIXTURE_TEST_CASE(MultipleSegmentFetching, Fixture) -{ - ValidatorNull nullValidator; - SegmentFetcher::fetch(face, Interest("/hello/world", time::seconds(1000)), - nullValidator, - bind(&Fixture::onComplete, this, _1), - bind(&Fixture::onError, this, _1)); - - advanceClocks(time::milliseconds(10)); - - for (uint64_t i = 0; i < 400; i++) { - advanceClocks(time::milliseconds(10)); - face.receive(*makeDataSegment("/hello/world/version0", i, false)); - } - advanceClocks(time::milliseconds(10)); - face.receive(*makeDataSegment("/hello/world/version0", 400, true)); - - advanceClocks(time::milliseconds(10)); - - BOOST_CHECK_EQUAL(nErrors, 0); - BOOST_CHECK_EQUAL(nData, 1); -} - -BOOST_FIXTURE_TEST_CASE(DuplicateNack, Fixture) -{ - SegmentFetcher::fetch(face, Interest("/hello/world", time::seconds(1000)), - make_shared(), - bind(&Fixture::onComplete, this, _1), - bind(&Fixture::onError, this, _1)); - advanceClocks(time::milliseconds(10)); - - // receive nack for the original interest - nackLastInterest(lp::NackReason::DUPLICATE); - - // receive nack due to Duplication for the reexpressed interests - for (uint32_t i = 1; i <= SegmentFetcher::MAX_INTEREST_REEXPRESS; ++i) { - nackLastInterest(lp::NackReason::DUPLICATE); - } - - BOOST_CHECK_EQUAL(face.sentInterests.size(), (SegmentFetcher::MAX_INTEREST_REEXPRESS + 1)); - BOOST_CHECK_EQUAL(lastError, static_cast(SegmentFetcher::NACK_ERROR)); -} - -BOOST_FIXTURE_TEST_CASE(CongestionNack, Fixture) -{ - SegmentFetcher::fetch(face, Interest("/hello/world", time::seconds(1000)), - make_shared(), - bind(&Fixture::onComplete, this, _1), - bind(&Fixture::onError, this, _1)); - advanceClocks(time::milliseconds(10)); - - // receive nack for the original interest - nackLastInterest(lp::NackReason::CONGESTION); - - // receive nack due to Congestion for the reexpressed interests - for (uint32_t i = 1; i <= SegmentFetcher::MAX_INTEREST_REEXPRESS; ++i) { - nackLastInterest(lp::NackReason::CONGESTION); - } - - BOOST_CHECK_EQUAL(face.sentInterests.size(), (SegmentFetcher::MAX_INTEREST_REEXPRESS + 1)); - BOOST_CHECK_EQUAL(lastError, static_cast(SegmentFetcher::NACK_ERROR)); -} - -BOOST_FIXTURE_TEST_CASE(SegmentZero, Fixture) -{ - int nNacks = 2; - - ndn::Name interestName("ndn:/A"); - SegmentFetcher::fetch(face, - Interest(interestName), - make_shared(), - bind(&Fixture::onComplete, this, _1), - bind(&Fixture::onError, this, _1)); - - advanceClocks(time::milliseconds(1000)); - - for (uint64_t segmentNo = 0; segmentNo <= 3; segmentNo++) { - if (segmentNo == 1) { - while (nNacks--) { - nackLastInterest(lp::NackReason::CONGESTION); - advanceClocks(time::milliseconds(10)); - } - } - - auto data = makeDataSegment(interestName, segmentNo, segmentNo == 3); - face.receive(*data); - advanceClocks(time::milliseconds(10)); - } - - // Total number of sent interests should be 6: one interest for segment zero and segment one each, - // two re-expressed interests for segment one after getting nack twice, and two interests for - // segment two and three - BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 6); - - BOOST_CHECK_EQUAL(face.sentInterests[0].getName(), ndn::Name("ndn:/A")); - BOOST_CHECK_EQUAL(face.sentInterests[1].getName(), ndn::Name("ndn:/A/%00%01")); - BOOST_CHECK_EQUAL(face.sentInterests[2].getName(), ndn::Name("ndn:/A/%00%01")); - BOOST_CHECK_EQUAL(face.sentInterests[3].getName(), ndn::Name("ndn:/A/%00%01")); - BOOST_CHECK_EQUAL(face.sentInterests[4].getName(), ndn::Name("ndn:/A/%00%02")); - BOOST_CHECK_EQUAL(face.sentInterests[5].getName(), ndn::Name("ndn:/A/%00%03")); -} - -BOOST_FIXTURE_TEST_CASE(ZeroComponentName, Fixture) -{ - SegmentFetcher::fetch(face, Interest("ndn:/"), - make_shared(), - bind(&Fixture::onComplete, this, _1), - bind(&Fixture::onError, this, _1)); - advanceClocks(time::milliseconds(10)); - nackLastInterest(lp::NackReason::DUPLICATE); - face.receive(*makeDataSegment("/hello/world", 0, true)); - - BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2); - BOOST_CHECK_EQUAL(face.sentInterests[0].getName(), ndn::Name("ndn:/")); - BOOST_CHECK_EQUAL(face.sentInterests[1].getName(), ndn::Name("ndn:/")); - BOOST_REQUIRE_EQUAL(nData, 1); -} - -BOOST_AUTO_TEST_SUITE_END() // TestSegmentFetcher -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace tests -} // namespace util -} // namespace ndn diff --git a/tests/unit-tests/util/simple-notification.hpp b/tests/unit-tests/util/simple-notification.hpp deleted file mode 100644 index ce6ec90a7..000000000 --- a/tests/unit-tests/util/simple-notification.hpp +++ /dev/null @@ -1,97 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2014-2016, Regents of the University of California, - * Arizona Board of Regents, - * Colorado State University, - * University Pierre & Marie Curie, Sorbonne University, - * Washington University in St. Louis, - * Beijing Institute of Technology, - * The University of Memphis. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#ifndef NDN_TESTS_UNIT_TESTS_UTIL_SIMPLE_NOTIFICATION_HPP -#define NDN_TESTS_UNIT_TESTS_UTIL_SIMPLE_NOTIFICATION_HPP - -#include "common.hpp" - -#include "encoding/encoding-buffer.hpp" -#include "security/key-chain.hpp" - -namespace ndn { -namespace util { -namespace tests { - -class SimpleNotification -{ -public: - SimpleNotification() = default; - - explicit - SimpleNotification(const Block& block) - { - wireDecode(block); - } - - SimpleNotification(const std::string& message) - : m_message(message) - { - } - - Block - wireEncode() const - { - ndn::EncodingBuffer buffer; - buffer.prependByteArrayBlock(0x8888, - reinterpret_cast(m_message.c_str()), - m_message.size()); - return buffer.block(); - } - - void - wireDecode(const Block& block) - { - m_message.assign(reinterpret_cast(block.value()), - block.value_size()); - - // error for testing - if (!m_message.empty() && m_message[0] == '\x07') - BOOST_THROW_EXCEPTION(tlv::Error("0x07 error")); - } - - const std::string& - getMessage() const - { - return m_message; - } - - void - setMessage(const std::string& message) - { - m_message = message; - } - -private: - std::string m_message; -}; - -} // namespace tests -} // namespace util -} // namespace ndn - -#endif // NDN_TESTS_UNIT_TESTS_UTIL_SIMPLE_NOTIFICATION_HPP diff --git a/tests/unit-tests/util/string-helper.t.cpp b/tests/unit-tests/util/string-helper.t.cpp deleted file mode 100644 index 22e8659a7..000000000 --- a/tests/unit-tests/util/string-helper.t.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/string-helper.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace util { -namespace test { - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_AUTO_TEST_SUITE(TestStringHelper) - -BOOST_AUTO_TEST_CASE(ToHex) -{ - std::string test = "Hello, world!"; - BOOST_CHECK_EQUAL(toHex(reinterpret_cast(test.data()), test.size()), - "48656C6C6F2C20776F726C6421"); - - BOOST_CHECK_EQUAL(toHex(reinterpret_cast(test.data()), test.size(), false), - "48656c6c6f2c20776f726c6421"); - - BOOST_CHECK_EQUAL(toHex(nullptr, 0), ""); - - Buffer buffer(test.data(), test.size()); - BOOST_CHECK_EQUAL(toHex(buffer, false), "48656c6c6f2c20776f726c6421"); -} - -BOOST_AUTO_TEST_CASE(FromHexChar) -{ - // for (int ch = 0; ch <= std::numeric_limits::max(); ++ch) { - // std::cout << "{0x" << std::hex << ch << ", " - // << std::dec << fromHexChar(static_cast(ch)) << "}, "; - // if (ch % 8 == 7) - // std::cout << std::endl; - // } - std::vector> hexMap{ - {0x0, -1}, {0x1, -1}, {0x2, -1}, {0x3, -1}, {0x4, -1}, {0x5, -1}, {0x6, -1}, {0x7, -1}, - {0x8, -1}, {0x9, -1}, {0xa, -1}, {0xb, -1}, {0xc, -1}, {0xd, -1}, {0xe, -1}, {0xf, -1}, - {0x10, -1}, {0x11, -1}, {0x12, -1}, {0x13, -1}, {0x14, -1}, {0x15, -1}, {0x16, -1}, {0x17, -1}, - {0x18, -1}, {0x19, -1}, {0x1a, -1}, {0x1b, -1}, {0x1c, -1}, {0x1d, -1}, {0x1e, -1}, {0x1f, -1}, - {0x20, -1}, {0x21, -1}, {0x22, -1}, {0x23, -1}, {0x24, -1}, {0x25, -1}, {0x26, -1}, {0x27, -1}, - {0x28, -1}, {0x29, -1}, {0x2a, -1}, {0x2b, -1}, {0x2c, -1}, {0x2d, -1}, {0x2e, -1}, {0x2f, -1}, - {0x30, 0}, {0x31, 1}, {0x32, 2}, {0x33, 3}, {0x34, 4}, {0x35, 5}, {0x36, 6}, {0x37, 7}, - {0x38, 8}, {0x39, 9}, {0x3a, -1}, {0x3b, -1}, {0x3c, -1}, {0x3d, -1}, {0x3e, -1}, {0x3f, -1}, - {0x40, -1}, {0x41, 10}, {0x42, 11}, {0x43, 12}, {0x44, 13}, {0x45, 14}, {0x46, 15}, {0x47, -1}, - {0x48, -1}, {0x49, -1}, {0x4a, -1}, {0x4b, -1}, {0x4c, -1}, {0x4d, -1}, {0x4e, -1}, {0x4f, -1}, - {0x50, -1}, {0x51, -1}, {0x52, -1}, {0x53, -1}, {0x54, -1}, {0x55, -1}, {0x56, -1}, {0x57, -1}, - {0x58, -1}, {0x59, -1}, {0x5a, -1}, {0x5b, -1}, {0x5c, -1}, {0x5d, -1}, {0x5e, -1}, {0x5f, -1}, - {0x60, -1}, {0x61, 10}, {0x62, 11}, {0x63, 12}, {0x64, 13}, {0x65, 14}, {0x66, 15}, {0x67, -1}, - {0x68, -1}, {0x69, -1}, {0x6a, -1}, {0x6b, -1}, {0x6c, -1}, {0x6d, -1}, {0x6e, -1}, {0x6f, -1}, - {0x70, -1}, {0x71, -1}, {0x72, -1}, {0x73, -1}, {0x74, -1}, {0x75, -1}, {0x76, -1}, {0x77, -1}, - {0x78, -1}, {0x79, -1}, {0x7a, -1}, {0x7b, -1}, {0x7c, -1}, {0x7d, -1}, {0x7e, -1}, {0x7f, -1}, - {0x80, -1}, {0x81, -1}, {0x82, -1}, {0x83, -1}, {0x84, -1}, {0x85, -1}, {0x86, -1}, {0x87, -1}, - {0x88, -1}, {0x89, -1}, {0x8a, -1}, {0x8b, -1}, {0x8c, -1}, {0x8d, -1}, {0x8e, -1}, {0x8f, -1}, - {0x90, -1}, {0x91, -1}, {0x92, -1}, {0x93, -1}, {0x94, -1}, {0x95, -1}, {0x96, -1}, {0x97, -1}, - {0x98, -1}, {0x99, -1}, {0x9a, -1}, {0x9b, -1}, {0x9c, -1}, {0x9d, -1}, {0x9e, -1}, {0x9f, -1}, - {0xa0, -1}, {0xa1, -1}, {0xa2, -1}, {0xa3, -1}, {0xa4, -1}, {0xa5, -1}, {0xa6, -1}, {0xa7, -1}, - {0xa8, -1}, {0xa9, -1}, {0xaa, -1}, {0xab, -1}, {0xac, -1}, {0xad, -1}, {0xae, -1}, {0xaf, -1}, - {0xb0, -1}, {0xb1, -1}, {0xb2, -1}, {0xb3, -1}, {0xb4, -1}, {0xb5, -1}, {0xb6, -1}, {0xb7, -1}, - {0xb8, -1}, {0xb9, -1}, {0xba, -1}, {0xbb, -1}, {0xbc, -1}, {0xbd, -1}, {0xbe, -1}, {0xbf, -1}, - {0xc0, -1}, {0xc1, -1}, {0xc2, -1}, {0xc3, -1}, {0xc4, -1}, {0xc5, -1}, {0xc6, -1}, {0xc7, -1}, - {0xc8, -1}, {0xc9, -1}, {0xca, -1}, {0xcb, -1}, {0xcc, -1}, {0xcd, -1}, {0xce, -1}, {0xcf, -1}, - {0xd0, -1}, {0xd1, -1}, {0xd2, -1}, {0xd3, -1}, {0xd4, -1}, {0xd5, -1}, {0xd6, -1}, {0xd7, -1}, - {0xd8, -1}, {0xd9, -1}, {0xda, -1}, {0xdb, -1}, {0xdc, -1}, {0xdd, -1}, {0xde, -1}, {0xdf, -1}, - {0xe0, -1}, {0xe1, -1}, {0xe2, -1}, {0xe3, -1}, {0xe4, -1}, {0xe5, -1}, {0xe6, -1}, {0xe7, -1}, - {0xe8, -1}, {0xe9, -1}, {0xea, -1}, {0xeb, -1}, {0xec, -1}, {0xed, -1}, {0xee, -1}, {0xef, -1}, - {0xf0, -1}, {0xf1, -1}, {0xf2, -1}, {0xf3, -1}, {0xf4, -1}, {0xf5, -1}, {0xf6, -1}, {0xf7, -1}, - {0xf8, -1}, {0xf9, -1}, {0xfa, -1}, {0xfb, -1}, {0xfc, -1}, {0xfd, -1}, {0xfe, -1}, {0xff, -1} - }; - for (const auto& item : hexMap) { - BOOST_CHECK_EQUAL(fromHexChar(static_cast(item.first)), item.second); - } -} - -BOOST_AUTO_TEST_CASE(FromHex) -{ - BOOST_CHECK_NO_THROW(fromHex("48656c6c6f2c20776f726c6421")); - BOOST_CHECK(*fromHex("48656c6c6f2c20776f726c6421") == - (std::vector{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21})); - - BOOST_CHECK_NO_THROW(fromHex("012a3Bc4defAB5CdEF")); - BOOST_CHECK(*fromHex("012a3Bc4defAB5CdEF") == - (std::vector{0x01, 0x2a, 0x3b, 0xc4, 0xde, 0xfa, 0xb5, 0xcd, 0xef})); - - BOOST_CHECK_THROW(fromHex("1"), StringHelperError); - BOOST_CHECK_THROW(fromHex("zz"), StringHelperError); - BOOST_CHECK_THROW(fromHex("00az"), StringHelperError); -} - -BOOST_AUTO_TEST_CASE(Trim) -{ - std::string test1 = "Hello, world!"; - std::string test2 = "\n \t Hello, world!\n\r \t "; - std::string test3 = " \t \n \r "; - - // TrimLeft - std::string test = test1; - trimLeft(test); - BOOST_CHECK_EQUAL(test, "Hello, world!"); - - test = test2; - trimLeft(test); - BOOST_CHECK_EQUAL(test, "Hello, world!\n\r \t "); - - test = test3; - trimLeft(test); - BOOST_CHECK_EQUAL(test, ""); - - // TrimRight - test = test1; - trimRight(test); - BOOST_CHECK_EQUAL(test, "Hello, world!"); - - test = test2; - trimRight(test); - BOOST_CHECK_EQUAL(test, "\n \t Hello, world!"); - - test = test3; - trimRight(test); - BOOST_CHECK_EQUAL(test, ""); - - // Trim - test = test1; - trim(test); - BOOST_CHECK_EQUAL(test, "Hello, world!"); - - test = test2; - trim(test); - BOOST_CHECK_EQUAL(test, "Hello, world!"); - - test = test3; - trim(test); - BOOST_CHECK_EQUAL(test, ""); -} - -BOOST_AUTO_TEST_CASE(Unescape) -{ - std::string test1 = "Hello%01, world!%AA "; - std::string test2 = "Invalid escape %ZZ (not a hex value)"; - std::string test3 = "Invalid escape %a (should be two hex symbols)"; - std::string test4 = "Invalid escape %a"; - - BOOST_CHECK_EQUAL(unescape(test1), "Hello\x01, world!\xAA "); - - BOOST_CHECK_EQUAL(unescape(test2), "Invalid escape %ZZ (not a hex value)"); - BOOST_CHECK_EQUAL(unescape(test3), "Invalid escape %a (should be two hex symbols)"); - BOOST_CHECK_EQUAL(unescape(test4), "Invalid escape %a"); - - BOOST_CHECK_EQUAL(unescape("%01%2a%3B%c4%de%fA%B5%Cd%EF"), - "\x01\x2a\x3b\xc4\xde\xfa\xb5\xcd\xef"); -} - -BOOST_AUTO_TEST_SUITE_END() // TestStringHelper -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace test -} // namespace util -} // namespace ndn diff --git a/tests/unit-tests/util/time.t.cpp b/tests/unit-tests/util/time.t.cpp deleted file mode 100644 index 74d893c59..000000000 --- a/tests/unit-tests/util/time.t.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - */ - -#include "util/time.hpp" - -#include "boost-test.hpp" - -namespace ndn { -namespace tests { - -BOOST_AUTO_TEST_SUITE(Util) -BOOST_AUTO_TEST_SUITE(TestTime) - -BOOST_AUTO_TEST_CASE(SystemClock) -{ - time::system_clock::TimePoint value = time::system_clock::now(); - time::system_clock::TimePoint referenceTime = - time::fromUnixTimestamp(time::milliseconds(1390966967032LL)); - - BOOST_CHECK_GT(value, referenceTime); - - BOOST_CHECK_EQUAL(time::toIsoString(referenceTime), "20140129T034247.032000"); - BOOST_CHECK_EQUAL(time::toString(referenceTime), "2014-01-29 03:42:47"); - BOOST_CHECK_EQUAL(time::toString(referenceTime), "2014-01-29 03:42:47"); - - // Unfortunately, not all systems has lv_LV locale installed :( - // BOOST_CHECK_EQUAL(time::toString(referenceTime, "%Y. gada %d. %B", - // std::locale("lv_LV.UTF-8")), - // "2014. gada 29. Janvāris"); - - BOOST_CHECK_EQUAL(time::toString(referenceTime, "%Y -- %d -- %B", - std::locale("C")), - "2014 -- 29 -- January"); - - BOOST_CHECK_EQUAL(time::fromIsoString("20140129T034247.032000"), referenceTime); - BOOST_CHECK_EQUAL(time::fromIsoString("20140129T034247.032000Z"), referenceTime); - BOOST_CHECK_EQUAL(time::fromString("2014-01-29 03:42:47"), - time::fromUnixTimestamp(time::seconds(1390966967))); - - // Unfortunately, not all systems has lv_LV locale installed :( - // BOOST_CHECK_EQUAL(time::fromString("2014. gada 29. Janvāris", "%Y. gada %d. %B", - // std::locale("lv_LV.UTF-8")), - // time::fromUnixTimestamp(time::seconds(1390953600))); - - BOOST_CHECK_EQUAL(time::fromString("2014 -- 29 -- January", "%Y -- %d -- %B", - std::locale("C")), - time::fromUnixTimestamp(time::seconds(1390953600))); -} - -BOOST_AUTO_TEST_CASE(SteadyClock) -{ - time::steady_clock::TimePoint oldValue = time::steady_clock::now(); - usleep(100); - time::steady_clock::TimePoint newValue = time::steady_clock::now(); - - BOOST_CHECK_GT(newValue, oldValue); -} - -BOOST_AUTO_TEST_CASE(Abs) -{ - BOOST_CHECK_EQUAL(time::abs(time::nanoseconds(24422)), time::nanoseconds(24422)); - BOOST_CHECK_EQUAL(time::abs(time::microseconds(0)), time::microseconds(0)); - BOOST_CHECK_EQUAL(time::abs(time::milliseconds(-15583)), time::milliseconds(15583)); -} - -BOOST_AUTO_TEST_SUITE_END() // TestTime -BOOST_AUTO_TEST_SUITE_END() // Util - -} // namespace tests -} // namespace ndn diff --git a/tests/boost-multi-log-formatter.hpp b/tests/unit/boost-multi-log-formatter.hpp similarity index 96% rename from tests/boost-multi-log-formatter.hpp rename to tests/unit/boost-multi-log-formatter.hpp index ae37416bc..59e850ea3 100644 --- a/tests/boost-multi-log-formatter.hpp +++ b/tests/unit/boost-multi-log-formatter.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2015 Regents of the University of California. +/* + * Copyright (c) 2015-2018 Regents of the University of California. * * Based on work by Martin Ba (http://stackoverflow.com/a/26718189) * @@ -8,8 +8,8 @@ * (See http://www.boost.org/LICENSE_1_0.txt) */ -#ifndef NDN_TESTS_BOOST_MULTI_LOG_FORMATTER_HPP -#define NDN_TESTS_BOOST_MULTI_LOG_FORMATTER_HPP +#ifndef NDN_TESTS_UNIT_BOOST_MULTI_LOG_FORMATTER_HPP +#define NDN_TESTS_UNIT_BOOST_MULTI_LOG_FORMATTER_HPP #include @@ -211,4 +211,4 @@ class multi_log_formatter : public unit_test_log_formatter } // namespace unit_test } // namespace boost -#endif // NDN_TESTS_BOOST_MULTI_LOG_FORMATTER_HPP +#endif // NDN_TESTS_UNIT_BOOST_MULTI_LOG_FORMATTER_HPP diff --git a/tests/unit/data.t.cpp b/tests/unit/data.t.cpp new file mode 100644 index 000000000..56ca7759a --- /dev/null +++ b/tests/unit/data.t.cpp @@ -0,0 +1,444 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/signature-sha256-with-rsa.hpp" +#include "ndn-cxx/security/transform/private-key.hpp" +#include "ndn-cxx/security/transform/public-key.hpp" +#include "ndn-cxx/security/transform/signer-filter.hpp" +#include "ndn-cxx/security/transform/step-source.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" +#include "ndn-cxx/security/verification-helpers.hpp" +#include "ndn-cxx/util/sha256.hpp" + +#include "tests/boost-test.hpp" +#include "tests/identity-management-fixture.hpp" +#include + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(TestData) + +const uint8_t CONTENT1[] = {0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x21}; + +const uint8_t DATA1[] = { +0x06, 0xc5, // Data + 0x07, 0x14, // Name + 0x08, 0x05, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, + 0x08, 0x03, + 0x6e, 0x64, 0x6e, + 0x08, 0x06, + 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, + 0x14, 0x04, // MetaInfo + 0x19, 0x02, // FreshnessPeriod + 0x27, 0x10, + 0x15, 0x08, // Content + 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x21, + 0x16, 0x1b, // SignatureInfo + 0x1b, 0x01, // SignatureType + 0x01, + 0x1c, 0x16, // KeyLocator + 0x07, 0x14, // Name + 0x08, 0x04, + 0x74, 0x65, 0x73, 0x74, + 0x08, 0x03, + 0x6b, 0x65, 0x79, + 0x08, 0x07, + 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, + 0x17, 0x80, // SignatureValue + 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, + 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, + 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, + 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, + 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, + 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, + 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, + 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, + 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, + 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1 +}; + +BOOST_AUTO_TEST_CASE(DefaultConstructor) +{ + Data d; + BOOST_CHECK_EQUAL(d.hasWire(), false); + BOOST_CHECK_EQUAL(d.getName(), "/"); + BOOST_CHECK_EQUAL(d.getContentType(), tlv::ContentType_Blob); + BOOST_CHECK_EQUAL(d.getFreshnessPeriod(), DEFAULT_FRESHNESS_PERIOD); + BOOST_CHECK(!d.getFinalBlock()); + BOOST_CHECK_EQUAL(d.getContent().type(), tlv::Content); + BOOST_CHECK_EQUAL(d.getContent().value_size(), 0); + BOOST_CHECK(!d.getSignature()); +} + +class DataSigningKeyFixture +{ +protected: + DataSigningKeyFixture() + { + m_privKey.loadPkcs1(PRIVATE_KEY_DER, sizeof(PRIVATE_KEY_DER)); + auto buf = m_privKey.derivePublicKey(); + m_pubKey.loadPkcs8(buf->data(), buf->size()); + } + +protected: + security::transform::PrivateKey m_privKey; + security::transform::PublicKey m_pubKey; + +private: + static const uint8_t PRIVATE_KEY_DER[632]; +}; + +const uint8_t DataSigningKeyFixture::PRIVATE_KEY_DER[] = { + 0x30, 0x82, 0x02, 0x74, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x5e, 0x30, 0x82, 0x02, 0x5a, 0x02, 0x01, + 0x00, 0x02, 0x81, 0x81, 0x00, 0x9e, 0x06, 0x3e, 0x47, 0x85, 0xb2, 0x34, 0x37, 0xaa, 0x85, 0x47, + 0xac, 0x03, 0x24, 0x83, 0xb5, 0x9c, 0xa8, 0x05, 0x3a, 0x24, 0x1e, 0xeb, 0x89, 0x01, 0xbb, 0xe9, + 0x9b, 0xb2, 0xc3, 0x22, 0xac, 0x68, 0xe3, 0xf0, 0x6c, 0x02, 0xce, 0x68, 0xa6, 0xc4, 0xd0, 0xa7, + 0x06, 0x90, 0x9c, 0xaa, 0x1b, 0x08, 0x1d, 0x8b, 0x43, 0x9a, 0x33, 0x67, 0x44, 0x6d, 0x21, 0xa3, + 0x1b, 0x88, 0x9a, 0x97, 0x5e, 0x59, 0xc4, 0x15, 0x0b, 0xd9, 0x2c, 0xbd, 0x51, 0x07, 0x61, 0x82, + 0xad, 0xc1, 0xb8, 0xd7, 0xbf, 0x9b, 0xcf, 0x7d, 0x24, 0xc2, 0x63, 0xf3, 0x97, 0x17, 0xeb, 0xfe, + 0x62, 0x25, 0xba, 0x5b, 0x4d, 0x8a, 0xc2, 0x7a, 0xbd, 0x43, 0x8a, 0x8f, 0xb8, 0xf2, 0xf1, 0xc5, + 0x6a, 0x30, 0xd3, 0x50, 0x8c, 0xc8, 0x9a, 0xdf, 0xef, 0xed, 0x35, 0xe7, 0x7a, 0x62, 0xea, 0x76, + 0x7c, 0xbb, 0x08, 0x26, 0xc7, 0x02, 0x01, 0x11, 0x02, 0x81, 0x80, 0x04, 0xa5, 0xd4, 0xa7, 0xc0, + 0x2a, 0xe3, 0x6b, 0x0c, 0x8b, 0x73, 0x0c, 0x96, 0xae, 0x40, 0x1b, 0xee, 0x04, 0xf1, 0x18, 0x4c, + 0x5b, 0x43, 0x29, 0xad, 0x3a, 0x3b, 0x93, 0xa3, 0x60, 0x17, 0x9b, 0xa8, 0xbb, 0x68, 0xf4, 0x1e, + 0x33, 0x3f, 0x50, 0x32, 0xf7, 0x13, 0xf8, 0xa9, 0xe6, 0x7d, 0x79, 0x44, 0x00, 0xde, 0x72, 0xed, + 0xf2, 0x73, 0xfa, 0x7b, 0xae, 0x2a, 0x71, 0xc0, 0x40, 0xc8, 0x37, 0x6f, 0x38, 0xb2, 0x69, 0x1f, + 0xa8, 0x83, 0x7b, 0x42, 0x00, 0x73, 0x46, 0xe6, 0x4c, 0x91, 0x7f, 0x13, 0x06, 0x69, 0x06, 0xd8, + 0x3f, 0x22, 0x15, 0x75, 0xf6, 0xde, 0xcd, 0xb0, 0xbc, 0x66, 0x61, 0x91, 0x08, 0x9b, 0x2b, 0xb2, + 0x00, 0xa9, 0x67, 0x05, 0x39, 0x40, 0xb9, 0x37, 0x85, 0x88, 0x4f, 0x76, 0x79, 0x63, 0xc0, 0x88, + 0x3c, 0x86, 0xa8, 0x12, 0x94, 0x5f, 0xe4, 0x36, 0x3d, 0xea, 0xb9, 0x02, 0x41, 0x00, 0xb6, 0x2e, + 0xbb, 0xcd, 0x2f, 0x3a, 0x99, 0xe0, 0xa1, 0xa5, 0x44, 0x77, 0xea, 0x0b, 0xbe, 0x16, 0x95, 0x0e, + 0x64, 0xa7, 0x68, 0xd7, 0x4b, 0x15, 0x15, 0x23, 0xe2, 0x1e, 0x4e, 0x00, 0x2c, 0x22, 0x97, 0xae, + 0xb0, 0x74, 0xa6, 0x99, 0xd0, 0x5d, 0xb7, 0x1b, 0x10, 0x34, 0x13, 0xd2, 0x5f, 0x6e, 0x56, 0xad, + 0x85, 0x4a, 0xdb, 0xf0, 0x78, 0xbd, 0xf4, 0x8c, 0xb7, 0x9a, 0x3e, 0x99, 0xef, 0xb9, 0x02, 0x41, + 0x00, 0xde, 0x0d, 0xa7, 0x48, 0x75, 0x90, 0xad, 0x11, 0xa1, 0xac, 0xee, 0xcb, 0x41, 0x81, 0xc6, + 0xc8, 0x7f, 0xe7, 0x25, 0x94, 0xa1, 0x2a, 0x21, 0xa8, 0x57, 0xfe, 0x84, 0xf2, 0x5e, 0xb4, 0x96, + 0x35, 0xaf, 0xef, 0x2e, 0x7a, 0xf8, 0xda, 0x3f, 0xac, 0x8a, 0x3c, 0x1c, 0x9c, 0xbd, 0x44, 0xd6, + 0x90, 0xb5, 0xce, 0x1b, 0x12, 0xf9, 0x3b, 0x8c, 0x69, 0xf6, 0xa9, 0x02, 0x93, 0x48, 0x35, 0x0a, + 0x7f, 0x02, 0x40, 0x6b, 0x2a, 0x8c, 0x96, 0xd0, 0x7c, 0xd2, 0xfc, 0x9b, 0x52, 0x28, 0x46, 0x89, + 0xac, 0x8d, 0xef, 0x2a, 0x80, 0xef, 0xea, 0x01, 0x6f, 0x95, 0x93, 0xee, 0x51, 0x57, 0xd5, 0x97, + 0x4b, 0x65, 0x41, 0x86, 0x66, 0xc2, 0x26, 0x80, 0x1e, 0x3e, 0x55, 0x3e, 0x88, 0x63, 0xe2, 0x66, + 0x03, 0x47, 0x31, 0xd8, 0xa2, 0x4e, 0x68, 0x45, 0x24, 0x0a, 0xca, 0x17, 0x61, 0xd5, 0x69, 0xca, + 0x78, 0xab, 0x21, 0x02, 0x41, 0x00, 0x8f, 0xae, 0x7b, 0x4d, 0x00, 0xc7, 0x06, 0x92, 0xf0, 0x24, + 0x9a, 0x83, 0x84, 0xbd, 0x62, 0x81, 0xbc, 0x2c, 0x27, 0x60, 0x2c, 0x0c, 0x33, 0xe5, 0x66, 0x1d, + 0x28, 0xd9, 0x10, 0x1a, 0x7f, 0x4f, 0xea, 0x4f, 0x78, 0x6d, 0xb0, 0x14, 0xbf, 0xc9, 0xff, 0x17, + 0xd6, 0x47, 0x4d, 0x4a, 0xa8, 0xf4, 0x39, 0x67, 0x3e, 0xb1, 0xec, 0x8f, 0xf1, 0x71, 0xbd, 0xb8, + 0xa7, 0x50, 0x3d, 0xc7, 0xf7, 0xbb, 0x02, 0x40, 0x0d, 0x85, 0x32, 0x73, 0x9f, 0x0a, 0x33, 0x2f, + 0x4b, 0xa2, 0xbd, 0xd1, 0xb1, 0x42, 0xf0, 0x72, 0xa8, 0x7a, 0xc8, 0x15, 0x37, 0x1b, 0xde, 0x76, + 0x70, 0xce, 0xfd, 0x69, 0x20, 0x00, 0x4d, 0xc9, 0x4f, 0x35, 0x6f, 0xd1, 0x35, 0xa1, 0x04, 0x95, + 0x30, 0xe8, 0x3b, 0xd5, 0x03, 0x5a, 0x50, 0x21, 0x6d, 0xa0, 0x84, 0x39, 0xe9, 0x2e, 0x1e, 0xfc, + 0xe4, 0x82, 0x43, 0x20, 0x46, 0x7d, 0x0a, 0xb6 +}; + +BOOST_FIXTURE_TEST_CASE(Encode, DataSigningKeyFixture) +{ + // manual data packet creation for now + + Data d(Name("/local/ndn/prefix")); + d.setContentType(tlv::ContentType_Blob); + d.setFreshnessPeriod(10_s); + d.setContent(CONTENT1, sizeof(CONTENT1)); + + Block signatureInfo(tlv::SignatureInfo); + // SignatureType + signatureInfo.push_back(makeNonNegativeIntegerBlock(tlv::SignatureType, tlv::SignatureSha256WithRsa)); + // KeyLocator + { + KeyLocator keyLocator; + keyLocator.setName("/test/key/locator"); + signatureInfo.push_back(keyLocator.wireEncode()); + } + signatureInfo.encode(); + + // SignatureValue + OBufferStream os; + tlv::writeVarNumber(os, tlv::SignatureValue); + + OBufferStream sig; + { + namespace tr = security::transform; + + tr::StepSource input; + input >> tr::signerFilter(DigestAlgorithm::SHA256, m_privKey) >> tr::streamSink(sig); + + input.write(d.getName(). wireEncode().wire(), d.getName(). wireEncode().size()); + input.write(d.getMetaInfo().wireEncode().wire(), d.getMetaInfo().wireEncode().size()); + input.write(d.getContent(). wire(), d.getContent(). size()); + input.write(signatureInfo. wire(), signatureInfo. size()); + input.end(); + } + auto buf = sig.buf(); + tlv::writeVarNumber(os, buf->size()); + os.write(buf->get(), buf->size()); + + Block signatureValue(os.buf()); + Signature signature(signatureInfo, signatureValue); + d.setSignature(signature); + + Block dataBlock(d.wireEncode()); + BOOST_CHECK_EQUAL_COLLECTIONS(DATA1, DATA1 + sizeof(DATA1), + dataBlock.begin(), dataBlock.end()); +} + +BOOST_FIXTURE_TEST_CASE(Decode02, DataSigningKeyFixture) +{ + Block dataBlock(DATA1, sizeof(DATA1)); + Data d(dataBlock); + + BOOST_CHECK_EQUAL(d.getName().toUri(), "/local/ndn/prefix"); + BOOST_CHECK_EQUAL(d.getContentType(), tlv::ContentType_Blob); + BOOST_CHECK_EQUAL(d.getFreshnessPeriod(), 10_s); + BOOST_CHECK_EQUAL(std::string(reinterpret_cast(d.getContent().value()), + d.getContent().value_size()), "SUCCESS!"); + BOOST_CHECK_EQUAL(d.getSignature().getType(), tlv::SignatureSha256WithRsa); + + Block block = d.getSignature().getInfo(); + block.parse(); + KeyLocator keyLocator(block.get(tlv::KeyLocator)); + BOOST_CHECK_EQUAL(keyLocator.getName().toUri(), "/test/key/locator"); + + BOOST_CHECK(security::verifySignature(d, m_pubKey)); +} + +class Decode03Fixture +{ +protected: + Decode03Fixture() + { + // initialize all elements to non-empty, to verify wireDecode clears them + d.setName("/A"); + d.setContentType(tlv::ContentType_Key); + d.setContent("1504C0C1C2C3"_block); + d.setSignature(Signature("160A 1B0101 1C050703080142"_block, + "1780 B48F1707A3BCA3CFC5F32DE51D9B46C32D7D262A21544EBDA88C3B415D637503" + "FC9BEF20F88202A56AF9831E0D30205FD4154B08502BCDEE860267A5C3E03D8E" + "A6CB74BE391C01E0A57B991B4404FC11B7D777F1B700A4B65F201118CF1840A8" + "30A2A7C17DB4B7A8777E58515121AF9E2498627F8475414CDFD9801B8152AD5B"_block)); + } + +protected: + Data d; +}; + +BOOST_FIXTURE_TEST_SUITE(Decode03, Decode03Fixture) + +BOOST_AUTO_TEST_CASE(MinimalNoSigValue) +{ + d.wireDecode("0607 0700 16031B0100"_block); + BOOST_CHECK_EQUAL(d.getName(), "/"); // empty Name is allowed in Data + BOOST_CHECK_EQUAL(d.getContentType(), tlv::ContentType_Blob); + BOOST_CHECK_EQUAL(d.getFreshnessPeriod(), 0_ms); + BOOST_CHECK_EQUAL(d.getFinalBlock().has_value(), false); + BOOST_CHECK_EQUAL(d.getContent().value_size(), 0); + BOOST_CHECK_EQUAL(d.getSignature().getType(), tlv::DigestSha256); + BOOST_CHECK_EQUAL(d.getSignature().getValue().value_size(), 0); +} + +BOOST_AUTO_TEST_CASE(Minimal) +{ + d.wireDecode("062C 0703080144 16031B0100 " + "1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76"_block); + BOOST_CHECK_EQUAL(d.getName(), "/D"); + BOOST_CHECK_EQUAL(d.getContentType(), tlv::ContentType_Blob); + BOOST_CHECK_EQUAL(d.getFreshnessPeriod(), 0_ms); + BOOST_CHECK_EQUAL(d.getFinalBlock().has_value(), false); + BOOST_CHECK_EQUAL(d.getContent().value_size(), 0); + BOOST_CHECK_EQUAL(d.getSignature().getType(), tlv::DigestSha256); + BOOST_CHECK_EQUAL(d.getSignature().getValue().value_size(), 32); + + // encode without modification: retain original wire encoding + BOOST_CHECK_EQUAL(d.wireEncode().value_size(), 44); + + // modify then re-encode as v0.2 format + d.setName("/E"); + BOOST_CHECK_EQUAL(d.wireEncode(), + "0630 0703080145 1400 1500 16031B0100 " + "1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76"_block); +} + +BOOST_AUTO_TEST_CASE(Full) +{ + d.wireDecode("063A 0703080144 FC00 1400 FC00 1500 FC00 16031B0100 FC00 " + "1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76 FC00"_block); + BOOST_CHECK_EQUAL(d.getName(), "/D"); + BOOST_CHECK_EQUAL(d.getContentType(), tlv::ContentType_Blob); + BOOST_CHECK_EQUAL(d.getFreshnessPeriod(), 0_ms); + BOOST_CHECK_EQUAL(d.getFinalBlock().has_value(), false); + BOOST_CHECK_EQUAL(d.getContent().value_size(), 0); + BOOST_CHECK_EQUAL(d.getSignature().getType(), tlv::DigestSha256); + BOOST_CHECK_EQUAL(d.getSignature().getValue().value_size(), 32); + + // encode without modification: retain original wire encoding + BOOST_CHECK_EQUAL(d.wireEncode().value_size(), 58); + + // modify then re-encode as v0.2 format + d.setName("/E"); + BOOST_CHECK_EQUAL(d.wireEncode(), + "0630 0703080145 1400 1500 16031B0100 " + "1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76"_block); +} + +BOOST_AUTO_TEST_CASE(CriticalElementOutOfOrder) +{ + BOOST_CHECK_THROW(d.wireDecode( + "0630 1400 0703080145 1500 16031B0100 " + "1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76"_block), + tlv::Error); + BOOST_CHECK_THROW(d.wireDecode( + "0630 0703080145 1500 1400 16031B0100 " + "1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76"_block), + tlv::Error); + BOOST_CHECK_THROW(d.wireDecode( + "0630 0703080145 1400 16031B0100 1500 " + "1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76"_block), + tlv::Error); + BOOST_CHECK_THROW(d.wireDecode( + "0630 0703080145 1400 1500 " + "1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76 16031B0100"_block), + tlv::Error); + BOOST_CHECK_THROW(d.wireDecode( + "0652 0703080145 1400 1500 16031B0100 " + "1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76" + "1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76"_block), + tlv::Error); +} + +BOOST_AUTO_TEST_CASE(NameMissing) +{ + BOOST_CHECK_THROW(d.wireDecode("0605 16031B0100"_block), tlv::Error); +} + +BOOST_AUTO_TEST_CASE(SigInfoMissing) +{ + BOOST_CHECK_THROW(d.wireDecode("0605 0703080144"_block), tlv::Error); +} + +BOOST_AUTO_TEST_CASE(UnrecognizedNonCriticalElementBeforeName) +{ + BOOST_CHECK_THROW(d.wireDecode( + "062F FC00 0703080144 16031B0100 " + "1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76"_block), + tlv::Error); +} + +BOOST_AUTO_TEST_CASE(UnrecognizedCriticalElement) +{ + BOOST_CHECK_THROW(d.wireDecode( + "0632 0703080145 FB00 1400 1500 16031B0100 " + "1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76"_block), + tlv::Error); +} + +BOOST_AUTO_TEST_SUITE_END() // Decode03 + +BOOST_FIXTURE_TEST_CASE(FullName, IdentityManagementFixture) +{ + Data d(Name("/local/ndn/prefix")); + d.setContentType(tlv::ContentType_Blob); + d.setFreshnessPeriod(10_s); + d.setContent(CONTENT1, sizeof(CONTENT1)); + BOOST_CHECK_THROW(d.getFullName(), Data::Error); // FullName is unavailable without signing + + m_keyChain.sign(d); + BOOST_CHECK_EQUAL(d.hasWire(), true); + Name fullName = d.getFullName(); // FullName is available after signing + + BOOST_CHECK_EQUAL(d.getName().size() + 1, fullName.size()); + BOOST_CHECK_EQUAL_COLLECTIONS(d.getName().begin(), d.getName().end(), + fullName.begin(), fullName.end() - 1); + BOOST_CHECK_EQUAL(fullName.get(-1).value_size(), util::Sha256::DIGEST_SIZE); + + // FullName should be cached, so value() pointer points to same memory location + BOOST_CHECK_EQUAL(fullName.get(-1).value(), d.getFullName().get(-1).value()); + + d.setFreshnessPeriod(100_s); // invalidates FullName + BOOST_CHECK_THROW(d.getFullName(), Data::Error); + + Data d1(Block(DATA1, sizeof(DATA1))); + BOOST_CHECK_EQUAL(d1.getFullName(), + "/local/ndn/prefix/" + "sha256digest=28bad4b5275bd392dbb670c75cf0b66f13f7942b21e80f55c0e86b374753a548"); +} + +BOOST_AUTO_TEST_CASE(Equality) +{ + Data a; + Data b; + BOOST_CHECK_EQUAL(a == b, true); + BOOST_CHECK_EQUAL(a != b, false); + + a.setName("ndn:/A"); + BOOST_CHECK_EQUAL(a == b, false); + BOOST_CHECK_EQUAL(a != b, true); + + b.setName("ndn:/B"); + BOOST_CHECK_EQUAL(a == b, false); + BOOST_CHECK_EQUAL(a != b, true); + + b.setName("ndn:/A"); + BOOST_CHECK_EQUAL(a == b, true); + BOOST_CHECK_EQUAL(a != b, false); + + a.setFreshnessPeriod(10_s); + BOOST_CHECK_EQUAL(a == b, false); + BOOST_CHECK_EQUAL(a != b, true); + + b.setFreshnessPeriod(10_s); + BOOST_CHECK_EQUAL(a == b, true); + BOOST_CHECK_EQUAL(a != b, false); + + static const uint8_t someData[] = "someData"; + a.setContent(someData, sizeof(someData)); + BOOST_CHECK_EQUAL(a == b, false); + BOOST_CHECK_EQUAL(a != b, true); + + b.setContent(someData, sizeof(someData)); + BOOST_CHECK_EQUAL(a == b, true); + BOOST_CHECK_EQUAL(a != b, false); + + a.setSignature(SignatureSha256WithRsa()); + BOOST_CHECK_EQUAL(a == b, false); + BOOST_CHECK_EQUAL(a != b, true); + + b.setSignature(SignatureSha256WithRsa()); + BOOST_CHECK_EQUAL(a == b, true); + BOOST_CHECK_EQUAL(a != b, false); +} + +BOOST_AUTO_TEST_CASE(Print) +{ + Data d(Block(DATA1, sizeof(DATA1))); + BOOST_CHECK_EQUAL(boost::lexical_cast(d), + "Name: /local/ndn/prefix\n" + "MetaInfo: ContentType: 0, FreshnessPeriod: 10000 milliseconds\n" + "Content: (size: 8)\n" + "Signature: (type: SignatureSha256WithRsa, value_length: 128)\n"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestData + +} // namespace tests +} // namespace ndn diff --git a/tests/unit/delegation-list.t.cpp b/tests/unit/delegation-list.t.cpp new file mode 100644 index 000000000..0831dca33 --- /dev/null +++ b/tests/unit/delegation-list.t.cpp @@ -0,0 +1,370 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/delegation-list.hpp" + +#include "tests/boost-test.hpp" +#include + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(TestDelegationList) + +const uint8_t DEL1A[] = { + 0x1f, 0x08, // Delegation + 0x1e, 0x01, 0x01, // Preference=1 + 0x07, 0x03, 0x08, 0x01, 0x41 // Name=/A +}; +const uint8_t DEL1B[] = { + 0x1f, 0x08, // Delegation + 0x1e, 0x01, 0x01, // Preference=1 + 0x07, 0x03, 0x08, 0x01, 0x42 // Name=/B +}; +const uint8_t DEL2A[] = { + 0x1f, 0x08, // Delegation + 0x1e, 0x01, 0x02, // Preference=2 + 0x07, 0x03, 0x08, 0x01, 0x41 // Name=/A +}; +const uint8_t DEL2B[] = { + 0x1f, 0x08, // Delegation + 0x1e, 0x01, 0x02, // Preference=2 + 0x07, 0x03, 0x08, 0x01, 0x42 // Name=/B +}; + +Block +makeDelegationListBlock(uint32_t type, std::initializer_list dels) +{ + Block block(type); + for (const uint8_t* del : dels) { + block.push_back(Block(del, 2 + del[1])); + } + block.encode(); + return block; +} + +BOOST_AUTO_TEST_SUITE(Decode) + +BOOST_AUTO_TEST_CASE(DecodeUnsorted) +{ + DelegationList dl(makeDelegationListBlock(tlv::ForwardingHint, {DEL2A, DEL2B, DEL1A}), false); + BOOST_CHECK_EQUAL(dl.size(), 3); + BOOST_CHECK_EQUAL(dl.at(0).preference, 2); + BOOST_CHECK_EQUAL(dl.at(0).name, "/A"); + BOOST_CHECK_EQUAL(dl.at(1).preference, 2); + BOOST_CHECK_EQUAL(dl.at(1).name, "/B"); + BOOST_CHECK_EQUAL(dl.at(2).preference, 1); + BOOST_CHECK_EQUAL(dl.at(2).name, "/A"); +} + +BOOST_AUTO_TEST_CASE(DecodeSorted) +{ + DelegationList dl(makeDelegationListBlock(tlv::Content, {DEL2A, DEL2B, DEL1A})); + BOOST_CHECK_EQUAL(dl.size(), 3); + BOOST_CHECK_EQUAL(dl.at(0).preference, 1); + BOOST_CHECK_EQUAL(dl.at(0).name, "/A"); + BOOST_CHECK_EQUAL(dl.at(1).preference, 2); + BOOST_CHECK_EQUAL(dl.at(1).name, "/A"); + BOOST_CHECK_EQUAL(dl.at(2).preference, 2); + BOOST_CHECK_EQUAL(dl.at(2).name, "/B"); +} + +BOOST_AUTO_TEST_CASE(DecodeEmpty) +{ + DelegationList dl; + Block block = makeDelegationListBlock(tlv::ForwardingHint, {}); + BOOST_CHECK_THROW(dl.wireDecode(block), DelegationList::Error); +} + +BOOST_AUTO_TEST_CASE(DecodeBadType) +{ + DelegationList dl; + Block block = makeDelegationListBlock(tlv::Selectors, {DEL1A, DEL2B}); + BOOST_CHECK_THROW(dl.wireDecode(block), DelegationList::Error); +} + +BOOST_AUTO_TEST_CASE(DecodeNotDelegation) +{ + const uint8_t BAD_DEL[] = { + 0x09, 0x00 // Selectors + }; + + DelegationList dl; + Block block = makeDelegationListBlock(tlv::ForwardingHint, {DEL1A, BAD_DEL}); + BOOST_CHECK_THROW(dl.wireDecode(block), DelegationList::Error); +} + +BOOST_AUTO_TEST_CASE(DecodeMissingPreference) +{ + const uint8_t BAD_DEL[] = { + 0x1f, 0x05, // Delegation + 0x07, 0x03, 0x08, 0x01, 0x42 // Name=/B + }; + + DelegationList dl; + Block block = makeDelegationListBlock(tlv::ForwardingHint, {DEL1A, BAD_DEL}); + BOOST_CHECK_THROW(dl.wireDecode(block), DelegationList::Error); +} + +BOOST_AUTO_TEST_CASE(DecodeMissingName) +{ + const uint8_t BAD_DEL[] = { + 0x1f, 0x03, // Delegation + 0x1e, 0x01, 0x02, // Preference=2 + }; + + DelegationList dl; + Block block = makeDelegationListBlock(tlv::ForwardingHint, {DEL1A, BAD_DEL}); + BOOST_CHECK_THROW(dl.wireDecode(block), DelegationList::Error); +} + +BOOST_AUTO_TEST_CASE(DecodeUnknownField) +{ + const uint8_t BAD_DEL[] = { + 0x1f, 0x0a, // Delegation + 0x1e, 0x01, 0x02, // Preference=2 + 0x09, 0x00, // Selectors + 0x07, 0x03, 0x08, 0x01, 0x42 // Name=/B + }; + + DelegationList dl; + Block block = makeDelegationListBlock(tlv::ForwardingHint, {DEL1A, BAD_DEL}); + BOOST_CHECK_THROW(dl.wireDecode(block), DelegationList::Error); +} + +BOOST_AUTO_TEST_CASE(DecodeWrongOrder) +{ + const uint8_t BAD_DEL[] = { + 0x1f, 0x08, // Delegation + 0x07, 0x03, 0x08, 0x01, 0x42, // Name=/B + 0x1e, 0x01, 0x02 // Preference=2 + }; + + DelegationList dl; + Block block = makeDelegationListBlock(tlv::ForwardingHint, {DEL1A, BAD_DEL}); + BOOST_CHECK_THROW(dl.wireDecode(block), DelegationList::Error); +} + +BOOST_AUTO_TEST_SUITE_END() // Decode + +BOOST_AUTO_TEST_SUITE(InsertEncode) + +BOOST_AUTO_TEST_CASE(InsertSimple) +{ + DelegationList dl; + BOOST_CHECK_EQUAL(dl.empty(), true); + dl.insert(2, "/A"); + BOOST_CHECK_EQUAL(dl.empty(), false); + dl.insert(1, "/B"); + BOOST_CHECK_EQUAL(dl.size(), 2); + + EncodingBuffer encoder; + dl.wireEncode(encoder); + BOOST_CHECK_EQUAL(encoder.block(), makeDelegationListBlock(tlv::ForwardingHint, {DEL1B, DEL2A})); +} + +BOOST_AUTO_TEST_CASE(InsertReplace) +{ + DelegationList dl({{2, "/A"}}); + dl.insert(Delegation{1, "/A"}, DelegationList::INS_REPLACE); + BOOST_CHECK_EQUAL(dl.size(), 1); + BOOST_CHECK_EQUAL(dl.at(0).preference, 1); + BOOST_CHECK_EQUAL(dl[0].name, "/A"); + + EncodingBuffer encoder; + dl.wireEncode(encoder); + BOOST_CHECK_EQUAL(encoder.block(), makeDelegationListBlock(tlv::ForwardingHint, {DEL1A})); +} + +BOOST_AUTO_TEST_CASE(InsertAppend) +{ + DelegationList dl({{2, "/A"}}); + dl.insert(Delegation{1, "/A"}, DelegationList::INS_APPEND); + BOOST_CHECK_EQUAL(dl.size(), 2); + BOOST_CHECK_EQUAL(dl.at(0).preference, 1); + BOOST_CHECK_EQUAL(dl.at(1).preference, 2); + + EncodingBuffer encoder; + dl.wireEncode(encoder); + BOOST_CHECK_EQUAL(encoder.block(), makeDelegationListBlock(tlv::ForwardingHint, {DEL1A, DEL2A})); +} + +BOOST_AUTO_TEST_CASE(InsertSkip) +{ + DelegationList dl({{2, "/A"}}); + dl.insert(Delegation{1, "/A"}, DelegationList::INS_SKIP); + BOOST_CHECK_EQUAL(dl.size(), 1); + BOOST_CHECK_EQUAL(dl.at(0).preference, 2); + + EncodingBuffer encoder; + dl.wireEncode(encoder); + BOOST_CHECK_EQUAL(encoder.block(), makeDelegationListBlock(tlv::ForwardingHint, {DEL2A})); +} + +BOOST_AUTO_TEST_CASE(Unsorted) +{ + DelegationList dl(makeDelegationListBlock(tlv::ForwardingHint, {DEL2A}), false); + dl.insert(1, "/B"); + BOOST_CHECK_EQUAL(dl.size(), 2); + BOOST_CHECK_EQUAL(dl.at(0).preference, 2); + BOOST_CHECK_EQUAL(dl.at(0).name, "/A"); + BOOST_CHECK_EQUAL(dl.at(1).preference, 1); + BOOST_CHECK_EQUAL(dl.at(1).name, "/B"); + + EncodingBuffer encoder; + dl.wireEncode(encoder, tlv::Content); + BOOST_CHECK_EQUAL(encoder.block(), makeDelegationListBlock(tlv::Content, {DEL2A, DEL1B})); +} + +BOOST_AUTO_TEST_CASE(EncodeBadType) +{ + DelegationList dl(makeDelegationListBlock(tlv::ForwardingHint, {DEL2A})); + EncodingBuffer encoder; + BOOST_CHECK_THROW(dl.wireEncode(encoder, tlv::Selectors), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(EncodeEmpty) +{ + DelegationList dl; + EncodingBuffer encoder; + BOOST_CHECK_THROW(dl.wireEncode(encoder), DelegationList::Error); +} + +BOOST_AUTO_TEST_SUITE_END() // InsertEncode + +BOOST_AUTO_TEST_SUITE(Erase) + +BOOST_AUTO_TEST_CASE(EraseNoop) +{ + DelegationList dl; + dl.insert(1, "/A"); + BOOST_CHECK_EQUAL(dl.erase(2, "/A"), 0); + BOOST_CHECK_EQUAL(dl.erase(Delegation{1, "/B"}), 0); + BOOST_CHECK_EQUAL(dl.size(), 1); + BOOST_CHECK_EQUAL(dl.at(0).preference, 1); + BOOST_CHECK_EQUAL(dl.at(0).name, "/A"); +} + +BOOST_AUTO_TEST_CASE(EraseOne) +{ + DelegationList dl; + dl.insert(1, "/A"); + BOOST_CHECK_EQUAL(dl.erase(1, "/A"), 1); + BOOST_CHECK_EQUAL(dl.size(), 0); +} + +BOOST_AUTO_TEST_CASE(EraseByName) +{ + DelegationList dl; + dl.insert(1, "/A"); + dl.insert(2, "/A", DelegationList::INS_APPEND); + BOOST_CHECK_EQUAL(dl.size(), 2); + BOOST_CHECK_EQUAL(dl.erase("/A"), 2); + BOOST_CHECK_EQUAL(dl.size(), 0); +} + +BOOST_AUTO_TEST_SUITE_END() // Erase + +BOOST_AUTO_TEST_SUITE(Sort) + +BOOST_AUTO_TEST_CASE(Noop) +{ + DelegationList dl(makeDelegationListBlock(tlv::ForwardingHint, {DEL1A})); + BOOST_CHECK_EQUAL(dl.isSorted(), true); + dl.sort(); + BOOST_CHECK_EQUAL(dl.isSorted(), true); +} + +BOOST_AUTO_TEST_CASE(Sort) +{ + DelegationList dl(makeDelegationListBlock(tlv::ForwardingHint, {DEL2A, DEL2B, DEL1A}), false); + BOOST_CHECK_EQUAL(dl.isSorted(), false); + dl.sort(); + BOOST_CHECK_EQUAL(dl.isSorted(), true); + BOOST_CHECK_EQUAL(dl.size(), 3); + BOOST_CHECK_EQUAL(dl.at(0).preference, 1); + BOOST_CHECK_EQUAL(dl.at(0).name, "/A"); + BOOST_CHECK_EQUAL(dl.at(1).preference, 2); + BOOST_CHECK_EQUAL(dl.at(1).name, "/A"); + BOOST_CHECK_EQUAL(dl.at(2).preference, 2); + BOOST_CHECK_EQUAL(dl.at(2).name, "/B"); +} + +BOOST_AUTO_TEST_SUITE_END() // Sort + +BOOST_AUTO_TEST_SUITE(Compare) + +BOOST_AUTO_TEST_CASE(Empty) +{ + DelegationList dl1, dl2; + BOOST_CHECK_EQUAL(dl1, dl2); +} + +BOOST_AUTO_TEST_CASE(SortedEqual) +{ + DelegationList dl1(makeDelegationListBlock(tlv::ForwardingHint, {DEL2A, DEL1B})), + dl2(makeDelegationListBlock(tlv::Content, {DEL1B, DEL2A})); + BOOST_CHECK_EQUAL(dl1, dl2); +} + +BOOST_AUTO_TEST_CASE(SortedUnequal) +{ + DelegationList dl1(makeDelegationListBlock(tlv::ForwardingHint, {DEL2A, DEL1B})), + dl2(makeDelegationListBlock(tlv::Content, {DEL1A, DEL2B})); + BOOST_CHECK_NE(dl1, dl2); +} + +BOOST_AUTO_TEST_CASE(UnsortedSameOrder) +{ + DelegationList dl1(makeDelegationListBlock(tlv::ForwardingHint, {DEL2A, DEL1B}), false), + dl2(makeDelegationListBlock(tlv::Content, {DEL2A, DEL1B}), false); + BOOST_CHECK_EQUAL(dl1, dl2); +} + +BOOST_AUTO_TEST_CASE(UnsortedDifferentOrder) +{ + DelegationList dl1(makeDelegationListBlock(tlv::ForwardingHint, {DEL2A, DEL1B}), false), + dl2(makeDelegationListBlock(tlv::Content, {DEL1B, DEL2A}), false); + BOOST_CHECK_NE(dl1, dl2); +} + +BOOST_AUTO_TEST_SUITE_END() // Compare + +BOOST_AUTO_TEST_SUITE(Print) + +BOOST_AUTO_TEST_CASE(PrintEmpty) +{ + DelegationList dl; + BOOST_CHECK_EQUAL(boost::lexical_cast(dl), "[]"); +} + +BOOST_AUTO_TEST_CASE(PrintNormal) +{ + DelegationList dl(makeDelegationListBlock(tlv::ForwardingHint, {DEL2A, DEL1B})); + BOOST_CHECK_EQUAL(boost::lexical_cast(dl), "[/B(1),/A(2)]"); +} + +BOOST_AUTO_TEST_SUITE_END() // Print + +BOOST_AUTO_TEST_SUITE_END() // TestDelegationList + +} // namespace tests +} // namespace ndn diff --git a/tests/unit/delegation.t.cpp b/tests/unit/delegation.t.cpp new file mode 100644 index 000000000..9f23e89b6 --- /dev/null +++ b/tests/unit/delegation.t.cpp @@ -0,0 +1,64 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/delegation.hpp" + +#include "tests/boost-test.hpp" +#include + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(TestDelegation) + +BOOST_AUTO_TEST_CASE(Compare) +{ + BOOST_CHECK_EQUAL((Delegation{1, "/A"}), (Delegation{1, "/A"})); + BOOST_CHECK_LE((Delegation{1, "/A"}), (Delegation{1, "/A"})); + BOOST_CHECK_GE((Delegation{1, "/A"}), (Delegation{1, "/A"})); + + BOOST_CHECK_NE((Delegation{1, "/A"}), (Delegation{2, "/A"})); + BOOST_CHECK_NE((Delegation{1, "/A"}), (Delegation{1, "/B"})); + + BOOST_CHECK_LT((Delegation{1, "/A"}), (Delegation{1, "/B"})); + BOOST_CHECK_LE((Delegation{1, "/A"}), (Delegation{1, "/B"})); + BOOST_CHECK_LT((Delegation{1, "/B"}), (Delegation{2, "/A"})); + BOOST_CHECK_LE((Delegation{1, "/B"}), (Delegation{2, "/A"})); + BOOST_CHECK_LT((Delegation{1, "/A"}), (Delegation{2, "/A"})); + BOOST_CHECK_LE((Delegation{1, "/A"}), (Delegation{2, "/A"})); + + BOOST_CHECK_GT((Delegation{1, "/B"}), (Delegation{1, "/A"})); + BOOST_CHECK_GE((Delegation{1, "/B"}), (Delegation{1, "/A"})); + BOOST_CHECK_GT((Delegation{2, "/A"}), (Delegation{1, "/B"})); + BOOST_CHECK_GE((Delegation{2, "/A"}), (Delegation{1, "/B"})); + BOOST_CHECK_GT((Delegation{2, "/A"}), (Delegation{1, "/A"})); + BOOST_CHECK_GE((Delegation{2, "/A"}), (Delegation{1, "/A"})); +} + +BOOST_AUTO_TEST_CASE(Print) +{ + BOOST_CHECK_EQUAL(boost::lexical_cast(Delegation{1, "/B"}), "/B(1)"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestDelegation + +} // namespace tests +} // namespace ndn diff --git a/tests/unit/detail/cancel-handle.t.cpp b/tests/unit/detail/cancel-handle.t.cpp new file mode 100644 index 000000000..2e951ddea --- /dev/null +++ b/tests/unit/detail/cancel-handle.t.cpp @@ -0,0 +1,139 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/detail/cancel-handle.hpp" + +#include "tests/boost-test.hpp" + +namespace ndn { +namespace detail { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Detail) +BOOST_AUTO_TEST_SUITE(TestCancelHandle) + +static CancelHandle +makeDummyCancelHandle(int& nCancels) +{ + return CancelHandle([&] { ++nCancels; }); +} + +BOOST_AUTO_TEST_SUITE(PlainHandle) + +BOOST_AUTO_TEST_CASE(ManualCancel) +{ + int nCancels = 0; + auto hdl = makeDummyCancelHandle(nCancels); + BOOST_CHECK_EQUAL(nCancels, 0); + + hdl.cancel(); + BOOST_CHECK_EQUAL(nCancels, 1); + + hdl = CancelHandle(); + BOOST_CHECK_EQUAL(nCancels, 1); +} + +BOOST_AUTO_TEST_SUITE_END() // PlainHandle + +BOOST_AUTO_TEST_SUITE(ScopedHandle) + +using ScopedTestHandle = ScopedCancelHandle; + +BOOST_AUTO_TEST_CASE(ManualCancel) +{ + int nCancels = 0; + { + ScopedTestHandle hdl = makeDummyCancelHandle(nCancels); + BOOST_CHECK_EQUAL(nCancels, 0); + + hdl.cancel(); + BOOST_CHECK_EQUAL(nCancels, 1); + } // hdl goes out of scope + BOOST_CHECK_EQUAL(nCancels, 1); +} + +BOOST_AUTO_TEST_CASE(Destruct) +{ + int nCancels = 0; + { + ScopedTestHandle hdl = makeDummyCancelHandle(nCancels); + BOOST_CHECK_EQUAL(nCancels, 0); + } // hdl goes out of scope + BOOST_CHECK_EQUAL(nCancels, 1); +} + +BOOST_AUTO_TEST_CASE(Assign) +{ + int nCancels1 = 0, nCancels2 = 0; + { + ScopedTestHandle hdl = makeDummyCancelHandle(nCancels1); + hdl = makeDummyCancelHandle(nCancels2); + BOOST_CHECK_EQUAL(nCancels1, 1); + BOOST_CHECK_EQUAL(nCancels2, 0); + } // hdl goes out of scope + BOOST_CHECK_EQUAL(nCancels2, 1); +} + +BOOST_AUTO_TEST_CASE(Release) +{ + int nCancels = 0; + { + ScopedTestHandle hdl = makeDummyCancelHandle(nCancels); + hdl.release(); + hdl.cancel(); // no effect + } // hdl goes out of scope + BOOST_CHECK_EQUAL(nCancels, 0); +} + +BOOST_AUTO_TEST_CASE(MoveConstruct) +{ + int nCancels = 0; + unique_ptr hdl1; + { + ScopedTestHandle hdl2 = makeDummyCancelHandle(nCancels); + hdl1 = make_unique(std::move(hdl2)); + } // hdl2 goes out of scope + BOOST_CHECK_EQUAL(nCancels, 0); + hdl1.reset(); + BOOST_CHECK_EQUAL(nCancels, 1); +} + +BOOST_AUTO_TEST_CASE(MoveAssign) +{ + int nCancels = 0; + { + ScopedTestHandle hdl1; + { + ScopedTestHandle hdl2 = makeDummyCancelHandle(nCancels); + hdl1 = std::move(hdl2); + } // hdl2 goes out of scope + BOOST_CHECK_EQUAL(nCancels, 0); + } // hdl1 goes out of scope + BOOST_CHECK_EQUAL(nCancels, 1); +} + +BOOST_AUTO_TEST_SUITE_END() // ScopedHandle +BOOST_AUTO_TEST_SUITE_END() // TestCancelHandle +BOOST_AUTO_TEST_SUITE_END() // Detail + +} // namespace tests +} // namespace detail +} // namespace ndn diff --git a/tests/unit/detail/packet-base.t.cpp b/tests/unit/detail/packet-base.t.cpp new file mode 100644 index 000000000..41d47db60 --- /dev/null +++ b/tests/unit/detail/packet-base.t.cpp @@ -0,0 +1,66 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/detail/packet-base.hpp" +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/lp/tags.hpp" + +#include "tests/boost-test.hpp" + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Detail) +BOOST_AUTO_TEST_SUITE(TestPacketBase) + +BOOST_AUTO_TEST_CASE(CongestionMark) +{ + Interest interest; + + BOOST_CHECK_EQUAL(interest.getCongestionMark(), 0); + + auto tag = interest.getTag(); + BOOST_CHECK(!tag); + + interest.setCongestionMark(true); + tag = interest.getTag(); + BOOST_REQUIRE(tag); + BOOST_CHECK_EQUAL(*tag, 1); + + interest.setCongestionMark(false); + tag = interest.getTag(); + BOOST_CHECK(!tag); + + interest.setCongestionMark(300); + tag = interest.getTag(); + BOOST_REQUIRE(tag); + BOOST_CHECK_EQUAL(*tag, 300); + + interest.setCongestionMark(0); + tag = interest.getTag(); + BOOST_CHECK(!tag); +} + +BOOST_AUTO_TEST_SUITE_END() // TestPacketBase +BOOST_AUTO_TEST_SUITE_END() // Detail + +} // namespace tests +} // namespace ndn diff --git a/tests/unit-tests/tag-host.t.cpp b/tests/unit/detail/tag-host.t.cpp similarity index 85% rename from tests/unit-tests/tag-host.t.cpp rename to tests/unit/detail/tag-host.t.cpp index ae99a8c36..72caa7e83 100644 --- a/tests/unit-tests/tag-host.t.cpp +++ b/tests/unit/detail/tag-host.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,24 +19,25 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "tag-host.hpp" +#include "ndn-cxx/detail/tag-host.hpp" +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/interest.hpp" -#include "boost-test.hpp" -#include "interest.hpp" -#include "data.hpp" +#include "tests/boost-test.hpp" #include namespace ndn { namespace tests { +BOOST_AUTO_TEST_SUITE(Detail) BOOST_AUTO_TEST_SUITE(TestTagHost) class TestTag : public Tag { public: - static constexpr size_t - getTypeId() + static constexpr int + getTypeId() noexcept { return 1; } @@ -45,8 +46,8 @@ class TestTag : public Tag class TestTag2 : public Tag { public: - static constexpr size_t - getTypeId() + static constexpr int + getTypeId() noexcept { return 2; } @@ -81,6 +82,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(Basic, T, Fixtures, T) } BOOST_AUTO_TEST_SUITE_END() // TestTagHost +BOOST_AUTO_TEST_SUITE_END() // Detail } // namespace tests } // namespace ndn diff --git a/tests/unit/dummy-validator.hpp b/tests/unit/dummy-validator.hpp new file mode 100644 index 000000000..aab9114aa --- /dev/null +++ b/tests/unit/dummy-validator.hpp @@ -0,0 +1,114 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TESTS_UNIT_DUMMY_VALIDATOR_HPP +#define NDN_TESTS_UNIT_DUMMY_VALIDATOR_HPP + +#include "ndn-cxx/security/v2/validator.hpp" +#include "ndn-cxx/security/v2/validation-policy.hpp" +#include "ndn-cxx/security/v2/certificate-fetcher-offline.hpp" + +namespace ndn { +namespace tests { + +/** \brief A validation policy for unit testing + */ +class DummyValidationPolicy : public security::v2::ValidationPolicy +{ +public: + /** \brief constructor + * \param shouldAccept whether to accept or reject all validation requests + */ + explicit + DummyValidationPolicy(bool shouldAccept = true) + { + this->setResult(shouldAccept); + } + + /** \brief change the validation result + * \param shouldAccept whether to accept or reject all validation requests + */ + void + setResult(bool shouldAccept) + { + m_decide = [shouldAccept] (const Name&) { return shouldAccept; }; + } + + /** \brief set a callback for validation + * \param cb a callback which receives the Interest/Data name for each validation request; + * its return value determines the validation result + */ + void + setResultCallback(const function& cb) + { + m_decide = cb; + } + +protected: + void + checkPolicy(const Data& data, const shared_ptr& state, + const ValidationContinuation& continueValidation) override + { + if (m_decide(data.getName())) { + continueValidation(nullptr, state); + } + else { + state->fail(security::v2::ValidationError::NO_ERROR); + } + } + + void + checkPolicy(const Interest& interest, const shared_ptr& state, + const ValidationContinuation& continueValidation) override + { + if (m_decide(interest.getName())) { + continueValidation(nullptr, state); + } + else { + state->fail(security::v2::ValidationError::NO_ERROR); + } + } + +private: + function m_decide; +}; + +class DummyValidator : public security::v2::Validator +{ +public: + explicit + DummyValidator(bool shouldAccept = true) + : security::v2::Validator(make_unique(shouldAccept), + make_unique()) + { + } + + DummyValidationPolicy& + getPolicy() + { + return static_cast(security::v2::Validator::getPolicy()); + } +}; + +} // namespace tests +} // namespace ndn + +#endif // NDN_TESTS_UNIT_DUMMY_VALIDATOR_HPP diff --git a/tests/unit/encoding/block-helpers.t.cpp b/tests/unit/encoding/block-helpers.t.cpp new file mode 100644 index 000000000..c44be8489 --- /dev/null +++ b/tests/unit/encoding/block-helpers.t.cpp @@ -0,0 +1,139 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/encoding/block-helpers.hpp" +#include "ndn-cxx/name.hpp" + +#include "tests/boost-test.hpp" + +namespace ndn { +namespace encoding { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Encoding) +BOOST_AUTO_TEST_SUITE(TestBlockHelpers) + +enum E8 : uint8_t +{ + E8_NONE +}; + +enum class EC8 : uint8_t +{ + NONE +}; + +enum E16 : uint16_t +{ + E16_NONE +}; + +enum class EC16 : uint16_t +{ + NONE +}; + +BOOST_AUTO_TEST_CASE(NonNegativeInteger) +{ + Block b = makeNonNegativeIntegerBlock(100, 1000); + BOOST_CHECK_EQUAL(b.type(), 100); + BOOST_CHECK_GT(b.value_size(), 0); + BOOST_CHECK_EQUAL(readNonNegativeInteger(b), 1000); + + BOOST_CHECK_THROW(readNonNegativeInteger(Block()), tlv::Error); + + BOOST_CHECK_THROW(readNonNegativeIntegerAs(b), tlv::Error); + BOOST_CHECK_EQUAL(readNonNegativeIntegerAs(b), 1000); + BOOST_CHECK_EQUAL(readNonNegativeIntegerAs(b), 1000); + BOOST_CHECK_THROW(readNonNegativeIntegerAs(b), tlv::Error); + BOOST_CHECK_EQUAL(static_cast(readNonNegativeIntegerAs(b)), 1000); + BOOST_CHECK_THROW(readNonNegativeIntegerAs(b), tlv::Error); + BOOST_CHECK_EQUAL(static_cast(readNonNegativeIntegerAs(b)), 1000); +} + +BOOST_AUTO_TEST_CASE(Empty) +{ + Block b = makeEmptyBlock(200); + BOOST_CHECK_EQUAL(b.type(), 200); + BOOST_CHECK_EQUAL(b.value_size(), 0); +} + +BOOST_AUTO_TEST_CASE(String) +{ + Block b = makeStringBlock(100, "Hello, world!"); + BOOST_CHECK_EQUAL(b.type(), 100); + BOOST_CHECK_GT(b.value_size(), 0); + BOOST_CHECK_EQUAL(readString(b), "Hello, world!"); +} + +BOOST_AUTO_TEST_CASE(Double) +{ + const double f = 0.25; + Block b = makeDoubleBlock(100, f); + BOOST_CHECK_EQUAL(b, "64083FD0000000000000"_block); + + EncodingEstimator estimator; + size_t totalLength = prependDoubleBlock(estimator, 100, f); + EncodingBuffer encoder(totalLength, 0); + prependDoubleBlock(encoder, 100, f); + BOOST_CHECK_EQUAL(encoder.block(), b); + + BOOST_CHECK_EQUAL(readDouble(b), f); + BOOST_CHECK_THROW(readDouble("4200"_block), tlv::Error); + BOOST_CHECK_THROW(readDouble("64043E800000"_block), tlv::Error); +} + +BOOST_AUTO_TEST_CASE(Data) +{ + std::string buf1{1, 1, 1, 1}; + const uint8_t buf2[]{1, 1, 1, 1}; + std::list buf3{1, 1, 1, 1}; + + Block b1 = makeBinaryBlock(100, buf1.data(), buf1.size()); + Block b2 = makeBinaryBlock(100, buf2, sizeof(buf2)); + Block b3 = makeBinaryBlock(100, buf1.begin(), buf1.end()); // fast encoding (random access iterator) + Block b4 = makeBinaryBlock(100, buf3.begin(), buf3.end()); // slow encoding (general iterator) + + BOOST_CHECK_EQUAL(b1, b2); + BOOST_CHECK_EQUAL(b1, b3); + BOOST_CHECK_EQUAL(b1.type(), 100); + BOOST_CHECK_EQUAL(b1.value_size(), buf1.size()); + BOOST_CHECK_EQUAL_COLLECTIONS(b1.value_begin(), b1.value_end(), buf2, buf2 + sizeof(buf2)); +} + +BOOST_AUTO_TEST_CASE(Nested) +{ + Name name("ndn:/Hello/World!"); + Block b1 = makeNestedBlock(100, name); + + BOOST_CHECK_EQUAL(b1.type(), 100); + b1.parse(); + BOOST_CHECK_EQUAL(b1.elements().size(), 1); + BOOST_CHECK_EQUAL(b1.elements().begin()->type(), name.wireEncode().type()); + BOOST_CHECK_EQUAL(*b1.elements().begin(), name.wireEncode()); +} + +BOOST_AUTO_TEST_SUITE_END() // TestBlockHelpers +BOOST_AUTO_TEST_SUITE_END() // Encoding + +} // namespace tests +} // namespace encoding +} // namespace ndn diff --git a/tests/unit/encoding/block.t.cpp b/tests/unit/encoding/block.t.cpp new file mode 100644 index 000000000..f6b245e16 --- /dev/null +++ b/tests/unit/encoding/block.t.cpp @@ -0,0 +1,694 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/encoding/block.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" + +#include "tests/boost-test.hpp" + +#include +#include + +#include +#include + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Encoding) +BOOST_AUTO_TEST_SUITE(TestBlock) + +BOOST_AUTO_TEST_SUITE(Construction) + +static const uint8_t TEST_BUFFER[] = { + 0x42, 0x01, 0xfa, + 0x01, 0x01, 0xfb, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, // bug #4726 +}; + +BOOST_AUTO_TEST_CASE(Default) +{ + Block b; + + BOOST_CHECK_EQUAL(b.isValid(), false); + BOOST_CHECK_EQUAL(b.empty(), true); + BOOST_CHECK_EQUAL(b.type(), tlv::Invalid); + BOOST_CHECK_EQUAL(b.hasValue(), false); + BOOST_CHECK_EQUAL(b.value_size(), 0); + BOOST_CHECK(b.value() == nullptr); + + BOOST_CHECK_THROW(b.size(), Block::Error); + BOOST_CHECK_THROW(b.begin(), Block::Error); + BOOST_CHECK_THROW(b.end(), Block::Error); + BOOST_CHECK_THROW(b.wire(), Block::Error); + BOOST_CHECK_THROW(b.blockFromValue(), Block::Error); +} + +BOOST_AUTO_TEST_CASE(FromEncodingBuffer) +{ + EncodingBuffer encoder; + BOOST_CHECK_THROW(Block{encoder}, tlv::Error); + + const uint8_t VALUE[] = {0x11, 0x12, 0x13, 0x14}; + size_t length = encoder.prependByteArray(VALUE, sizeof(VALUE)); + encoder.prependVarNumber(length); + encoder.prependVarNumber(0xe0); + + Block b = encoder.block(); + BOOST_CHECK_EQUAL(b.type(), 0xe0); + BOOST_CHECK_EQUAL(b.value_size(), sizeof(VALUE)); + BOOST_CHECK_EQUAL_COLLECTIONS(b.value_begin(), b.value_end(), + VALUE, VALUE + sizeof(VALUE)); + + b = Block(encoder); + BOOST_CHECK_EQUAL(b.type(), 0xe0); + BOOST_CHECK_EQUAL(b.value_size(), sizeof(VALUE)); + BOOST_CHECK_EQUAL_COLLECTIONS(b.value_begin(), b.value_end(), + VALUE, VALUE + sizeof(VALUE)); +} + +BOOST_AUTO_TEST_CASE(FromBlock) +{ + const uint8_t BUFFER[] = {0x80, 0x06, 0x81, 0x01, 0x01, 0x82, 0x01, 0x01}; + Block block(BUFFER, sizeof(BUFFER)); + + Block derivedBlock(block, block.begin(), block.end()); + BOOST_CHECK_EQUAL(derivedBlock.wire(), block.wire()); // pointers should match + BOOST_CHECK(derivedBlock == block); // blocks should match + + derivedBlock = Block(block, block.begin() + 2, block.begin() + 5); + BOOST_CHECK(derivedBlock.begin() == block.begin() + 2); + BOOST_CHECK(derivedBlock == Block(BUFFER + 2, 3)); + + Buffer otherBuffer(BUFFER, sizeof(BUFFER)); + BOOST_CHECK_THROW(Block(block, otherBuffer.begin(), block.end()), std::invalid_argument); + BOOST_CHECK_THROW(Block(block, block.begin(), otherBuffer.end()), std::invalid_argument); + BOOST_CHECK_THROW(Block(block, otherBuffer.begin(), otherBuffer.end()), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(FromBlockCopyOnWriteModifyOriginal) +{ + const uint8_t BUFFER[] = { + 0x05, 0x0b, 0x07, 0x03, 0x01, 0x02, 0x03, 0x0a, 0x04, 0x04, 0x05, 0x06, 0x07, + }; + + Block b1(BUFFER, sizeof(BUFFER)); + + Block b2(b1, b1.begin(), b1.end()); + auto buf2 = b2.getBuffer(); + + b1.parse(); + b1.remove(tlv::Name); + b1.encode(); + + b2.parse(); + + BOOST_CHECK_EQUAL_COLLECTIONS(b2.begin(), b2.end(), BUFFER, BUFFER + sizeof(BUFFER)); + BOOST_CHECK_EQUAL(buf2, b2.getBuffer()); +} + +BOOST_AUTO_TEST_CASE(FromBlockCopyOnWriteModifyCopy) +{ + const uint8_t BUFFER[] = { + 0x05, 0x0b, 0x07, 0x03, 0x01, 0x02, 0x03, 0x0a, 0x04, 0x04, 0x05, 0x06, 0x07, + }; + + Block b1(BUFFER, sizeof(BUFFER)); + auto buf1 = b1.getBuffer(); + + Block b2(b1, b1.begin(), b1.end()); + + b2.parse(); + b2.remove(tlv::Name); + b2.encode(); + + b1.parse(); + BOOST_CHECK_EQUAL_COLLECTIONS(b1.begin(), b1.end(), BUFFER, BUFFER + sizeof(BUFFER)); + BOOST_CHECK_EQUAL(buf1, b1.getBuffer()); +} + +BOOST_AUTO_TEST_CASE(FromType) +{ + Block b1(4); + BOOST_CHECK_EQUAL(b1.isValid(), true); + BOOST_CHECK_EQUAL(b1.type(), 4); + BOOST_CHECK_EQUAL(b1.size(), 2); // 1-octet TLV-TYPE and 1-octet TLV-LENGTH + BOOST_CHECK_EQUAL(b1.hasValue(), false); + BOOST_CHECK_EQUAL(b1.value_size(), 0); + + Block b2(258); + BOOST_CHECK_EQUAL(b2.isValid(), true); + BOOST_CHECK_EQUAL(b2.type(), 258); + BOOST_CHECK_EQUAL(b2.size(), 4); // 3-octet TLV-TYPE and 1-octet TLV-LENGTH + BOOST_CHECK_EQUAL(b2.hasValue(), false); + BOOST_CHECK_EQUAL(b2.value_size(), 0); + + Block b3(tlv::Invalid); + BOOST_CHECK_EQUAL(b3.isValid(), false); + BOOST_CHECK_EQUAL(b3.type(), tlv::Invalid); + BOOST_CHECK_EQUAL(b3.hasValue(), false); + BOOST_CHECK_EQUAL(b3.value_size(), 0); + BOOST_CHECK(b3.value() == nullptr); +} + +BOOST_AUTO_TEST_CASE(FromTypeAndBuffer) +{ + const uint8_t VALUE[] = {0x11, 0x12, 0x13, 0x14}; + auto bufferPtr = make_shared(VALUE, sizeof(VALUE)); + + Block b(42, bufferPtr); + BOOST_CHECK_EQUAL(b.isValid(), true); + BOOST_CHECK_EQUAL(b.type(), 42); + BOOST_CHECK_EQUAL(b.size(), 6); + BOOST_CHECK_EQUAL(b.hasValue(), true); + BOOST_CHECK_EQUAL(b.value_size(), sizeof(VALUE)); +} + +BOOST_AUTO_TEST_CASE(FromTypeAndBlock) +{ + const uint8_t BUFFER[] = {0x80, 0x06, 0x81, 0x01, 0x01, 0x82, 0x01, 0x01}; + Block nested(BUFFER, sizeof(BUFFER)); + + Block b(84, nested); + BOOST_CHECK_EQUAL(b.isValid(), true); + BOOST_CHECK_EQUAL(b.type(), 84); + BOOST_CHECK_EQUAL(b.size(), 10); + BOOST_CHECK_EQUAL(b.hasValue(), true); + BOOST_CHECK_EQUAL(b.value_size(), sizeof(BUFFER)); +} + +BOOST_AUTO_TEST_CASE(FromStream) +{ + std::stringstream stream; + stream.write(reinterpret_cast(TEST_BUFFER), sizeof(TEST_BUFFER)); + stream.seekg(0); + + Block b = Block::fromStream(stream); + BOOST_CHECK_EQUAL(b.type(), 66); + BOOST_CHECK_EQUAL(b.size(), 3); + BOOST_CHECK_EQUAL(b.value_size(), 1); + BOOST_CHECK_EQUAL(*b.wire(), 0x42); + BOOST_CHECK_EQUAL(*b.value(), 0xfa); + + b = Block::fromStream(stream); + BOOST_CHECK_EQUAL(b.type(), 1); + BOOST_CHECK_EQUAL(b.size(), 3); + BOOST_CHECK_EQUAL(b.value_size(), 1); + BOOST_CHECK_EQUAL(*b.wire(), 0x01); + BOOST_CHECK_EQUAL(*b.value(), 0xfb); + + b = Block::fromStream(stream); + BOOST_CHECK_EQUAL(b.type(), 0xffffffff); + BOOST_CHECK_EQUAL(b.size(), 6); + BOOST_CHECK_EQUAL(b.value_size(), 0); + BOOST_CHECK_EQUAL(*b.wire(), 0xfe); + + BOOST_CHECK(stream.eof()); + BOOST_CHECK_THROW(Block::fromStream(stream), tlv::Error); +} + +BOOST_AUTO_TEST_CASE(FromStreamWhitespace) // Bug 2728 +{ + const uint8_t PACKET[] = { + 0x06, 0x20, // Data + 0x07, 0x11, // Name + 0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, // GenericNameComponent 'hello' + 0x08, 0x01, 0x31, // GenericNameComponent '1' + 0x08, 0x05, 0x77, 0x6f, 0x72, 0x6c, 0x64, // GenericNameComponent 'world' + 0x14, 0x00, // MetaInfo empty + 0x15, 0x00, // Content empty + 0x16, 0x05, // SignatureInfo + 0x1b, 0x01, 0x01, // SignatureType RSA + 0x1c, 0x00, // KeyLocator empty + 0x17, 0x00 // SignatureValue empty + }; + // TLV-LENGTH of is 0x20 which happens to be ASCII whitespace + + std::stringstream stream; + stream.write(reinterpret_cast(PACKET), sizeof(PACKET)); + stream.seekg(0); + + Block b = Block::fromStream(stream); + BOOST_CHECK_EQUAL(b.type(), 6); + BOOST_CHECK_EQUAL(b.value_size(), 32); + b.parse(); + BOOST_CHECK_EQUAL(b.elements_size(), 5); +} + +BOOST_AUTO_TEST_CASE(FromStreamZeroLength) +{ + const uint8_t BUFFER[] = {0x70, 0x00, + 0x71, 0x03, 0x86, 0x11, 0x24, + 0x72, 0x00}; + + std::stringstream stream; + stream.write(reinterpret_cast(BUFFER), sizeof(BUFFER)); + stream.seekg(0); + + Block b1 = Block::fromStream(stream); + BOOST_CHECK_EQUAL(b1.type(), 0x70); + BOOST_CHECK_EQUAL(b1.value_size(), 0); + + Block b2 = Block::fromStream(stream); + BOOST_CHECK_EQUAL(b2.type(), 0x71); + BOOST_CHECK_EQUAL(b2.value_size(), 3); + const uint8_t EXPECTED_VALUE2[] = {0x86, 0x11, 0x24}; + BOOST_CHECK_EQUAL_COLLECTIONS(b2.value_begin(), b2.value_end(), + EXPECTED_VALUE2, EXPECTED_VALUE2 + sizeof(EXPECTED_VALUE2)); + + Block b3 = Block::fromStream(stream); + BOOST_CHECK_EQUAL(b3.type(), 0x72); + BOOST_CHECK_EQUAL(b3.value_size(), 0); + + BOOST_CHECK_THROW(Block::fromStream(stream), tlv::Error); +} + +BOOST_AUTO_TEST_CASE(FromStreamPacketTooLarge) +{ + const uint8_t BUFFER[] = {0x07, 0xfe, 0x00, 0x01, 0x00, 0x00}; + + std::stringstream stream; + stream.write(reinterpret_cast(BUFFER), sizeof(BUFFER)); + for (int i = 0; i < 0x10000; ++i) { + stream.put('\0'); + } + stream.seekg(0); + + BOOST_CHECK_THROW(Block::fromStream(stream), tlv::Error); +} + +BOOST_AUTO_TEST_CASE(FromWireBuffer) +{ + auto buffer = make_shared(TEST_BUFFER, sizeof(TEST_BUFFER)); + + size_t offset = 0; + bool isOk = false; + Block b; + std::tie(isOk, b) = Block::fromBuffer(buffer, offset); + BOOST_CHECK(isOk); + BOOST_CHECK_EQUAL(b.type(), 66); + BOOST_CHECK_EQUAL(b.size(), 3); + BOOST_CHECK_EQUAL(b.value_size(), 1); + BOOST_CHECK_EQUAL(*b.wire(), 0x42); + BOOST_CHECK_EQUAL(*b.value(), 0xfa); + offset += b.size(); + + std::tie(isOk, b) = Block::fromBuffer(buffer, offset); + BOOST_CHECK(isOk); + BOOST_CHECK_EQUAL(b.type(), 1); + BOOST_CHECK_EQUAL(b.size(), 3); + BOOST_CHECK_EQUAL(b.value_size(), 1); + BOOST_CHECK_EQUAL(*b.wire(), 0x01); + BOOST_CHECK_EQUAL(*b.value(), 0xfb); + offset += b.size(); + + std::tie(isOk, b) = Block::fromBuffer(buffer, offset); + BOOST_CHECK(isOk); + BOOST_CHECK_EQUAL(b.type(), 0xffffffff); + BOOST_CHECK_EQUAL(b.size(), 6); + BOOST_CHECK_EQUAL(b.value_size(), 0); + BOOST_CHECK_EQUAL(*b.wire(), 0xfe); +} + +BOOST_AUTO_TEST_CASE(FromRawBuffer) +{ + size_t offset = 0; + bool isOk = false; + Block b; + std::tie(isOk, b) = Block::fromBuffer(TEST_BUFFER + offset, sizeof(TEST_BUFFER) - offset); + BOOST_CHECK(isOk); + BOOST_CHECK_EQUAL(b.type(), 66); + BOOST_CHECK_EQUAL(b.size(), 3); + BOOST_CHECK_EQUAL(b.value_size(), 1); + BOOST_CHECK_EQUAL(*b.wire(), 0x42); + BOOST_CHECK_EQUAL(*b.value(), 0xfa); + offset += b.size(); + + std::tie(isOk, b) = Block::fromBuffer(TEST_BUFFER + offset, sizeof(TEST_BUFFER) - offset); + BOOST_CHECK(isOk); + BOOST_CHECK_EQUAL(b.type(), 1); + BOOST_CHECK_EQUAL(b.size(), 3); + BOOST_CHECK_EQUAL(b.value_size(), 1); + BOOST_CHECK_EQUAL(*b.wire(), 0x01); + BOOST_CHECK_EQUAL(*b.value(), 0xfb); + offset += b.size(); + + std::tie(isOk, b) = Block::fromBuffer(TEST_BUFFER + offset, sizeof(TEST_BUFFER) - offset); + BOOST_CHECK(isOk); + BOOST_CHECK_EQUAL(b.type(), 0xffffffff); + BOOST_CHECK_EQUAL(b.size(), 6); + BOOST_CHECK_EQUAL(b.value_size(), 0); + BOOST_CHECK_EQUAL(*b.wire(), 0xfe); +} + +template +struct MalformedInput +{ + static const std::vector INPUT; +}; + +template<> +const std::vector MalformedInput::INPUT{ + 0x00, 0x00 +}; +template<> +const std::vector MalformedInput::INPUT{ + 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +template<> +const std::vector MalformedInput::INPUT{ + 0x01, 0xff, 0x42, 0x42 +}; +template<> +const std::vector MalformedInput::INPUT{ + 0x01, 0x02, 0x03 +}; + +using MalformedInputs = boost::mpl::vector< + MalformedInput, + MalformedInput, + MalformedInput, + MalformedInput +>; + +BOOST_AUTO_TEST_CASE_TEMPLATE(Malformed, T, MalformedInputs) +{ + // constructor from raw buffer + BOOST_CHECK_THROW(Block(T::INPUT.data(), T::INPUT.size()), tlv::Error); + + // fromStream() + std::stringstream stream; + stream.write(reinterpret_cast(T::INPUT.data()), T::INPUT.size()); + stream.seekg(0); + BOOST_CHECK_THROW(Block::fromStream(stream), tlv::Error); + + // fromBuffer(), ConstBufferPtr overload + auto buf = make_shared(T::INPUT.begin(), T::INPUT.end()); + bool isOk; + Block b; + std::tie(isOk, b) = Block::fromBuffer(buf, 0); + BOOST_CHECK(!isOk); + BOOST_CHECK(!b.isValid()); + + // fromBuffer(), raw buffer overload + std::tie(isOk, b) = Block::fromBuffer(T::INPUT.data(), T::INPUT.size()); + BOOST_CHECK(!isOk); + BOOST_CHECK(!b.isValid()); +} + +BOOST_AUTO_TEST_SUITE_END() // Construction + +BOOST_AUTO_TEST_SUITE(SubElements) + +BOOST_AUTO_TEST_CASE(Parse) +{ + const uint8_t PACKET[] = { + 0x06, 0x20, // Data + 0x07, 0x11, // Name + 0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, // GenericNameComponent 'hello' + 0x08, 0x01, 0x31, // GenericNameComponent '1' + 0x08, 0x05, 0x77, 0x6f, 0x72, 0x6c, 0x64, // GenericNameComponent 'world' + 0x14, 0x00, // MetaInfo empty + 0x15, 0x00, // Content empty + 0x16, 0x05, // SignatureInfo + 0x1b, 0x01, 0x01, // SignatureType RSA + 0x1c, 0x00, // KeyLocator empty + 0x17, 0x00 // SignatureValue empty + }; + Block data(PACKET, sizeof(PACKET)); + data.parse(); + + BOOST_CHECK_EQUAL(data.elements_size(), 5); + BOOST_CHECK_EQUAL(data.elements().at(0).type(), 0x07); + BOOST_CHECK_EQUAL(data.elements().at(0).elements().size(), 0); // parse is not recursive + + BOOST_CHECK(data.get(0x15) == data.elements().at(2)); + BOOST_CHECK_THROW(data.get(0x01), Block::Error); + + BOOST_CHECK(data.find(0x15) == data.elements_begin() + 2); + BOOST_CHECK(data.find(0x01) == data.elements_end()); + + const uint8_t MALFORMED[] = { + // TLV-LENGTH of nested element is greater than TLV-LENGTH of enclosing element + 0x05, 0x05, 0x07, 0x07, 0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f + }; + Block bad(MALFORMED, sizeof(MALFORMED)); + BOOST_CHECK_THROW(bad.parse(), Block::Error); +} + +BOOST_AUTO_TEST_CASE(InsertBeginning) +{ + Block masterBlock(tlv::Name); + Block firstBlock = makeStringBlock(tlv::GenericNameComponent, "firstName"); + Block secondBlock = makeStringBlock(tlv::GenericNameComponent, "secondName"); + Block thirdBlock = makeStringBlock(tlv::GenericNameComponent, "thirdName"); + + BOOST_CHECK_EQUAL(masterBlock.elements_size(), 0); + masterBlock.push_back(secondBlock); + masterBlock.push_back(thirdBlock); + BOOST_CHECK_EQUAL(masterBlock.elements_size(), 2); + Block::element_const_iterator it = masterBlock.find(tlv::GenericNameComponent); + BOOST_CHECK_EQUAL(*it == secondBlock, true); + + it = masterBlock.insert(it, firstBlock); + + BOOST_CHECK_EQUAL(masterBlock.elements_size(), 3); + BOOST_CHECK_EQUAL(*(it + 1) == secondBlock, true); + BOOST_CHECK_EQUAL(*(masterBlock.elements_begin()) == firstBlock, true); +} + +BOOST_AUTO_TEST_CASE(InsertEnd) +{ + Block masterBlock(tlv::Name); + Block firstBlock = makeStringBlock(tlv::GenericNameComponent, "firstName"); + Block secondBlock = makeStringBlock(tlv::GenericNameComponent, "secondName"); + Block thirdBlock = makeStringBlock(tlv::GenericNameComponent, "thirdName"); + + BOOST_CHECK_EQUAL(masterBlock.elements_size(), 0); + masterBlock.push_back(firstBlock); + masterBlock.push_back(secondBlock); + BOOST_CHECK_EQUAL(masterBlock.elements_size(), 2); + Block::element_const_iterator it = masterBlock.elements_end(); + BOOST_CHECK_EQUAL(*(it - 1) == secondBlock, true); + + it = masterBlock.insert(it, thirdBlock); + + BOOST_CHECK_EQUAL(masterBlock.elements_size(), 3); + BOOST_CHECK_EQUAL(*(it - 1) == secondBlock, true); + BOOST_CHECK_EQUAL(*(masterBlock.elements_end() - 1) == thirdBlock, true); +} + +BOOST_AUTO_TEST_CASE(InsertMiddle) +{ + Block masterBlock(tlv::Name); + Block firstBlock = makeStringBlock(tlv::GenericNameComponent, "firstName"); + Block secondBlock = makeStringBlock(tlv::GenericNameComponent, "secondName"); + Block thirdBlock = makeStringBlock(tlv::GenericNameComponent, "thirdName"); + + BOOST_CHECK_EQUAL(masterBlock.elements_size(), 0); + masterBlock.push_back(firstBlock); + masterBlock.push_back(thirdBlock); + BOOST_CHECK_EQUAL(masterBlock.elements_size(), 2); + Block::element_const_iterator it = masterBlock.find(tlv::GenericNameComponent); + BOOST_CHECK_EQUAL(*it == firstBlock, true); + + it = masterBlock.insert(it + 1, secondBlock); + + BOOST_CHECK_EQUAL(*it == secondBlock, true); + BOOST_CHECK_EQUAL(*(it + 1) == thirdBlock, true); + BOOST_CHECK_EQUAL(*(it - 1) == firstBlock, true); +} + +BOOST_AUTO_TEST_CASE(EraseSingleElement) +{ + Block masterBlock(tlv::Name); + Block firstBlock = makeStringBlock(tlv::GenericNameComponent, "firstName"); + Block secondBlock = makeStringBlock(tlv::GenericNameComponent, "secondName"); + Block thirdBlock = makeStringBlock(tlv::GenericNameComponent, "thirdName"); + + BOOST_CHECK_EQUAL(masterBlock.elements_size(), 0); + masterBlock.push_back(firstBlock); + masterBlock.push_back(secondBlock); + masterBlock.push_back(thirdBlock); + BOOST_CHECK_EQUAL(masterBlock.elements_size(), 3); + Block::element_const_iterator it = masterBlock.find(tlv::GenericNameComponent); + it++; + BOOST_CHECK_EQUAL(*it == secondBlock, true); + + it = masterBlock.erase(it); + + BOOST_CHECK_EQUAL(masterBlock.elements_size(), 2); + BOOST_CHECK_EQUAL(*(it) == thirdBlock, true); + BOOST_CHECK_EQUAL(*(it - 1) == firstBlock, true); +} + +BOOST_AUTO_TEST_CASE(EraseRange) +{ + Block masterBlock(tlv::Name); + Block firstBlock = makeStringBlock(tlv::GenericNameComponent, "firstName"); + Block secondBlock = makeStringBlock(tlv::GenericNameComponent, "secondName"); + Block thirdBlock = makeStringBlock(tlv::GenericNameComponent, "thirdName"); + Block fourthBlock = makeStringBlock(tlv::GenericNameComponent, "fourthName"); + Block fifthBlock = makeStringBlock(tlv::GenericNameComponent, "fifthName"); + Block sixthBlock = makeStringBlock(tlv::GenericNameComponent, "sixthName"); + + BOOST_CHECK_EQUAL(masterBlock.elements_size(), 0); + masterBlock.push_back(firstBlock); + masterBlock.push_back(secondBlock); + masterBlock.push_back(thirdBlock); + masterBlock.push_back(fourthBlock); + masterBlock.push_back(fifthBlock); + masterBlock.push_back(sixthBlock); + BOOST_CHECK_EQUAL(masterBlock.elements_size(), 6); + Block::element_const_iterator itStart = masterBlock.find(tlv::GenericNameComponent); + itStart++; + Block::element_const_iterator itEnd = itStart + 3; + BOOST_CHECK_EQUAL(*itStart == secondBlock, true); + BOOST_CHECK_EQUAL(*itEnd == fifthBlock, true); + + Block::element_const_iterator newIt = masterBlock.erase(itStart, itEnd); + + BOOST_CHECK_EQUAL(masterBlock.elements_size(), 3); + BOOST_CHECK_EQUAL(*(newIt) == fifthBlock, true); + BOOST_CHECK_EQUAL(*(newIt - 1) == firstBlock, true); +} + +BOOST_AUTO_TEST_CASE(Remove) +{ + Block block(tlv::Data); + block.push_back(makeNonNegativeIntegerBlock(tlv::ContentType, 0)); + block.push_back(makeNonNegativeIntegerBlock(tlv::FreshnessPeriod, 123)); + block.push_back(makeStringBlock(tlv::Name, "ndn:/test-prefix")); + block.push_back(makeNonNegativeIntegerBlock(tlv::ContentType, 2)); + block.push_back(makeNonNegativeIntegerBlock(tlv::ContentType, 1)); + + BOOST_CHECK_EQUAL(5, block.elements_size()); + BOOST_CHECK_NO_THROW(block.remove(tlv::ContentType)); + BOOST_REQUIRE_EQUAL(2, block.elements_size()); + + auto elements = block.elements(); + BOOST_CHECK_EQUAL(tlv::FreshnessPeriod, elements[0].type()); + BOOST_CHECK_EQUAL(123, readNonNegativeInteger(elements[0])); + BOOST_CHECK_EQUAL(tlv::Name, elements[1].type()); + BOOST_CHECK_EQUAL(readString(elements[1]).compare("ndn:/test-prefix"), 0); +} + +BOOST_AUTO_TEST_SUITE_END() // SubElements + +BOOST_AUTO_TEST_CASE(Equality) +{ + const uint8_t one[] = {0x08, 0x00}; + Block a(one, sizeof(one)); + Block b(one, sizeof(one)); + BOOST_CHECK_EQUAL(a == b, true); + BOOST_CHECK_EQUAL(a != b, false); + + const uint8_t two[] = {0x06, 0x00}; + Block c(two, sizeof(two)); + Block d(one, sizeof(one)); + BOOST_CHECK_EQUAL(c == d, false); + BOOST_CHECK_EQUAL(c != d, true); + + const uint8_t three[] = {0x06, 0x01, 0xcc}; + Block e(two, sizeof(two)); + Block f(three, sizeof(three)); + BOOST_CHECK_EQUAL(e == f, false); + BOOST_CHECK_EQUAL(e != f, true); +} + +BOOST_AUTO_TEST_CASE(Print) +{ + // default constructed + Block b; + BOOST_CHECK_EQUAL(boost::lexical_cast(b), "[invalid]"); + + // zero length + b = "0700"_block; + BOOST_CHECK_EQUAL(boost::lexical_cast(b), "7[empty]"); + + // unparsed + b = "0E10FF7E4E6B3B21C902660F16ED589FCCCC"_block; + BOOST_CHECK_EQUAL(boost::lexical_cast(b), + "14[16]=FF7E4E6B3B21C902660F16ED589FCCCC"); + // set and restore format flags + { + std::ostringstream oss; + oss << std::showbase << std::hex << 0xd23c4 << b << 0x4981e; + BOOST_CHECK_EQUAL(oss.str(), "0xd23c414[16]=FF7E4E6B3B21C902660F16ED589FCCCC0x4981e"); + } + + // parsed + b = "FD010808 0502CADD 59024E42"_block; + b.parse(); + BOOST_CHECK_EQUAL(boost::lexical_cast(b), + "264[8]={5[2]=CADD,89[2]=4E42}"); + + // parsed then modified: print modified sub-elements + b = "FD010808 0502CADD 59024E42"_block; + b.parse(); + b.erase(b.elements_begin()); + b.push_back("10022386"_block); + BOOST_CHECK_EQUAL(boost::lexical_cast(b), + "264[8]={89[2]=4E42,16[2]=2386}"); +} + +BOOST_AUTO_TEST_SUITE(BlockLiteral) + +BOOST_AUTO_TEST_CASE(Simple) +{ + Block b0 = "4200"_block; + BOOST_CHECK_EQUAL(b0.type(), 0x42); + BOOST_CHECK_EQUAL(b0.value_size(), 0); + + Block b1 = "0101A0"_block; + BOOST_CHECK_EQUAL(b1.type(), 0x01); + BOOST_REQUIRE_EQUAL(b1.value_size(), 1); + BOOST_CHECK_EQUAL(b1.value()[0], 0xA0); +} + +BOOST_AUTO_TEST_CASE(Comment) +{ + Block b0 = "a2b0c0d2eBf0G.B 1+"_block; + BOOST_CHECK_EQUAL(b0.type(), 0x20); + BOOST_REQUIRE_EQUAL(b0.value_size(), 2); + BOOST_CHECK_EQUAL(b0.value()[0], 0xB0); + BOOST_CHECK_EQUAL(b0.value()[1], 0xB1); +} + +BOOST_AUTO_TEST_CASE(BadInput) +{ + BOOST_CHECK_THROW(""_block, std::invalid_argument); + BOOST_CHECK_THROW("1"_block, std::invalid_argument); + BOOST_CHECK_THROW("333"_block, std::invalid_argument); + BOOST_CHECK_THROW("xx yy zz"_block, std::invalid_argument); // only comments + + BOOST_CHECK_THROW("0000"_block, tlv::Error); // invalid type + BOOST_CHECK_THROW("0202C0"_block, tlv::Error); // truncated value + BOOST_CHECK_THROW("0201C0C1"_block, tlv::Error); // trailing garbage +} + +BOOST_AUTO_TEST_SUITE_END() // BlockLiteral + +BOOST_AUTO_TEST_SUITE_END() // TestBlock +BOOST_AUTO_TEST_SUITE_END() // Encoding + +} // namespace tests +} // namespace ndn diff --git a/tests/unit-tests/encoding/buffer-stream.t.cpp b/tests/unit/encoding/buffer-stream.t.cpp similarity index 93% rename from tests/unit-tests/encoding/buffer-stream.t.cpp rename to tests/unit/encoding/buffer-stream.t.cpp index 9c712ea4d..9418f8ccf 100644 --- a/tests/unit-tests/encoding/buffer-stream.t.cpp +++ b/tests/unit/encoding/buffer-stream.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,9 +19,9 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "encoding/buffer-stream.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace tests { diff --git a/tests/unit-tests/encoding/encoder.t.cpp b/tests/unit/encoding/encoder.t.cpp similarity index 97% rename from tests/unit-tests/encoding/encoder.t.cpp rename to tests/unit/encoding/encoder.t.cpp index 25344196b..3f5fe8eea 100644 --- a/tests/unit-tests/encoding/encoder.t.cpp +++ b/tests/unit/encoding/encoder.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,9 +19,9 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "encoding/encoder.hpp" +#include "ndn-cxx/encoding/encoder.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace encoding { diff --git a/tests/unit/encoding/encoding-buffer.t.cpp b/tests/unit/encoding/encoding-buffer.t.cpp new file mode 100644 index 000000000..c0997b428 --- /dev/null +++ b/tests/unit/encoding/encoding-buffer.t.cpp @@ -0,0 +1,202 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/encoding/encoding-buffer.hpp" +#include "ndn-cxx/encoding/block.hpp" + +#include "tests/boost-test.hpp" + +namespace ndn { +namespace tests { + +class BufferEstimatorFixture +{ +public: + EncodingBuffer buffer; + EncodingEstimator estimator; +}; + +BOOST_AUTO_TEST_SUITE(Encoding) +BOOST_AUTO_TEST_SUITE(TestEncodingBuffer) + +BOOST_AUTO_TEST_CASE(ConstructFromBlock) +{ + auto buf = make_shared(10); + Block block(0xab, buf); + block.encode(); + + { + EncodingBuffer buffer(block); + BOOST_CHECK_EQUAL(buffer.size(), 12); + BOOST_CHECK_EQUAL(buffer.capacity(), 12); + } + + (*buf)[1] = 0xe0; + (*buf)[2] = 2; + block = Block(buf, buf->begin() + 1, buf->begin() + 5); + BOOST_CHECK_EQUAL(block.type(), 0xe0); + + { + EncodingBuffer buffer(block); + BOOST_CHECK_EQUAL(buffer.size(), 4); + BOOST_CHECK_EQUAL(buffer.capacity(), 10); + } +} + +BOOST_FIXTURE_TEST_SUITE(PrependVarNumber, BufferEstimatorFixture) + +BOOST_AUTO_TEST_CASE(OneByte1) +{ + size_t s1 = buffer.prependVarNumber(252); + size_t s2 = estimator.prependVarNumber(252); + BOOST_CHECK_EQUAL(buffer.size(), 1); + BOOST_CHECK_EQUAL(s1, 1); + BOOST_CHECK_EQUAL(s2, 1); +} + +BOOST_AUTO_TEST_CASE(ThreeBytes1) +{ + size_t s1 = buffer.prependVarNumber(253); + size_t s2 = estimator.prependVarNumber(253); + BOOST_CHECK_EQUAL(buffer.size(), 3); + BOOST_CHECK_EQUAL(s1, 3); + BOOST_CHECK_EQUAL(s2, 3); +} + +BOOST_AUTO_TEST_CASE(ThreeBytes2) +{ + size_t s1 = buffer.prependVarNumber(255); + size_t s2 = estimator.prependVarNumber(255); + BOOST_CHECK_EQUAL(buffer.size(), 3); + BOOST_CHECK_EQUAL(s1, 3); + BOOST_CHECK_EQUAL(s2, 3); +} + +BOOST_AUTO_TEST_CASE(ThreeBytes3) +{ + size_t s1 = buffer.prependVarNumber(65535); + size_t s2 = estimator.prependVarNumber(65535); + BOOST_CHECK_EQUAL(buffer.size(), 3); + BOOST_CHECK_EQUAL(s1, 3); + BOOST_CHECK_EQUAL(s2, 3); +} + +BOOST_AUTO_TEST_CASE(FiveBytes1) +{ + size_t s1 = buffer.prependVarNumber(65536); + size_t s2 = estimator.prependVarNumber(65536); + BOOST_CHECK_EQUAL(buffer.size(), 5); + BOOST_CHECK_EQUAL(s1, 5); + BOOST_CHECK_EQUAL(s2, 5); +} + +BOOST_AUTO_TEST_CASE(FiveBytes2) +{ + size_t s1 = buffer.prependVarNumber(4294967295LL); + size_t s2 = estimator.prependVarNumber(4294967295LL); + BOOST_CHECK_EQUAL(buffer.size(), 5); + BOOST_CHECK_EQUAL(s1, 5); + BOOST_CHECK_EQUAL(s2, 5); +} + +BOOST_AUTO_TEST_CASE(NineBytes) +{ + size_t s1 = buffer.prependVarNumber(4294967296LL); + size_t s2 = estimator.prependVarNumber(4294967296LL); + BOOST_CHECK_EQUAL(buffer.size(), 9); + BOOST_CHECK_EQUAL(s1, 9); + BOOST_CHECK_EQUAL(s2, 9); +} + +BOOST_AUTO_TEST_SUITE_END() // PrependVarNumber + +BOOST_FIXTURE_TEST_SUITE(PrependNonNegativeNumber, BufferEstimatorFixture) + +BOOST_AUTO_TEST_CASE(NonNegativeNumberOneByte1) +{ + size_t s1 = buffer.prependNonNegativeInteger(252); + size_t s2 = estimator.prependNonNegativeInteger(252); + BOOST_CHECK_EQUAL(buffer.size(), 1); + BOOST_CHECK_EQUAL(s1, 1); + BOOST_CHECK_EQUAL(s2, 1); +} + +BOOST_AUTO_TEST_CASE(NonNegativeNumberOneByte2) +{ + size_t s1 = buffer.prependNonNegativeInteger(255); + size_t s2 = estimator.prependNonNegativeInteger(255); + BOOST_CHECK_EQUAL(buffer.size(), 1); + BOOST_CHECK_EQUAL(s1, 1); + BOOST_CHECK_EQUAL(s2, 1); +} + +BOOST_AUTO_TEST_CASE(NonNegativeNumberTwoBytes1) +{ + size_t s1 = buffer.prependNonNegativeInteger(256); + size_t s2 = estimator.prependNonNegativeInteger(256); + BOOST_CHECK_EQUAL(buffer.size(), 2); + BOOST_CHECK_EQUAL(s1, 2); + BOOST_CHECK_EQUAL(s2, 2); +} + +BOOST_AUTO_TEST_CASE(NonNegativeNumberTwoBytes2) +{ + size_t s1 = buffer.prependNonNegativeInteger(65535); + size_t s2 = estimator.prependNonNegativeInteger(65535); + BOOST_CHECK_EQUAL(buffer.size(), 2); + BOOST_CHECK_EQUAL(s1, 2); + BOOST_CHECK_EQUAL(s2, 2); +} + +BOOST_AUTO_TEST_CASE(NonNegativeNumberFourBytes1) +{ + size_t s1 = buffer.prependNonNegativeInteger(65536); + size_t s2 = estimator.prependNonNegativeInteger(65536); + BOOST_CHECK_EQUAL(buffer.size(), 4); + BOOST_CHECK_EQUAL(s1, 4); + BOOST_CHECK_EQUAL(s2, 4); +} + +BOOST_AUTO_TEST_CASE(NonNegativeNumberFourBytes2) +{ + size_t s1 = buffer.prependNonNegativeInteger(4294967295LL); + size_t s2 = estimator.prependNonNegativeInteger(4294967295LL); + BOOST_CHECK_EQUAL(buffer.size(), 4); + BOOST_CHECK_EQUAL(s1, 4); + BOOST_CHECK_EQUAL(s2, 4); +} + +BOOST_AUTO_TEST_CASE(NonNegativeNumberEightBytes) +{ + size_t s1 = buffer.prependNonNegativeInteger(4294967296LL); + size_t s2 = estimator.prependNonNegativeInteger(4294967296LL); + BOOST_CHECK_EQUAL(buffer.size(), 8); + BOOST_CHECK_EQUAL(s1, 8); + BOOST_CHECK_EQUAL(s2, 8); +} + +BOOST_AUTO_TEST_SUITE_END() // PrependNonNegativeNumber + +BOOST_AUTO_TEST_SUITE_END() // TestEncodingBuffer +BOOST_AUTO_TEST_SUITE_END() // Encoding + +} // namespace tests +} // namespace ndn diff --git a/tests/unit-tests/encoding/estimator.t.cpp b/tests/unit/encoding/estimator.t.cpp similarity index 86% rename from tests/unit-tests/encoding/estimator.t.cpp rename to tests/unit/encoding/estimator.t.cpp index 700ea9585..f5e4392a4 100644 --- a/tests/unit-tests/encoding/estimator.t.cpp +++ b/tests/unit/encoding/estimator.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,9 +19,9 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "encoding/estimator.hpp" +#include "ndn-cxx/encoding/estimator.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace encoding { @@ -33,23 +33,21 @@ BOOST_AUTO_TEST_SUITE(TestEstimator) BOOST_AUTO_TEST_CASE(Basic) { Estimator e; - Estimator e1(100); - Estimator e2(100, 100); BOOST_CHECK_EQUAL(e.prependByte(1), 1); BOOST_CHECK_EQUAL(e.appendByte(1), 1); uint8_t buf1[] = {'t', 'e', 's', 't', '1'}; - BOOST_CHECK_EQUAL(e1.prependByteArray(buf1, sizeof(buf1)), 5); - BOOST_CHECK_EQUAL(e1.appendByteArray(buf1, sizeof(buf1)), 5); + BOOST_CHECK_EQUAL(e.prependByteArray(buf1, sizeof(buf1)), 5); + BOOST_CHECK_EQUAL(e.appendByteArray(buf1, sizeof(buf1)), 5); std::vector buf2 = {'t', 'e', 's', 't', '2'}; - BOOST_CHECK_EQUAL(e1.prependRange(buf2.begin(), buf2.end()), 5); - BOOST_CHECK_EQUAL(e1.appendRange(buf2.begin(), buf2.end()), 5); + BOOST_CHECK_EQUAL(e.prependRange(buf2.begin(), buf2.end()), 5); + BOOST_CHECK_EQUAL(e.appendRange(buf2.begin(), buf2.end()), 5); std::list buf3 = {'t', 'e', 's', 't', '2'}; - BOOST_CHECK_EQUAL(e2.prependRange(buf3.begin(), buf3.end()), 5); - BOOST_CHECK_EQUAL(e2.appendRange(buf3.begin(), buf3.end()), 5); + BOOST_CHECK_EQUAL(e.prependRange(buf3.begin(), buf3.end()), 5); + BOOST_CHECK_EQUAL(e.appendRange(buf3.begin(), buf3.end()), 5); } BOOST_AUTO_TEST_CASE(Tlv) diff --git a/tests/unit/encoding/nfd-constants.t.cpp b/tests/unit/encoding/nfd-constants.t.cpp new file mode 100644 index 000000000..e87f39126 --- /dev/null +++ b/tests/unit/encoding/nfd-constants.t.cpp @@ -0,0 +1,143 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/encoding/nfd-constants.hpp" + +#include "tests/boost-test.hpp" + +#include +#include + +namespace ndn { +namespace nfd { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Encoding) +BOOST_AUTO_TEST_SUITE(TestNfdConstants) + +BOOST_AUTO_TEST_CASE(PrintFaceScope) +{ + BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_SCOPE_NONE), "none"); + BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_SCOPE_NON_LOCAL), "non-local"); + BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_SCOPE_LOCAL), "local"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(126)), "126"); +} + +BOOST_AUTO_TEST_CASE(PrintFacePersistency) +{ + BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_PERSISTENCY_NONE), "none"); + BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_PERSISTENCY_ON_DEMAND), "on-demand"); + BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_PERSISTENCY_PERSISTENT), "persistent"); + BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_PERSISTENCY_PERMANENT), "permanent"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(110)), "110"); +} + +BOOST_AUTO_TEST_CASE(PrintLinkType) +{ + BOOST_CHECK_EQUAL(boost::lexical_cast(LINK_TYPE_NONE), "none"); + BOOST_CHECK_EQUAL(boost::lexical_cast(LINK_TYPE_POINT_TO_POINT), "point-to-point"); + BOOST_CHECK_EQUAL(boost::lexical_cast(LINK_TYPE_MULTI_ACCESS), "multi-access"); + BOOST_CHECK_EQUAL(boost::lexical_cast(LINK_TYPE_AD_HOC), "adhoc"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(104)), "104"); +} + +BOOST_AUTO_TEST_CASE(PrintFaceEventKind) +{ + BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_EVENT_NONE), "none"); + BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_EVENT_CREATED), "created"); + BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_EVENT_DESTROYED), "destroyed"); + BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_EVENT_UP), "up"); + BOOST_CHECK_EQUAL(boost::lexical_cast(FACE_EVENT_DOWN), "down"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(175)), "175"); +} + +BOOST_AUTO_TEST_CASE(ParseRouteOrigin) +{ + auto expectSuccess = [] (const std::string& input, RouteOrigin expected) { + std::istringstream is(input); + RouteOrigin routeOrigin; + is >> routeOrigin; + + BOOST_TEST_MESSAGE("parsing " << input); + BOOST_CHECK_EQUAL(routeOrigin, expected); + }; + + auto expectFail = [] (const std::string& input) { + std::istringstream is(input); + RouteOrigin routeOrigin; + is >> routeOrigin; + + BOOST_TEST_MESSAGE("parsing " << input); + BOOST_CHECK(is.fail()); + BOOST_CHECK_EQUAL(routeOrigin, ROUTE_ORIGIN_NONE); + }; + + expectSuccess("none", ROUTE_ORIGIN_NONE); + expectSuccess("App", ROUTE_ORIGIN_APP); + expectSuccess("AutoReg", ROUTE_ORIGIN_AUTOREG); + expectSuccess("Client", ROUTE_ORIGIN_CLIENT); + expectSuccess("AutoConf", ROUTE_ORIGIN_AUTOCONF); + expectSuccess("NLSR", ROUTE_ORIGIN_NLSR); + expectSuccess("PrefixAnn", ROUTE_ORIGIN_PREFIXANN); + expectSuccess("static", ROUTE_ORIGIN_STATIC); + expectSuccess("27", static_cast(27)); + + expectSuccess(" app", ROUTE_ORIGIN_APP); + expectSuccess("app ", ROUTE_ORIGIN_APP); + expectSuccess(" app ", ROUTE_ORIGIN_APP); + + expectFail("unrecognized"); + expectFail("-1"); + expectFail("0.1"); + expectFail("65537"); + expectFail(""); +} + +BOOST_AUTO_TEST_CASE(PrintRouteOrigin) +{ + BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_ORIGIN_NONE), "none"); + BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_ORIGIN_APP), "app"); + BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_ORIGIN_AUTOREG), "autoreg"); + BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_ORIGIN_CLIENT), "client"); + BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_ORIGIN_AUTOCONF), "autoconf"); + BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_ORIGIN_NLSR), "nlsr"); + BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_ORIGIN_PREFIXANN), "prefixann"); + BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_ORIGIN_STATIC), "static"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(27)), "27"); +} + +BOOST_AUTO_TEST_CASE(PrintRouteFlags) +{ + BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_FLAGS_NONE), "none"); + BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_FLAG_CHILD_INHERIT), "child-inherit"); + BOOST_CHECK_EQUAL(boost::lexical_cast(ROUTE_FLAG_CAPTURE), "capture"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast( + ROUTE_FLAG_CHILD_INHERIT | ROUTE_FLAG_CAPTURE)), "child-inherit|capture"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast( + ROUTE_FLAG_CAPTURE | 0x9c)), "capture|0x9c"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestNfdConstants +BOOST_AUTO_TEST_SUITE_END() // Encoding + +} // namespace tests +} // namespace nfd +} // namespace ndn diff --git a/tests/unit/encoding/tlv.t.cpp b/tests/unit/encoding/tlv.t.cpp new file mode 100644 index 000000000..478fd8336 --- /dev/null +++ b/tests/unit/encoding/tlv.t.cpp @@ -0,0 +1,611 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/encoding/tlv.hpp" +#include "ndn-cxx/encoding/buffer.hpp" + +#include "tests/boost-test.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ndn { +namespace tlv { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Encoding) +BOOST_AUTO_TEST_SUITE(TestTlv) + +BOOST_AUTO_TEST_CASE(CriticalType) +{ + BOOST_CHECK_EQUAL(isCriticalType(0), true); + BOOST_CHECK_EQUAL(isCriticalType(1), true); + BOOST_CHECK_EQUAL(isCriticalType(2), true); + BOOST_CHECK_EQUAL(isCriticalType(30), true); + BOOST_CHECK_EQUAL(isCriticalType(31), true); + BOOST_CHECK_EQUAL(isCriticalType(32), false); + BOOST_CHECK_EQUAL(isCriticalType(33), true); + BOOST_CHECK_EQUAL(isCriticalType(34), false); + BOOST_CHECK_EQUAL(isCriticalType(10000), false); + BOOST_CHECK_EQUAL(isCriticalType(10001), true); +} + +using ArrayStream = boost::iostreams::stream; +using StreamIterator = std::istream_iterator; + +#define ASSERT_READ_NUMBER_IS_FAST(T) \ + static_assert(std::is_base_of, detail::ReadNumber>::value, \ + # T " should use ReadNumberFast") +#define ASSERT_READ_NUMBER_IS_SLOW(T) \ + static_assert(std::is_base_of, detail::ReadNumber>::value, \ + # T " should use ReadNumberSlow") + +ASSERT_READ_NUMBER_IS_FAST(const uint8_t*); +ASSERT_READ_NUMBER_IS_FAST(uint8_t*); +ASSERT_READ_NUMBER_IS_FAST(int8_t*); +ASSERT_READ_NUMBER_IS_FAST(char*); +ASSERT_READ_NUMBER_IS_FAST(unsigned char*); +ASSERT_READ_NUMBER_IS_FAST(signed char*); +ASSERT_READ_NUMBER_IS_FAST(const uint8_t[]); +ASSERT_READ_NUMBER_IS_FAST(uint8_t[]); +ASSERT_READ_NUMBER_IS_FAST(const uint8_t[12]); +ASSERT_READ_NUMBER_IS_FAST(uint8_t[12]); +using Uint8Array = std::array; +ASSERT_READ_NUMBER_IS_FAST(Uint8Array::const_iterator); +ASSERT_READ_NUMBER_IS_FAST(Uint8Array::iterator); +using CharArray = std::array; +ASSERT_READ_NUMBER_IS_FAST(CharArray::iterator); +ASSERT_READ_NUMBER_IS_FAST(std::string::const_iterator); +ASSERT_READ_NUMBER_IS_FAST(std::string::iterator); +ASSERT_READ_NUMBER_IS_FAST(Buffer::const_iterator); +ASSERT_READ_NUMBER_IS_FAST(Buffer::iterator); +ASSERT_READ_NUMBER_IS_FAST(std::vector::const_iterator); +ASSERT_READ_NUMBER_IS_FAST(std::vector::iterator); +ASSERT_READ_NUMBER_IS_FAST(std::vector::iterator); +ASSERT_READ_NUMBER_IS_FAST(std::vector::iterator); +ASSERT_READ_NUMBER_IS_FAST(std::vector::iterator); +ASSERT_READ_NUMBER_IS_FAST(std::vector::iterator); +ASSERT_READ_NUMBER_IS_SLOW(std::vector::iterator); +ASSERT_READ_NUMBER_IS_SLOW(std::vector::iterator); +ASSERT_READ_NUMBER_IS_SLOW(std::vector::iterator); +ASSERT_READ_NUMBER_IS_SLOW(std::vector::iterator); +ASSERT_READ_NUMBER_IS_SLOW(std::deque::iterator); +ASSERT_READ_NUMBER_IS_SLOW(std::list::iterator); +ASSERT_READ_NUMBER_IS_SLOW(StreamIterator); + +BOOST_AUTO_TEST_SUITE(VarNumber) + +// This check ensures readVarNumber and readType only require InputIterator concept and nothing +// more. This function should compile, but should never be executed. +void +checkArchetype() +{ + boost::input_iterator_archetype begin, end; + uint64_t number = readVarNumber(begin, end); + uint32_t type = readType(begin, end); + bool ok = readVarNumber(begin, end, number); + ok = readType(begin, end, type); + static_cast(ok); +} + +static const uint8_t BUFFER[] = { + 0x00, // == 0 + 0x01, // == 1 + 0xfc, // == 252 + 0xfd, 0x00, 0xfd, // == 253 + 0xfe, 0x00, 0x01, 0x00, 0x00, // == 65536 + 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 // == 4294967296 +}; + +BOOST_AUTO_TEST_CASE(SizeOf) +{ + BOOST_CHECK_EQUAL(sizeOfVarNumber(0), 1); + BOOST_CHECK_EQUAL(sizeOfVarNumber(1), 1); + BOOST_CHECK_EQUAL(sizeOfVarNumber(252), 1); + BOOST_CHECK_EQUAL(sizeOfVarNumber(253), 3); + BOOST_CHECK_EQUAL(sizeOfVarNumber(65536), 5); + BOOST_CHECK_EQUAL(sizeOfVarNumber(4294967295), 5); + BOOST_CHECK_EQUAL(sizeOfVarNumber(4294967296), 9); +} + +BOOST_AUTO_TEST_CASE(Write) +{ + std::ostringstream os; + + writeVarNumber(os, 0); + writeVarNumber(os, 1); + writeVarNumber(os, 252); + writeVarNumber(os, 253); + writeVarNumber(os, 65536); + writeVarNumber(os, 4294967296); + + std::string buffer = os.str(); + const uint8_t* actual = reinterpret_cast(buffer.data()); + + BOOST_CHECK_EQUAL(buffer.size(), sizeof(BUFFER)); + BOOST_CHECK_EQUAL_COLLECTIONS(BUFFER, BUFFER + sizeof(BUFFER), + actual, actual + sizeof(BUFFER)); +} + +BOOST_AUTO_TEST_CASE(ReadFromBuffer) +{ + const uint8_t* begin; + uint64_t value; + + begin = BUFFER; + BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), true); + begin = BUFFER; + BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 1)); + BOOST_CHECK_EQUAL(value, 0); + + begin = BUFFER + 1; + BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), true); + begin = BUFFER + 1; + BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 1)); + BOOST_CHECK_EQUAL(value, 1); + + begin = BUFFER + 2; + BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), true); + begin = BUFFER + 2; + BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 1)); + BOOST_CHECK_EQUAL(value, 252); + + begin = BUFFER + 3; + BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), false); + begin = BUFFER + 3; + BOOST_CHECK_THROW(readVarNumber(begin, begin + 1), Error); + + begin = BUFFER + 3; + BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 2, value), false); + begin = BUFFER + 3; + BOOST_CHECK_THROW(readVarNumber(begin, begin + 2), Error); + + begin = BUFFER + 3; + BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 3, value), true); + begin = BUFFER + 3; + BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 3)); + BOOST_CHECK_EQUAL(value, 253); + + begin = BUFFER + 6; + BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), false); + begin = BUFFER + 6; + BOOST_CHECK_THROW(readVarNumber(begin, begin + 1), Error); + + begin = BUFFER + 6; + BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 4, value), false); + begin = BUFFER + 6; + BOOST_CHECK_THROW(readVarNumber(begin, begin + 4), Error); + + begin = BUFFER + 6; + BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 5, value), true); + begin = BUFFER + 6; + BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 5)); + BOOST_CHECK_EQUAL(value, 65536); + + begin = BUFFER + 11; + BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 1, value), false); + begin = BUFFER + 11; + BOOST_CHECK_THROW(readVarNumber(begin, begin + 1), Error); + + begin = BUFFER + 11; + BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 8, value), false); + begin = BUFFER + 11; + BOOST_CHECK_THROW(readVarNumber(begin, begin + 8), Error); + + begin = BUFFER + 11; + BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 9, value), true); + begin = BUFFER + 11; + BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 9)); + BOOST_CHECK_EQUAL(value, 4294967296); +} + +BOOST_AUTO_TEST_CASE(ReadFromStream) +{ + StreamIterator end; // end of stream + uint64_t value; + + { + ArrayStream stream(reinterpret_cast(BUFFER), 1); + StreamIterator begin(stream); + BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true); + } + { + ArrayStream stream(reinterpret_cast(BUFFER), 1); + StreamIterator begin(stream); + BOOST_CHECK_NO_THROW(readVarNumber(begin, end)); + BOOST_CHECK_EQUAL(value, 0); + } + + { + ArrayStream stream(reinterpret_cast(BUFFER) + 1, 1); + StreamIterator begin(stream); + BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true); + } + { + ArrayStream stream(reinterpret_cast(BUFFER) + 1, 1); + StreamIterator begin(stream); + BOOST_CHECK_NO_THROW(readVarNumber(begin, end)); + BOOST_CHECK_EQUAL(value, 1); + } + + { + ArrayStream stream(reinterpret_cast(BUFFER) + 2, 1); + StreamIterator begin(stream); + BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true); + } + { + ArrayStream stream(reinterpret_cast(BUFFER) + 2, 1); + StreamIterator begin(stream); + BOOST_CHECK_NO_THROW(readVarNumber(begin, end)); + BOOST_CHECK_EQUAL(value, 252); + } + + { + ArrayStream stream(reinterpret_cast(BUFFER) + 3, 1); + StreamIterator begin(stream); + BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false); + } + { + ArrayStream stream(reinterpret_cast(BUFFER) + 3, 1); + StreamIterator begin(stream); + BOOST_CHECK_THROW(readVarNumber(begin, end), Error); + } + + { + ArrayStream stream(reinterpret_cast(BUFFER) + 3, 2); + StreamIterator begin(stream); + BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false); + } + { + ArrayStream stream(reinterpret_cast(BUFFER) + 3, 2); + StreamIterator begin(stream); + BOOST_CHECK_THROW(readVarNumber(begin, end), Error); + } + + { + ArrayStream stream(reinterpret_cast(BUFFER) + 3, 3); + StreamIterator begin(stream); + BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true); + } + { + ArrayStream stream(reinterpret_cast(BUFFER) + 3, 3); + StreamIterator begin(stream); + BOOST_CHECK_NO_THROW(readVarNumber(begin, end)); + BOOST_CHECK_EQUAL(value, 253); + } + + { + ArrayStream stream(reinterpret_cast(BUFFER) + 6, 1); + StreamIterator begin(stream); + BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false); + } + { + ArrayStream stream(reinterpret_cast(BUFFER) + 6, 1); + StreamIterator begin(stream); + BOOST_CHECK_THROW(readVarNumber(begin, end), Error); + } + + { + ArrayStream stream(reinterpret_cast(BUFFER) + 6, 4); + StreamIterator begin(stream); + BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false); + } + { + ArrayStream stream(reinterpret_cast(BUFFER) + 6, 4); + StreamIterator begin(stream); + BOOST_CHECK_THROW(readVarNumber(begin, end), Error); + } + + { + ArrayStream stream(reinterpret_cast(BUFFER) + 6, 5); + StreamIterator begin(stream); + BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true); + } + { + ArrayStream stream(reinterpret_cast(BUFFER) + 6, 5); + StreamIterator begin(stream); + BOOST_CHECK_NO_THROW(readVarNumber(begin, end)); + BOOST_CHECK_EQUAL(value, 65536); + } + + { + ArrayStream stream(reinterpret_cast(BUFFER) + 11, 1); + StreamIterator begin(stream); + BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false); + } + { + ArrayStream stream(reinterpret_cast(BUFFER) + 11, 1); + StreamIterator begin(stream); + BOOST_CHECK_THROW(readVarNumber(begin, end), Error); + } + + { + ArrayStream stream(reinterpret_cast(BUFFER) + 11, 8); + StreamIterator begin(stream); + BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false); + } + { + ArrayStream stream(reinterpret_cast(BUFFER) + 11, 8); + StreamIterator begin(stream); + BOOST_CHECK_THROW(readVarNumber(begin, end), Error); + } + + { + ArrayStream stream(reinterpret_cast(BUFFER) + 11, 9); + StreamIterator begin(stream); + BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true); + } + { + ArrayStream stream(reinterpret_cast(BUFFER) + 11, 9); + StreamIterator begin(stream); + BOOST_CHECK_NO_THROW(readVarNumber(begin, end)); + BOOST_CHECK_EQUAL(value, 4294967296); + } +} + +BOOST_AUTO_TEST_SUITE_END() // VarNumber + +BOOST_AUTO_TEST_SUITE(Type) + +static const uint8_t BUFFER[] = { + 0x00, // == 0 (illegal) + 0x01, // == 1 + 0xfd, 0x00, 0xfd, // == 253 + 0xfe, 0xff, 0xff, 0xff, 0xff, // == 4294967295 + 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 // == 4294967296 (illegal) +}; + +BOOST_AUTO_TEST_CASE(Read) +{ + const uint8_t* begin; + uint32_t type; + + begin = BUFFER; + BOOST_CHECK_EQUAL(readType(begin, begin + 1, type), false); + begin = BUFFER; + BOOST_CHECK_THROW(readType(begin, begin + 1), Error); + + begin = BUFFER + 1; + BOOST_CHECK_EQUAL(readType(begin, begin + 1, type), true); + begin = BUFFER + 1; + BOOST_CHECK_NO_THROW(readType(begin, begin + 1)); + BOOST_CHECK_EQUAL(type, 1); + + begin = BUFFER + 2; + BOOST_CHECK_EQUAL(readType(begin, begin + 1, type), false); + begin = BUFFER + 2; + BOOST_CHECK_THROW(readType(begin, begin + 1), Error); + + begin = BUFFER + 2; + BOOST_CHECK_EQUAL(readType(begin, begin + 2, type), false); + begin = BUFFER + 2; + BOOST_CHECK_THROW(readType(begin, begin + 2), Error); + + begin = BUFFER + 2; + BOOST_CHECK_EQUAL(readType(begin, begin + 3, type), true); + begin = BUFFER + 2; + BOOST_CHECK_NO_THROW(readType(begin, begin + 3)); + BOOST_CHECK_EQUAL(type, 253); + + begin = BUFFER + 5; + BOOST_CHECK_EQUAL(readType(begin, begin + 1, type), false); + begin = BUFFER + 5; + BOOST_CHECK_THROW(readType(begin, begin + 1), Error); + + begin = BUFFER + 5; + BOOST_CHECK_EQUAL(readType(begin, begin + 5, type), true); + begin = BUFFER + 5; + BOOST_CHECK_NO_THROW(readType(begin, begin + 5)); + BOOST_CHECK_EQUAL(type, 4294967295); + + begin = BUFFER + 10; + BOOST_CHECK_EQUAL(readType(begin, begin + 1, type), false); + begin = BUFFER + 10; + BOOST_CHECK_THROW(readType(begin, begin + 1), Error); + + begin = BUFFER + 10; + BOOST_CHECK_EQUAL(readType(begin, begin + 9, type), false); + begin = BUFFER + 10; + BOOST_CHECK_THROW(readType(begin, begin + 9), Error); +} + +BOOST_AUTO_TEST_SUITE_END() // Type + +BOOST_AUTO_TEST_SUITE(NonNegativeInteger) + +// This check ensures readNonNegativeInteger only requires InputIterator concept and nothing more. +// This function should compile, but should never be executed. +void +checkArchetype() +{ + boost::input_iterator_archetype begin, end; + readNonNegativeInteger(0, begin, end); +} + +static const uint8_t BUFFER[] = { + 0x01, // 1 + 0xff, // 255 + 0x01, 0x02, // 258 + 0x01, 0x01, 0x01, 0x02, // 16843010 + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02 // 72340172838076674 +}; + +BOOST_AUTO_TEST_CASE(SizeOf) +{ + BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(1), 1); + BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(253), 1); + BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(255), 1); + BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(256), 2); + BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(65536), 4); + BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(16843009), 4); + BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(4294967296), 8); + BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(72340172838076673), 8); +} + +BOOST_AUTO_TEST_CASE(Write) +{ + std::ostringstream os; + + writeNonNegativeInteger(os, 1); + writeNonNegativeInteger(os, 255); + writeNonNegativeInteger(os, 258); + writeNonNegativeInteger(os, 16843010); + writeNonNegativeInteger(os, 72340172838076674); + + std::string buffer = os.str(); + const uint8_t* actual = reinterpret_cast(buffer.data()); + + BOOST_CHECK_EQUAL_COLLECTIONS(BUFFER, BUFFER + sizeof(BUFFER), + actual, actual + sizeof(BUFFER)); +} + +BOOST_AUTO_TEST_CASE(ReadFromBuffer) +{ + const uint8_t* begin = nullptr; + + begin = BUFFER; + BOOST_CHECK_EQUAL(readNonNegativeInteger(1, begin, begin + 1), 1); + BOOST_CHECK_EQUAL(begin, BUFFER + 1); + + begin = BUFFER + 1; + BOOST_CHECK_EQUAL(readNonNegativeInteger(1, begin, begin + 1), 255); + BOOST_CHECK_EQUAL(begin, BUFFER + 2); + + begin = BUFFER + 2; + BOOST_CHECK_EQUAL(readNonNegativeInteger(2, begin, begin + 2), 258); + BOOST_CHECK_EQUAL(begin, BUFFER + 4); + + begin = BUFFER + 4; + BOOST_CHECK_EQUAL(readNonNegativeInteger(4, begin, begin + 4), 16843010); + BOOST_CHECK_EQUAL(begin, BUFFER + 8); + + begin = BUFFER + 8; + BOOST_CHECK_EQUAL(readNonNegativeInteger(8, begin, begin + 8), 72340172838076674); + BOOST_CHECK_EQUAL(begin, BUFFER + 16); + + // invalid size + begin = BUFFER; + BOOST_CHECK_THROW(readNonNegativeInteger(3, begin, begin + 3), Error); + + // available buffer smaller than size + begin = BUFFER; + BOOST_CHECK_THROW(readNonNegativeInteger(1, begin, begin + 0), Error); + begin = BUFFER; + BOOST_CHECK_THROW(readNonNegativeInteger(2, begin, begin + 1), Error); + begin = BUFFER; + BOOST_CHECK_THROW(readNonNegativeInteger(4, begin, begin + 3), Error); + begin = BUFFER; + BOOST_CHECK_THROW(readNonNegativeInteger(8, begin, begin + 7), Error); +} + +BOOST_AUTO_TEST_CASE(ReadFromStream) +{ + StreamIterator end; // end of stream + + { + ArrayStream stream(reinterpret_cast(BUFFER), sizeof(BUFFER)); + StreamIterator begin(stream); + BOOST_CHECK_EQUAL(readNonNegativeInteger(1, begin, end), 1); + BOOST_CHECK_EQUAL(readNonNegativeInteger(1, begin, end), 255); + BOOST_CHECK_EQUAL(readNonNegativeInteger(2, begin, end), 258); + BOOST_CHECK_EQUAL(readNonNegativeInteger(4, begin, end), 16843010); + BOOST_CHECK_EQUAL(readNonNegativeInteger(8, begin, end), 72340172838076674); + BOOST_CHECK(begin == end); + } + + // invalid size + { + ArrayStream stream(reinterpret_cast(BUFFER), 3); + StreamIterator begin(stream); + BOOST_CHECK_THROW(readNonNegativeInteger(3, begin, end), Error); + } + + // available buffer smaller than size + { + ArrayStream stream(reinterpret_cast(BUFFER), 0); + StreamIterator begin(stream); + BOOST_CHECK_THROW(readNonNegativeInteger(1, begin, end), Error); + } + { + ArrayStream stream(reinterpret_cast(BUFFER), 1); + StreamIterator begin(stream); + BOOST_CHECK_THROW(readNonNegativeInteger(2, begin, end), Error); + } + { + ArrayStream stream(reinterpret_cast(BUFFER), 3); + StreamIterator begin(stream); + BOOST_CHECK_THROW(readNonNegativeInteger(4, begin, end), Error); + } + { + ArrayStream stream(reinterpret_cast(BUFFER), 7); + StreamIterator begin(stream); + BOOST_CHECK_THROW(readNonNegativeInteger(8, begin, end), Error); + } +} + +BOOST_AUTO_TEST_SUITE_END() // NonNegativeInteger + +BOOST_AUTO_TEST_SUITE(PrintHelpers) + +BOOST_AUTO_TEST_CASE(PrintSignatureTypeValue) +{ + BOOST_CHECK_EQUAL(boost::lexical_cast(DigestSha256), "DigestSha256"); + BOOST_CHECK_EQUAL(boost::lexical_cast(SignatureSha256WithRsa), "SignatureSha256WithRsa"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(2)), "Unknown(2)"); + BOOST_CHECK_EQUAL(boost::lexical_cast(SignatureSha256WithEcdsa), "SignatureSha256WithEcdsa"); + BOOST_CHECK_EQUAL(boost::lexical_cast(SignatureHmacWithSha256), "SignatureHmacWithSha256"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(5)), "Unknown(5)"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(200)), "Unknown(200)"); +} + +BOOST_AUTO_TEST_CASE(PrintContentTypeValue) +{ + BOOST_CHECK_EQUAL(boost::lexical_cast(ContentType_Blob), "Blob"); + BOOST_CHECK_EQUAL(boost::lexical_cast(ContentType_Link), "Link"); + BOOST_CHECK_EQUAL(boost::lexical_cast(ContentType_Key), "Key"); + BOOST_CHECK_EQUAL(boost::lexical_cast(ContentType_Nack), "Nack"); + BOOST_CHECK_EQUAL(boost::lexical_cast(ContentType_Manifest), "Manifest"); + BOOST_CHECK_EQUAL(boost::lexical_cast(ContentType_PrefixAnn), "PrefixAnn"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(6)), "Reserved(6)"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(1023)), "Reserved(1023)"); + BOOST_CHECK_EQUAL(boost::lexical_cast(ContentType_Flic), "FLIC"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(1025)), "Unknown(1025)"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(8999)), "Unknown(8999)"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(9000)), "Experimental(9000)"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(9999)), "Experimental(9999)"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(10000)), "Unknown(10000)"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(19910118)), "Unknown(19910118)"); +} + +BOOST_AUTO_TEST_SUITE_END() // PrintHelpers + +BOOST_AUTO_TEST_SUITE_END() // TestTlv +BOOST_AUTO_TEST_SUITE_END() // Encoding + +} // namespace tests +} // namespace tlv +} // namespace ndn diff --git a/tests/unit/face.t.cpp b/tests/unit/face.t.cpp new file mode 100644 index 000000000..eb01f8f53 --- /dev/null +++ b/tests/unit/face.t.cpp @@ -0,0 +1,953 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/face.hpp" +#include "ndn-cxx/lp/tags.hpp" +#include "ndn-cxx/transport/tcp-transport.hpp" +#include "ndn-cxx/transport/unix-transport.hpp" +#include "ndn-cxx/util/dummy-client-face.hpp" +#include "ndn-cxx/util/scheduler.hpp" + +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" +#include "tests/unit/identity-management-time-fixture.hpp" + +#include + +namespace ndn { +namespace tests { + +using ndn::util::DummyClientFace; + +struct WantPrefixRegReply; +struct NoPrefixRegReply; + +template +class FaceFixture : public IdentityManagementTimeFixture +{ +public: + FaceFixture() + : face(io, m_keyChain, {true, !std::is_same::value}) + { + static_assert(std::is_same::value || + std::is_same::value, ""); + } + + /** \brief Execute a prefix registration, and optionally check the name in callback. + * \return whether the prefix registration succeeded. + */ + bool + runPrefixReg(function f) + { + boost::logic::tribool result = boost::logic::indeterminate; + f([&] (const Name&) { result = true; }, + [&] (const Name&, const std::string&) { result = false; }); + + advanceClocks(1_ms); + BOOST_REQUIRE(!boost::logic::indeterminate(result)); + return static_cast(result); + } + + /** \brief Execute a prefix unregistration, and optionally check the name in callback. + * \return whether the prefix unregistration succeeded. + */ + bool + runPrefixUnreg(function f) + { + boost::logic::tribool result = boost::logic::indeterminate; + f([&] { result = true; }, [&] (const std::string&) { result = false; }); + + advanceClocks(1_ms); + BOOST_REQUIRE(!boost::logic::indeterminate(result)); + return static_cast(result); + } + +public: + DummyClientFace face; +}; + +BOOST_FIXTURE_TEST_SUITE(TestFace, FaceFixture<>) + +BOOST_AUTO_TEST_SUITE(Consumer) + +BOOST_AUTO_TEST_CASE(ExpressInterestData) +{ + size_t nData = 0; + face.expressInterest(*makeInterest("/Hello/World", true, 50_ms), + [&] (const Interest& i, const Data& d) { + BOOST_CHECK(i.getName().isPrefixOf(d.getName())); + BOOST_CHECK_EQUAL(i.getName(), "/Hello/World"); + ++nData; + }, + bind([] { BOOST_FAIL("Unexpected Nack"); }), + bind([] { BOOST_FAIL("Unexpected timeout"); })); + + advanceClocks(40_ms); + + face.receive(*makeData("/Bye/World/a")); + face.receive(*makeData("/Hello/World/a")); + + advanceClocks(50_ms, 2); + + BOOST_CHECK_EQUAL(nData, 1); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); + BOOST_CHECK_EQUAL(face.sentData.size(), 0); + + size_t nTimeouts = 0; + face.expressInterest(*makeInterest("/Hello/World/a/2", false, 50_ms), + bind([]{}), + bind([]{}), + bind([&nTimeouts] { ++nTimeouts; })); + advanceClocks(200_ms, 5); + BOOST_CHECK_EQUAL(nTimeouts, 1); +} + +BOOST_AUTO_TEST_CASE(ExpressMultipleInterestData) +{ + size_t nData = 0; + + face.expressInterest(*makeInterest("/Hello/World", true, 50_ms), + [&] (const Interest& i, const Data& d) { + ++nData; + }, + bind([] { BOOST_FAIL("Unexpected Nack"); }), + bind([] { BOOST_FAIL("Unexpected timeout"); })); + + face.expressInterest(*makeInterest("/Hello/World/a", true, 50_ms), + [&] (const Interest& i, const Data& d) { + ++nData; + }, + bind([] { BOOST_FAIL("Unexpected Nack"); }), + bind([] { BOOST_FAIL("Unexpected timeout"); })); + + advanceClocks(40_ms); + + face.receive(*makeData("/Hello/World/a/b")); + + advanceClocks(50_ms, 2); + + BOOST_CHECK_EQUAL(nData, 2); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 2); + BOOST_CHECK_EQUAL(face.sentData.size(), 0); +} + +BOOST_AUTO_TEST_CASE(ExpressInterestEmptyDataCallback) +{ + face.expressInterest(*makeInterest("/Hello/World", true), + nullptr, + bind([] { BOOST_FAIL("Unexpected Nack"); }), + bind([] { BOOST_FAIL("Unexpected timeout"); })); + advanceClocks(1_ms); + + BOOST_CHECK_NO_THROW(do { + face.receive(*makeData("/Hello/World/a")); + advanceClocks(1_ms); + } while (false)); +} + +BOOST_AUTO_TEST_CASE(ExpressInterestTimeout) +{ + size_t nTimeouts = 0; + face.expressInterest(*makeInterest("/Hello/World", false, 50_ms), + bind([] { BOOST_FAIL("Unexpected Data"); }), + bind([] { BOOST_FAIL("Unexpected Nack"); }), + [&nTimeouts] (const Interest& i) { + BOOST_CHECK_EQUAL(i.getName(), "/Hello/World"); + ++nTimeouts; + }); + + advanceClocks(200_ms, 5); + + BOOST_CHECK_EQUAL(nTimeouts, 1); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); + BOOST_CHECK_EQUAL(face.sentData.size(), 0); + BOOST_CHECK_EQUAL(face.sentNacks.size(), 0); +} + +BOOST_AUTO_TEST_CASE(ExpressInterestEmptyTimeoutCallback) +{ + face.expressInterest(*makeInterest("/Hello/World", false, 50_ms), + bind([] { BOOST_FAIL("Unexpected Data"); }), + bind([] { BOOST_FAIL("Unexpected Nack"); }), + nullptr); + advanceClocks(40_ms); + + BOOST_CHECK_NO_THROW(do { + advanceClocks(6_ms, 2); + } while (false)); +} + +BOOST_AUTO_TEST_CASE(ExpressInterestNack) +{ + size_t nNacks = 0; + + auto interest = makeInterest("/Hello/World", false, 50_ms); + + face.expressInterest(*interest, + bind([] { BOOST_FAIL("Unexpected Data"); }), + [&] (const Interest& i, const lp::Nack& n) { + BOOST_CHECK(i.getName().isPrefixOf(n.getInterest().getName())); + BOOST_CHECK_EQUAL(i.getName(), "/Hello/World"); + BOOST_CHECK_EQUAL(n.getReason(), lp::NackReason::DUPLICATE); + ++nNacks; + }, + bind([] { BOOST_FAIL("Unexpected timeout"); })); + + advanceClocks(40_ms); + + face.receive(makeNack(face.sentInterests.at(0), lp::NackReason::DUPLICATE)); + + advanceClocks(50_ms, 2); + + BOOST_CHECK_EQUAL(nNacks, 1); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); +} + +BOOST_AUTO_TEST_CASE(ExpressMultipleInterestNack) +{ + size_t nNacks = 0; + + auto interest = makeInterest("/Hello/World", false, 50_ms, 1); + face.expressInterest(*interest, + bind([] { BOOST_FAIL("Unexpected Data"); }), + [&] (const Interest& i, const lp::Nack& n) { + ++nNacks; + }, + bind([] { BOOST_FAIL("Unexpected timeout"); })); + + interest->setNonce(2); + face.expressInterest(*interest, + bind([] { BOOST_FAIL("Unexpected Data"); }), + [&] (const Interest& i, const lp::Nack& n) { + ++nNacks; + }, + bind([] { BOOST_FAIL("Unexpected timeout"); })); + + advanceClocks(40_ms); + + face.receive(makeNack(face.sentInterests.at(1), lp::NackReason::DUPLICATE)); + + advanceClocks(50_ms, 2); + + BOOST_CHECK_EQUAL(nNacks, 2); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 2); +} + +BOOST_AUTO_TEST_CASE(ExpressInterestEmptyNackCallback) +{ + face.expressInterest(*makeInterest("/Hello/World"), + bind([] { BOOST_FAIL("Unexpected Data"); }), + nullptr, + bind([] { BOOST_FAIL("Unexpected timeout"); })); + advanceClocks(1_ms); + + BOOST_CHECK_NO_THROW(do { + face.receive(makeNack(face.sentInterests.at(0), lp::NackReason::DUPLICATE)); + advanceClocks(1_ms); + } while (false)); +} + +BOOST_AUTO_TEST_CASE(CancelPendingInterestHandle) +{ + auto hdl = face.expressInterest(*makeInterest("/Hello/World", true, 50_ms), + bind([] { BOOST_FAIL("Unexpected data"); }), + bind([] { BOOST_FAIL("Unexpected nack"); }), + bind([] { BOOST_FAIL("Unexpected timeout"); })); + advanceClocks(10_ms); + + hdl.cancel(); + advanceClocks(10_ms); + + face.receive(*makeData("/Hello/World/%21")); + advanceClocks(200_ms, 5); + + // avoid "test case [...] did not check any assertions" message from Boost.Test + BOOST_CHECK(true); +} + +BOOST_AUTO_TEST_CASE(RemoveAllPendingInterests) +{ + face.expressInterest(*makeInterest("/Hello/World/0", false, 50_ms), + bind([] { BOOST_FAIL("Unexpected data"); }), + bind([] { BOOST_FAIL("Unexpected nack"); }), + bind([] { BOOST_FAIL("Unexpected timeout"); })); + + face.expressInterest(*makeInterest("/Hello/World/1", false, 50_ms), + bind([] { BOOST_FAIL("Unexpected data"); }), + bind([] { BOOST_FAIL("Unexpected nack"); }), + bind([] { BOOST_FAIL("Unexpected timeout"); })); + + advanceClocks(10_ms); + + face.removeAllPendingInterests(); + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0); + + face.receive(*makeData("/Hello/World/0")); + face.receive(*makeData("/Hello/World/1")); + advanceClocks(200_ms, 5); +} + +BOOST_AUTO_TEST_CASE(DestructionWithoutCancellingPendingInterests) // Bug #2518 +{ + { + DummyClientFace face2(io, m_keyChain); + face2.expressInterest(*makeInterest("/Hello/World", false, 50_ms), + nullptr, nullptr, nullptr); + advanceClocks(50_ms, 2); + } + + advanceClocks(50_ms, 2); // should not crash + + // avoid "test case [...] did not check any assertions" message from Boost.Test + BOOST_CHECK(true); +} + +BOOST_AUTO_TEST_CASE(DataCallbackPutData) // Bug 4596 +{ + face.expressInterest(*makeInterest("/localhost/notification/1"), + [&] (const Interest& i, const Data& d) { + face.put(*makeData("/chronosync/sampleDigest/1")); + }, nullptr, nullptr); + advanceClocks(10_ms); + BOOST_CHECK_EQUAL(face.sentInterests.back().getName(), "/localhost/notification/1"); + + face.receive(*makeInterest("/chronosync/sampleDigest", true)); + advanceClocks(10_ms); + + face.put(*makeData("/localhost/notification/1")); + advanceClocks(10_ms); + BOOST_CHECK_EQUAL(face.sentData.back().getName(), "/chronosync/sampleDigest/1"); +} + +BOOST_AUTO_TEST_SUITE_END() // Consumer + +BOOST_AUTO_TEST_SUITE(Producer) + +BOOST_AUTO_TEST_CASE(PutData) +{ + BOOST_CHECK_EQUAL(face.sentData.size(), 0); + + Data data("/4g7xxcuEow/KFvK5Kf2m"); + signData(data); + face.put(data); + + lp::CachePolicy cachePolicy; + cachePolicy.setPolicy(lp::CachePolicyType::NO_CACHE); + data.setTag(make_shared(cachePolicy)); + data.setTag(make_shared(1)); + face.put(data); + + advanceClocks(10_ms); + BOOST_REQUIRE_EQUAL(face.sentData.size(), 2); + BOOST_CHECK(face.sentData[0].getTag() == nullptr); + BOOST_CHECK(face.sentData[0].getTag() == nullptr); + BOOST_CHECK(face.sentData[1].getTag() != nullptr); + BOOST_CHECK(face.sentData[1].getTag() != nullptr); +} + +BOOST_AUTO_TEST_CASE(PutDataLoopback) +{ + bool hasInterest1 = false, hasData = false; + + // first InterestFilter allows loopback and should receive Interest + face.setInterestFilter("/", [&] (const InterestFilter&, const Interest&) { + hasInterest1 = true; + // do not respond with Data right away, so Face must send Interest to forwarder + }); + // second InterestFilter disallows loopback and should not receive Interest + face.setInterestFilter(InterestFilter("/").allowLoopback(false), + bind([] { BOOST_ERROR("Unexpected Interest on second InterestFilter"); })); + + face.expressInterest(*makeInterest("/A", true), + bind([&] { hasData = true; }), + bind([] { BOOST_FAIL("Unexpected nack"); }), + bind([] { BOOST_FAIL("Unexpected timeout"); })); + advanceClocks(1_ms); + BOOST_CHECK_EQUAL(hasInterest1, true); // Interest looped back + BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); // Interest sent to forwarder + BOOST_CHECK_EQUAL(hasData, false); // waiting for Data + + face.put(*makeData("/A/B")); // first InterestFilter responds with Data + advanceClocks(1_ms); + BOOST_CHECK_EQUAL(hasData, true); + BOOST_CHECK_EQUAL(face.sentData.size(), 0); // do not spill Data to forwarder +} + +BOOST_AUTO_TEST_CASE(PutMultipleData) +{ + bool hasInterest1 = false; + // register two Interest destinations + face.setInterestFilter("/", bind([&] { + hasInterest1 = true; + // sending Data right away from the first destination, don't care whether Interest goes to second destination + face.put(*makeData("/A/B")); + })); + face.setInterestFilter("/", bind([]{})); + advanceClocks(10_ms); + + face.receive(*makeInterest("/A", true)); + advanceClocks(10_ms); + BOOST_CHECK(hasInterest1); + BOOST_CHECK_EQUAL(face.sentData.size(), 1); + BOOST_CHECK_EQUAL(face.sentData.at(0).getName(), "/A/B"); + + face.put(*makeData("/A/C")); + BOOST_CHECK_EQUAL(face.sentData.size(), 1); // additional Data are ignored +} + +BOOST_AUTO_TEST_CASE(PutNack) +{ + face.setInterestFilter("/", bind([]{})); // register one Interest destination so that face can accept Nacks + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(face.sentNacks.size(), 0); + + face.put(makeNack(*makeInterest("/unsolicited", false, DEFAULT_INTEREST_LIFETIME, 18645250), + lp::NackReason::NO_ROUTE)); + advanceClocks(10_ms); + BOOST_CHECK_EQUAL(face.sentNacks.size(), 0); // unsolicited Nack would not be sent + + auto interest1 = makeInterest("/Hello/World", false, DEFAULT_INTEREST_LIFETIME, 14247162); + face.receive(*interest1); + auto interest2 = makeInterest("/another/prefix", false, DEFAULT_INTEREST_LIFETIME, 92203002); + face.receive(*interest2); + advanceClocks(10_ms); + + face.put(makeNack(*interest1, lp::NackReason::DUPLICATE)); + advanceClocks(10_ms); + BOOST_REQUIRE_EQUAL(face.sentNacks.size(), 1); + BOOST_CHECK_EQUAL(face.sentNacks[0].getReason(), lp::NackReason::DUPLICATE); + BOOST_CHECK(face.sentNacks[0].getTag() == nullptr); + + auto nack = makeNack(*interest2, lp::NackReason::NO_ROUTE); + nack.setTag(make_shared(1)); + face.put(nack); + advanceClocks(10_ms); + BOOST_REQUIRE_EQUAL(face.sentNacks.size(), 2); + BOOST_CHECK_EQUAL(face.sentNacks[1].getReason(), lp::NackReason::NO_ROUTE); + BOOST_CHECK(face.sentNacks[1].getTag() != nullptr); +} + +BOOST_AUTO_TEST_CASE(PutMultipleNack) +{ + bool hasInterest1 = false, hasInterest2 = false; + // register two Interest destinations + face.setInterestFilter("/", [&] (const InterestFilter&, const Interest& interest) { + hasInterest1 = true; + // sending Nack right away from the first destination, Interest should still go to second destination + face.put(makeNack(interest, lp::NackReason::CONGESTION)); + }); + face.setInterestFilter("/", bind([&] { hasInterest2 = true; })); + advanceClocks(10_ms); + + auto interest = makeInterest("/A", false, DEFAULT_INTEREST_LIFETIME, 14333271); + face.receive(*interest); + advanceClocks(10_ms); + BOOST_CHECK(hasInterest1); + BOOST_CHECK(hasInterest2); + + // Nack from first destination is received, should wait for a response from the other destination + BOOST_CHECK_EQUAL(face.sentNacks.size(), 0); + + face.put(makeNack(*interest, lp::NackReason::NO_ROUTE)); // Nack from second destination + advanceClocks(10_ms); + BOOST_CHECK_EQUAL(face.sentNacks.size(), 1); // sending Nack after both destinations Nacked + BOOST_CHECK_EQUAL(face.sentNacks.at(0).getReason(), lp::NackReason::CONGESTION); // least severe reason + + face.put(makeNack(*interest, lp::NackReason::DUPLICATE)); + BOOST_CHECK_EQUAL(face.sentNacks.size(), 1); // additional Nacks are ignored +} + +BOOST_AUTO_TEST_CASE(PutMultipleNackLoopback) +{ + bool hasInterest1 = false, hasNack = false; + + // first InterestFilter allows loopback and should receive Interest + face.setInterestFilter("/", [&] (const InterestFilter&, const Interest& interest) { + hasInterest1 = true; + face.put(makeNack(interest, lp::NackReason::CONGESTION)); + }); + // second InterestFilter disallows loopback and should not receive Interest + face.setInterestFilter(InterestFilter("/").allowLoopback(false), + bind([] { BOOST_ERROR("Unexpected Interest on second InterestFilter"); })); + + auto interest = makeInterest("/A", false, DEFAULT_INTEREST_LIFETIME, 28395852); + face.expressInterest(*interest, + bind([] { BOOST_FAIL("Unexpected data"); }), + [&] (const Interest&, const lp::Nack& nack) { + hasNack = true; + BOOST_CHECK_EQUAL(nack.getReason(), lp::NackReason::CONGESTION); + }, + bind([] { BOOST_FAIL("Unexpected timeout"); })); + advanceClocks(1_ms); + BOOST_CHECK_EQUAL(hasInterest1, true); // Interest looped back + BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); // Interest sent to forwarder + BOOST_CHECK_EQUAL(hasNack, false); // waiting for Nack from forwarder + + face.receive(makeNack(*interest, lp::NackReason::NO_ROUTE)); + advanceClocks(1_ms); + BOOST_CHECK_EQUAL(hasNack, true); +} + +BOOST_AUTO_TEST_CASE(SetUnsetInterestFilter) +{ + size_t nInterests = 0; + size_t nRegs = 0; + auto hdl = face.setInterestFilter("/Hello/World", + bind([&nInterests] { ++nInterests; }), + bind([&nRegs] { ++nRegs; }), + bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); + advanceClocks(25_ms, 4); + BOOST_CHECK_EQUAL(nRegs, 1); + BOOST_CHECK_EQUAL(nInterests, 0); + + face.receive(*makeInterest("/Hello/World/%21")); + advanceClocks(25_ms, 4); + + BOOST_CHECK_EQUAL(nRegs, 1); + BOOST_CHECK_EQUAL(nInterests, 1); + + face.receive(*makeInterest("/Bye/World/%21")); + advanceClocks(10000_ms, 10); + BOOST_CHECK_EQUAL(nInterests, 1); + + face.receive(*makeInterest("/Hello/World/%21/2")); + advanceClocks(25_ms, 4); + BOOST_CHECK_EQUAL(nInterests, 2); + + // removing filter + hdl.cancel(); + advanceClocks(25_ms, 4); + + face.receive(*makeInterest("/Hello/World/%21/3")); + BOOST_CHECK_EQUAL(nInterests, 2); + + face.unsetInterestFilter(static_cast(nullptr)); + advanceClocks(25_ms, 4); + + face.unsetInterestFilter(static_cast(nullptr)); + advanceClocks(25_ms, 4); +} + +BOOST_AUTO_TEST_CASE(SetInterestFilterEmptyInterestCallback) +{ + face.setInterestFilter("/A", nullptr); + advanceClocks(1_ms); + + BOOST_CHECK_NO_THROW(do { + face.receive(*makeInterest("/A/1")); + advanceClocks(1_ms); + } while (false)); +} + +BOOST_AUTO_TEST_CASE(SetUnsetInterestFilterWithoutSucessCallback) +{ + size_t nInterests = 0; + auto hdl = face.setInterestFilter("/Hello/World", + bind([&nInterests] { ++nInterests; }), + bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); + advanceClocks(25_ms, 4); + BOOST_CHECK_EQUAL(nInterests, 0); + + face.receive(*makeInterest("/Hello/World/%21")); + advanceClocks(25_ms, 4); + + BOOST_CHECK_EQUAL(nInterests, 1); + + face.receive(*makeInterest("/Bye/World/%21")); + advanceClocks(10000_ms, 10); + BOOST_CHECK_EQUAL(nInterests, 1); + + face.receive(*makeInterest("/Hello/World/%21/2")); + advanceClocks(25_ms, 4); + BOOST_CHECK_EQUAL(nInterests, 2); + + // removing filter + hdl.cancel(); + advanceClocks(25_ms, 4); + + face.receive(*makeInterest("/Hello/World/%21/3")); + BOOST_CHECK_EQUAL(nInterests, 2); + + face.unsetInterestFilter(static_cast(nullptr)); + advanceClocks(25_ms, 4); + + face.unsetInterestFilter(static_cast(nullptr)); + advanceClocks(25_ms, 4); +} + +BOOST_FIXTURE_TEST_CASE(SetInterestFilterFail, FaceFixture) +{ + // don't enable registration reply + size_t nRegFailed = 0; + face.setInterestFilter("/Hello/World", + bind([] { BOOST_FAIL("Unexpected Interest"); }), + bind([] { BOOST_FAIL("Unexpected success of setInterestFilter"); }), + bind([&nRegFailed] { ++nRegFailed; })); + + advanceClocks(25_ms, 4); + BOOST_CHECK_EQUAL(nRegFailed, 0); + + advanceClocks(2000_ms, 5); + BOOST_CHECK_EQUAL(nRegFailed, 1); +} + +BOOST_FIXTURE_TEST_CASE(SetInterestFilterFailWithoutSuccessCallback, FaceFixture) +{ + // don't enable registration reply + size_t nRegFailed = 0; + face.setInterestFilter("/Hello/World", + bind([] { BOOST_FAIL("Unexpected Interest"); }), + bind([&nRegFailed] { ++nRegFailed; })); + + advanceClocks(25_ms, 4); + BOOST_CHECK_EQUAL(nRegFailed, 0); + + advanceClocks(2000_ms, 5); + BOOST_CHECK_EQUAL(nRegFailed, 1); +} + +BOOST_FIXTURE_TEST_CASE(RegisterUnregisterPrefixFail, FaceFixture) +{ + BOOST_CHECK(!runPrefixReg([&] (const auto& success, const auto& failure) { + face.registerPrefix("/Hello/World", success, failure); + this->advanceClocks(5_s, 20); // wait for command timeout + })); +} + +BOOST_AUTO_TEST_CASE(RegisterUnregisterPrefixHandle) +{ + RegisteredPrefixHandle hdl; + BOOST_CHECK(!runPrefixUnreg([&] (const auto& success, const auto& failure) { + // despite the "undefined behavior" warning, we try not to crash, but no API guarantee for this + hdl.unregister(success, failure); + })); + + BOOST_CHECK(runPrefixReg([&] (const auto& success, const auto& failure) { + hdl = face.registerPrefix("/Hello/World", success, failure); + })); + + BOOST_CHECK(runPrefixUnreg([&] (const auto& success, const auto& failure) { + hdl.unregister(success, failure); + })); +} + +BOOST_AUTO_TEST_CASE(SimilarFilters) +{ + size_t nInInterests1 = 0; + face.setInterestFilter("/Hello/World", + bind([&nInInterests1] { ++nInInterests1; }), + nullptr, + bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); + + size_t nInInterests2 = 0; + face.setInterestFilter("/Hello", + bind([&nInInterests2] { ++nInInterests2; }), + nullptr, + bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); + + size_t nInInterests3 = 0; + face.setInterestFilter("/Los/Angeles/Lakers", + bind([&nInInterests3] { ++nInInterests3; }), + nullptr, + bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); + + advanceClocks(25_ms, 4); + + face.receive(*makeInterest("/Hello/World/%21")); + advanceClocks(25_ms, 4); + + BOOST_CHECK_EQUAL(nInInterests1, 1); + BOOST_CHECK_EQUAL(nInInterests2, 1); + BOOST_CHECK_EQUAL(nInInterests3, 0); +} + +BOOST_AUTO_TEST_CASE(SetRegexFilterError) +{ + face.setInterestFilter(InterestFilter("/Hello/World", "<>?"), + [] (const Name&, const Interest&) { + BOOST_FAIL("InterestFilter::Error should have been triggered"); + }, + nullptr, + bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); + + advanceClocks(25_ms, 4); + + BOOST_REQUIRE_THROW(face.receive(*makeInterest("/Hello/World/XXX/b/c")), InterestFilter::Error); +} + +BOOST_AUTO_TEST_CASE(SetRegexFilter) +{ + size_t nInInterests = 0; + face.setInterestFilter(InterestFilter("/Hello/World", "<>?"), + bind([&nInInterests] { ++nInInterests; }), + nullptr, + bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); + + advanceClocks(25_ms, 4); + + face.receive(*makeInterest("/Hello/World/a")); // shouldn't match + BOOST_CHECK_EQUAL(nInInterests, 0); + + face.receive(*makeInterest("/Hello/World/a/b")); // should match + BOOST_CHECK_EQUAL(nInInterests, 1); + + face.receive(*makeInterest("/Hello/World/a/b/c")); // should match + BOOST_CHECK_EQUAL(nInInterests, 2); + + face.receive(*makeInterest("/Hello/World/a/b/d")); // should not match + BOOST_CHECK_EQUAL(nInInterests, 2); +} + +BOOST_AUTO_TEST_CASE(SetRegexFilterAndRegister) +{ + size_t nInInterests = 0; + face.setInterestFilter(InterestFilter("/Hello/World", "<>?"), + bind([&nInInterests] { ++nInInterests; })); + + size_t nRegSuccesses = 0; + face.registerPrefix("/Hello/World", + bind([&nRegSuccesses] { ++nRegSuccesses; }), + bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); + + advanceClocks(25_ms, 4); + BOOST_CHECK_EQUAL(nRegSuccesses, 1); + + face.receive(*makeInterest("/Hello/World/a")); // shouldn't match + BOOST_CHECK_EQUAL(nInInterests, 0); + + face.receive(*makeInterest("/Hello/World/a/b")); // should match + BOOST_CHECK_EQUAL(nInInterests, 1); + + face.receive(*makeInterest("/Hello/World/a/b/c")); // should match + BOOST_CHECK_EQUAL(nInInterests, 2); + + face.receive(*makeInterest("/Hello/World/a/b/d")); // should not match + BOOST_CHECK_EQUAL(nInInterests, 2); +} + +BOOST_FIXTURE_TEST_CASE(SetInterestFilterNoReg, FaceFixture) // Bug 2318 +{ + // This behavior is specific to DummyClientFace. + // Regular Face won't accept incoming packets until something is sent. + + int hit = 0; + face.setInterestFilter(Name("/"), bind([&hit] { ++hit; })); + face.processEvents(time::milliseconds(-1)); + + face.receive(*makeInterest("/A")); + face.processEvents(time::milliseconds(-1)); + + BOOST_CHECK_EQUAL(hit, 1); +} + +BOOST_AUTO_TEST_CASE(SetInterestFilterHandle) +{ + int hit = 0; + auto hdl = face.setInterestFilter(Name("/"), bind([&hit] { ++hit; })); + face.processEvents(-1_ms); + + face.receive(*makeInterest("/A")); + face.processEvents(-1_ms); + BOOST_CHECK_EQUAL(hit, 1); + + hdl.cancel(); + face.processEvents(-1_ms); + + face.receive(*makeInterest("/B")); + face.processEvents(-1_ms); + BOOST_CHECK_EQUAL(hit, 1); +} + +BOOST_AUTO_TEST_SUITE_END() // Producer + +BOOST_AUTO_TEST_SUITE(IoRoutines) + +BOOST_AUTO_TEST_CASE(ProcessEvents) +{ + face.processEvents(time::milliseconds(-1)); // io_service::reset()/poll() inside + + size_t nRegSuccesses = 0; + face.registerPrefix("/Hello/World", + bind([&nRegSuccesses] { ++nRegSuccesses; }), + bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); })); + + // io_service::poll() without reset + face.getIoService().poll(); + BOOST_CHECK_EQUAL(nRegSuccesses, 0); + + face.processEvents(time::milliseconds(-1)); // io_service::reset()/poll() inside + BOOST_CHECK_EQUAL(nRegSuccesses, 1); +} + +BOOST_AUTO_TEST_CASE(DestroyWithoutProcessEvents) // Bug 3248 +{ + auto face2 = make_unique(io); + face2.reset(); + + io.poll(); // should not crash + + // avoid "test case [...] did not check any assertions" message from Boost.Test + BOOST_CHECK(true); +} + +BOOST_AUTO_TEST_SUITE_END() // IoRoutines + +BOOST_AUTO_TEST_SUITE(Transport) + +using ndn::Transport; + +struct PibDirWithDefaultTpm +{ + const std::string PATH = "build/keys-with-default-tpm"; +}; + +BOOST_FIXTURE_TEST_CASE(FaceTransport, IdentityManagementTimeFixture) +{ + BOOST_CHECK(Face().getTransport() != nullptr); + + BOOST_CHECK(Face(shared_ptr()).getTransport() != nullptr); + BOOST_CHECK(Face(shared_ptr(), io).getTransport() != nullptr); + BOOST_CHECK(Face(shared_ptr(), io, m_keyChain).getTransport() != nullptr); + + auto transport = make_shared("localhost", "6363"); // no real io operations will be scheduled + BOOST_CHECK(Face(transport).getTransport() == transport); + BOOST_CHECK(Face(transport, io).getTransport() == transport); + BOOST_CHECK(Face(transport, io, m_keyChain).getTransport() == transport); +} + +class WithEnv : private IdentityManagementTimeFixture +{ +public: + WithEnv() + { + if (getenv("NDN_CLIENT_TRANSPORT") != nullptr) { + m_oldTransport = getenv("NDN_CLIENT_TRANSPORT"); + unsetenv("NDN_CLIENT_TRANSPORT"); + } + } + + void + configure(const std::string& faceUri) + { + setenv("NDN_CLIENT_TRANSPORT", faceUri.c_str(), true); + } + + ~WithEnv() + { + if (!m_oldTransport.empty()) { + setenv("NDN_CLIENT_TRANSPORT", m_oldTransport.c_str(), true); + } + else { + unsetenv("NDN_CLIENT_TRANSPORT"); + } + } + +private: + std::string m_oldTransport; +}; + +class WithConfig : private TestHomeFixture +{ +public: + void + configure(const std::string& faceUri) + { + createClientConf({"transport=" + faceUri}); + } +}; + +class WithEnvAndConfig : public WithEnv, public WithConfig +{ +}; + +typedef boost::mpl::vector ConfigOptions; + +BOOST_FIXTURE_TEST_CASE(NoConfig, WithEnvAndConfig) // fixture configures test HOME and PIB/TPM path +{ + shared_ptr face; + BOOST_REQUIRE_NO_THROW(face = make_shared()); + BOOST_CHECK(dynamic_pointer_cast(face->getTransport()) != nullptr); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(Unix, T, ConfigOptions, T) +{ + this->configure("unix://some/path"); + + shared_ptr face; + BOOST_REQUIRE_NO_THROW(face = make_shared()); + BOOST_CHECK(dynamic_pointer_cast(face->getTransport()) != nullptr); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(Tcp, T, ConfigOptions, T) +{ + this->configure("tcp://127.0.0.1:6000"); + + shared_ptr face; + BOOST_REQUIRE_NO_THROW(face = make_shared()); + BOOST_CHECK(dynamic_pointer_cast(face->getTransport()) != nullptr); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(WrongTransport, T, ConfigOptions, T) +{ + this->configure("wrong-transport:"); + + BOOST_CHECK_THROW(make_shared(), ConfigFile::Error); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(WrongUri, T, ConfigOptions, T) +{ + this->configure("wrong-uri"); + + BOOST_CHECK_THROW(make_shared(), ConfigFile::Error); +} + +BOOST_FIXTURE_TEST_CASE(EnvOverride, WithEnvAndConfig) +{ + this->WithEnv::configure("tcp://127.0.0.1:6000"); + this->WithConfig::configure("unix://some/path"); + + shared_ptr face; + BOOST_REQUIRE_NO_THROW(face = make_shared()); + BOOST_CHECK(dynamic_pointer_cast(face->getTransport()) != nullptr); +} + +BOOST_FIXTURE_TEST_CASE(ExplicitTransport, WithEnvAndConfig) +{ + this->WithEnv::configure("wrong-uri"); + this->WithConfig::configure("wrong-transport:"); + + auto transport = make_shared("unix://some/path"); + shared_ptr face; + BOOST_REQUIRE_NO_THROW(face = make_shared(transport)); + BOOST_CHECK(dynamic_pointer_cast(face->getTransport()) != nullptr); +} + +BOOST_AUTO_TEST_SUITE_END() // Transport + +BOOST_AUTO_TEST_SUITE_END() // TestFace + +} // namespace tests +} // namespace ndn diff --git a/tests/unit/identity-management-time-fixture.hpp b/tests/unit/identity-management-time-fixture.hpp new file mode 100644 index 000000000..6bff89035 --- /dev/null +++ b/tests/unit/identity-management-time-fixture.hpp @@ -0,0 +1,39 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TESTS_UNIT_IDENTITY_MANAGEMENT_TIME_FIXTURE_HPP +#define NDN_TESTS_UNIT_IDENTITY_MANAGEMENT_TIME_FIXTURE_HPP + +#include "tests/identity-management-fixture.hpp" +#include "tests/unit/unit-test-time-fixture.hpp" + +namespace ndn { +namespace tests { + +class IdentityManagementTimeFixture : public UnitTestTimeFixture + , public IdentityManagementFixture +{ +}; + +} // namespace tests +} // namespace ndn + +#endif // NDN_TESTS_UNIT_IDENTITY_MANAGEMENT_TIME_FIXTURE_HPP diff --git a/tests/unit/ims/in-memory-storage-fifo.t.cpp b/tests/unit/ims/in-memory-storage-fifo.t.cpp new file mode 100644 index 000000000..b18879765 --- /dev/null +++ b/tests/unit/ims/in-memory-storage-fifo.t.cpp @@ -0,0 +1,95 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/ims/in-memory-storage-fifo.hpp" + +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" + +namespace ndn { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Ims) +BOOST_AUTO_TEST_SUITE(TestInMemoryStorageFifo) + +BOOST_AUTO_TEST_CASE(ArrivalQueue) +{ + InMemoryStorageFifo ims; + + ims.insert(*makeData("/1")); + ims.insert(*makeData("/2")); + ims.insert(*makeData("/3")); + + ims.evictItem(); + BOOST_CHECK_EQUAL(ims.size(), 2); + + shared_ptr interest = makeInterest("/1"); + shared_ptr found = ims.find(*interest); + BOOST_CHECK(found == nullptr); +} + +BOOST_AUTO_TEST_CASE(ArrivalQueue2) +{ + InMemoryStorageFifo ims; + + ims.insert(*makeData("/1")); + ims.insert(*makeData("/2")); + ims.insert(*makeData("/3")); + + ims.evictItem(); + BOOST_CHECK_EQUAL(ims.size(), 2); + + shared_ptr interest1 = makeInterest("/1"); + shared_ptr found1 = ims.find(*interest1); + BOOST_CHECK(found1 == nullptr); + + ims.insert(*makeData("/4")); + + ims.evictItem(); + BOOST_CHECK_EQUAL(ims.size(), 2); + + shared_ptr interest2 = makeInterest("/2"); + shared_ptr found2 = ims.find(*interest2); + BOOST_CHECK(found2 == nullptr); +} + +BOOST_AUTO_TEST_CASE(MemoryPoolSizeZeroBug) // Bug #4769 +{ + InMemoryStorageFifo ims; + + BOOST_CHECK_EQUAL(ims.getCapacity(), 16); + for (int i = 1; i < 5; ++i) { + ims.insert(*makeData(to_string(i))); + ims.erase(Name(to_string(i))); + } + + BOOST_CHECK_EQUAL(ims.getCapacity(), 16); + ims.insert(*makeData("/5")); + BOOST_CHECK_EQUAL(ims.getCapacity(), 16); +} + +BOOST_AUTO_TEST_SUITE_END() // TestInMemoryStorageFifo +BOOST_AUTO_TEST_SUITE_END() // Ims + +} // namespace tests +} // namespace ndn diff --git a/tests/unit-tests/util/in-memory-storage-lfu.t.cpp b/tests/unit/ims/in-memory-storage-lfu.t.cpp similarity index 88% rename from tests/unit-tests/util/in-memory-storage-lfu.t.cpp rename to tests/unit/ims/in-memory-storage-lfu.t.cpp index bc52b30b1..8756856bc 100644 --- a/tests/unit-tests/util/in-memory-storage-lfu.t.cpp +++ b/tests/unit/ims/in-memory-storage-lfu.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,21 +19,18 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "util/in-memory-storage-lfu.hpp" -#include "security/key-chain.hpp" +#include "ndn-cxx/ims/in-memory-storage-lfu.hpp" -#include "boost-test.hpp" -#include "../make-interest-data.hpp" +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" namespace ndn { -namespace util { namespace tests { using namespace ndn::tests; -BOOST_AUTO_TEST_SUITE(Util) -BOOST_AUTO_TEST_SUITE(TestInMemoryStorage) -BOOST_AUTO_TEST_SUITE(Lfu) +BOOST_AUTO_TEST_SUITE(Ims) +BOOST_AUTO_TEST_SUITE(TestInMemoryStorageLfu) BOOST_AUTO_TEST_CASE(FrequencyQueue) { @@ -131,10 +128,8 @@ BOOST_AUTO_TEST_CASE(FrequencyQueue2) BOOST_CHECK_EQUAL(found3->getName(), name3); } -BOOST_AUTO_TEST_SUITE_END() // Lfu -BOOST_AUTO_TEST_SUITE_END() // TestInMemoryStorage -BOOST_AUTO_TEST_SUITE_END() // Util +BOOST_AUTO_TEST_SUITE_END() // TestInMemoryStorageLfu +BOOST_AUTO_TEST_SUITE_END() // Ims } // namespace tests -} // namespace util } // namespace ndn diff --git a/tests/unit-tests/util/in-memory-storage-lru.t.cpp b/tests/unit/ims/in-memory-storage-lru.t.cpp similarity index 88% rename from tests/unit-tests/util/in-memory-storage-lru.t.cpp rename to tests/unit/ims/in-memory-storage-lru.t.cpp index 758598712..aeeb846cb 100644 --- a/tests/unit-tests/util/in-memory-storage-lru.t.cpp +++ b/tests/unit/ims/in-memory-storage-lru.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,21 +19,18 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "util/in-memory-storage-lru.hpp" -#include "security/key-chain.hpp" +#include "ndn-cxx/ims/in-memory-storage-lru.hpp" -#include "boost-test.hpp" -#include "../make-interest-data.hpp" +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" namespace ndn { -namespace util { namespace tests { using namespace ndn::tests; -BOOST_AUTO_TEST_SUITE(Util) -BOOST_AUTO_TEST_SUITE(TestInMemoryStorage) -BOOST_AUTO_TEST_SUITE(Lru) +BOOST_AUTO_TEST_SUITE(Ims) +BOOST_AUTO_TEST_SUITE(TestInMemoryStorageLru) BOOST_AUTO_TEST_CASE(UsedTimeQueue) { @@ -133,10 +130,8 @@ BOOST_AUTO_TEST_CASE(UsedTimeQueue2) BOOST_CHECK_EQUAL(found3->getName(), name3); } -BOOST_AUTO_TEST_SUITE_END() // Lru -BOOST_AUTO_TEST_SUITE_END() // TestInMemoryStorage -BOOST_AUTO_TEST_SUITE_END() // Util +BOOST_AUTO_TEST_SUITE_END() // TestInMemoryStorageLru +BOOST_AUTO_TEST_SUITE_END() // Ims } // namespace tests -} // namespace util } // namespace ndn diff --git a/tests/unit/ims/in-memory-storage-persistent.t.cpp b/tests/unit/ims/in-memory-storage-persistent.t.cpp new file mode 100644 index 000000000..3758cc2a8 --- /dev/null +++ b/tests/unit/ims/in-memory-storage-persistent.t.cpp @@ -0,0 +1,83 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/ims/in-memory-storage-persistent.hpp" + +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" + +namespace ndn { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Ims) +BOOST_AUTO_TEST_SUITE(TestInMemoryStoragePersistent) + +BOOST_AUTO_TEST_CASE(GetLimit) +{ + InMemoryStoragePersistent ims; + + BOOST_CHECK_EQUAL(ims.getLimit(), -1); +} + +BOOST_AUTO_TEST_CASE(InsertAndDouble) +{ + InMemoryStoragePersistent ims; + size_t initialCapacity = ims.getCapacity(); + + for (size_t i = 0; i < initialCapacity + 1; i++) { + shared_ptr data = makeData(to_string(i)); + data->setFreshnessPeriod(5000_ms); + signData(data); + ims.insert(*data); + } + + BOOST_CHECK_EQUAL(ims.size(), initialCapacity + 1); + + BOOST_CHECK_EQUAL(ims.getCapacity(), initialCapacity * 2); +} + +BOOST_AUTO_TEST_CASE(EraseAndShrink) +{ + InMemoryStoragePersistent ims; + + auto capacity = ims.getCapacity() * 2; + ims.setCapacity(capacity); + + Name name("/1"); + shared_ptr data = makeData(name); + data->setFreshnessPeriod(5000_ms); + signData(data); + ims.insert(*data); + BOOST_CHECK_EQUAL(ims.size(), 1); + + ims.erase(name); + + BOOST_CHECK_EQUAL(ims.size(), 0); + BOOST_CHECK_EQUAL(ims.getCapacity(), capacity / 2); +} + +BOOST_AUTO_TEST_SUITE_END() // TestInMemoryStoragePersistent +BOOST_AUTO_TEST_SUITE_END() // Ims + +} // namespace tests +} // namespace ndn diff --git a/tests/unit/ims/in-memory-storage.t.cpp b/tests/unit/ims/in-memory-storage.t.cpp new file mode 100644 index 000000000..ca1fc3576 --- /dev/null +++ b/tests/unit/ims/in-memory-storage.t.cpp @@ -0,0 +1,614 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/ims/in-memory-storage.hpp" +#include "ndn-cxx/ims/in-memory-storage-fifo.hpp" +#include "ndn-cxx/ims/in-memory-storage-lfu.hpp" +#include "ndn-cxx/ims/in-memory-storage-lru.hpp" +#include "ndn-cxx/ims/in-memory-storage-persistent.hpp" +#include "ndn-cxx/security/signature-sha256-with-rsa.hpp" +#include "ndn-cxx/util/sha256.hpp" + +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" +#include "tests/unit/unit-test-time-fixture.hpp" + +#include + +namespace ndn { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Ims) +BOOST_AUTO_TEST_SUITE(TestInMemoryStorage) + +using InMemoryStorages = boost::mpl::vector; + +BOOST_AUTO_TEST_CASE_TEMPLATE(Insertion, T, InMemoryStorages) +{ + T ims; + + ims.insert(*makeData("/a")); + ims.insert(*makeData("/b")); + ims.insert(*makeData("/c")); + ims.insert(*makeData("/d")); + + BOOST_CHECK_EQUAL(ims.size(), 4); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(Insertion2, T, InMemoryStorages) +{ + T ims; + + Name name("/a"); + + uint32_t content1 = 1; + shared_ptr data1 = makeData(name); + data1->setFreshnessPeriod(99999_ms); + data1->setContent(reinterpret_cast(&content1), sizeof(content1)); + signData(data1); + ims.insert(*data1); + + uint32_t content2 = 2; + shared_ptr data2 = makeData(name); + data2->setFreshnessPeriod(99999_ms); + data2->setContent(reinterpret_cast(&content2), sizeof(content2)); + signData(data2); + ims.insert(*data2); + + BOOST_CHECK_EQUAL(ims.size(), 2); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(DuplicateInsertion, T, InMemoryStorages) +{ + T ims; + + shared_ptr data0 = makeData("/insert/smth"); + ims.insert(*data0); + + shared_ptr data = makeData("/insert/duplicate"); + ims.insert(*data); + + ims.insert(*data); + BOOST_CHECK_EQUAL(ims.size(), 2); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(DuplicateInsertion2, T, InMemoryStorages) +{ + T ims; + + shared_ptr data = makeData("/insert/duplicate"); + ims.insert(*data); + + ims.insert(*data); + BOOST_CHECK_EQUAL(ims.size(), 1); + + shared_ptr data2 = makeData("/insert/original"); + ims.insert(*data2); + BOOST_CHECK_EQUAL(ims.size(), 2); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndFind, T, InMemoryStorages) +{ + T ims; + + Name name("/insert/and/find"); + + shared_ptr data = makeData(name); + ims.insert(*data); + + shared_ptr interest = makeInterest(name); + + shared_ptr found = ims.find(*interest); + BOOST_CHECK(found != nullptr); + BOOST_CHECK_EQUAL(data->getName(), found->getName()); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndNotFind, T, InMemoryStorages) +{ + T ims; + + Name name("/insert/and/find"); + shared_ptr data = makeData(name); + ims.insert(*data); + + Name name2("/not/find"); + shared_ptr interest = makeInterest(name2); + + shared_ptr found = ims.find(*interest); + + BOOST_CHECK_EQUAL(found.get(), static_cast(0)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndFindByName, T, InMemoryStorages) +{ + T ims; + + Name name("/insert/and/find"); + + shared_ptr data = makeData(name); + ims.insert(*data); + + shared_ptr found = ims.find(name); + BOOST_CHECK(found != nullptr); + BOOST_CHECK_EQUAL(data->getName(), found->getName()); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndFindByFullName, T, InMemoryStorages) +{ + T ims; + + Name name("/insert/and/find"); + + shared_ptr data = makeData(name); + ims.insert(*data); + + shared_ptr found = ims.find(data->getFullName()); + BOOST_CHECK(found != nullptr); + BOOST_CHECK_EQUAL(data->getFullName(), found->getFullName()); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndNotFindByName, T, InMemoryStorages) +{ + T ims; + + Name name("/insert/and/find"); + shared_ptr data = makeData(name); + ims.insert(*data); + + Name name2("/not/find"); + + shared_ptr found = ims.find(name2); + BOOST_CHECK(found == nullptr); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndNotFindByFullName, T, InMemoryStorages) +{ + T ims; + + Name name("/a"); + uint32_t content1 = 1; + shared_ptr data1 = makeData(name); + data1->setContent(reinterpret_cast(&content1), sizeof(content1)); + signData(data1); + ims.insert(*data1); + + uint32_t content2 = 2; + shared_ptr data2 = makeData(name); + data2->setContent(reinterpret_cast(&content2), sizeof(content2)); + signData(data2); + + shared_ptr found = ims.find(data2->getFullName()); + BOOST_CHECK(found == nullptr); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndEraseByName, T, InMemoryStorages) +{ + T ims; + + Name name("/insertandremovebyname"); + + uint32_t content1 = 1; + shared_ptr data1 = makeData(name); + data1->setFreshnessPeriod(99999_ms); + data1->setContent(reinterpret_cast(&content1), sizeof(content1)); + signData(data1); + ims.insert(*data1); + + uint32_t content2 = 2; + shared_ptr data2 = makeData(name); + data2->setFreshnessPeriod(99999_ms); + data2->setContent(reinterpret_cast(&content2), sizeof(content2)); + signData(data2); + ims.insert(*data2); + + shared_ptr data3 = makeData("/insertandremovebyname/1"); + ims.insert(*data3); + + shared_ptr data4 = makeData("/insertandremovebyname/2"); + ims.insert(*data4); + + BOOST_CHECK_EQUAL(ims.size(), 4); + + ims.erase(data1->getFullName(), false); + BOOST_CHECK_EQUAL(ims.size(), 3); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndEraseByPrefix, T, InMemoryStorages) +{ + T ims; + + shared_ptr data = makeData("/a"); + ims.insert(*data); + + shared_ptr data2 = makeData("/b"); + ims.insert(*data2); + + shared_ptr data3 = makeData("/c"); + ims.insert(*data3); + + shared_ptr data4 = makeData("/d"); + ims.insert(*data4); + + shared_ptr data5 = makeData("/c/c/1/2/3/4/5/6"); + ims.insert(*data5); + + shared_ptr data6 = makeData("/c/c/1/2/3"); + ims.insert(*data6); + + shared_ptr data7 = makeData("/c/c/1"); + ims.insert(*data7); + + BOOST_CHECK_EQUAL(ims.size(), 7); + + Name name("/c"); + ims.erase(name); + BOOST_CHECK_EQUAL(ims.size(), 3); + BOOST_CHECK_EQUAL(ims.getCapacity(), 16); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(DigestCalculation, T, InMemoryStorages) +{ + shared_ptr data = makeData("/digest/compute"); + + ConstBufferPtr digest1 = util::Sha256::computeDigest(data->wireEncode().wire(), data->wireEncode().size()); + BOOST_CHECK_EQUAL(digest1->size(), 32); + + InMemoryStorageEntry entry; + entry.setData(*data); + + BOOST_CHECK_EQUAL_COLLECTIONS(digest1->begin(), digest1->end(), + entry.getFullName()[-1].value_begin(), + entry.getFullName()[-1].value_end()); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(Iterator, T, InMemoryStorages) +{ + T ims; + + BOOST_CONCEPT_ASSERT((boost::InputIterator)); + + for (int i = 0; i < 10; i++) { + std::ostringstream convert; + convert << i; + Name name("/" + convert.str()); + shared_ptr data = makeData(name); + ims.insert(*data); + } + + InMemoryStorage::const_iterator it = ims.begin(); + InMemoryStorage::const_iterator tmp1 = it; + BOOST_REQUIRE(tmp1 == it); + InMemoryStorage::const_iterator tmp2 = tmp1++; + BOOST_REQUIRE(tmp2 != tmp1); + tmp2 = ++tmp1; + BOOST_REQUIRE(tmp2 == tmp1); + + int i = 0; + for (; it != ims.end(); it++) { + std::ostringstream convert; + convert << i; + Name name("/" + convert.str()); + BOOST_CHECK_EQUAL(it->getName(), name); + BOOST_CHECK_EQUAL((*it).getName(), name); + i++; + } +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(InsertCanonical, T, InMemoryStorages) +{ + T ims; + + shared_ptr data = makeData("/a"); + ims.insert(*data); + + shared_ptr data2 = makeData("/b"); + ims.insert(*data2); + + shared_ptr data3 = makeData("/c"); + ims.insert(*data3); + + shared_ptr data4 = makeData("/d"); + ims.insert(*data4); + + shared_ptr data5 = makeData("/c/c/1/2/3/4/5/6"); + ims.insert(*data5); + + shared_ptr data6 = makeData("/c/c/1/2/3"); + ims.insert(*data6); + + shared_ptr data7 = makeData("/c/c/1"); + ims.insert(*data7); + + // avoid "test case [...] did not check any assertions" message from Boost.Test + BOOST_CHECK(true); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(EraseCanonical, T, InMemoryStorages) +{ + T ims; + + shared_ptr data = makeData("/a"); + ims.insert(*data); + + shared_ptr data2 = makeData("/b"); + ims.insert(*data2); + + shared_ptr data3 = makeData("/c"); + ims.insert(*data3); + + shared_ptr data4 = makeData("/d"); + ims.insert(*data4); + + shared_ptr data5 = makeData("/c/c/1/2/3/4/5/6"); + ims.insert(*data5); + + shared_ptr data6 = makeData("/c/c/1/2/3"); + ims.insert(*data6); + + shared_ptr data7 = makeData("/c/c/1"); + ims.insert(*data7); + + ConstBufferPtr digest1 = util::Sha256::computeDigest(data->wireEncode().wire(), data->wireEncode().size()); + + Name name("/a"); + ims.erase(name); + BOOST_CHECK_EQUAL(ims.size(), 6); +} + +using InMemoryStoragesLimited = boost::mpl::vector; + +BOOST_AUTO_TEST_CASE_TEMPLATE(SetCapacity, T, InMemoryStoragesLimited) +{ + T ims; + + ims.setCapacity(18); + for (int i = 1; i < 19; ++i) { + ims.insert(*makeData(to_string(i))); + } + BOOST_CHECK_EQUAL(ims.size(), 18); + + ims.setCapacity(16); + BOOST_CHECK_EQUAL(ims.size(), 16); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(GetLimit, T, InMemoryStoragesLimited) +{ + T ims(10000); + BOOST_CHECK_EQUAL(ims.getLimit(), 10000); + + T ims2(4); + BOOST_CHECK_EQUAL(ims2.getLimit(), 4); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndDouble, T, InMemoryStoragesLimited) +{ + T ims(40); + size_t initialCapacity = ims.getCapacity(); + + for (size_t i = 0; i < initialCapacity + 1; i++) { + shared_ptr data = makeData(to_string(i)); + data->setFreshnessPeriod(5000_ms); + signData(data); + ims.insert(*data); + } + + BOOST_CHECK_EQUAL(ims.size(), initialCapacity + 1); + BOOST_CHECK_EQUAL(ims.getCapacity(), initialCapacity * 2); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndEvict, T, InMemoryStoragesLimited) +{ + T ims(2); + + Name name("/insert/1"); + shared_ptr data = makeData(name); + ims.insert(*data); + + Name name2("/insert/2"); + shared_ptr data2 = makeData(name2); + ims.insert(*data2); + + Name name3("/insert/3"); + shared_ptr data3 = makeData(name3); + ims.insert(*data3); + + BOOST_CHECK_EQUAL(ims.size(), 2); + + shared_ptr interest = makeInterest(name); + shared_ptr found = ims.find(*interest); + BOOST_CHECK(found == nullptr); +} + +// Find function is implemented at the base case, so it's sufficient to test for one derived class. +class FindFixture : public tests::UnitTestTimeFixture +{ +protected: + FindFixture() + : m_ims(io) + { + } + + Name + insert(uint32_t id, const Name& name, + const std::function& modifyData = nullptr, + const time::milliseconds& freshWindow = InMemoryStorage::INFINITE_WINDOW) + { + auto data = makeData(name); + data->setContent(reinterpret_cast(&id), sizeof(id)); + + if (modifyData != nullptr) { + modifyData(*data); + } + + data->wireEncode(); + m_ims.insert(*data, freshWindow); + + return data->getFullName(); + } + + Interest& + startInterest(const Name& name) + { + m_interest = makeInterest(name, false); + return *m_interest; + } + + uint32_t + find() + { + shared_ptr found = m_ims.find(*m_interest); + if (found == 0) { + return 0; + } + const Block& content = found->getContent(); + if (content.value_size() != sizeof(uint32_t)) { + return 0; + } + uint32_t id = 0; + std::memcpy(&id, content.value(), sizeof(id)); + return id; + } + +protected: + InMemoryStoragePersistent m_ims; + shared_ptr m_interest; +}; + +BOOST_FIXTURE_TEST_SUITE(Find, FindFixture) + +BOOST_AUTO_TEST_CASE(ExactName) +{ + insert(1, "/"); + insert(2, "/A"); + insert(3, "/A/B"); + insert(4, "/A/C"); + insert(5, "/D"); + + startInterest("/A"); + BOOST_CHECK_EQUAL(find(), 2); +} + +BOOST_AUTO_TEST_CASE(ExactName_CanBePrefix) +{ + insert(1, "/"); + insert(2, "/A"); + insert(3, "/A/B"); + insert(4, "/A/C"); + insert(5, "/D"); + + startInterest("/A") + .setCanBePrefix(true); + BOOST_CHECK_EQUAL(find(), 2); +} + +BOOST_AUTO_TEST_CASE(FullName) +{ + Name n1 = insert(1, "/A"); + Name n2 = insert(2, "/A"); + + startInterest(n1); + BOOST_CHECK_EQUAL(find(), 1); + + startInterest(n2); + BOOST_CHECK_EQUAL(find(), 2); +} + +BOOST_AUTO_TEST_CASE(FullName_EmptyDataName) +{ + Name n1 = insert(1, "/"); + Name n2 = insert(2, "/"); + + startInterest(n1); + BOOST_CHECK_EQUAL(find(), 1); + + startInterest(n2); + BOOST_CHECK_EQUAL(find(), 2); +} + +BOOST_AUTO_TEST_CASE(PrefixName) +{ + insert(1, "/A"); + insert(2, "/B/p/1"); + insert(3, "/B/p/2"); + insert(4, "/B/q/1"); + insert(5, "/B/q/2"); + insert(6, "/C"); + + startInterest("/B") + .setCanBePrefix(true); + BOOST_CHECK_EQUAL(find(), 2); +} + +BOOST_AUTO_TEST_CASE(PrefixName_NoCanBePrefix) +{ + insert(1, "/B/p/1"); + + startInterest("/B"); + BOOST_CHECK_EQUAL(find(), 0); +} + +BOOST_AUTO_TEST_CASE(MustBeFresh) +{ + insert(1, "/A/1"); // omitted FreshnessPeriod means FreshnessPeriod = 0 ms + insert(2, "/A/2", [] (Data& data) { data.setFreshnessPeriod(0_s); }); + insert(3, "/A/3", [] (Data& data) { data.setFreshnessPeriod(1_s); }, 1_s); + insert(4, "/A/4", [] (Data& data) { data.setFreshnessPeriod(1_h); }, 1_h); + + // lookup at exact same moment as insertion is not tested because this won't happen in reality + + advanceClocks(500_ms); // @500ms + startInterest("/A") + .setCanBePrefix(true) + .setMustBeFresh(true); + BOOST_CHECK_EQUAL(find(), 3); + + advanceClocks(1500_ms); // @2s + startInterest("/A") + .setCanBePrefix(true) + .setMustBeFresh(true); + BOOST_CHECK_EQUAL(find(), 4); + + advanceClocks(3500_s); // @3502s + startInterest("/A") + .setCanBePrefix(true) + .setMustBeFresh(true); + BOOST_CHECK_EQUAL(find(), 4); + + advanceClocks(3500_s); // @7002s + startInterest("/A") + .setCanBePrefix(true) + .setMustBeFresh(true); + BOOST_CHECK_EQUAL(find(), 0); +} + +BOOST_AUTO_TEST_SUITE_END() // Find +BOOST_AUTO_TEST_SUITE_END() // TestInMemoryStorage +BOOST_AUTO_TEST_SUITE_END() // Ims + +} // namespace tests +} // namespace ndn diff --git a/tests/unit/interest-filter.t.cpp b/tests/unit/interest-filter.t.cpp new file mode 100644 index 000000000..100429c01 --- /dev/null +++ b/tests/unit/interest-filter.t.cpp @@ -0,0 +1,76 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/interest-filter.hpp" +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/signature-sha256-with-rsa.hpp" +#include "ndn-cxx/security/digest-sha256.hpp" +#include "ndn-cxx/util/dummy-client-face.hpp" + +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(TestInterestFilter) + +BOOST_AUTO_TEST_CASE(Matching) +{ + BOOST_CHECK_EQUAL(InterestFilter("/a").doesMatch("/a/b"), true); + BOOST_CHECK_EQUAL(InterestFilter("/a/b").doesMatch("/a/b"), true); + BOOST_CHECK_EQUAL(InterestFilter("/a/b/c").doesMatch("/a/b"), false); + + BOOST_CHECK_EQUAL(InterestFilter("/a", "").doesMatch("/a/b"), true); + BOOST_CHECK_EQUAL(InterestFilter("/a/b", "").doesMatch("/a/b"), false); + + BOOST_CHECK_EQUAL(InterestFilter("/a/b", "").doesMatch("/a/b/c/b"), false); + BOOST_CHECK_EQUAL(InterestFilter("/a/b", "<>*").doesMatch("/a/b/c/b"), true); + + BOOST_CHECK_EQUAL(InterestFilter("/a", "").doesMatch("/a/b/c/d"), false); + BOOST_CHECK_EQUAL(InterestFilter("/a", "<>*").doesMatch("/a/b/c/d"), true); + BOOST_CHECK_EQUAL(InterestFilter("/a", "<>*").doesMatch("/a/b"), true); + BOOST_CHECK_EQUAL(InterestFilter("/a", "<>+").doesMatch("/a/b"), false); + BOOST_CHECK_EQUAL(InterestFilter("/a", "<>+").doesMatch("/a/b/c"), true); +} + +BOOST_AUTO_TEST_CASE(RegexConvertToName) +{ + util::DummyClientFace face; + face.setInterestFilter(InterestFilter("/Hello/World", "<>?"), + [] (const Name&, const Interest&) { BOOST_ERROR("unexpected Interest"); }); + face.processEvents(1_ms); + BOOST_CHECK_THROW(face.receive(*makeInterest("/Hello/World/a/b/c")), InterestFilter::Error); +} + +BOOST_AUTO_TEST_CASE(AllowLoopback) +{ + InterestFilter filter("/A"); + BOOST_CHECK_EQUAL(filter.allowsLoopback(), true); + BOOST_CHECK_EQUAL(&filter.allowLoopback(false), &filter); + BOOST_CHECK_EQUAL(filter.allowsLoopback(), false); +} + +BOOST_AUTO_TEST_SUITE_END() // TestInterestFilter + +} // namespace tests +} // namespace ndn diff --git a/tests/unit/interest.t.cpp b/tests/unit/interest.t.cpp new file mode 100644 index 000000000..7b8f8438d --- /dev/null +++ b/tests/unit/interest.t.cpp @@ -0,0 +1,790 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/interest.hpp" +#include "ndn-cxx/data.hpp" + +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(TestInterest) + +class DisableAutoCheckParametersDigest +{ +public: + DisableAutoCheckParametersDigest() + : m_saved(Interest::getAutoCheckParametersDigest()) + { + Interest::setAutoCheckParametersDigest(false); + } + + ~DisableAutoCheckParametersDigest() + { + Interest::setAutoCheckParametersDigest(m_saved); + } + +private: + bool m_saved; +}; + +BOOST_AUTO_TEST_CASE(DefaultConstructor) +{ + Interest i; + BOOST_CHECK_EQUAL(i.hasWire(), false); + BOOST_CHECK_EQUAL(i.getName(), "/"); + BOOST_CHECK_EQUAL(i.getCanBePrefix(), true); + BOOST_CHECK_EQUAL(i.getMustBeFresh(), false); + BOOST_CHECK_EQUAL(i.getForwardingHint().empty(), true); + BOOST_CHECK_EQUAL(i.hasNonce(), false); + BOOST_CHECK_EQUAL(i.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME); + BOOST_CHECK(i.getHopLimit() == nullopt); + BOOST_CHECK_EQUAL(i.hasApplicationParameters(), false); + BOOST_CHECK_EQUAL(i.getApplicationParameters().isValid(), false); + BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true); +} + +BOOST_AUTO_TEST_SUITE(Encode) + +BOOST_AUTO_TEST_CASE(Basic) +{ + const uint8_t WIRE[] = { + 0x05, 0x1c, // Interest + 0x07, 0x14, // Name + 0x08, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, // GenericNameComponent + 0x08, 0x03, 0x6e, 0x64, 0x6e, // GenericNameComponent + 0x08, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, // GenericNameComponent + 0x0a, 0x04, // Nonce + 0x01, 0x00, 0x00, 0x00, + }; + + Interest i1; + i1.setName("/local/ndn/prefix"); + i1.setCanBePrefix(false); + i1.setNonce(1); + BOOST_CHECK_EQUAL(i1.isParametersDigestValid(), true); + + Block wire1 = i1.wireEncode(); + BOOST_CHECK_EQUAL_COLLECTIONS(wire1.begin(), wire1.end(), WIRE, WIRE + sizeof(WIRE)); + + Interest i2(wire1); + BOOST_CHECK_EQUAL(i2.getName(), "/local/ndn/prefix"); + BOOST_CHECK_EQUAL(i2.getCanBePrefix(), false); + BOOST_CHECK_EQUAL(i2.getMustBeFresh(), false); + BOOST_CHECK_EQUAL(i2.getForwardingHint().empty(), true); + BOOST_CHECK_EQUAL(i2.hasNonce(), true); + BOOST_CHECK_EQUAL(i2.getNonce(), 1); + BOOST_CHECK_EQUAL(i2.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME); + BOOST_CHECK(i2.getHopLimit() == nullopt); + BOOST_CHECK_EQUAL(i2.hasApplicationParameters(), false); + BOOST_CHECK_EQUAL(i2.getApplicationParameters().isValid(), false); +} + +BOOST_AUTO_TEST_CASE(WithParameters) +{ + const uint8_t WIRE[] = { + 0x05, 0x44, // Interest + 0x07, 0x36, // Name + 0x08, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, // GenericNameComponent + 0x08, 0x03, 0x6e, 0x64, 0x6e, // GenericNameComponent + 0x08, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, // GenericNameComponent + 0x02, 0x20, // ParametersSha256DigestComponent + 0xff, 0x91, 0x00, 0xe0, 0x4e, 0xaa, 0xdc, 0xf3, 0x06, 0x74, 0xd9, 0x80, + 0x26, 0xa0, 0x51, 0xba, 0x25, 0xf5, 0x6b, 0x69, 0xbf, 0xa0, 0x26, 0xdc, + 0xcc, 0xd7, 0x2c, 0x6e, 0xa0, 0xf7, 0x31, 0x5a, + 0x0a, 0x04, // Nonce + 0x01, 0x00, 0x00, 0x00, + 0x24, 0x04, // ApplicationParameters + 0xc0, 0xc1, 0xc2, 0xc3 + }; + + Interest i1; + i1.setName("/local/ndn/prefix"); + i1.setCanBePrefix(false); + i1.setNonce(1); + i1.setApplicationParameters("2404C0C1C2C3"_block); + BOOST_CHECK_EQUAL(i1.isParametersDigestValid(), true); + + Block wire1 = i1.wireEncode(); + BOOST_CHECK_EQUAL_COLLECTIONS(wire1.begin(), wire1.end(), WIRE, WIRE + sizeof(WIRE)); + + Interest i2(wire1); + BOOST_CHECK_EQUAL(i2.getName(), + "/local/ndn/prefix/params-sha256=ff9100e04eaadcf30674d98026a051ba25f56b69bfa026dcccd72c6ea0f7315a"); + BOOST_CHECK_EQUAL(i2.getCanBePrefix(), false); + BOOST_CHECK_EQUAL(i2.getMustBeFresh(), false); + BOOST_CHECK_EQUAL(i2.getForwardingHint().empty(), true); + BOOST_CHECK_EQUAL(i2.hasNonce(), true); + BOOST_CHECK_EQUAL(i2.getNonce(), 1); + BOOST_CHECK_EQUAL(i2.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME); + BOOST_CHECK(i2.getHopLimit() == nullopt); + BOOST_CHECK_EQUAL(i2.hasApplicationParameters(), true); + BOOST_CHECK_EQUAL(i2.getApplicationParameters(), "2404C0C1C2C3"_block); +} + +BOOST_AUTO_TEST_CASE(Full) +{ + const uint8_t WIRE[] = { + 0x05, 0x5c, // Interest + 0x07, 0x36, // Name + 0x08, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, // GenericNameComponent + 0x08, 0x03, 0x6e, 0x64, 0x6e, // GenericNameComponent + 0x08, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, // GenericNameComponent + 0x02, 0x20, // ParametersSha256DigestComponent + 0xff, 0x91, 0x00, 0xe0, 0x4e, 0xaa, 0xdc, 0xf3, 0x06, 0x74, 0xd9, 0x80, + 0x26, 0xa0, 0x51, 0xba, 0x25, 0xf5, 0x6b, 0x69, 0xbf, 0xa0, 0x26, 0xdc, + 0xcc, 0xd7, 0x2c, 0x6e, 0xa0, 0xf7, 0x31, 0x5a, + 0x21, 0x00, // CanBePrefix + 0x12, 0x00, // MustBeFresh + 0x1e, 0x0b, // ForwardingHint + 0x1f, 0x09, // Delegation List + 0x1e, 0x02, + 0x3e, 0x15, + 0x07, 0x03, + 0x08, 0x01, 0x48, + 0x0a, 0x04, // Nonce + 0x4a, 0xcb, 0x1e, 0x4c, + 0x0c, 0x02, // InterestLifetime + 0x76, 0xa1, + 0x22, 0x01, // HopLimit + 0xdc, + 0x24, 0x04, // ApplicationParameters + 0xc0, 0xc1, 0xc2, 0xc3 + }; + + Interest i1; + i1.setName("/local/ndn/prefix"); + i1.setMustBeFresh(true); + i1.setCanBePrefix(true); + i1.setForwardingHint(DelegationList({{15893, "/H"}})); + i1.setNonce(0x4c1ecb4a); + i1.setInterestLifetime(30369_ms); + i1.setHopLimit(220); + i1.setApplicationParameters("2404C0C1C2C3"_block); + BOOST_CHECK_EQUAL(i1.isParametersDigestValid(), true); + + Block wire1 = i1.wireEncode(); + BOOST_CHECK_EQUAL_COLLECTIONS(wire1.begin(), wire1.end(), WIRE, WIRE + sizeof(WIRE)); + + Interest i2(wire1); + BOOST_CHECK_EQUAL(i2.getName(), + "/local/ndn/prefix/params-sha256=ff9100e04eaadcf30674d98026a051ba25f56b69bfa026dcccd72c6ea0f7315a"); + BOOST_CHECK_EQUAL(i2.getCanBePrefix(), true); + BOOST_CHECK_EQUAL(i2.getMustBeFresh(), true); + BOOST_CHECK_EQUAL(i2.getForwardingHint(), DelegationList({{15893, "/H"}})); + BOOST_CHECK_EQUAL(i2.hasNonce(), true); + BOOST_CHECK_EQUAL(i2.getNonce(), 0x4c1ecb4a); + BOOST_CHECK_EQUAL(i2.getInterestLifetime(), 30369_ms); + BOOST_CHECK_EQUAL(*i2.getHopLimit(), 220); + BOOST_CHECK_EQUAL(i2.getApplicationParameters(), "2404C0C1C2C3"_block); +} + +BOOST_AUTO_TEST_CASE(MissingApplicationParameters) +{ + Interest i; + i.setName(Name("/A").appendParametersSha256DigestPlaceholder()); + i.setCanBePrefix(false); + BOOST_CHECK_EQUAL(i.isParametersDigestValid(), false); + BOOST_CHECK_THROW(i.wireEncode(), tlv::Error); +} + +BOOST_AUTO_TEST_CASE(MissingParametersSha256DigestComponent) +{ + // there's no way to create an Interest that fails this check via programmatic construction, + // so we have to decode an invalid Interest and force reencoding + + DisableAutoCheckParametersDigest disabler; + Interest i("050F 0703(080149) 0A04F000F000 2402CAFE"_block); + BOOST_CHECK_EQUAL(i.isParametersDigestValid(), false); + BOOST_CHECK_NO_THROW(i.wireEncode()); // this succeeds because it uses the cached wire encoding + + i.setNonce(42); // trigger reencoding + BOOST_CHECK_THROW(i.wireEncode(), tlv::Error); // now the check fails while attempting to reencode +} + +BOOST_AUTO_TEST_SUITE_END() // Encode + +class DecodeFixture +{ +protected: + DecodeFixture() + { + // initialize all elements to non-empty, to verify wireDecode clears them + i.setName("/A"); + i.setForwardingHint({{10309, "/F"}}); + i.setNonce(0x03d645a8); + i.setInterestLifetime(18554_ms); + i.setHopLimit(64); + i.setApplicationParameters("2404A0A1A2A3"_block); + } + +protected: + Interest i; +}; + +BOOST_FIXTURE_TEST_SUITE(Decode, DecodeFixture) + +BOOST_AUTO_TEST_CASE(NotAnInterest) +{ + BOOST_CHECK_THROW(i.wireDecode("4202CAFE"_block), tlv::Error); +} + +BOOST_AUTO_TEST_CASE(NameOnly) +{ + i.wireDecode("0505 0703(080149)"_block); + BOOST_CHECK_EQUAL(i.hasWire(), true); + BOOST_CHECK_EQUAL(i.getName(), "/I"); + BOOST_CHECK_EQUAL(i.getCanBePrefix(), false); + BOOST_CHECK_EQUAL(i.getMustBeFresh(), false); + BOOST_CHECK_EQUAL(i.getForwardingHint().empty(), true); + BOOST_CHECK_EQUAL(i.hasNonce(), false); + BOOST_CHECK_EQUAL(i.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME); + BOOST_CHECK(i.getHopLimit() == nullopt); + BOOST_CHECK_EQUAL(i.hasApplicationParameters(), false); + BOOST_CHECK_EQUAL(i.getApplicationParameters().isValid(), false); + + // modify then re-encode + i.setNonce(0x54657c95); + BOOST_CHECK_EQUAL(i.hasWire(), false); + BOOST_CHECK_EQUAL(i.wireEncode(), "050B 0703(080149) 0A04957C6554"_block); +} + +BOOST_AUTO_TEST_CASE(NameCanBePrefix) +{ + i.wireDecode("0507 0703(080149) 2100"_block); + BOOST_CHECK_EQUAL(i.hasWire(), true); + BOOST_CHECK_EQUAL(i.getName(), "/I"); + BOOST_CHECK_EQUAL(i.getCanBePrefix(), true); + BOOST_CHECK_EQUAL(i.getMustBeFresh(), false); + BOOST_CHECK_EQUAL(i.getForwardingHint().empty(), true); + BOOST_CHECK_EQUAL(i.hasNonce(), false); + BOOST_CHECK_EQUAL(i.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME); + BOOST_CHECK(i.getHopLimit() == nullopt); + BOOST_CHECK_EQUAL(i.hasApplicationParameters(), false); + BOOST_CHECK_EQUAL(i.getApplicationParameters().isValid(), false); +} + +BOOST_AUTO_TEST_CASE(FullWithoutParameters) +{ + i.wireDecode("0531 0703(080149) " + "FC00 2100 FC00 1200 FC00 1E0B(1F09 1E023E15 0703080148) " + "FC00 0A044ACB1E4C FC00 0C0276A1 FC00 2201D6 FC00"_block); + BOOST_CHECK_EQUAL(i.getName(), "/I"); + BOOST_CHECK_EQUAL(i.getCanBePrefix(), true); + BOOST_CHECK_EQUAL(i.getMustBeFresh(), true); + BOOST_CHECK_EQUAL(i.getForwardingHint(), DelegationList({{15893, "/H"}})); + BOOST_CHECK_EQUAL(i.hasNonce(), true); + BOOST_CHECK_EQUAL(i.getNonce(), 0x4c1ecb4a); + BOOST_CHECK_EQUAL(i.getInterestLifetime(), 30369_ms); + BOOST_CHECK_EQUAL(*i.getHopLimit(), 214); + BOOST_CHECK_EQUAL(i.hasApplicationParameters(), false); + BOOST_CHECK_EQUAL(i.getApplicationParameters().isValid(), false); + + // encode without modification: retain original wire encoding + BOOST_CHECK_EQUAL(i.wireEncode().value_size(), 49); + + // modify then re-encode: unrecognized elements are discarded + i.setName("/J"); + BOOST_CHECK_EQUAL(i.wireEncode(), + "0523 0703(08014A) " + "2100 1200 1E0B(1F09 1E023E15 0703080148) " + "0A044ACB1E4C 0C0276A1 2201D6"_block); +} + +BOOST_AUTO_TEST_CASE(FullWithParameters) +{ + i.wireDecode("055B 0725(080149 0220F16DB273F40436A852063F864D5072B01EAD53151F5A688EA1560492BEBEDD05) " + "FC00 2100 FC00 1200 FC00 1E0B(1F09 1E023E15 0703080148) " + "FC00 0A044ACB1E4C FC00 0C0276A1 FC00 2201D6 FC00 2404C0C1C2C3 FC00"_block); + BOOST_CHECK_EQUAL(i.getName(), + "/I/params-sha256=f16db273f40436a852063f864d5072b01ead53151f5a688ea1560492bebedd05"); + BOOST_CHECK_EQUAL(i.getCanBePrefix(), true); + BOOST_CHECK_EQUAL(i.getMustBeFresh(), true); + BOOST_CHECK_EQUAL(i.getForwardingHint(), DelegationList({{15893, "/H"}})); + BOOST_CHECK_EQUAL(i.hasNonce(), true); + BOOST_CHECK_EQUAL(i.getNonce(), 0x4c1ecb4a); + BOOST_CHECK_EQUAL(i.getInterestLifetime(), 30369_ms); + BOOST_CHECK_EQUAL(*i.getHopLimit(), 214); + BOOST_CHECK_EQUAL(i.hasApplicationParameters(), true); + BOOST_CHECK_EQUAL(i.getApplicationParameters(), "2404C0C1C2C3"_block); + + // encode without modification: retain original wire encoding + BOOST_CHECK_EQUAL(i.wireEncode().value_size(), 91); + + // modify then re-encode: unrecognized elements after ApplicationParameters + // are preserved, the rest are discarded + i.setName("/J"); + BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true); + BOOST_CHECK_EQUAL(i.wireEncode(), + "054D 0725(08014A 0220F16DB273F40436A852063F864D5072B01EAD53151F5A688EA1560492BEBEDD05) " + "2100 1200 1E0B(1F09 1E023E15 0703080148) " + "0A044ACB1E4C 0C0276A1 2201D6 2404C0C1C2C3 FC00"_block); + + // modify ApplicationParameters: unrecognized elements are preserved + i.setApplicationParameters("2402CAFE"_block); + BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true); + BOOST_CHECK_EQUAL(i.wireEncode(), + "054B 0725(08014A 02205FDA67967EE302FC457E41B7D3D51BA6A9379574D193FD88F64954BF16C2927A) " + "2100 1200 1E0B(1F09 1E023E15 0703080148) " + "0A044ACB1E4C 0C0276A1 2201D6 2402CAFE FC00"_block); +} + +BOOST_AUTO_TEST_CASE(CriticalElementOutOfOrder) +{ + BOOST_CHECK_THROW(i.wireDecode( + "0529 2100 0703080149 1200 1E0B(1F09 1E023E15 0703080148) " + "0A044ACB1E4C 0C0276A1 2201D6 2404C0C1C2C3"_block), + tlv::Error); + BOOST_CHECK_THROW(i.wireDecode( + "0529 0703080149 1200 2100 1E0B(1F09 1E023E15 0703080148) " + "0A044ACB1E4C 0C0276A1 2201D6 2404C0C1C2C3"_block), + tlv::Error); + BOOST_CHECK_THROW(i.wireDecode( + "0529 0703080149 2100 1E0B(1F09 1E023E15 0703080148) 1200 " + "0A044ACB1E4C 0C0276A1 2201D6 2404C0C1C2C3"_block), + tlv::Error); + BOOST_CHECK_THROW(i.wireDecode( + "0529 0703080149 2100 1200 0A044ACB1E4C " + "1E0B(1F09 1E023E15 0703080148) 0C0276A1 2201D6 2404C0C1C2C3"_block), + tlv::Error); + BOOST_CHECK_THROW(i.wireDecode( + "0529 0703080149 2100 1200 1E0B(1F09 1E023E15 0703080148) " + "0C0276A1 0A044ACB1E4C 2201D6 2404C0C1C2C3"_block), + tlv::Error); + BOOST_CHECK_THROW(i.wireDecode( + "0529 0703080149 2100 1200 1E0B(1F09 1E023E15 0703080148) " + "0A044ACB1E4C 2201D6 0C0276A1 2404C0C1C2C3"_block), + tlv::Error); +} + +BOOST_AUTO_TEST_CASE(NonCriticalElementOutOfOrder) +{ + // duplicate HopLimit + i.wireDecode("0536 0725(080149 0220FF9100E04EAADCF30674D98026A051BA25F56B69BFA026DCCCD72C6EA0F7315A)" + "2201D6 2200 2404C0C1C2C3 22020101"_block); + BOOST_CHECK_EQUAL(i.getName(), + "/I/params-sha256=ff9100e04eaadcf30674d98026a051ba25f56b69bfa026dcccd72c6ea0f7315a"); + BOOST_CHECK_EQUAL(*i.getHopLimit(), 214); + BOOST_CHECK_EQUAL(i.hasApplicationParameters(), true); + BOOST_CHECK_EQUAL(i.getApplicationParameters(), "2404C0C1C2C3"_block); + + // duplicate ApplicationParameters + i.wireDecode("0541 0725(080149 0220FF9100E04EAADCF30674D98026A051BA25F56B69BFA026DCCCD72C6EA0F7315A)" + "2100 1200 0A044ACB1E4C 0C0276A1 2201D6 2404C0C1C2C3 2401EE"_block); + BOOST_CHECK_EQUAL(i.getName(), + "/I/params-sha256=ff9100e04eaadcf30674d98026a051ba25f56b69bfa026dcccd72c6ea0f7315a"); + BOOST_CHECK_EQUAL(*i.getHopLimit(), 214); + BOOST_CHECK_EQUAL(i.hasApplicationParameters(), true); + BOOST_CHECK_EQUAL(i.getApplicationParameters(), "2404C0C1C2C3"_block); +} + +BOOST_AUTO_TEST_CASE(MissingName) +{ + BOOST_CHECK_THROW(i.wireDecode("0500"_block), tlv::Error); + BOOST_CHECK_THROW(i.wireDecode("0502 1200"_block), tlv::Error); +} + +BOOST_AUTO_TEST_CASE(BadName) +{ + // empty + BOOST_CHECK_THROW(i.wireDecode("0502 0700"_block), tlv::Error); + + // more than one ParametersSha256DigestComponent + BOOST_CHECK_THROW(i.wireDecode("054C 074A(080149" + "02200000000000000000000000000000000000000000000000000000000000000000" + "080132" + "02200000000000000000000000000000000000000000000000000000000000000000)"_block), + tlv::Error); +} + +BOOST_AUTO_TEST_CASE(BadCanBePrefix) +{ + BOOST_CHECK_THROW(i.wireDecode("0508 0703080149 210102"_block), tlv::Error); +} + +BOOST_AUTO_TEST_CASE(BadMustBeFresh) +{ + BOOST_CHECK_THROW(i.wireDecode("0508 0703080149 120102"_block), tlv::Error); +} + +BOOST_AUTO_TEST_CASE(BadNonce) +{ + BOOST_CHECK_THROW(i.wireDecode("0507 0703080149 0A00"_block), tlv::Error); + BOOST_CHECK_THROW(i.wireDecode("050A 0703080149 0A0304C263"_block), tlv::Error); + BOOST_CHECK_THROW(i.wireDecode("050C 0703080149 0A05EFA420B262"_block), tlv::Error); +} + +BOOST_AUTO_TEST_CASE(BadHopLimit) +{ + BOOST_CHECK_THROW(i.wireDecode("0507 0703080149 2200"_block), tlv::Error); + BOOST_CHECK_THROW(i.wireDecode("0509 0703080149 22021356"_block), tlv::Error); +} + +BOOST_AUTO_TEST_CASE(BadParametersDigest) +{ + // ApplicationParameters without ParametersSha256DigestComponent + Block b1("0509 0703(080149) 2402CAFE"_block); + // ParametersSha256DigestComponent without ApplicationParameters + Block b2("0527 0725(080149 0220E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855)"_block); + // digest mismatch + Block b3("052B 0725(080149 02200000000000000000000000000000000000000000000000000000000000000000) " + "2402CAFE"_block); + + BOOST_CHECK_THROW(i.wireDecode(b1), tlv::Error); + BOOST_CHECK_THROW(i.wireDecode(b2), tlv::Error); + BOOST_CHECK_THROW(i.wireDecode(b3), tlv::Error); + + DisableAutoCheckParametersDigest disabler; + BOOST_CHECK_NO_THROW(i.wireDecode(b1)); + BOOST_CHECK_EQUAL(i.isParametersDigestValid(), false); + BOOST_CHECK_NO_THROW(i.wireDecode(b2)); + BOOST_CHECK_EQUAL(i.isParametersDigestValid(), false); + BOOST_CHECK_NO_THROW(i.wireDecode(b3)); + BOOST_CHECK_EQUAL(i.isParametersDigestValid(), false); +} + +BOOST_AUTO_TEST_CASE(UnrecognizedNonCriticalElementBeforeName) +{ + BOOST_CHECK_THROW(i.wireDecode("0507 FC00 0703080149"_block), tlv::Error); +} + +BOOST_AUTO_TEST_CASE(UnrecognizedCriticalElement) +{ + BOOST_CHECK_THROW(i.wireDecode("0507 0703080149 FB00"_block), tlv::Error); + // v0.2 packet with Selectors + BOOST_CHECK_THROW(i.wireDecode("0507 0703080149 09030D0101 0A0401000000"_block), tlv::Error); +} + +BOOST_AUTO_TEST_SUITE_END() // Decode + +BOOST_AUTO_TEST_CASE(MatchesData) +{ + auto interest = makeInterest("/A"); + + auto data = makeData("/A"); + BOOST_CHECK_EQUAL(interest->matchesData(*data), true); + + data->setName("/A/D"); + BOOST_CHECK_EQUAL(interest->matchesData(*data), false); // violates CanBePrefix + + interest->setCanBePrefix(true); + BOOST_CHECK_EQUAL(interest->matchesData(*data), true); + + interest->setMustBeFresh(true); + BOOST_CHECK_EQUAL(interest->matchesData(*data), false); // violates MustBeFresh + + data->setFreshnessPeriod(1_s); + BOOST_CHECK_EQUAL(interest->matchesData(*data), true); + + data->setName("/H/I"); + BOOST_CHECK_EQUAL(interest->matchesData(*data), false); // Name does not match + + data->wireEncode(); + interest = makeInterest(data->getFullName()); + BOOST_CHECK_EQUAL(interest->matchesData(*data), true); + + setNameComponent(*interest, -1, name::Component::fromEscapedString( + "sha256digest=0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(interest->matchesData(*data), false); // violates implicit digest +} + +BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(MatchesInterest, 1) +BOOST_AUTO_TEST_CASE(MatchesInterest) +{ + Interest interest; + interest.setName("/A") + .setCanBePrefix(true) + .setMustBeFresh(true) + .setForwardingHint({{1, "/H"}}) + .setNonce(2228) + .setInterestLifetime(5_s) + .setHopLimit(90); + + Interest other; + BOOST_CHECK_EQUAL(interest.matchesInterest(other), false); + + other.setName(interest.getName()); + BOOST_CHECK_EQUAL(interest.matchesInterest(other), false); + + other.setCanBePrefix(interest.getCanBePrefix()); + BOOST_CHECK_EQUAL(interest.matchesInterest(other), false); + + other.setMustBeFresh(interest.getMustBeFresh()); + BOOST_CHECK_EQUAL(interest.matchesInterest(other), false); // will match until #3162 implemented + + other.setForwardingHint(interest.getForwardingHint()); + BOOST_CHECK_EQUAL(interest.matchesInterest(other), true); + + other.setNonce(9336); + BOOST_CHECK_EQUAL(interest.matchesInterest(other), true); + + other.setInterestLifetime(3_s); + BOOST_CHECK_EQUAL(interest.matchesInterest(other), true); + + other.setHopLimit(31); + BOOST_CHECK_EQUAL(interest.matchesInterest(other), true); +} + +BOOST_AUTO_TEST_CASE(SetName) +{ + Interest i; + BOOST_CHECK_EQUAL(i.getName(), "/"); + i.setName("/A/B"); + BOOST_CHECK_EQUAL(i.getName(), "/A/B"); + i.setName("/I/params-sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + BOOST_CHECK_EQUAL(i.getName(), + "/I/params-sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + BOOST_CHECK_THROW(i.setName("/I" + "/params-sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + "/params-sha256=0000000000000000000000000000000000000000000000000000000000000000"), + std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(SetCanBePrefix) +{ + Interest i; + BOOST_CHECK_EQUAL(i.getCanBePrefix(), true); + i.setCanBePrefix(false); + BOOST_CHECK_EQUAL(i.getCanBePrefix(), false); + i.setCanBePrefix(true); + BOOST_CHECK_EQUAL(i.getCanBePrefix(), true); +} + +BOOST_AUTO_TEST_CASE(SetMustBeFresh) +{ + Interest i; + BOOST_CHECK_EQUAL(i.getMustBeFresh(), false); + i.setMustBeFresh(true); + BOOST_CHECK_EQUAL(i.getMustBeFresh(), true); + i.setMustBeFresh(false); + BOOST_CHECK_EQUAL(i.getMustBeFresh(), false); +} + +BOOST_AUTO_TEST_CASE(ModifyForwardingHint) +{ + Interest i("/I"); + i.setCanBePrefix(false); + i.setForwardingHint({{1, "/A"}}); + i.wireEncode(); + BOOST_CHECK(i.hasWire()); + + i.modifyForwardingHint([] (DelegationList& fh) { fh.insert(2, "/B"); }); + BOOST_CHECK(!i.hasWire()); + BOOST_CHECK_EQUAL(i.getForwardingHint(), DelegationList({{1, "/A"}, {2, "/B"}})); +} + +BOOST_AUTO_TEST_CASE(GetNonce) +{ + unique_ptr i1, i2; + + // getNonce automatically assigns a random Nonce. + // It's possible to assign the same Nonce to two Interest, but it's unlikely to get 100 pairs of + // same Nonces in a row. + int nIterations = 0; + uint32_t nonce1 = 0, nonce2 = 0; + do { + i1 = make_unique(); + nonce1 = i1->getNonce(); + i2 = make_unique(); + nonce2 = i2->getNonce(); + } + while (nonce1 == nonce2 && ++nIterations < 100); + BOOST_CHECK_NE(nonce1, nonce2); + BOOST_CHECK(i1->hasNonce()); + BOOST_CHECK(i2->hasNonce()); + + // Once a Nonce is assigned, it should not change. + BOOST_CHECK_EQUAL(i1->getNonce(), nonce1); +} + +BOOST_AUTO_TEST_CASE(SetNonce) +{ + Interest i1("/A"); + i1.setCanBePrefix(false); + i1.setNonce(1); + i1.wireEncode(); + BOOST_CHECK_EQUAL(i1.getNonce(), 1); + + Interest i2(i1); + BOOST_CHECK_EQUAL(i2.getNonce(), 1); + + i2.setNonce(2); + BOOST_CHECK_EQUAL(i2.getNonce(), 2); + BOOST_CHECK_EQUAL(i1.getNonce(), 1); // should not affect i1 Nonce (Bug #4168) +} + +BOOST_AUTO_TEST_CASE(RefreshNonce) +{ + Interest i; + BOOST_CHECK(!i.hasNonce()); + i.refreshNonce(); + BOOST_CHECK(!i.hasNonce()); + + i.setNonce(1); + BOOST_CHECK(i.hasNonce()); + i.refreshNonce(); + BOOST_CHECK(i.hasNonce()); + BOOST_CHECK_NE(i.getNonce(), 1); +} + +BOOST_AUTO_TEST_CASE(SetInterestLifetime) +{ + BOOST_CHECK_THROW(Interest("/A", -1_ms), std::invalid_argument); + BOOST_CHECK_NO_THROW(Interest("/A", 0_ms)); + + Interest i; + BOOST_CHECK_EQUAL(i.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME); + BOOST_CHECK_THROW(i.setInterestLifetime(-1_ms), std::invalid_argument); + BOOST_CHECK_EQUAL(i.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME); + i.setInterestLifetime(0_ms); + BOOST_CHECK_EQUAL(i.getInterestLifetime(), 0_ms); + i.setInterestLifetime(1_ms); + BOOST_CHECK_EQUAL(i.getInterestLifetime(), 1_ms); + + i = Interest("/B", 15_s); + BOOST_CHECK_EQUAL(i.getInterestLifetime(), 15_s); +} + +BOOST_AUTO_TEST_CASE(SetHopLimit) +{ + Interest i; + BOOST_CHECK(i.getHopLimit() == nullopt); + i.setHopLimit(42); + BOOST_CHECK(i.getHopLimit() == 42); + i.setHopLimit(nullopt); + BOOST_CHECK(i.getHopLimit() == nullopt); +} + +BOOST_AUTO_TEST_CASE(SetApplicationParameters) +{ + const uint8_t PARAMETERS1[] = {0xc1}; + const uint8_t PARAMETERS2[] = {0xc2}; + + Interest i; + BOOST_CHECK(!i.hasApplicationParameters()); + i.setApplicationParameters("2400"_block); + BOOST_CHECK(i.hasApplicationParameters()); + i.unsetApplicationParameters(); + BOOST_CHECK(!i.hasApplicationParameters()); + + // Block overload + i.setApplicationParameters(Block{}); + BOOST_CHECK_EQUAL(i.getApplicationParameters(), "2400"_block); + i.setApplicationParameters("2401C0"_block); + BOOST_CHECK_EQUAL(i.getApplicationParameters(), "2401C0"_block); + i.setApplicationParameters("8001C1"_block); + BOOST_CHECK_EQUAL(i.getApplicationParameters(), "24038001C1"_block); + + // raw buffer+size overload + i.setApplicationParameters(PARAMETERS1, sizeof(PARAMETERS1)); + BOOST_CHECK_EQUAL(i.getApplicationParameters(), "2401C1"_block); + i.setApplicationParameters(nullptr, 0); + BOOST_CHECK_EQUAL(i.getApplicationParameters(), "2400"_block); + BOOST_CHECK_THROW(i.setApplicationParameters(nullptr, 42), std::invalid_argument); + + // ConstBufferPtr overload + i.setApplicationParameters(make_shared(PARAMETERS2, sizeof(PARAMETERS2))); + BOOST_CHECK_EQUAL(i.getApplicationParameters(), "2401C2"_block); + i.setApplicationParameters(make_shared()); + BOOST_CHECK_EQUAL(i.getApplicationParameters(), "2400"_block); + BOOST_CHECK_THROW(i.setApplicationParameters(nullptr), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(ParametersSha256DigestComponent) +{ + Interest i("/I"); + BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true); + + i.setApplicationParameters("2404C0C1C2C3"_block); // auto-appends ParametersSha256DigestComponent + BOOST_CHECK_EQUAL(i.getName(), + "/I/params-sha256=ff9100e04eaadcf30674d98026a051ba25f56b69bfa026dcccd72c6ea0f7315a"); + BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true); + + i.setApplicationParameters(nullptr, 0); // updates ParametersSha256DigestComponent + BOOST_CHECK_EQUAL(i.getName(), + "/I/params-sha256=33b67cb5385ceddad93d0ee960679041613bed34b8b4a5e6362fe7539ba2d3ce"); + BOOST_CHECK_EQUAL(i.hasApplicationParameters(), true); + BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true); + + i.unsetApplicationParameters(); // removes ParametersSha256DigestComponent + BOOST_CHECK_EQUAL(i.getName(), "/I"); + BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true); + + i.setName(Name("/P").appendParametersSha256DigestPlaceholder().append("Q")); + BOOST_CHECK_EQUAL(i.hasApplicationParameters(), false); + BOOST_CHECK_EQUAL(i.isParametersDigestValid(), false); + + i.unsetApplicationParameters(); // removes ParametersSha256DigestComponent + BOOST_CHECK_EQUAL(i.getName(), "/P/Q"); + BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true); + + i.setName(Name("/P").appendParametersSha256DigestPlaceholder().append("Q")); + i.setApplicationParameters("2404C0C1C2C3"_block); // updates ParametersSha256DigestComponent + BOOST_CHECK_EQUAL(i.getName(), + "/P/params-sha256=ff9100e04eaadcf30674d98026a051ba25f56b69bfa026dcccd72c6ea0f7315a/Q"); + BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true); + + i.setName("/A/B/C"); // auto-appends ParametersSha256DigestComponent + BOOST_CHECK_EQUAL(i.getName(), + "/A/B/C/params-sha256=ff9100e04eaadcf30674d98026a051ba25f56b69bfa026dcccd72c6ea0f7315a"); + BOOST_CHECK_EQUAL(i.hasApplicationParameters(), true); + BOOST_CHECK_EQUAL(i.isParametersDigestValid(), true); +} + +BOOST_AUTO_TEST_CASE(ToUri) +{ + Interest i; + i.setCanBePrefix(false); + BOOST_CHECK_EQUAL(i.toUri(), "/"); + + i.setName("/foo"); + BOOST_CHECK_EQUAL(i.toUri(), "/foo"); + + i.setCanBePrefix(true); + BOOST_CHECK_EQUAL(i.toUri(), "/foo?CanBePrefix"); + + i.setMustBeFresh(true); + BOOST_CHECK_EQUAL(i.toUri(), "/foo?CanBePrefix&MustBeFresh"); + + i.setNonce(1234); + BOOST_CHECK_EQUAL(i.toUri(), "/foo?CanBePrefix&MustBeFresh&Nonce=1234"); + + i.setInterestLifetime(2_s); + BOOST_CHECK_EQUAL(i.toUri(), "/foo?CanBePrefix&MustBeFresh&Nonce=1234&Lifetime=2000"); + + i.setHopLimit(18); + BOOST_CHECK_EQUAL(i.toUri(), "/foo?CanBePrefix&MustBeFresh&Nonce=1234&Lifetime=2000&HopLimit=18"); + + i.setCanBePrefix(false); + i.setMustBeFresh(false); + i.setHopLimit(nullopt); + i.setApplicationParameters("2402CAFE"_block); + BOOST_CHECK_EQUAL(i.toUri(), + "/foo/params-sha256=8621f5e8321f04104640c8d02877d7c5142cad6e203c5effda1783b1a0e476d6" + "?Nonce=1234&Lifetime=2000"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestInterest + +} // namespace tests +} // namespace ndn diff --git a/tests/unit/key-locator.t.cpp b/tests/unit/key-locator.t.cpp new file mode 100644 index 000000000..a94869e90 --- /dev/null +++ b/tests/unit/key-locator.t.cpp @@ -0,0 +1,194 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/key-locator.hpp" +#include "ndn-cxx/encoding/block-helpers.hpp" + +#include "tests/boost-test.hpp" +#include + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(TestKeyLocator) + +BOOST_AUTO_TEST_CASE(TypeNone) +{ + KeyLocator a; + BOOST_CHECK_EQUAL(a.empty(), true); + BOOST_CHECK_EQUAL(a.getType(), tlv::Invalid); + BOOST_CHECK_THROW(a.getName(), KeyLocator::Error); + BOOST_CHECK_THROW(a.getKeyDigest(), KeyLocator::Error); + + Block wire = a.wireEncode(); + // These octets are obtained from the snippet below. + // This check is intended to detect unexpected encoding change in the future. + // for (auto it = wire.begin(); it != wire.end(); ++it) { + // printf("0x%02x, ", *it); + // } + static const uint8_t expected[] = { + 0x1c, 0x00 + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + KeyLocator b(wire); + BOOST_CHECK_EQUAL(a, b); + BOOST_CHECK_EQUAL(a.empty(), true); + BOOST_CHECK_EQUAL(b.getType(), tlv::Invalid); + BOOST_CHECK_THROW(b.getName(), KeyLocator::Error); + BOOST_CHECK_THROW(b.getKeyDigest(), KeyLocator::Error); + BOOST_CHECK_EQUAL(boost::lexical_cast(b), "None"); +} + +BOOST_AUTO_TEST_CASE(TypeName) +{ + KeyLocator a; + a.setName("/N"); + BOOST_CHECK_EQUAL(a.empty(), false); + BOOST_CHECK_EQUAL(a.getType(), tlv::Name); + BOOST_CHECK_EQUAL(a.getName(), Name("/N")); + BOOST_CHECK_THROW(a.getKeyDigest(), KeyLocator::Error); + + Block wire = a.wireEncode(); + // These octets are obtained from the snippet below. + // This check is intended to detect unexpected encoding change in the future. + // for (auto it = wire.begin(); it != wire.end(); ++it) { + // printf("0x%02x, ", *it); + // } + static const uint8_t expected[] = { + 0x1c, 0x05, 0x07, 0x03, 0x08, 0x01, 0x4e + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + KeyLocator b(wire); + BOOST_CHECK_EQUAL(a, b); + BOOST_CHECK_EQUAL(b.getType(), tlv::Name); + BOOST_CHECK_EQUAL(b.getName(), Name("/N")); + BOOST_CHECK_THROW(b.getKeyDigest(), KeyLocator::Error); + BOOST_CHECK_EQUAL(boost::lexical_cast(b), "Name=/N"); + + KeyLocator c("/N"); + BOOST_CHECK_EQUAL(a, c); +} + +BOOST_AUTO_TEST_CASE(TypeKeyDigest) +{ + std::string digestOctets = "\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45"; + ConstBufferPtr digestBuffer = make_shared(digestOctets.data(), digestOctets.size()); + Block expectedDigestBlock = makeBinaryBlock(tlv::KeyDigest, digestOctets.data(), digestOctets.size()); + + KeyLocator a; + a.setKeyDigest(digestBuffer); + BOOST_CHECK_EQUAL(a.empty(), false); + BOOST_CHECK_EQUAL(a.getType(), tlv::KeyDigest); + BOOST_CHECK_EQUAL(a.getKeyDigest(), expectedDigestBlock); + BOOST_CHECK_THROW(a.getName(), KeyLocator::Error); + + Block wire = a.wireEncode(); + // These octets are obtained from the snippet below. + // This check is intended to detect unexpected encoding change in the future. + // for (auto it = wire.begin(); it != wire.end(); ++it) { + // printf("0x%02x, ", *it); + // } + static const uint8_t expected[] = { + 0x1c, 0x0c, 0x1d, 0x0a, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf1, 0x23, 0x45 + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + KeyLocator b(wire); + BOOST_CHECK_EQUAL(a, b); + BOOST_CHECK_EQUAL(b.getType(), tlv::KeyDigest); + BOOST_CHECK_EQUAL(b.getKeyDigest(), expectedDigestBlock); + BOOST_CHECK_THROW(b.getName(), KeyLocator::Error); + BOOST_CHECK_EQUAL(boost::lexical_cast(b), "KeyDigest=123456789A..."); + + b.setKeyDigest("1D03BCDEF1"_block); + BOOST_CHECK_EQUAL(b.getType(), tlv::KeyDigest); + BOOST_CHECK_EQUAL(b.getKeyDigest(), "1D03BCDEF1"_block); + BOOST_CHECK_THROW(b.getName(), KeyLocator::Error); + BOOST_CHECK_EQUAL(boost::lexical_cast(b), "KeyDigest=BCDEF1"); +} + +BOOST_AUTO_TEST_CASE(TypeUnknown) +{ + const auto wire = "1C037F01CC"_block; + KeyLocator a(wire); + BOOST_CHECK_EQUAL(a.empty(), false); + BOOST_CHECK_EQUAL(a.getType(), 127); + + KeyLocator b(wire); + BOOST_CHECK_EQUAL(a, b); + BOOST_CHECK_EQUAL(b.getType(), 127); + BOOST_CHECK_EQUAL(boost::lexical_cast(b), "Unknown(127)"); + + b.setName("/N"); + BOOST_CHECK_NE(a, b); +} + +BOOST_AUTO_TEST_CASE(Clear) +{ + KeyLocator a("/foo"); + BOOST_CHECK_EQUAL(a.empty(), false); + + a.clear(); + BOOST_CHECK_EQUAL(a.empty(), true); + BOOST_CHECK_EQUAL(a.getType(), tlv::Invalid); + BOOST_CHECK_EQUAL(a, KeyLocator{}); +} + +BOOST_AUTO_TEST_CASE(Equality) +{ + KeyLocator a; + KeyLocator b; + BOOST_CHECK_EQUAL(a == b, true); + BOOST_CHECK_EQUAL(a != b, false); + + a.setName("ndn:/A"); + BOOST_CHECK_EQUAL(a == b, false); + BOOST_CHECK_EQUAL(a != b, true); + + b.setName("ndn:/B"); + BOOST_CHECK_EQUAL(a == b, false); + BOOST_CHECK_EQUAL(a != b, true); + + b.setName("ndn:/A"); + BOOST_CHECK_EQUAL(a == b, true); + BOOST_CHECK_EQUAL(a != b, false); + + const char digestOctets[] = "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"; + auto digestBuffer = make_shared(digestOctets, 8); + + a.setKeyDigest(digestBuffer); + BOOST_CHECK_EQUAL(a == b, false); + BOOST_CHECK_EQUAL(a != b, true); + + b.setKeyDigest(digestBuffer); + BOOST_CHECK_EQUAL(a == b, true); + BOOST_CHECK_EQUAL(a != b, false); +} + +BOOST_AUTO_TEST_SUITE_END() // TestKeyLocator + +} // namespace tests +} // namespace ndn diff --git a/tests/unit/link.t.cpp b/tests/unit/link.t.cpp new file mode 100644 index 000000000..ef85f9f35 --- /dev/null +++ b/tests/unit/link.t.cpp @@ -0,0 +1,178 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/link.hpp" + +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(TestLink) + +const uint8_t GOOD_LINK[] = { +0x06, 0xda, // Data + 0x07, 0x14, // Name + 0x08, 0x05, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, + 0x08, 0x03, + 0x6e, 0x64, 0x6e, + 0x08, 0x06, + 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, + 0x14, 0x07, // MetaInfo + 0x18, 0x01, // ContentType + 0x01, + 0x19, 0x02, // FreshnessPeriod + 0x27, 0x10, + 0x15, 0x1a, // Content + 0x1f, 0x0c, // LinkDelegation + 0x1e, 0x01, // LinkPreference + 0x0a, + 0x07, 0x07, // Name + 0x08, 0x05, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, + 0x1f, 0x0a, // LinkDelegation + 0x1e, 0x01, // LinkPreference + 0x14, + 0x07, 0x05, // Name + 0x08, 0x03, + 0x6e, 0x64, 0x6e, + 0x16, 0x1b, // SignatureInfo + 0x1b, 0x01, // SignatureType + 0x01, + 0x1c, 0x16, // KeyLocator + 0x07, 0x14, // Name + 0x08, 0x04, + 0x74, 0x65, 0x73, 0x74, + 0x08, 0x03, + 0x6b, 0x65, 0x79, + 0x08, 0x07, + 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, + 0x17, 0x80, // SignatureValue + 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, + 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, + 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, + 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, + 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, + 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, + 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, + 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, + 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, + 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1 +}; + +BOOST_AUTO_TEST_SUITE(EncodeDecode) + +BOOST_AUTO_TEST_CASE(Decode) +{ + Link link(Block(GOOD_LINK, sizeof(GOOD_LINK))); + BOOST_CHECK_EQUAL(link.getName(), Name("/local/ndn/prefix")); + BOOST_CHECK_EQUAL(link.getDelegationList(), + DelegationList({{10, Name("/local")}, {20, Name("/ndn")}})); +} + +BOOST_AUTO_TEST_CASE(DecodeBadContentType) +{ + Data linkData(Block(GOOD_LINK, sizeof(GOOD_LINK))); + linkData.setContentType(tlv::ContentType_Key); + Block badLink = linkData.wireEncode(); + + BOOST_CHECK_THROW((Link(badLink)), Link::Error); + Link link; + BOOST_CHECK_THROW(link.wireDecode(badLink), Link::Error); +} + +BOOST_AUTO_TEST_CASE(Encode) +{ + Link link1("/test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}}); + signData(link1); + Block wire = link1.wireEncode(); + + Link link2(wire); + BOOST_CHECK_EQUAL(link2.getName(), "/test"); + BOOST_CHECK_EQUAL(link2.getDelegationList(), + DelegationList({{10, "/test1"}, {20, "/test2"}, {100, "/test3"}})); +} + +BOOST_AUTO_TEST_SUITE_END() // EncodeDecode + +BOOST_AUTO_TEST_SUITE(Modify) + +BOOST_AUTO_TEST_CASE(SetDelegationList) +{ + Link link("/test"); + BOOST_CHECK_EQUAL(link.getDelegationList(), DelegationList()); + + link.setDelegationList(DelegationList({{10, "/test1"}, {20, "/test2"}})); + BOOST_CHECK_EQUAL(link.getDelegationList(), DelegationList({{10, "/test1"}, {20, "/test2"}})); +} + +BOOST_AUTO_TEST_CASE(AddDelegation) +{ + Link link1("/test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}}); + BOOST_CHECK_EQUAL(link1.getDelegationList(), + DelegationList({{10, "/test1"}, {20, "/test2"}, {100, "/test3"}})); + + link1.addDelegation(30, "/test4"); + BOOST_CHECK_EQUAL(link1.getDelegationList(), + DelegationList({{10, "/test1"}, {20, "/test2"}, {30, "/test4"}, {100, "/test3"}})); + + link1.addDelegation(40, "/test2"); + BOOST_CHECK_EQUAL(link1.getDelegationList(), + DelegationList({{10, "/test1"}, {30, "/test4"}, {40, "/test2"}, {100, "/test3"}})); + + signData(link1); + Link link2(link1.wireEncode()); + BOOST_CHECK_EQUAL(link2.getDelegationList(), + DelegationList({{10, "/test1"}, {30, "/test4"}, {40, "/test2"}, {100, "/test3"}})); +} + +BOOST_AUTO_TEST_CASE(RemoveDelegation) +{ + Link link1("/test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}}); + BOOST_CHECK_EQUAL(link1.getDelegationList(), + DelegationList({{10, "/test1"}, {20, "/test2"}, {100, "/test3"}})); + + link1.removeDelegation("/test4"); // non-existent + BOOST_CHECK_EQUAL(link1.getDelegationList(), + DelegationList({{10, "/test1"}, {20, "/test2"}, {100, "/test3"}})); + + link1.removeDelegation("/test2"); + BOOST_CHECK_EQUAL(link1.getDelegationList(), + DelegationList({{10, "/test1"}, {100, "/test3"}})); + + signData(link1); + Link link2(link1.wireEncode()); + BOOST_CHECK_EQUAL(link2.getDelegationList(), + DelegationList({{10, "/test1"}, {100, "/test3"}})); + + link1.removeDelegation("/test1"); + link1.removeDelegation("/test3"); + BOOST_CHECK_EQUAL(link1.getDelegationList(), DelegationList()); +} + +BOOST_AUTO_TEST_SUITE_END() // Modify + +BOOST_AUTO_TEST_SUITE_END() // TestLink + +} // namespace tests +} // namespace ndn diff --git a/tests/unit-tests/lp/cache-policy.t.cpp b/tests/unit/lp/cache-policy.t.cpp similarity index 95% rename from tests/unit-tests/lp/cache-policy.t.cpp rename to tests/unit/lp/cache-policy.t.cpp index 106d6854f..78c1548b5 100644 --- a/tests/unit-tests/lp/cache-policy.t.cpp +++ b/tests/unit/lp/cache-policy.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -21,9 +21,9 @@ * @author Eric Newberry */ -#include "lp/cache-policy.hpp" +#include "ndn-cxx/lp/cache-policy.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace lp { diff --git a/tests/unit-tests/lp/nack-header.t.cpp b/tests/unit/lp/nack-header.t.cpp similarity index 82% rename from tests/unit-tests/lp/nack-header.t.cpp rename to tests/unit/lp/nack-header.t.cpp index 83c9f9d17..4670608e4 100644 --- a/tests/unit-tests/lp/nack-header.t.cpp +++ b/tests/unit/lp/nack-header.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -21,9 +21,9 @@ * @author Eric Newberry */ -#include "lp/nack-header.hpp" +#include "ndn-cxx/lp/nack-header.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace lp { @@ -32,6 +32,18 @@ namespace tests { BOOST_AUTO_TEST_SUITE(Lp) BOOST_AUTO_TEST_SUITE(TestNackHeader) +BOOST_AUTO_TEST_CASE(IsLessSevere) +{ + BOOST_CHECK_EQUAL(isLessSevere(NackReason::NONE, NackReason::NONE), false); + BOOST_CHECK_EQUAL(isLessSevere(NackReason::CONGESTION, NackReason::CONGESTION), false); + + BOOST_CHECK_EQUAL(isLessSevere(NackReason::CONGESTION, NackReason::NONE), true); + BOOST_CHECK_EQUAL(isLessSevere(NackReason::NONE, NackReason::CONGESTION), false); + + BOOST_CHECK_EQUAL(isLessSevere(NackReason::CONGESTION, NackReason::NO_ROUTE), true); + BOOST_CHECK_EQUAL(isLessSevere(NackReason::NO_ROUTE, NackReason::CONGESTION), false); +} + BOOST_AUTO_TEST_CASE(Encode) { NackHeader header; diff --git a/tests/unit-tests/lp/nack.t.cpp b/tests/unit/lp/nack.t.cpp similarity index 93% rename from tests/unit-tests/lp/nack.t.cpp rename to tests/unit/lp/nack.t.cpp index 8ca609de7..ef30de119 100644 --- a/tests/unit-tests/lp/nack.t.cpp +++ b/tests/unit/lp/nack.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -21,9 +21,9 @@ * @author Eric Newberry */ -#include "lp/nack.hpp" +#include "ndn-cxx/lp/nack.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace lp { diff --git a/tests/unit/lp/packet.t.cpp b/tests/unit/lp/packet.t.cpp new file mode 100644 index 000000000..30c8baeac --- /dev/null +++ b/tests/unit/lp/packet.t.cpp @@ -0,0 +1,468 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/lp/packet.hpp" +#include "ndn-cxx/prefix-announcement.hpp" +#include "ndn-cxx/security/signature-sha256-with-rsa.hpp" + +#include "tests/boost-test.hpp" +#include "tests/identity-management-fixture.hpp" + +namespace ndn { +namespace lp { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Lp) +BOOST_AUTO_TEST_SUITE(TestPacket) + +BOOST_AUTO_TEST_CASE(FieldAccess) +{ + Packet packet; + + BOOST_CHECK(packet.empty()); + BOOST_CHECK(!packet.has()); + BOOST_CHECK_EQUAL(packet.count(), 0); + + packet.set(1234); + BOOST_CHECK(!packet.empty()); + BOOST_CHECK(packet.has()); + BOOST_CHECK_THROW(packet.add(5678), std::invalid_argument); + BOOST_CHECK_EQUAL(packet.count(), 1); + BOOST_CHECK_EQUAL(packet.get(0), 1234); + BOOST_CHECK_THROW(packet.get(1), std::out_of_range); + BOOST_CHECK_THROW(packet.remove(1), std::out_of_range); + + packet.remove(0); + BOOST_CHECK_EQUAL(packet.count(), 0); + + packet.add(832); + std::vector fragIndexes = packet.list(); + BOOST_CHECK_EQUAL(fragIndexes.size(), 1); + BOOST_CHECK_EQUAL(fragIndexes.at(0), 832); + + packet.clear(); + BOOST_CHECK_EQUAL(packet.count(), 0); + BOOST_CHECK(packet.empty()); + + packet.add(4001); + packet.add(4002); + packet.add(4003); + BOOST_CHECK_EQUAL(packet.count(), 3); + BOOST_CHECK_EQUAL(packet.get(0), 4001); + BOOST_CHECK_EQUAL(packet.get(1), 4002); + BOOST_CHECK_EQUAL(packet.get(2), 4003); + + packet.remove(1); + BOOST_CHECK_EQUAL(packet.count(), 2); + BOOST_CHECK_EQUAL(packet.get(0), 4001); + BOOST_CHECK_EQUAL(packet.get(1), 4003); + + packet.remove(0); + packet.remove(0); + BOOST_CHECK_EQUAL(packet.count(), 0); + BOOST_CHECK(packet.empty()); +} + +BOOST_AUTO_TEST_CASE(EncodeFragment) +{ + static const uint8_t expectedBlock[] = { + 0x64, 0x0e, // LpPacket + 0x51, 0x08, // Sequence + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe8, + 0x50, 0x02, // Fragment + 0x03, 0xe8, + }; + + Buffer buf(2); + buf[0] = 0x03; + buf[1] = 0xe8; + + Packet packet; + packet.add(std::make_pair(buf.begin(), buf.end())); + packet.add(1000); + Block wire = packet.wireEncode(); + BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock), + wire.begin(), wire.end()); +} + +BOOST_AUTO_TEST_CASE(EncodeSubTlv) +{ + static const uint8_t expectedBlock[] = { + 0x64, 0x09, // LpPacket + 0xfd, 0x03, 0x20, 0x05, // Nack + 0xfd, 0x03, 0x21, 0x01, // NackReason + 0x64, + }; + + NackHeader nack; + nack.setReason(NackReason::DUPLICATE); + + Packet packet; + packet.add(nack); + Block wire = packet.wireEncode(); + BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock), + wire.begin(), wire.end()); +} + +BOOST_AUTO_TEST_CASE(EncodeZeroLengthTlv) +{ + static const uint8_t expectedBlock[] = { + 0x64, 0x04, // LpPacket + 0xfd, 0x03, 0x4c, 0x00, // NonDiscovery + }; + + Packet packet1; + packet1.set(EmptyValue{}); + Block wire = packet1.wireEncode(); + BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock), + wire.begin(), wire.end()); + + Packet packet2; + packet2.add(EmptyValue{}); + wire = packet2.wireEncode(); + BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock), + wire.begin(), wire.end()); +} + +BOOST_AUTO_TEST_CASE(EncodeSortOrder) +{ + static const uint8_t expectedBlock[] = { + 0x64, 0x2e, // LpPacket + 0x52, 0x01, // FragIndex + 0x00, + 0x53, 0x01, // FragCount + 0x01, + 0xfd, 0x03, 0x44, 0x08, // Ack + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0xfd, 0x03, 0x44, 0x08, // Ack + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0xfd, 0x03, 0x44, 0x08, // Ack + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x50, 0x02, // Fragment + 0x03, 0xe8, + }; + + Buffer frag(2); + frag[0] = 0x03; + frag[1] = 0xe8; + + Packet packet; + packet.add(std::make_pair(frag.begin(), frag.end())); + packet.add(0); + packet.add(2); + packet.wireEncode(); + packet.add(1); + packet.wireEncode(); + packet.add(4); + packet.wireEncode(); + packet.add(3); + Block wire = packet.wireEncode(); + BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock), + wire.begin(), wire.end()); +} + +BOOST_AUTO_TEST_CASE(DecodeNormal) +{ + static const uint8_t inputBlock[] = { + 0x64, 0x2e, // LpPacket + 0x52, 0x01, // FragIndex + 0x00, + 0x53, 0x01, // FragCount + 0x01, + 0xfd, 0x03, 0x44, 0x08, // Ack + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xfd, 0x03, 0x44, 0x08, // Ack + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xfd, 0x03, 0x44, 0x08, // Ack + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x50, 0x02, // Fragment + 0x03, 0xe8, + }; + + Packet packet; + Block wire(inputBlock, sizeof(inputBlock)); + packet.wireDecode(wire); + + BOOST_CHECK_EQUAL(packet.count(), 1); + BOOST_CHECK_EQUAL(packet.get(), 0); + + BOOST_CHECK_EQUAL(packet.count(), 1); + BOOST_CHECK_EQUAL(packet.get(), 1); + + BOOST_CHECK_EQUAL(packet.count(), 3); + BOOST_CHECK_EQUAL(packet.get(), 1); + BOOST_CHECK_EQUAL(packet.get(0), 1); + BOOST_CHECK_EQUAL(packet.get(1), 3); + BOOST_CHECK_EQUAL(packet.get(2), 2); + + BOOST_CHECK_EQUAL(packet.count(), 1); + Buffer::const_iterator first, last; + std::tie(first, last) = packet.get(0); + BOOST_CHECK_EQUAL(2, last - first); + BOOST_CHECK_EQUAL(0x03, *first); + BOOST_CHECK_EQUAL(0xe8, *(last - 1)); +} + +BOOST_AUTO_TEST_CASE(DecodeIdle) +{ + static const uint8_t inputBlock[] = { + 0x64, 0x06, // LpPacket + 0x52, 0x01, // FragIndex + 0x00, + 0x53, 0x01, // FragCount + 0x01, + }; + + Packet packet; + Block wire(inputBlock, sizeof(inputBlock)); + packet.wireDecode(wire); + BOOST_CHECK_EQUAL(0, packet.count()); + BOOST_CHECK_EQUAL(1, packet.count()); + BOOST_CHECK_EQUAL(1, packet.count()); + BOOST_CHECK_EQUAL(0, packet.get(0)); + BOOST_CHECK_EQUAL(1, packet.get(0)); +} + +BOOST_AUTO_TEST_CASE(DecodeFragment) +{ + static const uint8_t inputBlock[] = { + 0x64, 0x04, // LpPacket + 0x50, 0x02, // Fragment + 0x03, 0xe8, + }; + + Packet packet; + Block wire(inputBlock, sizeof(inputBlock)); + packet.wireDecode(wire); + BOOST_CHECK_EQUAL(1, packet.count()); + BOOST_CHECK_EQUAL(0, packet.count()); + Buffer::const_iterator first, last; + std::tie(first, last) = packet.get(0); + BOOST_CHECK_EQUAL(2, last - first); + BOOST_CHECK_EQUAL(0x03, *first); + BOOST_CHECK_EQUAL(0xe8, *(last - 1)); +} + +BOOST_AUTO_TEST_CASE(DecodeNonDiscoveryHeader) +{ + static const uint8_t inputBlock[] = { + 0x64, 0x04, // LpPacket + 0xfd, 0x03, 0x4c, 0x00, // NonDiscovery + }; + + Packet packet; + Block wire(inputBlock, sizeof(inputBlock)); + packet.wireDecode(wire); + BOOST_CHECK_EQUAL(true, packet.has()); + packet.get(); +} + +BOOST_AUTO_TEST_CASE(DecodeEmpty) +{ + static const uint8_t inputBlock[] = { + 0x64, 0x00, // LpPacket + }; + + Packet packet; + Block wire(inputBlock, sizeof(inputBlock)); + packet.wireDecode(wire); + BOOST_CHECK_EQUAL(0, packet.count()); + BOOST_CHECK_EQUAL(0, packet.count()); + BOOST_CHECK_EQUAL(false, packet.has()); +} + +BOOST_AUTO_TEST_CASE(DecodeRepeatedNonRepeatableHeader) +{ + static const uint8_t inputBlock[] = { + 0x64, 0x06, // LpPacket + 0x52, 0x01, // FragIndex + 0x00, + 0x52, 0x01, // FragIndex + 0x01, + }; + + Packet packet; + Block wire(inputBlock, sizeof(inputBlock)); + BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error); +} + +BOOST_AUTO_TEST_CASE(DecodeRepeatedFragment) +{ + static const uint8_t inputBlock[] = { + 0x64, 0x08, // LpPacket + 0x50, 0x02, // Fragment + 0x03, 0xe8, + 0x50, 0x02, // Fragment + 0x03, 0xe9, + }; + + Packet packet; + Block wire(inputBlock, sizeof(inputBlock)); + BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error); +} + +BOOST_AUTO_TEST_CASE(DecodeWrongOrderAmongHeaders) +{ + static const uint8_t inputBlock[] = { + 0x64, 0x0a, // LpPacket + 0x53, 0x01, // FragCount + 0x01, + 0x52, 0x01, // FragIndex + 0x00, + 0x50, 0x02, // Fragment + 0x03, 0xe8, + }; + + Packet packet; + Block wire(inputBlock, sizeof(inputBlock)); + BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error); +} + +BOOST_AUTO_TEST_CASE(DecodeWrongOrderFragment) +{ + static const uint8_t inputBlock[] = { + 0x64, 0x0a, // LpPacket + 0x52, 0x01, // FragIndex + 0x00, + 0x50, 0x02, // Fragment + 0x03, 0xe8, + 0x53, 0x01, // FragCount + 0x01, + }; + + Packet packet; + Block wire(inputBlock, sizeof(inputBlock)); + BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error); +} + +BOOST_AUTO_TEST_CASE(DecodeIgnoredHeader) +{ + static const uint8_t inputBlock[] = { + 0x64, 0x0c, // LpPacket + 0x52, 0x01, // FragIndex + 0x00, + 0xfd, 0x03, 0x24, 0x01, // unknown TLV-TYPE 804 (ignored) + 0x02, + 0x50, 0x02, // Fragment + 0x03, 0xe8, + }; + + Packet packet; + Block wire(inputBlock, sizeof(inputBlock)); + packet.wireDecode(wire); + BOOST_CHECK_EQUAL(1, packet.count()); + BOOST_CHECK_EQUAL(1, packet.count()); +} + +BOOST_AUTO_TEST_CASE(DecodeUnrecognizedHeader) +{ + static const uint8_t inputBlock[] = { + 0x64, 0x0c, // LpPacket + 0x52, 0x01, // FragIndex + 0x00, + 0xfd, 0x03, 0x22, 0x01, // unknown TLV-TYPE 802 (cannot ignore) + 0x02, + 0x50, 0x02, // Fragment + 0x03, 0xe8, + }; + + Packet packet; + Block wire(inputBlock, sizeof(inputBlock)); + BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error); +} + +BOOST_AUTO_TEST_CASE(DecodeBareNetworkLayerPacket) +{ + static const uint8_t inputBlock[] = { + 0x05, 0x0a, // Interest + 0x07, 0x02, // Name + 0x03, 0xe8, + 0x0a, 0x04, // Nonce + 0x01, 0x02, 0x03, 0x04, + }; + + Packet packet; + Block wire(inputBlock, sizeof(inputBlock)); + packet.wireDecode(wire); + BOOST_CHECK_EQUAL(1, packet.count()); + + Block encoded = packet.wireEncode(); + BOOST_CHECK_EQUAL_COLLECTIONS(inputBlock, inputBlock + sizeof(inputBlock), + encoded.begin(), encoded.end()); +} + +BOOST_AUTO_TEST_CASE(DecodeSeqNum) +{ + Packet packet; + + // Sequence number is fixed-width, not NonNegativeInteger + packet.wireDecode("640A 5104A4A5A6A7 5002FFFF"_block); + BOOST_CHECK_THROW(packet.get(), ndn::tlv::Error); + + packet.wireDecode("640E 5108A0A1A2A3A4A5A6A7 5002FFFF"_block); + BOOST_CHECK_EQUAL(packet.get(), 0xA0A1A2A3A4A5A6A7); +} + +BOOST_AUTO_TEST_CASE(DecodeUnrecognizedTlvType) +{ + Packet packet; + Block wire = encoding::makeEmptyBlock(ndn::tlv::Name); + BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error); +} + +BOOST_FIXTURE_TEST_CASE(DecodePrefixAnnouncement, ndn::tests::IdentityManagementFixture) +{ + // Construct Data which prefix announcement is attached to + Data data0("/edu/ua/cs/news/index.html"); + ndn::SignatureSha256WithRsa fakeSignature; + fakeSignature.setValue(ndn::encoding::makeEmptyBlock(ndn::tlv::SignatureValue)); + data0.setSignature(fakeSignature); + + Block wire; + wire = data0.wireEncode(); + Packet packet0; + packet0.wireDecode(wire); + + // Construct Prefix Announcement + PrefixAnnouncement pa; + pa.setAnnouncedName("/net/example"); + pa.setExpiration(5_min); + pa.setValidityPeriod(security::ValidityPeriod(time::fromIsoString("20181030T000000"), + time::fromIsoString("20181124T235959"))); + pa.toData(m_keyChain, signingWithSha256(), 1); + PrefixAnnouncementHeader pah0(pa); + packet0.add(pah0); + Block encoded = packet0.wireEncode(); + + // check decoding + Packet packet1; + packet1.wireDecode(encoded); + BOOST_CHECK_EQUAL(true, packet1.has()); + PrefixAnnouncementHeader pah1 = packet1.get(); + BOOST_CHECK_EQUAL(pah1.getPrefixAnn()->getAnnouncedName(), "/net/example"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestPacket +BOOST_AUTO_TEST_SUITE_END() // Lp + +} // namespace tests +} // namespace lp +} // namespace ndn diff --git a/tests/unit/lp/pit-token.t.cpp b/tests/unit/lp/pit-token.t.cpp new file mode 100644 index 000000000..48ef8d691 --- /dev/null +++ b/tests/unit/lp/pit-token.t.cpp @@ -0,0 +1,80 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/lp/pit-token.hpp" +#include "ndn-cxx/lp/packet.hpp" + +#include "tests/boost-test.hpp" +#include + +namespace ndn { +namespace lp { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Lp) +BOOST_AUTO_TEST_SUITE(TestPitToken) + +BOOST_AUTO_TEST_CASE(Decode) +{ + Packet pkt("6405 pit-token=6200 fragment=5001C0"_block); + BOOST_CHECK_THROW(PitToken(pkt.get()), ndn::tlv::Error); + + pkt.wireDecode("6406 pit-token=6201A0 fragment=5001C0"_block); + PitToken pitToken1(pkt.get()); + BOOST_CHECK_EQUAL(boost::lexical_cast(pitToken1), "a0"); + + pkt.wireDecode("640A pit-token=6205A0A1A2A3A4 fragment=5001C0"_block); + PitToken pitToken5(pkt.get()); + BOOST_CHECK_EQUAL(boost::lexical_cast(pitToken5), "a0a1a2a3a4"); + + pkt.wireDecode("640D pit-token=6208A0A1A2A3A4A5A6A7 fragment=5001C0"_block); + PitToken pitToken8(pkt.get()); + BOOST_CHECK_EQUAL(boost::lexical_cast(pitToken8), "a0a1a2a3a4a5a6a7"); + + pkt.wireDecode("6425 pit-token=6220A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF" + " fragment=5001C0"_block); + PitToken pitToken32(pkt.get()); + BOOST_CHECK_EQUAL(boost::lexical_cast(pitToken32), + "a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf"); + + pkt.wireDecode("6426 pit-token=6221A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0" + " fragment=5001C0"_block); + BOOST_CHECK_THROW(PitToken(pkt.get()), ndn::tlv::Error); + + BOOST_CHECK_EQUAL(pitToken1, pitToken1); + BOOST_CHECK_NE(pitToken1, pitToken5); + + pkt.wireDecode("640A pit-token=6205B0B1B2B3B4 fragment=5001C0"_block); + PitToken pitToken5b(pkt.get()); + BOOST_CHECK_NE(pitToken5, pitToken5b); + + pkt.set(pitToken5); + BOOST_CHECK_EQUAL(pkt.wireEncode(), "640A pit-token=6205A0A1A2A3A4 fragment=5001C0"_block); + PitToken pitToken5a(pkt.get()); + BOOST_CHECK_EQUAL(pitToken5, pitToken5a); +} + +BOOST_AUTO_TEST_SUITE_END() // TestPitToken +BOOST_AUTO_TEST_SUITE_END() // Lp + +} // namespace tests +} // namespace lp +} // namespace ndn diff --git a/tests/unit/lp/prefix-announcement-header.t.cpp b/tests/unit/lp/prefix-announcement-header.t.cpp new file mode 100644 index 000000000..fb57ded96 --- /dev/null +++ b/tests/unit/lp/prefix-announcement-header.t.cpp @@ -0,0 +1,70 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/lp/prefix-announcement-header.hpp" +#include "ndn-cxx/lp/tlv.hpp" +#include "ndn-cxx/security/signature-sha256-with-rsa.hpp" + +#include "tests/boost-test.hpp" +#include "tests/identity-management-fixture.hpp" + +namespace ndn { +namespace lp { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Lp) +BOOST_FIXTURE_TEST_SUITE(TestPrefixAnnouncementHeader, ndn::tests::IdentityManagementFixture) + +BOOST_AUTO_TEST_CASE(EncodeDecode) +{ + EncodingEstimator estimator; + PrefixAnnouncementHeader header; + BOOST_CHECK_THROW(header.wireEncode(estimator), PrefixAnnouncementHeader::Error); + BOOST_CHECK_THROW(PrefixAnnouncementHeader{PrefixAnnouncement()}, PrefixAnnouncementHeader::Error); + + PrefixAnnouncement pa; + pa.setAnnouncedName("/net/example"); + pa.setExpiration(1_h); + const Data& data = pa.toData(m_keyChain, signingWithSha256(), 1); + Block encodedData = data.wireEncode(); + + Block expectedBlock(tlv::PrefixAnnouncement); + expectedBlock.push_back(encodedData); + expectedBlock.encode(); + + PrefixAnnouncementHeader pah0(pa); + size_t estimatedSize = pah0.wireEncode(estimator); + EncodingBuffer buffer(estimatedSize, 0); + pah0.wireEncode(buffer); + Block wire = buffer.block(); + BOOST_CHECK_EQUAL(expectedBlock, wire); + + PrefixAnnouncementHeader pah1; + pah1.wireDecode(wire); + BOOST_CHECK_EQUAL(*pah0.getPrefixAnn(), *pah1.getPrefixAnn()); +} + +BOOST_AUTO_TEST_SUITE_END() // TestPrefixAnnouncementHeader +BOOST_AUTO_TEST_SUITE_END() // Lp + +} // namespace tests +} // namespace lp +} // namespace ndn diff --git a/tests/main.cpp b/tests/unit/main.cpp similarity index 93% rename from tests/main.cpp rename to tests/unit/main.cpp index cf03e21f7..cb54695a5 100644 --- a/tests/main.cpp +++ b/tests/unit/main.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,20 +19,18 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#define BOOST_TEST_MODULE ndn-cxx Tests -#define BOOST_TEST_DYN_LINK -#define BOOST_TEST_ALTERNATIVE_INIT_API +#define BOOST_TEST_MODULE ndn-cxx Unit Tests #include #if BOOST_VERSION >= 106200 // Boost.Test v3.3 (Boost 1.62) natively supports multi-logger output -#include "boost-test.hpp" +#include "tests/boost-test.hpp" #else +#define BOOST_TEST_ALTERNATIVE_INIT_API #define BOOST_TEST_NO_MAIN -#include "boost-test.hpp" - -#include "boost-multi-log-formatter.hpp" +#include "tests/boost-test.hpp" +#include "tests/unit/boost-multi-log-formatter.hpp" #include #include diff --git a/tests/unit/meta-info.t.cpp b/tests/unit/meta-info.t.cpp new file mode 100644 index 000000000..e5229bf7e --- /dev/null +++ b/tests/unit/meta-info.t.cpp @@ -0,0 +1,162 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/meta-info.hpp" +#include "ndn-cxx/data.hpp" + +#include "tests/boost-test.hpp" + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(TestMetaInfo) + +BOOST_AUTO_TEST_CASE(EncodeDecode) +{ + // default values + MetaInfo a("1406 type=180100 freshness=190100"_block); + BOOST_CHECK_EQUAL(a.getType(), tlv::ContentType_Blob); + BOOST_CHECK_EQUAL(a.getFreshnessPeriod(), 0_ms); + BOOST_CHECK(a.getFinalBlock() == nullopt); + + MetaInfo b; + BOOST_CHECK_NE(a.wireEncode(), b.wireEncode()); + b.setType(a.getType()); + b.setFreshnessPeriod(a.getFreshnessPeriod()); + b.setFinalBlock(a.getFinalBlock()); + BOOST_CHECK_NE(a.wireEncode(), b.wireEncode()); + BOOST_CHECK_EQUAL(b.wireEncode(), "1400"_block); + + // non-default values + Block wire2("140C type=180101 freshness=190266B2 finalblock=1A03080141"_block); + a.wireDecode(wire2); + BOOST_CHECK_EQUAL(a.getType(), tlv::ContentType_Link); + BOOST_CHECK_EQUAL(a.getFreshnessPeriod(), 26290_ms); + BOOST_REQUIRE(a.getFinalBlock().has_value()); + BOOST_CHECK_EQUAL(*a.getFinalBlock(), name::Component("A")); + BOOST_CHECK_NE(a.wireEncode(), b.wireEncode()); + + b.setType(a.getType()); + b.setFreshnessPeriod(a.getFreshnessPeriod()); + b.setFinalBlock(a.getFinalBlock()); + BOOST_CHECK_EQUAL(b.wireEncode(), wire2); + + // FinalBlockId is a typed name component + Block wire3 = "1405 finalblock=1A03DD0141"_block; + a.wireDecode(wire3); + BOOST_CHECK_EQUAL(a.getType(), tlv::ContentType_Blob); + BOOST_CHECK_EQUAL(a.getFreshnessPeriod(), 0_ms); + BOOST_REQUIRE(a.getFinalBlock().has_value()); + BOOST_CHECK_EQUAL(*a.getFinalBlock(), name::Component::fromEscapedString("221=A")); + BOOST_CHECK_NE(a.wireEncode(), b.wireEncode()); + + b.setType(a.getType()); + b.setFreshnessPeriod(a.getFreshnessPeriod()); + b.setFinalBlock(a.getFinalBlock()); + BOOST_CHECK_EQUAL(b.wireEncode(), wire3); +} + +BOOST_AUTO_TEST_CASE(AppMetaInfo) +{ + MetaInfo info1; + info1.setType(196); + info1.setFreshnessPeriod(3600_ms); + info1.setFinalBlock(name::Component("/att/final")); + + uint32_t ints[5] = {128, 129, 130, 131, 132}; + std::string ss[5] = {"h", "hello", "hello, world", "hello, world, alex", + "hello, world, alex, I am Xiaoke Jiang"}; + + for (size_t i = 0; i < 5; i++) { + uint32_t type = 128 + i * 10; + info1.addAppMetaInfo(makeNonNegativeIntegerBlock(type, ints[i])); + type += 5; + info1.addAppMetaInfo(makeStringBlock(type, ss[i])); + } + + BOOST_CHECK(info1.findAppMetaInfo(252) == nullptr); + + info1.addAppMetaInfo(makeNonNegativeIntegerBlock(252, 1000)); + BOOST_CHECK(info1.findAppMetaInfo(252) != nullptr); + + info1.addAppMetaInfo(makeNonNegativeIntegerBlock(252, 1000)); + BOOST_CHECK(info1.findAppMetaInfo(252) != nullptr); + + info1.removeAppMetaInfo(252); + BOOST_CHECK(info1.findAppMetaInfo(252) != nullptr); + + info1.removeAppMetaInfo(252); + BOOST_CHECK(info1.findAppMetaInfo(252) == nullptr); + + // // These octets are obtained by the snippet below. + // // This check is intended to detect unexpected encoding change in the future. + // const Block& wire = info1.wireEncode(); + // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { + // printf("0x%02x, ", *it); + // } + const uint8_t METAINFO[] = {0x14, 0x77, 0x18, 0x01, 0xc4, 0x19, 0x02, 0x0e, 0x10, 0x1a, 0x0c, + 0x08, 0x0a, 0x2f, 0x61, 0x74, 0x74, 0x2f, 0x66, 0x69, 0x6e, 0x61, + 0x6c, 0x80, 0x01, 0x80, 0x85, 0x01, 0x68, 0x8a, 0x01, 0x81, 0x8f, + 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x94, 0x01, 0x82, 0x99, 0x0c, + 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, + 0x64, 0x9e, 0x01, 0x83, 0xa3, 0x12, 0x68, 0x65, 0x6c, 0x6c, 0x6f, + 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2c, 0x20, 0x61, 0x6c, + 0x65, 0x78, 0xa8, 0x01, 0x84, 0xad, 0x25, 0x68, 0x65, 0x6c, 0x6c, + 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2c, 0x20, 0x61, + 0x6c, 0x65, 0x78, 0x2c, 0x20, 0x49, 0x20, 0x61, 0x6d, 0x20, 0x58, + 0x69, 0x61, 0x6f, 0x6b, 0x65, 0x20, 0x4a, 0x69, 0x61, 0x6e, 0x67}; + + BOOST_REQUIRE_EQUAL_COLLECTIONS(info1.wireEncode().begin(), info1.wireEncode().end(), + METAINFO, METAINFO + sizeof(METAINFO)); + + MetaInfo info2; + info2.wireDecode(Block(METAINFO, sizeof(METAINFO))); + + for (size_t i = 0; i < 5; i++) { + uint32_t tlvType = 128 + i * 10; + const Block* block = info2.findAppMetaInfo(tlvType); + BOOST_REQUIRE(block != nullptr); + BOOST_CHECK_EQUAL(readNonNegativeInteger(*block), ints[i]); + tlvType += 5; + + block = info2.findAppMetaInfo(tlvType); + BOOST_REQUIRE(block != nullptr); + + std::string s3(reinterpret_cast(block->value()), block->value_size()); + BOOST_CHECK_EQUAL(s3, ss[i]); + } +} + +BOOST_AUTO_TEST_CASE(AppMetaInfoTypeRange) +{ + MetaInfo info; + + BOOST_CHECK_NO_THROW(info.addAppMetaInfo(makeNonNegativeIntegerBlock(128, 1000))); + BOOST_CHECK_NO_THROW(info.addAppMetaInfo(makeNonNegativeIntegerBlock(252, 1000))); + + BOOST_CHECK_THROW(info.addAppMetaInfo(makeNonNegativeIntegerBlock(127, 1000)), MetaInfo::Error); + BOOST_CHECK_THROW(info.addAppMetaInfo(makeNonNegativeIntegerBlock(253, 1000)), MetaInfo::Error); +} + +BOOST_AUTO_TEST_SUITE_END() // TestMetaInfo + +} // namespace tests +} // namespace ndn diff --git a/tests/unit/metadata-object.t.cpp b/tests/unit/metadata-object.t.cpp new file mode 100644 index 000000000..6074c59fe --- /dev/null +++ b/tests/unit/metadata-object.t.cpp @@ -0,0 +1,152 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * @author Chavoosh Ghasemi + */ + +#include "ndn-cxx/metadata-object.hpp" + +#include "tests/boost-test.hpp" +#include "tests/identity-management-fixture.hpp" + +namespace ndn { +namespace tests { + +class MetadataObjectFixture : public IdentityManagementFixture +{ +public: + MetadataObjectFixture() + : metadataComponent(32, reinterpret_cast("metadata"), std::strlen("metadata")) + , versionedContentName(Name(baseContentName) + .appendVersion(342092199154ULL)) + , metadataFullName(Name(baseContentName) + .append(metadataComponent) + .appendVersion(metadataVerNo) + .appendSegment(0)) + { + } + +protected: + const name::Component metadataComponent; + + // content prefix + const Name baseContentName = "/ndn/unit/tests"; + const Name versionedContentName; + + // metadata prefix + const uint64_t metadataVerNo = 89400192181ULL; + const Name metadataFullName; +}; + +BOOST_FIXTURE_TEST_SUITE(TestMetadataObject, MetadataObjectFixture) + +BOOST_AUTO_TEST_CASE(EncodeDecode) +{ + MetadataObject metadata1; + metadata1.setVersionedName(versionedContentName); + + // pass metadata version number + const Data data1 = metadata1.makeData(metadataFullName.getPrefix(-2), m_keyChain, + KeyChain::getDefaultSigningInfo(), metadataVerNo); + + BOOST_CHECK_EQUAL(metadata1.getVersionedName(), versionedContentName); + BOOST_CHECK_EQUAL(data1.getName(), metadataFullName); + BOOST_CHECK_EQUAL(data1.getFreshnessPeriod(), 10_ms); + + // do not pass metadata version number + metadata1.setVersionedName(versionedContentName); + const Data data2 = metadata1.makeData(metadataFullName.getPrefix(-2), m_keyChain); + BOOST_CHECK_NE(data2.getName()[-2].toVersion(), metadataVerNo); + + // construct a metadata object based on a valid metadata packet + MetadataObject metadata2(data1); + + BOOST_CHECK_EQUAL(metadata2.getVersionedName(), versionedContentName); + BOOST_CHECK(baseContentName.isPrefixOf(metadata2.makeData(metadataFullName.getPrefix(-2), + m_keyChain).getName())); +} + +BOOST_AUTO_TEST_CASE(InvalidFormat) +{ + Data data; + + // invalid content type + data.setName(Name("/ndn/unit/test").append(metadataComponent)); + data.setContentType(tlv::ContentType_Key); + BOOST_CHECK_THROW(MetadataObject metadata(data), tlv::Error); + + // invalid metadata name + data.setName("/ndn/unit/test"); + data.setContentType(tlv::ContentType_Blob); + BOOST_CHECK_THROW(MetadataObject metadata(data), tlv::Error); + + // empty content + data.setName(Name("ndn/unit/test").append(metadataComponent)); + BOOST_CHECK_THROW(MetadataObject metadata(data), tlv::Error); + + // non-empty content with no name element + data.setContent("F000"_block); + BOOST_CHECK_THROW(MetadataObject metadata(data), tlv::Error); +} + +BOOST_AUTO_TEST_CASE(IsValidName) +{ + // valid name + Name name = Name("/ndn/unit/test") + .append(metadataComponent) + .appendVersion() + .appendSegment(0); + BOOST_CHECK(MetadataObject::isValidName(name)); + + // invalid names + // segment component is missing + BOOST_CHECK_EQUAL(MetadataObject::isValidName(name.getPrefix(-1)), false); + + // version component is missing + BOOST_CHECK_EQUAL(MetadataObject::isValidName(name.getPrefix(-2)), false); + + // keyword name component `32=keyword` is missing + BOOST_CHECK_EQUAL(MetadataObject::isValidName(name.getPrefix(-3)), false); + + // too short name + BOOST_CHECK_EQUAL(MetadataObject::isValidName(name.getPrefix(-4)), false); + + // out-of-order segment and version components + name = name.getPrefix(-2).appendSegment(0).appendVersion(); + BOOST_CHECK_EQUAL(MetadataObject::isValidName(name), false); + + // invalid name component keyword + name = name.getPrefix(-3) + .append(32, reinterpret_cast("foo"), std::strlen("foo")) + .appendVersion() + .appendSegment(0); + BOOST_CHECK_EQUAL(MetadataObject::isValidName(name), false); +} + +BOOST_AUTO_TEST_CASE(MakeDiscoveryInterest) +{ + Interest interest = MetadataObject::makeDiscoveryInterest(baseContentName); + BOOST_CHECK_EQUAL(interest.getName(), Name(baseContentName).append(metadataComponent)); + BOOST_CHECK(interest.getCanBePrefix()); + BOOST_CHECK(interest.getMustBeFresh()); +} + +BOOST_AUTO_TEST_SUITE_END() // TestMetadataObject + +} // namespace tests +} // namespace ndn diff --git a/tests/unit/mgmt/control-response.t.cpp b/tests/unit/mgmt/control-response.t.cpp new file mode 100644 index 000000000..74b1b0330 --- /dev/null +++ b/tests/unit/mgmt/control-response.t.cpp @@ -0,0 +1,61 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/control-response.hpp" + +#include "tests/boost-test.hpp" + +namespace ndn { +namespace mgmt { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Mgmt) +BOOST_AUTO_TEST_SUITE(TestControlResponse) + +static const uint8_t WIRE[] = { + 0x65, 0x17, // ControlResponse + 0x66, 0x02, // StatusCode + 0x01, 0x94, + 0x67, 0x11, // StatusText + 0x4e, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x6f, 0x74, 0x20, + 0x66, 0x6f, 0x75, 0x6e, 0x64}; + +BOOST_AUTO_TEST_CASE(Encode) +{ + ControlResponse cr(404, "Nothing not found"); + const Block& wire = cr.wireEncode(); + BOOST_CHECK_EQUAL_COLLECTIONS(WIRE, WIRE + sizeof(WIRE), + wire.begin(), wire.end()); +} + +BOOST_AUTO_TEST_CASE(Decode) +{ + ControlResponse cr(Block(WIRE, sizeof(WIRE))); + BOOST_CHECK_EQUAL(cr.getCode(), 404); + BOOST_CHECK_EQUAL(cr.getText(), "Nothing not found"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestControlResponse +BOOST_AUTO_TEST_SUITE_END() // Mgmt + +} // namespace tests +} // namespace mgmt +} // namespace ndn diff --git a/tests/unit/mgmt/dispatcher.t.cpp b/tests/unit/mgmt/dispatcher.t.cpp new file mode 100644 index 000000000..7fa74e586 --- /dev/null +++ b/tests/unit/mgmt/dispatcher.t.cpp @@ -0,0 +1,494 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/dispatcher.hpp" +#include "ndn-cxx/mgmt/nfd/control-parameters.hpp" +#include "ndn-cxx/util/dummy-client-face.hpp" + +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" +#include "tests/unit/identity-management-time-fixture.hpp" + +namespace ndn { +namespace mgmt { +namespace tests { + +using namespace ndn::tests; + +class DispatcherFixture : public IdentityManagementTimeFixture +{ +public: + DispatcherFixture() + : face(io, m_keyChain, {true, true}) + , dispatcher(face, m_keyChain, security::SigningInfo()) + , storage(dispatcher.m_storage) + { + } + +public: + util::DummyClientFace face; + mgmt::Dispatcher dispatcher; + InMemoryStorageFifo& storage; +}; + +class VoidParameters : public mgmt::ControlParameters +{ +public: + explicit + VoidParameters(const Block& wire) + { + wireDecode(wire); + } + + Block + wireEncode() const final + { + return Block(128); + } + + void + wireDecode(const Block& wire) final + { + if (wire.type() != 128) + NDN_THROW(tlv::Error("Expecting TLV type 128")); + } +}; + +static Authorization +makeTestAuthorization() +{ + return [] (const Name& prefix, + const Interest& interest, + const ControlParameters* params, + AcceptContinuation accept, + RejectContinuation reject) { + if (interest.getName()[-1] == name::Component("valid")) { + accept(""); + } + else { + if (interest.getName()[-1] == name::Component("silent")) { + reject(RejectReply::SILENT); + } + else { + reject(RejectReply::STATUS403); + } + } + }; +} + +BOOST_AUTO_TEST_SUITE(Mgmt) +BOOST_FIXTURE_TEST_SUITE(TestDispatcher, DispatcherFixture) + +BOOST_AUTO_TEST_CASE(Basic) +{ + BOOST_CHECK_NO_THROW(dispatcher + .addControlCommand("test/1", makeAcceptAllAuthorization(), + bind([] { return true; }), + bind([]{}))); + BOOST_CHECK_NO_THROW(dispatcher + .addControlCommand("test/2", makeAcceptAllAuthorization(), + bind([] { return true; }), + bind([]{}))); + + BOOST_CHECK_THROW(dispatcher + .addControlCommand("test", makeAcceptAllAuthorization(), + bind([] { return true; }), + bind([]{})), + std::out_of_range); + + BOOST_CHECK_NO_THROW(dispatcher.addStatusDataset("status/1", + makeAcceptAllAuthorization(), bind([]{}))); + BOOST_CHECK_NO_THROW(dispatcher.addStatusDataset("status/2", + makeAcceptAllAuthorization(), bind([]{}))); + BOOST_CHECK_THROW(dispatcher.addStatusDataset("status", + makeAcceptAllAuthorization(), bind([]{})), + std::out_of_range); + + BOOST_CHECK_NO_THROW(dispatcher.addNotificationStream("stream/1")); + BOOST_CHECK_NO_THROW(dispatcher.addNotificationStream("stream/2")); + BOOST_CHECK_THROW(dispatcher.addNotificationStream("stream"), std::out_of_range); + + + BOOST_CHECK_NO_THROW(dispatcher.addTopPrefix("/root/1")); + BOOST_CHECK_NO_THROW(dispatcher.addTopPrefix("/root/2")); + BOOST_CHECK_THROW(dispatcher.addTopPrefix("/root"), std::out_of_range); + + BOOST_CHECK_THROW(dispatcher + .addControlCommand("test/3", makeAcceptAllAuthorization(), + bind([] { return true; }), + bind([]{})), + std::domain_error); + + BOOST_CHECK_THROW(dispatcher.addStatusDataset("status/3", + makeAcceptAllAuthorization(), bind([]{})), + std::domain_error); + + BOOST_CHECK_THROW(dispatcher.addNotificationStream("stream/3"), std::domain_error); +} + +BOOST_AUTO_TEST_CASE(AddRemoveTopPrefix) +{ + std::map nCallbackCalled; + dispatcher + .addControlCommand("test/1", makeAcceptAllAuthorization(), + bind([] { return true; }), + bind([&nCallbackCalled] { ++nCallbackCalled["test/1"]; })); + + dispatcher + .addControlCommand("test/2", makeAcceptAllAuthorization(), + bind([] { return true; }), + bind([&nCallbackCalled] { ++nCallbackCalled["test/2"]; })); + + face.receive(*makeInterest("/root/1/test/1/%80%00")); + advanceClocks(1_ms); + BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 0); + BOOST_CHECK_EQUAL(nCallbackCalled["test/2"], 0); + + dispatcher.addTopPrefix("/root/1"); + advanceClocks(1_ms); + + face.receive(*makeInterest("/root/1/test/1/%80%00")); + advanceClocks(1_ms); + BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 1); + BOOST_CHECK_EQUAL(nCallbackCalled["test/2"], 0); + + face.receive(*makeInterest("/root/1/test/2/%80%00")); + advanceClocks(1_ms); + BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 1); + BOOST_CHECK_EQUAL(nCallbackCalled["test/2"], 1); + + face.receive(*makeInterest("/root/2/test/1/%80%00")); + face.receive(*makeInterest("/root/2/test/2/%80%00")); + advanceClocks(1_ms); + BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 1); + BOOST_CHECK_EQUAL(nCallbackCalled["test/2"], 1); + + dispatcher.addTopPrefix("/root/2"); + advanceClocks(1_ms); + + face.receive(*makeInterest("/root/1/test/1/%80%00")); + advanceClocks(1_ms); + BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 2); + + face.receive(*makeInterest("/root/2/test/1/%80%00")); + advanceClocks(1_ms); + BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 3); + + dispatcher.removeTopPrefix("/root/1"); + advanceClocks(1_ms); + + face.receive(*makeInterest("/root/1/test/1/%80%00")); + advanceClocks(1_ms); + BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 3); + + face.receive(*makeInterest("/root/2/test/1/%80%00")); + advanceClocks(1_ms); + BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 4); +} + +BOOST_AUTO_TEST_CASE(ControlCommand) +{ + size_t nCallbackCalled = 0; + dispatcher + .addControlCommand("test", + makeTestAuthorization(), + bind([] { return true; }), + bind([&nCallbackCalled] { ++nCallbackCalled; })); + + dispatcher.addTopPrefix("/root"); + advanceClocks(1_ms); + face.sentData.clear(); + + face.receive(*makeInterest("/root/test/%80%00")); // returns 403 + face.receive(*makeInterest("/root/test/%80%00/invalid")); // returns 403 + face.receive(*makeInterest("/root/test/%80%00/silent")); // silently ignored + face.receive(*makeInterest("/root/test/.../invalid")); // silently ignored (wrong format) + face.receive(*makeInterest("/root/test/.../valid")); // silently ignored (wrong format) + advanceClocks(1_ms, 20); + BOOST_CHECK_EQUAL(nCallbackCalled, 0); + BOOST_CHECK_EQUAL(face.sentData.size(), 2); + + BOOST_CHECK_EQUAL(face.sentData[0].getContentType(), tlv::ContentType_Blob); + BOOST_CHECK_EQUAL(ControlResponse(face.sentData[0].getContent().blockFromValue()).getCode(), 403); + BOOST_CHECK_EQUAL(face.sentData[1].getContentType(), tlv::ContentType_Blob); + BOOST_CHECK_EQUAL(ControlResponse(face.sentData[1].getContent().blockFromValue()).getCode(), 403); + + face.receive(*makeInterest("/root/test/%80%00/valid")); + advanceClocks(1_ms, 10); + BOOST_CHECK_EQUAL(nCallbackCalled, 1); +} + +class StatefulParameters : public mgmt::ControlParameters +{ +public: + explicit + StatefulParameters(const Block& wire) + { + wireDecode(wire); + } + + Block + wireEncode() const final + { + return Block(); + } + + void + wireDecode(const Block& wire) final + { + m_state = EXPECTED_STATE; + } + + bool + check() const + { + return m_state == EXPECTED_STATE; + } + +private: + static constexpr int EXPECTED_STATE = 12602; + int m_state = 0; +}; + +BOOST_AUTO_TEST_CASE(ControlCommandAsyncAuthorization) // Bug 4059 +{ + AcceptContinuation authorizationAccept; + auto authorization = + [&authorizationAccept] (const Name& prefix, const Interest& interest, const ControlParameters* params, + AcceptContinuation accept, RejectContinuation reject) { + authorizationAccept = accept; + }; + + auto validateParameters = + [] (const ControlParameters& params) { + return dynamic_cast(params).check(); + }; + + size_t nCallbackCalled = 0; + dispatcher + .addControlCommand("test", + authorization, + validateParameters, + bind([&nCallbackCalled] { ++nCallbackCalled; })); + + dispatcher.addTopPrefix("/root"); + advanceClocks(1_ms); + + face.receive(*makeInterest("/root/test/%80%00")); + BOOST_CHECK_EQUAL(nCallbackCalled, 0); + BOOST_REQUIRE(authorizationAccept != nullptr); + + advanceClocks(1_ms); + authorizationAccept(""); + advanceClocks(1_ms); + BOOST_CHECK_EQUAL(nCallbackCalled, 1); +} + +BOOST_AUTO_TEST_CASE(StatusDataset) +{ + const uint8_t smallBuf[] = {0x81, 0x01, 0x01}; + const Block smallBlock(smallBuf, sizeof(smallBuf)); + Block largeBlock; + { + EncodingBuffer encoder; + for (size_t i = 0; i < 2500; ++i) { + encoder.prependByte(1); + } + encoder.prependVarNumber(2500); + encoder.prependVarNumber(129); + largeBlock = encoder.block(); + } + + dispatcher.addStatusDataset("test/small", + makeTestAuthorization(), + [&smallBlock] (const Name& prefix, const Interest& interest, + StatusDatasetContext& context) { + context.append(smallBlock); + context.append(smallBlock); + context.append(smallBlock); + context.end(); + }); + + dispatcher.addStatusDataset("test/large", + makeTestAuthorization(), + [&largeBlock] (const Name& prefix, const Interest& interest, + StatusDatasetContext& context) { + context.append(largeBlock); + context.append(largeBlock); + context.append(largeBlock); + context.end(); + }); + + dispatcher.addStatusDataset("test/reject", + makeTestAuthorization(), + [] (const Name& prefix, const Interest& interest, + StatusDatasetContext& context) { + context.reject(); + }); + + dispatcher.addTopPrefix("/root"); + advanceClocks(1_ms); + face.sentData.clear(); + + face.receive(*makeInterest("/root/test/small/%80%00")); // returns 403 + face.receive(*makeInterest("/root/test/small/%80%00/invalid")); // returns 403 + face.receive(*makeInterest("/root/test/small/%80%00/silent")); // silently ignored + advanceClocks(1_ms, 20); + BOOST_CHECK_EQUAL(face.sentData.size(), 2); + + BOOST_CHECK_EQUAL(face.sentData[0].getContentType(), tlv::ContentType_Blob); + BOOST_CHECK_EQUAL(ControlResponse(face.sentData[0].getContent().blockFromValue()).getCode(), 403); + BOOST_CHECK_EQUAL(face.sentData[1].getContentType(), tlv::ContentType_Blob); + BOOST_CHECK_EQUAL(ControlResponse(face.sentData[1].getContent().blockFromValue()).getCode(), 403); + + face.sentData.clear(); + + auto interestSmall = *makeInterest("/root/test/small/valid", true); + face.receive(interestSmall); + advanceClocks(1_ms, 10); + + // one data packet is generated and sent to both places + BOOST_CHECK_EQUAL(face.sentData.size(), 1); + BOOST_CHECK_EQUAL(storage.size(), 1); + + auto fetchedData = storage.find(interestSmall); + BOOST_REQUIRE(fetchedData != nullptr); + BOOST_CHECK_EQUAL(face.sentData[0].wireEncode(), fetchedData->wireEncode()); + + face.receive(*makeInterest(Name("/root/test/small/valid").appendVersion(10))); // should be ignored + face.receive(*makeInterest(Name("/root/test/small/valid").appendSegment(20))); // should be ignored + advanceClocks(1_ms, 10); + BOOST_CHECK_EQUAL(face.sentData.size(), 1); + BOOST_CHECK_EQUAL(storage.size(), 1); + + Block content = face.sentData[0].getContent(); + BOOST_CHECK_NO_THROW(content.parse()); + + BOOST_REQUIRE_EQUAL(content.elements().size(), 3); + BOOST_CHECK_EQUAL(content.elements()[0], smallBlock); + BOOST_CHECK_EQUAL(content.elements()[1], smallBlock); + BOOST_CHECK_EQUAL(content.elements()[2], smallBlock); + + storage.erase("/", true); // clear the storage + face.sentData.clear(); + face.receive(*makeInterest("/root/test/large/valid")); + advanceClocks(1_ms, 10); + + // two data packets are generated, the first one will be sent to both places + // while the second one will only be inserted into the in-memory storage + BOOST_CHECK_EQUAL(face.sentData.size(), 1); + BOOST_CHECK_EQUAL(storage.size(), 2); + + // segment0 should be sent through the face + const auto& component = face.sentData[0].getName().at(-1); + BOOST_CHECK(component.isSegment()); + BOOST_CHECK_EQUAL(component.toSegment(), 0); + + std::vector dataInStorage; + std::copy(storage.begin(), storage.end(), std::back_inserter(dataInStorage)); + + // the Data sent through the face should be the same as the first Data in the storage + BOOST_CHECK_EQUAL(face.sentData[0].getName(), dataInStorage[0].getName()); + BOOST_CHECK_EQUAL(face.sentData[0].getContent(), dataInStorage[0].getContent()); + + content = [&dataInStorage] () -> Block { + EncodingBuffer encoder; + size_t valueLength = encoder.prependByteArray(dataInStorage[1].getContent().value(), + dataInStorage[1].getContent().value_size()); + valueLength += encoder.prependByteArray(dataInStorage[0].getContent().value(), + dataInStorage[0].getContent().value_size()); + encoder.prependVarNumber(valueLength); + encoder.prependVarNumber(tlv::Content); + return encoder.block(); + }(); + + BOOST_CHECK_NO_THROW(content.parse()); + BOOST_REQUIRE_EQUAL(content.elements().size(), 3); + BOOST_CHECK_EQUAL(content.elements()[0], largeBlock); + BOOST_CHECK_EQUAL(content.elements()[1], largeBlock); + BOOST_CHECK_EQUAL(content.elements()[2], largeBlock); + + storage.erase("/", true);// clear the storage + face.sentData.clear(); + face.receive(*makeInterest("/root/test/reject/%80%00/valid")); // returns nack + advanceClocks(1_ms); + BOOST_CHECK_EQUAL(face.sentData.size(), 1); + BOOST_CHECK_EQUAL(face.sentData[0].getContentType(), tlv::ContentType_Nack); + BOOST_CHECK_EQUAL(ControlResponse(face.sentData[0].getContent().blockFromValue()).getCode(), 400); + BOOST_CHECK_EQUAL(storage.size(), 0); // the nack packet will not be inserted into the in-memory storage +} + +BOOST_AUTO_TEST_CASE(NotificationStream) +{ + const uint8_t buf[] = {0x82, 0x01, 0x02}; + const Block block(buf, sizeof(buf)); + auto post = dispatcher.addNotificationStream("test"); + + post(block); + advanceClocks(1_ms); + BOOST_CHECK_EQUAL(face.sentData.size(), 0); + + dispatcher.addTopPrefix("/root"); + advanceClocks(1_ms); + face.sentData.clear(); + + post(block); + advanceClocks(1_ms); + BOOST_CHECK_EQUAL(face.sentData.size(), 1); + BOOST_CHECK_EQUAL(storage.size(), 1); + + post(block); + post(block); + post(block); + advanceClocks(1_ms, 10); + + BOOST_REQUIRE_EQUAL(face.sentData.size(), 4); + BOOST_CHECK_EQUAL(face.sentData[0].getName(), "/root/test/%FE%00"); + BOOST_CHECK_EQUAL(face.sentData[1].getName(), "/root/test/%FE%01"); + BOOST_CHECK_EQUAL(face.sentData[2].getName(), "/root/test/%FE%02"); + BOOST_CHECK_EQUAL(face.sentData[3].getName(), "/root/test/%FE%03"); + + BOOST_CHECK_EQUAL(face.sentData[0].getContent().blockFromValue(), block); + BOOST_CHECK_EQUAL(face.sentData[1].getContent().blockFromValue(), block); + BOOST_CHECK_EQUAL(face.sentData[2].getContent().blockFromValue(), block); + BOOST_CHECK_EQUAL(face.sentData[3].getContent().blockFromValue(), block); + + // each version of notification will be sent to both places + std::vector dataInStorage; + std::copy(storage.begin(), storage.end(), std::back_inserter(dataInStorage)); + BOOST_REQUIRE_EQUAL(dataInStorage.size(), 4); + BOOST_CHECK_EQUAL(dataInStorage[0].getName(), "/root/test/%FE%00"); + BOOST_CHECK_EQUAL(dataInStorage[1].getName(), "/root/test/%FE%01"); + BOOST_CHECK_EQUAL(dataInStorage[2].getName(), "/root/test/%FE%02"); + BOOST_CHECK_EQUAL(dataInStorage[3].getName(), "/root/test/%FE%03"); + + BOOST_CHECK_EQUAL(dataInStorage[0].getContent().blockFromValue(), block); + BOOST_CHECK_EQUAL(dataInStorage[1].getContent().blockFromValue(), block); + BOOST_CHECK_EQUAL(dataInStorage[2].getContent().blockFromValue(), block); + BOOST_CHECK_EQUAL(dataInStorage[3].getContent().blockFromValue(), block); +} + +BOOST_AUTO_TEST_SUITE_END() // TestDispatcher +BOOST_AUTO_TEST_SUITE_END() // Mgmt + +} // namespace tests +} // namespace mgmt +} // namespace ndn diff --git a/tests/unit/mgmt/nfd/channel-status.t.cpp b/tests/unit/mgmt/nfd/channel-status.t.cpp new file mode 100644 index 000000000..9b1a4fa4e --- /dev/null +++ b/tests/unit/mgmt/nfd/channel-status.t.cpp @@ -0,0 +1,86 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/channel-status.hpp" + +#include "tests/boost-test.hpp" +#include + +namespace ndn { +namespace nfd { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Mgmt) +BOOST_AUTO_TEST_SUITE(Nfd) +BOOST_AUTO_TEST_SUITE(TestChannelStatus) + +BOOST_AUTO_TEST_CASE(Encode) +{ + ChannelStatus status1; + status1.setLocalUri("udp4://192.168.2.1"); + Block wire = status1.wireEncode(); + + // These octets are obtained by the snippet below. + // This check is intended to detect unexpected encoding change in the future. + // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { + // printf("0x%02x, ", *it); + // } + static const uint8_t expected[] = { + 0x82, 0x14, 0x81, 0x12, 0x75, 0x64, 0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, + 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x32, 0x2e, 0x31 + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + ChannelStatus status2(wire); + BOOST_CHECK_EQUAL(status1, status2); +} + +BOOST_AUTO_TEST_CASE(Equality) +{ + ChannelStatus status1, status2; + + status1.setLocalUri("udp4://127.0.0.1:6363"); + status2 = status1; + BOOST_CHECK_EQUAL(status1, status2); + + status2.setLocalUri("dev://eth0"); + BOOST_CHECK_NE(status1, status2); +} + +BOOST_AUTO_TEST_CASE(Print) +{ + ChannelStatus status; + BOOST_CHECK_EQUAL(boost::lexical_cast(status), + "Channel(LocalUri: )"); + + status.setLocalUri("udp4://127.0.0.1:6363"); + BOOST_CHECK_EQUAL(boost::lexical_cast(status), + "Channel(LocalUri: udp4://127.0.0.1:6363)"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestChannelStatus +BOOST_AUTO_TEST_SUITE_END() // Nfd +BOOST_AUTO_TEST_SUITE_END() // Mgmt + +} // namespace tests +} // namespace nfd +} // namespace ndn diff --git a/tests/unit-tests/mgmt/nfd/command-options.t.cpp b/tests/unit/mgmt/nfd/command-options.t.cpp similarity index 83% rename from tests/unit-tests/mgmt/nfd/command-options.t.cpp rename to tests/unit/mgmt/nfd/command-options.t.cpp index 470cac9d1..d41c512e5 100644 --- a/tests/unit-tests/mgmt/nfd/command-options.t.cpp +++ b/tests/unit/mgmt/nfd/command-options.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,10 +19,10 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "mgmt/nfd/command-options.hpp" -#include "security/signing-helpers.hpp" +#include "ndn-cxx/mgmt/nfd/command-options.hpp" +#include "ndn-cxx/security/signing-helpers.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace nfd { @@ -37,15 +37,15 @@ BOOST_AUTO_TEST_CASE(Timeout) CommandOptions co; BOOST_CHECK_EQUAL(co.getTimeout(), CommandOptions::DEFAULT_TIMEOUT); - co.setTimeout(time::milliseconds(7414)); - BOOST_CHECK_EQUAL(co.getTimeout(), time::milliseconds(7414)); + co.setTimeout(7414_ms); + BOOST_CHECK_EQUAL(co.getTimeout(), 7414_ms); BOOST_CHECK_THROW(co.setTimeout(time::milliseconds::zero()), std::out_of_range); BOOST_CHECK_THROW(co.setTimeout(time::milliseconds(-1)), std::out_of_range); - BOOST_CHECK_EQUAL(co.getTimeout(), time::milliseconds(7414)); // unchanged after throw + BOOST_CHECK_EQUAL(co.getTimeout(), 7414_ms); // unchanged after throw - co.setTimeout(time::milliseconds(1)); - BOOST_CHECK_EQUAL(co.getTimeout(), time::milliseconds(1)); + co.setTimeout(1_ms); + BOOST_CHECK_EQUAL(co.getTimeout(), 1_ms); } BOOST_AUTO_TEST_CASE(Prefix) diff --git a/tests/unit/mgmt/nfd/control-command.t.cpp b/tests/unit/mgmt/nfd/control-command.t.cpp new file mode 100644 index 000000000..97c67ac81 --- /dev/null +++ b/tests/unit/mgmt/nfd/control-command.t.cpp @@ -0,0 +1,479 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/control-command.hpp" + +#include "tests/boost-test.hpp" + +namespace ndn { +namespace nfd { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Mgmt) +BOOST_AUTO_TEST_SUITE(Nfd) +BOOST_AUTO_TEST_SUITE(TestControlCommand) + +BOOST_AUTO_TEST_CASE(FaceCreateRequest) +{ + FaceCreateCommand command; + + // good with required fields only + ControlParameters p1; + p1.setUri("tcp4://192.0.2.1:6363"); + BOOST_CHECK_NO_THROW(command.validateRequest(p1)); + BOOST_CHECK(Name("/PREFIX/faces/create").isPrefixOf(command.getRequestName("/PREFIX", p1))); + + // good with optional fields + ControlParameters p2(p1); + p2.setLocalUri("tcp4://192.0.2.2:32114") + .setFacePersistency(FACE_PERSISTENCY_PERMANENT) + .setBaseCongestionMarkingInterval(100_ms) + .setDefaultCongestionThreshold(10000) + .setMtu(8192) + .setFlags(0x3) + .setMask(0x1); + BOOST_CHECK_NO_THROW(command.validateRequest(p1)); + + // Uri is required + ControlParameters p3; + BOOST_CHECK_THROW(command.validateRequest(p3), ControlCommand::ArgumentError); + + // Name is forbidden + ControlParameters p4(p1); + p4.setName("/example"); + BOOST_CHECK_THROW(command.validateRequest(p4), ControlCommand::ArgumentError); + + // Flags and Mask must be specified together + ControlParameters p5(p1); + p5.setFlags(0x3); + BOOST_CHECK_THROW(command.validateRequest(p5), ControlCommand::ArgumentError); + + ControlParameters p6(p1); + p6.setMask(0x1); + BOOST_CHECK_THROW(command.validateRequest(p6), ControlCommand::ArgumentError); +} + +BOOST_AUTO_TEST_CASE(FaceCreateResponse) +{ + FaceCreateCommand command; + + // good + ControlParameters p1; + p1.setFaceId(3208) + .setUri("tcp4://192.0.2.1:6363") + .setLocalUri("tcp4://192.0.2.2:32114") + .setFacePersistency(FACE_PERSISTENCY_PERMANENT) + .setBaseCongestionMarkingInterval(500_ns) + .setDefaultCongestionThreshold(12345) + .setMtu(2048) + .setFlags(0x3); + BOOST_CHECK_NO_THROW(command.validateResponse(p1)); + + // Name is forbidden + ControlParameters p2(p1); + p2.setName("/example"); + BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); + + // Mask is forbidden + ControlParameters p3(p1); + p3.setMask(0x1); + BOOST_CHECK_THROW(command.validateResponse(p3), ControlCommand::ArgumentError); + + // FaceId must be valid + ControlParameters p4(p1); + p4.setFaceId(INVALID_FACE_ID); + BOOST_CHECK_THROW(command.validateResponse(p4), ControlCommand::ArgumentError); + + // LocalUri is required + ControlParameters p5(p1); + p5.unsetLocalUri(); + BOOST_CHECK_THROW(command.validateResponse(p5), ControlCommand::ArgumentError); +} + +BOOST_AUTO_TEST_CASE(FaceUpdate) +{ + FaceUpdateCommand command; + + ControlParameters p1; + p1.setFaceId(0); + BOOST_CHECK_NO_THROW(command.validateRequest(p1)); + p1.setFaceId(INVALID_FACE_ID); + BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError); + + p1.setFaceId(1); + BOOST_CHECK_NO_THROW(command.validateRequest(p1)); + BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError); + command.applyDefaultsToRequest(p1); + BOOST_CHECK_EQUAL(p1.getFaceId(), 1); + + ControlParameters p2; + p2.setFaceId(1) + .setFacePersistency(FACE_PERSISTENCY_PERSISTENT) + .setBaseCongestionMarkingInterval(765_ns) + .setDefaultCongestionThreshold(54321) + .setFlagBit(BIT_LOCAL_FIELDS_ENABLED, false); + BOOST_CHECK_NO_THROW(command.validateRequest(p2)); + BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); // Mask forbidden but present + + // Flags without Mask + p2.unsetMask(); + BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError); + BOOST_CHECK_NO_THROW(command.validateResponse(p2)); + + p2.setFlagBit(BIT_LOCAL_FIELDS_ENABLED, false); + p2.unsetFaceId(); + BOOST_CHECK_NO_THROW(command.validateRequest(p2)); + + ControlParameters p3; + p3.setFaceId(1) + .setName("/ndn/name"); + BOOST_CHECK_THROW(command.validateRequest(p3), ControlCommand::ArgumentError); + BOOST_CHECK_THROW(command.validateResponse(p3), ControlCommand::ArgumentError); + + ControlParameters p4; + p4.setFaceId(1) + .setUri("tcp4://192.0.2.1"); + BOOST_CHECK_THROW(command.validateRequest(p4), ControlCommand::ArgumentError); + BOOST_CHECK_THROW(command.validateResponse(p4), ControlCommand::ArgumentError); + + ControlParameters p5; + BOOST_CHECK_NO_THROW(command.validateRequest(p5)); + BOOST_CHECK_THROW(command.validateResponse(p5), ControlCommand::ArgumentError); + BOOST_CHECK(!p5.hasFaceId()); + command.applyDefaultsToRequest(p5); + BOOST_REQUIRE(p5.hasFaceId()); + BOOST_CHECK_NO_THROW(command.validateRequest(p5)); + BOOST_CHECK_THROW(command.validateResponse(p5), ControlCommand::ArgumentError); + BOOST_CHECK_EQUAL(p5.getFaceId(), 0); + + ControlParameters p6; + p6.setFaceId(1) + .setMtu(1024); + BOOST_CHECK_THROW(command.validateRequest(p6), ControlCommand::ArgumentError); + BOOST_CHECK_THROW(command.validateResponse(p6), ControlCommand::ArgumentError); +} + +BOOST_AUTO_TEST_CASE(FaceDestroy) +{ + FaceDestroyCommand command; + + ControlParameters p1; + p1.setUri("tcp4://192.0.2.1") + .setFaceId(4); + BOOST_CHECK_THROW(command.validateRequest(p1), ControlCommand::ArgumentError); + BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError); + + ControlParameters p2; + p2.setFaceId(INVALID_FACE_ID); + BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError); + BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); + + ControlParameters p3; + p3.setFaceId(6); + BOOST_CHECK_NO_THROW(command.validateRequest(p3)); + BOOST_CHECK_NO_THROW(command.validateResponse(p3)); + Name n3; + BOOST_CHECK_NO_THROW(n3 = command.getRequestName("/PREFIX", p3)); + BOOST_CHECK(Name("ndn:/PREFIX/faces/destroy").isPrefixOf(n3)); +} + +BOOST_AUTO_TEST_CASE(FibAddNextHop) +{ + FibAddNextHopCommand command; + + ControlParameters p1; + p1.setName("ndn:/") + .setFaceId(22); + BOOST_CHECK_NO_THROW(command.validateRequest(p1)); + BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError); + Name n1; + BOOST_CHECK_NO_THROW(n1 = command.getRequestName("/PREFIX", p1)); + BOOST_CHECK(Name("ndn:/PREFIX/fib/add-nexthop").isPrefixOf(n1)); + + ControlParameters p2; + p2.setName("ndn:/example") + .setFaceId(0) + .setCost(6); + BOOST_CHECK_NO_THROW(command.validateRequest(p2)); + p2.setFaceId(INVALID_FACE_ID); + BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); + + command.applyDefaultsToRequest(p1); + BOOST_REQUIRE(p1.hasCost()); + BOOST_CHECK_EQUAL(p1.getCost(), 0); + + p1.unsetFaceId(); + BOOST_CHECK_NO_THROW(command.validateRequest(p1)); + command.applyDefaultsToRequest(p1); + BOOST_REQUIRE(p1.hasFaceId()); + BOOST_CHECK_EQUAL(p1.getFaceId(), 0); +} + +BOOST_AUTO_TEST_CASE(FibRemoveNextHop) +{ + FibRemoveNextHopCommand command; + + ControlParameters p1; + p1.setName("ndn:/") + .setFaceId(22); + BOOST_CHECK_NO_THROW(command.validateRequest(p1)); + BOOST_CHECK_NO_THROW(command.validateResponse(p1)); + Name n1; + BOOST_CHECK_NO_THROW(n1 = command.getRequestName("/PREFIX", p1)); + BOOST_CHECK(Name("ndn:/PREFIX/fib/remove-nexthop").isPrefixOf(n1)); + + ControlParameters p2; + p2.setName("ndn:/example") + .setFaceId(0); + BOOST_CHECK_NO_THROW(command.validateRequest(p2)); + p2.setFaceId(INVALID_FACE_ID); + BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); + + p1.unsetFaceId(); + BOOST_CHECK_NO_THROW(command.validateRequest(p1)); + command.applyDefaultsToRequest(p1); + BOOST_REQUIRE(p1.hasFaceId()); + BOOST_CHECK_EQUAL(p1.getFaceId(), 0); +} + +BOOST_AUTO_TEST_CASE(CsConfigRequest) +{ + CsConfigCommand command; + + // good empty request + ControlParameters p1; + command.validateRequest(p1); + BOOST_CHECK(Name("/PREFIX/cs/config").isPrefixOf(command.getRequestName("/PREFIX", p1))); + + // good full request + ControlParameters p2; + p2.setCapacity(1574); + p2.setFlagBit(BIT_CS_ENABLE_ADMIT, true); + p2.setFlagBit(BIT_CS_ENABLE_SERVE, true); + command.validateRequest(p2); + + // bad request: Flags but no Mask + ControlParameters p3(p2); + p3.unsetMask(); + BOOST_CHECK_THROW(command.validateRequest(p3), ControlCommand::ArgumentError); + + // bad request: Mask but no Flags + ControlParameters p4(p2); + p4.unsetFlags(); + BOOST_CHECK_THROW(command.validateRequest(p4), ControlCommand::ArgumentError); + + // bad request: forbidden field + ControlParameters p5(p2); + p5.setName("/example"); + BOOST_CHECK_THROW(command.validateRequest(p5), ControlCommand::ArgumentError); +} + +BOOST_AUTO_TEST_CASE(CsConfigResponse) +{ + CsConfigCommand command; + + // bad empty response + ControlParameters p1; + BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError); + + // bad response: Mask not allowed + ControlParameters p2; + p2.setCapacity(1574); + p2.setFlagBit(BIT_CS_ENABLE_ADMIT, true); + p2.setFlagBit(BIT_CS_ENABLE_SERVE, true); + BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); + + // good response + ControlParameters p3(p2); + p3.unsetMask(); + command.validateResponse(p3); +} + +BOOST_AUTO_TEST_CASE(CsEraseRequest) +{ + CsEraseCommand command; + + // good no-limit request + ControlParameters p1; + p1.setName("/u4LYPNU8Q"); + command.validateRequest(p1); + BOOST_CHECK(Name("/PREFIX/cs/erase").isPrefixOf(command.getRequestName("/PREFIX", p1))); + + // good limited request + ControlParameters p2; + p2.setName("/IMw1RaLF"); + p2.setCount(177); + command.validateRequest(p2); + + // bad request: zero entry + ControlParameters p3; + p3.setName("/ahMID1jcib"); + p3.setCount(0); + BOOST_CHECK_THROW(command.validateRequest(p3), ControlCommand::ArgumentError); + + // bad request: forbidden field + ControlParameters p4(p2); + p4.setCapacity(278); + BOOST_CHECK_THROW(command.validateRequest(p3), ControlCommand::ArgumentError); +} + +BOOST_AUTO_TEST_CASE(CsEraseResponse) +{ + CsEraseCommand command; + + // good normal response + ControlParameters p1; + p1.setName("/TwiIwCdR"); + p1.setCount(1); + command.validateResponse(p1); + + // good limit exceeded request + ControlParameters p2; + p2.setName("/NMsiy44pr"); + p2.setCapacity(360); + p2.setCount(360); + command.validateResponse(p2); + + // good zero-entry response + ControlParameters p3; + p3.setName("/5f1LRPh1L"); + p3.setCount(0); + command.validateResponse(p3); + + // bad request: missing Count + ControlParameters p4(p1); + p4.unsetCount(); + BOOST_CHECK_THROW(command.validateResponse(p4), ControlCommand::ArgumentError); + + // bad request: zero capacity + ControlParameters p5(p1); + p5.setCapacity(0); + BOOST_CHECK_THROW(command.validateResponse(p5), ControlCommand::ArgumentError); +} + +BOOST_AUTO_TEST_CASE(StrategyChoiceSet) +{ + StrategyChoiceSetCommand command; + + ControlParameters p1; + p1.setName("ndn:/") + .setStrategy("ndn:/strategy/P"); + BOOST_CHECK_NO_THROW(command.validateRequest(p1)); + BOOST_CHECK_NO_THROW(command.validateResponse(p1)); + Name n1; + BOOST_CHECK_NO_THROW(n1 = command.getRequestName("/PREFIX", p1)); + BOOST_CHECK(Name("ndn:/PREFIX/strategy-choice/set").isPrefixOf(n1)); + + ControlParameters p2; + p2.setName("ndn:/example"); + BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError); + BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); +} + +BOOST_AUTO_TEST_CASE(StrategyChoiceUnset) +{ + StrategyChoiceUnsetCommand command; + + ControlParameters p1; + p1.setName("ndn:/example"); + BOOST_CHECK_NO_THROW(command.validateRequest(p1)); + BOOST_CHECK_NO_THROW(command.validateResponse(p1)); + Name n1; + BOOST_CHECK_NO_THROW(n1 = command.getRequestName("/PREFIX", p1)); + BOOST_CHECK(Name("ndn:/PREFIX/strategy-choice/unset").isPrefixOf(n1)); + + ControlParameters p2; + p2.setName("ndn:/example") + .setStrategy("ndn:/strategy/P"); + BOOST_CHECK_THROW(command.validateRequest(p2), ControlCommand::ArgumentError); + BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); + + ControlParameters p3; + p3.setName("ndn:/"); + BOOST_CHECK_THROW(command.validateRequest(p3), ControlCommand::ArgumentError); + BOOST_CHECK_THROW(command.validateResponse(p3), ControlCommand::ArgumentError); +} + +BOOST_AUTO_TEST_CASE(RibRegister) +{ + RibRegisterCommand command; + + ControlParameters p1; + p1.setName("ndn:/"); + BOOST_CHECK_NO_THROW(command.validateRequest(p1)); + BOOST_CHECK_THROW(command.validateResponse(p1), ControlCommand::ArgumentError); + Name n1; + BOOST_CHECK_NO_THROW(n1 = command.getRequestName("/PREFIX", p1)); + BOOST_CHECK(Name("ndn:/PREFIX/rib/register").isPrefixOf(n1)); + + command.applyDefaultsToRequest(p1); + BOOST_REQUIRE(p1.hasOrigin()); + BOOST_CHECK_EQUAL(p1.getOrigin(), ROUTE_ORIGIN_APP); + BOOST_REQUIRE(p1.hasCost()); + BOOST_CHECK_EQUAL(p1.getCost(), 0); + BOOST_REQUIRE(p1.hasFlags()); + BOOST_CHECK_EQUAL(p1.getFlags(), static_cast(ROUTE_FLAG_CHILD_INHERIT)); + BOOST_CHECK_EQUAL(p1.hasExpirationPeriod(), false); + + ControlParameters p2; + p2.setName("ndn:/example") + .setFaceId(2) + .setCost(6); + BOOST_CHECK_NO_THROW(command.validateRequest(p2)); + command.applyDefaultsToRequest(p2); + BOOST_CHECK_EQUAL(p2.hasExpirationPeriod(), false); + BOOST_CHECK_NO_THROW(command.validateResponse(p2)); +} + +BOOST_AUTO_TEST_CASE(RibUnregister) +{ + RibUnregisterCommand command; + + ControlParameters p1; + p1.setName("ndn:/") + .setFaceId(22) + .setOrigin(ROUTE_ORIGIN_STATIC); + BOOST_CHECK_NO_THROW(command.validateRequest(p1)); + BOOST_CHECK_NO_THROW(command.validateResponse(p1)); + Name n1; + BOOST_CHECK_NO_THROW(n1 = command.getRequestName("/PREFIX", p1)); + BOOST_CHECK(Name("ndn:/PREFIX/rib/unregister").isPrefixOf(n1)); + + ControlParameters p2; + p2.setName("ndn:/example") + .setFaceId(0) + .setOrigin(ROUTE_ORIGIN_APP); + BOOST_CHECK_NO_THROW(command.validateRequest(p2)); + p2.setFaceId(INVALID_FACE_ID); + BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); + + p2.unsetFaceId(); + BOOST_CHECK_NO_THROW(command.validateRequest(p2)); + BOOST_CHECK_THROW(command.validateResponse(p2), ControlCommand::ArgumentError); +} + +BOOST_AUTO_TEST_SUITE_END() // TestControlCommand +BOOST_AUTO_TEST_SUITE_END() // Nfd +BOOST_AUTO_TEST_SUITE_END() // Mgmt + +} // namespace tests +} // namespace nfd +} // namespace ndn diff --git a/tests/unit/mgmt/nfd/control-parameters.t.cpp b/tests/unit/mgmt/nfd/control-parameters.t.cpp new file mode 100644 index 000000000..b09852959 --- /dev/null +++ b/tests/unit/mgmt/nfd/control-parameters.t.cpp @@ -0,0 +1,247 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/control-parameters.hpp" + +#include "tests/boost-test.hpp" + +namespace ndn { +namespace nfd { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Mgmt) +BOOST_AUTO_TEST_SUITE(Nfd) +BOOST_AUTO_TEST_SUITE(TestControlParameters) + +BOOST_AUTO_TEST_CASE(Fields) +{ + ControlParameters input; + + ControlParameters decoded(input.wireEncode()); + BOOST_CHECK_EQUAL(decoded.hasName(), false); + BOOST_CHECK_EQUAL(decoded.hasFaceId(), false); + BOOST_CHECK_EQUAL(decoded.hasUri(), false); + BOOST_CHECK_EQUAL(decoded.hasLocalUri(), false); + BOOST_CHECK_EQUAL(decoded.hasOrigin(), false); + BOOST_CHECK_EQUAL(decoded.hasCost(), false); + BOOST_CHECK_EQUAL(decoded.hasCapacity(), false); + BOOST_CHECK_EQUAL(decoded.hasCount(), false); + BOOST_CHECK_EQUAL(decoded.hasFlags(), false); + BOOST_CHECK_EQUAL(decoded.hasMask(), false); + BOOST_CHECK_EQUAL(decoded.hasStrategy(), false); + BOOST_CHECK_EQUAL(decoded.hasExpirationPeriod(), false); + BOOST_CHECK_EQUAL(decoded.hasFacePersistency(), false); + + input.setName("/name"); + input.setFaceId(2634); + input.setUri("udp4://192.0.2.1:6363"); + input.setLocalUri("udp4://192.0.2.2:6363"); + input.setOrigin(ROUTE_ORIGIN_NLSR); + input.setCost(1388); + input.setCapacity(2632); + input.setCount(3100); + input.setFlags(0xAFC4); + input.setMask(0xF7A1); + input.setStrategy("/strategy-name"); + input.setExpirationPeriod(1800000_ms); + input.setFacePersistency(FacePersistency::FACE_PERSISTENCY_PERSISTENT); + + decoded.wireDecode(input.wireEncode()); + BOOST_CHECK_EQUAL(decoded.hasName(), true); + BOOST_CHECK_EQUAL(decoded.hasFaceId(), true); + BOOST_CHECK_EQUAL(decoded.hasUri(), true); + BOOST_CHECK_EQUAL(decoded.hasLocalUri(), true); + BOOST_CHECK_EQUAL(decoded.hasOrigin(), true); + BOOST_CHECK_EQUAL(decoded.hasCost(), true); + BOOST_CHECK_EQUAL(decoded.hasCapacity(), true); + BOOST_CHECK_EQUAL(decoded.hasCount(), true); + BOOST_CHECK_EQUAL(decoded.hasFlags(), true); + BOOST_CHECK_EQUAL(decoded.hasMask(), true); + BOOST_CHECK_EQUAL(decoded.hasStrategy(), true); + BOOST_CHECK_EQUAL(decoded.hasExpirationPeriod(), true); + BOOST_CHECK_EQUAL(decoded.hasFacePersistency(), true); + + BOOST_CHECK_EQUAL(decoded.getName(), "/name"); + BOOST_CHECK_EQUAL(decoded.getFaceId(), 2634); + BOOST_CHECK_EQUAL(decoded.getUri(), "udp4://192.0.2.1:6363"); + BOOST_CHECK_EQUAL(decoded.getLocalUri(), "udp4://192.0.2.2:6363"); + BOOST_CHECK_EQUAL(decoded.getOrigin(), ROUTE_ORIGIN_NLSR); + BOOST_CHECK_EQUAL(decoded.getCost(), 1388); + BOOST_CHECK_EQUAL(decoded.getCapacity(), 2632); + BOOST_CHECK_EQUAL(decoded.getCount(), 3100); + BOOST_CHECK_EQUAL(decoded.getFlags(), 0xAFC4); + BOOST_CHECK_EQUAL(decoded.getMask(), 0xF7A1); + BOOST_CHECK_EQUAL(decoded.getStrategy(), "/strategy-name"); + BOOST_CHECK_EQUAL(decoded.getExpirationPeriod(), 1800000_ms); + BOOST_CHECK_EQUAL(decoded.getFacePersistency(), FacePersistency::FACE_PERSISTENCY_PERSISTENT); + + input.unsetName(); + input.unsetFaceId(); + input.unsetUri(); + input.unsetLocalUri(); + input.unsetOrigin(); + input.unsetCost(); + input.unsetCapacity(); + input.unsetCount(); + input.unsetFlags(); + input.unsetMask(); + input.unsetStrategy(); + input.unsetExpirationPeriod(); + input.unsetFacePersistency(); + BOOST_CHECK_EQUAL(input.hasName(), false); + BOOST_CHECK_EQUAL(input.hasFaceId(), false); + BOOST_CHECK_EQUAL(input.hasUri(), false); + BOOST_CHECK_EQUAL(input.hasLocalUri(), false); + BOOST_CHECK_EQUAL(input.hasOrigin(), false); + BOOST_CHECK_EQUAL(input.hasCost(), false); + BOOST_CHECK_EQUAL(input.hasCapacity(), false); + BOOST_CHECK_EQUAL(input.hasCount(), false); + BOOST_CHECK_EQUAL(input.hasFlags(), false); + BOOST_CHECK_EQUAL(input.hasMask(), false); + BOOST_CHECK_EQUAL(input.hasStrategy(), false); + BOOST_CHECK_EQUAL(input.hasExpirationPeriod(), false); + BOOST_CHECK_EQUAL(input.hasFacePersistency(), false); +} + +BOOST_AUTO_TEST_CASE(FlagsAndMask) +{ + ControlParameters p; + + BOOST_CHECK(!p.hasFlags()); + BOOST_CHECK(!p.hasMask()); + BOOST_CHECK(!p.hasFlagBit(0)); + BOOST_CHECK(!p.getFlagBit(0)); + + // Set bit 2 to true (change Mask) + p.setFlagBit(2, true); + // 2^2 = 4 + BOOST_CHECK_EQUAL(p.getFlags(), 4); + BOOST_CHECK_EQUAL(p.getMask(), 4); + BOOST_CHECK(p.hasFlagBit(2)); + BOOST_CHECK(p.getFlagBit(2)); + BOOST_CHECK(!p.hasFlagBit(1)); + BOOST_CHECK(!p.getFlagBit(1)); + + // Set bit 3 to true (no change to Mask) + p.setFlagBit(3, true, false); + // 2^3 + 2^2 = 12 + BOOST_CHECK_EQUAL(p.getFlags(), 12); + // 2^2 = 4 + BOOST_CHECK_EQUAL(p.getMask(), 4); + BOOST_CHECK(!p.hasFlagBit(3)); + BOOST_CHECK(p.getFlagBit(3)); + BOOST_CHECK(p.hasFlagBit(2)); + BOOST_CHECK(p.getFlagBit(2)); + + // Set bit 1 to false (change Mask) + p.setFlagBit(1, false); + // 2^3 + 2^2 = 12 + BOOST_CHECK_EQUAL(p.getFlags(), 12); + // 2^2 + 2^1 = 6 + BOOST_CHECK_EQUAL(p.getMask(), 6); + BOOST_CHECK(!p.hasFlagBit(3)); + BOOST_CHECK(p.getFlagBit(3)); + BOOST_CHECK(p.hasFlagBit(2)); + BOOST_CHECK(p.getFlagBit(2)); + BOOST_CHECK(p.hasFlagBit(1)); + BOOST_CHECK(!p.getFlagBit(1)); + + // Set bit 2 to false (change Mask) + p.setFlagBit(2, false); + // 2^3 = 8 + BOOST_CHECK_EQUAL(p.getFlags(), 8); + // 2^2 + 2^1 = 6 + BOOST_CHECK_EQUAL(p.getMask(), 6); + BOOST_CHECK(!p.hasFlagBit(3)); + BOOST_CHECK(p.getFlagBit(3)); + BOOST_CHECK(p.hasFlagBit(2)); + BOOST_CHECK(!p.getFlagBit(2)); + BOOST_CHECK(p.hasFlagBit(1)); + BOOST_CHECK(!p.getFlagBit(1)); + + // Set bit 0 to true (change Mask) + p.setFlagBit(0, true); + // 2^3 + 2^0 = 9 + BOOST_CHECK_EQUAL(p.getFlags(), 9); + // 2^2 + 2^1 + 2^0 = 7 + BOOST_CHECK_EQUAL(p.getMask(), 7); + BOOST_CHECK(p.hasFlagBit(0)); + BOOST_CHECK(p.getFlagBit(0)); + + // Unset bit 0 + p.unsetFlagBit(0); + BOOST_REQUIRE(p.hasFlags()); + BOOST_REQUIRE(p.hasMask()); + // 2^3 + 2^0 = 9 + BOOST_CHECK_EQUAL(p.getFlags(), 9); + // 2^2 + 2^1 = 6 + BOOST_CHECK_EQUAL(p.getMask(), 6); + BOOST_CHECK(p.hasFlagBit(1)); + BOOST_CHECK(!p.hasFlagBit(0)); + BOOST_CHECK(p.getFlagBit(0)); + + // Unset bit 3 (already unset in Mask, so no change) + p.unsetFlagBit(3); + BOOST_REQUIRE(p.hasFlags()); + BOOST_REQUIRE(p.hasMask()); + // 2^3 + 2^0 = 9 + BOOST_CHECK_EQUAL(p.getFlags(), 9); + // 2^2 + 2^1 = 6 + BOOST_CHECK_EQUAL(p.getMask(), 6); + BOOST_CHECK(!p.hasFlagBit(3)); + BOOST_CHECK(p.getFlagBit(3)); + + // Unset bit 2 + p.unsetFlagBit(2); + BOOST_REQUIRE(p.hasFlags()); + BOOST_REQUIRE(p.hasMask()); + // 2^3 + 2^0 = 9 + BOOST_CHECK_EQUAL(p.getFlags(), 9); + // 2^1 = 2 + BOOST_CHECK_EQUAL(p.getMask(), 2); + BOOST_CHECK(!p.hasFlagBit(2)); + BOOST_CHECK(!p.getFlagBit(2)); + + // Unset bit 1 + // Flags and Mask fields will be deleted as Mask is now 0 + p.unsetFlagBit(1); + BOOST_CHECK(!p.hasFlags()); + BOOST_CHECK(!p.hasMask()); + BOOST_CHECK(!p.hasFlagBit(3)); + BOOST_CHECK(!p.getFlagBit(3)); + BOOST_CHECK(!p.hasFlagBit(2)); + BOOST_CHECK(!p.getFlagBit(2)); + BOOST_CHECK(!p.hasFlagBit(1)); + BOOST_CHECK(!p.getFlagBit(1)); + BOOST_CHECK(!p.hasFlagBit(0)); + BOOST_CHECK(!p.getFlagBit(0)); + + BOOST_CHECK_THROW(p.setFlagBit(64, true), std::out_of_range); + BOOST_CHECK_THROW(p.unsetFlagBit(64), std::out_of_range); +} + +BOOST_AUTO_TEST_SUITE_END() // TestControlParameters +BOOST_AUTO_TEST_SUITE_END() // Nfd +BOOST_AUTO_TEST_SUITE_END() // Mgmt + +} // namespace tests +} // namespace nfd +} // namespace ndn diff --git a/tests/unit-tests/mgmt/nfd/controller-fixture.hpp b/tests/unit/mgmt/nfd/controller-fixture.hpp similarity index 78% rename from tests/unit-tests/mgmt/nfd/controller-fixture.hpp rename to tests/unit/mgmt/nfd/controller-fixture.hpp index 76e7bde5c..bc42e2063 100644 --- a/tests/unit-tests/mgmt/nfd/controller-fixture.hpp +++ b/tests/unit/mgmt/nfd/controller-fixture.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,15 +19,15 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#ifndef NDN_TESTS_MGMT_NFD_CONTROLLER_FIXTURE_HPP -#define NDN_TESTS_MGMT_NFD_CONTROLLER_FIXTURE_HPP +#ifndef NDN_TESTS_UNIT_MGMT_NFD_CONTROLLER_FIXTURE_HPP +#define NDN_TESTS_UNIT_MGMT_NFD_CONTROLLER_FIXTURE_HPP -#include "mgmt/nfd/controller.hpp" -#include "../../../dummy-validator.hpp" +#include "ndn-cxx/mgmt/nfd/controller.hpp" +#include "ndn-cxx/security/v2/certificate-fetcher-offline.hpp" +#include "ndn-cxx/util/dummy-client-face.hpp" -#include "boost-test.hpp" -#include "util/dummy-client-face.hpp" -#include "../../identity-management-time-fixture.hpp" +#include "tests/unit/dummy-validator.hpp" +#include "tests/unit/identity-management-time-fixture.hpp" namespace ndn { namespace nfd { @@ -40,17 +40,13 @@ class ControllerFixture : public IdentityManagementTimeFixture protected: ControllerFixture() : face(io, m_keyChain) + , m_validator(true) , controller(face, m_keyChain, m_validator) , commandFailCallback(bind(&ControllerFixture::recordCommandFail, this, _1)) , datasetFailCallback(bind(&ControllerFixture::recordDatasetFail, this, _1, _2)) { Name identityName("/localhost/ControllerFixture"); - if (this->addIdentity(identityName)) { - m_keyChain.setDefaultIdentity(identityName); - } - else { - BOOST_FAIL("cannot create identity"); - } + m_keyChain.setDefaultIdentity(this->addIdentity(identityName)); } /** \brief controls whether Controller's validator should accept or reject validation requests @@ -61,7 +57,7 @@ class ControllerFixture : public IdentityManagementTimeFixture void setValidationResult(bool shouldAccept) { - m_validator.setResult(shouldAccept); + m_validator.getPolicy().setResult(shouldAccept); } private: @@ -79,17 +75,15 @@ class ControllerFixture : public IdentityManagementTimeFixture protected: ndn::util::DummyClientFace face; + DummyValidator m_validator; Controller controller; Controller::CommandFailCallback commandFailCallback; Controller::DatasetFailCallback datasetFailCallback; std::vector failCodes; - -private: - DummyValidator m_validator; }; } // namespace tests } // namespace nfd } // namespace ndn -#endif // NDN_TESTS_MGMT_NFD_CONTROLLER_FIXTURE_HPP +#endif // NDN_TESTS_UNIT_MGMT_NFD_CONTROLLER_FIXTURE_HPP diff --git a/tests/unit/mgmt/nfd/controller.t.cpp b/tests/unit/mgmt/nfd/controller.t.cpp new file mode 100644 index 000000000..01ff7670a --- /dev/null +++ b/tests/unit/mgmt/nfd/controller.t.cpp @@ -0,0 +1,274 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/controller.hpp" +#include "ndn-cxx/mgmt/nfd/control-response.hpp" + +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" +#include "tests/unit/mgmt/nfd/controller-fixture.hpp" + +namespace ndn { +namespace nfd { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Mgmt) +BOOST_AUTO_TEST_SUITE(Nfd) + +class CommandFixture : public ControllerFixture +{ +protected: + CommandFixture() + : succeedCallback(bind(&CommandFixture::succeed, this, _1)) + { + } + + void + respond(const ControlResponse& responsePayload) + { + auto responseData = makeData(face.sentInterests.at(0).getName()); + responseData->setContent(responsePayload.wireEncode()); + face.receive(*responseData); + this->advanceClocks(1_ms); + } + +private: + void + succeed(const ControlParameters& parameters) + { + succeeds.push_back(parameters); + } + +protected: + Controller::CommandSucceedCallback succeedCallback; + std::vector succeeds; +}; + +// This test suite focuses on ControlCommand functionality of Controller. +// Individual commands are tested in nfd-control-command.t.cpp +// StatusDataset functionality is tested in nfd-status-dataset.t.cpp +BOOST_FIXTURE_TEST_SUITE(TestController, CommandFixture) + +static ControlParameters +makeFaceCreateResponse() +{ + ControlParameters resp; + resp.setFaceId(22) + .setUri("tcp4://192.0.2.1:6363") + .setLocalUri("tcp4://192.0.2.2:10847") + .setFacePersistency(ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERSISTENT) + .setFlags(0x7); + return resp; +} + +BOOST_AUTO_TEST_CASE(Success) +{ + ControlParameters parameters; + parameters.setUri("tcp4://192.0.2.1:6363"); + + controller.start(parameters, succeedCallback, commandFailCallback); + this->advanceClocks(1_ms); + + BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1); + const Interest& requestInterest = face.sentInterests[0]; + + FaceCreateCommand command; + BOOST_CHECK(Name("/localhost/nfd/faces/create").isPrefixOf(requestInterest.getName())); + // 9 components: ndn:/localhost/nfd/faces/create// + BOOST_REQUIRE_EQUAL(requestInterest.getName().size(), 9); + ControlParameters request; + // 4th component: + BOOST_REQUIRE_NO_THROW(request.wireDecode(requestInterest.getName().at(4).blockFromValue())); + BOOST_CHECK_NO_THROW(command.validateRequest(request)); + BOOST_CHECK_EQUAL(request.getUri(), parameters.getUri()); + BOOST_CHECK_EQUAL(requestInterest.getInterestLifetime(), CommandOptions::DEFAULT_TIMEOUT); + + ControlParameters responseBody = makeFaceCreateResponse(); + ControlResponse responsePayload(201, "created"); + responsePayload.setBody(responseBody.wireEncode()); + this->respond(responsePayload); + + BOOST_CHECK_EQUAL(failCodes.size(), 0); + BOOST_REQUIRE_EQUAL(succeeds.size(), 1); + BOOST_CHECK_EQUAL(succeeds.back().getUri(), responseBody.getUri()); + BOOST_CHECK_EQUAL(succeeds.back().getFaceId(), responseBody.getFaceId()); +} + +BOOST_AUTO_TEST_CASE(SuccessNoCallback) +{ + ControlParameters parameters; + parameters.setUri("tcp4://192.0.2.1:6363"); + + controller.start(parameters, nullptr, commandFailCallback); + this->advanceClocks(1_ms); + + ControlParameters responseBody = makeFaceCreateResponse(); + ControlResponse responsePayload(201, "created"); + responsePayload.setBody(responseBody.wireEncode()); + this->respond(responsePayload); + + BOOST_CHECK_EQUAL(failCodes.size(), 0); +} + +BOOST_AUTO_TEST_CASE(OptionsPrefix) +{ + ControlParameters parameters; + parameters.setName("/ndn/com/example"); + parameters.setFaceId(400); + + CommandOptions options; + options.setPrefix("/localhop/net/example/router1/nfd"); + + controller.start(parameters, succeedCallback, commandFailCallback, options); + this->advanceClocks(1_ms); + + BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1); + const Interest& requestInterest = face.sentInterests[0]; + + FaceCreateCommand command; + BOOST_CHECK(Name("/localhop/net/example/router1/nfd/rib/register").isPrefixOf(requestInterest.getName())); +} + +BOOST_AUTO_TEST_CASE(InvalidRequest) +{ + ControlParameters parameters; + parameters.setName("ndn:/should-not-have-this-field"); + // Uri is missing + + BOOST_CHECK_THROW(controller.start( + parameters, succeedCallback, commandFailCallback), + ControlCommand::ArgumentError); +} + +BOOST_AUTO_TEST_CASE(ValidationFailure) +{ + this->setValidationResult(false); + + ControlParameters parameters; + parameters.setUri("tcp4://192.0.2.1:6363"); + + controller.start(parameters, succeedCallback, commandFailCallback); + this->advanceClocks(1_ms); + + ControlParameters responseBody = makeFaceCreateResponse(); + ControlResponse responsePayload(201, "created"); + responsePayload.setBody(responseBody.wireEncode()); + this->respond(responsePayload); + + BOOST_CHECK_EQUAL(succeeds.size(), 0); + BOOST_REQUIRE_EQUAL(failCodes.size(), 1); + BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_VALIDATION); +} + +BOOST_AUTO_TEST_CASE(ErrorCode) +{ + ControlParameters parameters; + parameters.setUri("tcp4://192.0.2.1:6363"); + + controller.start(parameters, succeedCallback, commandFailCallback); + this->advanceClocks(1_ms); + + ControlResponse responsePayload(401, "Not Authenticated"); + this->respond(responsePayload); + + BOOST_CHECK_EQUAL(succeeds.size(), 0); + BOOST_REQUIRE_EQUAL(failCodes.size(), 1); + BOOST_CHECK_EQUAL(failCodes.back(), 401); +} + +BOOST_AUTO_TEST_CASE(InvalidResponse) +{ + ControlParameters parameters; + parameters.setUri("tcp4://192.0.2.1:6363"); + + controller.start(parameters, succeedCallback, commandFailCallback); + this->advanceClocks(1_ms); + + ControlParameters responseBody = makeFaceCreateResponse(); + responseBody.unsetFaceId() // FaceId is missing + .setName("ndn:/should-not-have-this-field"); + ControlResponse responsePayload(201, "created"); + responsePayload.setBody(responseBody.wireEncode()); + this->respond(responsePayload); + + BOOST_CHECK_EQUAL(succeeds.size(), 0); + BOOST_REQUIRE_EQUAL(failCodes.size(), 1); +} + +BOOST_AUTO_TEST_CASE(Nack) +{ + ControlParameters parameters; + parameters.setUri("tcp4://192.0.2.1:6363"); + + controller.start(parameters, succeedCallback, commandFailCallback); + this->advanceClocks(1_ms); + + BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1); + const Interest& requestInterest = face.sentInterests[0]; + + auto responseNack = makeNack(requestInterest, lp::NackReason::NO_ROUTE); + face.receive(responseNack); + this->advanceClocks(1_ms); + + BOOST_REQUIRE_EQUAL(failCodes.size(), 1); + BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_NACK); +} + +BOOST_AUTO_TEST_CASE(Timeout) +{ + ControlParameters parameters; + parameters.setUri("tcp4://192.0.2.1:6363"); + + CommandOptions options; + options.setTimeout(50_ms); + + controller.start(parameters, succeedCallback, commandFailCallback, options); + this->advanceClocks(1_ms); // express Interest + this->advanceClocks(51_ms); // timeout + + BOOST_REQUIRE_EQUAL(failCodes.size(), 1); + BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_TIMEOUT); +} + +BOOST_AUTO_TEST_CASE(FailureNoCallback) +{ + ControlParameters parameters; + parameters.setUri("tcp4://192.0.2.1:6363"); + + CommandOptions options; + options.setTimeout(50_ms); + + controller.start(parameters, succeedCallback, nullptr, options); + this->advanceClocks(1_ms); // express Interest + this->advanceClocks(51_ms); // timeout + + BOOST_CHECK_EQUAL(succeeds.size(), 0); +} + +BOOST_AUTO_TEST_SUITE_END() // TestController +BOOST_AUTO_TEST_SUITE_END() // Nfd +BOOST_AUTO_TEST_SUITE_END() // Mgmt + +} // namespace tests +} // namespace nfd +} // namespace ndn diff --git a/tests/unit/mgmt/nfd/cs-info.t.cpp b/tests/unit/mgmt/nfd/cs-info.t.cpp new file mode 100644 index 000000000..3bc5f7b1d --- /dev/null +++ b/tests/unit/mgmt/nfd/cs-info.t.cpp @@ -0,0 +1,127 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/cs-info.hpp" + +#include "tests/boost-test.hpp" +#include + +namespace ndn { +namespace nfd { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Mgmt) +BOOST_AUTO_TEST_SUITE(Nfd) +BOOST_AUTO_TEST_SUITE(TestCsInfo) + +static CsInfo +makeCsInfo() +{ + return CsInfo() + .setCapacity(20177) + .setEnableAdmit(false) + .setEnableServe(true) + .setNEntries(5509) + .setNHits(12951) + .setNMisses(28179); +} + +BOOST_AUTO_TEST_CASE(Encode) +{ + CsInfo csi1 = makeCsInfo(); + Block wire = csi1.wireEncode(); + + static const uint8_t EXPECTED[] = { + 0x80, 0x13, // CsInfo + 0x83, 0x02, 0x4E, 0xD1, // Capacity + 0x6C, 0x01, 0x02, // Flags + 0x87, 0x02, 0x15, 0x85, // NCsEntries + 0x81, 0x02, 0x32, 0x97, // NHits + 0x82, 0x02, 0x6E, 0x13, // NMisses + }; + BOOST_CHECK_EQUAL_COLLECTIONS(wire.begin(), wire.end(), EXPECTED, EXPECTED + sizeof(EXPECTED)); + + CsInfo csi2(wire); + BOOST_CHECK_EQUAL(csi2.getCapacity(), 20177); + BOOST_CHECK_EQUAL(csi2.getEnableAdmit(), false); + BOOST_CHECK_EQUAL(csi2.getEnableServe(), true); + BOOST_CHECK_EQUAL(csi2.getNEntries(), 5509); + BOOST_CHECK_EQUAL(csi2.getNHits(), 12951); + BOOST_CHECK_EQUAL(csi2.getNMisses(), 28179); +} + +BOOST_AUTO_TEST_CASE(Equality) +{ + CsInfo csi1, csi2; + BOOST_CHECK_EQUAL(csi1, csi2); + + csi1 = makeCsInfo(); + BOOST_CHECK_NE(csi1, csi2); + csi2 = csi1; + BOOST_CHECK_EQUAL(csi1, csi2); + + csi2.setCapacity(csi2.getCapacity() + 1); + BOOST_CHECK_NE(csi1, csi2); + csi2 = csi1; + + csi2.setEnableAdmit(!csi2.getEnableAdmit()); + BOOST_CHECK_NE(csi1, csi2); + csi2 = csi1; + + csi2.setEnableServe(!csi2.getEnableServe()); + BOOST_CHECK_NE(csi1, csi2); + csi2 = csi1; + + csi2.setNEntries(csi2.getNEntries() + 1); + BOOST_CHECK_NE(csi1, csi2); + csi2 = csi1; + + csi2.setNHits(csi2.getNHits() + 1); + BOOST_CHECK_NE(csi1, csi2); + csi2 = csi1; + + csi2.setNMisses(csi2.getNMisses() + 1); + BOOST_CHECK_NE(csi1, csi2); + csi2 = csi1; +} + +BOOST_AUTO_TEST_CASE(Print) +{ + CsInfo csi; + BOOST_CHECK_EQUAL(boost::lexical_cast(csi), + "CsInfo: 0 entries, 0 max, admit disabled, serve disabled, 0 hits, 0 misses"); + + csi = makeCsInfo(); + BOOST_CHECK_EQUAL(boost::lexical_cast(csi), + "CsInfo: 5509 entries, 20177 max, admit disabled, serve enabled, 12951 hits, 28179 misses"); + + csi.setEnableAdmit(true).setNHits(1).setNMisses(1); + BOOST_CHECK_EQUAL(boost::lexical_cast(csi), + "CsInfo: 5509 entries, 20177 max, admit enabled, serve enabled, 1 hit, 1 miss"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestCsInfo +BOOST_AUTO_TEST_SUITE_END() // Nfd +BOOST_AUTO_TEST_SUITE_END() // Mgmt + +} // namespace tests +} // namespace nfd +} // namespace ndn diff --git a/tests/unit/mgmt/nfd/face-event-notification.t.cpp b/tests/unit/mgmt/nfd/face-event-notification.t.cpp new file mode 100644 index 000000000..3354a1b2d --- /dev/null +++ b/tests/unit/mgmt/nfd/face-event-notification.t.cpp @@ -0,0 +1,269 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/face-event-notification.hpp" + +#include "tests/boost-test.hpp" +#include + +namespace ndn { +namespace nfd { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Mgmt) +BOOST_AUTO_TEST_SUITE(Nfd) +BOOST_AUTO_TEST_SUITE(TestFaceEventNotification) + +BOOST_AUTO_TEST_CASE(Traits) +{ + FaceEventNotification notification; + BOOST_CHECK_EQUAL(notification.getFaceScope(), FACE_SCOPE_NON_LOCAL); + BOOST_CHECK_EQUAL(notification.getFacePersistency(), FACE_PERSISTENCY_PERSISTENT); + BOOST_CHECK_EQUAL(notification.getLinkType(), LINK_TYPE_POINT_TO_POINT); + + notification.setFaceScope(FACE_SCOPE_LOCAL); + BOOST_CHECK_EQUAL(notification.getFaceScope(), FACE_SCOPE_LOCAL); + BOOST_CHECK_EQUAL(notification.getFacePersistency(), FACE_PERSISTENCY_PERSISTENT); + BOOST_CHECK_EQUAL(notification.getLinkType(), LINK_TYPE_POINT_TO_POINT); + + notification.setFacePersistency(FACE_PERSISTENCY_ON_DEMAND); + BOOST_CHECK_EQUAL(notification.getFaceScope(), FACE_SCOPE_LOCAL); + BOOST_CHECK_EQUAL(notification.getFacePersistency(), FACE_PERSISTENCY_ON_DEMAND); + BOOST_CHECK_EQUAL(notification.getLinkType(), LINK_TYPE_POINT_TO_POINT); + + notification.setFacePersistency(FACE_PERSISTENCY_PERMANENT); + BOOST_CHECK_EQUAL(notification.getFaceScope(), FACE_SCOPE_LOCAL); + BOOST_CHECK_EQUAL(notification.getFacePersistency(), FACE_PERSISTENCY_PERMANENT); + BOOST_CHECK_EQUAL(notification.getLinkType(), LINK_TYPE_POINT_TO_POINT); + + notification.setLinkType(LINK_TYPE_MULTI_ACCESS); + BOOST_CHECK_EQUAL(notification.getFaceScope(), FACE_SCOPE_LOCAL); + BOOST_CHECK_EQUAL(notification.getFacePersistency(), FACE_PERSISTENCY_PERMANENT); + BOOST_CHECK_EQUAL(notification.getLinkType(), LINK_TYPE_MULTI_ACCESS); +} + +BOOST_AUTO_TEST_CASE(Created) +{ + FaceEventNotification notification1; + notification1.setKind(FACE_EVENT_CREATED) + .setFaceId(20) + .setRemoteUri("tcp4://192.0.2.1:55555") + .setLocalUri("tcp4://192.0.2.2:6363") + .setFaceScope(FACE_SCOPE_LOCAL) + .setFacePersistency(FACE_PERSISTENCY_ON_DEMAND) + .setLinkType(LINK_TYPE_MULTI_ACCESS) + .setFlags(0x3); + Block wire = notification1.wireEncode(); + + // These octets are obtained by the snippet below. + // This check is intended to detect unexpected encoding change in the future. + // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { + // printf("0x%02x, ", *it); + // } + static const uint8_t expected[] = { + 0xc0, 0x41, 0xc1, 0x01, 0x01, 0x69, 0x01, 0x14, 0x72, 0x16, + 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, + 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x31, 0x3a, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x81, 0x15, 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, + 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x32, + 0x3a, 0x36, 0x33, 0x36, 0x33, 0x84, 0x01, 0x01, 0x85, 0x01, + 0x01, 0x86, 0x01, 0x01, 0x6c, 0x01, 0x03, + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + FaceEventNotification notification2(wire); + BOOST_CHECK_EQUAL(notification1, notification2); + + BOOST_CHECK_EQUAL(boost::lexical_cast(notification2), + "FaceEvent(Kind: created,\n" + " FaceId: 20,\n" + " RemoteUri: tcp4://192.0.2.1:55555,\n" + " LocalUri: tcp4://192.0.2.2:6363,\n" + " FaceScope: local,\n" + " FacePersistency: on-demand,\n" + " LinkType: multi-access,\n" + " Flags: 0x3\n" + " )"); +} + +BOOST_AUTO_TEST_CASE(Destroyed) +{ + FaceEventNotification notification1; + notification1.setKind(FACE_EVENT_DESTROYED) + .setFaceId(20) + .setRemoteUri("tcp4://192.0.2.1:55555") + .setLocalUri("tcp4://192.0.2.2:6363") + .setFaceScope(FACE_SCOPE_LOCAL) + .setFacePersistency(FACE_PERSISTENCY_ON_DEMAND) + .setLinkType(LINK_TYPE_MULTI_ACCESS) + .setFlags(0x4); + Block wire = notification1.wireEncode(); + + // These octets are obtained by the snippet below. + // This check is intended to detect unexpected encoding change in the future. + // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { + // printf("0x%02x, ", *it); + // } + static const uint8_t expected[] = { + 0xc0, 0x41, 0xc1, 0x01, 0x02, 0x69, 0x01, 0x14, 0x72, 0x16, + 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, + 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x31, 0x3a, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x81, 0x15, 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, + 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x32, + 0x3a, 0x36, 0x33, 0x36, 0x33, 0x84, 0x01, 0x01, 0x85, 0x01, + 0x01, 0x86, 0x01, 0x01, 0x6c, 0x01, 0x04, + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + FaceEventNotification notification2(wire); + BOOST_CHECK_EQUAL(notification1, notification2); + + BOOST_CHECK_EQUAL(boost::lexical_cast(notification2), + "FaceEvent(Kind: destroyed,\n" + " FaceId: 20,\n" + " RemoteUri: tcp4://192.0.2.1:55555,\n" + " LocalUri: tcp4://192.0.2.2:6363,\n" + " FaceScope: local,\n" + " FacePersistency: on-demand,\n" + " LinkType: multi-access,\n" + " Flags: 0x4\n" + " )"); +} + +BOOST_AUTO_TEST_CASE(Up) +{ + FaceEventNotification notification1; + notification1.setKind(FACE_EVENT_UP) + .setFaceId(20) + .setRemoteUri("tcp4://192.0.2.1:55555") + .setLocalUri("tcp4://192.0.2.2:6363") + .setFaceScope(FACE_SCOPE_LOCAL) + .setFacePersistency(FACE_PERSISTENCY_ON_DEMAND) + .setLinkType(LINK_TYPE_MULTI_ACCESS) + .setFlags(0x05); + Block wire = notification1.wireEncode(); + + // These octets are obtained by the snippet below. + // This check is intended to detect unexpected encoding change in the future. + // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { + // printf("0x%02x, ", *it); + // } + static const uint8_t expected[] = { + 0xc0, 0x41, 0xc1, 0x01, 0x03, 0x69, 0x01, 0x14, 0x72, 0x16, + 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, + 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x31, 0x3a, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x81, 0x15, 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, + 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x32, + 0x3a, 0x36, 0x33, 0x36, 0x33, 0x84, 0x01, 0x01, 0x85, 0x01, + 0x01, 0x86, 0x01, 0x01, 0x6c, 0x01, 0x05, + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + FaceEventNotification notification2(wire); + BOOST_CHECK_EQUAL(notification1, notification2); + + BOOST_CHECK_EQUAL(boost::lexical_cast(notification2), + "FaceEvent(Kind: up,\n" + " FaceId: 20,\n" + " RemoteUri: tcp4://192.0.2.1:55555,\n" + " LocalUri: tcp4://192.0.2.2:6363,\n" + " FaceScope: local,\n" + " FacePersistency: on-demand,\n" + " LinkType: multi-access,\n" + " Flags: 0x5\n" + " )"); +} + +BOOST_AUTO_TEST_CASE(Down) +{ + FaceEventNotification notification1; + notification1.setKind(FACE_EVENT_DOWN) + .setFaceId(20) + .setRemoteUri("tcp4://192.0.2.1:55555") + .setLocalUri("tcp4://192.0.2.2:6363") + .setFaceScope(FACE_SCOPE_LOCAL) + .setFacePersistency(FACE_PERSISTENCY_ON_DEMAND) + .setLinkType(LINK_TYPE_MULTI_ACCESS) + .setFlags(0x06); + Block wire = notification1.wireEncode(); + + // These octets are obtained by the snippet below. + // This check is intended to detect unexpected encoding change in the future. + // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { + // printf("0x%02x, ", *it); + // } + static const uint8_t expected[] = { + 0xc0, 0x41, 0xc1, 0x01, 0x04, 0x69, 0x01, 0x14, 0x72, 0x16, + 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, + 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x31, 0x3a, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x81, 0x15, 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, + 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x32, + 0x3a, 0x36, 0x33, 0x36, 0x33, 0x84, 0x01, 0x01, 0x85, 0x01, + 0x01, 0x86, 0x01, 0x01, 0x6c, 0x01, 0x06, + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + FaceEventNotification notification2(wire); + BOOST_CHECK_EQUAL(notification1, notification2); + + BOOST_CHECK_EQUAL(boost::lexical_cast(notification2), + "FaceEvent(Kind: down,\n" + " FaceId: 20,\n" + " RemoteUri: tcp4://192.0.2.1:55555,\n" + " LocalUri: tcp4://192.0.2.2:6363,\n" + " FaceScope: local,\n" + " FacePersistency: on-demand,\n" + " LinkType: multi-access,\n" + " Flags: 0x6\n" + " )"); +} + +BOOST_AUTO_TEST_CASE(Equality) +{ + FaceEventNotification notification1, notification2; + BOOST_CHECK_EQUAL(notification1, notification2); + + notification1.setKind(FACE_EVENT_CREATED) + .setFaceId(123) + .setRemoteUri("tcp4://192.0.2.1:55555") + .setLocalUri("tcp4://192.0.2.2:6363"); + notification2 = notification1; + BOOST_CHECK_EQUAL(notification1, notification2); + + notification2.setFaceId(42); + BOOST_CHECK_NE(notification1, notification2); + + notification2 = notification1; + notification2.setKind(FACE_EVENT_DESTROYED); + BOOST_CHECK_NE(notification1, notification2); +} + +BOOST_AUTO_TEST_SUITE_END() // TestFaceEventNotification +BOOST_AUTO_TEST_SUITE_END() // Nfd +BOOST_AUTO_TEST_SUITE_END() // Mgmt + +} // namespace tests +} // namespace nfd +} // namespace ndn diff --git a/tests/unit/mgmt/nfd/face-query-filter.t.cpp b/tests/unit/mgmt/nfd/face-query-filter.t.cpp new file mode 100644 index 000000000..3b32ac8d5 --- /dev/null +++ b/tests/unit/mgmt/nfd/face-query-filter.t.cpp @@ -0,0 +1,143 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/face-query-filter.hpp" + +#include "tests/boost-test.hpp" +#include + +namespace ndn { +namespace nfd { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Mgmt) +BOOST_AUTO_TEST_SUITE(Nfd) +BOOST_AUTO_TEST_SUITE(TestFaceQueryFilter) + +BOOST_AUTO_TEST_CASE(Encode) +{ + FaceQueryFilter filter1; + BOOST_CHECK_EQUAL(filter1.hasFaceId(), false); + BOOST_CHECK_EQUAL(filter1.hasUriScheme(), false); + BOOST_CHECK_EQUAL(filter1.hasRemoteUri(), false); + BOOST_CHECK_EQUAL(filter1.hasLocalUri(), false); + BOOST_CHECK_EQUAL(filter1.hasFaceScope(), false); + BOOST_CHECK_EQUAL(filter1.hasFacePersistency(), false); + BOOST_CHECK_EQUAL(filter1.hasLinkType(), false); + + filter1.setFaceId(100) + .setUriScheme("tcp4") + .setRemoteUri("tcp4://192.0.2.1:6363") + .setLocalUri("tcp4://192.0.2.2:55555") + .setFaceScope(FACE_SCOPE_LOCAL) + .setFacePersistency(FACE_PERSISTENCY_ON_DEMAND) + .setLinkType(LINK_TYPE_MULTI_ACCESS); + + Block wire = filter1.wireEncode(); + + // These octets are obtained by the snippet below. + // This check is intended to detect unexpected encoding change in the future. + // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { + // printf("0x%02x, ", *it); + // } + static const uint8_t expected[] = { + 0x96, 0x41, 0x69, 0x01, 0x64, 0x83, 0x04, 0x74, 0x63, 0x70, + 0x34, 0x72, 0x15, 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, 0x2f, + 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x31, 0x3a, + 0x36, 0x33, 0x36, 0x33, 0x81, 0x16, 0x74, 0x63, 0x70, 0x34, + 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, + 0x2e, 0x32, 0x3a, 0x35, 0x35, 0x35, 0x35, 0x35, 0x84, 0x01, + 0x01, 0x85, 0x01, 0x01, 0x86, 0x01, 0x01, + }; + + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + FaceQueryFilter filter2(wire); + BOOST_CHECK_EQUAL(filter1.getFaceId(), filter2.getFaceId()); + BOOST_CHECK_EQUAL(filter1.getUriScheme(), filter2.getUriScheme()); + BOOST_CHECK_EQUAL(filter1.getRemoteUri(), filter2.getRemoteUri()); + BOOST_CHECK_EQUAL(filter1.getLocalUri(), filter2.getLocalUri()); + BOOST_CHECK_EQUAL(filter1.getFaceScope(), filter2.getFaceScope()); + BOOST_CHECK_EQUAL(filter1.getFacePersistency(), filter2.getFacePersistency()); + BOOST_CHECK_EQUAL(filter1.getLinkType(), filter2.getLinkType()); +} + +BOOST_AUTO_TEST_CASE(Equality) +{ + FaceQueryFilter filter1, filter2; + BOOST_CHECK_EQUAL(filter1.empty(), true); + BOOST_CHECK_EQUAL(filter1, filter2); + + filter1.setFaceId(100) + .setUriScheme("tcp4") + .setRemoteUri("tcp4://192.0.2.1:6363") + .setLocalUri("tcp4://192.0.2.2:55555") + .setFaceScope(FACE_SCOPE_LOCAL) + .setFacePersistency(FACE_PERSISTENCY_ON_DEMAND) + .setLinkType(LINK_TYPE_MULTI_ACCESS); + BOOST_CHECK_EQUAL(filter1.empty(), false); + BOOST_CHECK_NE(filter1, filter2); + + filter2 = filter1; + BOOST_CHECK_EQUAL(filter1, filter2); + + filter2.setFaceScope(FACE_SCOPE_NON_LOCAL); + BOOST_CHECK_NE(filter1, filter2); +} + +BOOST_AUTO_TEST_CASE(Print) +{ + FaceQueryFilter filter; + filter.setFaceId(100) + .setUriScheme("tcp4") + .setRemoteUri("tcp4://192.0.2.1:6363") + .setLocalUri("tcp4://192.0.2.2:55555") + .setFaceScope(FACE_SCOPE_LOCAL) + .setFacePersistency(FACE_PERSISTENCY_ON_DEMAND) + .setLinkType(LINK_TYPE_MULTI_ACCESS); + BOOST_CHECK_EQUAL(boost::lexical_cast(filter), + "FaceQueryFilter(FaceID: 100,\n" + "UriScheme: tcp4,\n" + "RemoteUri: tcp4://192.0.2.1:6363,\n" + "LocalUri: tcp4://192.0.2.2:55555,\n" + "FaceScope: local,\n" + "FacePersistency: on-demand,\n" + "LinkType: multi-access,\n" + ")"); + + filter.unsetFaceId() + .unsetUriScheme() + .unsetRemoteUri() + .unsetLocalUri() + .unsetFaceScope() + .unsetFacePersistency() + .unsetLinkType(); + BOOST_CHECK_EQUAL(boost::lexical_cast(filter), "FaceQueryFilter()"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestFaceQueryFilter +BOOST_AUTO_TEST_SUITE_END() // Nfd +BOOST_AUTO_TEST_SUITE_END() // Mgmt + +} // namespace tests +} // namespace nfd +} // namespace ndn diff --git a/tests/unit/mgmt/nfd/face-status.t.cpp b/tests/unit/mgmt/nfd/face-status.t.cpp new file mode 100644 index 000000000..a4ad4ac17 --- /dev/null +++ b/tests/unit/mgmt/nfd/face-status.t.cpp @@ -0,0 +1,179 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/face-status.hpp" + +#include "tests/boost-test.hpp" +#include + +namespace ndn { +namespace nfd { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Mgmt) +BOOST_AUTO_TEST_SUITE(Nfd) +BOOST_AUTO_TEST_SUITE(TestFaceStatus) + +static FaceStatus +makeFaceStatus() +{ + return FaceStatus() + .setFaceId(100) + .setRemoteUri("tcp4://192.0.2.1:6363") + .setLocalUri("tcp4://192.0.2.2:55555") + .setFaceScope(FACE_SCOPE_LOCAL) + .setFacePersistency(FACE_PERSISTENCY_ON_DEMAND) + .setLinkType(LINK_TYPE_MULTI_ACCESS) + .setExpirationPeriod(10_s) + .setBaseCongestionMarkingInterval(5_ns) + .setDefaultCongestionThreshold(7) + .setMtu(9) + .setNInInterests(10) + .setNInData(200) + .setNInNacks(1) + .setNOutInterests(3000) + .setNOutData(4) + .setNOutNacks(2) + .setNInBytes(1329719163) + .setNOutBytes(999110448) + .setFlags(0x7); +} + +BOOST_AUTO_TEST_CASE(Encode) +{ + FaceStatus status1 = makeFaceStatus(); + Block wire = status1.wireEncode(); + + // These octets are obtained by the snippet below. + // This check is intended to detect unexpected encoding change in the future. + // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { + // printf("0x%02x, ", *it); + // } + static const uint8_t expected[] = { + 0x80, 0x6a, 0x69, 0x01, 0x64, 0x72, 0x15, 0x74, 0x63, 0x70, + 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, + 0x32, 0x2e, 0x31, 0x3a, 0x36, 0x33, 0x36, 0x33, 0x81, 0x16, + 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, + 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x32, 0x3a, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x6d, 0x02, 0x27, 0x10, 0x84, 0x01, 0x01, 0x85, + 0x01, 0x01, 0x86, 0x01, 0x01, 0x87, 0x01, 0x05, 0x88, 0x01, + 0x07, 0x89, 0x01, 0x09, 0x90, 0x01, 0x0a, 0x91, 0x01, 0xc8, + 0x97, 0x01, 0x01, 0x92, 0x02, 0x0b, 0xb8, 0x93, 0x01, 0x04, + 0x98, 0x01, 0x02, 0x94, 0x04, 0x4f, 0x41, 0xe7, 0x7b, 0x95, + 0x04, 0x3b, 0x8d, 0x37, 0x30, 0x6c, 0x01, 0x07, + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + FaceStatus status2(wire); + BOOST_CHECK_EQUAL(status1, status2); +} + +BOOST_AUTO_TEST_CASE(Equality) +{ + FaceStatus status1, status2; + + status1 = makeFaceStatus(); + status2 = status1; + BOOST_CHECK_EQUAL(status1, status2); + + status2.setFaceId(42); + BOOST_CHECK_NE(status1, status2); +} + +BOOST_AUTO_TEST_CASE(Print) +{ + FaceStatus status; + BOOST_CHECK_EQUAL(boost::lexical_cast(status), + "Face(FaceId: 0,\n" + " RemoteUri: ,\n" + " LocalUri: ,\n" + " ExpirationPeriod: infinite,\n" + " FaceScope: non-local,\n" + " FacePersistency: persistent,\n" + " LinkType: point-to-point,\n" + " Flags: 0x0,\n" + " Counters: {Interests: {in: 0, out: 0},\n" + " Data: {in: 0, out: 0},\n" + " Nacks: {in: 0, out: 0},\n" + " bytes: {in: 0, out: 0}}\n" + " )"); + + status = makeFaceStatus(); + BOOST_CHECK_EQUAL(boost::lexical_cast(status), + "Face(FaceId: 100,\n" + " RemoteUri: tcp4://192.0.2.1:6363,\n" + " LocalUri: tcp4://192.0.2.2:55555,\n" + " ExpirationPeriod: 10000 milliseconds,\n" + " FaceScope: local,\n" + " FacePersistency: on-demand,\n" + " LinkType: multi-access,\n" + " BaseCongestionMarkingInterval: 5 nanoseconds,\n" + " DefaultCongestionThreshold: 7 bytes,\n" + " Mtu: 9 bytes,\n" + " Flags: 0x7,\n" + " Counters: {Interests: {in: 10, out: 3000},\n" + " Data: {in: 200, out: 4},\n" + " Nacks: {in: 1, out: 2},\n" + " bytes: {in: 1329719163, out: 999110448}}\n" + " )"); +} + +BOOST_AUTO_TEST_CASE(ExpirationPeriod) +{ + FaceStatus status; + BOOST_CHECK_EQUAL(status.hasExpirationPeriod(), false); + + status.setExpirationPeriod(1_min); + BOOST_REQUIRE_EQUAL(status.hasExpirationPeriod(), true); + BOOST_CHECK_EQUAL(status.getExpirationPeriod(), 1_min); + + status.unsetExpirationPeriod(); + BOOST_CHECK_EQUAL(status.hasExpirationPeriod(), false); +} + +BOOST_AUTO_TEST_CASE(FlagBit) +{ + FaceStatus status; + status.setFlags(0x7); + BOOST_CHECK_EQUAL(status.getFlags(), 0x7); + + BOOST_CHECK(status.getFlagBit(0)); + BOOST_CHECK(status.getFlagBit(1)); + BOOST_CHECK(status.getFlagBit(2)); + BOOST_CHECK(!status.getFlagBit(3)); + + status.setFlagBit(3, true); + BOOST_CHECK_EQUAL(status.getFlags(), 0xf); + BOOST_CHECK(status.getFlagBit(3)); + + status.setFlagBit(1, false); + BOOST_CHECK_EQUAL(status.getFlags(), 0xd); + BOOST_CHECK(!status.getFlagBit(1)); +} + +BOOST_AUTO_TEST_SUITE_END() // TestFaceStatus +BOOST_AUTO_TEST_SUITE_END() // Nfd +BOOST_AUTO_TEST_SUITE_END() // Mgmt + +} // namespace tests +} // namespace nfd +} // namespace ndn diff --git a/tests/unit/mgmt/nfd/fib-entry.t.cpp b/tests/unit/mgmt/nfd/fib-entry.t.cpp new file mode 100644 index 000000000..ff5d21bf4 --- /dev/null +++ b/tests/unit/mgmt/nfd/fib-entry.t.cpp @@ -0,0 +1,212 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/fib-entry.hpp" + +#include "tests/boost-test.hpp" +#include + +namespace ndn { +namespace nfd { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Mgmt) +BOOST_AUTO_TEST_SUITE(Nfd) +BOOST_AUTO_TEST_SUITE(TestFibEntry) + +static FibEntry +makeFibEntry() +{ + std::vector nexthops; + for (size_t i = 1; i < 4; i++) { + nexthops.push_back(NextHopRecord() + .setFaceId(i * 10) + .setCost(i * 100 + 100)); + } + + return FibEntry() + .setPrefix("/this/is/a/test") + .setNextHopRecords(nexthops.begin(), nexthops.end()); +} + +BOOST_AUTO_TEST_CASE(NextHopRecordEncode) +{ + NextHopRecord record1; + record1.setFaceId(10) + .setCost(200); + const Block& wire = record1.wireEncode(); + + static const uint8_t expected[] = { + 0x81, 0x06, // NextHopRecord + 0x69, 0x01, 0x0a, // FaceId + 0x6a, 0x01, 0xc8, // Cost + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + NextHopRecord record2(wire); + BOOST_CHECK_EQUAL(record1, record2); +} + +BOOST_AUTO_TEST_CASE(NextHopRecordEquality) +{ + NextHopRecord record1, record2; + + record1.setFaceId(10) + .setCost(200); + record2 = record1; + BOOST_CHECK_EQUAL(record1, record2); + + record2.setFaceId(42); + BOOST_CHECK_NE(record1, record2); + + record2 = record1; + record2.setCost(42); + BOOST_CHECK_NE(record1, record2); +} + +BOOST_AUTO_TEST_CASE(FibEntryNoNextHopsEncode) +{ + FibEntry entry1; + entry1.setPrefix("/this/is/a/test"); + BOOST_REQUIRE(entry1.getNextHopRecords().empty()); + const Block& wire = entry1.wireEncode(); + + static const uint8_t expected[] = { + 0x80, 0x15, 0x07, 0x13, 0x08, 0x04, 0x74, 0x68, 0x69, 0x73, + 0x08, 0x02, 0x69, 0x73, 0x08, 0x01, 0x61, 0x08, 0x04, 0x74, + 0x65, 0x73, 0x74 + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + FibEntry entry2(wire); + BOOST_CHECK_EQUAL(entry1, entry2); +} + +BOOST_AUTO_TEST_CASE(FibEntryEncode) +{ + FibEntry entry1 = makeFibEntry(); + NextHopRecord oneMore; + oneMore.setFaceId(40); + oneMore.setCost(500); + entry1.addNextHopRecord(oneMore); + const Block& wire = entry1.wireEncode(); + + static const uint8_t expected[] = { + 0x80, 0x38, // FibEntry + 0x07, 0x13, // Name + 0x08, 0x04, 0x74, 0x68, 0x69, 0x73, // GenericNameComponent + 0x08, 0x02, 0x69, 0x73, // GenericNameComponent + 0x08, 0x01, 0x61, // GenericNameComponent + 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, // GenericNameComponent + 0x81, 0x06, // NextHopRecord + 0x69, 0x01, 0x0a, // FaceId + 0x6a, 0x01, 0xc8, // Cost + 0x81, 0x07, // NextHopRecord + 0x69, 0x01, 0x14, // FaceId + 0x6a, 0x02, 0x01, 0x2c, // Cost + 0x81, 0x07, // NextHopRecord + 0x69, 0x01, 0x1e, // FaceId + 0x6a, 0x02, 0x01, 0x90, // Cost + 0x81, 0x07, // NextHopRecord + 0x69, 0x01, 0x28, // FaceId + 0x6a, 0x02, 0x01, 0xf4, // Cost + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + FibEntry entry2(wire); + BOOST_CHECK_EQUAL(entry1, entry2); +} + +BOOST_AUTO_TEST_CASE(FibEntryEquality) +{ + FibEntry entry1, entry2; + BOOST_CHECK_EQUAL(entry1, entry2); + + entry1 = entry2 = makeFibEntry(); + BOOST_CHECK_EQUAL(entry1, entry2); + BOOST_CHECK_EQUAL(entry2, entry1); + + entry2.setPrefix("/another/prefix"); + BOOST_CHECK_NE(entry1, entry2); + + entry2 = entry1; + std::vector empty; + entry2.setNextHopRecords(empty.begin(), empty.end()); + BOOST_CHECK_NE(entry1, entry2); + BOOST_CHECK_NE(entry2, entry1); + + entry2 = entry1; + auto nh1 = NextHopRecord() + .setFaceId(1) + .setCost(1000); + entry1.addNextHopRecord(nh1); + BOOST_CHECK_NE(entry1, entry2); + BOOST_CHECK_NE(entry2, entry1); + + auto nh42 = NextHopRecord() + .setFaceId(42) + .setCost(42); + entry1.addNextHopRecord(nh42); + entry2.addNextHopRecord(nh42) + .addNextHopRecord(nh1); + BOOST_CHECK_EQUAL(entry1, entry2); // order of NextHopRecords is irrelevant + BOOST_CHECK_EQUAL(entry2, entry1); + + entry1 = entry2 = makeFibEntry(); + entry1.addNextHopRecord(nh1) + .addNextHopRecord(nh42); + entry2.addNextHopRecord(nh42) + .addNextHopRecord(nh42); + BOOST_CHECK_NE(entry1, entry2); // match each NextHopRecord at most once + BOOST_CHECK_NE(entry2, entry1); +} + +BOOST_AUTO_TEST_CASE(Print) +{ + NextHopRecord record; + BOOST_CHECK_EQUAL(boost::lexical_cast(record), + "NextHopRecord(FaceId: 0, Cost: 0)"); + + FibEntry entry; + BOOST_CHECK_EQUAL(boost::lexical_cast(entry), + "FibEntry(Prefix: /,\n" + " NextHops: []\n" + " )"); + + entry = makeFibEntry(); + BOOST_CHECK_EQUAL(boost::lexical_cast(entry), + "FibEntry(Prefix: /this/is/a/test,\n" + " NextHops: [NextHopRecord(FaceId: 10, Cost: 200),\n" + " NextHopRecord(FaceId: 20, Cost: 300),\n" + " NextHopRecord(FaceId: 30, Cost: 400)]\n" + " )"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestFibEntry +BOOST_AUTO_TEST_SUITE_END() // Nfd +BOOST_AUTO_TEST_SUITE_END() // Mgmt + +} // namespace tests +} // namespace nfd +} // namespace ndn diff --git a/tests/unit/mgmt/nfd/forwarder-status.t.cpp b/tests/unit/mgmt/nfd/forwarder-status.t.cpp new file mode 100644 index 000000000..f899ce941 --- /dev/null +++ b/tests/unit/mgmt/nfd/forwarder-status.t.cpp @@ -0,0 +1,141 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/forwarder-status.hpp" + +#include "tests/boost-test.hpp" +#include + +namespace ndn { +namespace nfd { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Mgmt) +BOOST_AUTO_TEST_SUITE(Nfd) +BOOST_AUTO_TEST_SUITE(TestForwarderStatus) + +static ForwarderStatus +makeForwarderStatus() +{ + return ForwarderStatus() + .setNfdVersion("0.5.1-14-g05dd444") + .setStartTimestamp(time::fromUnixTimestamp(time::milliseconds(375193249325LL))) + .setCurrentTimestamp(time::fromUnixTimestamp(time::milliseconds(886109034272LL))) + .setNNameTreeEntries(1849943160) + .setNFibEntries(621739748) + .setNPitEntries(482129741) + .setNMeasurementsEntries(1771725298) + .setNCsEntries(1264968688) + .setNInInterests(612811615) + .setNInData(1843576050) + .setNInNacks(1234) + .setNOutInterests(952144445) + .setNOutData(138198826) + .setNOutNacks(4321) + .setNSatisfiedInterests(961020) + .setNUnsatisfiedInterests(941024); +} + +BOOST_AUTO_TEST_CASE(Encode) +{ + ForwarderStatus status1 = makeForwarderStatus(); + Block wire = status1.wireEncode(); + + // These octets are obtained by the snippet below. + // This check is intended to detect unexpected encoding change in the future. + // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { + // printf("0x%02x, ", *it); + // } + static const uint8_t expected[] = { + 0x15, 0x71, 0x80, 0x11, 0x30, 0x2e, 0x35, 0x2e, 0x31, 0x2d, 0x31, 0x34, + 0x2d, 0x67, 0x30, 0x35, 0x64, 0x64, 0x34, 0x34, 0x34, 0x81, 0x08, 0x00, + 0x00, 0x00, 0x57, 0x5b, 0x42, 0xa6, 0x2d, 0x82, 0x08, 0x00, 0x00, 0x00, + 0xce, 0x50, 0x36, 0xd7, 0x20, 0x83, 0x04, 0x6e, 0x43, 0xe4, 0x78, 0x84, + 0x04, 0x25, 0x0e, 0xfe, 0xe4, 0x85, 0x04, 0x1c, 0xbc, 0xb7, 0x4d, 0x86, + 0x04, 0x69, 0x9a, 0x61, 0xf2, 0x87, 0x04, 0x4b, 0x65, 0xe3, 0xf0, 0x90, + 0x04, 0x24, 0x86, 0xc3, 0x5f, 0x91, 0x04, 0x6d, 0xe2, 0xbc, 0xf2, 0x97, + 0x02, 0x04, 0xd2, 0x92, 0x04, 0x38, 0xc0, 0x92, 0x3d, 0x93, 0x04, 0x08, + 0x3c, 0xbf, 0x2a, 0x98, 0x02, 0x10, 0xe1, 0x99, 0x04, 0x00, 0x0e, 0xa9, + 0xfc, 0x9a, 0x04, 0x00, 0x0e, 0x5b, 0xe0, + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + ForwarderStatus status2(wire); + BOOST_CHECK_EQUAL(status1, status2); +} + +BOOST_AUTO_TEST_CASE(Equality) +{ + ForwarderStatus status1, status2; + + status1 = makeForwarderStatus(); + status2 = status1; + BOOST_CHECK_EQUAL(status1, status2); + + status2.setNPitEntries(42); + BOOST_CHECK_NE(status1, status2); +} + +BOOST_AUTO_TEST_CASE(Print) +{ + ForwarderStatus status; + BOOST_CHECK_EQUAL(boost::lexical_cast(status), + "GeneralStatus(NfdVersion: ,\n" + " StartTimestamp: 0 nanoseconds since Jan 1, 1970,\n" + " CurrentTimestamp: 0 nanoseconds since Jan 1, 1970,\n" + " Counters: {NameTreeEntries: 0,\n" + " FibEntries: 0,\n" + " PitEntries: 0,\n" + " MeasurementsEntries: 0,\n" + " CsEntries: 0,\n" + " Interests: {in: 0, out: 0},\n" + " Data: {in: 0, out: 0},\n" + " Nacks: {in: 0, out: 0},\n" + " SatisfiedInterests: 0,\n" + " UnsatisfiedInterests: 0}\n" + " )"); + + status = makeForwarderStatus(); + BOOST_CHECK_EQUAL(boost::lexical_cast(status), + "GeneralStatus(NfdVersion: 0.5.1-14-g05dd444,\n" + " StartTimestamp: 375193249325000000 nanoseconds since Jan 1, 1970,\n" + " CurrentTimestamp: 886109034272000000 nanoseconds since Jan 1, 1970,\n" + " Counters: {NameTreeEntries: 1849943160,\n" + " FibEntries: 621739748,\n" + " PitEntries: 482129741,\n" + " MeasurementsEntries: 1771725298,\n" + " CsEntries: 1264968688,\n" + " Interests: {in: 612811615, out: 952144445},\n" + " Data: {in: 1843576050, out: 138198826},\n" + " Nacks: {in: 1234, out: 4321},\n" + " SatisfiedInterests: 961020,\n" + " UnsatisfiedInterests: 941024}\n" + " )"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestForwarderStatus +BOOST_AUTO_TEST_SUITE_END() // Nfd +BOOST_AUTO_TEST_SUITE_END() // Mgmt + +} // namespace tests +} // namespace nfd +} // namespace ndn diff --git a/tests/unit/mgmt/nfd/rib-entry.t.cpp b/tests/unit/mgmt/nfd/rib-entry.t.cpp new file mode 100644 index 000000000..950a1967d --- /dev/null +++ b/tests/unit/mgmt/nfd/rib-entry.t.cpp @@ -0,0 +1,240 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/rib-entry.hpp" + +#include "tests/boost-test.hpp" +#include + +namespace ndn { +namespace nfd { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Mgmt) +BOOST_AUTO_TEST_SUITE(Nfd) +BOOST_AUTO_TEST_SUITE(TestRibEntry) + +static Route +makeRoute() +{ + return Route() + .setFaceId(1) + .setOrigin(ROUTE_ORIGIN_NLSR) + .setCost(100) + .setFlags(ROUTE_FLAG_CAPTURE); +} + +static RibEntry +makeRibEntry() +{ + return RibEntry() + .setName("/hello/world") + .addRoute(makeRoute() + .setExpirationPeriod(10_s)); +} + +BOOST_AUTO_TEST_CASE(RouteEncode) +{ + Route route1 = makeRoute(); + route1.setExpirationPeriod(10_s); + const Block& wire = route1.wireEncode(); + + static const uint8_t expected[] = { + 0x81, 0x10, 0x69, 0x01, 0x01, 0x6f, 0x01, 0x80, 0x6a, 0x01, 0x64, 0x6c, 0x01, 0x02, + 0x6d, 0x02, 0x27, 0x10 + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + Route route2(wire); + BOOST_CHECK_EQUAL(route1, route2); +} + +BOOST_AUTO_TEST_CASE(RouteNoExpirationPeriodEncode) +{ + Route route1 = makeRoute(); + const Block& wire = route1.wireEncode(); + + static const uint8_t expected[] = { + 0x81, 0x0C, 0x69, 0x01, 0x01, 0x6f, 0x01, 0x80, 0x6a, 0x01, 0x64, 0x6c, 0x01, 0x02 + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + Route route2(wire); + BOOST_CHECK_EQUAL(route1, route2); +} + +BOOST_AUTO_TEST_CASE(RouteExpirationPeriod) +{ + Route route; + BOOST_CHECK_EQUAL(route.hasExpirationPeriod(), false); + BOOST_CHECK_EQUAL(route.getExpirationPeriod(), time::milliseconds::max()); + + route.setExpirationPeriod(1_min); + BOOST_CHECK_EQUAL(route.hasExpirationPeriod(), true); + BOOST_CHECK_EQUAL(route.getExpirationPeriod(), 1_min); + + route.setExpirationPeriod(time::milliseconds::max()); + BOOST_CHECK_EQUAL(route.hasExpirationPeriod(), false); + BOOST_CHECK_EQUAL(route.getExpirationPeriod(), time::milliseconds::max()); + + route.setExpirationPeriod(1_min); + BOOST_CHECK_EQUAL(route.hasExpirationPeriod(), true); + + route.unsetExpirationPeriod(); + BOOST_CHECK_EQUAL(route.hasExpirationPeriod(), false); +} + +BOOST_AUTO_TEST_CASE(RouteEquality) +{ + Route route1, route2; + + route1 = makeRoute(); + route2 = route1; + BOOST_CHECK_EQUAL(route1, route2); + + route2.setFaceId(42); + BOOST_CHECK_NE(route1, route2); + + route2 = route1; + route2.setExpirationPeriod(1_min); + BOOST_CHECK_NE(route1, route2); +} + +BOOST_AUTO_TEST_CASE(RibEntryEncode) +{ + RibEntry entry1 = makeRibEntry(); + entry1.addRoute(Route() + .setFaceId(2) + .setOrigin(ROUTE_ORIGIN_APP) + .setCost(32) + .setFlags(ROUTE_FLAG_CHILD_INHERIT) + .setExpirationPeriod(5_s)); + const Block& wire = entry1.wireEncode(); + + static const uint8_t expected[] = { + 0x80, 0x34, 0x07, 0x0e, 0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x08, 0x05, 0x77, + 0x6f, 0x72, 0x6c, 0x64, 0x81, 0x10, 0x69, 0x01, 0x01, 0x6f, 0x01, 0x80, 0x6a, 0x01, + 0x64, 0x6c, 0x01, 0x02, 0x6d, 0x02, 0x27, 0x10, 0x81, 0x10, 0x69, 0x01, 0x02, 0x6f, + 0x01, 0x00, 0x6a, 0x01, 0x20, 0x6c, 0x01, 0x01, 0x6d, 0x02, 0x13, 0x88 + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + RibEntry entry2(wire); + BOOST_CHECK_EQUAL(entry1, entry2); +} + +BOOST_AUTO_TEST_CASE(RibEntryClearRoutes) +{ + RibEntry entry; + entry.setName("/hello/world"); + BOOST_CHECK_EQUAL(entry.getRoutes().size(), 0); + + Route route1; + route1.setFaceId(42); + entry.addRoute(route1); + BOOST_REQUIRE_EQUAL(entry.getRoutes().size(), 1); + BOOST_CHECK_EQUAL(entry.getRoutes().front(), route1); + + entry.clearRoutes(); + BOOST_CHECK_EQUAL(entry.getRoutes().size(), 0); +} + +BOOST_AUTO_TEST_CASE(RibEntryEquality) +{ + RibEntry entry1, entry2; + BOOST_CHECK_EQUAL(entry1, entry2); + + entry1 = entry2 = makeRibEntry(); + BOOST_CHECK_EQUAL(entry1, entry2); + BOOST_CHECK_EQUAL(entry2, entry1); + + entry2.setName("/different/name"); + BOOST_CHECK_NE(entry1, entry2); + + entry2 = entry1; + std::vector empty; + entry2.setRoutes(empty.begin(), empty.end()); + BOOST_CHECK_NE(entry1, entry2); + BOOST_CHECK_NE(entry2, entry1); + + entry2 = entry1; + auto r1 = Route() + .setFaceId(1) + .setCost(1000); + entry1.addRoute(r1); + BOOST_CHECK_NE(entry1, entry2); + BOOST_CHECK_NE(entry2, entry1); + + auto r42 = Route() + .setFaceId(42) + .setCost(42); + entry1.addRoute(r42); + entry2.addRoute(r42) + .addRoute(r1); + BOOST_CHECK_EQUAL(entry1, entry2); // order of Routes is irrelevant + BOOST_CHECK_EQUAL(entry2, entry1); + + entry1 = entry2 = makeRibEntry(); + entry1.addRoute(r1) + .addRoute(r42); + entry2.addRoute(r42) + .addRoute(r42); + BOOST_CHECK_NE(entry1, entry2); // match each Route at most once + BOOST_CHECK_NE(entry2, entry1); +} + +BOOST_AUTO_TEST_CASE(Print) +{ + Route route; + BOOST_CHECK_EQUAL(boost::lexical_cast(route), + "Route(FaceId: 0, Origin: app, Cost: 0, Flags: 0x1, ExpirationPeriod: infinite)"); + + RibEntry entry; + BOOST_CHECK_EQUAL(boost::lexical_cast(entry), + "RibEntry(Prefix: /,\n" + " Routes: []\n" + " )"); + + entry = makeRibEntry(); + entry.addRoute(Route() + .setFaceId(2) + .setOrigin(ROUTE_ORIGIN_STATIC) + .setCost(32) + .setFlags(ROUTE_FLAG_CHILD_INHERIT)); + BOOST_CHECK_EQUAL(boost::lexical_cast(entry), + "RibEntry(Prefix: /hello/world,\n" + " Routes: [Route(FaceId: 1, Origin: nlsr, Cost: 100, Flags: 0x2, " + "ExpirationPeriod: 10000 milliseconds),\n" + " Route(FaceId: 2, Origin: static, Cost: 32, Flags: 0x1, " + "ExpirationPeriod: infinite)]\n" + " )"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestRibEntry +BOOST_AUTO_TEST_SUITE_END() // Nfd +BOOST_AUTO_TEST_SUITE_END() // Mgmt + +} // namespace tests +} // namespace nfd +} // namespace ndn diff --git a/tests/unit-tests/mgmt/nfd/status-dataset.t.cpp b/tests/unit/mgmt/nfd/status-dataset.t.cpp similarity index 83% rename from tests/unit-tests/mgmt/nfd/status-dataset.t.cpp rename to tests/unit/mgmt/nfd/status-dataset.t.cpp index aadb2c44e..aac874b80 100644 --- a/tests/unit-tests/mgmt/nfd/status-dataset.t.cpp +++ b/tests/unit/mgmt/nfd/status-dataset.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,11 +19,12 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "mgmt/nfd/status-dataset.hpp" -#include "mgmt/nfd/controller.hpp" +#include "ndn-cxx/mgmt/nfd/status-dataset.hpp" +#include "ndn-cxx/mgmt/nfd/controller.hpp" -#include "controller-fixture.hpp" -#include "../../make-interest-data.hpp" +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" +#include "tests/unit/mgmt/nfd/controller-fixture.hpp" namespace ndn { namespace nfd { @@ -98,7 +99,8 @@ class ControllerStatusDatasetFixture : public ControllerFixture } auto data = make_shared(name); - data->setFinalBlockId(data->getName()[-1]); + data->setFreshnessPeriod(1_s); + data->setFinalBlock(name[-1]); return data; } }; @@ -110,13 +112,16 @@ BOOST_AUTO_TEST_SUITE(Failures) BOOST_AUTO_TEST_CASE(Timeout) { CommandOptions options; - options.setTimeout(time::milliseconds(3000)); + options.setTimeout(3000_ms); controller.fetch( [] (const std::vector& result) { BOOST_FAIL("fetchDataset should not succeed"); }, datasetFailCallback, options); - this->advanceClocks(time::milliseconds(500), 7); + this->advanceClocks(500_ms); + BOOST_CHECK_EQUAL(controller.m_fetchers.size(), 1); + this->advanceClocks(500_ms, 6); + BOOST_CHECK_EQUAL(controller.m_fetchers.size(), 0); BOOST_REQUIRE_EQUAL(failCodes.size(), 1); BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_TIMEOUT); } @@ -126,10 +131,12 @@ BOOST_AUTO_TEST_CASE(DataHasNoSegment) controller.fetch( [] (const std::vector& result) { BOOST_FAIL("fetchDataset should not succeed"); }, datasetFailCallback); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); - face.receive(*makeData("/localhost/nfd/faces/list/%FD%00")); - this->advanceClocks(time::milliseconds(500)); + auto data = makeData("/localhost/nfd/faces/list/%FD%00"); + data->setFreshnessPeriod(1_s); + face.receive(*data); + this->advanceClocks(500_ms); BOOST_REQUIRE_EQUAL(failCodes.size(), 1); BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_SERVER); @@ -142,12 +149,12 @@ BOOST_AUTO_TEST_CASE(ValidationFailure) controller.fetch( [] (const std::vector& result) { BOOST_FAIL("fetchDataset should not succeed"); }, datasetFailCallback); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); FaceStatus payload; payload.setFaceId(5744); this->sendDataset("/localhost/nfd/faces/list", payload); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); BOOST_REQUIRE_EQUAL(failCodes.size(), 1); BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_VALIDATION); @@ -158,11 +165,11 @@ BOOST_AUTO_TEST_CASE(Nack) controller.fetch( [] (const std::vector& result) { BOOST_FAIL("fetchDataset should not succeed"); }, datasetFailCallback); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1); face.receive(lp::Nack(face.sentInterests.back())); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); BOOST_REQUIRE_EQUAL(failCodes.size(), 1); BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_NACK); @@ -173,11 +180,11 @@ BOOST_AUTO_TEST_CASE(ParseError1) controller.fetch( [] (const std::vector& result) { BOOST_FAIL("fetchDataset should not succeed"); }, datasetFailCallback); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); Name payload; // Name is not valid FaceStatus this->sendDataset("/localhost/nfd/faces/list", payload); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); BOOST_REQUIRE_EQUAL(failCodes.size(), 1); BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_SERVER); @@ -188,13 +195,13 @@ BOOST_AUTO_TEST_CASE(ParseError2) controller.fetch( [] (const std::vector& result) { BOOST_FAIL("fetchDataset should not succeed"); }, datasetFailCallback); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); FaceStatus payload1; payload1.setFaceId(10930); Name payload2; // Name is not valid FaceStatus this->sendDataset("/localhost/nfd/faces/list", payload1, payload2); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); BOOST_REQUIRE_EQUAL(failCodes.size(), 1); BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_SERVER); @@ -209,25 +216,27 @@ BOOST_AUTO_TEST_CASE(Success) controller.fetch( nullptr, datasetFailCallback); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); + BOOST_CHECK_EQUAL(controller.m_fetchers.size(), 1); FaceStatus payload; payload.setFaceId(2577); this->sendDataset("/localhost/nfd/faces/list", payload); - BOOST_CHECK_NO_THROW(this->advanceClocks(time::milliseconds(500))); + BOOST_CHECK_NO_THROW(this->advanceClocks(500_ms)); BOOST_CHECK_EQUAL(failCodes.size(), 0); + BOOST_CHECK_EQUAL(controller.m_fetchers.size(), 0); } BOOST_AUTO_TEST_CASE(Failure) { CommandOptions options; - options.setTimeout(time::milliseconds(3000)); + options.setTimeout(3000_ms); controller.fetch( [] (const std::vector& result) { BOOST_FAIL("fetchDataset should not succeed"); }, nullptr, options); - BOOST_CHECK_NO_THROW(this->advanceClocks(time::milliseconds(500), 7)); + BOOST_CHECK_NO_THROW(this->advanceClocks(500_ms, 7)); } BOOST_AUTO_TEST_SUITE_END() // NoCallback @@ -243,12 +252,12 @@ BOOST_AUTO_TEST_CASE(StatusGeneral) BOOST_CHECK_EQUAL(result.getNfdVersion(), "0.4.2"); }, datasetFailCallback); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); ForwarderStatus payload; payload.setNfdVersion("0.4.2"); this->sendDataset("/localhost/nfd/status/general", payload); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); BOOST_CHECK(hasResult); BOOST_CHECK_EQUAL(failCodes.size(), 0); @@ -264,14 +273,14 @@ BOOST_AUTO_TEST_CASE(FaceList) BOOST_CHECK_EQUAL(result.front().getFaceId(), 24485); }, datasetFailCallback); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); FaceStatus payload1; payload1.setFaceId(24485); FaceStatus payload2; payload2.setFaceId(12987); this->sendDataset("/localhost/nfd/faces/list", payload1, payload2); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); BOOST_CHECK(hasResult); BOOST_CHECK_EQUAL(failCodes.size(), 0); @@ -290,14 +299,14 @@ BOOST_AUTO_TEST_CASE(FaceQuery) BOOST_CHECK_EQUAL(result.front().getFaceId(), 8795); }, datasetFailCallback); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); Name prefix("/localhost/nfd/faces/query"); prefix.append(filter.wireEncode()); FaceStatus payload; payload.setFaceId(8795); this->sendDataset(prefix, payload); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); BOOST_CHECK(hasResult); BOOST_CHECK_EQUAL(failCodes.size(), 0); @@ -308,7 +317,7 @@ BOOST_AUTO_TEST_CASE(FaceQueryWithOptions) FaceQueryFilter filter; filter.setUriScheme("udp4"); CommandOptions options; - options.setTimeout(time::milliseconds(3000)); + options.setTimeout(3000_ms); bool hasResult = false; controller.fetch( filter, @@ -319,14 +328,14 @@ BOOST_AUTO_TEST_CASE(FaceQueryWithOptions) }, datasetFailCallback, options); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); Name prefix("/localhost/nfd/faces/query"); prefix.append(filter.wireEncode()); FaceStatus payload; payload.setFaceId(14022); this->sendDataset(prefix, payload); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); BOOST_CHECK(hasResult); BOOST_CHECK_EQUAL(failCodes.size(), 0); @@ -342,14 +351,14 @@ BOOST_AUTO_TEST_CASE(FaceChannels) BOOST_CHECK_EQUAL(result.front().getLocalUri(), "tcp4://192.0.2.1:6363"); }, datasetFailCallback); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); ChannelStatus payload1; payload1.setLocalUri("tcp4://192.0.2.1:6363"); ChannelStatus payload2; payload2.setLocalUri("udp4://192.0.2.1:6363"); this->sendDataset("/localhost/nfd/faces/channels", payload1, payload2); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); BOOST_CHECK(hasResult); BOOST_CHECK_EQUAL(failCodes.size(), 0); @@ -365,14 +374,36 @@ BOOST_AUTO_TEST_CASE(FibList) BOOST_CHECK_EQUAL(result.front().getPrefix(), "/wYs7fzYcfG"); }, datasetFailCallback); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); FibEntry payload1; payload1.setPrefix("/wYs7fzYcfG"); FibEntry payload2; payload2.setPrefix("/LKvmnzY5S"); this->sendDataset("/localhost/nfd/fib/list", payload1, payload2); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); + + BOOST_CHECK(hasResult); + BOOST_CHECK_EQUAL(failCodes.size(), 0); +} + +BOOST_AUTO_TEST_CASE(CsInfo) +{ + using ndn::nfd::CsInfo; + + bool hasResult = false; + controller.fetch( + [&hasResult] (const CsInfo& result) { + hasResult = true; + BOOST_CHECK_EQUAL(result.getNHits(), 4539); + }, + datasetFailCallback); + this->advanceClocks(500_ms); + + CsInfo payload; + payload.setNHits(4539); + this->sendDataset("/localhost/nfd/cs/info", payload); + this->advanceClocks(500_ms); BOOST_CHECK(hasResult); BOOST_CHECK_EQUAL(failCodes.size(), 0); @@ -388,14 +419,14 @@ BOOST_AUTO_TEST_CASE(StrategyChoiceList) BOOST_CHECK_EQUAL(result.front().getName(), "/8MLz6N3B"); }, datasetFailCallback); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); StrategyChoice payload1; payload1.setName("/8MLz6N3B"); StrategyChoice payload2; payload2.setName("/svqcBu0YwU"); this->sendDataset("/localhost/nfd/strategy-choice/list", payload1, payload2); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); BOOST_CHECK(hasResult); BOOST_CHECK_EQUAL(failCodes.size(), 0); @@ -411,14 +442,14 @@ BOOST_AUTO_TEST_CASE(RibList) BOOST_CHECK_EQUAL(result.front().getName(), "/zXxBth97ee"); }, datasetFailCallback); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); RibEntry payload1; payload1.setName("/zXxBth97ee"); RibEntry payload2; payload2.setName("/rJ8CvUpr4G"); this->sendDataset("/localhost/nfd/rib/list", payload1, payload2); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); BOOST_CHECK(hasResult); BOOST_CHECK_EQUAL(failCodes.size(), 0); @@ -437,12 +468,12 @@ BOOST_AUTO_TEST_CASE(RibListWithOptions) }, datasetFailCallback, options); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); RibEntry payload; payload.setName("/e6L5K4ascd"); this->sendDataset("/localhop/nfd/rib/list", payload); - this->advanceClocks(time::milliseconds(500)); + this->advanceClocks(500_ms); BOOST_CHECK(hasResult); BOOST_CHECK_EQUAL(failCodes.size(), 0); diff --git a/tests/unit/mgmt/nfd/strategy-choice.t.cpp b/tests/unit/mgmt/nfd/strategy-choice.t.cpp new file mode 100644 index 000000000..1d8329bd1 --- /dev/null +++ b/tests/unit/mgmt/nfd/strategy-choice.t.cpp @@ -0,0 +1,96 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/mgmt/nfd/strategy-choice.hpp" + +#include "tests/boost-test.hpp" +#include + +namespace ndn { +namespace nfd { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Mgmt) +BOOST_AUTO_TEST_SUITE(Nfd) +BOOST_AUTO_TEST_SUITE(TestStrategyChoice) + +BOOST_AUTO_TEST_CASE(Encode) +{ + StrategyChoice sc1; + sc1.setName("/hello/world") + .setStrategy("/some/non/existing/strategy/name"); + Block wire = sc1.wireEncode(); + + // These octets are obtained by the snippet below. + // This check is intended to detect unexpected encoding change in the future. + // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) { + // printf("0x%02x, ", *it); + // } + static const uint8_t expected[] = { + 0x80, 0x39, 0x07, 0x0e, 0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x08, 0x05, 0x77, + 0x6f, 0x72, 0x6c, 0x64, 0x6b, 0x27, 0x07, 0x25, 0x08, 0x04, 0x73, 0x6f, 0x6d, 0x65, + 0x08, 0x03, 0x6e, 0x6f, 0x6e, 0x08, 0x08, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, + 0x67, 0x08, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x08, 0x04, 0x6e, + 0x61, 0x6d, 0x65 + }; + BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected), + wire.begin(), wire.end()); + + StrategyChoice sc2(wire); + BOOST_CHECK_EQUAL(sc1, sc2); +} + +BOOST_AUTO_TEST_CASE(Equality) +{ + StrategyChoice sc1, sc2; + + sc1.setName("/A") + .setStrategy("/strategyP"); + sc2 = sc1; + BOOST_CHECK_EQUAL(sc1, sc2); + + sc2.setName("/B"); + BOOST_CHECK_NE(sc1, sc2); + + sc2 = sc1; + sc2.setStrategy("/strategyQ"); + BOOST_CHECK_NE(sc1, sc2); +} + +BOOST_AUTO_TEST_CASE(Print) +{ + StrategyChoice sc; + BOOST_CHECK_EQUAL(boost::lexical_cast(sc), + "StrategyChoice(Name: /, Strategy: /)"); + + sc.setName("/A") + .setStrategy("/strategyP"); + BOOST_CHECK_EQUAL(boost::lexical_cast(sc), + "StrategyChoice(Name: /A, Strategy: /strategyP)"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestStrategyChoice +BOOST_AUTO_TEST_SUITE_END() // Nfd +BOOST_AUTO_TEST_SUITE_END() // Mgmt + +} // namespace tests +} // namespace nfd +} // namespace ndn diff --git a/tests/unit-tests/mgmt/status-dataset-context.t.cpp b/tests/unit/mgmt/status-dataset-context.t.cpp similarity index 88% rename from tests/unit-tests/mgmt/status-dataset-context.t.cpp rename to tests/unit/mgmt/status-dataset-context.t.cpp index cff721b7b..6ea594e2e 100644 --- a/tests/unit-tests/mgmt/status-dataset-context.t.cpp +++ b/tests/unit/mgmt/status-dataset-context.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,10 +19,10 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "mgmt/status-dataset-context.hpp" +#include "ndn-cxx/mgmt/status-dataset-context.hpp" -#include "boost-test.hpp" -#include "unit-tests/make-interest-data.hpp" +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" namespace ndn { namespace mgmt { @@ -54,7 +54,7 @@ class StatusDatasetContextFixture [this] (const ControlResponse& resp) { sendNackHistory.push_back(resp); }) - , defaultImsFresh(time::milliseconds(1000)) + , defaultImsFresh(1000_ms) { } @@ -97,7 +97,7 @@ BOOST_AUTO_TEST_CASE(Get) { Name dataName = context.getPrefix(); BOOST_CHECK(dataName[-1].isVersion()); - BOOST_CHECK(dataName.getPrefix(-1) == interest->getName()); + BOOST_CHECK_EQUAL(dataName.getPrefix(-1), interest->getName()); } BOOST_AUTO_TEST_CASE(SetValid) @@ -105,7 +105,7 @@ BOOST_AUTO_TEST_CASE(SetValid) Name validPrefix = Name(interest->getName()).append("/valid"); BOOST_CHECK_NO_THROW(context.setPrefix(validPrefix)); BOOST_CHECK(context.getPrefix()[-1].isVersion()); - BOOST_CHECK(context.getPrefix().getPrefix(-1) == validPrefix); + BOOST_CHECK_EQUAL(context.getPrefix().getPrefix(-1), validPrefix); } BOOST_AUTO_TEST_CASE(SetInvalid) @@ -141,8 +141,8 @@ BOOST_AUTO_TEST_SUITE(Expiry) BOOST_AUTO_TEST_CASE(GetAndSet) { - auto period = time::milliseconds(9527); - BOOST_CHECK_EQUAL(context.getExpiry(), time::milliseconds(1000)); + auto period = 9527_ms; + BOOST_CHECK_EQUAL(context.getExpiry(), 1000_ms); BOOST_CHECK_EQUAL(context.setExpiry(period).getExpiry(), period); } @@ -161,7 +161,7 @@ BOOST_AUTO_TEST_CASE(Basic) const auto& args = sendDataHistory[0]; BOOST_CHECK_EQUAL(args.dataName, makeSegmentName(0)); - BOOST_CHECK(args.content.blockFromValue() == contentBlock); + BOOST_CHECK_EQUAL(args.content.blockFromValue(), contentBlock); BOOST_CHECK_EQUAL(args.imsFresh, defaultImsFresh); BOOST_CHECK_EQUAL(args.isFinalBlock, true); } @@ -199,7 +199,7 @@ BOOST_AUTO_TEST_CASE(Large) auto contentLargeBlock = concatenateDataContent(); BOOST_CHECK_NO_THROW(contentLargeBlock.parse()); BOOST_REQUIRE_EQUAL(contentLargeBlock.elements().size(), 1); - BOOST_CHECK(contentLargeBlock.elements()[0] == largeBlock); + BOOST_CHECK_EQUAL(contentLargeBlock.elements()[0], largeBlock); } BOOST_AUTO_TEST_CASE(MultipleSmall) @@ -220,7 +220,7 @@ BOOST_AUTO_TEST_CASE(MultipleSmall) BOOST_CHECK_NO_THROW(contentMultiBlocks.parse()); BOOST_CHECK_EQUAL(contentMultiBlocks.elements().size(), nBlocks); for (auto&& element : contentMultiBlocks.elements()) { - BOOST_CHECK(element == contentBlock); + BOOST_CHECK_EQUAL(element, contentBlock); } } @@ -253,13 +253,15 @@ BOOST_FIXTURE_TEST_SUITE(AbnormalState, AbnormalStateTestFixture) BOOST_AUTO_TEST_CASE(AppendReject) { - BOOST_CHECK_NO_THROW(context.append(Block("\x82\x01\x02", 3))); + const uint8_t buf[] = {0x82, 0x01, 0x02}; + BOOST_CHECK_NO_THROW(context.append(Block(buf, sizeof(buf)))); BOOST_CHECK_THROW(context.reject(), std::domain_error); } BOOST_AUTO_TEST_CASE(AppendEndReject) { - BOOST_CHECK_NO_THROW(context.append(Block("\x82\x01\x02", 3))); + const uint8_t buf[] = {0x82, 0x01, 0x02}; + BOOST_CHECK_NO_THROW(context.append(Block(buf, sizeof(buf)))); BOOST_CHECK_NO_THROW(context.end()); BOOST_CHECK_THROW(context.reject(), std::domain_error); } @@ -268,7 +270,8 @@ BOOST_AUTO_TEST_CASE(EndAppend) { BOOST_CHECK_NO_THROW(context.end()); // end, append -> error - BOOST_CHECK_THROW(context.append(Block("\x82\x01\x02", 3)), std::domain_error); + const uint8_t buf[] = {0x82, 0x01, 0x02}; + BOOST_CHECK_THROW(context.append(Block(buf, sizeof(buf))), std::domain_error); } BOOST_AUTO_TEST_CASE(EndEnd) @@ -286,7 +289,8 @@ BOOST_AUTO_TEST_CASE(EndReject) BOOST_AUTO_TEST_CASE(RejectAppend) { BOOST_CHECK_NO_THROW(context.reject()); - BOOST_CHECK_THROW(context.append(Block("\x82\x01\x02", 3)), std::domain_error); + const uint8_t buf[] = {0x82, 0x01, 0x02}; + BOOST_CHECK_THROW(context.append(Block(buf, sizeof(buf))), std::domain_error); } BOOST_AUTO_TEST_CASE(RejectEnd) diff --git a/tests/unit/name-component.t.cpp b/tests/unit/name-component.t.cpp new file mode 100644 index 000000000..fe62ee077 --- /dev/null +++ b/tests/unit/name-component.t.cpp @@ -0,0 +1,578 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/name-component.hpp" +#include "ndn-cxx/name.hpp" +#include "ndn-cxx/util/string-helper.hpp" + +#include "tests/boost-test.hpp" + +#include +#include +#include +#include + +namespace ndn { +namespace name { +namespace tests { + +BOOST_AUTO_TEST_SUITE(TestNameComponent) + +BOOST_AUTO_TEST_SUITE(Decode) + +#define CHECK_COMP_ERR(expr, whatstring) \ + BOOST_CHECK_EXCEPTION(expr, Component::Error, \ + [] (const auto& e) { return boost::contains(e.what(), whatstring); }) + +BOOST_AUTO_TEST_CASE(Generic) +{ + Component comp("0807 6E646E2D637878"_block); + BOOST_CHECK_EQUAL(comp.type(), tlv::GenericNameComponent); + BOOST_CHECK_EQUAL(comp.isGeneric(), true); + BOOST_CHECK_EQUAL(comp.toUri(), "ndn-cxx"); + BOOST_CHECK_EQUAL(comp.toUri(UriFormat::CANONICAL), "8=ndn-cxx"); + BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ALTERNATE), "ndn-cxx"); + BOOST_CHECK_EQUAL(boost::lexical_cast(comp), "ndn-cxx"); + BOOST_CHECK_EQUAL(Component::fromEscapedString("ndn-cxx"), comp); + BOOST_CHECK_EQUAL(Component::fromEscapedString("8=ndn-cxx"), comp); + + comp.wireDecode("0800"_block); + BOOST_CHECK_EQUAL(comp.toUri(), "..."); + BOOST_CHECK_EQUAL(Component::fromEscapedString("..."), comp); + BOOST_CHECK_EQUAL(Component::fromEscapedString("8=..."), comp); + BOOST_CHECK_EQUAL(Component::fromEscapedString(".%2E."), comp); + + comp.wireDecode("0801 2E"_block); + BOOST_CHECK_EQUAL(comp.toUri(), "...."); + BOOST_CHECK_EQUAL(Component::fromEscapedString("...."), comp); + BOOST_CHECK_EQUAL(Component::fromEscapedString("%2E..%2E"), comp); + + comp.wireDecode("0803 2E412E"_block); + BOOST_CHECK_EQUAL(comp.toUri(), ".A."); + BOOST_CHECK_EQUAL(Component::fromEscapedString(".A."), comp); + + comp.wireDecode("0807 666F6F25626172"_block); + BOOST_CHECK_EQUAL(comp.toUri(), "foo%25bar"); + BOOST_CHECK_EQUAL(Component::fromEscapedString("foo%25bar"), comp); + BOOST_CHECK_EQUAL(Component::fromEscapedString("8=foo%25bar"), comp); + + comp.wireDecode("0804 2D2E5F7E"_block); + BOOST_CHECK_EQUAL(comp.toUri(), "-._~"); + BOOST_CHECK_EQUAL(Component::fromEscapedString("-._~"), comp); + + comp.wireDecode("0803 393D41"_block); + BOOST_CHECK_EQUAL(comp.toUri(), "9%3DA"); + BOOST_CHECK_EQUAL(Component::fromEscapedString("9%3DA"), comp); + + comp = Component(":/?#[]@"); + BOOST_CHECK_EQUAL(comp.toUri(), "%3A%2F%3F%23%5B%5D%40"); + BOOST_CHECK_EQUAL(Component::fromEscapedString("%3A%2F%3F%23%5B%5D%40"), comp); + + BOOST_CHECK_THROW(Component::fromEscapedString(""), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString("."), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString(".."), Component::Error); +} + +static void +testSha256Component(uint32_t type, const std::string& uriPrefix) +{ + const std::string hexLower = "28bad4b5275bd392dbb670c75cf0b66f13f7942b21e80f55c0e86b374753a548"; + const std::string hexUpper = boost::to_upper_copy(hexLower); + std::string hexPct; + for (size_t i = 0; i < hexUpper.size(); i += 2) { + hexPct += "%" + hexUpper.substr(i, 2); + } + const std::string hexPctCanonical = "%28%BA%D4%B5%27%5B%D3%92%DB%B6p%C7%5C%F0%B6o%13%F7%94%2B%21%E8%0FU%C0%E8k7GS%A5H"; + + Component comp(Block(type, fromHex(hexLower))); + + BOOST_CHECK_EQUAL(comp.type(), type); + BOOST_CHECK_EQUAL(comp.toUri(), uriPrefix + hexLower); + BOOST_CHECK_EQUAL(comp.toUri(UriFormat::CANONICAL), to_string(type) + "=" + hexPctCanonical); + BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ALTERNATE), uriPrefix + hexLower); + BOOST_CHECK_EQUAL(boost::lexical_cast(comp), uriPrefix + hexLower); + BOOST_CHECK_EQUAL(comp, Component::fromEscapedString(uriPrefix + hexLower)); + BOOST_CHECK_EQUAL(comp, Component::fromEscapedString(uriPrefix + hexUpper)); + BOOST_CHECK_EQUAL(comp, Component::fromEscapedString(to_string(type) + "=" + hexPct)); + BOOST_CHECK_EQUAL(comp, Component::fromEscapedString(to_string(type) + "=" + hexPctCanonical)); + + CHECK_COMP_ERR(comp.wireDecode(Block(type, fromHex("A791806951F25C4D"))), "TLV-LENGTH must be 32"); + CHECK_COMP_ERR(Component::fromEscapedString(uriPrefix), "TLV-LENGTH must be 32"); + CHECK_COMP_ERR(Component::fromEscapedString(uriPrefix + "a791806951f25c4d"), "TLV-LENGTH must be 32"); + CHECK_COMP_ERR(Component::fromEscapedString(uriPrefix + "foo"), "invalid hex encoding"); + CHECK_COMP_ERR(Component::fromEscapedString(boost::to_upper_copy(uriPrefix) + hexLower), "Unknown TLV-TYPE"); +} + +BOOST_AUTO_TEST_CASE(ImplicitDigest) +{ + testSha256Component(tlv::ImplicitSha256DigestComponent, "sha256digest="); +} + +BOOST_AUTO_TEST_CASE(ParametersDigest) +{ + testSha256Component(tlv::ParametersSha256DigestComponent, "params-sha256="); +} + +static void +testDecimalComponent(uint32_t type, const std::string& uriPrefix) +{ + const Component comp(makeNonNegativeIntegerBlock(type, 42)); // TLV-VALUE is a nonNegativeInteger + BOOST_CHECK_EQUAL(comp.type(), type); + BOOST_CHECK_EQUAL(comp.isNumber(), true); + const auto compUri = uriPrefix + "42"; + BOOST_CHECK_EQUAL(comp.toUri(), compUri); + BOOST_CHECK_EQUAL(comp.toUri(UriFormat::CANONICAL), to_string(type) + "=%2A"); + BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ALTERNATE), compUri); + BOOST_CHECK_EQUAL(boost::lexical_cast(comp), compUri); + BOOST_CHECK_EQUAL(comp, Component::fromEscapedString(compUri)); + BOOST_CHECK_EQUAL(comp, Component::fromEscapedString(to_string(type) + "=%2A")); + BOOST_CHECK_EQUAL(comp, Component::fromNumber(42, type)); + + const Component comp2(Block(type, fromHex("010203"))); // TLV-VALUE is *not* a nonNegativeInteger + BOOST_CHECK_EQUAL(comp2.type(), type); + BOOST_CHECK_EQUAL(comp2.isNumber(), false); + const auto comp2Uri = to_string(type) + "=%01%02%03"; + BOOST_CHECK_EQUAL(comp2.toUri(), comp2Uri); + BOOST_CHECK_EQUAL(boost::lexical_cast(comp2), comp2Uri); + BOOST_CHECK_EQUAL(comp2, Component::fromEscapedString(comp2Uri)); + + CHECK_COMP_ERR(Component::fromEscapedString(uriPrefix), "invalid format"); + CHECK_COMP_ERR(Component::fromEscapedString(uriPrefix + "foo"), "invalid format"); + CHECK_COMP_ERR(Component::fromEscapedString(uriPrefix + "00"), "invalid format"); + CHECK_COMP_ERR(Component::fromEscapedString(uriPrefix + "-1"), "invalid format"); + CHECK_COMP_ERR(Component::fromEscapedString(uriPrefix + "9.3"), "invalid format"); + CHECK_COMP_ERR(Component::fromEscapedString(uriPrefix + " 84"), "invalid format"); + CHECK_COMP_ERR(Component::fromEscapedString(uriPrefix + "0xAF"), "invalid format"); + CHECK_COMP_ERR(Component::fromEscapedString(uriPrefix + "18446744073709551616"), "out of range"); + CHECK_COMP_ERR(Component::fromEscapedString(boost::to_upper_copy(uriPrefix) + "42"), "Unknown TLV-TYPE"); +} + +BOOST_AUTO_TEST_CASE(Segment) +{ + testDecimalComponent(tlv::SegmentNameComponent, "seg="); +} + +BOOST_AUTO_TEST_CASE(ByteOffset) +{ + testDecimalComponent(tlv::ByteOffsetNameComponent, "off="); +} + +BOOST_AUTO_TEST_CASE(Version) +{ + testDecimalComponent(tlv::VersionNameComponent, "v="); +} + +BOOST_AUTO_TEST_CASE(Timestamp) +{ + testDecimalComponent(tlv::TimestampNameComponent, "t="); +} + +BOOST_AUTO_TEST_CASE(SequenceNum) +{ + testDecimalComponent(tlv::SequenceNumNameComponent, "seq="); +} + +BOOST_AUTO_TEST_CASE(OtherType) +{ + Component comp("0907 6E646E2D637878"_block); + BOOST_CHECK_EQUAL(comp.type(), 0x09); + BOOST_CHECK_EQUAL(comp.toUri(), "9=ndn-cxx"); + BOOST_CHECK_EQUAL(Component::fromEscapedString("9=ndn-cxx"), comp); + + comp.wireDecode("FDFFFF00"_block); + BOOST_CHECK_EQUAL(comp.type(), 0xFFFF); + BOOST_CHECK_EQUAL(comp.toUri(), "65535=..."); + BOOST_CHECK_EQUAL(Component::fromEscapedString("65535=..."), comp); + + comp.wireDecode("FD576501 2E"_block); + BOOST_CHECK_EQUAL(comp.type(), 0x5765); + BOOST_CHECK_EQUAL(comp.toUri(), "22373=...."); + BOOST_CHECK_EQUAL(Component::fromEscapedString("22373=...."), comp); + + BOOST_CHECK_THROW(Component::fromEscapedString("3="), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString("3=."), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString("3=.."), Component::Error); +} + +BOOST_AUTO_TEST_CASE(InvalidType) +{ + Component comp; + BOOST_CHECK_THROW(comp.wireDecode(Block{}), Component::Error); + BOOST_CHECK_THROW(comp.wireDecode("FE0001000001 80"_block), Component::Error); + + BOOST_CHECK_THROW(Component::fromEscapedString("0=A"), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString("65536=A"), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString("4294967296=A"), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString("-1=A"), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString("+=A"), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString("=A"), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString("0x1=A"), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString("Z=A"), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString("09=A"), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString("0x3=A"), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString("+9=A"), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString(" 9=A"), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString("9 =A"), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString("9.0=A"), Component::Error); + BOOST_CHECK_THROW(Component::fromEscapedString("9E0=A"), Component::Error); +} + +BOOST_AUTO_TEST_SUITE_END() // Decode + +BOOST_AUTO_TEST_CASE(Compare) +{ + const std::vector comps = { + Component("0120 0000000000000000000000000000000000000000000000000000000000000000"_block), + Component("0120 0000000000000000000000000000000000000000000000000000000000000001"_block), + Component("0120 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"_block), + Component("0220 0000000000000000000000000000000000000000000000000000000000000000"_block), + Component("0220 0000000000000000000000000000000000000000000000000000000000000001"_block), + Component("0220 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"_block), + Component(0x03), + Component("0301 44"_block), + Component("0301 46"_block), + Component("0302 4141"_block), + Component(), + Component("D"), + Component("F"), + Component("AA"), + Component(0x53B2), + Component("FD53B201 44"_block), + Component("FD53B201 46"_block), + Component("FD53B202 4141"_block), + }; + + for (size_t i = 0; i < comps.size(); ++i) { + for (size_t j = 0; j < comps.size(); ++j) { + Component lhs = comps[i]; + Component rhs = comps[j]; + BOOST_CHECK_EQUAL(lhs == rhs, i == j); + BOOST_CHECK_EQUAL(lhs != rhs, i != j); + BOOST_CHECK_EQUAL(lhs < rhs, i < j); + BOOST_CHECK_EQUAL(lhs <= rhs, i <= j); + BOOST_CHECK_EQUAL(lhs > rhs, i > j); + BOOST_CHECK_EQUAL(lhs >= rhs, i >= j); + } + } +} + +BOOST_AUTO_TEST_SUITE(CreateFromIterators) // Bug 2490 + +using ContainerTypes = boost::mpl::vector, + std::list, + std::vector, + std::list>; + +BOOST_AUTO_TEST_CASE_TEMPLATE(ZeroOctet, T, ContainerTypes) +{ + T bytes; + Component c(bytes.begin(), bytes.end()); + BOOST_CHECK_EQUAL(c.type(), tlv::GenericNameComponent); + BOOST_CHECK_EQUAL(c.value_size(), 0); + BOOST_CHECK_EQUAL(c.size(), 2); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(OneOctet, T, ContainerTypes) +{ + T bytes{1}; + Component c(0x09, bytes.begin(), bytes.end()); + BOOST_CHECK_EQUAL(c.type(), 0x09); + BOOST_CHECK_EQUAL(c.value_size(), 1); + BOOST_CHECK_EQUAL(c.size(), 3); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(FourOctets, T, ContainerTypes) +{ + T bytes{1, 2, 3, 4}; + Component c(0xFCEC, bytes.begin(), bytes.end()); + BOOST_CHECK_EQUAL(c.type(), 0xFCEC); + BOOST_CHECK_EQUAL(c.value_size(), 4); + BOOST_CHECK_EQUAL(c.size(), 8); +} + +BOOST_AUTO_TEST_SUITE_END() // CreateFromIterators + +BOOST_AUTO_TEST_SUITE(NamingConvention) + +template +struct ConventionTest +{ + std::function makeComponent; + std::function getValue; + std::function append; + Name expected; + ArgType value; + std::function isComponent; +}; + +class ConventionMarker +{ +}; + +class ConventionTyped +{ +public: + ConventionTyped() + { + name::setConventionEncoding(name::Convention::TYPED); + } + + ~ConventionTyped() + { + name::setConventionEncoding(name::Convention::MARKER); + } +}; + +class NumberWithMarker +{ +public: + using ConventionRev = ConventionMarker; + + ConventionTest + operator()() const + { + return {bind(&Component::fromNumberWithMarker, 0xAA, _1), + bind(&Component::toNumberWithMarker, _1, 0xAA), + bind(&Name::appendNumberWithMarker, _1, 0xAA, _2), + Name("/%AA%03%E8"), + 1000, + bind(&Component::isNumberWithMarker, _1, 0xAA)}; + } +}; + +class SegmentMarker +{ +public: + using ConventionRev = ConventionMarker; + + ConventionTest + operator()() const + { + return {&Component::fromSegment, + bind(&Component::toSegment, _1), + bind(&Name::appendSegment, _1, _2), + Name("/%00%27%10"), + 10000, + bind(&Component::isSegment, _1)}; + } +}; + +class SegmentTyped +{ +public: + using ConventionRev = ConventionTyped; + + ConventionTest + operator()() const + { + return {&Component::fromSegment, + bind(&Component::toSegment, _1), + bind(&Name::appendSegment, _1, _2), + Name("/33=%27%10"), + 10000, + bind(&Component::isSegment, _1)}; + } +}; + +class SegmentOffsetMarker +{ +public: + using ConventionRev = ConventionMarker; + + ConventionTest + operator()() const + { + return {&Component::fromSegmentOffset, + bind(&Component::toSegmentOffset, _1), + bind(&Name::appendSegmentOffset, _1, _2), + Name("/%FB%00%01%86%A0"), + 100000, + bind(&Component::isSegmentOffset, _1)}; + } +}; + +class ByteOffsetTyped +{ +public: + using ConventionRev = ConventionTyped; + + ConventionTest + operator()() const + { + return {&Component::fromByteOffset, + bind(&Component::toByteOffset, _1), + bind(&Name::appendByteOffset, _1, _2), + Name("/34=%00%01%86%A0"), + 100000, + bind(&Component::isByteOffset, _1)}; + } +}; + +class VersionMarker +{ +public: + using ConventionRev = ConventionMarker; + + ConventionTest + operator()() const + { + return {&Component::fromVersion, + bind(&Component::toVersion, _1), + [] (Name& name, uint64_t version) -> Name& { return name.appendVersion(version); }, + Name("/%FD%00%0FB%40"), + 1000000, + bind(&Component::isVersion, _1)}; + } +}; + +class VersionTyped +{ +public: + using ConventionRev = ConventionTyped; + + ConventionTest + operator()() const + { + return {&Component::fromVersion, + bind(&Component::toVersion, _1), + [] (Name& name, uint64_t version) -> Name& { return name.appendVersion(version); }, + Name("/35=%00%0FB%40"), + 1000000, + bind(&Component::isVersion, _1)}; + } +}; + +class TimestampMarker +{ +public: + using ConventionRev = ConventionMarker; + + ConventionTest + operator()() const + { + return {&Component::fromTimestamp, + bind(&Component::toTimestamp, _1), + [] (Name& name, time::system_clock::TimePoint t) -> Name& { return name.appendTimestamp(t); }, + Name("/%FC%00%04%7BE%E3%1B%00%00"), + time::getUnixEpoch() + 14600_days, // 40 years + bind(&Component::isTimestamp, _1)}; + } +}; + +class TimestampTyped +{ +public: + using ConventionRev = ConventionTyped; + + ConventionTest + operator()() const + { + return {&Component::fromTimestamp, + bind(&Component::toTimestamp, _1), + [] (Name& name, time::system_clock::TimePoint t) -> Name& { return name.appendTimestamp(t); }, + Name("/36=%00%04%7BE%E3%1B%00%00"), + time::getUnixEpoch() + 14600_days, // 40 years + bind(&Component::isTimestamp, _1)}; + } +}; + +class SequenceNumberMarker +{ +public: + using ConventionRev = ConventionMarker; + + ConventionTest + operator()() const + { + return {&Component::fromSequenceNumber, + bind(&Component::toSequenceNumber, _1), + bind(&Name::appendSequenceNumber, _1, _2), + Name("/%FE%00%98%96%80"), + 10000000, + bind(&Component::isSequenceNumber, _1)}; + } +}; + +class SequenceNumberTyped +{ +public: + using ConventionRev = ConventionTyped; + + ConventionTest + operator()() const + { + return {&Component::fromSequenceNumber, + bind(&Component::toSequenceNumber, _1), + bind(&Name::appendSequenceNumber, _1, _2), + Name("/37=%00%98%96%80"), + 10000000, + bind(&Component::isSequenceNumber, _1)}; + } +}; + +using ConventionTests = boost::mpl::vector< + NumberWithMarker, + SegmentMarker, + SegmentTyped, + SegmentOffsetMarker, + ByteOffsetTyped, + VersionMarker, + VersionTyped, + TimestampMarker, + TimestampTyped, + SequenceNumberMarker, + SequenceNumberTyped +>; + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(Convention, T, ConventionTests, T::ConventionRev) +{ + Component invalidComponent1; + Component invalidComponent2("1234567890"); + + auto test = T()(); + + const Name& expected = test.expected; + BOOST_TEST_MESSAGE("Check " << expected[0]); + + Component actualComponent = test.makeComponent(test.value); + BOOST_CHECK_EQUAL(actualComponent, expected[0]); + + Name actualName; + test.append(actualName, test.value); + BOOST_CHECK_EQUAL(actualName, expected); + + BOOST_CHECK_EQUAL(test.isComponent(expected[0]), true); + BOOST_CHECK_EQUAL(test.getValue(expected[0]), test.value); + + BOOST_CHECK_EQUAL(test.isComponent(invalidComponent1), false); + BOOST_CHECK_EQUAL(test.isComponent(invalidComponent2), false); + + BOOST_CHECK_THROW(test.getValue(invalidComponent1), Component::Error); + BOOST_CHECK_THROW(test.getValue(invalidComponent2), Component::Error); +} + +BOOST_AUTO_TEST_SUITE_END() // NamingConvention + +BOOST_AUTO_TEST_SUITE_END() // TestNameComponent + +} // namespace tests +} // namespace name +} // namespace ndn diff --git a/tests/unit/name.t.cpp b/tests/unit/name.t.cpp new file mode 100644 index 000000000..21ecc00fb --- /dev/null +++ b/tests/unit/name.t.cpp @@ -0,0 +1,534 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/name.hpp" + +#include "tests/boost-test.hpp" + +#include + +namespace ndn { +namespace tests { + +using Component = name::Component; +using UriFormat = name::UriFormat; + +BOOST_AUTO_TEST_SUITE(TestName) + +// ---- encoding, decoding, and URI ---- + +BOOST_AUTO_TEST_CASE(EncodeDecode) +{ + std::string uri = "/Emid/25042=P3/.../..../%1C%9F/" + "sha256digest=0415e3624a151850ac686c84f155f29808c0dd73819aa4a4c20be73a4d8a874c"; + Name name(uri); + BOOST_CHECK_EQUAL(name.size(), 6); + BOOST_CHECK_EQUAL(name[0], Component("Emid")); + BOOST_CHECK_EQUAL(name[1], Component("FD61D2025033"_block)); + BOOST_CHECK_EQUAL(name[2], Component("")); + BOOST_CHECK_EQUAL(name[3], Component(".")); + BOOST_CHECK_EQUAL(name[4], Component("\x1C\x9F")); + BOOST_CHECK(name[5].isImplicitSha256Digest()); + + BOOST_CHECK_EQUAL(name.toUri(UriFormat::CANONICAL), + "/8=Emid/25042=P3/8=.../8=..../8=%1C%9F/" + "1=%04%15%E3bJ%15%18P%AChl%84%F1U%F2%98%08%C0%DDs%81%9A%A4%A4%C2%0B%E7%3AM%8A%87L"); + + Block wire = name.wireEncode(); + BOOST_CHECK_EQUAL(wire, + "0737 0804456D6964 FD61D2025033 0800 08012E 08021C9F " + "01200415E3624A151850AC686C84F155F29808C0DD73819AA4A4C20BE73A4D8A874C"_block); + + Name decoded(wire); + BOOST_CHECK_EQUAL(decoded, name); +} + +BOOST_AUTO_TEST_CASE(ParseUri) +{ + // canonical URI + BOOST_CHECK_EQUAL(Name("/8=hello/8=world").toUri(), "/hello/world"); + + // URI with correct scheme + BOOST_CHECK_EQUAL(Name("ndn:/hello/world").toUri(), "/hello/world"); + + // URI with incorrect scheme: auto-corrected + BOOST_CHECK_EQUAL(Name("ncc:/hello/world").toUri(), "/hello/world"); + + // URI with authority: authority ignored + BOOST_CHECK_EQUAL(Name("//authority/hello/world").toUri(), "/hello/world"); + BOOST_CHECK_EQUAL(Name("ndn://authority/hello/world").toUri(), "/hello/world"); + + // URI containing unescaped characters: auto-corrected + BOOST_CHECK_EQUAL(Name("/ hello\t/\tworld \r\n").toUri(), "/%20hello%09/%09world%20%0D%0A"); + BOOST_CHECK_EQUAL(Name("/hello/world/ ").toUri(), "/hello/world/%20%20"); + BOOST_CHECK_EQUAL(Name("/:?#[]@").toUri(), "/%3A%3F%23%5B%5D%40"); + + // URI not starting with '/': accepted as PartialName + BOOST_CHECK_EQUAL(Name("").toUri(), "/"); + BOOST_CHECK_EQUAL(Name(" ").toUri(), "/%20"); + BOOST_CHECK_EQUAL(Name(" /hello/world").toUri(), "/%20%20/hello/world"); + BOOST_CHECK_EQUAL(Name("hello/world").toUri(), "/hello/world"); + + // URI ending with '/': auto-corrected + BOOST_CHECK_EQUAL(Name("/hello/world/").toUri(), "/hello/world"); + + // URI containing bad component: rejected + BOOST_CHECK_THROW(Name("/hello//world"), name::Component::Error); + BOOST_CHECK_THROW(Name("/hello/./world"), name::Component::Error); + BOOST_CHECK_THROW(Name("/hello/../world"), name::Component::Error); +} + +BOOST_AUTO_TEST_CASE(DeepCopy) +{ + Name n1("/hello/world"); + Name n2 = n1.deepCopy(); + + BOOST_CHECK_EQUAL(n1, n2); + BOOST_CHECK_NE(&n1.wireEncode(), &n2.wireEncode()); + + EncodingBuffer buffer(1024, 0); + n1.wireEncode(buffer); + Name n3(buffer.block()); + + BOOST_CHECK_EQUAL(n1, n3); + BOOST_CHECK_EQUAL(n3.wireEncode().getBuffer()->size(), 1024); + n3 = n3.deepCopy(); + + BOOST_CHECK_LT(n3.wireEncode().size(), 1024); + BOOST_CHECK_EQUAL(n3.wireEncode().getBuffer()->size(), n3.wireEncode().size()); +} + +// ---- access ---- + +BOOST_AUTO_TEST_CASE(At) +{ + Name name("/hello/5=NDN"); + + BOOST_CHECK_EQUAL(name.at(0), name::Component("080568656C6C6F"_block)); + BOOST_CHECK_EQUAL(name.at(1), name::Component("05034E444E"_block)); + BOOST_CHECK_EQUAL(name.at(-1), name::Component("05034E444E"_block)); + BOOST_CHECK_EQUAL(name.at(-2), name::Component("080568656C6C6F"_block)); + + BOOST_CHECK_THROW(name.at(2), Name::Error); + BOOST_CHECK_THROW(name.at(-3), Name::Error); +} + +BOOST_AUTO_TEST_CASE(SubName) +{ + Name name("/hello/world"); + + BOOST_CHECK_EQUAL("/hello/world", name.getSubName(0)); + BOOST_CHECK_EQUAL("/world", name.getSubName(1)); + BOOST_CHECK_EQUAL("/hello", name.getSubName(0, 1)); +} + +BOOST_AUTO_TEST_CASE(SubNameNegativeIndex) +{ + Name name("/first/second/third/last"); + + BOOST_CHECK_EQUAL("/last", name.getSubName(-1)); + BOOST_CHECK_EQUAL("/third/last", name.getSubName(-2)); + BOOST_CHECK_EQUAL("/second", name.getSubName(-3, 1)); +} + +BOOST_AUTO_TEST_CASE(SubNameOutOfRangeIndexes) +{ + Name name("/first/second/last"); + // No length + BOOST_CHECK_EQUAL("/first/second/last", name.getSubName(-10)); + BOOST_CHECK_EQUAL("/", name.getSubName(10)); + + // Starting after the max position + BOOST_CHECK_EQUAL("/", name.getSubName(10, 1)); + BOOST_CHECK_EQUAL("/", name.getSubName(10, 10)); + + // Not enough components + BOOST_CHECK_EQUAL("/second/last", name.getSubName(1, 10)); + BOOST_CHECK_EQUAL("/last", name.getSubName(-1, 10)); + + // Start before first + BOOST_CHECK_EQUAL("/first/second", name.getSubName(-10, 2)); + BOOST_CHECK_EQUAL("/first/second/last", name.getSubName(-10, 10)); +} + +// ---- iterators ---- + +BOOST_AUTO_TEST_CASE(ForwardIterator) +{ + name::Component comps[] { + name::Component("A"), + name::Component("B"), + name::Component("C"), + name::Component("D") + }; + + Name n0; + BOOST_CHECK_EQUAL_COLLECTIONS(n0.begin(), n0.end(), comps, comps + 0); + + Name n4("/A/B/C/D"); + BOOST_CHECK_EQUAL_COLLECTIONS(n4.begin(), n4.end(), comps, comps + 4); +} + +BOOST_AUTO_TEST_CASE(ReverseIterator) +{ + name::Component comps[] { + name::Component("D"), + name::Component("C"), + name::Component("B"), + name::Component("A") + }; + + Name n0; + BOOST_CHECK_EQUAL_COLLECTIONS(n0.rbegin(), n0.rend(), comps, comps + 0); + + Name n4("/A/B/C/D"); + BOOST_CHECK_EQUAL_COLLECTIONS(n4.rbegin(), n4.rend(), comps, comps + 4); +} + +// ---- modifiers ---- + +BOOST_AUTO_TEST_CASE(SetComponent) +{ + Name name("/A/B"); + BOOST_CHECK_EQUAL(name.wireEncode(), "0706 080141 080142"_block); + BOOST_CHECK_EQUAL(name.hasWire(), true); + + // pass by const lvalue ref + const Component c("C"); + name.set(0, c); + BOOST_CHECK_EQUAL(name.hasWire(), false); + BOOST_CHECK_EQUAL(name.wireEncode(), "0706 080143 080142"_block); + + // pass by rvalue ref + Component d("D"); + name.set(1, std::move(d)); + BOOST_CHECK_EQUAL(name.hasWire(), false); + BOOST_CHECK_EQUAL(name.wireEncode(), "0706 080143 080144"_block); + + // negative index + name.set(-1, Component("E")); + BOOST_CHECK_EQUAL(name.wireEncode(), "0706 080143 080145"_block); +} + +BOOST_AUTO_TEST_CASE(AppendComponent) +{ + Name name; + BOOST_CHECK_EQUAL(name.wireEncode(), "0700"_block); + + name.append(Component("Emid")); + BOOST_CHECK_EQUAL(name.wireEncode(), "0706 0804456D6964"_block); + + name.append(25042, reinterpret_cast("P3"), 2); + BOOST_CHECK_EQUAL(name.wireEncode(), "070C 0804456D6964 FD61D2025033"_block); + + name.append(reinterpret_cast("."), 1); + BOOST_CHECK_EQUAL(name.wireEncode(), "070F 0804456D6964 FD61D2025033 08012E"_block); + + std::vector v1{0x28, 0xF0, 0xA3, 0x6B}; + name.append(16, v1.begin(), v1.end()); + BOOST_CHECK_EQUAL(name.wireEncode(), "0715 0804456D6964 FD61D2025033 08012E 100428F0A36B"_block); + + BOOST_CHECK(!name.empty()); + name.clear(); + BOOST_CHECK(name.empty()); + BOOST_CHECK_EQUAL(name.wireEncode(), "0700"_block); + + name.append(v1.begin(), v1.end()); + BOOST_CHECK_EQUAL(name.wireEncode(), "0706 080428F0A36B"_block); + + name.append("xKh"); + BOOST_CHECK_EQUAL(name.wireEncode(), "070B 080428F0A36B 0803784B68"_block); + + name.append("0100"_block); + BOOST_CHECK_EQUAL(name.wireEncode(), "070F 080428F0A36B 0803784B68 08020100"_block); + + name.append("080109"_block); + BOOST_CHECK_EQUAL(name.wireEncode(), "0712 080428F0A36B 0803784B68 08020100 080109"_block); +} + +BOOST_AUTO_TEST_CASE(AppendPartialName) +{ + Name name("/A/B"); + name.append(PartialName("/6=C/D")) + .append(PartialName("/E")); + BOOST_CHECK_EQUAL(name.wireEncode(), "070F 080141 080142 060143 080144 080145"_block); + + name = "/A/B"; + name.append(name); + BOOST_CHECK_EQUAL(name.wireEncode(), "070C 080141 080142 080141 080142"_block); +} + +BOOST_AUTO_TEST_CASE(AppendNumber) +{ + Name name; + for (uint32_t i = 0; i < 10; i++) { + name.appendNumber(i); + } + BOOST_CHECK_EQUAL(name.size(), 10); + + for (uint32_t i = 0; i < 10; i++) { + BOOST_CHECK_EQUAL(name[i].toNumber(), i); + } +} + +BOOST_AUTO_TEST_CASE(AppendParametersSha256Digest) +{ + auto digest = make_shared(32); + + Name name("/P"); + name.appendParametersSha256Digest(digest); + BOOST_CHECK_EQUAL(name.wireEncode(), + "0725 080150 02200000000000000000000000000000000000000000000000000000000000000000"_block); + + name = "/P"; + name.appendParametersSha256Digest(digest->data(), digest->size()); + BOOST_CHECK_EQUAL(name.wireEncode(), + "0725 080150 02200000000000000000000000000000000000000000000000000000000000000000"_block); + + name = "/P"; + name.appendParametersSha256DigestPlaceholder(); + BOOST_CHECK_EQUAL(name.wireEncode(), + "0725 080150 0220E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"_block); +} + +BOOST_AUTO_TEST_CASE(Markers) +{ + // TestNameComponent/NamingConvention provides additional coverage for these methods, + // including verifications of the wire format. + + Name name; + uint64_t number; + + BOOST_REQUIRE_NO_THROW(number = name.appendSegment(30923).at(-1).toSegment()); + BOOST_CHECK_EQUAL(number, 30923); + + BOOST_REQUIRE_NO_THROW(number = name.appendSegmentOffset(589).at(-1).toSegmentOffset()); + BOOST_CHECK_EQUAL(number, 589); + + BOOST_REQUIRE_NO_THROW(number = name.appendVersion().at(-1).toVersion()); + + BOOST_REQUIRE_NO_THROW(number = name.appendVersion(25912).at(-1).toVersion()); + BOOST_CHECK_EQUAL(number, 25912); + + const time::system_clock::TimePoint tp = time::system_clock::now(); + time::system_clock::TimePoint tp2; + BOOST_REQUIRE_NO_THROW(tp2 = name.appendTimestamp(tp).at(-1).toTimestamp()); + BOOST_CHECK_LE(time::abs(tp2 - tp), 1_us); + + BOOST_REQUIRE_NO_THROW(number = name.appendSequenceNumber(11676).at(-1).toSequenceNumber()); + BOOST_CHECK_EQUAL(number, 11676); +} + +BOOST_AUTO_TEST_CASE(EraseComponent) +{ + Name name("/A/B/C"); + BOOST_CHECK_EQUAL(name.wireEncode(), "0709 080141 080142 080143"_block); + BOOST_CHECK_EQUAL(name.hasWire(), true); + + name.erase(1); + BOOST_CHECK_EQUAL(name.size(), 2); + BOOST_CHECK_EQUAL(name.hasWire(), false); + BOOST_CHECK_EQUAL(name.wireEncode(), "0706 080141 080143"_block); + + name.erase(-1); + BOOST_CHECK_EQUAL(name.size(), 1); + BOOST_CHECK_EQUAL(name.hasWire(), false); + BOOST_CHECK_EQUAL(name.wireEncode(), "0703 080141"_block); +} + +BOOST_AUTO_TEST_CASE(Clear) +{ + Name name("/A/B/C"); + BOOST_CHECK_EQUAL(name.empty(), false); + name.clear(); + BOOST_CHECK_EQUAL(name.empty(), true); + BOOST_CHECK(name.begin() == name.end()); +} + +// ---- algorithms ---- + +BOOST_AUTO_TEST_CASE(GetSuccessor) +{ + BOOST_CHECK_EQUAL(Name().getSuccessor(), "/sha256digest=0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(Name("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000").getSuccessor(), + "/sha256digest=0000000000000000000000000000000000000000000000000000000000000001"); + BOOST_CHECK_EQUAL(Name("/sha256digest=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").getSuccessor(), + "/params-sha256=0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(Name("/params-sha256=0000000000000000000000000000000000000000000000000000000000000000").getSuccessor(), + "/params-sha256=0000000000000000000000000000000000000000000000000000000000000001"); + BOOST_CHECK_EQUAL(Name("/params-sha256=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").getSuccessor(), + "/3=..."); + BOOST_CHECK_EQUAL(Name("/P/A").getSuccessor(), "/P/B"); + BOOST_CHECK_EQUAL(Name("/P/AAA").getSuccessor(), "/P/AAB"); + BOOST_CHECK_EQUAL(Name("/Q/...").getSuccessor(), "/Q/%00"); + BOOST_CHECK_EQUAL(Name("/Q/%FF").getSuccessor(), "/Q/%00%00"); + BOOST_CHECK_EQUAL(Name("/Q/%FE%FF").getSuccessor(), "/Q/%FF%00"); + BOOST_CHECK_EQUAL(Name("/Q/%FF%FF").getSuccessor(), "/Q/%00%00%00"); + BOOST_CHECK_EQUAL(Name("/P/3=A").getSuccessor(), "/P/3=B"); + BOOST_CHECK_EQUAL(Name("/P/3=AAA").getSuccessor(), "/P/3=AAB"); + BOOST_CHECK_EQUAL(Name("/Q/3=...").getSuccessor(), "/Q/3=%00"); + BOOST_CHECK_EQUAL(Name("/Q/3=%FF").getSuccessor(), "/Q/3=%00%00"); + BOOST_CHECK_EQUAL(Name("/Q/3=%FE%FF").getSuccessor(), "/Q/3=%FF%00"); + BOOST_CHECK_EQUAL(Name("/Q/3=%FF%FF").getSuccessor(), "/Q/3=%00%00%00"); +} + +BOOST_AUTO_TEST_CASE(IsPrefixOf) +{ + BOOST_CHECK(Name("/").isPrefixOf("/")); + BOOST_CHECK(Name("/").isPrefixOf("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK(Name("/").isPrefixOf("/params-sha256=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); + BOOST_CHECK(Name("/").isPrefixOf("/3=D")); + BOOST_CHECK(Name("/").isPrefixOf("/F")); + BOOST_CHECK(Name("/").isPrefixOf("/21426=AA")); + + BOOST_CHECK(Name("/B").isPrefixOf("/B")); + BOOST_CHECK(Name("/B").isPrefixOf("/B/sha256digest=0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK(Name("/").isPrefixOf("/B/params-sha256=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); + BOOST_CHECK(Name("/B").isPrefixOf("/B/3=D")); + BOOST_CHECK(Name("/B").isPrefixOf("/B/F")); + BOOST_CHECK(Name("/B").isPrefixOf("/B/21426=AA")); + + BOOST_CHECK(!Name("/C").isPrefixOf("/")); + BOOST_CHECK(!Name("/C").isPrefixOf("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK(Name("/").isPrefixOf("/params-sha256=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); + BOOST_CHECK(!Name("/C").isPrefixOf("/3=D")); + BOOST_CHECK(!Name("/C").isPrefixOf("/F")); + BOOST_CHECK(!Name("/C").isPrefixOf("/21426=AA")); +} + +BOOST_AUTO_TEST_CASE(CompareOp) +{ + std::vector names = { + Name("/"), + Name("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000"), + Name("/sha256digest=0000000000000000000000000000000000000000000000000000000000000001"), + Name("/sha256digest=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), + Name("/params-sha256=0000000000000000000000000000000000000000000000000000000000000000"), + Name("/params-sha256=0000000000000000000000000000000000000000000000000000000000000001"), + Name("/params-sha256=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), + Name("/3=..."), + Name("/3=D"), + Name("/3=F"), + Name("/3=AA"), + Name("/..."), + Name("/D"), + Name("/D/sha256digest=0000000000000000000000000000000000000000000000000000000000000000"), + Name("/D/sha256digest=0000000000000000000000000000000000000000000000000000000000000001"), + Name("/D/sha256digest=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), + Name("/D/params-sha256=0000000000000000000000000000000000000000000000000000000000000000"), + Name("/D/params-sha256=0000000000000000000000000000000000000000000000000000000000000001"), + Name("/D/params-sha256=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), + Name("/D/3=..."), + Name("/D/3=D"), + Name("/D/3=F"), + Name("/D/3=AA"), + Name("/D/..."), + Name("/D/D"), + Name("/D/F"), + Name("/D/AA"), + Name("/D/21426=..."), + Name("/D/21426=D"), + Name("/D/21426=F"), + Name("/D/21426=AA"), + Name("/F"), + Name("/AA"), + Name("/21426=..."), + Name("/21426=D"), + Name("/21426=F"), + Name("/21426=AA"), + }; + + for (size_t i = 0; i < names.size(); ++i) { + for (size_t j = 0; j < names.size(); ++j) { + Name lhs = names[i]; + Name rhs = names[j]; + BOOST_CHECK_EQUAL(lhs == rhs, i == j); + BOOST_CHECK_EQUAL(lhs != rhs, i != j); + BOOST_CHECK_EQUAL(lhs < rhs, i < j); + BOOST_CHECK_EQUAL(lhs <= rhs, i <= j); + BOOST_CHECK_EQUAL(lhs > rhs, i > j); + BOOST_CHECK_EQUAL(lhs >= rhs, i >= j); + } + } +} + +BOOST_AUTO_TEST_CASE(CompareFunc) +{ + BOOST_CHECK_EQUAL(Name("/A") .compare(Name("/A")), 0); + BOOST_CHECK_LT (Name("/A") .compare(Name("/B")), 0); + BOOST_CHECK_GT (Name("/B") .compare(Name("/A")), 0); + BOOST_CHECK_LT (Name("/A") .compare(Name("/AA")), 0); + BOOST_CHECK_GT (Name("/AA") .compare(Name("/A")), 0); + BOOST_CHECK_LT (Name("/A") .compare(Name("/A/C")), 0); + BOOST_CHECK_GT (Name("/A/C").compare(Name("/A")), 0); + + BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/A")), 0); + BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/B")), 0); + BOOST_CHECK_GT (Name("/Z/B/Y") .compare(1, 1, Name("/A")), 0); + BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/AA")), 0); + BOOST_CHECK_GT (Name("/Z/AA/Y") .compare(1, 1, Name("/A")), 0); + BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/A/C")), 0); + BOOST_CHECK_GT (Name("/Z/A/C/Y").compare(1, 2, Name("/A")), 0); + + BOOST_CHECK_EQUAL(Name("/Z/A") .compare(1, Name::npos, Name("/A")), 0); + BOOST_CHECK_LT (Name("/Z/A") .compare(1, Name::npos, Name("/B")), 0); + BOOST_CHECK_GT (Name("/Z/B") .compare(1, Name::npos, Name("/A")), 0); + BOOST_CHECK_LT (Name("/Z/A") .compare(1, Name::npos, Name("/AA")), 0); + BOOST_CHECK_GT (Name("/Z/AA") .compare(1, Name::npos, Name("/A")), 0); + BOOST_CHECK_LT (Name("/Z/A") .compare(1, Name::npos, Name("/A/C")), 0); + BOOST_CHECK_GT (Name("/Z/A/C").compare(1, Name::npos, Name("/A")), 0); + + BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/X/A/W"), 1, 1), 0); + BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/B/W"), 1, 1), 0); + BOOST_CHECK_GT (Name("/Z/B/Y") .compare(1, 1, Name("/X/A/W"), 1, 1), 0); + BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/AA/W"), 1, 1), 0); + BOOST_CHECK_GT (Name("/Z/AA/Y") .compare(1, 1, Name("/X/A/W"), 1, 1), 0); + BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/A/C/W"), 1, 2), 0); + BOOST_CHECK_GT (Name("/Z/A/C/Y").compare(1, 2, Name("/X/A/W"), 1, 1), 0); + + BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/X/A"), 1), 0); + BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/B"), 1), 0); + BOOST_CHECK_GT (Name("/Z/B/Y") .compare(1, 1, Name("/X/A"), 1), 0); + BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/AA"), 1), 0); + BOOST_CHECK_GT (Name("/Z/AA/Y") .compare(1, 1, Name("/X/A"), 1), 0); + BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/A/C"), 1), 0); + BOOST_CHECK_GT (Name("/Z/A/C/Y").compare(1, 2, Name("/X/A"), 1), 0); +} + +BOOST_AUTO_TEST_CASE(UnorderedMap) +{ + std::unordered_map map; + Name name1("/1"); + Name name2("/2"); + Name name3("/3"); + map[name1] = 1; + map[name2] = 2; + map[name3] = 3; + + BOOST_CHECK_EQUAL(map[name1], 1); + BOOST_CHECK_EQUAL(map[name2], 2); + BOOST_CHECK_EQUAL(map[name3], 3); +} + +BOOST_AUTO_TEST_SUITE_END() // TestName + +} // namespace tests +} // namespace ndn diff --git a/tests/unit-tests/ndebug.t.cpp b/tests/unit/ndebug.t.cpp similarity index 91% rename from tests/unit-tests/ndebug.t.cpp rename to tests/unit/ndebug.t.cpp index 05f510e60..39dcd8fff 100644 --- a/tests/unit-tests/ndebug.t.cpp +++ b/tests/unit/ndebug.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,9 +19,9 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "common.hpp" +#include "ndn-cxx/detail/common.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace tests { diff --git a/tests/unit/net/collect-netifs.cpp b/tests/unit/net/collect-netifs.cpp new file mode 100644 index 000000000..fe866af8d --- /dev/null +++ b/tests/unit/net/collect-netifs.cpp @@ -0,0 +1,59 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "tests/unit/net/collect-netifs.hpp" +#include "ndn-cxx/net/network-monitor.hpp" + +#include + +namespace ndn { +namespace net { +namespace tests { + +std::vector> +collectNetworkInterfaces(bool allowCached) +{ + static optional>> cached; + + if (!allowCached || !cached) { + boost::asio::io_service io; + NetworkMonitor netmon(io); + + if (netmon.getCapabilities() & NetworkMonitor::CAP_ENUM) { + netmon.onEnumerationCompleted.connect([&io] { io.stop(); }); + io.run(); + io.reset(); + } + cached = netmon.listNetworkInterfaces(); + } + + return *cached; +} + +} // namespace tests +} // namespace net +} // namespace ndn diff --git a/tests/unit/net/collect-netifs.hpp b/tests/unit/net/collect-netifs.hpp new file mode 100644 index 000000000..cc104f641 --- /dev/null +++ b/tests/unit/net/collect-netifs.hpp @@ -0,0 +1,50 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TESTS_UNIT_NET_COLLECT_NETIFS_HPP +#define NDN_TESTS_UNIT_NET_COLLECT_NETIFS_HPP + +#include "ndn-cxx/net/network-interface.hpp" + +#include + +namespace ndn { +namespace net { +namespace tests { + +/** \brief Collect information about network interfaces + * \param allowCached if true, previously collected information can be returned + * \note This function is blocking if \p allowCached is false or no previous information exists + */ +std::vector> +collectNetworkInterfaces(bool allowCached = true); + +} // namespace tests +} // namespace net +} // namespace ndn + +#endif // NDN_TESTS_UNIT_NET_COLLECT_NETIFS_HPP diff --git a/tests/unit/net/dns.t.cpp b/tests/unit/net/dns.t.cpp new file mode 100644 index 000000000..db834c0cf --- /dev/null +++ b/tests/unit/net/dns.t.cpp @@ -0,0 +1,185 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/net/dns.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/net/network-configuration-detector.hpp" + +#include + +namespace ndn { +namespace dns { +namespace tests { + +using boost::asio::ip::address_v4; +using boost::asio::ip::address_v6; + +class DnsFixture +{ +public: + DnsFixture() + : m_nFailures(0) + , m_nSuccesses(0) + { + } + + void + onSuccess(const IpAddress& resolvedAddress, + const IpAddress& expectedAddress, + bool isValid, + bool shouldCheckAddress = false) + { + ++m_nSuccesses; + + if (!isValid) { + BOOST_FAIL("Resolved to " + resolvedAddress.to_string() + ", but should have failed"); + } + + BOOST_CHECK_EQUAL(resolvedAddress.is_v4(), expectedAddress.is_v4()); + + // checking address is not deterministic and should be enabled only + // if only one IP address will be returned by resolution + if (shouldCheckAddress) { + BOOST_CHECK_EQUAL(resolvedAddress, expectedAddress); + } + } + + void + onFailure(bool isValid) + { + ++m_nFailures; + + if (!isValid) { + BOOST_FAIL("Resolution should not have failed"); + } + + BOOST_CHECK_MESSAGE(true, "Resolution failed as expected"); + } + +protected: + uint32_t m_nFailures; + uint32_t m_nSuccesses; + boost::asio::io_service m_ioService; +}; + +BOOST_AUTO_TEST_SUITE(Net) +BOOST_FIXTURE_TEST_SUITE(TestDns, DnsFixture) + +BOOST_AUTO_TEST_CASE(Asynchronous) +{ + SKIP_IF_IP_UNAVAILABLE(); + + asyncResolve("nothost.nothost.nothost.arpa", + bind(&DnsFixture::onSuccess, this, _1, IpAddress(address_v4()), false, false), + bind(&DnsFixture::onFailure, this, true), + m_ioService); // should fail + + m_ioService.run(); + BOOST_CHECK_EQUAL(m_nFailures, 1); + BOOST_CHECK_EQUAL(m_nSuccesses, 0); +} + +BOOST_AUTO_TEST_CASE(AsynchronousV4) +{ + SKIP_IF_IPV4_UNAVAILABLE(); + + asyncResolve("192.0.2.1", + bind(&DnsFixture::onSuccess, this, _1, + IpAddress(address_v4::from_string("192.0.2.1")), true, true), + bind(&DnsFixture::onFailure, this, false), + m_ioService); + + m_ioService.run(); + BOOST_CHECK_EQUAL(m_nFailures, 0); + BOOST_CHECK_EQUAL(m_nSuccesses, 1); +} + +BOOST_AUTO_TEST_CASE(AsynchronousV6) +{ + SKIP_IF_IPV6_UNAVAILABLE(); + + asyncResolve("ipv6.google.com", // only IPv6 address should be available + bind(&DnsFixture::onSuccess, this, _1, IpAddress(address_v6()), true, false), + bind(&DnsFixture::onFailure, this, false), + m_ioService); + + asyncResolve("2001:db8:3f9:0:3025:ccc5:eeeb:86d3", + bind(&DnsFixture::onSuccess, this, _1, + IpAddress(address_v6::from_string("2001:db8:3f9:0:3025:ccc5:eeeb:86d3")), + true, true), + bind(&DnsFixture::onFailure, this, false), + m_ioService); + + m_ioService.run(); + BOOST_CHECK_EQUAL(m_nFailures, 0); + BOOST_CHECK_EQUAL(m_nSuccesses, 2); +} + +BOOST_AUTO_TEST_CASE(AsynchronousV4AndV6) +{ + SKIP_IF_IPV4_UNAVAILABLE(); + SKIP_IF_IPV6_UNAVAILABLE(); + + asyncResolve("www.named-data.net", + bind(&DnsFixture::onSuccess, this, _1, IpAddress(address_v4()), true, false), + bind(&DnsFixture::onFailure, this, false), + m_ioService, Ipv4Only()); + + asyncResolve("a.root-servers.net", + bind(&DnsFixture::onSuccess, this, _1, IpAddress(address_v4()), true, false), + bind(&DnsFixture::onFailure, this, false), + m_ioService, Ipv4Only()); // request IPv4 address + + asyncResolve("a.root-servers.net", + bind(&DnsFixture::onSuccess, this, _1, IpAddress(address_v6()), true, false), + bind(&DnsFixture::onFailure, this, false), + m_ioService, Ipv6Only()); // request IPv6 address + + asyncResolve("ipv6.google.com", // only IPv6 address should be available + bind(&DnsFixture::onSuccess, this, _1, IpAddress(address_v6()), true, false), + bind(&DnsFixture::onFailure, this, false), + m_ioService, Ipv6Only()); + + asyncResolve("ipv6.google.com", // only IPv6 address should be available + bind(&DnsFixture::onSuccess, this, _1, IpAddress(address_v6()), false, false), + bind(&DnsFixture::onFailure, this, true), + m_ioService, Ipv4Only()); // should fail + + m_ioService.run(); + BOOST_CHECK_EQUAL(m_nFailures, 1); + BOOST_CHECK_EQUAL(m_nSuccesses, 4); +} + +BOOST_AUTO_TEST_CASE(Synchronous) +{ + SKIP_IF_IP_UNAVAILABLE(); + + IpAddress address = syncResolve("www.named-data.net", m_ioService); + BOOST_CHECK(address.is_v4() || address.is_v6()); +} + +BOOST_AUTO_TEST_SUITE_END() // TestDns +BOOST_AUTO_TEST_SUITE_END() // Net + +} // namespace tests +} // namespace dns +} // namespace ndn diff --git a/tests/unit-tests/util/ethernet.t.cpp b/tests/unit/net/ethernet.t.cpp similarity index 95% rename from tests/unit-tests/util/ethernet.t.cpp rename to tests/unit/net/ethernet.t.cpp index e8e59e51b..162170b43 100644 --- a/tests/unit-tests/util/ethernet.t.cpp +++ b/tests/unit/net/ethernet.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California, +/* + * Copyright (c) 2014-2018 Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -25,15 +25,14 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "util/ethernet.hpp" +#include "ndn-cxx/net/ethernet.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { -namespace util { namespace tests { -BOOST_AUTO_TEST_SUITE(Util) +BOOST_AUTO_TEST_SUITE(Net) BOOST_AUTO_TEST_SUITE(TestEthernet) BOOST_AUTO_TEST_CASE(Basic) @@ -112,8 +111,7 @@ BOOST_AUTO_TEST_CASE(StdHash) } BOOST_AUTO_TEST_SUITE_END() // TestEthernet -BOOST_AUTO_TEST_SUITE_END() // Util +BOOST_AUTO_TEST_SUITE_END() // Net } // namespace tests -} // namespace util } // namespace ndn diff --git a/tests/unit/net/face-uri.t.cpp b/tests/unit/net/face-uri.t.cpp new file mode 100644 index 000000000..2b99470a4 --- /dev/null +++ b/tests/unit/net/face-uri.t.cpp @@ -0,0 +1,647 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/net/face-uri.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/net/collect-netifs.hpp" +#include "tests/unit/net/network-configuration-detector.hpp" + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Net) +BOOST_AUTO_TEST_SUITE(TestFaceUri) + +class CanonizeFixture : noncopyable +{ +protected: + void + addTest(const std::string& request, bool shouldSucceed, const std::string& expectedUri) + { + ++m_nPending; + auto tc = make_shared(request, shouldSucceed, expectedUri); + + FaceUri uri(request); + uri.canonize(bind(&CanonizeFixture::onCanonizeSuccess, this, tc, _1), + bind(&CanonizeFixture::onCanonizeFailure, this, tc, _1), + m_io, 10_s); + } + + void + runTests() + { + m_io.run(); + BOOST_CHECK_EQUAL(m_nPending, 0); + } + +private: + class CanonizeTestCase + { + public: + CanonizeTestCase(const std::string& request, bool shouldSucceed, const std::string& expectedUri) + : m_expectedUri(expectedUri) + , m_message(request + " should " + (shouldSucceed ? "succeed" : "fail")) + , m_shouldSucceed(shouldSucceed) + , m_isCompleted(false) + { + } + + public: + std::string m_expectedUri; + std::string m_message; + bool m_shouldSucceed; + bool m_isCompleted; + }; + + void + onCanonizeSuccess(const shared_ptr& tc, const FaceUri& canonicalUri) + { + BOOST_CHECK_EQUAL(tc->m_isCompleted, false); + tc->m_isCompleted = true; + --m_nPending; + + BOOST_CHECK_MESSAGE(tc->m_shouldSucceed, tc->m_message); + if (tc->m_shouldSucceed) { + BOOST_CHECK_EQUAL(canonicalUri.toString(), tc->m_expectedUri); + } + } + + void + onCanonizeFailure(const shared_ptr& tc, const std::string& reason) + { + BOOST_CHECK_EQUAL(tc->m_isCompleted, false); + tc->m_isCompleted = true; + --m_nPending; + + BOOST_CHECK_MESSAGE(!tc->m_shouldSucceed, tc->m_message); + } + +private: + boost::asio::io_service m_io; + ssize_t m_nPending = 0; +}; + +BOOST_AUTO_TEST_CASE(ParseInternal) +{ + FaceUri uri; + + BOOST_CHECK(uri.parse("internal://")); + BOOST_CHECK_EQUAL(uri.getScheme(), "internal"); + BOOST_CHECK_EQUAL(uri.getHost(), ""); + BOOST_CHECK_EQUAL(uri.getPort(), ""); + BOOST_CHECK_EQUAL(uri.getPath(), ""); + + BOOST_CHECK_EQUAL(uri.parse("internal:"), false); + BOOST_CHECK_EQUAL(uri.parse("internal:/"), false); +} + +BOOST_AUTO_TEST_CASE(ParseUdp) +{ + FaceUri uri("udp://hostname:6363"); + BOOST_CHECK_THROW(FaceUri("udp//hostname:6363"), FaceUri::Error); + BOOST_CHECK_THROW(FaceUri("udp://hostname:port"), FaceUri::Error); + + BOOST_CHECK_EQUAL(uri.parse("udp//hostname:6363"), false); + + BOOST_CHECK(uri.parse("udp://hostname:80")); + BOOST_CHECK_EQUAL(uri.getScheme(), "udp"); + BOOST_CHECK_EQUAL(uri.getHost(), "hostname"); + BOOST_CHECK_EQUAL(uri.getPort(), "80"); + BOOST_CHECK_EQUAL(uri.getPath(), ""); + + BOOST_CHECK(uri.parse("udp4://192.0.2.1:20")); + BOOST_CHECK_EQUAL(uri.getScheme(), "udp4"); + BOOST_CHECK_EQUAL(uri.getHost(), "192.0.2.1"); + BOOST_CHECK_EQUAL(uri.getPort(), "20"); + BOOST_CHECK_EQUAL(uri.getPath(), ""); + + BOOST_CHECK(uri.parse("udp6://[2001:db8:3f9:0::1]:6363")); + BOOST_CHECK_EQUAL(uri.getScheme(), "udp6"); + BOOST_CHECK_EQUAL(uri.getHost(), "2001:db8:3f9:0::1"); + BOOST_CHECK_EQUAL(uri.getPort(), "6363"); + BOOST_CHECK_EQUAL(uri.getPath(), ""); + + BOOST_CHECK(uri.parse("udp6://[2001:db8:3f9:0:3025:ccc5:eeeb:86d3]:6363")); + BOOST_CHECK_EQUAL(uri.getScheme(), "udp6"); + BOOST_CHECK_EQUAL(uri.getHost(), "2001:db8:3f9:0:3025:ccc5:eeeb:86d3"); + BOOST_CHECK_EQUAL(uri.getPort(), "6363"); + BOOST_CHECK_EQUAL(uri.getPath(), ""); + + BOOST_CHECK_EQUAL(uri.parse("udp6://[2001:db8:3f9:0:3025:ccc5:eeeb:86dg]:6363"), false); + + namespace ip = boost::asio::ip; + + ip::udp::endpoint endpoint4(ip::address_v4::from_string("192.0.2.1"), 7777); + uri = FaceUri(endpoint4); + BOOST_CHECK_EQUAL(uri.toString(), "udp4://192.0.2.1:7777"); + + ip::udp::endpoint endpoint6(ip::address_v6::from_string("2001:DB8::1"), 7777); + uri = FaceUri(endpoint6); + BOOST_CHECK_EQUAL(uri.toString(), "udp6://[2001:db8::1]:7777"); + + BOOST_CHECK(uri.parse("udp6://[fe80::1%25eth1]:6363")); + BOOST_CHECK_EQUAL(uri.getHost(), "fe80::1%25eth1"); + + BOOST_CHECK(uri.parse("udp6://[fe80::1%eth1]:6363")); + BOOST_CHECK_EQUAL(uri.getHost(), "fe80::1%eth1"); + + BOOST_CHECK(uri.parse("udp6://[fe80::1%1]:6363")); + BOOST_CHECK(uri.parse("udp6://[fe80::1%eth1]")); + + BOOST_CHECK(uri.parse("udp6://[ff01::114%eth#1]")); + BOOST_CHECK(uri.parse("udp6://[ff01::114%eth.1,2]")); + BOOST_CHECK(uri.parse("udp6://[ff01::114%a+b-c=0]")); + BOOST_CHECK(uri.parse("udp6://[ff01::114%[foo]]")); + BOOST_CHECK(uri.parse("udp6://[ff01::114%]]")); + BOOST_CHECK(uri.parse("udp6://[ff01::114%%]")); + BOOST_CHECK(!uri.parse("udp6://[ff01::114%]")); + BOOST_CHECK(!uri.parse("udp6://[ff01::114%foo bar]")); + BOOST_CHECK(!uri.parse("udp6://[ff01::114%foo/bar]")); + BOOST_CHECK(!uri.parse("udp6://[ff01::114%eth0:1]")); +} + +BOOST_FIXTURE_TEST_CASE(IsCanonicalUdp, CanonizeFixture) +{ + BOOST_CHECK_EQUAL(FaceUri::canCanonize("udp"), true); + BOOST_CHECK_EQUAL(FaceUri::canCanonize("udp4"), true); + BOOST_CHECK_EQUAL(FaceUri::canCanonize("udp6"), true); + + BOOST_CHECK_EQUAL(FaceUri("udp4://192.0.2.1:6363").isCanonical(), true); + BOOST_CHECK_EQUAL(FaceUri("udp://192.0.2.1:6363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("udp4://192.0.2.1").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("udp4://192.0.2.1:6363/").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("udp6://[2001:db8::1]:6363").isCanonical(), true); + BOOST_CHECK_EQUAL(FaceUri("udp6://[2001:db8::01]:6363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("udp://[2001:db8::1]:6363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("udp://example.net:6363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("udp4://example.net:6363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("udp6://example.net:6363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("udp4://224.0.23.170:56363").isCanonical(), true); + BOOST_CHECK_EQUAL(FaceUri("udp4://[2001:db8::1]:6363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("udp6://192.0.2.1:6363").isCanonical(), false); + + const auto& networkInterfaces = ndn::net::tests::collectNetworkInterfaces(); + if (!networkInterfaces.empty()) { + const auto& netif = networkInterfaces.front(); + auto name = netif->getName(); + auto index = to_string(netif->getIndex()); + + BOOST_CHECK_EQUAL(FaceUri("udp6://[fe80::1%" + name + "]:6363").isCanonical(), true); + BOOST_CHECK_EQUAL(FaceUri("udp6://[fe80::1%" + index + "]:6363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("udp6://[fe80::1%" + name + "]").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("udp6://[fe80::1068:dddb:fe26:fe3f%25en0]:6363").isCanonical(), false); + } +} + +BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(CanonizeUdpV4, 1) +BOOST_FIXTURE_TEST_CASE(CanonizeUdpV4, CanonizeFixture) +{ + SKIP_IF_IPV4_UNAVAILABLE(); + + // IPv4 unicast + addTest("udp4://192.0.2.1:6363", true, "udp4://192.0.2.1:6363"); + addTest("udp://192.0.2.2:6363", true, "udp4://192.0.2.2:6363"); + addTest("udp4://192.0.2.3", true, "udp4://192.0.2.3:6363"); + addTest("udp4://192.0.2.4:6363/", true, "udp4://192.0.2.4:6363"); + addTest("udp4://192.0.2.5:9695", true, "udp4://192.0.2.5:9695"); + addTest("udp4://192.0.2.666:6363", false, ""); + addTest("udp4://192.0.2.7:99999", false, ""); // Bug #3897 + addTest("udp4://google-public-dns-a.google.com", true, "udp4://8.8.8.8:6363"); + addTest("udp4://google-public-dns-a.google.com:70000", false, ""); + addTest("udp4://invalid.invalid", false, ""); + + // IPv4 multicast + addTest("udp4://224.0.23.170:56363", true, "udp4://224.0.23.170:56363"); + addTest("udp4://224.0.23.170", true, "udp4://224.0.23.170:56363"); + addTest("udp4://all-routers.mcast.net:56363", true, "udp4://224.0.0.2:56363"); + + // IPv6 used with udp4 protocol - not canonical + addTest("udp4://[2001:db8::1]:6363", false, ""); + + runTests(); +} + +BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(CanonizeUdpV6, 1) +BOOST_FIXTURE_TEST_CASE(CanonizeUdpV6, CanonizeFixture) +{ + SKIP_IF_IPV6_UNAVAILABLE(); + + // IPv6 unicast + addTest("udp6://[2001:db8::1]:6363", true, "udp6://[2001:db8::1]:6363"); + addTest("udp6://[2001:db8::1]", true, "udp6://[2001:db8::1]:6363"); + addTest("udp://[2001:db8::1]:6363", true, "udp6://[2001:db8::1]:6363"); + addTest("udp6://[2001:db8::01]:6363", true, "udp6://[2001:db8::1]:6363"); + addTest("udp6://[2001::db8::1]:6363", false, ""); + addTest("udp6://[2001:db8::1]:99999", false, ""); // Bug #3897 + addTest("udp6://google-public-dns-a.google.com", true, "udp6://[2001:4860:4860::8888]:6363"); + addTest("udp6://google-public-dns-a.google.com:70000", false, ""); + addTest("udp6://invalid.invalid", false, ""); + addTest("udp://invalid.invalid", false, ""); + + // IPv6 multicast + addTest("udp6://[ff02::2]:56363", true, "udp6://[ff02::2]:56363"); + addTest("udp6://[ff02::2]", true, "udp6://[ff02::2]:56363"); + + // IPv4 used with udp6 protocol - not canonical + addTest("udp6://192.0.2.1:6363", false, ""); + + const auto& networkInterfaces = ndn::net::tests::collectNetworkInterfaces(); + if (!networkInterfaces.empty()) { + const auto& netif = networkInterfaces.front(); + auto name = netif->getName(); + auto index = to_string(netif->getIndex()); + + addTest("udp6://[fe80::1068:dddb:fe26:fe3f%25" + name + "]:6363", true, + "udp6://[fe80::1068:dddb:fe26:fe3f%" + name + "]:6363"); + + addTest("udp6://[fe80::1068:dddb:fe26:fe3f%" + index + "]:6363", true, + "udp6://[fe80::1068:dddb:fe26:fe3f%" + name + "]:6363"); + } + + runTests(); +} + +BOOST_AUTO_TEST_CASE(ParseTcp) +{ + FaceUri uri; + + BOOST_CHECK(uri.parse("tcp://random.host.name")); + BOOST_CHECK_EQUAL(uri.getScheme(), "tcp"); + BOOST_CHECK_EQUAL(uri.getHost(), "random.host.name"); + BOOST_CHECK_EQUAL(uri.getPort(), ""); + BOOST_CHECK_EQUAL(uri.getPath(), ""); + + BOOST_CHECK_EQUAL(uri.parse("tcp://192.0.2.1:"), false); + BOOST_CHECK_EQUAL(uri.parse("tcp://[::zzzz]"), false); + + namespace ip = boost::asio::ip; + + ip::tcp::endpoint endpoint4(ip::address_v4::from_string("192.0.2.1"), 7777); + uri = FaceUri(endpoint4); + BOOST_CHECK_EQUAL(uri.toString(), "tcp4://192.0.2.1:7777"); + + uri = FaceUri(endpoint4, "wsclient"); + BOOST_CHECK_EQUAL(uri.toString(), "wsclient://192.0.2.1:7777"); + + ip::tcp::endpoint endpoint6(ip::address_v6::from_string("2001:DB8::1"), 7777); + uri = FaceUri(endpoint6); + BOOST_CHECK_EQUAL(uri.toString(), "tcp6://[2001:db8::1]:7777"); + + BOOST_CHECK(uri.parse("tcp6://[fe80::1%25eth1]:6363")); + BOOST_CHECK_EQUAL(uri.getHost(), "fe80::1%25eth1"); + + BOOST_CHECK(uri.parse("tcp6://[fe80::1%eth1]:6363")); + BOOST_CHECK_EQUAL(uri.getHost(), "fe80::1%eth1"); + + BOOST_CHECK(uri.parse("tcp6://[fe80::1%1]:6363")); + BOOST_CHECK(uri.parse("tcp6://[fe80::1%eth1]")); +} + +BOOST_FIXTURE_TEST_CASE(IsCanonicalTcp, CanonizeFixture) +{ + BOOST_CHECK_EQUAL(FaceUri::canCanonize("tcp"), true); + BOOST_CHECK_EQUAL(FaceUri::canCanonize("tcp4"), true); + BOOST_CHECK_EQUAL(FaceUri::canCanonize("tcp6"), true); + + BOOST_CHECK_EQUAL(FaceUri("tcp4://192.0.2.1:6363").isCanonical(), true); + BOOST_CHECK_EQUAL(FaceUri("tcp://192.0.2.1:6363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("tcp4://192.0.2.1").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("tcp4://192.0.2.1:6363/").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("tcp6://[2001:db8::1]:6363").isCanonical(), true); + BOOST_CHECK_EQUAL(FaceUri("tcp6://[2001:db8::01]:6363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("tcp://[2001:db8::1]:6363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("tcp://example.net:6363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("tcp4://example.net:6363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("tcp6://example.net:6363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("tcp4://224.0.23.170:56363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("tcp4://[2001:db8::1]:6363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("tcp6://192.0.2.1:6363").isCanonical(), false); + + const auto& networkInterfaces = ndn::net::tests::collectNetworkInterfaces(); + if (!networkInterfaces.empty()) { + const auto& netif = networkInterfaces.front(); + auto name = netif->getName(); + auto index = to_string(netif->getIndex()); + + BOOST_CHECK_EQUAL(FaceUri("tcp6://[fe80::1%" + name + "]:6363").isCanonical(), true); + BOOST_CHECK_EQUAL(FaceUri("tcp6://[fe80::1%" + index + "]:6363").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("tcp6://[fe80::1%" + name + "]").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("tcp6://[fe80::1068:dddb:fe26:fe3f%25en0]:6363").isCanonical(), false); + } +} + +BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(CanonizeTcpV4, 1) +BOOST_FIXTURE_TEST_CASE(CanonizeTcpV4, CanonizeFixture) +{ + SKIP_IF_IPV4_UNAVAILABLE(); + + // IPv4 unicast + addTest("tcp4://192.0.2.1:6363", true, "tcp4://192.0.2.1:6363"); + addTest("tcp://192.0.2.2:6363", true, "tcp4://192.0.2.2:6363"); + addTest("tcp4://192.0.2.3", true, "tcp4://192.0.2.3:6363"); + addTest("tcp4://192.0.2.4:6363/", true, "tcp4://192.0.2.4:6363"); + addTest("tcp4://192.0.2.5:9695", true, "tcp4://192.0.2.5:9695"); + addTest("tcp4://192.0.2.666:6363", false, ""); + addTest("tcp4://192.0.2.7:99999", false, ""); // Bug #3897 + addTest("tcp4://google-public-dns-a.google.com", true, "tcp4://8.8.8.8:6363"); + addTest("tcp4://google-public-dns-a.google.com:70000", false, ""); + addTest("tcp4://invalid.invalid", false, ""); + + // IPv4 multicast + addTest("tcp4://224.0.23.170:56363", false, ""); + addTest("tcp4://224.0.23.170", false, ""); + addTest("tcp4://all-routers.mcast.net:56363", false, ""); + + // IPv6 used with tcp4 protocol - not canonical + addTest("tcp4://[2001:db8::1]:6363", false, ""); + + const auto& networkInterfaces = ndn::net::tests::collectNetworkInterfaces(); + if (!networkInterfaces.empty()) { + const auto& netif = networkInterfaces.front(); + auto name = netif->getName(); + auto index = to_string(netif->getIndex()); + + addTest("tcp6://[fe80::1068:dddb:fe26:fe3f%25" + name + "]:6363", true, + "tcp6://[fe80::1068:dddb:fe26:fe3f%" + name + "]:6363"); + + addTest("tcp6://[fe80::1068:dddb:fe26:fe3f%" + index + "]:6363", true, + "tcp6://[fe80::1068:dddb:fe26:fe3f%" + name + "]:6363"); + } + + runTests(); +} + +BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(CanonizeTcpV6, 1) +BOOST_FIXTURE_TEST_CASE(CanonizeTcpV6, CanonizeFixture) +{ + SKIP_IF_IPV6_UNAVAILABLE(); + + // IPv6 unicast + addTest("tcp6://[2001:db8::1]:6363", true, "tcp6://[2001:db8::1]:6363"); + addTest("tcp6://[2001:db8::1]", true, "tcp6://[2001:db8::1]:6363"); + addTest("tcp://[2001:db8::1]:6363", true, "tcp6://[2001:db8::1]:6363"); + addTest("tcp6://[2001:db8::01]:6363", true, "tcp6://[2001:db8::1]:6363"); + addTest("tcp6://[2001::db8::1]:6363", false, ""); + addTest("tcp6://[2001:db8::1]:99999", false, ""); // Bug #3897 + addTest("tcp6://google-public-dns-a.google.com", true, "tcp6://[2001:4860:4860::8888]:6363"); + addTest("tcp6://google-public-dns-a.google.com:70000", false, ""); + addTest("tcp6://invalid.invalid", false, ""); + addTest("tcp://invalid.invalid", false, ""); + + // IPv6 multicast + addTest("tcp6://[ff02::2]:56363", false, ""); + addTest("tcp6://[ff02::2]", false, ""); + + // IPv4 used with tcp6 protocol - not canonical + addTest("tcp6://192.0.2.1:6363", false, ""); + + runTests(); +} + +BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(ParseUnix, 1) +BOOST_AUTO_TEST_CASE(ParseUnix) +{ + FaceUri uri; + + BOOST_CHECK(uri.parse("unix:///var/run/example.sock")); + BOOST_CHECK_EQUAL(uri.getScheme(), "unix"); + BOOST_CHECK_EQUAL(uri.getHost(), ""); + BOOST_CHECK_EQUAL(uri.getPort(), ""); + BOOST_CHECK_EQUAL(uri.getPath(), "/var/run/example.sock"); + + // This is not a valid unix:// URI, but the parse would treat "var" as host + BOOST_CHECK_EQUAL(uri.parse("unix://var/run/example.sock"), false); // Bug #3896 + +#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS + using boost::asio::local::stream_protocol; + stream_protocol::endpoint endpoint("/var/run/example.sock"); + uri = FaceUri(endpoint); + BOOST_CHECK_EQUAL(uri.toString(), "unix:///var/run/example.sock"); +#endif // BOOST_ASIO_HAS_LOCAL_SOCKETS +} + +BOOST_AUTO_TEST_CASE(ParseFd) +{ + FaceUri uri; + + BOOST_CHECK(uri.parse("fd://6")); + BOOST_CHECK_EQUAL(uri.getScheme(), "fd"); + BOOST_CHECK_EQUAL(uri.getHost(), "6"); + BOOST_CHECK_EQUAL(uri.getPort(), ""); + BOOST_CHECK_EQUAL(uri.getPath(), ""); + + int fd = 21; + uri = FaceUri::fromFd(fd); + BOOST_CHECK_EQUAL(uri.toString(), "fd://21"); +} + +BOOST_AUTO_TEST_CASE(ParseEther) +{ + FaceUri uri; + + BOOST_CHECK(uri.parse("ether://[08:00:27:01:dd:01]")); + BOOST_CHECK_EQUAL(uri.getScheme(), "ether"); + BOOST_CHECK_EQUAL(uri.getHost(), "08:00:27:01:dd:01"); + BOOST_CHECK_EQUAL(uri.getPort(), ""); + BOOST_CHECK_EQUAL(uri.getPath(), ""); + + BOOST_CHECK_EQUAL(uri.parse("ether://[08:00:27:zz:dd:01]"), false); + + auto address = ethernet::Address::fromString("33:33:01:01:01:01"); + uri = FaceUri(address); + BOOST_CHECK_EQUAL(uri.toString(), "ether://[33:33:01:01:01:01]"); +} + +BOOST_FIXTURE_TEST_CASE(CanonizeEther, CanonizeFixture) +{ + BOOST_CHECK_EQUAL(FaceUri::canCanonize("ether"), true); + + BOOST_CHECK_EQUAL(FaceUri("ether://[08:00:27:01:01:01]").isCanonical(), true); + BOOST_CHECK_EQUAL(FaceUri("ether://[08:00:27:1:1:1]").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("ether://[08:00:27:01:01:01]/").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("ether://[33:33:01:01:01:01]").isCanonical(), true); + + addTest("ether://[08:00:27:01:01:01]", true, "ether://[08:00:27:01:01:01]"); + addTest("ether://[08:00:27:1:1:1]", true, "ether://[08:00:27:01:01:01]"); + addTest("ether://[08:00:27:01:01:01]/", true, "ether://[08:00:27:01:01:01]"); + addTest("ether://[33:33:01:01:01:01]", true, "ether://[33:33:01:01:01:01]"); + + runTests(); +} + +BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(ParseDev, 1) +BOOST_AUTO_TEST_CASE(ParseDev) +{ + FaceUri uri; + + BOOST_CHECK(uri.parse("dev://eth0")); + BOOST_CHECK_EQUAL(uri.getScheme(), "dev"); + BOOST_CHECK_EQUAL(uri.getHost(), "eth0"); + BOOST_CHECK_EQUAL(uri.getPort(), ""); + BOOST_CHECK_EQUAL(uri.getPath(), ""); + + BOOST_CHECK_EQUAL(uri.parse("dev://eth0:8888"), false); // Bug #3896 + + std::string ifname = "en1"; + uri = FaceUri::fromDev(ifname); + BOOST_CHECK_EQUAL(uri.toString(), "dev://en1"); +} + +BOOST_AUTO_TEST_CASE(IsCanonicalDev) +{ + BOOST_CHECK_EQUAL(FaceUri::canCanonize("dev"), true); + + BOOST_CHECK_EQUAL(FaceUri("dev://eth0").isCanonical(), true); + BOOST_CHECK_EQUAL(FaceUri("dev://").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("dev://eth0:8888").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("dev://eth0/").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("dev://eth0/A").isCanonical(), false); +} + +BOOST_FIXTURE_TEST_CASE(CanonizeDev, CanonizeFixture) +{ + addTest("dev://eth0", true, "dev://eth0"); + addTest("dev://", false, ""); + addTest("dev://eth0:8888", false, ""); + addTest("dev://eth0/", true, "dev://eth0"); + addTest("dev://eth0/A", false, ""); + + runTests(); +} + +BOOST_AUTO_TEST_CASE(ParseUdpDev) +{ + FaceUri uri; + + BOOST_CHECK(uri.parse("udp4+dev://eth0:7777")); + BOOST_CHECK_EQUAL(uri.getScheme(), "udp4+dev"); + BOOST_CHECK_EQUAL(uri.getHost(), "eth0"); + BOOST_CHECK_EQUAL(uri.getPort(), "7777"); + BOOST_CHECK_EQUAL(uri.getPath(), ""); + + BOOST_CHECK(uri.parse("udp6+dev://eth1:7777")); + BOOST_CHECK_EQUAL(uri.getScheme(), "udp6+dev"); + BOOST_CHECK_EQUAL(uri.getHost(), "eth1"); + BOOST_CHECK_EQUAL(uri.getPort(), "7777"); + BOOST_CHECK_EQUAL(uri.getPath(), ""); + + BOOST_CHECK(uri.parse("abc+efg://eth0")); + BOOST_CHECK(!uri.parse("abc+://eth0")); + BOOST_CHECK(!uri.parse("+abc://eth0")); + + namespace ip = boost::asio::ip; + + ip::udp::endpoint endpoint4(ip::udp::v4(), 7777); + uri = FaceUri::fromUdpDev(endpoint4, "en1"); + BOOST_CHECK_EQUAL(uri.toString(), "udp4+dev://en1:7777"); + + ip::udp::endpoint endpoint6(ip::udp::v6(), 7777); + uri = FaceUri::fromUdpDev(endpoint6, "en2"); + BOOST_CHECK_EQUAL(uri.toString(), "udp6+dev://en2:7777"); +} + +BOOST_FIXTURE_TEST_CASE(CanonizeUdpDev, CanonizeFixture) +{ + BOOST_CHECK_EQUAL(FaceUri("udp4+dev://eth0:7777").isCanonical(), true); + BOOST_CHECK_EQUAL(FaceUri("udp6+dev://eth1:7777").isCanonical(), true); + BOOST_CHECK_EQUAL(FaceUri("udp+dev://eth1:7777").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("udp6+dev://eth1").isCanonical(), false); + + addTest("udp4+dev://en0:7777", true, "udp4+dev://en0:7777"); + addTest("udp6+dev://en0:7777", true, "udp6+dev://en0:7777"); + addTest("udp+dev://en1:7777", false, ""); + addTest("udp6+dev://en2", false, ""); +} + +BOOST_AUTO_TEST_CASE(CanonizeEmptyCallback) +{ + boost::asio::io_service io; + + // unsupported scheme + FaceUri("null://").canonize(FaceUri::CanonizeSuccessCallback(), + FaceUri::CanonizeFailureCallback(), + io, 1_ms); + + // cannot resolve + FaceUri("udp://192.0.2.333").canonize(FaceUri::CanonizeSuccessCallback(), + FaceUri::CanonizeFailureCallback(), + io, 1_ms); + + // already canonical + FaceUri("udp4://192.0.2.1:6363").canonize(FaceUri::CanonizeSuccessCallback(), + FaceUri::CanonizeFailureCallback(), + io, 1_ms); + + // need DNS resolution + FaceUri("udp://192.0.2.1:6363").canonize(FaceUri::CanonizeSuccessCallback(), + FaceUri::CanonizeFailureCallback(), + io, 1_ms); + + io.run(); // should not crash + + // avoid "test case [...] did not check any assertions" message from Boost.Test + BOOST_CHECK(true); +} + +BOOST_FIXTURE_TEST_CASE(CanonizeUnsupported, CanonizeFixture) +{ + BOOST_CHECK_EQUAL(FaceUri::canCanonize("internal"), false); + BOOST_CHECK_EQUAL(FaceUri::canCanonize("null"), false); + BOOST_CHECK_EQUAL(FaceUri::canCanonize("unix"), false); + BOOST_CHECK_EQUAL(FaceUri::canCanonize("fd"), false); + + BOOST_CHECK_EQUAL(FaceUri("internal://").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("null://").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("unix:///var/run/nfd.sock").isCanonical(), false); + BOOST_CHECK_EQUAL(FaceUri("fd://0").isCanonical(), false); + + addTest("internal://", false, ""); + addTest("null://", false, ""); + addTest("unix:///var/run/nfd.sock", false, ""); + addTest("fd://0", false, ""); + + runTests(); +} + +BOOST_AUTO_TEST_CASE(Bug1635) +{ + FaceUri uri; + + BOOST_CHECK(uri.parse("wsclient://[::ffff:76.90.11.239]:56366")); + BOOST_CHECK_EQUAL(uri.getScheme(), "wsclient"); + BOOST_CHECK_EQUAL(uri.getHost(), "76.90.11.239"); + BOOST_CHECK_EQUAL(uri.getPort(), "56366"); + BOOST_CHECK_EQUAL(uri.getPath(), ""); + BOOST_CHECK_EQUAL(uri.toString(), "wsclient://76.90.11.239:56366"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestFaceUri +BOOST_AUTO_TEST_SUITE_END() // Net + +} // namespace tests +} // namespace ndn diff --git a/tests/unit-tests/network-configuration-detector.cpp b/tests/unit/net/network-configuration-detector.cpp similarity index 94% rename from tests/unit-tests/network-configuration-detector.cpp rename to tests/unit/net/network-configuration-detector.cpp index f00b3e81c..84e124440 100644 --- a/tests/unit-tests/network-configuration-detector.cpp +++ b/tests/unit/net/network-configuration-detector.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,12 +19,12 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "network-configuration-detector.hpp" +#include "tests/unit/net/network-configuration-detector.hpp" +#include #include -#include #include -#include +#include #include namespace ndn { diff --git a/tests/unit/net/network-configuration-detector.hpp b/tests/unit/net/network-configuration-detector.hpp new file mode 100644 index 000000000..015b2b8d4 --- /dev/null +++ b/tests/unit/net/network-configuration-detector.hpp @@ -0,0 +1,75 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TESTS_UNIT_NET_NETWORK_CONFIGURATION_DETECTOR_HPP +#define NDN_TESTS_UNIT_NET_NETWORK_CONFIGURATION_DETECTOR_HPP + +#define SKIP_IF_IPV4_UNAVAILABLE() \ + do { \ + if (!::ndn::tests::NetworkConfigurationDetector::hasIpv4()) { \ + BOOST_WARN_MESSAGE(false, "skipping assertions that require IPv4 support"); \ + return; \ + } \ + } while (false) + +#define SKIP_IF_IPV6_UNAVAILABLE() \ + do { \ + if (!::ndn::tests::NetworkConfigurationDetector::hasIpv6()) { \ + BOOST_WARN_MESSAGE(false, "skipping assertions that require IPv6 support"); \ + return; \ + } \ + } while (false) + +#define SKIP_IF_IP_UNAVAILABLE() \ + do { \ + if (!::ndn::tests::NetworkConfigurationDetector::hasIpv4() && \ + !::ndn::tests::NetworkConfigurationDetector::hasIpv6()) { \ + BOOST_WARN_MESSAGE(false, "skipping assertions that require either IPv4 or IPv6 support"); \ + return; \ + } \ + } while (false) + +namespace ndn { +namespace tests { + +class NetworkConfigurationDetector +{ +public: + static bool + hasIpv4(); + + static bool + hasIpv6(); + +private: + static void + detect(); + +private: + static bool m_isInitialized; + static bool m_hasIpv4; + static bool m_hasIpv6; +}; + +} // namespace tests +} // namespace ndn + +#endif // NDN_TESTS_UNIT_NET_NETWORK_CONFIGURATION_DETECTOR_HPP diff --git a/tests/unit/net/network-monitor-stub.t.cpp b/tests/unit/net/network-monitor-stub.t.cpp new file mode 100644 index 000000000..453a510fd --- /dev/null +++ b/tests/unit/net/network-monitor-stub.t.cpp @@ -0,0 +1,125 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/net/network-monitor-stub.hpp" + +#include "tests/boost-test.hpp" + +namespace ndn { +namespace net { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Net) +BOOST_AUTO_TEST_SUITE(TestNetworkMonitorStub) + +BOOST_AUTO_TEST_CASE(Capabilities) +{ + NetworkMonitorStub stub(NetworkMonitor::CAP_ENUM | NetworkMonitor::CAP_IF_ADD_REMOVE); + BOOST_CHECK_EQUAL(stub.getCapabilities(), + NetworkMonitor::CAP_ENUM | NetworkMonitor::CAP_IF_ADD_REMOVE); +} + +class StubFixture +{ +public: + StubFixture() + : stub(~0) + { + stub.onEnumerationCompleted.connect([this] { signals.push_back("EnumerationCompleted"); }); + stub.onInterfaceAdded.connect([this] (shared_ptr netif) { + signals.push_back("InterfaceAdded " + netif->getName()); }); + stub.onInterfaceRemoved.connect([this] (shared_ptr netif) { + signals.push_back("InterfaceRemoved " + netif->getName()); }); + } + +public: + NetworkMonitorStub stub; + std::vector signals; +}; + +BOOST_FIXTURE_TEST_CASE(AddInterface, StubFixture) +{ + BOOST_CHECK_EQUAL(stub.listNetworkInterfaces().size(), 0); + BOOST_CHECK(stub.getNetworkInterface("eth1") == nullptr); + + shared_ptr if1 = stub.makeNetworkInterface(); + if1->setIndex(13697); + if1->setName("eth1"); + stub.addInterface(if1); + if1.reset(); + BOOST_REQUIRE(stub.getNetworkInterface("eth1") != nullptr); + BOOST_CHECK_EQUAL(stub.getNetworkInterface("eth1")->getIndex(), 13697); + BOOST_CHECK_EQUAL(stub.listNetworkInterfaces().at(0)->getIndex(), 13697); + BOOST_REQUIRE_EQUAL(signals.size(), 1); + BOOST_CHECK_EQUAL(signals.back(), "InterfaceAdded eth1"); + + shared_ptr if1b = stub.makeNetworkInterface(); + if1b->setIndex(3280); + if1b->setName("eth1"); + BOOST_CHECK_THROW(stub.addInterface(if1b), std::invalid_argument); + BOOST_CHECK(stub.getNetworkInterface("eth1") != nullptr); + BOOST_CHECK_EQUAL(stub.getNetworkInterface("eth1")->getIndex(), 13697); + BOOST_CHECK_EQUAL(stub.listNetworkInterfaces().at(0)->getIndex(), 13697); + BOOST_CHECK_EQUAL(signals.size(), 1); + + stub.emitEnumerationCompleted(); + BOOST_REQUIRE_EQUAL(signals.size(), 2); + BOOST_CHECK_EQUAL(signals.back(), "EnumerationCompleted"); + + shared_ptr if2 = stub.makeNetworkInterface(); + if2->setIndex(19243); + if2->setName("eth2"); + stub.addInterface(if2); + if2.reset(); + BOOST_REQUIRE(stub.getNetworkInterface("eth2") != nullptr); + BOOST_CHECK_EQUAL(stub.getNetworkInterface("eth2")->getIndex(), 19243); + BOOST_CHECK_EQUAL(stub.listNetworkInterfaces().size(), 2); + BOOST_REQUIRE_EQUAL(signals.size(), 3); + BOOST_CHECK_EQUAL(signals.back(), "InterfaceAdded eth2"); +} + +BOOST_FIXTURE_TEST_CASE(RemoveInterface, StubFixture) +{ + shared_ptr if1 = stub.makeNetworkInterface(); + if1->setIndex(13697); + if1->setName("eth1"); + stub.addInterface(if1); + + stub.emitEnumerationCompleted(); + BOOST_REQUIRE_EQUAL(signals.size(), 2); + BOOST_CHECK_EQUAL(signals.back(), "EnumerationCompleted"); + + stub.removeInterface("eth1"); + BOOST_CHECK(stub.getNetworkInterface("eth1") == nullptr); + BOOST_CHECK_EQUAL(stub.listNetworkInterfaces().size(), 0); + BOOST_REQUIRE_EQUAL(signals.size(), 3); + BOOST_CHECK_EQUAL(signals.back(), "InterfaceRemoved eth1"); + + stub.removeInterface("eth2"); // non-existent + BOOST_CHECK_EQUAL(signals.size(), 3); +} + +BOOST_AUTO_TEST_SUITE_END() // TestNetworkMonitorStub +BOOST_AUTO_TEST_SUITE_END() // Net + +} // namespace tests +} // namespace net +} // namespace ndn diff --git a/tests/unit/net/network-monitor.t.cpp b/tests/unit/net/network-monitor.t.cpp new file mode 100644 index 000000000..132d0db99 --- /dev/null +++ b/tests/unit/net/network-monitor.t.cpp @@ -0,0 +1,74 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/net/network-monitor.hpp" + +#include "tests/boost-test.hpp" + +#include + +namespace ndn { +namespace net { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Net) +BOOST_AUTO_TEST_SUITE(TestNetworkMonitor) + +#define NM_REQUIRE_CAP(capability) \ + do { \ + if ((nm->getCapabilities() & NetworkMonitor::CAP_ ## capability) == 0) { \ + BOOST_WARN_MESSAGE(false, "skipping assertions that require " #capability " capability"); \ + return; \ + } \ + } while (false) + +BOOST_AUTO_TEST_CASE(DestructWithoutRun) +{ + boost::asio::io_service io; + auto nm = make_unique(io); + nm.reset(); + BOOST_CHECK(true); // if we got this far, the test passed +} + +BOOST_AUTO_TEST_CASE(DestructWhileEnumerating) +{ + boost::asio::io_service io; + auto nm = make_unique(io); + NM_REQUIRE_CAP(ENUM); + + nm->onInterfaceAdded.connect([&] (const shared_ptr&) { + io.post([&] { nm.reset(); }); + }); + nm->onEnumerationCompleted.connect([&] { + // make sure the test case terminates even if we have zero interfaces + io.post([&] { nm.reset(); }); + }); + + io.run(); + BOOST_CHECK(true); // if we got this far, the test passed +} + +BOOST_AUTO_TEST_SUITE_END() // TestNetworkMonitor +BOOST_AUTO_TEST_SUITE_END() // Net + +} // namespace tests +} // namespace net +} // namespace ndn diff --git a/tests/unit/prefix-announcement.t.cpp b/tests/unit/prefix-announcement.t.cpp new file mode 100644 index 000000000..31449e4e0 --- /dev/null +++ b/tests/unit/prefix-announcement.t.cpp @@ -0,0 +1,247 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/prefix-announcement.hpp" +#include "ndn-cxx/encoding/tlv-nfd.hpp" + +#include "tests/boost-test.hpp" +#include "tests/identity-management-fixture.hpp" +#include "tests/make-interest-data.hpp" + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(TestPrefixAnnouncement) + +static Data +makePrefixAnnData() +{ + return Data( + "067A 071A announced-name=/net/example 08036E6574 08076578616D706C65" + " keyword-prefix-ann=20025041 version=0802FD01 segment=08020000" + " 1403 content-type=prefix-ann 180105" + " 1530 expire in one hour 6D040036EE80" + " validity FD00FD26 FD00FE0F323031383130333054303030303030" + " FD00FF0F323031383131323454323335393539" + " 1603 1B0100 signature" + " 1720 0000000000000000000000000000000000000000000000000000000000000000"_block); +} + +BOOST_AUTO_TEST_CASE(DecodeGood) +{ + Data data0 = makePrefixAnnData(); + PrefixAnnouncement pa0(data0); + BOOST_CHECK_EQUAL(pa0.getAnnouncedName(), "/net/example"); + BOOST_CHECK_EQUAL(pa0.getExpiration(), 1_h); + BOOST_CHECK(pa0.getValidityPeriod()); + BOOST_CHECK_EQUAL(*pa0.getValidityPeriod(), + security::ValidityPeriod(time::fromIsoString("20181030T000000"), + time::fromIsoString("20181124T235959"))); + + // reorder ExpirationPeriod and ValidityPeriod, unrecognized non-critical element + Data data1 = makePrefixAnnData(); + Block payload1 = data1.getContent(); + payload1.parse(); + Block expirationElement = payload1.get(tlv::nfd::ExpirationPeriod); + payload1.remove(tlv::nfd::ExpirationPeriod); + payload1.push_back(expirationElement); + payload1.push_back("2000"_block); + payload1.encode(); + data1.setContent(payload1); + PrefixAnnouncement pa1(data1); + BOOST_CHECK_EQUAL(pa1.getAnnouncedName(), "/net/example"); + BOOST_CHECK_EQUAL(pa1.getExpiration(), 1_h); + BOOST_CHECK(pa1.getValidityPeriod()); + BOOST_CHECK_EQUAL(*pa1.getValidityPeriod(), + security::ValidityPeriod(time::fromIsoString("20181030T000000"), + time::fromIsoString("20181124T235959"))); + + // no ValidityPeriod + Data data2 = makePrefixAnnData(); + Block payload2 = data2.getContent(); + payload2.parse(); + payload2.remove(tlv::ValidityPeriod); + payload2.encode(); + data2.setContent(payload2); + PrefixAnnouncement pa2(data2); + BOOST_CHECK_EQUAL(pa2.getAnnouncedName(), "/net/example"); + BOOST_CHECK_EQUAL(pa2.getExpiration(), 1_h); + BOOST_CHECK(!pa2.getValidityPeriod()); +} + +BOOST_AUTO_TEST_CASE(DecodeBad) +{ + // wrong ContentType + Data data0 = makePrefixAnnData(); + data0.setContentType(tlv::ContentType_Blob); + BOOST_CHECK_THROW(PrefixAnnouncement pa0(data0), tlv::Error); + + // Name has no "32=PA" keyword + Data data1 = makePrefixAnnData(); + setNameComponent(data1, -3, name::Component::fromEscapedString("32=not-PA")); + BOOST_CHECK_THROW(PrefixAnnouncement pa1(data1), tlv::Error); + + // Name has no version component + Data data2 = makePrefixAnnData(); + setNameComponent(data2, -2, "not-version"); + BOOST_CHECK_THROW(PrefixAnnouncement pa2(data2), tlv::Error); + + // Name has no segment number component + Data data3 = makePrefixAnnData(); + setNameComponent(data3, -2, "not-segment"); + BOOST_CHECK_THROW(PrefixAnnouncement pa3(data3), tlv::Error); + + // Content has no ExpirationPeriod element + Data data4 = makePrefixAnnData(); + Block payload4 = data4.getContent(); + payload4.parse(); + payload4.remove(tlv::nfd::ExpirationPeriod); + payload4.encode(); + data4.setContent(payload4); + BOOST_CHECK_THROW(PrefixAnnouncement pa4(data4), tlv::Error); + + // ExpirationPeriod is malformed + Data data5 = makePrefixAnnData(); + Block payload5 = data5.getContent(); + payload5.parse(); + payload5.remove(tlv::nfd::ExpirationPeriod); + payload5.push_back("6D03010101"_block); + payload5.encode(); + data5.setContent(payload5); + BOOST_CHECK_THROW(PrefixAnnouncement pa5(data5), tlv::Error); + + // ValidityPeriod is malformed + Data data6 = makePrefixAnnData(); + Block payload6 = data6.getContent(); + payload6.parse(); + payload6.remove(tlv::ValidityPeriod); + payload6.push_back("FD00FD00"_block); + payload6.encode(); + data6.setContent(payload6); + BOOST_CHECK_THROW(PrefixAnnouncement pa6(data6), tlv::Error); + + // Content has unrecognized critical element + Data data7 = makePrefixAnnData(); + Block payload7 = data7.getContent(); + payload7.parse(); + payload7.push_back("0200"_block); + payload7.encode(); + data7.setContent(payload7); + BOOST_CHECK_THROW(PrefixAnnouncement pa7(data7), tlv::Error); +} + +BOOST_FIXTURE_TEST_CASE(EncodeEmpty, IdentityManagementFixture) +{ + PrefixAnnouncement pa; + BOOST_CHECK(!pa.getData()); + BOOST_CHECK_EQUAL(pa.getAnnouncedName(), "/"); + BOOST_CHECK_EQUAL(pa.getExpiration(), 0_ms); + BOOST_CHECK(!pa.getValidityPeriod()); + + const Data& data = pa.toData(m_keyChain, signingWithSha256(), 5); + BOOST_CHECK_EQUAL(data.getName(), "/32=PA/%FD%05/%00%00"); + BOOST_CHECK_EQUAL(data.getContentType(), tlv::ContentType_PrefixAnn); + BOOST_REQUIRE(pa.getData()); + BOOST_CHECK_EQUAL(*pa.getData(), data); + + PrefixAnnouncement decoded(data); + BOOST_CHECK_EQUAL(decoded.getAnnouncedName(), "/"); + BOOST_CHECK_EQUAL(decoded.getExpiration(), 0_s); + BOOST_CHECK(!decoded.getValidityPeriod()); + + BOOST_CHECK_EQUAL(pa, decoded); +} + +BOOST_FIXTURE_TEST_CASE(EncodeNoValidity, IdentityManagementFixture) +{ + PrefixAnnouncement pa; + pa.setAnnouncedName("/net/example"); + BOOST_CHECK_THROW(pa.setExpiration(-1_ms), std::invalid_argument); + pa.setExpiration(1_h); + + const Data& data = pa.toData(m_keyChain, signingWithSha256(), 1); + BOOST_CHECK_EQUAL(data.getName(), "/net/example/32=PA/%FD%01/%00%00"); + BOOST_CHECK_EQUAL(data.getContentType(), tlv::ContentType_PrefixAnn); + + const Block& payload = data.getContent(); + payload.parse(); + BOOST_CHECK_EQUAL(readNonNegativeInteger(payload.get(tlv::nfd::ExpirationPeriod)), 3600000); + BOOST_CHECK(payload.find(tlv::ValidityPeriod) == payload.elements_end()); + + PrefixAnnouncement decoded(data); + BOOST_CHECK_EQUAL(decoded.getAnnouncedName(), "/net/example"); + BOOST_CHECK_EQUAL(decoded.getExpiration(), 1_h); + BOOST_CHECK(!decoded.getValidityPeriod()); + + BOOST_CHECK_EQUAL(pa, decoded); +} + +BOOST_FIXTURE_TEST_CASE(EncodeWithValidity, IdentityManagementFixture) +{ + PrefixAnnouncement pa; + pa.setAnnouncedName("/net/example"); + pa.setExpiration(1_h); + security::ValidityPeriod validity(time::fromIsoString("20181030T000000"), + time::fromIsoString("20181124T235959")); + pa.setValidityPeriod(validity); + + const Data& data = pa.toData(m_keyChain); + const Block& payload = data.getContent(); + payload.parse(); + BOOST_CHECK_EQUAL(readNonNegativeInteger(payload.get(tlv::nfd::ExpirationPeriod)), 3600000); + BOOST_CHECK_EQUAL(payload.get(tlv::ValidityPeriod), validity.wireEncode()); + + PrefixAnnouncement decoded(data); + BOOST_CHECK_EQUAL(decoded.getAnnouncedName(), "/net/example"); + BOOST_CHECK_EQUAL(decoded.getExpiration(), 1_h); + BOOST_REQUIRE(decoded.getValidityPeriod()); + BOOST_CHECK_EQUAL(*decoded.getValidityPeriod(), validity); + + BOOST_CHECK_EQUAL(pa, decoded); +} + +BOOST_AUTO_TEST_CASE(Modify) +{ + PrefixAnnouncement pa(makePrefixAnnData()); + + PrefixAnnouncement pa0(pa); + BOOST_REQUIRE(pa0.getData()); + BOOST_CHECK_EQUAL(*pa0.getData(), makePrefixAnnData()); + pa0.setAnnouncedName("/com/example"); + BOOST_CHECK(!pa0.getData()); + BOOST_CHECK_NE(pa0, pa); + + PrefixAnnouncement pa1(makePrefixAnnData()); + pa1.setExpiration(5_min); + BOOST_CHECK(!pa1.getData()); + BOOST_CHECK_NE(pa1, pa); + + PrefixAnnouncement pa2(makePrefixAnnData()); + pa2.setValidityPeriod(security::ValidityPeriod(time::fromIsoString("20180118T000000"), + time::fromIsoString("20180212T235959"))); + BOOST_CHECK(!pa2.getData()); + BOOST_CHECK_NE(pa2, pa); +} + +BOOST_AUTO_TEST_SUITE_END() // TestPrefixAnnouncement + +} // namespace tests +} // namespace ndn diff --git a/tests/unit/security/command-interest-signer.t.cpp b/tests/unit/security/command-interest-signer.t.cpp new file mode 100644 index 000000000..fe85ba8d8 --- /dev/null +++ b/tests/unit/security/command-interest-signer.t.cpp @@ -0,0 +1,69 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/command-interest-signer.hpp" +#include "ndn-cxx/security/signing-helpers.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/identity-management-time-fixture.hpp" + +namespace ndn { +namespace security { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_FIXTURE_TEST_SUITE(TestCommandInterestSigner, IdentityManagementTimeFixture) + +BOOST_AUTO_TEST_CASE(Basic) +{ + addIdentity("/test"); + + CommandInterestSigner signer(m_keyChain); + Interest i1 = signer.makeCommandInterest("/hello/world"); + BOOST_CHECK_EQUAL(i1.getName().size(), 6); + BOOST_CHECK_EQUAL(i1.getName().at(command_interest::POS_SIG_VALUE).blockFromValue().type(), tlv::SignatureValue); + BOOST_CHECK_EQUAL(i1.getName().at(command_interest::POS_SIG_INFO).blockFromValue().type(), tlv::SignatureInfo); + + time::milliseconds timestamp = toUnixTimestamp(time::system_clock::now()); + BOOST_CHECK_EQUAL(i1.getName().at(command_interest::POS_TIMESTAMP).toNumber(), timestamp.count()); + + Interest i2 = signer.makeCommandInterest("/hello/world/!", signingByIdentity("/test")); + BOOST_CHECK_EQUAL(i2.getName().size(), 7); + BOOST_CHECK_EQUAL(i2.getName().at(command_interest::POS_SIG_VALUE).blockFromValue().type(), tlv::SignatureValue); + BOOST_CHECK_EQUAL(i2.getName().at(command_interest::POS_SIG_INFO).blockFromValue().type(), tlv::SignatureInfo); + BOOST_CHECK_GT(i2.getName().at(command_interest::POS_TIMESTAMP), i1.getName().at(command_interest::POS_TIMESTAMP)); + BOOST_CHECK_NE(i2.getName().at(command_interest::POS_RANDOM_VAL), + i1.getName().at(command_interest::POS_RANDOM_VAL)); // this sometimes can fail + + advanceClocks(100_s); + + i2 = signer.makeCommandInterest("/hello/world/!"); + BOOST_CHECK_GT(i2.getName().at(command_interest::POS_TIMESTAMP), i1.getName().at(command_interest::POS_TIMESTAMP)); +} + +BOOST_AUTO_TEST_SUITE_END() // TestCommandInterestSigner +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/config-file.README.txt b/tests/unit/security/config-file.README.txt new file mode 100644 index 000000000..f77cf6587 --- /dev/null +++ b/tests/unit/security/config-file.README.txt @@ -0,0 +1,11 @@ +In tests, we set a test-specific HOME, which causes macOS Keychain to look for +the default keychain of a "different" user. If the default keychain does not +exist, all subsequent calls to macOS Keychain will fail. User interaction +(such as entering the password) is required to create a keychain. However, +user interaction is not feasible in automated tests. + +This problem is caused by macOS's assumption that a user must have a login +keychain, which is also the user's default keychain, because a user account is +always created with a login keychain by default. Thus, macOS infers the user +according to the HOME env, and does not expect the user to change the HOME env +during normal use. diff --git a/tests/unit/security/digest-sha256.t.cpp b/tests/unit/security/digest-sha256.t.cpp new file mode 100644 index 000000000..d3fcf4ac5 --- /dev/null +++ b/tests/unit/security/digest-sha256.t.cpp @@ -0,0 +1,74 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/digest-sha256.hpp" +#include "ndn-cxx/security/verification-helpers.hpp" +#include "ndn-cxx/util/sha256.hpp" +#include "ndn-cxx/util/string-helper.hpp" + +#include "tests/boost-test.hpp" +#include "tests/identity-management-fixture.hpp" + +namespace ndn { +namespace security { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_FIXTURE_TEST_SUITE(TestDigestSha256, IdentityManagementFixture) + +BOOST_AUTO_TEST_CASE(Sha256) +{ + char content[6] = "1234\n"; + ConstBufferPtr buf = util::Sha256::computeDigest(reinterpret_cast(content), 5); + + BOOST_CHECK_EQUAL(toHex(buf->data(), buf->size(), false), + "a883dafc480d466ee04e0d6da986bd78eb1fdd2178d04693723da3a8f95d42f4"); +} + +BOOST_AUTO_TEST_CASE(DataSignature) +{ + Name name("/TestSignatureSha/Basic"); + Data testData(name); + char content[5] = "1234"; + testData.setContent(reinterpret_cast(content), 5); + m_keyChain.sign(testData, security::SigningInfo(security::SigningInfo::SIGNER_TYPE_SHA256)); + + BOOST_CHECK_THROW(testData.getSignature().getKeyLocator(), ndn::SignatureInfo::Error); + verifyDigest(testData, DigestAlgorithm::SHA256); +} + +BOOST_AUTO_TEST_CASE(InterestSignature) +{ + Name name("/SecurityTestDigestSha256/InterestSignature/Interest1"); + Interest testInterest(name); + + m_keyChain.sign(testInterest, security::SigningInfo(security::SigningInfo::SIGNER_TYPE_SHA256)); + verifyDigest(testInterest, DigestAlgorithm::SHA256); +} + +BOOST_AUTO_TEST_SUITE_END() // TestDigestSha256 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/key-params.t.cpp b/tests/unit/security/key-params.t.cpp new file mode 100644 index 000000000..b2dafcd03 --- /dev/null +++ b/tests/unit/security/key-params.t.cpp @@ -0,0 +1,163 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/key-params.hpp" + +#include "tests/boost-test.hpp" + +#include + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(TestKeyParams) + +BOOST_AUTO_TEST_CASE(Rsa) +{ + RsaKeyParams params; + BOOST_CHECK_EQUAL(params.getKeyType(), KeyType::RSA); + BOOST_CHECK_EQUAL(params.getKeySize(), 2048); + BOOST_CHECK_EQUAL(params.getKeyIdType(), KeyIdType::RANDOM); + + RsaKeyParams params2(4096, KeyIdType::SHA256); + BOOST_CHECK_EQUAL(params2.getKeyType(), KeyType::RSA); + BOOST_CHECK_EQUAL(params2.getKeySize(), 4096); + BOOST_CHECK_EQUAL(params2.getKeyIdType(), KeyIdType::SHA256); + + BOOST_CHECK_THROW(RsaKeyParams(1024), KeyParams::Error); + + name::Component keyId("keyId"); + RsaKeyParams params4(keyId); + BOOST_CHECK_EQUAL(params4.getKeyType(), KeyType::RSA); + BOOST_CHECK_EQUAL(params4.getKeySize(), 2048); + BOOST_CHECK_EQUAL(params4.getKeyIdType(), KeyIdType::USER_SPECIFIED); + BOOST_CHECK_EQUAL(params4.getKeyId(), keyId); +} + +BOOST_AUTO_TEST_CASE(Ec) +{ + EcKeyParams params; + BOOST_CHECK_EQUAL(params.getKeyType(), KeyType::EC); + BOOST_CHECK_EQUAL(params.getKeySize(), 256); + BOOST_CHECK_EQUAL(params.getKeyIdType(), KeyIdType::RANDOM); + + EcKeyParams params2(384, KeyIdType::SHA256); + BOOST_CHECK_EQUAL(params2.getKeyType(), KeyType::EC); + BOOST_CHECK_EQUAL(params2.getKeySize(), 384); + BOOST_CHECK_EQUAL(params2.getKeyIdType(), KeyIdType::SHA256); + + BOOST_CHECK_THROW(EcKeyParams(64), KeyParams::Error); + + name::Component keyId("keyId"); + EcKeyParams params4(keyId); + BOOST_CHECK_EQUAL(params4.getKeyType(), KeyType::EC); + BOOST_CHECK_EQUAL(params4.getKeySize(), 256); + BOOST_CHECK_EQUAL(params4.getKeyIdType(), KeyIdType::USER_SPECIFIED); + BOOST_CHECK_EQUAL(params4.getKeyId(), keyId); +} + +BOOST_AUTO_TEST_CASE(Aes) +{ + name::Component keyId("keyId"); + AesKeyParams params(keyId); + BOOST_CHECK_EQUAL(params.getKeyType(), KeyType::AES); + BOOST_CHECK_EQUAL(params.getKeySize(), 128); + BOOST_CHECK_EQUAL(params.getKeyIdType(), KeyIdType::USER_SPECIFIED); + BOOST_CHECK_EQUAL(params.getKeyId(), keyId); + + AesKeyParams params2(keyId, 192); + BOOST_CHECK_EQUAL(params2.getKeyType(), KeyType::AES); + BOOST_CHECK_EQUAL(params2.getKeySize(), 192); + BOOST_CHECK_EQUAL(params2.getKeyIdType(), KeyIdType::USER_SPECIFIED); + BOOST_CHECK_EQUAL(params2.getKeyId(), keyId); + + AesKeyParams params3(keyId, 256); + BOOST_CHECK_EQUAL(params3.getKeyType(), KeyType::AES); + BOOST_CHECK_EQUAL(params3.getKeySize(), 256); + BOOST_CHECK_EQUAL(params3.getKeyIdType(), KeyIdType::USER_SPECIFIED); + BOOST_CHECK_EQUAL(params3.getKeyId(), keyId); + + BOOST_CHECK_THROW(AesKeyParams(keyId, 64), KeyParams::Error); + + AesKeyParams params4; + BOOST_CHECK_EQUAL(params4.getKeyType(), KeyType::AES); + BOOST_CHECK_EQUAL(params4.getKeySize(), 128); + BOOST_CHECK_EQUAL(params4.getKeyIdType(), KeyIdType::RANDOM); + + AesKeyParams params5(192); + BOOST_CHECK_EQUAL(params5.getKeyType(), KeyType::AES); + BOOST_CHECK_EQUAL(params5.getKeySize(), 192); + BOOST_CHECK_EQUAL(params5.getKeyIdType(), KeyIdType::RANDOM); +} + +BOOST_AUTO_TEST_CASE(Hmac) +{ + name::Component keyId("keyId"); + HmacKeyParams params(keyId); + BOOST_CHECK_EQUAL(params.getKeyType(), KeyType::HMAC); + BOOST_CHECK_EQUAL(params.getKeySize(), 256); + BOOST_CHECK_EQUAL(params.getKeyIdType(), KeyIdType::USER_SPECIFIED); + BOOST_CHECK_EQUAL(params.getKeyId(), keyId); + + HmacKeyParams params2(keyId, 384); + BOOST_CHECK_EQUAL(params2.getKeyType(), KeyType::HMAC); + BOOST_CHECK_EQUAL(params2.getKeySize(), 384); + BOOST_CHECK_EQUAL(params2.getKeyIdType(), KeyIdType::USER_SPECIFIED); + BOOST_CHECK_EQUAL(params2.getKeyId(), keyId); + + BOOST_CHECK_THROW(HmacKeyParams(keyId, 0), KeyParams::Error); + BOOST_CHECK_THROW(HmacKeyParams(keyId, 300), KeyParams::Error); // not a multiple of 8 + + HmacKeyParams params3; + BOOST_CHECK_EQUAL(params3.getKeyType(), KeyType::HMAC); + BOOST_CHECK_EQUAL(params3.getKeySize(), 256); + BOOST_CHECK_EQUAL(params3.getKeyIdType(), KeyIdType::RANDOM); + + HmacKeyParams params4(1024); + BOOST_CHECK_EQUAL(params4.getKeyType(), KeyType::HMAC); + BOOST_CHECK_EQUAL(params4.getKeySize(), 1024); + BOOST_CHECK_EQUAL(params4.getKeyIdType(), KeyIdType::RANDOM); +} + +BOOST_AUTO_TEST_CASE(KeyTypeToString) +{ + BOOST_CHECK_EQUAL(boost::lexical_cast(KeyType::NONE), "NONE"); + BOOST_CHECK_EQUAL(boost::lexical_cast(KeyType::RSA), "RSA"); + BOOST_CHECK_EQUAL(boost::lexical_cast(KeyType::EC), "EC"); + BOOST_CHECK_EQUAL(boost::lexical_cast(KeyType::AES), "AES"); + BOOST_CHECK_EQUAL(boost::lexical_cast(KeyType::HMAC), "HMAC"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(12345)), "12345"); +} + +BOOST_AUTO_TEST_CASE(KeyIdTypeToString) +{ + BOOST_CHECK_EQUAL(boost::lexical_cast(KeyIdType::USER_SPECIFIED), "USER-SPECIFIED"); + BOOST_CHECK_EQUAL(boost::lexical_cast(KeyIdType::SHA256), "SHA256"); + BOOST_CHECK_EQUAL(boost::lexical_cast(KeyIdType::RANDOM), "RANDOM"); + BOOST_CHECK_EQUAL(boost::lexical_cast(static_cast(12345)), "12345"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestKeyParams +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace ndn diff --git a/tests/unit/security/pib/certificate-container.t.cpp b/tests/unit/security/pib/certificate-container.t.cpp new file mode 100644 index 000000000..b6e9f1237 --- /dev/null +++ b/tests/unit/security/pib/certificate-container.t.cpp @@ -0,0 +1,167 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/certificate-container.hpp" +#include "ndn-cxx/security/pib/impl/pib-memory.hpp" +#include "ndn-cxx/security/pib/pib.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/pib/pib-data-fixture.hpp" + +namespace ndn { +namespace security { +namespace pib { +namespace tests { + +using namespace ndn::security::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(Pib) +BOOST_FIXTURE_TEST_SUITE(TestCertificateContainer, PibDataFixture) + +using pib::Pib; + +BOOST_AUTO_TEST_CASE(Basic) +{ + auto pibImpl = make_shared(); + + // start with an empty container + CertificateContainer container(id1Key1Name, pibImpl); + BOOST_CHECK_EQUAL(container.size(), 0); + BOOST_CHECK_EQUAL(container.getCache().size(), 0); + + // add one cert + container.add(id1Key1Cert1); + BOOST_CHECK_EQUAL(container.size(), 1); + BOOST_CHECK_EQUAL(container.getCache().size(), 1); + BOOST_CHECK(container.find(id1Key1Cert1.getName()) != container.end()); + + // add the same cert again + container.add(id1Key1Cert1); + BOOST_CHECK_EQUAL(container.size(), 1); + BOOST_CHECK_EQUAL(container.getCache().size(), 1); + BOOST_CHECK(container.find(id1Key1Cert1.getName()) != container.end()); + + // add another cert + container.add(id1Key1Cert2); + BOOST_CHECK_EQUAL(container.size(), 2); + BOOST_CHECK_EQUAL(container.getCache().size(), 2); + BOOST_CHECK(container.find(id1Key1Cert1.getName()) != container.end()); + BOOST_CHECK(container.find(id1Key1Cert2.getName()) != container.end()); + + // get certs + BOOST_REQUIRE_NO_THROW(container.get(id1Key1Cert1.getName())); + BOOST_REQUIRE_NO_THROW(container.get(id1Key1Cert2.getName())); + Name id1Key1Cert3Name = id1Key1Name; + id1Key1Cert3Name.append("issuer").appendVersion(3); + BOOST_CHECK_THROW(container.get(id1Key1Cert3Name), Pib::Error); + + // check cert + v2::Certificate cert1 = container.get(id1Key1Cert1.getName()); + v2::Certificate cert2 = container.get(id1Key1Cert2.getName()); + BOOST_CHECK_EQUAL(cert1, id1Key1Cert1); + BOOST_CHECK_EQUAL(cert2, id1Key1Cert2); + + // create another container from the same PibImpl + // cache should be empty + CertificateContainer container2(id1Key1Name, pibImpl); + BOOST_CHECK_EQUAL(container2.size(), 2); + BOOST_CHECK_EQUAL(container2.getCache().size(), 0); + + // get certificate, cache should be filled + BOOST_REQUIRE_NO_THROW(container2.get(id1Key1Cert1.getName())); + BOOST_CHECK_EQUAL(container2.size(), 2); + BOOST_CHECK_EQUAL(container2.getCache().size(), 1); + + BOOST_REQUIRE_NO_THROW(container2.get(id1Key1Cert2.getName())); + BOOST_CHECK_EQUAL(container2.size(), 2); + BOOST_CHECK_EQUAL(container2.getCache().size(), 2); + + // remove a certificate + container2.remove(id1Key1Cert1.getName()); + BOOST_CHECK_EQUAL(container2.size(), 1); + BOOST_CHECK_EQUAL(container2.getCache().size(), 1); + BOOST_CHECK(container2.find(id1Key1Cert1.getName()) == container2.end()); + BOOST_CHECK(container2.find(id1Key1Cert2.getName()) != container2.end()); + + // remove another certificate + container2.remove(id1Key1Cert2.getName()); + BOOST_CHECK_EQUAL(container2.size(), 0); + BOOST_CHECK_EQUAL(container2.getCache().size(), 0); + BOOST_CHECK(container2.find(id1Key1Cert2.getName()) == container2.end()); +} + +BOOST_AUTO_TEST_CASE(Errors) +{ + auto pibImpl = make_shared(); + + CertificateContainer container(id1Key1Name, pibImpl); + + BOOST_CHECK_THROW(container.add(id1Key2Cert1), std::invalid_argument); + BOOST_CHECK_THROW(container.remove(id1Key2Cert1.getName()), std::invalid_argument); + BOOST_CHECK_THROW(container.get(id1Key2Cert1.getName()), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(Iterator) +{ + auto pibImpl = make_shared(); + + // start with an empty container + CertificateContainer container(id1Key1Name, pibImpl); + container.add(id1Key1Cert1); + container.add(id1Key1Cert2); + + std::set certNames; + certNames.insert(id1Key1Cert1.getName()); + certNames.insert(id1Key1Cert2.getName()); + + CertificateContainer::const_iterator it = container.begin(); + std::set::const_iterator testIt = certNames.begin(); + BOOST_CHECK_EQUAL((*it).getName(), *testIt); + it++; + testIt++; + BOOST_CHECK_EQUAL((*it).getName(), *testIt); + ++it; + testIt++; + BOOST_CHECK(it == container.end()); + + size_t count = 0; + testIt = certNames.begin(); + for (const auto& cert : container) { + BOOST_CHECK_EQUAL(cert.getName(), *testIt); + testIt++; + count++; + } + BOOST_CHECK_EQUAL(count, 2); + + BOOST_CHECK(CertificateContainer::const_iterator() == CertificateContainer::const_iterator()); + BOOST_CHECK(CertificateContainer::const_iterator() == container.end()); + BOOST_CHECK(container.end() == CertificateContainer::const_iterator()); +} + +BOOST_AUTO_TEST_SUITE_END() // TestCertificateContainer +BOOST_AUTO_TEST_SUITE_END() // Pib +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/pib/identity-container.t.cpp b/tests/unit/security/pib/identity-container.t.cpp new file mode 100644 index 000000000..fb5e9cc27 --- /dev/null +++ b/tests/unit/security/pib/identity-container.t.cpp @@ -0,0 +1,156 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/identity-container.hpp" +#include "ndn-cxx/security/pib/impl/pib-memory.hpp" +#include "ndn-cxx/security/pib/pib.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/pib/pib-data-fixture.hpp" + +namespace ndn { +namespace security { +namespace pib { +namespace tests { + +using namespace ndn::security::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(Pib) +BOOST_FIXTURE_TEST_SUITE(TestIdentityContainer, PibDataFixture) + +using pib::Pib; + +BOOST_AUTO_TEST_CASE(Basic) +{ + auto pibImpl = make_shared(); + + // start with an empty container + IdentityContainer container(pibImpl); + BOOST_CHECK_EQUAL(container.size(), 0); + BOOST_CHECK_EQUAL(container.getLoadedIdentities().size(), 0); + + // add the first identity + Identity identity11 = container.add(id1); + BOOST_CHECK_EQUAL(identity11.getName(), id1); + BOOST_CHECK_EQUAL(container.size(), 1); + BOOST_CHECK_EQUAL(container.getLoadedIdentities().size(), 1); + BOOST_CHECK(container.find(id1) != container.end()); + + // add the same identity again + Identity identity12 = container.add(id1); + BOOST_CHECK_EQUAL(identity12.getName(), id1); + BOOST_CHECK_EQUAL(container.size(), 1); + BOOST_CHECK_EQUAL(container.getLoadedIdentities().size(), 1); + BOOST_CHECK(container.find(id1) != container.end()); + + // add the second identity + Identity identity21 = container.add(id2); + BOOST_CHECK_EQUAL(identity21.getName(), id2); + BOOST_CHECK_EQUAL(container.size(), 2); + BOOST_CHECK_EQUAL(container.getLoadedIdentities().size(), 2); + BOOST_CHECK(container.find(id1) != container.end()); + BOOST_CHECK(container.find(id2) != container.end()); + + // get identities + BOOST_REQUIRE_NO_THROW(container.get(id1)); + BOOST_REQUIRE_NO_THROW(container.get(id2)); + BOOST_CHECK_THROW(container.get(Name("/non-existing")), Pib::Error); + + // check identity + Identity identity1 = container.get(id1); + Identity identity2 = container.get(id2); + BOOST_CHECK_EQUAL(identity1.getName(), id1); + BOOST_CHECK_EQUAL(identity2.getName(), id2); + + // create another container from the same PibImpl + // cache should be empty + IdentityContainer container2(pibImpl); + BOOST_CHECK_EQUAL(container2.size(), 2); + BOOST_CHECK_EQUAL(container2.getLoadedIdentities().size(), 0); + + // get key, cache should be filled + BOOST_REQUIRE_NO_THROW(container2.get(id1)); + BOOST_CHECK_EQUAL(container2.size(), 2); + BOOST_CHECK_EQUAL(container2.getLoadedIdentities().size(), 1); + + BOOST_REQUIRE_NO_THROW(container2.get(id2)); + BOOST_CHECK_EQUAL(container2.size(), 2); + BOOST_CHECK_EQUAL(container2.getLoadedIdentities().size(), 2); + + // remove a key + container2.remove(id1); + BOOST_CHECK_EQUAL(container2.size(), 1); + BOOST_CHECK_EQUAL(container2.getLoadedIdentities().size(), 1); + BOOST_CHECK(container2.find(id1) == container2.end()); + BOOST_CHECK(container2.find(id2) != container2.end()); + + // remove another key + container2.remove(id2); + BOOST_CHECK_EQUAL(container2.size(), 0); + BOOST_CHECK_EQUAL(container2.getLoadedIdentities().size(), 0); + BOOST_CHECK(container2.find(id2) == container2.end()); + +} + +BOOST_AUTO_TEST_CASE(Iterator) +{ + auto pibImpl = make_shared(); + IdentityContainer container(pibImpl); + container.add(id1); + container.add(id2); + + std::set idNames; + idNames.insert(id1); + idNames.insert(id2); + + IdentityContainer::const_iterator it = container.begin(); + std::set::const_iterator testIt = idNames.begin(); + BOOST_CHECK_EQUAL((*it).getName(), *testIt); + it++; + testIt++; + BOOST_CHECK_EQUAL((*it).getName(), *testIt); + ++it; + testIt++; + BOOST_CHECK(it == container.end()); + + size_t count = 0; + testIt = idNames.begin(); + for (const auto& identity : container) { + BOOST_CHECK_EQUAL(identity.getName(), *testIt); + testIt++; + count++; + } + BOOST_CHECK_EQUAL(count, 2); + + BOOST_CHECK(IdentityContainer::const_iterator() == IdentityContainer::const_iterator()); + BOOST_CHECK(IdentityContainer::const_iterator() == container.end()); + BOOST_CHECK(container.end() == IdentityContainer::const_iterator()); +} + +BOOST_AUTO_TEST_SUITE_END() // TestIdentityContainer +BOOST_AUTO_TEST_SUITE_END() // Pib +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/pib/identity.t.cpp b/tests/unit/security/pib/identity.t.cpp new file mode 100644 index 000000000..4d79bbc6a --- /dev/null +++ b/tests/unit/security/pib/identity.t.cpp @@ -0,0 +1,81 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/identity.hpp" +#include "ndn-cxx/security/pib/impl/identity-impl.hpp" +#include "ndn-cxx/security/pib/impl/pib-memory.hpp" +#include "ndn-cxx/security/pib/pib.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/pib/pib-data-fixture.hpp" + +namespace ndn { +namespace security { +namespace pib { +namespace tests { + +using namespace ndn::security::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(Pib) +BOOST_FIXTURE_TEST_SUITE(TestIdentity, PibDataFixture) + +BOOST_AUTO_TEST_CASE(ValidityChecking) +{ + Identity id; + BOOST_CHECK(!id); + BOOST_CHECK_EQUAL(static_cast(id), false); + + auto identityImpl = make_shared(id1, make_shared(), true); + id = Identity(identityImpl); + BOOST_CHECK(id); + BOOST_CHECK_EQUAL(!id, false); +} + +// pib::Identity is a wrapper of pib::detail::IdentityImpl. Since the functionalities of +// IdentityImpl have already been tested in detail/identity-impl.t.cpp, we only test the shared +// property of pib::Identity in this test case. +BOOST_AUTO_TEST_CASE(SharedImpl) +{ + auto identityImpl = make_shared(id1, make_shared(), true); + Identity identity1(identityImpl); + Identity identity2(identityImpl); + BOOST_CHECK_EQUAL(identity1, identity2); + BOOST_CHECK_NE(identity1, Identity()); + BOOST_CHECK_EQUAL(Identity(), Identity()); + + identity1.addKey(id1Key1.data(), id1Key1.size(), id1Key1Name); + BOOST_CHECK_NO_THROW(identity2.getKey(id1Key1Name)); + identity2.removeKey(id1Key1Name); + BOOST_CHECK_THROW(identity1.getKey(id1Key1Name), pib::Pib::Error); + + identity1.setDefaultKey(id1Key1.data(), id1Key1.size(), id1Key1Name); + BOOST_CHECK_NO_THROW(identity2.getDefaultKey()); +} + +BOOST_AUTO_TEST_SUITE_END() // TestIdentity +BOOST_AUTO_TEST_SUITE_END() // Pib +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/pib/impl/identity-impl.t.cpp b/tests/unit/security/pib/impl/identity-impl.t.cpp new file mode 100644 index 000000000..bb523f4f0 --- /dev/null +++ b/tests/unit/security/pib/impl/identity-impl.t.cpp @@ -0,0 +1,160 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/impl/identity-impl.hpp" +#include "ndn-cxx/security/pib/impl/pib-memory.hpp" +#include "ndn-cxx/security/pib/pib.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/pib/pib-data-fixture.hpp" + +namespace ndn { +namespace security { +namespace pib { +namespace detail { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(Pib) +BOOST_AUTO_TEST_SUITE(Detail) +BOOST_FIXTURE_TEST_SUITE(TestIdentityImpl, ndn::security::tests::PibDataFixture) + +using security::Pib; + +BOOST_AUTO_TEST_CASE(Basic) +{ + auto pibImpl = make_shared(); + IdentityImpl identity1(id1, pibImpl, true); + + BOOST_CHECK_EQUAL(identity1.getName(), id1); +} + +BOOST_AUTO_TEST_CASE(KeyOperation) +{ + auto pibImpl = make_shared(); + IdentityImpl identity1(id1, pibImpl, true); + BOOST_CHECK_NO_THROW(IdentityImpl(id1, pibImpl, false)); + + // identity does not have any key + BOOST_CHECK_EQUAL(identity1.getKeys().size(), 0); + + // get non-existing key, throw Pib::Error + BOOST_CHECK_THROW(identity1.getKey(id1Key1Name), Pib::Error); + // get default key, throw Pib::Error + BOOST_CHECK_THROW(identity1.getDefaultKey(), Pib::Error); + // set non-existing key as default key, throw Pib::Error + BOOST_REQUIRE_THROW(identity1.setDefaultKey(id1Key1Name), Pib::Error); + + // add key + identity1.addKey(id1Key1.data(), id1Key1.size(), id1Key1Name); + BOOST_CHECK_NO_THROW(identity1.getKey(id1Key1Name)); + + // new key becomes default key when there is no default key + BOOST_REQUIRE_NO_THROW(identity1.getDefaultKey()); + const Key& defaultKey0 = identity1.getDefaultKey(); + BOOST_CHECK_EQUAL(defaultKey0.getName(), id1Key1Name); + BOOST_CHECK(defaultKey0.getPublicKey() == id1Key1); + + // remove key + identity1.removeKey(id1Key1Name); + BOOST_CHECK_THROW(identity1.getKey(id1Key1Name), Pib::Error); + BOOST_CHECK_THROW(identity1.getDefaultKey(), Pib::Error); + + // set default key directly + BOOST_REQUIRE_NO_THROW(identity1.setDefaultKey(id1Key1.data(), id1Key1.size(), id1Key1Name)); + BOOST_REQUIRE_NO_THROW(identity1.getDefaultKey()); + BOOST_CHECK_NO_THROW(identity1.getKey(id1Key1Name)); + + // check default key + const Key& defaultKey1 = identity1.getDefaultKey(); + BOOST_CHECK_EQUAL(defaultKey1.getName(), id1Key1Name); + BOOST_CHECK(defaultKey1.getPublicKey() == id1Key1); + + // add another key + identity1.addKey(id1Key2.data(), id1Key2.size(), id1Key2Name); + BOOST_CHECK_EQUAL(identity1.getKeys().size(), 2); + + // set default key through name + BOOST_REQUIRE_NO_THROW(identity1.setDefaultKey(id1Key2Name)); + BOOST_REQUIRE_NO_THROW(identity1.getDefaultKey()); + const Key& defaultKey2 = identity1.getDefaultKey(); + BOOST_CHECK_EQUAL(defaultKey2.getName(), id1Key2Name); + BOOST_CHECK(defaultKey2.getPublicKey() == id1Key2); + + // remove key + identity1.removeKey(id1Key1Name); + BOOST_CHECK_THROW(identity1.getKey(id1Key1Name), Pib::Error); + BOOST_CHECK_EQUAL(identity1.getKeys().size(), 1); + + // set default key directly again, change the default setting + BOOST_REQUIRE_NO_THROW(identity1.setDefaultKey(id1Key1.data(), id1Key1.size(), id1Key1Name)); + const Key& defaultKey3 = identity1.getDefaultKey(); + BOOST_CHECK_EQUAL(defaultKey3.getName(), id1Key1Name); + BOOST_CHECK(defaultKey3.getPublicKey() == id1Key1); + BOOST_CHECK_EQUAL(identity1.getKeys().size(), 2); + + // remove all keys + identity1.removeKey(id1Key1Name); + BOOST_CHECK_THROW(identity1.getKey(id1Key1Name), Pib::Error); + BOOST_CHECK_EQUAL(identity1.getKeys().size(), 1); + identity1.removeKey(id1Key2Name); + BOOST_CHECK_THROW(identity1.getKey(id1Key2Name), Pib::Error); + BOOST_CHECK_EQUAL(identity1.getKeys().size(), 0); + BOOST_CHECK_THROW(identity1.getDefaultKey(), Pib::Error); +} + +BOOST_AUTO_TEST_CASE(Overwrite) +{ + auto pibImpl = make_shared(); + IdentityImpl identity1(id1, pibImpl, true); + + identity1.addKey(id1Key1.data(), id1Key1.size(), id1Key1Name); + BOOST_CHECK(identity1.getKey(id1Key1Name).getPublicKey() == id1Key1); + + identity1.addKey(id1Key2.data(), id1Key2.size(), id1Key1Name); // overwriting key should work + BOOST_CHECK(identity1.getKey(id1Key1Name).getPublicKey() == id1Key2); +} + +BOOST_AUTO_TEST_CASE(Errors) +{ + auto pibImpl = make_shared(); + + BOOST_CHECK_THROW(IdentityImpl(id1, pibImpl, false), Pib::Error); + IdentityImpl identity1(id1, pibImpl, true); + + identity1.addKey(id1Key1.data(), id1Key1.size(), id1Key1Name); + BOOST_CHECK_THROW(identity1.addKey(id2Key1.data(), id2Key1.size(), id2Key1Name), std::invalid_argument); + BOOST_CHECK_THROW(identity1.removeKey(id2Key1Name), std::invalid_argument); + BOOST_CHECK_THROW(identity1.getKey(id2Key1Name), std::invalid_argument); + BOOST_CHECK_THROW(identity1.setDefaultKey(id2Key1.data(), id2Key1.size(), id2Key1Name), std::invalid_argument); + BOOST_CHECK_THROW(identity1.setDefaultKey(id2Key1Name), std::invalid_argument); +} + +BOOST_AUTO_TEST_SUITE_END() // TestIdentityImpl +BOOST_AUTO_TEST_SUITE_END() // Detail +BOOST_AUTO_TEST_SUITE_END() // Pib +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace detail +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/pib/impl/key-impl.t.cpp b/tests/unit/security/pib/impl/key-impl.t.cpp new file mode 100644 index 000000000..2a6c641fb --- /dev/null +++ b/tests/unit/security/pib/impl/key-impl.t.cpp @@ -0,0 +1,200 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/impl/key-impl.hpp" +#include "ndn-cxx/security/pib/impl/pib-memory.hpp" +#include "ndn-cxx/security/pib/pib.hpp" + +#include "tests/boost-test.hpp" +#include "tests/identity-management-fixture.hpp" +#include "tests/unit/security/pib/pib-data-fixture.hpp" + +namespace ndn { +namespace security { +namespace pib { +namespace detail { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(Pib) +BOOST_AUTO_TEST_SUITE(Detail) +BOOST_FIXTURE_TEST_SUITE(TestKeyImpl, security::tests::PibDataFixture) + +using security::Pib; + +BOOST_AUTO_TEST_CASE(Basic) +{ + auto pibImpl = make_shared(); + KeyImpl key11(id1Key1Name, id1Key1.data(), id1Key1.size(), pibImpl); + + BOOST_CHECK_EQUAL(key11.getName(), id1Key1Name); + BOOST_CHECK_EQUAL(key11.getIdentity(), id1); + BOOST_CHECK_EQUAL(key11.getKeyType(), KeyType::EC); + BOOST_CHECK(key11.getPublicKey() == id1Key1); + + KeyImpl key11Bak(id1Key1Name, pibImpl); + BOOST_CHECK_EQUAL(key11Bak.getName(), id1Key1Name); + BOOST_CHECK_EQUAL(key11Bak.getIdentity(), id1); + BOOST_CHECK_EQUAL(key11Bak.getKeyType(), KeyType::EC); + BOOST_CHECK(key11Bak.getPublicKey() == id1Key1); +} + +BOOST_AUTO_TEST_CASE(CertificateOperation) +{ + auto pibImpl = make_shared(); + KeyImpl key11(id1Key1Name, id1Key1.data(), id1Key1.size(), pibImpl); + BOOST_CHECK_NO_THROW(KeyImpl(id1Key1Name, pibImpl)); + + // key does not have any certificate + BOOST_CHECK_EQUAL(key11.getCertificates().size(), 0); + + // get non-existing certificate, throw Pib::Error + BOOST_CHECK_THROW(key11.getCertificate(id1Key1Cert1.getName()), Pib::Error); + // get default certificate, throw Pib::Error + BOOST_CHECK_THROW(key11.getDefaultCertificate(), Pib::Error); + // set non-existing certificate as default certificate, throw Pib::Error + BOOST_REQUIRE_THROW(key11.setDefaultCertificate(id1Key1Cert1.getName()), Pib::Error); + + // add certificate + key11.addCertificate(id1Key1Cert1); + BOOST_CHECK_NO_THROW(key11.getCertificate(id1Key1Cert1.getName())); + + // new certificate becomes default certificate when there was no default certificate + BOOST_REQUIRE_NO_THROW(key11.getDefaultCertificate()); + const auto& defaultCert0 = key11.getDefaultCertificate(); + BOOST_CHECK_EQUAL(defaultCert0.getName(), id1Key1Cert1.getName()); + BOOST_CHECK_EQUAL(defaultCert0, id1Key1Cert1); + + // remove certificate + key11.removeCertificate(id1Key1Cert1.getName()); + BOOST_CHECK_THROW(key11.getCertificate(id1Key1Cert1.getName()), Pib::Error); + BOOST_CHECK_THROW(key11.getDefaultCertificate(), Pib::Error); + + // set default certificate directly + BOOST_REQUIRE_NO_THROW(key11.setDefaultCertificate(id1Key1Cert1)); + BOOST_REQUIRE_NO_THROW(key11.getDefaultCertificate()); + BOOST_CHECK_NO_THROW(key11.getCertificate(id1Key1Cert1.getName())); + + // check default cert + const auto& defaultCert1 = key11.getDefaultCertificate(); + BOOST_CHECK_EQUAL(defaultCert1.getName(), id1Key1Cert1.getName()); + BOOST_CHECK_EQUAL(defaultCert1, id1Key1Cert1); + + // add another certificate + key11.addCertificate(id1Key1Cert2); + BOOST_CHECK_EQUAL(key11.getCertificates().size(), 2); + + // set default certificate through name + BOOST_REQUIRE_NO_THROW(key11.setDefaultCertificate(id1Key1Cert2.getName())); + BOOST_REQUIRE_NO_THROW(key11.getDefaultCertificate()); + const auto& defaultCert2 = key11.getDefaultCertificate(); + BOOST_CHECK_EQUAL(defaultCert2.getName(), id1Key1Cert2.getName()); + BOOST_CHECK_EQUAL(defaultCert2, id1Key1Cert2); + + // remove certificate + key11.removeCertificate(id1Key1Cert1.getName()); + BOOST_CHECK_THROW(key11.getCertificate(id1Key1Cert1.getName()), Pib::Error); + BOOST_CHECK_EQUAL(key11.getCertificates().size(), 1); + + // set default certificate directly again, change the default setting + BOOST_REQUIRE_NO_THROW(key11.setDefaultCertificate(id1Key1Cert1)); + const auto& defaultCert3 = key11.getDefaultCertificate(); + BOOST_CHECK_EQUAL(defaultCert3.getName(), id1Key1Cert1.getName()); + BOOST_CHECK_EQUAL(defaultCert3, id1Key1Cert1); + BOOST_CHECK_EQUAL(key11.getCertificates().size(), 2); + + // remove all certificates + key11.removeCertificate(id1Key1Cert1.getName()); + BOOST_CHECK_THROW(key11.getCertificate(id1Key1Cert1.getName()), Pib::Error); + BOOST_CHECK_EQUAL(key11.getCertificates().size(), 1); + key11.removeCertificate(id1Key1Cert2.getName()); + BOOST_CHECK_THROW(key11.getCertificate(id1Key1Cert2.getName()), Pib::Error); + BOOST_CHECK_THROW(key11.getDefaultCertificate(), Pib::Error); + BOOST_CHECK_EQUAL(key11.getCertificates().size(), 0); +} + +class OverwriteFixture : public ndn::security::tests::PibDataFixture, + public ndn::tests::IdentityManagementFixture +{ +}; + +BOOST_FIXTURE_TEST_CASE(Overwrite, OverwriteFixture) +{ + auto pibImpl = make_shared(); + + BOOST_CHECK_THROW(KeyImpl(id1Key1Name, pibImpl), Pib::Error); + KeyImpl(id1Key1Name, id1Key1.data(), id1Key1.size(), pibImpl); + KeyImpl key1(id1Key1Name, pibImpl); + + KeyImpl(id1Key1Name, id1Key2.data(), id1Key2.size(), pibImpl); // overwriting of the key should work + KeyImpl key2(id1Key1Name, pibImpl); + + BOOST_CHECK(key1.getPublicKey() != key2.getPublicKey()); // key1 cached the original public key + BOOST_CHECK(key2.getPublicKey() == id1Key2); + + key1.addCertificate(id1Key1Cert1); + BOOST_CHECK_EQUAL(key1.getCertificate(id1Key1Cert1.getName()), id1Key1Cert1); + + auto otherCert = id1Key1Cert1; + SignatureInfo info; + info.setValidityPeriod(ValidityPeriod(time::system_clock::now(), + time::system_clock::now() + 1_s)); + m_keyChain.sign(otherCert, SigningInfo().setSignatureInfo(info)); + + BOOST_CHECK_EQUAL(otherCert.getName(), id1Key1Cert1.getName()); + BOOST_CHECK(otherCert.getContent() == id1Key1Cert1.getContent()); + BOOST_CHECK_NE(otherCert, id1Key1Cert1); + + key1.addCertificate(otherCert); + + BOOST_CHECK_EQUAL(key1.getCertificate(id1Key1Cert1.getName()), otherCert); +} + +BOOST_AUTO_TEST_CASE(Errors) +{ + auto pibImpl = make_shared(); + + BOOST_CHECK_THROW(KeyImpl(id1Key1Name, pibImpl), Pib::Error); + KeyImpl key11(id1Key1Name, id1Key1.data(), id1Key1.size(), pibImpl); + + BOOST_CHECK_THROW(KeyImpl(Name("/wrong"), pibImpl), std::invalid_argument); + BOOST_CHECK_THROW(KeyImpl(Name("/wrong"), id1Key1.data(), id1Key1.size(), pibImpl), std::invalid_argument); + Buffer wrongKey; + BOOST_CHECK_THROW(KeyImpl(id1Key2Name, wrongKey.data(), wrongKey.size(), pibImpl), std::invalid_argument); + + key11.addCertificate(id1Key1Cert1); + BOOST_CHECK_THROW(key11.addCertificate(id1Key2Cert1), std::invalid_argument); + BOOST_CHECK_THROW(key11.removeCertificate(id1Key2Cert1.getName()), std::invalid_argument); + BOOST_CHECK_THROW(key11.getCertificate(id1Key2Cert1.getName()), std::invalid_argument); + BOOST_CHECK_THROW(key11.setDefaultCertificate(id1Key2Cert1), std::invalid_argument); + BOOST_CHECK_THROW(key11.setDefaultCertificate(id1Key2Cert1.getName()), std::invalid_argument); +} + +BOOST_AUTO_TEST_SUITE_END() // TestKeyImpl +BOOST_AUTO_TEST_SUITE_END() // Detail +BOOST_AUTO_TEST_SUITE_END() // Pib +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace detail +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/pib/key-container.t.cpp b/tests/unit/security/pib/key-container.t.cpp new file mode 100644 index 000000000..aab7b1cc7 --- /dev/null +++ b/tests/unit/security/pib/key-container.t.cpp @@ -0,0 +1,174 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/key-container.hpp" +#include "ndn-cxx/security/pib/impl/pib-memory.hpp" +#include "ndn-cxx/security/pib/pib.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/pib/pib-data-fixture.hpp" + +namespace ndn { +namespace security { +namespace pib { +namespace tests { + +using namespace ndn::security::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(Pib) +BOOST_FIXTURE_TEST_SUITE(TestKeyContainer, PibDataFixture) + +using pib::Pib; + +BOOST_AUTO_TEST_CASE(Basic) +{ + auto pibImpl = make_shared(); + + // start with an empty container + KeyContainer container(id1, pibImpl); + BOOST_CHECK_EQUAL(container.size(), 0); + BOOST_CHECK_EQUAL(container.getLoadedKeys().size(), 0); + + // add the first key + Key key11 = container.add(id1Key1.data(), id1Key1.size(), id1Key1Name); + BOOST_CHECK_EQUAL(key11.getName(), id1Key1Name); + BOOST_CHECK(key11.getPublicKey() == id1Key1); + BOOST_CHECK_EQUAL(container.size(), 1); + BOOST_CHECK_EQUAL(container.getLoadedKeys().size(), 1); + BOOST_CHECK(container.find(id1Key1Name) != container.end()); + + // add the same key again + Key key12 = container.add(id1Key1.data(), id1Key1.size(), id1Key1Name); + BOOST_CHECK_EQUAL(key12.getName(), id1Key1Name); + BOOST_CHECK(key12.getPublicKey() == id1Key1); + BOOST_CHECK_EQUAL(container.size(), 1); + BOOST_CHECK_EQUAL(container.getLoadedKeys().size(), 1); + BOOST_CHECK(container.find(id1Key1Name) != container.end()); + + // add the second key + Key key21 = container.add(id1Key2.data(), id1Key2.size(), id1Key2Name); + BOOST_CHECK_EQUAL(key21.getName(), id1Key2Name); + BOOST_CHECK(key21.getPublicKey() == id1Key2); + BOOST_CHECK_EQUAL(container.size(), 2); + BOOST_CHECK_EQUAL(container.getLoadedKeys().size(), 2); + BOOST_CHECK(container.find(id1Key1Name) != container.end()); + BOOST_CHECK(container.find(id1Key2Name) != container.end()); + + // get keys + BOOST_REQUIRE_NO_THROW(container.get(id1Key1Name)); + BOOST_REQUIRE_NO_THROW(container.get(id1Key2Name)); + Name id1Key3Name = v2::constructKeyName(id1, name::Component("non-existing-id")); + BOOST_CHECK_THROW(container.get(id1Key3Name), Pib::Error); + + // check key + Key key1 = container.get(id1Key1Name); + Key key2 = container.get(id1Key2Name); + BOOST_CHECK_EQUAL(key1.getName(), id1Key1Name); + BOOST_CHECK(key1.getPublicKey() == id1Key1); + BOOST_CHECK_EQUAL(key2.getName(), id1Key2Name); + BOOST_CHECK(key2.getPublicKey() == id1Key2); + + // create another container from the same PibImpl + // cache should be empty + KeyContainer container2(id1, pibImpl); + BOOST_CHECK_EQUAL(container2.size(), 2); + BOOST_CHECK_EQUAL(container2.getLoadedKeys().size(), 0); + + // get key, cache should be filled + BOOST_REQUIRE_NO_THROW(container2.get(id1Key1Name)); + BOOST_CHECK_EQUAL(container2.size(), 2); + BOOST_CHECK_EQUAL(container2.getLoadedKeys().size(), 1); + + BOOST_REQUIRE_NO_THROW(container2.get(id1Key2Name)); + BOOST_CHECK_EQUAL(container2.size(), 2); + BOOST_CHECK_EQUAL(container2.getLoadedKeys().size(), 2); + + // remove a key + container2.remove(id1Key1Name); + BOOST_CHECK_EQUAL(container2.size(), 1); + BOOST_CHECK_EQUAL(container2.getLoadedKeys().size(), 1); + BOOST_CHECK(container2.find(id1Key1Name) == container2.end()); + BOOST_CHECK(container2.find(id1Key2Name) != container2.end()); + + // remove another key + container2.remove(id1Key2Name); + BOOST_CHECK_EQUAL(container2.size(), 0); + BOOST_CHECK_EQUAL(container2.getLoadedKeys().size(), 0); + BOOST_CHECK(container2.find(id1Key2Name) == container2.end()); +} + +BOOST_AUTO_TEST_CASE(Errors) +{ + auto pibImpl = make_shared(); + + KeyContainer container(id1, pibImpl); + + BOOST_CHECK_THROW(container.add(id2Key1.data(), id2Key1.size(), id2Key1Name), std::invalid_argument); + BOOST_CHECK_THROW(container.remove(id2Key1Name), std::invalid_argument); + BOOST_CHECK_THROW(container.get(id2Key1Name), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(Iterator) +{ + auto pibImpl = make_shared(); + KeyContainer container(id1, pibImpl); + + container.add(id1Key1.data(), id1Key1.size(), id1Key1Name); + container.add(id1Key2.data(), id1Key2.size(), id1Key2Name); + + std::set keyNames; + keyNames.insert(id1Key1Name); + keyNames.insert(id1Key2Name); + + KeyContainer::const_iterator it = container.begin(); + std::set::const_iterator testIt = keyNames.begin(); + BOOST_CHECK_EQUAL((*it).getName(), *testIt); + it++; + testIt++; + BOOST_CHECK_EQUAL((*it).getName(), *testIt); + ++it; + testIt++; + BOOST_CHECK(it == container.end()); + + size_t count = 0; + testIt = keyNames.begin(); + for (const auto& key : container) { + BOOST_CHECK_EQUAL(key.getIdentity(), id1); + BOOST_CHECK_EQUAL(key.getName(), *testIt); + testIt++; + count++; + } + BOOST_CHECK_EQUAL(count, 2); + + BOOST_CHECK(KeyContainer::const_iterator() == KeyContainer::const_iterator()); + BOOST_CHECK(KeyContainer::const_iterator() == container.end()); + BOOST_CHECK(container.end() == KeyContainer::const_iterator()); +} + +BOOST_AUTO_TEST_SUITE_END() // TestKeyContainer +BOOST_AUTO_TEST_SUITE_END() // Pib +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/pib/key.t.cpp b/tests/unit/security/pib/key.t.cpp new file mode 100644 index 000000000..f5c62facb --- /dev/null +++ b/tests/unit/security/pib/key.t.cpp @@ -0,0 +1,101 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/key.hpp" +#include "ndn-cxx/security/pib/impl/key-impl.hpp" +#include "ndn-cxx/security/pib/impl/pib-memory.hpp" +#include "ndn-cxx/security/pib/pib.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/pib/pib-data-fixture.hpp" + +namespace ndn { +namespace security { +namespace pib { +namespace tests { + +using namespace ndn::security::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(Pib) +BOOST_FIXTURE_TEST_SUITE(TestKey, PibDataFixture) + +BOOST_AUTO_TEST_CASE(ValidityChecking) +{ + Key key; + BOOST_CHECK(!key); + BOOST_CHECK_EQUAL(static_cast(key), false); + + auto keyImpl = make_shared(id1Key1Name, id1Key1.data(), id1Key1.size(), + make_shared()); + key = Key(keyImpl); + BOOST_CHECK(key); + BOOST_CHECK_EQUAL(!key, false); +} + +// pib::Key is a wrapper of pib::detail::KeyImpl. Since the functionalities of KeyImpl +// have already been tested in detail/key-impl.t.cpp, we only test the shared property +// of pib::Key in this test case. +BOOST_AUTO_TEST_CASE(SharedImpl) +{ + auto keyImpl = make_shared(id1Key1Name, id1Key1.data(), id1Key1.size(), + make_shared()); + Key key1(keyImpl); + Key key2(keyImpl); + BOOST_CHECK_EQUAL(key1, key2); + BOOST_CHECK_NE(key1, Key()); + BOOST_CHECK_EQUAL(Key(), Key()); + + key1.addCertificate(id1Key1Cert1); + BOOST_CHECK_NO_THROW(key2.getCertificate(id1Key1Cert1.getName())); + key2.removeCertificate(id1Key1Cert1.getName()); + BOOST_CHECK_THROW(key1.getCertificate(id1Key1Cert1.getName()), pib::Pib::Error); + + key1.setDefaultCertificate(id1Key1Cert1); + BOOST_CHECK_NO_THROW(key2.getDefaultCertificate()); +} + +BOOST_AUTO_TEST_CASE(Helpers) +{ + BOOST_CHECK_EQUAL(v2::constructKeyName("/hello", name::Component("world")), "/hello/KEY/world"); + + BOOST_CHECK_EQUAL(v2::isValidKeyName("/hello"), false); + BOOST_CHECK_EQUAL(v2::isValidKeyName("/hello/KEY"), false); + BOOST_CHECK_EQUAL(v2::isValidKeyName("/hello/KEY/world"), true); + + BOOST_CHECK_EQUAL(v2::isValidKeyName("/KEY/hello"), true); + BOOST_CHECK_EQUAL(v2::isValidKeyName("/hello/world/KEY/!"), true); + + BOOST_CHECK_EQUAL(v2::extractIdentityFromKeyName("/KEY/hello"), "/"); + BOOST_CHECK_EQUAL(v2::extractIdentityFromKeyName("/hello/KEY/world"), "/hello"); + BOOST_CHECK_EQUAL(v2::extractIdentityFromKeyName("/hello/world/KEY/!"), "/hello/world"); + + BOOST_CHECK_THROW(v2::extractIdentityFromKeyName("/hello"), std::invalid_argument); +} + +BOOST_AUTO_TEST_SUITE_END() // TestKey +BOOST_AUTO_TEST_SUITE_END() // Pib +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/pib/pib-data-fixture.cpp b/tests/unit/security/pib/pib-data-fixture.cpp new file mode 100644 index 000000000..d2ddd101a --- /dev/null +++ b/tests/unit/security/pib/pib-data-fixture.cpp @@ -0,0 +1,428 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "tests/unit/security/pib/pib-data-fixture.hpp" + +// #include "ndn-cxx/security/pib/pib-memory.hpp" +// #include "ndn-cxx/security/tpm/tpm.hpp" +// #include "ndn-cxx/security/tpm/back-end-mem.hpp" +// #include + +namespace ndn { +namespace security { +namespace tests { + +// class TestCertDataGenerator +// { +// public: +// TestCertDataGenerator() +// : tpm("test", "test", make_unique()) +// { +// } + +// void +// printTestDataForId(const std::string& prefix, const Name& id) +// { +// for (int keyId : {1, 2}) { +// Name keyName = tpm.createKey(id, EcKeyParams(name::Component::fromNumber(keyId))); + +// for (int certVersion : {1, 2}) { +// Name certName = keyName; +// certName +// .append("issuer") +// .appendVersion(certVersion); +// v2::Certificate cert; +// cert.setName(certName); +// cert.setFreshnessPeriod(1_h); +// cert.setContent(tpm.getPublicKey(keyName)); + +// // @TODO sign using the new KeyChain +// SignatureInfo info; +// info.setSignatureType(tlv::SignatureSha256WithEcdsa); +// info.setKeyLocator(KeyLocator(keyName)); +// info.setValidityPeriod(ValidityPeriod(time::fromIsoString("20170102T000000"), +// time::fromIsoString("20180102T000000"))); +// cert.setSignature(Signature(info, Block())); + +// EncodingBuffer buf; +// cert.wireEncode(buf, true); + +// cert.setSignatureValue(Block(tlv::SignatureValue, +// tpm.sign(buf.buf(), buf.size(), keyName, DigestAlgorithm::SHA256))); + +// printBytes(prefix + "_KEY" + to_string(keyId) + "_CERT" + to_string(certVersion), +// cert.wireEncode()); +// } +// } +// } + +// static void +// printBytes(const std::string& name, const Block& block) +// { +// printBytes(name, block.wire(), block.size()); +// } + +// static void +// printBytes(const std::string& name, const Buffer& buffer) +// { +// printBytes(name, buffer.buf(), buffer.size()); +// } + +// static void +// printBytes(const std::string& name, const uint8_t* buf, size_t size) +// { +// std::cout << "\nconst uint8_t " << name << "[] = {\n" +// << " "; + +// std::string hex = toHex(buf, size); + +// for (size_t i = 0; i < hex.size(); i++) { +// if (i > 0 && i % 40 == 0) +// std::cout << "\n "; + +// std::cout << "0x" << hex[i]; +// std::cout << hex[++i]; + +// if ((i + 1) != hex.size()) +// std::cout << ", "; +// } +// std::cout << "\n" +// << "};" << std::endl; +// } + +// public: +// pib::PibMemory pib; +// Tpm tpm; +// }; + +// // The test data can be generated using this test case +// BOOST_FIXTURE_TEST_CASE(GenerateTestCertData, TestCertDataGenerator) +// { +// printTestDataForId("ID1", Name("/pib/interface/id/1")); +// printTestDataForId("ID2", Name("/pib/interface/id/2")); +// } + +const uint8_t ID1_KEY1_CERT1[] = { + 0x06, 0xFD, 0x02, 0x25, 0x07, 0x2B, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x31, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x01, 0x01, 0x08, 0x06, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x08, 0x02, 0xFD, 0x01, 0x14, 0x09, 0x18, 0x01, 0x02, 0x19, 0x04, 0x00, 0x36, 0xEE, 0x80, + 0x15, 0xFD, 0x01, 0x4F, 0x30, 0x82, 0x01, 0x4B, 0x30, 0x82, 0x01, 0x03, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, + 0x01, 0x30, 0x81, 0xF7, 0x02, 0x01, 0x01, 0x30, 0x2C, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01, 0x01, 0x02, 0x21, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x5B, 0x04, 0x20, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x04, 0x20, 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, + 0xEB, 0xBD, 0x55, 0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, 0x3B, 0xCE, 0x3C, 0x3E, 0x27, + 0xD2, 0x60, 0x4B, 0x03, 0x15, 0x00, 0xC4, 0x9D, 0x36, 0x08, 0x86, 0xE7, 0x04, 0x93, 0x6A, 0x66, 0x78, 0xE1, 0x13, 0x9D, + 0x26, 0xB7, 0x81, 0x9F, 0x7E, 0x90, 0x04, 0x41, 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, + 0xE5, 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, + 0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16, 0x2B, 0xCE, 0x33, + 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, + 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51, 0x02, 0x01, 0x01, 0x03, 0x42, 0x00, 0x04, 0xCB, 0x46, 0xF7, 0x16, 0x2E, + 0x83, 0x3D, 0x5E, 0x4A, 0x80, 0x6A, 0x78, 0xB7, 0xA8, 0x7A, 0x15, 0x95, 0x2D, 0x23, 0xA8, 0x41, 0xF7, 0x62, 0xE4, 0x0E, + 0x66, 0x36, 0xB3, 0xF3, 0x14, 0xD6, 0xB3, 0xAB, 0x19, 0x26, 0x9D, 0x5A, 0x8A, 0x51, 0xD4, 0x4E, 0xBA, 0xBE, 0x13, 0x96, + 0xCA, 0x38, 0x52, 0x16, 0xE4, 0x3D, 0xB0, 0x88, 0xBA, 0xBB, 0x7B, 0x97, 0x00, 0xA5, 0x95, 0x97, 0x4E, 0xE8, 0xF6, 0x16, + 0x50, 0x1B, 0x01, 0x03, 0x1C, 0x21, 0x07, 0x1F, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, + 0x66, 0x61, 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x31, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x01, 0x01, 0xFD, + 0x00, 0xFD, 0x26, 0xFD, 0x00, 0xFE, 0x0F, 0x32, 0x30, 0x31, 0x37, 0x30, 0x31, 0x30, 0x32, 0x54, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0xFD, 0x00, 0xFF, 0x0F, 0x32, 0x30, 0x31, 0x38, 0x30, 0x31, 0x30, 0x32, 0x54, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x17, 0x46, 0x30, 0x44, 0x02, 0x20, 0x53, 0xC8, 0xAD, 0x88, 0xBA, 0x52, 0x29, 0x68, 0xFF, 0x74, 0xA8, 0x39, 0x7F, + 0x2C, 0xE2, 0x8E, 0x04, 0xC1, 0x78, 0x36, 0x46, 0x89, 0x38, 0x58, 0x45, 0x22, 0x44, 0xA3, 0xC8, 0xC1, 0xFF, 0x72, 0x02, + 0x20, 0x23, 0x9D, 0xE4, 0x92, 0x00, 0xF1, 0x43, 0x69, 0xF7, 0x32, 0xF6, 0xAA, 0x8C, 0xFD, 0x7F, 0x2B, 0xFB, 0xD2, 0x40, + 0x6A, 0x1E, 0xA3, 0xE5, 0xF0, 0xF8, 0x2B, 0x92, 0x99, 0x6B, 0xDB, 0xE2, 0x6D +}; + +const uint8_t ID1_KEY1_CERT2[] = { + 0x06, 0xFD, 0x02, 0x26, 0x07, 0x2B, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x31, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x01, 0x01, 0x08, 0x06, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x08, 0x02, 0xFD, 0x02, 0x14, 0x09, 0x18, 0x01, 0x02, 0x19, 0x04, 0x00, 0x36, 0xEE, 0x80, + 0x15, 0xFD, 0x01, 0x4F, 0x30, 0x82, 0x01, 0x4B, 0x30, 0x82, 0x01, 0x03, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, + 0x01, 0x30, 0x81, 0xF7, 0x02, 0x01, 0x01, 0x30, 0x2C, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01, 0x01, 0x02, 0x21, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x5B, 0x04, 0x20, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x04, 0x20, 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, + 0xEB, 0xBD, 0x55, 0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, 0x3B, 0xCE, 0x3C, 0x3E, 0x27, + 0xD2, 0x60, 0x4B, 0x03, 0x15, 0x00, 0xC4, 0x9D, 0x36, 0x08, 0x86, 0xE7, 0x04, 0x93, 0x6A, 0x66, 0x78, 0xE1, 0x13, 0x9D, + 0x26, 0xB7, 0x81, 0x9F, 0x7E, 0x90, 0x04, 0x41, 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, + 0xE5, 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, + 0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16, 0x2B, 0xCE, 0x33, + 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, + 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51, 0x02, 0x01, 0x01, 0x03, 0x42, 0x00, 0x04, 0xCB, 0x46, 0xF7, 0x16, 0x2E, + 0x83, 0x3D, 0x5E, 0x4A, 0x80, 0x6A, 0x78, 0xB7, 0xA8, 0x7A, 0x15, 0x95, 0x2D, 0x23, 0xA8, 0x41, 0xF7, 0x62, 0xE4, 0x0E, + 0x66, 0x36, 0xB3, 0xF3, 0x14, 0xD6, 0xB3, 0xAB, 0x19, 0x26, 0x9D, 0x5A, 0x8A, 0x51, 0xD4, 0x4E, 0xBA, 0xBE, 0x13, 0x96, + 0xCA, 0x38, 0x52, 0x16, 0xE4, 0x3D, 0xB0, 0x88, 0xBA, 0xBB, 0x7B, 0x97, 0x00, 0xA5, 0x95, 0x97, 0x4E, 0xE8, 0xF6, 0x16, + 0x50, 0x1B, 0x01, 0x03, 0x1C, 0x21, 0x07, 0x1F, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, + 0x66, 0x61, 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x31, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x01, 0x01, 0xFD, + 0x00, 0xFD, 0x26, 0xFD, 0x00, 0xFE, 0x0F, 0x32, 0x30, 0x31, 0x37, 0x30, 0x31, 0x30, 0x32, 0x54, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0xFD, 0x00, 0xFF, 0x0F, 0x32, 0x30, 0x31, 0x38, 0x30, 0x31, 0x30, 0x32, 0x54, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x17, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xB2, 0x93, 0xCD, 0x3D, 0x01, 0x00, 0xB5, 0xF1, 0x75, 0x22, 0x68, 0x9F, + 0xE4, 0x5E, 0x0A, 0x76, 0x34, 0xBC, 0x9D, 0xCF, 0x9A, 0x4C, 0x21, 0x3F, 0xA5, 0x12, 0x51, 0xF7, 0x3A, 0x5E, 0x37, 0x7D, + 0x02, 0x20, 0x33, 0xA9, 0xA9, 0x8F, 0xD8, 0x2E, 0xED, 0x3C, 0xE5, 0x18, 0x94, 0x59, 0x28, 0xEA, 0x82, 0x38, 0x5B, 0x20, + 0xE4, 0xBF, 0x15, 0xF4, 0x0D, 0x45, 0xAE, 0x8B, 0x63, 0x19, 0x79, 0x78, 0x50, 0x3A +}; + +const uint8_t ID1_KEY2_CERT1[] = { + 0x06, 0xFD, 0x02, 0x25, 0x07, 0x2B, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x31, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x01, 0x02, 0x08, 0x06, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x08, 0x02, 0xFD, 0x01, 0x14, 0x09, 0x18, 0x01, 0x02, 0x19, 0x04, 0x00, 0x36, 0xEE, 0x80, + 0x15, 0xFD, 0x01, 0x4F, 0x30, 0x82, 0x01, 0x4B, 0x30, 0x82, 0x01, 0x03, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, + 0x01, 0x30, 0x81, 0xF7, 0x02, 0x01, 0x01, 0x30, 0x2C, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01, 0x01, 0x02, 0x21, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x5B, 0x04, 0x20, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x04, 0x20, 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, + 0xEB, 0xBD, 0x55, 0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, 0x3B, 0xCE, 0x3C, 0x3E, 0x27, + 0xD2, 0x60, 0x4B, 0x03, 0x15, 0x00, 0xC4, 0x9D, 0x36, 0x08, 0x86, 0xE7, 0x04, 0x93, 0x6A, 0x66, 0x78, 0xE1, 0x13, 0x9D, + 0x26, 0xB7, 0x81, 0x9F, 0x7E, 0x90, 0x04, 0x41, 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, + 0xE5, 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, + 0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16, 0x2B, 0xCE, 0x33, + 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, + 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51, 0x02, 0x01, 0x01, 0x03, 0x42, 0x00, 0x04, 0x34, 0xAA, 0x4B, 0x1A, 0x97, + 0x4A, 0x6B, 0x6F, 0x3F, 0xB3, 0xC9, 0xD1, 0x39, 0x9F, 0x1E, 0x49, 0xB6, 0x6E, 0x19, 0x97, 0x13, 0x5E, 0xFA, 0xE6, 0xD3, + 0xFE, 0xF3, 0xB0, 0xCA, 0x80, 0x09, 0x31, 0xCA, 0x50, 0x5C, 0xE6, 0x57, 0xBF, 0x13, 0x16, 0xCE, 0x3E, 0xF1, 0xD4, 0x23, + 0xF8, 0x7F, 0x31, 0xFA, 0x13, 0x39, 0x09, 0xED, 0xC6, 0x74, 0x3D, 0xFD, 0x1A, 0x0B, 0xC7, 0xC1, 0x01, 0x15, 0x7F, 0x16, + 0x50, 0x1B, 0x01, 0x03, 0x1C, 0x21, 0x07, 0x1F, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, + 0x66, 0x61, 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x31, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x01, 0x02, 0xFD, + 0x00, 0xFD, 0x26, 0xFD, 0x00, 0xFE, 0x0F, 0x32, 0x30, 0x31, 0x37, 0x30, 0x31, 0x30, 0x32, 0x54, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0xFD, 0x00, 0xFF, 0x0F, 0x32, 0x30, 0x31, 0x38, 0x30, 0x31, 0x30, 0x32, 0x54, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x17, 0x46, 0x30, 0x44, 0x02, 0x20, 0x71, 0x3A, 0xB4, 0x19, 0x4B, 0xB3, 0x25, 0xA5, 0x03, 0x23, 0x8C, 0xC1, 0xB9, + 0x68, 0xC1, 0x41, 0x4B, 0xED, 0x13, 0xCC, 0x87, 0x16, 0xB5, 0x13, 0x87, 0xA0, 0x54, 0xA2, 0x9F, 0xF0, 0xD7, 0x72, 0x02, + 0x20, 0x4B, 0xEF, 0xB5, 0x6A, 0x8C, 0x40, 0x71, 0x17, 0xD2, 0x4F, 0xB6, 0x0F, 0xBE, 0x60, 0x1A, 0x46, 0x9B, 0x78, 0x15, + 0x46, 0x09, 0xC2, 0x7A, 0x80, 0xD4, 0xE6, 0x71, 0x52, 0xD6, 0x83, 0x4B, 0x04 +}; + +const uint8_t ID1_KEY2_CERT2[] = { + 0x06, 0xFD, 0x02, 0x26, 0x07, 0x2B, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x31, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x01, 0x02, 0x08, 0x06, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x08, 0x02, 0xFD, 0x02, 0x14, 0x09, 0x18, 0x01, 0x02, 0x19, 0x04, 0x00, 0x36, 0xEE, 0x80, + 0x15, 0xFD, 0x01, 0x4F, 0x30, 0x82, 0x01, 0x4B, 0x30, 0x82, 0x01, 0x03, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, + 0x01, 0x30, 0x81, 0xF7, 0x02, 0x01, 0x01, 0x30, 0x2C, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01, 0x01, 0x02, 0x21, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x5B, 0x04, 0x20, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x04, 0x20, 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, + 0xEB, 0xBD, 0x55, 0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, 0x3B, 0xCE, 0x3C, 0x3E, 0x27, + 0xD2, 0x60, 0x4B, 0x03, 0x15, 0x00, 0xC4, 0x9D, 0x36, 0x08, 0x86, 0xE7, 0x04, 0x93, 0x6A, 0x66, 0x78, 0xE1, 0x13, 0x9D, + 0x26, 0xB7, 0x81, 0x9F, 0x7E, 0x90, 0x04, 0x41, 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, + 0xE5, 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, + 0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16, 0x2B, 0xCE, 0x33, + 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, + 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51, 0x02, 0x01, 0x01, 0x03, 0x42, 0x00, 0x04, 0x34, 0xAA, 0x4B, 0x1A, 0x97, + 0x4A, 0x6B, 0x6F, 0x3F, 0xB3, 0xC9, 0xD1, 0x39, 0x9F, 0x1E, 0x49, 0xB6, 0x6E, 0x19, 0x97, 0x13, 0x5E, 0xFA, 0xE6, 0xD3, + 0xFE, 0xF3, 0xB0, 0xCA, 0x80, 0x09, 0x31, 0xCA, 0x50, 0x5C, 0xE6, 0x57, 0xBF, 0x13, 0x16, 0xCE, 0x3E, 0xF1, 0xD4, 0x23, + 0xF8, 0x7F, 0x31, 0xFA, 0x13, 0x39, 0x09, 0xED, 0xC6, 0x74, 0x3D, 0xFD, 0x1A, 0x0B, 0xC7, 0xC1, 0x01, 0x15, 0x7F, 0x16, + 0x50, 0x1B, 0x01, 0x03, 0x1C, 0x21, 0x07, 0x1F, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, + 0x66, 0x61, 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x31, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x01, 0x02, 0xFD, + 0x00, 0xFD, 0x26, 0xFD, 0x00, 0xFE, 0x0F, 0x32, 0x30, 0x31, 0x37, 0x30, 0x31, 0x30, 0x32, 0x54, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0xFD, 0x00, 0xFF, 0x0F, 0x32, 0x30, 0x31, 0x38, 0x30, 0x31, 0x30, 0x32, 0x54, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x17, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xD2, 0x90, 0x8C, 0xA3, 0x52, 0x2F, 0x79, 0xB3, 0xD7, 0x39, 0xE1, 0x6C, + 0x7F, 0xA0, 0xDF, 0xD1, 0x3E, 0x0F, 0x70, 0xBE, 0xF5, 0xDB, 0x08, 0xDF, 0xE1, 0x0B, 0xDF, 0x79, 0x99, 0xFE, 0x5C, 0xDC, + 0x02, 0x20, 0x3D, 0xD4, 0x7C, 0xD1, 0x83, 0xBE, 0x29, 0xBB, 0x73, 0xA3, 0x82, 0xE5, 0xE6, 0x83, 0xA1, 0xC1, 0xBC, 0xF6, + 0x84, 0x42, 0x85, 0x00, 0x92, 0x4B, 0xA2, 0xA8, 0xCA, 0x10, 0x7B, 0x92, 0x89, 0xB0 +}; + +const uint8_t ID2_KEY1_CERT1[] = { + 0x06, 0xFD, 0x02, 0x25, 0x07, 0x2B, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x32, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x01, 0x01, 0x08, 0x06, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x08, 0x02, 0xFD, 0x01, 0x14, 0x09, 0x18, 0x01, 0x02, 0x19, 0x04, 0x00, 0x36, 0xEE, 0x80, + 0x15, 0xFD, 0x01, 0x4F, 0x30, 0x82, 0x01, 0x4B, 0x30, 0x82, 0x01, 0x03, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, + 0x01, 0x30, 0x81, 0xF7, 0x02, 0x01, 0x01, 0x30, 0x2C, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01, 0x01, 0x02, 0x21, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x5B, 0x04, 0x20, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x04, 0x20, 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, + 0xEB, 0xBD, 0x55, 0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, 0x3B, 0xCE, 0x3C, 0x3E, 0x27, + 0xD2, 0x60, 0x4B, 0x03, 0x15, 0x00, 0xC4, 0x9D, 0x36, 0x08, 0x86, 0xE7, 0x04, 0x93, 0x6A, 0x66, 0x78, 0xE1, 0x13, 0x9D, + 0x26, 0xB7, 0x81, 0x9F, 0x7E, 0x90, 0x04, 0x41, 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, + 0xE5, 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, + 0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16, 0x2B, 0xCE, 0x33, + 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, + 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51, 0x02, 0x01, 0x01, 0x03, 0x42, 0x00, 0x04, 0xAC, 0x62, 0xD7, 0x31, 0x3B, + 0x19, 0x1F, 0x44, 0x76, 0x6E, 0x79, 0x03, 0xB9, 0xC8, 0x26, 0xC4, 0x1E, 0x38, 0x3A, 0x41, 0xFE, 0xB4, 0x72, 0xA2, 0x36, + 0xBB, 0x82, 0x9C, 0xB9, 0x07, 0x62, 0x6F, 0x1C, 0x79, 0x12, 0xCA, 0x9C, 0x3D, 0xAA, 0x7A, 0x96, 0xFF, 0xAF, 0x5B, 0x6F, + 0xE1, 0x72, 0x60, 0xB0, 0x7F, 0x44, 0x38, 0x05, 0x21, 0xCC, 0x49, 0x78, 0x89, 0xC1, 0xEF, 0xEE, 0x81, 0x8E, 0xF5, 0x16, + 0x50, 0x1B, 0x01, 0x03, 0x1C, 0x21, 0x07, 0x1F, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, + 0x66, 0x61, 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x32, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x01, 0x01, 0xFD, + 0x00, 0xFD, 0x26, 0xFD, 0x00, 0xFE, 0x0F, 0x32, 0x30, 0x31, 0x37, 0x30, 0x31, 0x30, 0x32, 0x54, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0xFD, 0x00, 0xFF, 0x0F, 0x32, 0x30, 0x31, 0x38, 0x30, 0x31, 0x30, 0x32, 0x54, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x17, 0x46, 0x30, 0x44, 0x02, 0x20, 0x16, 0xC0, 0xF4, 0xE3, 0x15, 0x43, 0x6E, 0x27, 0x33, 0x7C, 0x46, 0x4D, 0x35, + 0xA7, 0x8B, 0x0C, 0xE3, 0x27, 0x63, 0x4B, 0xB2, 0xB6, 0x4F, 0x06, 0x90, 0x2A, 0xD8, 0x54, 0x92, 0xE8, 0xBA, 0xBE, 0x02, + 0x20, 0x67, 0xA6, 0x55, 0x8D, 0x16, 0x0E, 0x1E, 0x9E, 0x10, 0x0E, 0xB9, 0x3C, 0xEF, 0xEE, 0xB5, 0xF7, 0x9C, 0xB3, 0x1D, + 0x04, 0xF1, 0xD4, 0xB5, 0x9F, 0xD4, 0x13, 0xBB, 0xFF, 0xA7, 0x58, 0xAE, 0xCB +}; + +const uint8_t ID2_KEY1_CERT2[] = { + 0x06, 0xFD, 0x02, 0x26, 0x07, 0x2B, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x32, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x01, 0x01, 0x08, 0x06, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x08, 0x02, 0xFD, 0x02, 0x14, 0x09, 0x18, 0x01, 0x02, 0x19, 0x04, 0x00, 0x36, 0xEE, 0x80, + 0x15, 0xFD, 0x01, 0x4F, 0x30, 0x82, 0x01, 0x4B, 0x30, 0x82, 0x01, 0x03, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, + 0x01, 0x30, 0x81, 0xF7, 0x02, 0x01, 0x01, 0x30, 0x2C, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01, 0x01, 0x02, 0x21, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x5B, 0x04, 0x20, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x04, 0x20, 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, + 0xEB, 0xBD, 0x55, 0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, 0x3B, 0xCE, 0x3C, 0x3E, 0x27, + 0xD2, 0x60, 0x4B, 0x03, 0x15, 0x00, 0xC4, 0x9D, 0x36, 0x08, 0x86, 0xE7, 0x04, 0x93, 0x6A, 0x66, 0x78, 0xE1, 0x13, 0x9D, + 0x26, 0xB7, 0x81, 0x9F, 0x7E, 0x90, 0x04, 0x41, 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, + 0xE5, 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, + 0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16, 0x2B, 0xCE, 0x33, + 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, + 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51, 0x02, 0x01, 0x01, 0x03, 0x42, 0x00, 0x04, 0xAC, 0x62, 0xD7, 0x31, 0x3B, + 0x19, 0x1F, 0x44, 0x76, 0x6E, 0x79, 0x03, 0xB9, 0xC8, 0x26, 0xC4, 0x1E, 0x38, 0x3A, 0x41, 0xFE, 0xB4, 0x72, 0xA2, 0x36, + 0xBB, 0x82, 0x9C, 0xB9, 0x07, 0x62, 0x6F, 0x1C, 0x79, 0x12, 0xCA, 0x9C, 0x3D, 0xAA, 0x7A, 0x96, 0xFF, 0xAF, 0x5B, 0x6F, + 0xE1, 0x72, 0x60, 0xB0, 0x7F, 0x44, 0x38, 0x05, 0x21, 0xCC, 0x49, 0x78, 0x89, 0xC1, 0xEF, 0xEE, 0x81, 0x8E, 0xF5, 0x16, + 0x50, 0x1B, 0x01, 0x03, 0x1C, 0x21, 0x07, 0x1F, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, + 0x66, 0x61, 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x32, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x01, 0x01, 0xFD, + 0x00, 0xFD, 0x26, 0xFD, 0x00, 0xFE, 0x0F, 0x32, 0x30, 0x31, 0x37, 0x30, 0x31, 0x30, 0x32, 0x54, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0xFD, 0x00, 0xFF, 0x0F, 0x32, 0x30, 0x31, 0x38, 0x30, 0x31, 0x30, 0x32, 0x54, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x17, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xF2, 0x0D, 0x1D, 0x60, 0x0B, 0x2D, 0x97, 0x3A, 0x6B, 0xEE, 0xEC, 0x56, + 0xD1, 0x64, 0xBF, 0xED, 0x68, 0xB7, 0x10, 0x0B, 0xDF, 0x81, 0x29, 0xCD, 0xB0, 0xBB, 0x87, 0x0D, 0xDA, 0x12, 0x52, 0xCC, + 0x02, 0x20, 0x64, 0x33, 0x4E, 0x91, 0xAF, 0x81, 0xF4, 0xE7, 0xAD, 0x38, 0x8E, 0xBF, 0x79, 0xA7, 0x70, 0x1E, 0xD6, 0x71, + 0x7E, 0xF5, 0xEB, 0x92, 0x56, 0x5F, 0xC7, 0x05, 0xDC, 0x27, 0xE5, 0x11, 0xC2, 0x43 +}; + +const uint8_t ID2_KEY2_CERT1[] = { + 0x06, 0xFD, 0x02, 0x26, 0x07, 0x2B, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x32, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x01, 0x02, 0x08, 0x06, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x08, 0x02, 0xFD, 0x01, 0x14, 0x09, 0x18, 0x01, 0x02, 0x19, 0x04, 0x00, 0x36, 0xEE, 0x80, + 0x15, 0xFD, 0x01, 0x4F, 0x30, 0x82, 0x01, 0x4B, 0x30, 0x82, 0x01, 0x03, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, + 0x01, 0x30, 0x81, 0xF7, 0x02, 0x01, 0x01, 0x30, 0x2C, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01, 0x01, 0x02, 0x21, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x5B, 0x04, 0x20, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x04, 0x20, 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, + 0xEB, 0xBD, 0x55, 0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, 0x3B, 0xCE, 0x3C, 0x3E, 0x27, + 0xD2, 0x60, 0x4B, 0x03, 0x15, 0x00, 0xC4, 0x9D, 0x36, 0x08, 0x86, 0xE7, 0x04, 0x93, 0x6A, 0x66, 0x78, 0xE1, 0x13, 0x9D, + 0x26, 0xB7, 0x81, 0x9F, 0x7E, 0x90, 0x04, 0x41, 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, + 0xE5, 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, + 0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16, 0x2B, 0xCE, 0x33, + 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, + 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51, 0x02, 0x01, 0x01, 0x03, 0x42, 0x00, 0x04, 0x2C, 0xC3, 0xAF, 0xA8, 0x73, + 0xF2, 0x61, 0xCF, 0x48, 0x04, 0x0F, 0x9D, 0xD3, 0xAF, 0x0B, 0xC6, 0x2F, 0x4D, 0xDA, 0x0E, 0x4C, 0x66, 0x1D, 0x03, 0x9D, + 0xFE, 0x2C, 0x0B, 0xB6, 0x25, 0x60, 0xBC, 0xFA, 0xDA, 0xFE, 0x6F, 0x43, 0xFA, 0x95, 0x45, 0x57, 0x8A, 0x25, 0xEC, 0x0F, + 0xF2, 0xB7, 0x43, 0x85, 0x0D, 0x0B, 0x8D, 0x97, 0x40, 0x83, 0x4C, 0x28, 0x1B, 0xD4, 0x2E, 0x99, 0x2C, 0x73, 0x7D, 0x16, + 0x50, 0x1B, 0x01, 0x03, 0x1C, 0x21, 0x07, 0x1F, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, + 0x66, 0x61, 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x32, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x01, 0x02, 0xFD, + 0x00, 0xFD, 0x26, 0xFD, 0x00, 0xFE, 0x0F, 0x32, 0x30, 0x31, 0x37, 0x30, 0x31, 0x30, 0x32, 0x54, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0xFD, 0x00, 0xFF, 0x0F, 0x32, 0x30, 0x31, 0x38, 0x30, 0x31, 0x30, 0x32, 0x54, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x17, 0x47, 0x30, 0x45, 0x02, 0x20, 0x56, 0x34, 0x49, 0xAC, 0x72, 0x4E, 0x58, 0x24, 0x6F, 0x14, 0xEE, 0xD3, 0x01, + 0x5B, 0xD4, 0x0A, 0x26, 0x2B, 0x6A, 0xD1, 0xB3, 0x33, 0x69, 0x4D, 0x64, 0x0C, 0xAA, 0xAE, 0x63, 0x59, 0x6A, 0xFD, 0x02, + 0x21, 0x00, 0xFD, 0xB9, 0x9E, 0x37, 0x70, 0x9C, 0xE2, 0x7A, 0x0A, 0xFD, 0x64, 0x99, 0x1B, 0xA3, 0x78, 0x83, 0x09, 0xC6, + 0xA0, 0x6D, 0x7A, 0x55, 0x8F, 0x6C, 0x35, 0xAB, 0x63, 0x78, 0x9D, 0xF3, 0xDC, 0xBC +}; + +const uint8_t ID2_KEY2_CERT2[] = { + 0x06, 0xFD, 0x02, 0x27, 0x07, 0x2B, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x32, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x01, 0x02, 0x08, 0x06, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x08, 0x02, 0xFD, 0x02, 0x14, 0x09, 0x18, 0x01, 0x02, 0x19, 0x04, 0x00, 0x36, 0xEE, 0x80, + 0x15, 0xFD, 0x01, 0x4F, 0x30, 0x82, 0x01, 0x4B, 0x30, 0x82, 0x01, 0x03, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, + 0x01, 0x30, 0x81, 0xF7, 0x02, 0x01, 0x01, 0x30, 0x2C, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01, 0x01, 0x02, 0x21, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x5B, 0x04, 0x20, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x04, 0x20, 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, + 0xEB, 0xBD, 0x55, 0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, 0x3B, 0xCE, 0x3C, 0x3E, 0x27, + 0xD2, 0x60, 0x4B, 0x03, 0x15, 0x00, 0xC4, 0x9D, 0x36, 0x08, 0x86, 0xE7, 0x04, 0x93, 0x6A, 0x66, 0x78, 0xE1, 0x13, 0x9D, + 0x26, 0xB7, 0x81, 0x9F, 0x7E, 0x90, 0x04, 0x41, 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, + 0xE5, 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, + 0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16, 0x2B, 0xCE, 0x33, + 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, + 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51, 0x02, 0x01, 0x01, 0x03, 0x42, 0x00, 0x04, 0x2C, 0xC3, 0xAF, 0xA8, 0x73, + 0xF2, 0x61, 0xCF, 0x48, 0x04, 0x0F, 0x9D, 0xD3, 0xAF, 0x0B, 0xC6, 0x2F, 0x4D, 0xDA, 0x0E, 0x4C, 0x66, 0x1D, 0x03, 0x9D, + 0xFE, 0x2C, 0x0B, 0xB6, 0x25, 0x60, 0xBC, 0xFA, 0xDA, 0xFE, 0x6F, 0x43, 0xFA, 0x95, 0x45, 0x57, 0x8A, 0x25, 0xEC, 0x0F, + 0xF2, 0xB7, 0x43, 0x85, 0x0D, 0x0B, 0x8D, 0x97, 0x40, 0x83, 0x4C, 0x28, 0x1B, 0xD4, 0x2E, 0x99, 0x2C, 0x73, 0x7D, 0x16, + 0x50, 0x1B, 0x01, 0x03, 0x1C, 0x21, 0x07, 0x1F, 0x08, 0x03, 0x70, 0x69, 0x62, 0x08, 0x09, 0x69, 0x6E, 0x74, 0x65, 0x72, + 0x66, 0x61, 0x63, 0x65, 0x08, 0x02, 0x69, 0x64, 0x08, 0x01, 0x32, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x01, 0x02, 0xFD, + 0x00, 0xFD, 0x26, 0xFD, 0x00, 0xFE, 0x0F, 0x32, 0x30, 0x31, 0x37, 0x30, 0x31, 0x30, 0x32, 0x54, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0xFD, 0x00, 0xFF, 0x0F, 0x32, 0x30, 0x31, 0x38, 0x30, 0x31, 0x30, 0x32, 0x54, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x17, 0x48, 0x30, 0x46, 0x02, 0x21, 0x00, 0xB3, 0xF5, 0x96, 0x19, 0xE7, 0xF9, 0x6B, 0xCF, 0x14, 0x64, 0xB1, 0x08, + 0xFA, 0xFF, 0xB3, 0x52, 0x8B, 0x41, 0xCB, 0xE7, 0xE0, 0x3D, 0x14, 0x7B, 0xC2, 0xD0, 0xC8, 0x89, 0x88, 0xFA, 0x95, 0x73, + 0x02, 0x21, 0x00, 0xEC, 0x8E, 0x0C, 0x8B, 0x8C, 0x18, 0x8D, 0x00, 0x7C, 0x12, 0x68, 0x57, 0x87, 0xB1, 0x99, 0x69, 0xDA, + 0x46, 0xEF, 0x14, 0x2D, 0x04, 0x18, 0xBE, 0x1D, 0xAE, 0x79, 0x49, 0xFD, 0x22, 0x8E, 0xBB +}; + +PibDataFixture::PibDataFixture() + : id1Key1Cert1(Block(ID1_KEY1_CERT1, sizeof(ID1_KEY1_CERT1))) + , id1Key1Cert2(Block(ID1_KEY1_CERT2, sizeof(ID1_KEY1_CERT2))) + , id1Key2Cert1(Block(ID1_KEY2_CERT1, sizeof(ID1_KEY2_CERT1))) + , id1Key2Cert2(Block(ID1_KEY2_CERT2, sizeof(ID1_KEY2_CERT2))) + + , id2Key1Cert1(Block(ID2_KEY1_CERT1, sizeof(ID2_KEY1_CERT1))) + , id2Key1Cert2(Block(ID2_KEY1_CERT2, sizeof(ID2_KEY1_CERT2))) + , id2Key2Cert1(Block(ID2_KEY2_CERT1, sizeof(ID2_KEY2_CERT1))) + , id2Key2Cert2(Block(ID2_KEY2_CERT2, sizeof(ID2_KEY2_CERT2))) + + , id1(id1Key1Cert1.getIdentity()) + , id2(id2Key1Cert1.getIdentity()) + + , id1Key1Name(id1Key1Cert1.getKeyName()) + , id1Key2Name(id1Key2Cert1.getKeyName()) + + , id2Key1Name(id2Key1Cert1.getKeyName()) + , id2Key2Name(id2Key2Cert1.getKeyName()) + + , id1Key1(id1Key1Cert1.getPublicKey()) + , id1Key2(id1Key2Cert1.getPublicKey()) + , id2Key1(id2Key1Cert1.getPublicKey()) + , id2Key2(id2Key2Cert1.getPublicKey()) +{ + BOOST_ASSERT(id1Key1Cert1.getPublicKey() == id1Key1Cert2.getPublicKey()); + BOOST_ASSERT(id1Key2Cert1.getPublicKey() == id1Key2Cert2.getPublicKey()); + BOOST_ASSERT(id2Key1Cert1.getPublicKey() == id2Key1Cert2.getPublicKey()); + BOOST_ASSERT(id2Key2Cert1.getPublicKey() == id2Key2Cert2.getPublicKey()); + + BOOST_ASSERT(id1Key1Cert1.getPublicKey() == id1Key1); + BOOST_ASSERT(id1Key1Cert2.getPublicKey() == id1Key1); + BOOST_ASSERT(id1Key2Cert1.getPublicKey() == id1Key2); + BOOST_ASSERT(id1Key2Cert2.getPublicKey() == id1Key2); + + BOOST_ASSERT(id2Key1Cert1.getPublicKey() == id2Key1); + BOOST_ASSERT(id2Key1Cert2.getPublicKey() == id2Key1); + BOOST_ASSERT(id2Key2Cert1.getPublicKey() == id2Key2); + BOOST_ASSERT(id2Key2Cert2.getPublicKey() == id2Key2); + + BOOST_ASSERT(id1Key1Cert2.getIdentity() == id1); + BOOST_ASSERT(id1Key2Cert1.getIdentity() == id1); + BOOST_ASSERT(id1Key2Cert2.getIdentity() == id1); + + BOOST_ASSERT(id2Key1Cert2.getIdentity() == id2); + BOOST_ASSERT(id2Key2Cert1.getIdentity() == id2); + BOOST_ASSERT(id2Key2Cert2.getIdentity() == id2); + + BOOST_ASSERT(id1Key1Cert2.getKeyName() == id1Key1Name); + BOOST_ASSERT(id1Key2Cert2.getKeyName() == id1Key2Name); + + BOOST_ASSERT(id2Key1Cert2.getKeyName() == id2Key1Name); + BOOST_ASSERT(id2Key2Cert2.getKeyName() == id2Key2Name); +} + +} // namespace tests +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/pib/pib-data-fixture.hpp b/tests/unit/security/pib/pib-data-fixture.hpp new file mode 100644 index 000000000..21af85022 --- /dev/null +++ b/tests/unit/security/pib/pib-data-fixture.hpp @@ -0,0 +1,64 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TESTS_UNIT_SECURITY_PIB_DATA_FIXTURE_HPP +#define NDN_TESTS_UNIT_SECURITY_PIB_DATA_FIXTURE_HPP + +#include "ndn-cxx/security/v2/certificate.hpp" + +namespace ndn { +namespace security { +namespace tests { + +class PibDataFixture +{ +public: + PibDataFixture(); + +public: + v2::Certificate id1Key1Cert1; + v2::Certificate id1Key1Cert2; + v2::Certificate id1Key2Cert1; + v2::Certificate id1Key2Cert2; + v2::Certificate id2Key1Cert1; + v2::Certificate id2Key1Cert2; + v2::Certificate id2Key2Cert1; + v2::Certificate id2Key2Cert2; + + Name id1; + Name id2; + + Name id1Key1Name; + Name id1Key2Name; + Name id2Key1Name; + Name id2Key2Name; + + Buffer id1Key1; + Buffer id1Key2; + Buffer id2Key1; + Buffer id2Key2; +}; + +} // namespace tests +} // namespace security +} // namespace ndn + +#endif // NDN_TESTS_UNIT_SECURITY_PIB_DATA_FIXTURE_HPP diff --git a/tests/unit/security/pib/pib-impl.t.cpp b/tests/unit/security/pib/pib-impl.t.cpp new file mode 100644 index 000000000..500e5fd71 --- /dev/null +++ b/tests/unit/security/pib/pib-impl.t.cpp @@ -0,0 +1,352 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/impl/pib-memory.hpp" +#include "ndn-cxx/security/pib/impl/pib-sqlite3.hpp" +#include "ndn-cxx/security/pib/pib.hpp" +#include "ndn-cxx/security/security-common.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/pib/pib-data-fixture.hpp" + +#include +#include + +namespace ndn { +namespace security { +namespace pib { +namespace tests { + +using namespace ndn::security::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(Pib) +BOOST_AUTO_TEST_SUITE(TestPibImpl) + +using pib::Pib; + +class PibMemoryFixture : public PibDataFixture +{ +public: + PibMemory pib; +}; + +class PibSqlite3Fixture : public PibDataFixture +{ +public: + PibSqlite3Fixture() + : tmpPath(boost::filesystem::path(UNIT_TEST_CONFIG_PATH) / "DbTest") + , pib(tmpPath.c_str()) + { + } + + ~PibSqlite3Fixture() + { + boost::filesystem::remove_all(tmpPath); + } + +public: + boost::filesystem::path tmpPath; + PibSqlite3 pib; +}; + +using PibImpls = boost::mpl::vector; + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(TpmLocator, T, PibImpls, T) +{ + // Basic getting and setting + BOOST_CHECK_NO_THROW(this->pib.getTpmLocator()); + + BOOST_CHECK_NO_THROW(this->pib.setTpmLocator("tpmLocator")); + BOOST_CHECK_EQUAL(this->pib.getTpmLocator(), "tpmLocator"); + + // Add cert, and do not change TPM locator + this->pib.addCertificate(this->id1Key1Cert1); + BOOST_CHECK(this->pib.hasIdentity(this->id1)); + BOOST_CHECK(this->pib.hasKey(this->id1Key1Name)); + BOOST_CHECK(this->pib.hasCertificate(this->id1Key1Cert1.getName())); + + // Set TPM locator to the same value, nothing should change + this->pib.setTpmLocator("tpmLocator"); + BOOST_CHECK(this->pib.hasIdentity(this->id1)); + BOOST_CHECK(this->pib.hasKey(this->id1Key1Name)); + BOOST_CHECK(this->pib.hasCertificate(this->id1Key1Cert1.getName())); + + // Change TPM locator (contents of PIB should not change) + this->pib.setTpmLocator("newTpmLocator"); + BOOST_CHECK(this->pib.hasIdentity(this->id1)); + BOOST_CHECK(this->pib.hasKey(this->id1Key1Name)); + BOOST_CHECK(this->pib.hasCertificate(this->id1Key1Cert1.getName())); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(IdentityManagement, T, PibImpls, T) +{ + // no default setting, throw Error + BOOST_CHECK_THROW(this->pib.getDefaultIdentity(), Pib::Error); + + // check id1, which should not exist + BOOST_CHECK_EQUAL(this->pib.hasIdentity(this->id1), false); + + // add id1, should be default + this->pib.addIdentity(this->id1); + BOOST_CHECK_EQUAL(this->pib.hasIdentity(this->id1), true); + BOOST_CHECK_NO_THROW(this->pib.getDefaultIdentity()); + BOOST_CHECK_EQUAL(this->pib.getDefaultIdentity(), this->id1); + + // add id2, should not be default + this->pib.addIdentity(this->id2); + BOOST_CHECK_EQUAL(this->pib.hasIdentity(this->id2), true); + BOOST_CHECK_EQUAL(this->pib.getDefaultIdentity(), this->id1); + + // set id2 explicitly as default + this->pib.setDefaultIdentity(this->id2); + BOOST_CHECK_EQUAL(this->pib.getDefaultIdentity(), this->id2); + + // remove id2, should not have default identity + this->pib.removeIdentity(this->id2); + BOOST_CHECK_EQUAL(this->pib.hasIdentity(this->id2), false); + BOOST_CHECK_THROW(this->pib.getDefaultIdentity(), Pib::Error); + + // add id2 again, should be default + this->pib.addIdentity(this->id2); + BOOST_CHECK_EQUAL(this->pib.getDefaultIdentity(), this->id2); + + // get all identities, should contain id1 and id2 + std::set idNames = this->pib.getIdentities(); + BOOST_CHECK_EQUAL(idNames.size(), 2); + BOOST_CHECK_EQUAL(idNames.count(this->id1), 1); + BOOST_CHECK_EQUAL(idNames.count(this->id2), 1); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(ClearIdentities, T, PibImpls, T) +{ + this->pib.setTpmLocator("tpmLocator"); + + // Add id, key, and cert + this->pib.addCertificate(this->id1Key1Cert1); + BOOST_CHECK(this->pib.hasIdentity(this->id1)); + BOOST_CHECK(this->pib.hasKey(this->id1Key1Name)); + BOOST_CHECK(this->pib.hasCertificate(this->id1Key1Cert1.getName())); + + // Clear identities + this->pib.clearIdentities(); + BOOST_CHECK_EQUAL(this->pib.getIdentities().size(), 0); + BOOST_CHECK_EQUAL(this->pib.getKeysOfIdentity(this->id1).size(), 0); + BOOST_CHECK_EQUAL(this->pib.getCertificatesOfKey(this->id1Key1Name).size(), 0); + BOOST_CHECK_EQUAL(this->pib.getTpmLocator(), "tpmLocator"); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(KeyManagement, T, PibImpls, T) +{ + // no default setting, throw Error + BOOST_CHECK_THROW(this->pib.getDefaultKeyOfIdentity(this->id1), Pib::Error); + + // check id1Key1, should not exist, neither should id1. + BOOST_CHECK_EQUAL(this->pib.hasKey(this->id1Key1Name), false); + BOOST_CHECK_EQUAL(this->pib.hasIdentity(this->id1), false); + + // add id1Key1, should be default, id1 should be added implicitly + this->pib.addKey(this->id1, this->id1Key1Name, this->id1Key1.data(), this->id1Key1.size()); + BOOST_CHECK_EQUAL(this->pib.hasKey(this->id1Key1Name), true); + BOOST_CHECK_EQUAL(this->pib.hasIdentity(this->id1), true); + const Buffer& keyBits = this->pib.getKeyBits(this->id1Key1Name); + BOOST_CHECK(keyBits == this->id1Key1); + BOOST_CHECK_NO_THROW(this->pib.getDefaultKeyOfIdentity(this->id1)); + BOOST_CHECK_EQUAL(this->pib.getDefaultKeyOfIdentity(this->id1), this->id1Key1Name); + + // add id1Key2, should not be default + this->pib.addKey(this->id1, this->id1Key2Name, this->id1Key2.data(), this->id1Key2.size()); + BOOST_CHECK_EQUAL(this->pib.hasKey(this->id1Key2Name), true); + BOOST_CHECK_EQUAL(this->pib.getDefaultKeyOfIdentity(this->id1), this->id1Key1Name); + + // set id1Key2 explicitly as default + this->pib.setDefaultKeyOfIdentity(this->id1, this->id1Key2Name); + BOOST_CHECK_EQUAL(this->pib.getDefaultKeyOfIdentity(this->id1), this->id1Key2Name); + + // set a non-existing key as default, throw Error + BOOST_CHECK_THROW(this->pib.setDefaultKeyOfIdentity(this->id1, Name("/non-existing")), + Pib::Error); + + // remove id1Key2, should not have default key + this->pib.removeKey(this->id1Key2Name); + BOOST_CHECK_EQUAL(this->pib.hasKey(this->id1Key2Name), false); + BOOST_CHECK_THROW(this->pib.getKeyBits(this->id1Key2Name), Pib::Error); + BOOST_CHECK_THROW(this->pib.getDefaultKeyOfIdentity(this->id1), Pib::Error); + + // add id1Key2 back, should be default + this->pib.addKey(this->id1, this->id1Key2Name, this->id1Key2.data(), this->id1Key2.size()); + BOOST_CHECK_NO_THROW(this->pib.getKeyBits(this->id1Key2Name)); + BOOST_CHECK_EQUAL(this->pib.getDefaultKeyOfIdentity(this->id1), this->id1Key2Name); + + // get all the keys: id1Key1 and id1Key2 + std::set keyNames = this->pib.getKeysOfIdentity(this->id1); + BOOST_CHECK_EQUAL(keyNames.size(), 2); + BOOST_CHECK_EQUAL(keyNames.count(this->id1Key1Name), 1); + BOOST_CHECK_EQUAL(keyNames.count(this->id1Key2Name), 1); + + // remove id1, should remove all the keys + this->pib.removeIdentity(this->id1); + keyNames = this->pib.getKeysOfIdentity(this->id1); + BOOST_CHECK_EQUAL(keyNames.size(), 0); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(CertificateManagement, T, PibImpls, T) +{ + // no default setting, throw Error + BOOST_CHECK_THROW(this->pib.getDefaultCertificateOfKey(this->id1Key1Name), Pib::Error); + + // check id1Key1Cert1, should not exist, neither should id1 and id1Key1 + BOOST_CHECK_EQUAL(this->pib.hasCertificate(this->id1Key1Cert1.getName()), false); + BOOST_CHECK_EQUAL(this->pib.hasIdentity(this->id1), false); + BOOST_CHECK_EQUAL(this->pib.hasKey(this->id1Key1Name), false); + + // add id1Key1Cert1, should be default, id1 and id1Key1 should be added implicitly + this->pib.addCertificate(this->id1Key1Cert1); + BOOST_CHECK_EQUAL(this->pib.hasCertificate(this->id1Key1Cert1.getName()), true); + BOOST_CHECK_EQUAL(this->pib.hasIdentity(this->id1), true); + BOOST_CHECK_EQUAL(this->pib.hasKey(this->id1Key1Name), true); + BOOST_CHECK_EQUAL(this->pib.getCertificate(this->id1Key1Cert1.getName()).wireEncode(), + this->id1Key1Cert1.wireEncode()); + BOOST_CHECK_NO_THROW(this->pib.getDefaultCertificateOfKey(this->id1Key1Name)); + BOOST_CHECK_EQUAL(this->pib.getDefaultCertificateOfKey(this->id1Key1Name), this->id1Key1Cert1); + + // add id1Key1Cert2, should not be default + this->pib.addCertificate(this->id1Key1Cert2); + BOOST_CHECK_EQUAL(this->pib.hasCertificate(this->id1Key1Cert2.getName()), true); + BOOST_CHECK_EQUAL(this->pib.getDefaultCertificateOfKey(this->id1Key1Name), this->id1Key1Cert1); + + // set id1Key1Cert2 explicitly as default + this->pib.setDefaultCertificateOfKey(this->id1Key1Name, this->id1Key1Cert2.getName()); + BOOST_CHECK_EQUAL(this->pib.getDefaultCertificateOfKey(this->id1Key1Name), this->id1Key1Cert2); + + // set a non-existing cert as default, throw Error + BOOST_CHECK_THROW(this->pib.setDefaultCertificateOfKey(this->id1Key1Name, Name("/non-existing")), + Pib::Error); + + // remove id1Key1Cert2, should not have default cert + this->pib.removeCertificate(this->id1Key1Cert2.getName()); + BOOST_CHECK_EQUAL(this->pib.hasCertificate(this->id1Key1Cert2.getName()), false); + BOOST_CHECK_THROW(this->pib.getCertificate(this->id1Key1Cert2.getName()), Pib::Error); + BOOST_CHECK_THROW(this->pib.getDefaultCertificateOfKey(this->id1Key1Name), Pib::Error); + + // add id1Key1Cert2, should be default + this->pib.addCertificate(this->id1Key1Cert2); + BOOST_CHECK_NO_THROW(this->pib.getCertificate(this->id1Key1Cert1.getName())); + BOOST_CHECK_EQUAL(this->pib.getDefaultCertificateOfKey(this->id1Key1Name), this->id1Key1Cert2); + + // get all certificates: id1Key1Cert1 and id1Key1Cert2 + std::set certNames = this->pib.getCertificatesOfKey(this->id1Key1Name); + BOOST_CHECK_EQUAL(certNames.size(), 2); + BOOST_CHECK_EQUAL(certNames.count(this->id1Key1Cert1.getName()), 1); + BOOST_CHECK_EQUAL(certNames.count(this->id1Key1Cert2.getName()), 1); + + // remove id1Key1, should remove all the certs + this->pib.removeKey(this->id1Key1Name); + certNames = this->pib.getCertificatesOfKey(this->id1Key1Name); + BOOST_CHECK_EQUAL(certNames.size(), 0); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(DefaultsManagement, T, PibImpls, T) +{ + this->pib.addIdentity(this->id1); + BOOST_CHECK_EQUAL(this->pib.getDefaultIdentity(), this->id1); + + this->pib.addIdentity(this->id2); + BOOST_CHECK_EQUAL(this->pib.getDefaultIdentity(), this->id1); + + this->pib.removeIdentity(this->id1); + BOOST_CHECK_THROW(this->pib.getDefaultIdentity(), Pib::Error); + + this->pib.addKey(this->id2, this->id2Key1Name, this->id2Key1.data(), this->id2Key1.size()); + BOOST_CHECK_EQUAL(this->pib.getDefaultIdentity(), this->id2); + BOOST_CHECK_EQUAL(this->pib.getDefaultKeyOfIdentity(this->id2), this->id2Key1Name); + + this->pib.addKey(this->id2, this->id2Key2Name, this->id2Key2.data(), this->id2Key2.size()); + BOOST_CHECK_EQUAL(this->pib.getDefaultKeyOfIdentity(this->id2), this->id2Key1Name); + + this->pib.removeKey(this->id2Key1Name); + BOOST_CHECK_THROW(this->pib.getDefaultKeyOfIdentity(this->id2), Pib::Error); + + this->pib.addCertificate(this->id2Key2Cert1); + BOOST_CHECK_EQUAL(this->pib.getDefaultKeyOfIdentity(this->id2), this->id2Key2Name); + BOOST_CHECK_EQUAL(this->pib.getDefaultCertificateOfKey(this->id2Key2Name).getName(), + this->id2Key2Cert1.getName()); + + this->pib.addCertificate(this->id2Key2Cert2); + BOOST_CHECK_EQUAL(this->pib.getDefaultCertificateOfKey(this->id2Key2Name).getName(), + this->id2Key2Cert1.getName()); + + this->pib.removeCertificate(this->id2Key2Cert2.getName()); + BOOST_CHECK_EQUAL(this->pib.getDefaultCertificateOfKey(this->id2Key2Name).getName(), + this->id2Key2Cert1.getName()); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(Overwrite, T, PibImpls, T) +{ + // check id1Key1, should not exist + this->pib.removeIdentity(this->id1); + BOOST_CHECK_EQUAL(this->pib.hasKey(this->id1Key1Name), false); + + // add id1Key1 + this->pib.addKey(this->id1, this->id1Key1Name, this->id1Key1.data(), this->id1Key1.size()); + BOOST_CHECK_EQUAL(this->pib.hasKey(this->id1Key1Name), true); + const Buffer& keyBits = this->pib.getKeyBits(this->id1Key1Name); + BOOST_CHECK(keyBits == this->id1Key1); + + // check overwrite, add a key with the same name. + this->pib.addKey(this->id1, this->id1Key1Name, this->id1Key2.data(), this->id1Key2.size()); + const Buffer& keyBits2 = this->pib.getKeyBits(this->id1Key1Name); + BOOST_CHECK(keyBits2 == this->id1Key2); + + // check id1Key1Cert1, should not exist + this->pib.removeIdentity(this->id1); + BOOST_CHECK_EQUAL(this->pib.hasCertificate(this->id1Key1Cert1.getName()), false); + + // add id1Key1Cert1 + this->pib.addKey(this->id1, this->id1Key1Name, this->id1Key1.data(), this->id1Key1.size()); + this->pib.addCertificate(this->id1Key1Cert1); + BOOST_CHECK_EQUAL(this->pib.hasCertificate(this->id1Key1Cert1.getName()), true); + + auto cert = this->pib.getCertificate(this->id1Key1Cert1.getName()); + BOOST_CHECK_EQUAL(cert.wireEncode(), this->id1Key1Cert1.wireEncode()); + + // Create a fake cert with the same name + auto cert2 = this->id1Key2Cert1; + cert2.setName(this->id1Key1Cert1.getName()); + cert2.setSignature(this->id1Key2Cert1.getSignature()); + this->pib.addCertificate(cert2); + + auto cert3 = this->pib.getCertificate(this->id1Key1Cert1.getName()); + BOOST_CHECK_EQUAL(cert3.wireEncode(), cert2.wireEncode()); + + // both key and certificate are overwritten + Buffer keyBits3 = this->pib.getKeyBits(this->id1Key1Name); + BOOST_CHECK(keyBits3 == this->id1Key2); +} + +BOOST_AUTO_TEST_SUITE_END() // TestPibImpl +BOOST_AUTO_TEST_SUITE_END() // Pib +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/pib/pib.t.cpp b/tests/unit/security/pib/pib.t.cpp new file mode 100644 index 000000000..c40cddcdd --- /dev/null +++ b/tests/unit/security/pib/pib.t.cpp @@ -0,0 +1,130 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/pib/pib.hpp" +#include "ndn-cxx/security/pib/impl/pib-memory.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/pib/pib-data-fixture.hpp" + +namespace ndn { +namespace security { +namespace pib { +namespace tests { + +using namespace ndn::security::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(Pib) +BOOST_FIXTURE_TEST_SUITE(TestPib, PibDataFixture) + +using pib::Pib; + +BOOST_AUTO_TEST_CASE(ValidityChecking) +{ + Pib pib("pib-memory", "", make_shared()); + + Identity id = pib.addIdentity(id1); + BOOST_CHECK(id); + BOOST_CHECK_EQUAL(!id, false); + + Key key = id.addKey(id1Key1.data(), id1Key1.size(), id1Key1Name); + BOOST_CHECK(key); + BOOST_CHECK_EQUAL(!key, false); +} + +BOOST_AUTO_TEST_CASE(TpmLocator) +{ + Pib pib("pib-memory", "", make_shared()); + + BOOST_CHECK_EQUAL(pib.getPibLocator(), "pib-memory:"); + BOOST_CHECK_THROW(pib.getTpmLocator(), Pib::Error); + + pib.setTpmLocator("test-tpm-locator"); + BOOST_CHECK_NO_THROW(pib.getTpmLocator()); + + BOOST_CHECK_THROW(pib.getIdentity(id1), Pib::Error); + pib.addIdentity(id1); + BOOST_CHECK_NO_THROW(pib.getIdentity(id1)); + + pib.setTpmLocator("another-tpm-locator"); + BOOST_CHECK_THROW(pib.getIdentity(id1), Pib::Error); + + pib.addIdentity(id1); + BOOST_CHECK_NO_THROW(pib.getIdentity(id1)); + pib.reset(); + BOOST_CHECK_THROW(pib.getIdentity(id1), Pib::Error); + BOOST_CHECK_THROW(pib.getTpmLocator(), Pib::Error); +} + +BOOST_AUTO_TEST_CASE(IdentityOperations) +{ + Pib pib("pib-memory", "", make_shared()); + BOOST_CHECK_EQUAL(pib.getIdentities().size(), 0); + + // get non-existing identity, throw Pib::Error + BOOST_CHECK_THROW(pib.getIdentity(id1), Pib::Error); + // get default identity when it is not set yet, throw Pib::Error + BOOST_CHECK_THROW(pib.getDefaultIdentity(), Pib::Error); + + // add identity + pib.addIdentity(id1); + BOOST_CHECK_NO_THROW(pib.getIdentity(id1)); + BOOST_CHECK_EQUAL(pib.getIdentities().size(), 1); + + // new key becomes default key when there was no default key + BOOST_REQUIRE_NO_THROW(pib.getDefaultIdentity()); + BOOST_CHECK_EQUAL(pib.getDefaultIdentity().getName(), id1); + + // remove identity + pib.removeIdentity(id1); + BOOST_CHECK_THROW(pib.getIdentity(id1), Pib::Error); + BOOST_CHECK_THROW(pib.getDefaultIdentity(), Pib::Error); + BOOST_CHECK_EQUAL(pib.getIdentities().size(), 0); + + // set default identity + BOOST_REQUIRE_NO_THROW(pib.setDefaultIdentity(id1)); + BOOST_REQUIRE_NO_THROW(pib.getDefaultIdentity()); + BOOST_CHECK_EQUAL(pib.getDefaultIdentity().getName(), id1); + BOOST_CHECK_EQUAL(pib.getIdentities().size(), 1); + BOOST_REQUIRE_NO_THROW(pib.setDefaultIdentity(id2)); + BOOST_REQUIRE_NO_THROW(pib.getDefaultIdentity()); + BOOST_CHECK_EQUAL(pib.getDefaultIdentity().getName(), id2); + BOOST_CHECK_EQUAL(pib.getIdentities().size(), 2); + + // remove default identity + pib.removeIdentity(id2); + BOOST_CHECK_THROW(pib.getIdentity(id2), Pib::Error); + BOOST_CHECK_THROW(pib.getDefaultIdentity(), Pib::Error); + BOOST_CHECK_EQUAL(pib.getIdentities().size(), 1); + pib.removeIdentity(id1); + BOOST_CHECK_THROW(pib.getIdentity(id1), Pib::Error); + BOOST_CHECK_EQUAL(pib.getIdentities().size(), 0); +} + +BOOST_AUTO_TEST_SUITE_END() // TestPib +BOOST_AUTO_TEST_SUITE_END() // Pib +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace pib +} // namespace security +} // namespace ndn diff --git a/tests/unit-tests/security/safe-bag.t.cpp b/tests/unit/security/safe-bag.t.cpp similarity index 97% rename from tests/unit-tests/security/safe-bag.t.cpp rename to tests/unit/security/safe-bag.t.cpp index 3c93e5876..d59cdefe4 100644 --- a/tests/unit-tests/security/safe-bag.t.cpp +++ b/tests/unit/security/safe-bag.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -21,9 +21,9 @@ * @author Zhiyi Zhang */ -#include "security/safe-bag.hpp" +#include "ndn-cxx/security/safe-bag.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace security { @@ -150,7 +150,7 @@ BOOST_AUTO_TEST_CASE(EncoderAndDecoder) Block block(SAFE_BAG, sizeof(SAFE_BAG)); // check safe bag block - BOOST_CHECK(wireBlock == block); + BOOST_CHECK_EQUAL(wireBlock, block); // wire decode SafeBag safeBag2; diff --git a/tests/unit/security/signature-sha256-with-ecdsa.t.cpp b/tests/unit/security/signature-sha256-with-ecdsa.t.cpp new file mode 100644 index 000000000..38817568d --- /dev/null +++ b/tests/unit/security/signature-sha256-with-ecdsa.t.cpp @@ -0,0 +1,148 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/signature-sha256-with-ecdsa.hpp" +#include "ndn-cxx/security/verification-helpers.hpp" +#include "ndn-cxx/util/scheduler.hpp" + +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" +#include "tests/unit/identity-management-time-fixture.hpp" + +namespace ndn { +namespace security { +namespace tests { + +using namespace ndn::tests; + +class SignatureSha256EcdsaTimeFixture : public IdentityManagementTimeFixture +{ +public: + SignatureSha256EcdsaTimeFixture() + : scheduler(io) + { + } + +public: + Scheduler scheduler; +}; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_FIXTURE_TEST_SUITE(TestSignatureSha256WithEcdsa, SignatureSha256EcdsaTimeFixture) + +const uint8_t sigInfo[] = { + 0x16, 0x1b, // SignatureInfo + 0x1b, 0x01, // SignatureType + 0x03, + 0x1c, 0x16, // KeyLocator + 0x07, 0x14, // Name: /test/key/locator + 0x08, 0x04, + 0x74, 0x65, 0x73, 0x74, + 0x08, 0x03, + 0x6b, 0x65, 0x79, + 0x08, 0x07, + 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72 +}; + +const uint8_t sigValue[] = { + 0x17, 0x40, // SignatureValue + 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, + 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, + 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, + 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, + 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b +}; + + +BOOST_AUTO_TEST_CASE(Decoding) +{ + Block sigInfoBlock(sigInfo, sizeof(sigInfo)); + Block sigValueBlock(sigValue, sizeof(sigValue)); + + Signature sig(sigInfoBlock, sigValueBlock); + BOOST_CHECK_NO_THROW(SignatureSha256WithEcdsa{sig}); + BOOST_CHECK_NO_THROW(sig.getKeyLocator()); +} + +BOOST_AUTO_TEST_CASE(Encoding) +{ + Name name("/test/key/locator"); + KeyLocator keyLocator(name); + + SignatureSha256WithEcdsa sig(keyLocator); + + BOOST_CHECK_NO_THROW(sig.getKeyLocator()); + + const Block& encodeSigInfoBlock = sig.getInfo(); + + Block sigInfoBlock(sigInfo, sizeof(sigInfo)); + + BOOST_CHECK_EQUAL_COLLECTIONS(sigInfoBlock.wire(), + sigInfoBlock.wire() + sigInfoBlock.size(), + encodeSigInfoBlock.wire(), + encodeSigInfoBlock.wire() + encodeSigInfoBlock.size()); + + sig.setKeyLocator(Name("/test/another/key/locator")); + + const Block& encodeSigInfoBlock2 = sig.getInfo(); + BOOST_CHECK_NE(sigInfoBlock, encodeSigInfoBlock2); +} + +BOOST_AUTO_TEST_CASE(DataSignature) +{ + Identity identity = addIdentity("/SecurityTestSignatureSha256WithEcdsa/DataSignature", EcKeyParams()); + + Data testData("/SecurityTestSignatureSha256WithEcdsa/DataSignature/Data1"); + char content[5] = "1234"; + testData.setContent(reinterpret_cast(content), 5); + BOOST_CHECK_NO_THROW(m_keyChain.sign(testData, security::SigningInfo(identity))); + Block dataBlock(testData.wireEncode().wire(), testData.wireEncode().size()); + + Data testData2; + testData2.wireDecode(dataBlock); + BOOST_CHECK(verifySignature(testData2, identity.getDefaultKey())); +} + +BOOST_AUTO_TEST_CASE(InterestSignature) +{ + Identity identity = addIdentity("/SecurityTestSignatureSha256WithEcdsa/InterestSignature", EcKeyParams()); + + auto interest = makeInterest("/SecurityTestSignatureSha256WithEcdsa/InterestSignature/Interest1"); + auto interest11 = makeInterest("/SecurityTestSignatureSha256WithEcdsa/InterestSignature/Interest1"); + + scheduler.schedule(100_ms, [&] { m_keyChain.sign(*interest, security::SigningInfo(identity)); }); + advanceClocks(100_ms); + scheduler.schedule(100_ms, [&] { m_keyChain.sign(*interest11, security::SigningInfo(identity)); }); + advanceClocks(100_ms); + + Block interestBlock(interest->wireEncode().wire(), interest->wireEncode().size()); + + Interest interest2; + interest2.wireDecode(interestBlock); + BOOST_CHECK(verifySignature(interest2, identity.getDefaultKey())); +} + +BOOST_AUTO_TEST_SUITE_END() // TestSignatureSha256WithEcdsa +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/signature-sha256-with-rsa.t.cpp b/tests/unit/security/signature-sha256-with-rsa.t.cpp new file mode 100644 index 000000000..2363551dc --- /dev/null +++ b/tests/unit/security/signature-sha256-with-rsa.t.cpp @@ -0,0 +1,153 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/signature-sha256-with-rsa.hpp" +#include "ndn-cxx/security/verification-helpers.hpp" +#include "ndn-cxx/util/scheduler.hpp" + +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" +#include "tests/unit/identity-management-time-fixture.hpp" + +namespace ndn { +namespace security { +namespace tests { + +using namespace ndn::tests; + +class SignatureSha256RsaTimeFixture : public IdentityManagementTimeFixture +{ +public: + SignatureSha256RsaTimeFixture() + : scheduler(io) + { + } + +public: + Scheduler scheduler; +}; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_FIXTURE_TEST_SUITE(TestSignatureSha256WithRsa, SignatureSha256RsaTimeFixture) + +const uint8_t sigInfo[] = { + 0x16, 0x1b, // SignatureInfo + 0x1b, 0x01, // SignatureType + 0x01, + 0x1c, 0x16, // KeyLocator + 0x07, 0x14, // Name + 0x08, 0x04, + 0x74, 0x65, 0x73, 0x74, + 0x08, 0x03, + 0x6b, 0x65, 0x79, + 0x08, 0x07, + 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72 +}; + +const uint8_t sigValue[] = { +0x17, 0x80, // SignatureValue + 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, + 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, + 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, + 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, + 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, + 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, + 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, + 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, + 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, + 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1 +}; + + +BOOST_AUTO_TEST_CASE(Decoding) +{ + Block sigInfoBlock(sigInfo, sizeof(sigInfo)); + Block sigValueBlock(sigValue, sizeof(sigValue)); + + Signature sig(sigInfoBlock, sigValueBlock); + BOOST_CHECK_NO_THROW(SignatureSha256WithRsa{sig}); + BOOST_CHECK_NO_THROW(sig.getKeyLocator()); +} + +BOOST_AUTO_TEST_CASE(Encoding) +{ + Name name("/test/key/locator"); + KeyLocator keyLocator(name); + + SignatureSha256WithRsa sig(keyLocator); + + BOOST_CHECK_NO_THROW(sig.getKeyLocator()); + + const Block& encodeSigInfoBlock = sig.getInfo(); + + Block sigInfoBlock(sigInfo, sizeof(sigInfo)); + + BOOST_CHECK_EQUAL_COLLECTIONS(sigInfoBlock.wire(), + sigInfoBlock.wire() + sigInfoBlock.size(), + encodeSigInfoBlock.wire(), + encodeSigInfoBlock.wire() + encodeSigInfoBlock.size()); + + sig.setKeyLocator(Name("/test/another/key/locator")); + + const Block& encodeSigInfoBlock2 = sig.getInfo(); + BOOST_CHECK_NE(sigInfoBlock, encodeSigInfoBlock2); +} + +BOOST_AUTO_TEST_CASE(DataSignature) +{ + Identity identity = addIdentity("/SecurityTestSignatureSha256WithRsa/DataSignature", RsaKeyParams()); + + Data testData("/SecurityTestSignatureSha256WithRsa/DataSignature/Data1"); + char content[5] = "1234"; + testData.setContent(reinterpret_cast(content), 5); + BOOST_CHECK_NO_THROW(m_keyChain.sign(testData, security::SigningInfo(identity))); + Block dataBlock(testData.wireEncode().wire(), testData.wireEncode().size()); + + Data testData2; + testData2.wireDecode(dataBlock); + BOOST_CHECK(verifySignature(testData2, identity.getDefaultKey())); +} + +BOOST_AUTO_TEST_CASE(InterestSignature) +{ + Identity identity = addIdentity("/SecurityTestSignatureSha256WithRsa/InterestSignature", RsaKeyParams()); + + auto interest = makeInterest("/SecurityTestSignatureSha256WithRsa/InterestSignature/Interest1"); + auto interest11 = makeInterest("/SecurityTestSignatureSha256WithRsa/InterestSignature/Interest1"); + + scheduler.schedule(100_ms, [&] { m_keyChain.sign(*interest, security::SigningInfo(identity)); }); + advanceClocks(100_ms); + scheduler.schedule(100_ms, [&] { m_keyChain.sign(*interest11, security::SigningInfo(identity)); }); + advanceClocks(100_ms); + + Block interestBlock(interest->wireEncode().wire(), interest->wireEncode().size()); + + Interest interest2; + interest2.wireDecode(interestBlock); + BOOST_CHECK(verifySignature(interest2, identity.getDefaultKey())); +} + +BOOST_AUTO_TEST_SUITE_END() // TestSignatureSha256WithRsa +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace security +} // namespace ndn diff --git a/tests/unit-tests/security/signing-helpers.t.cpp b/tests/unit/security/signing-helpers.t.cpp similarity index 87% rename from tests/unit-tests/security/signing-helpers.t.cpp rename to tests/unit/security/signing-helpers.t.cpp index b29954c26..f9a51b2f9 100644 --- a/tests/unit-tests/security/signing-helpers.t.cpp +++ b/tests/unit/security/signing-helpers.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,9 +19,9 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "security/signing-helpers.hpp" +#include "ndn-cxx/security/signing-helpers.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace security { @@ -30,6 +30,8 @@ namespace tests { BOOST_AUTO_TEST_SUITE(Security) BOOST_AUTO_TEST_SUITE(TestSigningHelpers) +// update of this test case deferred until the new IdentityManagementFixture is available + BOOST_AUTO_TEST_CASE(Identity) { Name identity("/identity"); @@ -58,7 +60,7 @@ BOOST_AUTO_TEST_CASE(Sha256) { SigningInfo info = signingWithSha256(); BOOST_CHECK_EQUAL(info.getSignerType(), SigningInfo::SIGNER_TYPE_SHA256); - BOOST_CHECK_EQUAL(info.getSignerName(), SigningInfo::EMPTY_NAME); + BOOST_CHECK_EQUAL(info.getSignerName(), SigningInfo::getEmptyName()); } BOOST_AUTO_TEST_SUITE_END() // TestSigningHelpers diff --git a/tests/unit/security/signing-info.t.cpp b/tests/unit/security/signing-info.t.cpp new file mode 100644 index 000000000..e32d5b1a4 --- /dev/null +++ b/tests/unit/security/signing-info.t.cpp @@ -0,0 +1,269 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/signing-info.hpp" + +#include "tests/boost-test.hpp" + +#include +#include + +namespace ndn { +namespace security { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(TestSigningInfo) + +BOOST_AUTO_TEST_CASE(Basic) +{ + Name id("/my-identity"); + Name key("/my-key"); + Name cert("/my-cert"); + + SigningInfo info; + + BOOST_CHECK_EQUAL(info.getSignerType(), SigningInfo::SIGNER_TYPE_NULL); + BOOST_CHECK_EQUAL(info.getSignerName(), SigningInfo::getEmptyName()); + BOOST_CHECK_EQUAL(info.getDigestAlgorithm(), DigestAlgorithm::SHA256); + + const SignatureInfo& sigInfo = info.getSignatureInfo(); + BOOST_CHECK_EQUAL(sigInfo.getSignatureType(), -1); + BOOST_CHECK_EQUAL(sigInfo.hasKeyLocator(), false); + + info.setSigningIdentity(id); + BOOST_CHECK_EQUAL(info.getSignerType(), SigningInfo::SIGNER_TYPE_ID); + BOOST_CHECK_EQUAL(info.getSignerName(), id); + BOOST_CHECK_EQUAL(info.getDigestAlgorithm(), DigestAlgorithm::SHA256); + + SigningInfo infoId(SigningInfo::SIGNER_TYPE_ID, id); + BOOST_CHECK_EQUAL(infoId.getSignerType(), SigningInfo::SIGNER_TYPE_ID); + BOOST_CHECK_EQUAL(infoId.getSignerName(), id); + BOOST_CHECK_EQUAL(infoId.getDigestAlgorithm(), DigestAlgorithm::SHA256); + + info.setSigningKeyName(key); + BOOST_CHECK_EQUAL(info.getSignerType(), SigningInfo::SIGNER_TYPE_KEY); + BOOST_CHECK_EQUAL(info.getSignerName(), key); + BOOST_CHECK_EQUAL(info.getDigestAlgorithm(), DigestAlgorithm::SHA256); + + SigningInfo infoKey(SigningInfo::SIGNER_TYPE_KEY, key); + BOOST_CHECK_EQUAL(infoKey.getSignerType(), SigningInfo::SIGNER_TYPE_KEY); + BOOST_CHECK_EQUAL(infoKey.getSignerName(), key); + BOOST_CHECK_EQUAL(infoKey.getDigestAlgorithm(), DigestAlgorithm::SHA256); + + info.setSigningCertName(cert); + BOOST_CHECK_EQUAL(info.getSignerType(), SigningInfo::SIGNER_TYPE_CERT); + BOOST_CHECK_EQUAL(info.getSignerName(), cert); + BOOST_CHECK_EQUAL(info.getDigestAlgorithm(), DigestAlgorithm::SHA256); + + SigningInfo infoCert(SigningInfo::SIGNER_TYPE_CERT, cert); + BOOST_CHECK_EQUAL(infoCert.getSignerType(), SigningInfo::SIGNER_TYPE_CERT); + BOOST_CHECK_EQUAL(infoCert.getSignerName(), cert); + BOOST_CHECK_EQUAL(infoCert.getDigestAlgorithm(), DigestAlgorithm::SHA256); + + info.setSha256Signing(); + BOOST_CHECK_EQUAL(info.getSignerType(), SigningInfo::SIGNER_TYPE_SHA256); + BOOST_CHECK_EQUAL(info.getSignerName(), SigningInfo::getEmptyName()); + BOOST_CHECK_EQUAL(info.getDigestAlgorithm(), DigestAlgorithm::SHA256); + + SigningInfo infoSha(SigningInfo::SIGNER_TYPE_SHA256); + BOOST_CHECK_EQUAL(infoSha.getSignerType(), SigningInfo::SIGNER_TYPE_SHA256); + BOOST_CHECK_EQUAL(infoSha.getSignerName(), SigningInfo::getEmptyName()); + BOOST_CHECK_EQUAL(infoSha.getDigestAlgorithm(), DigestAlgorithm::SHA256); + + std::string encodedKey("QjM3NEEyNkE3MTQ5MDQzN0FBMDI0RTRGQURENUI0OTdGRE" + "ZGMUE4RUE2RkYxMkY2RkI2NUFGMjcyMEI1OUNDRg=="); + info.setSigningHmacKey(encodedKey); + BOOST_CHECK_EQUAL(info.getSignerType(), SigningInfo::SIGNER_TYPE_HMAC); + BOOST_CHECK_EQUAL(info.getDigestAlgorithm(), DigestAlgorithm::SHA256); + + SigningInfo infoHmac(SigningInfo::SIGNER_TYPE_HMAC, info.getSignerName()); + BOOST_CHECK_EQUAL(infoHmac.getSignerType(), SigningInfo::SIGNER_TYPE_HMAC); + BOOST_CHECK_EQUAL(infoHmac.getDigestAlgorithm(), DigestAlgorithm::SHA256); +} + +BOOST_AUTO_TEST_CASE(CustomSignatureInfo) +{ + SigningInfo info1; + BOOST_CHECK_EQUAL(info1.getSignatureInfo(), SignatureInfo()); + + SignatureInfo si; + si.setKeyLocator(Name("ndn:/test/key/locator")); + info1.setSignatureInfo(si); + + BOOST_CHECK_EQUAL(info1.getSignatureInfo(), si); + + SigningInfo info2(SigningInfo::SIGNER_TYPE_NULL, SigningInfo::getEmptyName(), si); + BOOST_CHECK_EQUAL(info2.getSignatureInfo(), si); +} + +BOOST_AUTO_TEST_CASE(FromString) +{ + SigningInfo infoDefault(""); + BOOST_CHECK_EQUAL(infoDefault.getSignerType(), SigningInfo::SIGNER_TYPE_NULL); + BOOST_CHECK_EQUAL(infoDefault.getSignerName(), SigningInfo::getEmptyName()); + BOOST_CHECK_EQUAL(infoDefault.getDigestAlgorithm(), DigestAlgorithm::SHA256); + + SigningInfo infoId("id:/my-identity"); + BOOST_CHECK_EQUAL(infoId.getSignerType(), SigningInfo::SIGNER_TYPE_ID); + BOOST_CHECK_EQUAL(infoId.getSignerName(), "/my-identity"); + BOOST_CHECK_EQUAL(infoId.getDigestAlgorithm(), DigestAlgorithm::SHA256); + + SigningInfo infoKey("key:/my-key"); + BOOST_CHECK_EQUAL(infoKey.getSignerType(), SigningInfo::SIGNER_TYPE_KEY); + BOOST_CHECK_EQUAL(infoKey.getSignerName(), "/my-key"); + BOOST_CHECK_EQUAL(infoKey.getDigestAlgorithm(), DigestAlgorithm::SHA256); + + SigningInfo infoCert("cert:/my-cert"); + BOOST_CHECK_EQUAL(infoCert.getSignerType(), SigningInfo::SIGNER_TYPE_CERT); + BOOST_CHECK_EQUAL(infoCert.getSignerName(), "/my-cert"); + BOOST_CHECK_EQUAL(infoCert.getDigestAlgorithm(), DigestAlgorithm::SHA256); + + SigningInfo infoHmac("hmac-sha256:QjM3NEEyNkE3MTQ5MDQzN0FBMDI0RTRGQURENU" + "I0OTdGREZGMUE4RUE2RkYxMkY2RkI2NUFGMjcyMEI1OUNDRg=="); + BOOST_CHECK_EQUAL(infoHmac.getSignerType(), SigningInfo::SIGNER_TYPE_HMAC); + BOOST_CHECK_EQUAL(infoHmac.getSignerName().getPrefix(3), SigningInfo::getHmacIdentity()); + BOOST_CHECK_EQUAL(infoHmac.getDigestAlgorithm(), DigestAlgorithm::SHA256); + + SigningInfo infoSha("id:/localhost/identity/digest-sha256"); + BOOST_CHECK_EQUAL(infoSha.getSignerType(), SigningInfo::SIGNER_TYPE_SHA256); + BOOST_CHECK_EQUAL(infoSha.getSignerName(), SigningInfo::getEmptyName()); + BOOST_CHECK_EQUAL(infoSha.getDigestAlgorithm(), DigestAlgorithm::SHA256); +} + +BOOST_AUTO_TEST_CASE(ToString) +{ + // We can't use lexical_cast due to Boost Bug 6298. + std::stringstream ss; + ss << SigningInfo(); + BOOST_CHECK_EQUAL(ss.str(), ""); + + BOOST_CHECK_EQUAL(boost::lexical_cast( + SigningInfo(SigningInfo::SIGNER_TYPE_ID, "/my-identity")), "id:/my-identity"); + BOOST_CHECK_EQUAL(boost::lexical_cast( + SigningInfo(SigningInfo::SIGNER_TYPE_KEY, "/my-key")), "key:/my-key"); + BOOST_CHECK_EQUAL(boost::lexical_cast( + SigningInfo(SigningInfo::SIGNER_TYPE_CERT, "/my-cert")), "cert:/my-cert"); + BOOST_CHECK_EQUAL(boost::lexical_cast( + SigningInfo(SigningInfo::SIGNER_TYPE_SHA256)), + "id:/localhost/identity/digest-sha256"); + BOOST_CHECK_EQUAL(boost::lexical_cast( + SigningInfo(SigningInfo::SIGNER_TYPE_HMAC, "/localhost/identity/hmac/1234")), + "id:/localhost/identity/hmac/1234"); +} + +BOOST_AUTO_TEST_CASE(Chaining) +{ + SigningInfo info = SigningInfo() + .setSigningIdentity("/identity") + .setSigningKeyName("/key/name") + .setSigningCertName("/cert/name") + .setPibIdentity(Identity()) + .setPibKey(Key()) + .setSha256Signing() + .setDigestAlgorithm(DigestAlgorithm::SHA256) + .setSignatureInfo(SignatureInfo()); + + BOOST_CHECK_EQUAL(boost::lexical_cast(info), "id:/localhost/identity/digest-sha256"); +} + +BOOST_AUTO_TEST_CASE(OperatorEquals) +{ + // Check name equality + SigningInfo info1("id:/my-id"); + SigningInfo info2("id:/my-id"); + BOOST_CHECK_EQUAL(info1, info2); + // Change name, check inequality + info2 = SigningInfo("id:/not-same-id"); + BOOST_CHECK_NE(info1, info2); + + // Check name, digest algo equality + info1 = SigningInfo("id:/my-id"); + info2 = SigningInfo("id:/my-id"); + info1.setDigestAlgorithm(DigestAlgorithm::SHA256); + info2.setDigestAlgorithm(DigestAlgorithm::SHA256); + BOOST_CHECK_EQUAL(info1, info2); + // Change digest algo, check inequality + info2.setDigestAlgorithm(DigestAlgorithm::NONE); + BOOST_CHECK_NE(info1, info2); + + // Check name, digest algo, signature info equality + info1 = SigningInfo("id:/my-id"); + info2 = SigningInfo("id:/my-id"); + info1.setDigestAlgorithm(DigestAlgorithm::SHA256); + info2.setDigestAlgorithm(DigestAlgorithm::SHA256); + SignatureInfo sigInfo1(tlv::DigestSha256); + info1.setSignatureInfo(sigInfo1); + info2.setSignatureInfo(sigInfo1); + BOOST_CHECK_EQUAL(info1, info2); + // Change signature info, check inequality + SignatureInfo sigInfo2(tlv::SignatureSha256WithRsa); + info2.setSignatureInfo(sigInfo2); + BOOST_CHECK_NE(info1, info2); +} + +BOOST_AUTO_TEST_CASE(OperatorEqualsDifferentTypes) +{ + SigningInfo info1("key:/my-id/KEY/1"); + SigningInfo info2("key:/my-id/KEY/1"); + // Check equality for key type + BOOST_CHECK_EQUAL(info1, info2); + info2 = SigningInfo("id:/my-id"); + // Change signature type, check inequality + BOOST_CHECK_NE(info1, info2); + info2 = SigningInfo("key:/not-same-id/KEY/1"); + // Change key name, check inequality + BOOST_CHECK_NE(info1, info2); + + info1 = SigningInfo("cert:/my-id/KEY/1/self/%FD01"); + info2 = SigningInfo("cert:/my-id/KEY/1/self/%FD01"); + // Check equality for cert type + BOOST_CHECK_EQUAL(info1, info2); + info2 = SigningInfo("cert:/not-my-id/KEY/1/other/%FD01"); + // Change cert name, check inequality + BOOST_CHECK_NE(info1, info2); + info2 = SigningInfo("id:/my-id"); + // Change signature type, check inequality + BOOST_CHECK_NE(info1, info2); + + info1 = SigningInfo(SigningInfo::SIGNER_TYPE_NULL); + info2 = SigningInfo(SigningInfo::SIGNER_TYPE_NULL); + // Check equality for null type + BOOST_CHECK_EQUAL(info1, info2); + info2 = SigningInfo("id:/my-id"); + // Change signature type, check inequality + BOOST_CHECK_NE(info1, info2); + + info1 = SigningInfo(SigningInfo::SIGNER_TYPE_SHA256); + info2 = SigningInfo(SigningInfo::SIGNER_TYPE_SHA256); + // Check equality for SHA256 digest type + BOOST_CHECK_EQUAL(info1, info2); + info2 = SigningInfo("id:/my-id"); + // Change signature type, check inequality + BOOST_CHECK_NE(info1, info2); +} + +BOOST_AUTO_TEST_SUITE_END() // TestSigningInfo +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace security +} // namespace ndn diff --git a/tests/unit-tests/security/tmp-home/.ndn/client.conf b/tests/unit/security/tmp-home/.ndn/client.conf similarity index 100% rename from tests/unit-tests/security/tmp-home/.ndn/client.conf rename to tests/unit/security/tmp-home/.ndn/client.conf diff --git a/tests/unit/security/tpm/back-end-wrapper-file.hpp b/tests/unit/security/tpm/back-end-wrapper-file.hpp new file mode 100644 index 000000000..16b9bf27e --- /dev/null +++ b/tests/unit/security/tpm/back-end-wrapper-file.hpp @@ -0,0 +1,73 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TESTS_SECURITY_TPM_BACK_END_WRAPPER_FILE_HPP +#define NDN_TESTS_SECURITY_TPM_BACK_END_WRAPPER_FILE_HPP + +#include "ndn-cxx/security/tpm/impl/back-end-file.hpp" + +#include + +namespace ndn { +namespace security { +namespace tpm { +namespace tests { + +/** + * @brief A wrapper of tpm::BackEndFile for unit test template. + */ +class BackEndWrapperFile +{ +public: + BackEndWrapperFile() + : m_tmpPath(boost::filesystem::path(UNIT_TEST_CONFIG_PATH) / "TpmFileTest") + , m_impl(make_unique(m_tmpPath.string())) + { + } + + ~BackEndWrapperFile() + { + boost::filesystem::remove_all(m_tmpPath); + } + + BackEnd& + getTpm() + { + return *m_impl; + } + + std::string + getScheme() const + { + return "tpm-file"; + } + +private: + const boost::filesystem::path m_tmpPath; + const unique_ptr m_impl; +}; + +} // namespace tests +} // namespace tpm +} // namespace security +} // namespace ndn + +#endif // NDN_TESTS_SECURITY_TPM_BACK_END_WRAPPER_FILE_HPP diff --git a/tests/unit/security/tpm/back-end-wrapper-mem.hpp b/tests/unit/security/tpm/back-end-wrapper-mem.hpp new file mode 100644 index 000000000..67dd7e09e --- /dev/null +++ b/tests/unit/security/tpm/back-end-wrapper-mem.hpp @@ -0,0 +1,64 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TESTS_SECURITY_TPM_BACK_END_WRAPPER_MEM_HPP +#define NDN_TESTS_SECURITY_TPM_BACK_END_WRAPPER_MEM_HPP + +#include "ndn-cxx/security/tpm/impl/back-end-mem.hpp" + +namespace ndn { +namespace security { +namespace tpm { +namespace tests { + +/** + * @brief A wrapper of tpm::BackEndMem for unit test template. + */ +class BackEndWrapperMem +{ +public: + BackEndWrapperMem() + : m_impl(make_unique()) + { + } + + BackEnd& + getTpm() + { + return *m_impl; + } + + std::string + getScheme() const + { + return "tpm-memory"; + } + +private: + const unique_ptr m_impl; +}; + +} // namespace tests +} // namespace tpm +} // namespace security +} // namespace ndn + +#endif // NDN_TESTS_SECURITY_TPM_BACK_END_WRAPPER_MEM_HPP diff --git a/tests/unit/security/tpm/back-end-wrapper-osx.hpp b/tests/unit/security/tpm/back-end-wrapper-osx.hpp new file mode 100644 index 000000000..124c89765 --- /dev/null +++ b/tests/unit/security/tpm/back-end-wrapper-osx.hpp @@ -0,0 +1,88 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TESTS_SECURITY_TPM_BACK_END_WRAPPER_OSX_HPP +#define NDN_TESTS_SECURITY_TPM_BACK_END_WRAPPER_OSX_HPP + +#include "ndn-cxx/security/tpm/impl/back-end-osx.hpp" +#include "ndn-cxx/security/tpm/impl/key-handle-osx.hpp" + +#include + +namespace ndn { +namespace security { +namespace tpm { +namespace tests { + +/** + * @brief A wrapper of tpm::BackEndOsx for unit test template. + */ +class BackEndWrapperOsx +{ +public: + BackEndWrapperOsx() + { + std::string oldHOME; + if (std::getenv("OLD_HOME")) + oldHOME = std::getenv("OLD_HOME"); + + if (std::getenv("HOME")) + m_HOME = std::getenv("HOME"); + + if (!oldHOME.empty()) + setenv("HOME", oldHOME.data(), 1); + else + unsetenv("HOME"); + + m_impl = make_unique(); + } + + ~BackEndWrapperOsx() + { + if (!m_HOME.empty()) + setenv("HOME", m_HOME.data(), 1); + else + unsetenv("HOME"); + } + + BackEnd& + getTpm() + { + return *m_impl; + } + + std::string + getScheme() const + { + return "tpm-osxkeychain"; + } + +private: + std::string m_HOME; + unique_ptr m_impl; +}; + +} // namespace tests +} // namespace tpm +} // namespace security +} // namespace ndn + +#endif // NDN_TESTS_SECURITY_TPM_BACK_END_WRAPPER_OSX_HPP diff --git a/tests/unit/security/tpm/back-end.t.cpp b/tests/unit/security/tpm/back-end.t.cpp new file mode 100644 index 000000000..8d4b41a3c --- /dev/null +++ b/tests/unit/security/tpm/back-end.t.cpp @@ -0,0 +1,326 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/tpm/back-end.hpp" + +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/pib/key.hpp" +#include "ndn-cxx/security/transform/bool-sink.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/private-key.hpp" +#include "ndn-cxx/security/transform/public-key.hpp" +#include "ndn-cxx/security/transform/verifier-filter.hpp" + +#include "tests/unit/security/tpm/back-end-wrapper-file.hpp" +#include "tests/unit/security/tpm/back-end-wrapper-mem.hpp" +#ifdef NDN_CXX_HAVE_OSX_FRAMEWORKS +#include "tests/unit/security/tpm/back-end-wrapper-osx.hpp" +#endif // NDN_CXX_HAVE_OSX_FRAMEWORKS + +#include "tests/boost-test.hpp" + +#include +#include + +namespace ndn { +namespace security { +namespace tpm { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(Tpm) +BOOST_AUTO_TEST_SUITE(TestBackEnd) + +using tpm::Tpm; + +using TestBackEnds = boost::mpl::vector< +#ifdef NDN_CXX_HAVE_OSX_FRAMEWORKS + BackEndWrapperOsx, +#endif // NDN_CXX_HAVE_OSX_FRAMEWORKS + BackEndWrapperMem, + BackEndWrapperFile>; + +BOOST_AUTO_TEST_CASE_TEMPLATE(KeyManagement, T, TestBackEnds) +{ + T wrapper; + BackEnd& tpm = wrapper.getTpm(); + + Name identity("/Test/KeyName"); + name::Component keyId("1"); + Name keyName = v2::constructKeyName(identity, keyId); + + // key should not exist + BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false); + BOOST_CHECK(tpm.getKeyHandle(keyName) == nullptr); + + // create key, should exist + BOOST_CHECK(tpm.createKey(identity, RsaKeyParams(keyId)) != nullptr); + BOOST_CHECK(tpm.hasKey(keyName)); + BOOST_CHECK(tpm.getKeyHandle(keyName) != nullptr); + + // create a key with the same name, should throw error + BOOST_CHECK_THROW(tpm.createKey(identity, RsaKeyParams(keyId)), Tpm::Error); + + // delete key, should not exist + tpm.deleteKey(keyName); + BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false); + BOOST_CHECK(tpm.getKeyHandle(keyName) == nullptr); +} + +BOOST_AUTO_TEST_CASE(CreateHmacKey) +{ + Name identity("/Test/Identity/HMAC"); + + BackEndWrapperMem mem; + BackEnd& memTpm = mem.getTpm(); + auto key = memTpm.createKey(identity, HmacKeyParams()); + BOOST_REQUIRE(key != nullptr); + BOOST_CHECK(!key->getKeyName().empty()); + BOOST_CHECK(memTpm.hasKey(key->getKeyName())); + + BackEndWrapperFile file; + BackEnd& fileTpm = file.getTpm(); + BOOST_CHECK_THROW(fileTpm.createKey(identity, HmacKeyParams()), std::invalid_argument); + +#ifdef NDN_CXX_HAVE_OSX_FRAMEWORKS + BackEndWrapperOsx osx; + BackEnd& osxTpm = osx.getTpm(); + BOOST_CHECK_THROW(osxTpm.createKey(identity, HmacKeyParams()), std::invalid_argument); +#endif // NDN_CXX_HAVE_OSX_FRAMEWORKS +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(RsaSigning, T, TestBackEnds) +{ + T wrapper; + BackEnd& tpm = wrapper.getTpm(); + + // create an RSA key + Name identity("/Test/RSA/KeyName"); + unique_ptr key = tpm.createKey(identity, RsaKeyParams()); + Name keyName = key->getKeyName(); + + const uint8_t content[] = {0x01, 0x02, 0x03, 0x04}; + auto sigValue = key->sign(DigestAlgorithm::SHA256, content, sizeof(content)); + BOOST_REQUIRE(sigValue != nullptr); + Block sigBlock(tlv::SignatureValue, sigValue); + + transform::PublicKey pubKey; + ConstBufferPtr pubKeyBits = key->derivePublicKey(); + pubKey.loadPkcs8(pubKeyBits->data(), pubKeyBits->size()); + + bool result; + { + using namespace transform; + bufferSource(content, sizeof(content)) >> + verifierFilter(DigestAlgorithm::SHA256, pubKey, sigBlock.value(), sigBlock.value_size()) >> + boolSink(result); + } + BOOST_CHECK_EQUAL(result, true); + + tpm.deleteKey(keyName); + BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(RsaDecryption, T, TestBackEnds) +{ + T wrapper; + BackEnd& tpm = wrapper.getTpm(); + + // create an RSA key + Name identity("/Test/KeyName"); + unique_ptr key = tpm.createKey(identity, RsaKeyParams()); + Name keyName = key->getKeyName(); + + const uint8_t content[] = {0x01, 0x02, 0x03, 0x04}; + + transform::PublicKey pubKey; + ConstBufferPtr pubKeyBits = key->derivePublicKey(); + pubKey.loadPkcs8(pubKeyBits->data(), pubKeyBits->size()); + + ConstBufferPtr cipherText = pubKey.encrypt(content, sizeof(content)); + ConstBufferPtr plainText = key->decrypt(cipherText->data(), cipherText->size()); + + BOOST_CHECK_EQUAL_COLLECTIONS(content, content + sizeof(content), + plainText->begin(), plainText->end()); + + tpm.deleteKey(keyName); + BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(EcdsaSigning, T, TestBackEnds) +{ + T wrapper; + BackEnd& tpm = wrapper.getTpm(); + + // create an EC key + Name identity("/Test/EC/KeyName"); + unique_ptr key = tpm.createKey(identity, EcKeyParams()); + Name ecKeyName = key->getKeyName(); + + const uint8_t content[] = {0x01, 0x02, 0x03, 0x04}; + auto sigValue = key->sign(DigestAlgorithm::SHA256, content, sizeof(content)); + BOOST_REQUIRE(sigValue != nullptr); + Block sigBlock(tlv::SignatureValue, sigValue); + + transform::PublicKey pubKey; + ConstBufferPtr pubKeyBits = key->derivePublicKey(); + pubKey.loadPkcs8(pubKeyBits->data(), pubKeyBits->size()); + + bool result; + { + using namespace transform; + bufferSource(content, sizeof(content)) >> + verifierFilter(DigestAlgorithm::SHA256, pubKey, sigBlock.value(), sigBlock.value_size()) >> + boolSink(result); + } + BOOST_CHECK_EQUAL(result, true); + + tpm.deleteKey(ecKeyName); + BOOST_CHECK_EQUAL(tpm.hasKey(ecKeyName), false); +} + +BOOST_AUTO_TEST_CASE(HmacSigningAndVerifying) +{ + BackEndWrapperMem wrapper; + BackEnd& tpm = wrapper.getTpm(); + + // create an HMAC key + Name identity("/Test/HMAC/KeyName"); + unique_ptr key = tpm.createKey(identity, HmacKeyParams()); + Name hmacKeyName = key->getKeyName(); + + const uint8_t content[] = {0x01, 0x02, 0x03, 0x04}; + auto sigValue = key->sign(DigestAlgorithm::SHA256, content, sizeof(content)); + BOOST_REQUIRE(sigValue != nullptr); + Block sigBlock(tlv::SignatureValue, sigValue); + + bool result = key->verify(DigestAlgorithm::SHA256, content, sizeof(content), + sigBlock.value(), sigBlock.value_size()); + BOOST_CHECK_EQUAL(result, true); + + tpm.deleteKey(hmacKeyName); + BOOST_CHECK_EQUAL(tpm.hasKey(hmacKeyName), false); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(ImportExport, T, TestBackEnds) +{ + const std::string privKeyPkcs1 = + "MIIEpAIBAAKCAQEAw0WM1/WhAxyLtEqsiAJgWDZWuzkYpeYVdeeZcqRZzzfRgBQT\n" + "sNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobws3iigohnM9yTK+KKiayPhIAm/+5H\n" + "GT6SgFJhYhqo1/upWdueojil6RP4/AgavHhopxlAVbk6G9VdVnlQcQ5Zv0OcGi73\n" + "c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9gZwIL5PuE9BiO6I39cL9z7EK1SfZh\n" + "OWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA9rH58ynaAix0tcR/nBMRLUX+e3rU\n" + "RHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0ywIDAQABAoIBADQkckOIl4IZMUTn\n" + "W8LFv6xOdkJwMKC8G6bsPRFbyY+HvC2TLt7epSvfS+f4AcYWaOPcDu2E49vt2sNr\n" + "cASly8hgwiRRAB3dHH9vcsboiTo8bi2RFvMqvjv9w3tK2yMxVDtmZamzrrnaV3YV\n" + "Q+5nyKo2F/PMDjQ4eUAKDOzjhBuKHsZBTFnA1MFNI+UKj5X4Yp64DFmKlxTX/U2b\n" + "wzVywo5hzx2Uhw51jmoLls4YUvMJXD0wW5ZtYRuPogXvXb/of9ef/20/wU11WFKg\n" + "Xb4gfR8zUXaXS1sXcnVm3+24vIs9dApUwykuoyjOqxWqcHRec2QT2FxVGkFEraze\n" + "CPa4rMECgYEA5Y8CywomIcTgerFGFCeMHJr8nQGqY2V/owFb3k9maczPnC9p4a9R\n" + "c5szLxA9FMYFxurQZMBWSEG2JS1HR2mnjigx8UKjYML/A+rvvjZOMe4M6Sy2ggh4\n" + "SkLZKpWTzjTe07ByM/j5v/SjNZhWAG7sw4/LmPGRQkwJv+KZhGojuOkCgYEA2cOF\n" + "T6cJRv6kvzTz9S0COZOVm+euJh/BXp7oAsAmbNfOpckPMzqHXy8/wpdKl6AAcB57\n" + "OuztlNfV1D7qvbz7JuRlYwQ0cEfBgbZPcz1p18HHDXhwn57ZPb8G33Yh9Omg0HNA\n" + "Imb4LsVuSqxA6NwSj7cpRekgTedrhLFPJ+Ydb5MCgYEAsM3Q7OjILcIg0t6uht9e\n" + "vrlwTsz1mtCV2co2I6crzdj9HeI2vqf1KAElDt6G7PUHhglcr/yjd8uEqmWRPKNX\n" + "ddnnfVZB10jYeP/93pac6z/Zmc3iU4yKeUe7U10ZFf0KkiiYDQd59CpLef/2XScS\n" + "HB0oRofnxRQjfjLc4muNT+ECgYEAlcDk06MOOTly+F8lCc1bA1dgAmgwFd2usDBd\n" + "Y07a3e0HGnGLN3Kfl7C5i0tZq64HvxLnMd2vgLVxQlXGPpdQrC1TH+XLXg+qnlZO\n" + "ivSH7i0/gx75bHvj75eH1XK65V8pDVDEoSPottllAIs21CxLw3N1ObOZWJm2EfmR\n" + "cuHICmsCgYAtFJ1idqMoHxES3mlRpf2JxyQudP3SCm2WpGmqVzhRYInqeatY5sUd\n" + "lPLHm/p77RT7EyxQHTlwn8FJPuM/4ZH1rQd/vB+Y8qAtYJCexDMsbvLW+Js+VOvk\n" + "jweEC0nrcL31j9mF0vz5E6tfRu4hhJ6L4yfWs0gSejskeVB/w8QY4g==\n"; + const std::string password("password"); + const std::string wrongPassword("wrong"); + + T wrapper; + BackEnd& tpm = wrapper.getTpm(); + + Name keyName("/Test/KeyName/KEY/1"); + tpm.deleteKey(keyName); + BOOST_REQUIRE_EQUAL(tpm.hasKey(keyName), false); + + transform::PrivateKey sKey; + sKey.loadPkcs1Base64(reinterpret_cast(privKeyPkcs1.data()), privKeyPkcs1.size()); + OBufferStream os; + sKey.savePkcs8(os, password.data(), password.size()); + auto pkcs8 = os.buf(); + + // import with wrong password + BOOST_CHECK_THROW(tpm.importKey(keyName, pkcs8->data(), pkcs8->size(), wrongPassword.data(), wrongPassword.size()), + Tpm::Error); + BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false); + + // import with correct password + tpm.importKey(keyName, pkcs8->data(), pkcs8->size(), password.data(), password.size()); + BOOST_CHECK_EQUAL(tpm.hasKey(keyName), true); + + // import already present key + BOOST_CHECK_THROW(tpm.importKey(keyName, pkcs8->data(), pkcs8->size(), password.data(), password.size()), + Tpm::Error); + + // test derivePublicKey with the imported key + auto keyHdl = tpm.getKeyHandle(keyName); + auto pubKey = keyHdl->derivePublicKey(); + BOOST_CHECK(pubKey != nullptr); + + // export + auto exportedKey = tpm.exportKey(keyName, password.data(), password.size()); + BOOST_CHECK_EQUAL(tpm.hasKey(keyName), true); + + transform::PrivateKey sKey2; + sKey2.loadPkcs8(exportedKey->data(), exportedKey->size(), password.data(), password.size()); + OBufferStream os2; + sKey.savePkcs1Base64(os2); + auto pkcs1 = os2.buf(); + + // verify that the exported key is identical to the key that was imported + BOOST_CHECK_EQUAL_COLLECTIONS(privKeyPkcs1.begin(), privKeyPkcs1.end(), + pkcs1->begin(), pkcs1->end()); + + // export nonexistent key + tpm.deleteKey(keyName); + BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false); + BOOST_CHECK_THROW(tpm.exportKey(keyName, password.data(), password.size()), Tpm::Error); +} + +BOOST_AUTO_TEST_CASE(RandomKeyId) +{ + BackEndWrapperMem wrapper; + BackEnd& tpm = wrapper.getTpm(); + Name identity("/Test/KeyName"); + + std::set keyNames; + for (int i = 0; i < 100; i++) { + auto key = tpm.createKey(identity, RsaKeyParams()); + Name keyName = key->getKeyName(); + BOOST_CHECK(keyNames.insert(keyName).second); + } +} + +BOOST_AUTO_TEST_SUITE_END() // TestBackEnd +BOOST_AUTO_TEST_SUITE_END() // Tpm +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace tpm +} // namespace security +} // namespace ndn diff --git a/tests/unit-tests/security/transform.t.cpp b/tests/unit/security/transform.t.cpp similarity index 92% rename from tests/unit-tests/security/transform.t.cpp rename to tests/unit/security/transform.t.cpp index ab5d612ff..901839bb1 100644 --- a/tests/unit-tests/security/transform.t.cpp +++ b/tests/unit/security/transform.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,9 +19,9 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "security/transform.hpp" +#include "ndn-cxx/security/transform.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace security { @@ -65,9 +65,6 @@ BOOST_AUTO_TEST_CASE(SymbolVisibility) transform::DigestFilter* digestFilter = nullptr; BOOST_CHECK(digestFilter == nullptr); - transform::HmacFilter* hmacFilter = nullptr; - BOOST_CHECK(hmacFilter == nullptr); - transform::BlockCipher* blockCipher = nullptr; BOOST_CHECK(blockCipher == nullptr); diff --git a/tests/unit-tests/security/transform/base64-decode.t.cpp b/tests/unit/security/transform/base64-decode.t.cpp similarity index 95% rename from tests/unit-tests/security/transform/base64-decode.t.cpp rename to tests/unit/security/transform/base64-decode.t.cpp index 05c9e564f..93d09c233 100644 --- a/tests/unit-tests/security/transform/base64-decode.t.cpp +++ b/tests/unit/security/transform/base64-decode.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,14 +19,13 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "security/transform/base64-decode.hpp" -#include "security/transform/buffer-source.hpp" -#include "security/transform/step-source.hpp" -#include "security/transform/stream-sink.hpp" -#include "encoding/buffer-stream.hpp" -#include +#include "ndn-cxx/security/transform/base64-decode.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/step-source.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace security { @@ -77,7 +76,6 @@ BOOST_AUTO_TEST_CASE(NoNewLine) "AAECAwQFBgcICQoLDA0ODwABAgMEBQYHCAkKCwwNDg8AAQIDBAUGBwgJCgsMDQ4P" "AAECAwQFBgcICQoLDA0ODwABAgMEBQYHCAkKCwwNDg8="; - uint8_t out[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, diff --git a/tests/unit-tests/security/transform/base64-encode.t.cpp b/tests/unit/security/transform/base64-encode.t.cpp similarity index 95% rename from tests/unit-tests/security/transform/base64-encode.t.cpp rename to tests/unit/security/transform/base64-encode.t.cpp index 8d383ab37..228f214b8 100644 --- a/tests/unit-tests/security/transform/base64-encode.t.cpp +++ b/tests/unit/security/transform/base64-encode.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,14 +19,14 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "security/transform/base64-encode.hpp" -#include "security/transform/buffer-source.hpp" -#include "security/transform/step-source.hpp" -#include "security/transform/stream-sink.hpp" -#include "encoding/buffer-stream.hpp" -#include +#include "ndn-cxx/security/transform/base64-encode.hpp" -#include "boost-test.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/step-source.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" + +#include "tests/boost-test.hpp" namespace ndn { namespace security { diff --git a/tests/unit/security/transform/block-cipher.t.cpp b/tests/unit/security/transform/block-cipher.t.cpp new file mode 100644 index 000000000..12b20bbd3 --- /dev/null +++ b/tests/unit/security/transform/block-cipher.t.cpp @@ -0,0 +1,112 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/transform/block-cipher.hpp" + +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" + +#include "tests/boost-test.hpp" + +namespace ndn { +namespace security { +namespace transform { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(Transform) +BOOST_AUTO_TEST_SUITE(TestBlockCipher) + +BOOST_AUTO_TEST_CASE(AesCbc) +{ + const uint8_t key[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + const uint8_t iv[] = { + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + const uint8_t plainText[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + // + // You can use the following shell one-liner to calculate the ciphertext: + // echo ${plaintext} | xxd -p -r | openssl enc -aes-128-cbc -K ${key} -iv ${iv} | xxd -i + // + const uint8_t cipherText[] = { + 0x07, 0x4d, 0x32, 0x68, 0xc3, 0x40, 0x64, 0x43, + 0x1e, 0x66, 0x4c, 0x25, 0x66, 0x42, 0x0f, 0x59, + 0x0a, 0x51, 0x19, 0x07, 0x67, 0x5c, 0x0e, 0xfa, + 0xa6, 0x8c, 0xbb, 0xaf, 0xfd, 0xea, 0x47, 0xd4, + 0xc7, 0x2c, 0x12, 0x34, 0x79, 0xde, 0xec, 0xc8, + 0x75, 0x33, 0x8f, 0x6b, 0xd6, 0x55, 0xf3, 0xfa + }; + + // encrypt + OBufferStream os; + bufferSource(plainText, sizeof(plainText)) >> + blockCipher(BlockCipherAlgorithm::AES_CBC, CipherOperator::ENCRYPT, + key, sizeof(key), iv, sizeof(iv)) >> streamSink(os); + + auto buf = os.buf(); + BOOST_CHECK_EQUAL_COLLECTIONS(cipherText, cipherText + sizeof(cipherText), + buf->begin(), buf->end()); + + // decrypt + OBufferStream os2; + bufferSource(cipherText, sizeof(cipherText)) >> + blockCipher(BlockCipherAlgorithm::AES_CBC, CipherOperator::DECRYPT, + key, sizeof(key), iv, sizeof(iv)) >> streamSink(os2); + + auto buf2 = os2.buf(); + BOOST_CHECK_EQUAL_COLLECTIONS(plainText, plainText + sizeof(plainText), + buf2->begin(), buf2->end()); + + // invalid key length + const uint8_t badKey[] = {0x00, 0x01, 0x02, 0x03}; + BOOST_CHECK_THROW(BlockCipher(BlockCipherAlgorithm::AES_CBC, CipherOperator::ENCRYPT, + badKey, sizeof(badKey), iv, sizeof(iv)), Error); + + // wrong iv length + const uint8_t badIv[] = {0x00, 0x01, 0x02, 0x03}; + BOOST_CHECK_THROW(BlockCipher(BlockCipherAlgorithm::AES_CBC, CipherOperator::ENCRYPT, + key, sizeof(key), badIv, sizeof(badIv)), Error); +} + +BOOST_AUTO_TEST_CASE(InvalidAlgorithm) +{ + BOOST_CHECK_THROW(BlockCipher(BlockCipherAlgorithm::NONE, CipherOperator::ENCRYPT, + nullptr, 0, nullptr, 0), Error); +} + +BOOST_AUTO_TEST_SUITE_END() // TestBlockCipher +BOOST_AUTO_TEST_SUITE_END() // Transform +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace transform +} // namespace security +} // namespace ndn diff --git a/tests/unit-tests/security/transform/bool-sink.t.cpp b/tests/unit/security/transform/bool-sink.t.cpp similarity index 92% rename from tests/unit-tests/security/transform/bool-sink.t.cpp rename to tests/unit/security/transform/bool-sink.t.cpp index 4683219f5..f287e1cd3 100644 --- a/tests/unit-tests/security/transform/bool-sink.t.cpp +++ b/tests/unit/security/transform/bool-sink.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,9 +19,9 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "security/transform/bool-sink.hpp" +#include "ndn-cxx/security/transform/bool-sink.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace security { diff --git a/tests/unit-tests/security/transform/buffer-source.t.cpp b/tests/unit/security/transform/buffer-source.t.cpp similarity index 94% rename from tests/unit-tests/security/transform/buffer-source.t.cpp rename to tests/unit/security/transform/buffer-source.t.cpp index 151fd9634..80b9d8d9e 100644 --- a/tests/unit-tests/security/transform/buffer-source.t.cpp +++ b/tests/unit/security/transform/buffer-source.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,10 +19,10 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "security/transform/buffer-source.hpp" -#include "security/transform/stream-sink.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace security { diff --git a/tests/unit/security/transform/digest-filter.t.cpp b/tests/unit/security/transform/digest-filter.t.cpp new file mode 100644 index 000000000..984611dce --- /dev/null +++ b/tests/unit/security/transform/digest-filter.t.cpp @@ -0,0 +1,222 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/transform/digest-filter.hpp" + +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/impl/openssl.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/step-source.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" + +#include "tests/boost-test.hpp" + +namespace ndn { +namespace security { +namespace transform { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(Transform) +BOOST_AUTO_TEST_SUITE(TestDigestFilter) + +static const uint8_t in[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f +}; +static const uint8_t out[] = { + 0x3e, 0x14, 0xfd, 0x66, 0x9a, 0x79, 0x80, 0x65, + 0xc4, 0x0d, 0x61, 0xf8, 0x6a, 0xc7, 0x98, 0x29, + 0xc0, 0x6b, 0x90, 0x8f, 0xbb, 0x19, 0xa0, 0x85, + 0xf7, 0xfa, 0x7b, 0x2d, 0xd6, 0x8c, 0xd5, 0xa3 +}; + +BOOST_AUTO_TEST_CASE(BufferInput) +{ + OBufferStream os; + bufferSource(in, sizeof(in)) >> digestFilter(DigestAlgorithm::SHA256) >> streamSink(os); + BOOST_CHECK_EQUAL_COLLECTIONS(out, out + sizeof(out), os.buf()->begin(), os.buf()->end()); +} + +BOOST_AUTO_TEST_CASE(StepInput) +{ + StepSource source; + OBufferStream os; + source >> digestFilter(DigestAlgorithm::SHA256) >> streamSink(os); + source.write(in, 32); + source.write(in + 32, 1); + source.write(in + 33, 2); + source.write(in + 35, 3); + source.write(in + 38, 26); + source.write(in + 64, 64); + source.end(); + BOOST_CHECK_EQUAL_COLLECTIONS(out, out + sizeof(out), os.buf()->begin(), os.buf()->end()); +} + +BOOST_AUTO_TEST_CASE(AlgorithmNone) +{ + BOOST_CHECK_THROW(DigestFilter{DigestAlgorithm::NONE}, Error); +} + +BOOST_AUTO_TEST_CASE(AlgorithmSha224) +{ + const uint8_t out[] = { + 0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47, 0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, + 0x15, 0xa2, 0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4, 0x2f, + }; + OBufferStream os; + bufferSource("") >> digestFilter(DigestAlgorithm::SHA224) >> streamSink(os); + BOOST_CHECK_EQUAL_COLLECTIONS(out, out + sizeof(out), os.buf()->begin(), os.buf()->end()); +} + +BOOST_AUTO_TEST_CASE(AlgorithmSha256) +{ + const uint8_t out[] = { + 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, + 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55, + }; + OBufferStream os; + bufferSource("") >> digestFilter(DigestAlgorithm::SHA256) >> streamSink(os); + BOOST_CHECK_EQUAL_COLLECTIONS(out, out + sizeof(out), os.buf()->begin(), os.buf()->end()); +} + +BOOST_AUTO_TEST_CASE(AlgorithmSha384) +{ + const uint8_t out[] = { + 0x38, 0xb0, 0x60, 0xa7, 0x51, 0xac, 0x96, 0x38, 0x4c, 0xd9, 0x32, 0x7e, 0xb1, 0xb1, 0xe3, 0x6a, + 0x21, 0xfd, 0xb7, 0x11, 0x14, 0xbe, 0x07, 0x43, 0x4c, 0x0c, 0xc7, 0xbf, 0x63, 0xf6, 0xe1, 0xda, + 0x27, 0x4e, 0xde, 0xbf, 0xe7, 0x6f, 0x65, 0xfb, 0xd5, 0x1a, 0xd2, 0xf1, 0x48, 0x98, 0xb9, 0x5b, + }; + OBufferStream os; + bufferSource("") >> digestFilter(DigestAlgorithm::SHA384) >> streamSink(os); + BOOST_CHECK_EQUAL_COLLECTIONS(out, out + sizeof(out), os.buf()->begin(), os.buf()->end()); +} + +BOOST_AUTO_TEST_CASE(AlgorithmSha512) +{ + const uint8_t out[] = { + 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, + 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, + 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, + 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e, + }; + OBufferStream os; + bufferSource("") >> digestFilter(DigestAlgorithm::SHA512) >> streamSink(os); + BOOST_CHECK_EQUAL_COLLECTIONS(out, out + sizeof(out), os.buf()->begin(), os.buf()->end()); +} + +#if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_BLAKE2) +BOOST_AUTO_TEST_CASE(AlgorithmBlake2b_512) +{ + const uint8_t out[] = { + 0x78, 0x6a, 0x02, 0xf7, 0x42, 0x01, 0x59, 0x03, 0xc6, 0xc6, 0xfd, 0x85, 0x25, 0x52, 0xd2, 0x72, + 0x91, 0x2f, 0x47, 0x40, 0xe1, 0x58, 0x47, 0x61, 0x8a, 0x86, 0xe2, 0x17, 0xf7, 0x1f, 0x54, 0x19, + 0xd2, 0x5e, 0x10, 0x31, 0xaf, 0xee, 0x58, 0x53, 0x13, 0x89, 0x64, 0x44, 0x93, 0x4e, 0xb0, 0x4b, + 0x90, 0x3a, 0x68, 0x5b, 0x14, 0x48, 0xb7, 0x55, 0xd5, 0x6f, 0x70, 0x1a, 0xfe, 0x9b, 0xe2, 0xce, + }; + OBufferStream os; + bufferSource("") >> digestFilter(DigestAlgorithm::BLAKE2B_512) >> streamSink(os); + BOOST_CHECK_EQUAL_COLLECTIONS(out, out + sizeof(out), os.buf()->begin(), os.buf()->end()); +} + +BOOST_AUTO_TEST_CASE(AlgorithmBlake2s_256) +{ + const uint8_t out[] = { + 0x69, 0x21, 0x7a, 0x30, 0x79, 0x90, 0x80, 0x94, 0xe1, 0x11, 0x21, 0xd0, 0x42, 0x35, 0x4a, 0x7c, + 0x1f, 0x55, 0xb6, 0x48, 0x2c, 0xa1, 0xa5, 0x1e, 0x1b, 0x25, 0x0d, 0xfd, 0x1e, 0xd0, 0xee, 0xf9, + }; + OBufferStream os; + bufferSource("") >> digestFilter(DigestAlgorithm::BLAKE2S_256) >> streamSink(os); + BOOST_CHECK_EQUAL_COLLECTIONS(out, out + sizeof(out), os.buf()->begin(), os.buf()->end()); +} +#endif // OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_BLAKE2) + +#if OPENSSL_VERSION_NUMBER >= 0x10101001L +BOOST_AUTO_TEST_CASE(AlgorithmSha3_224) +{ + const uint8_t out[] = { + 0x6b, 0x4e, 0x03, 0x42, 0x36, 0x67, 0xdb, 0xb7, 0x3b, 0x6e, 0x15, 0x45, 0x4f, 0x0e, 0xb1, 0xab, + 0xd4, 0x59, 0x7f, 0x9a, 0x1b, 0x07, 0x8e, 0x3f, 0x5b, 0x5a, 0x6b, 0xc7, + }; + OBufferStream os; + bufferSource("") >> digestFilter(DigestAlgorithm::SHA3_224) >> streamSink(os); + BOOST_CHECK_EQUAL_COLLECTIONS(out, out + sizeof(out), os.buf()->begin(), os.buf()->end()); +} + +BOOST_AUTO_TEST_CASE(AlgorithmSha3_256) +{ + const uint8_t out[] = { + 0xa7, 0xff, 0xc6, 0xf8, 0xbf, 0x1e, 0xd7, 0x66, 0x51, 0xc1, 0x47, 0x56, 0xa0, 0x61, 0xd6, 0x62, + 0xf5, 0x80, 0xff, 0x4d, 0xe4, 0x3b, 0x49, 0xfa, 0x82, 0xd8, 0x0a, 0x4b, 0x80, 0xf8, 0x43, 0x4a, + }; + OBufferStream os; + bufferSource("") >> digestFilter(DigestAlgorithm::SHA3_256) >> streamSink(os); + BOOST_CHECK_EQUAL_COLLECTIONS(out, out + sizeof(out), os.buf()->begin(), os.buf()->end()); +} + +BOOST_AUTO_TEST_CASE(AlgorithmSha3_384) +{ + const uint8_t out[] = { + 0x0c, 0x63, 0xa7, 0x5b, 0x84, 0x5e, 0x4f, 0x7d, 0x01, 0x10, 0x7d, 0x85, 0x2e, 0x4c, 0x24, 0x85, + 0xc5, 0x1a, 0x50, 0xaa, 0xaa, 0x94, 0xfc, 0x61, 0x99, 0x5e, 0x71, 0xbb, 0xee, 0x98, 0x3a, 0x2a, + 0xc3, 0x71, 0x38, 0x31, 0x26, 0x4a, 0xdb, 0x47, 0xfb, 0x6b, 0xd1, 0xe0, 0x58, 0xd5, 0xf0, 0x04, + }; + OBufferStream os; + bufferSource("") >> digestFilter(DigestAlgorithm::SHA3_384) >> streamSink(os); + BOOST_CHECK_EQUAL_COLLECTIONS(out, out + sizeof(out), os.buf()->begin(), os.buf()->end()); +} + +BOOST_AUTO_TEST_CASE(AlgorithmSha3_512) +{ + const uint8_t out[] = { + 0xa6, 0x9f, 0x73, 0xcc, 0xa2, 0x3a, 0x9a, 0xc5, 0xc8, 0xb5, 0x67, 0xdc, 0x18, 0x5a, 0x75, 0x6e, + 0x97, 0xc9, 0x82, 0x16, 0x4f, 0xe2, 0x58, 0x59, 0xe0, 0xd1, 0xdc, 0xc1, 0x47, 0x5c, 0x80, 0xa6, + 0x15, 0xb2, 0x12, 0x3a, 0xf1, 0xf5, 0xf9, 0x4c, 0x11, 0xe3, 0xe9, 0x40, 0x2c, 0x3a, 0xc5, 0x58, + 0xf5, 0x00, 0x19, 0x9d, 0x95, 0xb6, 0xd3, 0xe3, 0x01, 0x75, 0x85, 0x86, 0x28, 0x1d, 0xcd, 0x26, + }; + OBufferStream os; + bufferSource("") >> digestFilter(DigestAlgorithm::SHA3_512) >> streamSink(os); + BOOST_CHECK_EQUAL_COLLECTIONS(out, out + sizeof(out), os.buf()->begin(), os.buf()->end()); +} +#endif // OPENSSL_VERSION_NUMBER >= 0x10101001L + +BOOST_AUTO_TEST_SUITE_END() // TestDigestFilter +BOOST_AUTO_TEST_SUITE_END() // Transform +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace transform +} // namespace security +} // namespace ndn diff --git a/tests/unit-tests/security/transform/hex-decode.t.cpp b/tests/unit/security/transform/hex-decode.t.cpp similarity index 97% rename from tests/unit-tests/security/transform/hex-decode.t.cpp rename to tests/unit/security/transform/hex-decode.t.cpp index 4a9c78e5c..bd2e88025 100644 --- a/tests/unit-tests/security/transform/hex-decode.t.cpp +++ b/tests/unit/security/transform/hex-decode.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,14 +19,14 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "security/transform/hex-decode.hpp" -#include "security/transform/buffer-source.hpp" -#include "security/transform/step-source.hpp" -#include "security/transform/stream-sink.hpp" -#include "encoding/buffer-stream.hpp" -#include +#include "ndn-cxx/security/transform/hex-decode.hpp" -#include "boost-test.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/step-source.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" + +#include "tests/boost-test.hpp" namespace ndn { namespace security { diff --git a/tests/unit-tests/security/transform/hex-encode.t.cpp b/tests/unit/security/transform/hex-encode.t.cpp similarity index 95% rename from tests/unit-tests/security/transform/hex-encode.t.cpp rename to tests/unit/security/transform/hex-encode.t.cpp index 5edcaaac5..791fdd72c 100644 --- a/tests/unit-tests/security/transform/hex-encode.t.cpp +++ b/tests/unit/security/transform/hex-encode.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,14 +19,13 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "security/transform/hex-encode.hpp" -#include "security/transform/buffer-source.hpp" -#include "security/transform/step-source.hpp" -#include "security/transform/stream-sink.hpp" -#include "encoding/buffer-stream.hpp" -#include +#include "ndn-cxx/security/transform/hex-encode.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/step-source.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace security { diff --git a/tests/unit/security/transform/private-key.t.cpp b/tests/unit/security/transform/private-key.t.cpp new file mode 100644 index 000000000..231747913 --- /dev/null +++ b/tests/unit/security/transform/private-key.t.cpp @@ -0,0 +1,501 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/transform/private-key.hpp" + +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/impl/openssl.hpp" +#include "ndn-cxx/security/key-params.hpp" +#include "ndn-cxx/security/transform/base64-decode.hpp" +#include "ndn-cxx/security/transform/bool-sink.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/public-key.hpp" +#include "ndn-cxx/security/transform/signer-filter.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" +#include "ndn-cxx/security/transform/verifier-filter.hpp" + +#include "tests/boost-test.hpp" + +#include + +#include + +namespace ndn { +namespace security { +namespace transform { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(Transform) +BOOST_AUTO_TEST_SUITE(TestPrivateKey) + +BOOST_AUTO_TEST_CASE(Empty) +{ + // test invoking member functions on an empty (default-constructed) PrivateKey + PrivateKey sKey; + BOOST_CHECK_EQUAL(sKey.getKeyType(), KeyType::NONE); + BOOST_CHECK_EQUAL(sKey.getKeySize(), 0); + BOOST_CHECK_THROW(sKey.getKeyDigest(DigestAlgorithm::SHA256), PrivateKey::Error); + BOOST_CHECK_THROW(sKey.derivePublicKey(), PrivateKey::Error); + const uint8_t theAnswer = 42; + BOOST_CHECK_THROW(sKey.decrypt(&theAnswer, sizeof(theAnswer)), PrivateKey::Error); + std::ostringstream os; + BOOST_CHECK_THROW(sKey.savePkcs1(os), PrivateKey::Error); + std::string passwd("password"); + BOOST_CHECK_THROW(sKey.savePkcs8(os, passwd.data(), passwd.size()), PrivateKey::Error); +} + +BOOST_AUTO_TEST_CASE(KeyDigest) +{ + const Buffer buf(16); + PrivateKey sKey; + sKey.loadRaw(KeyType::HMAC, buf.data(), buf.size()); + auto digest = sKey.getKeyDigest(DigestAlgorithm::SHA256); + + const uint8_t expected[] = { + 0x37, 0x47, 0x08, 0xff, 0xf7, 0x71, 0x9d, 0xd5, 0x97, 0x9e, 0xc8, 0x75, 0xd5, 0x6c, 0xd2, 0x28, + 0x6f, 0x6d, 0x3c, 0xf7, 0xec, 0x31, 0x7a, 0x3b, 0x25, 0x63, 0x2a, 0xab, 0x28, 0xec, 0x37, 0xbb, + }; + BOOST_CHECK_EQUAL_COLLECTIONS(digest->begin(), digest->end(), + expected, expected + sizeof(expected)); +} + +BOOST_AUTO_TEST_CASE(LoadRaw) +{ + const Buffer buf(32); + PrivateKey sKey; + sKey.loadRaw(KeyType::HMAC, buf.data(), buf.size()); + BOOST_CHECK_EQUAL(sKey.getKeyType(), KeyType::HMAC); + BOOST_CHECK_EQUAL(sKey.getKeySize(), 256); + + PrivateKey sKey2; + BOOST_CHECK_THROW(sKey2.loadRaw(KeyType::NONE, buf.data(), buf.size()), std::invalid_argument); + BOOST_CHECK_THROW(sKey2.loadRaw(KeyType::RSA, buf.data(), buf.size()), std::invalid_argument); + BOOST_CHECK_THROW(sKey2.loadRaw(KeyType::EC, buf.data(), buf.size()), std::invalid_argument); + BOOST_CHECK_THROW(sKey2.loadRaw(KeyType::AES, buf.data(), buf.size()), std::invalid_argument); +} + +struct RsaKeyTestData +{ + const size_t keySize = 2048; + const std::string privateKeyPkcs1 = + "MIIEpAIBAAKCAQEAw0WM1/WhAxyLtEqsiAJgWDZWuzkYpeYVdeeZcqRZzzfRgBQT\n" + "sNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobws3iigohnM9yTK+KKiayPhIAm/+5H\n" + "GT6SgFJhYhqo1/upWdueojil6RP4/AgavHhopxlAVbk6G9VdVnlQcQ5Zv0OcGi73\n" + "c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9gZwIL5PuE9BiO6I39cL9z7EK1SfZh\n" + "OWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA9rH58ynaAix0tcR/nBMRLUX+e3rU\n" + "RHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0ywIDAQABAoIBADQkckOIl4IZMUTn\n" + "W8LFv6xOdkJwMKC8G6bsPRFbyY+HvC2TLt7epSvfS+f4AcYWaOPcDu2E49vt2sNr\n" + "cASly8hgwiRRAB3dHH9vcsboiTo8bi2RFvMqvjv9w3tK2yMxVDtmZamzrrnaV3YV\n" + "Q+5nyKo2F/PMDjQ4eUAKDOzjhBuKHsZBTFnA1MFNI+UKj5X4Yp64DFmKlxTX/U2b\n" + "wzVywo5hzx2Uhw51jmoLls4YUvMJXD0wW5ZtYRuPogXvXb/of9ef/20/wU11WFKg\n" + "Xb4gfR8zUXaXS1sXcnVm3+24vIs9dApUwykuoyjOqxWqcHRec2QT2FxVGkFEraze\n" + "CPa4rMECgYEA5Y8CywomIcTgerFGFCeMHJr8nQGqY2V/owFb3k9maczPnC9p4a9R\n" + "c5szLxA9FMYFxurQZMBWSEG2JS1HR2mnjigx8UKjYML/A+rvvjZOMe4M6Sy2ggh4\n" + "SkLZKpWTzjTe07ByM/j5v/SjNZhWAG7sw4/LmPGRQkwJv+KZhGojuOkCgYEA2cOF\n" + "T6cJRv6kvzTz9S0COZOVm+euJh/BXp7oAsAmbNfOpckPMzqHXy8/wpdKl6AAcB57\n" + "OuztlNfV1D7qvbz7JuRlYwQ0cEfBgbZPcz1p18HHDXhwn57ZPb8G33Yh9Omg0HNA\n" + "Imb4LsVuSqxA6NwSj7cpRekgTedrhLFPJ+Ydb5MCgYEAsM3Q7OjILcIg0t6uht9e\n" + "vrlwTsz1mtCV2co2I6crzdj9HeI2vqf1KAElDt6G7PUHhglcr/yjd8uEqmWRPKNX\n" + "ddnnfVZB10jYeP/93pac6z/Zmc3iU4yKeUe7U10ZFf0KkiiYDQd59CpLef/2XScS\n" + "HB0oRofnxRQjfjLc4muNT+ECgYEAlcDk06MOOTly+F8lCc1bA1dgAmgwFd2usDBd\n" + "Y07a3e0HGnGLN3Kfl7C5i0tZq64HvxLnMd2vgLVxQlXGPpdQrC1TH+XLXg+qnlZO\n" + "ivSH7i0/gx75bHvj75eH1XK65V8pDVDEoSPottllAIs21CxLw3N1ObOZWJm2EfmR\n" + "cuHICmsCgYAtFJ1idqMoHxES3mlRpf2JxyQudP3SCm2WpGmqVzhRYInqeatY5sUd\n" + "lPLHm/p77RT7EyxQHTlwn8FJPuM/4ZH1rQd/vB+Y8qAtYJCexDMsbvLW+Js+VOvk\n" + "jweEC0nrcL31j9mF0vz5E6tfRu4hhJ6L4yfWs0gSejskeVB/w8QY4g==\n"; + const std::string privateKeyPkcs8 = + "MIIFCzA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIOKYJXvB6p8kCAggA\n" + "MBEGBSsOAwIHBAiQgMK8kQXTyASCBMjeNiKYYw5/yHgs9BfSGrpqvV0LkkgMQNUW\n" + "R4ZY8fuNjZynd+PxDuw2pyrv1Yv3jc+tupwUehZEzYOnGd53wQAuLO+Z0TBgRFN7\n" + "Lhk+AxlT7hu0xaB3ZpJ/uvWpgEJHsq/aB/GYgyzXcQo2AiqzERVpMCWJVmE1L977\n" + "CHwJmLm5mxclVLYp1UK5lkIBFu/M4nPavmNmYNUU1LOrXRo56TlJ2kUp8gQyQI1P\n" + "VPxi4chmlsr/OnQ2d1eZN+euFm0CS+yP+LFgI9ZqdyH1w+J43SXdHDzauVcZp7oa\n" + "Kw24OrhHfolLAnQIECXEJYeT7tZmhC4O9V6B18PFVyxWnEU4eFNpFE8kYSmm8Um2\n" + "buvDKI71q43hm23moYT9uIM1f4M8UkoOliJGrlf4xgEcmDuokEX01PdOq1gc4nvG\n" + "0DCwDI9cOsyn8cxhk9UVtFgzuG/seuznxIv1F5H0hzYOyloStXxRisJES0kgByBt\n" + "FFTfyoFKRrmCjRIygwVKUSkSDR0DlQS5ZLvQyIswnSQFwxAHqfvoSL4dB9UAIAQ+\n" + "ALVF1maaHgptbL6Ifqf0GFCv0hdNCVNDNCdy8R+S6nEYE+YdYSIdT1L88KD5PjU3\n" + "YY/CMnxhTncMaT4acPO1UUYuSGRZ/JL6E0ihoqIU+bqUgLSHNzhPySPfN9uqN61Y\n" + "HFBtxeEPWKU0f/JPkRBMmZdMI1/OVmA3QHSRBydI+CQN8no2gZRFoVbHTkG8IMpE\n" + "1fiDJpwFkpzIv/JPiTSE7DeBH5NJk1bgu7TcuZfa4unyAqss0UuLnXzS06TppkUj\n" + "QGft0g8VPW56eli6B4xrSzzuvAdbrxsVfxdmtHPyYxLb3/UG1g4x/H/yULhx7x9P\n" + "iI6cw6JUE+8bwJV2ZIlHXXHO+wUp/gCFJ6MHo9wkR1QvnHP2ClJAzBm9OvYnUx2Y\n" + "SX0HxEowW8BkhxOF184LEmxeua0yyZUqCdrYmErp7x9EY/LhD1zBwH8OGRa0qzmR\n" + "VKxAPKihkb9OgxcUKbvKePx3k2cQ7fbCUspGPm4Kn1zwMgRAZ4fz/o8Lnwc8MSY3\n" + "lPWnmLTFu420SRH2g9N0o/r195hiZ5cc+KfF4pwZWKbEbKFk/UfXA9vmOi7BBtDJ\n" + "RWshOINhzMU6Ij3KuaEpHni1HoHjw0SQ97ow2x/aB8k2QC28tbsa49lD2KKJku6b\n" + "2Or89adwFKqMgS2IXfXMXs/iG5EFLYN6r8e40Dn5f1vJfRLJl03XByIfT2n92pw3\n" + "fP7muOIKLUsEKjOrmn94NwMlfeW13oQHEH2KjPOWFS/tyJHDdVU+of4COH5yg59a\n" + "TZqFkOTGeliE1O+6sfF9fRuVxFUF3D8Hpr0JIjdc6+3RgIlGsXc8BwiSjDSI2XW+\n" + "vo75/2zPU9t8OeXEIJk2CQGyqLwUJ6dyi/yDRrvZAgjrUvbpcxydnBAHrLbLUGXJ\n" + "aEHH2tjEtnTqVyTchr1yHoupcFOCkA0dAA66XqwcssQxJiMGrWTpCbgd9mrTXQaZ\n" + "U7afFN1jpO78tgBQUUpImXdHLLsqdN5tefqjileZGZ9x3/C6TNAfDwYJdsicNNn5\n" + "y+JVsbltfLWlJxb9teb3dtQiFlJ7ofprLJnJVqI/Js8lozY+KaxV2vtbZkcD4dM=\n"; + const std::string publicKeyPkcs8 = + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw0WM1/WhAxyLtEqsiAJg\n" + "WDZWuzkYpeYVdeeZcqRZzzfRgBQTsNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobw\n" + "s3iigohnM9yTK+KKiayPhIAm/+5HGT6SgFJhYhqo1/upWdueojil6RP4/AgavHho\n" + "pxlAVbk6G9VdVnlQcQ5Zv0OcGi73c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9g\n" + "ZwIL5PuE9BiO6I39cL9z7EK1SfZhOWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA\n" + "9rH58ynaAix0tcR/nBMRLUX+e3rURHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0\n" + "ywIDAQAB\n"; +}; + +struct EcKeyTestData +{ + const size_t keySize = 256; + const std::string privateKeyPkcs1 = + "MIIBaAIBAQQgRxwcbzK9RV6AHYFsDcykI86o3M/a1KlJn0z8PcLMBZOggfowgfcC\n" + "AQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA////////////////\n" + "MFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57Pr\n" + "vVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEE\n" + "axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54W\n" + "K84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8\n" + "YyVRAgEBoUQDQgAEaG4WJuDAt0QkEM4t29KDUdzkQlMPGrqWzkWhgt9OGnwc6O7A\n" + "ZLPSrDyhwyrKS7XLRXml5DisQ93RvByll32y8A==\n"; + const std::string privateKeyPkcs8 = + "MIIBwzA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIVHkBzLGtDvICAggA\n" + "MBEGBSsOAwIHBAhk6g9eI3toNwSCAYDd+LWPDBTrKV7vUyxTvDbpUd0eXfh73DKA\n" + "MHkdHuVmhpmpBbsF9XvaFuL8J/1xi1Yl2XGw8j3WyrprD2YEhl/+zKjNbdTDJmNO\n" + "SlomuwWb5AVCJ9reT94zIXKCnexUcyBFS7ep+P4dwuef0VjzprjfmnAZHrP+u594\n" + "ELHpKwi0ZpQLtcJjjud13bn43vbXb+aU7jmPV5lU2XP8TxaQJiYIibNEh1Y3TZGr\n" + "akJormYvhaYbiZkKLHQ9AvQMEjhoIW5WCB3q+tKZUKTzcQpjNnf9FOTeKN3jk3Kd\n" + "2OmibPZcbMJdgCD/nRVn1cBo7Hjn3IMjgtszQHtEUphOQiAkOJUnKmy9MTYqtcNN\n" + "6cuFItbu4QvbVwailgdUjOYwIJCmIxExlPV0ohS24pFGsO03Yn7W8rBB9VWENYmG\n" + "HkZIbGsHv7O9Wy7fv+FJgZkjeti0807IsNXSJl8LUK0ZIhAR7OU8uONWMsbHdQnk\n" + "q1HB1ZKa52ugACl7g/DF9b7CoSAjFeE=\n"; + const std::string publicKeyPkcs8 = + "MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\n" + "AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////\n" + "///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd\n" + "NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5\n" + "RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n" + "//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABGhuFibgwLdEJBDOLdvSg1Hc\n" + "5EJTDxq6ls5FoYLfThp8HOjuwGSz0qw8ocMqyku1y0V5peQ4rEPd0bwcpZd9svA=\n"; +}; + +using KeyTestDataSets = boost::mpl::vector; + +static void +checkPkcs8Encoding(ConstBufferPtr encoding, const std::string& password, ConstBufferPtr pkcs1) +{ + PrivateKey sKey; + sKey.loadPkcs8(encoding->data(), encoding->size(), password.data(), password.size()); + OBufferStream os; + sKey.savePkcs1(os); + BOOST_CHECK_EQUAL_COLLECTIONS(pkcs1->begin(), pkcs1->end(), + os.buf()->begin(), os.buf()->end()); +} + +static void +checkPkcs8Base64Encoding(ConstBufferPtr encoding, const std::string& password, ConstBufferPtr pkcs1) +{ + OBufferStream os; + bufferSource(*encoding) >> base64Decode() >> streamSink(os); + checkPkcs8Encoding(os.buf(), password, pkcs1); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(SaveLoad, T, KeyTestDataSets) +{ + T dataSet; + + const uint8_t* sKeyPkcs1Base64 = reinterpret_cast(dataSet.privateKeyPkcs1.data()); + size_t sKeyPkcs1Base64Len = dataSet.privateKeyPkcs1.size(); + OBufferStream os; + bufferSource(sKeyPkcs1Base64, sKeyPkcs1Base64Len) >> base64Decode() >> streamSink(os); + ConstBufferPtr sKeyPkcs1Buf = os.buf(); + const uint8_t* sKeyPkcs1 = sKeyPkcs1Buf->data(); + size_t sKeyPkcs1Len = sKeyPkcs1Buf->size(); + + // load key in base64-encoded pkcs1 format + PrivateKey sKey; + BOOST_CHECK_NO_THROW(sKey.loadPkcs1Base64(sKeyPkcs1Base64, sKeyPkcs1Base64Len)); + BOOST_CHECK_EQUAL(sKey.getKeySize(), dataSet.keySize); + + std::stringstream ss2(dataSet.privateKeyPkcs1); + PrivateKey sKey2; + BOOST_CHECK_NO_THROW(sKey2.loadPkcs1Base64(ss2)); + + // load key in pkcs1 format + PrivateKey sKey3; + BOOST_CHECK_NO_THROW(sKey3.loadPkcs1(sKeyPkcs1, sKeyPkcs1Len)); + BOOST_CHECK_EQUAL(sKey3.getKeySize(), dataSet.keySize); + + std::stringstream ss4; + ss4.write(reinterpret_cast(sKeyPkcs1), sKeyPkcs1Len); + PrivateKey sKey4; + BOOST_CHECK_NO_THROW(sKey4.loadPkcs1(ss4)); + + // save key in base64-encoded pkcs1 format + OBufferStream os2; + BOOST_REQUIRE_NO_THROW(sKey.savePkcs1Base64(os2)); + BOOST_CHECK_EQUAL_COLLECTIONS(sKeyPkcs1Base64, sKeyPkcs1Base64 + sKeyPkcs1Base64Len, + os2.buf()->begin(), os2.buf()->end()); + + // save key in pkcs1 format + OBufferStream os3; + BOOST_REQUIRE_NO_THROW(sKey.savePkcs1(os3)); + BOOST_CHECK_EQUAL_COLLECTIONS(sKeyPkcs1, sKeyPkcs1 + sKeyPkcs1Len, + os3.buf()->begin(), os3.buf()->end()); + + const uint8_t* sKeyPkcs8Base64 = reinterpret_cast(dataSet.privateKeyPkcs8.data()); + size_t sKeyPkcs8Base64Len = dataSet.privateKeyPkcs8.size(); + OBufferStream os4; + bufferSource(sKeyPkcs8Base64, sKeyPkcs8Base64Len) >> base64Decode() >> streamSink(os4); + const uint8_t* sKeyPkcs8 = os4.buf()->data(); + size_t sKeyPkcs8Len = os4.buf()->size(); + + std::string password("password"); + std::string wrongpw("wrongpw"); + auto pwCallback = [&password] (char* buf, size_t size, int) -> int { + BOOST_REQUIRE_LE(password.size(), size); + std::copy(password.begin(), password.end(), buf); + return static_cast(password.size()); + }; + + // load key in base64-encoded pkcs8 format + PrivateKey sKey5; + BOOST_CHECK_NO_THROW(sKey5.loadPkcs8Base64(sKeyPkcs8Base64, sKeyPkcs8Base64Len, + password.data(), password.size())); + BOOST_CHECK_EQUAL(sKey5.getKeySize(), dataSet.keySize); + + PrivateKey sKey6; + BOOST_CHECK_NO_THROW(sKey6.loadPkcs8Base64(sKeyPkcs8Base64, sKeyPkcs8Base64Len, pwCallback)); + + std::stringstream ss7(dataSet.privateKeyPkcs8); + PrivateKey sKey7; + BOOST_CHECK_NO_THROW(sKey7.loadPkcs8Base64(ss7, password.data(), password.size())); + + std::stringstream ss8(dataSet.privateKeyPkcs8); + PrivateKey sKey8; + BOOST_CHECK_NO_THROW(sKey8.loadPkcs8Base64(ss8, pwCallback)); + + // load key in pkcs8 format + PrivateKey sKey9; + BOOST_CHECK_NO_THROW(sKey9.loadPkcs8(sKeyPkcs8, sKeyPkcs8Len, password.data(), password.size())); + BOOST_CHECK_EQUAL(sKey9.getKeySize(), dataSet.keySize); + + PrivateKey sKey10; + BOOST_CHECK_NO_THROW(sKey10.loadPkcs8(sKeyPkcs8, sKeyPkcs8Len, pwCallback)); + + std::stringstream ss11; + ss11.write(reinterpret_cast(sKeyPkcs8), sKeyPkcs8Len); + PrivateKey sKey11; + BOOST_CHECK_NO_THROW(sKey11.loadPkcs8(ss11, password.data(), password.size())); + + std::stringstream ss12; + ss12.write(reinterpret_cast(sKeyPkcs8), sKeyPkcs8Len); + PrivateKey sKey12; + BOOST_CHECK_NO_THROW(sKey12.loadPkcs8(ss12, pwCallback)); + + // load key using wrong password, Error is expected + PrivateKey sKey13; + BOOST_CHECK_THROW(sKey13.loadPkcs8Base64(sKeyPkcs8Base64, sKeyPkcs8Base64Len, wrongpw.data(), wrongpw.size()), + PrivateKey::Error); + BOOST_CHECK_EQUAL(sKey13.getKeyType(), KeyType::NONE); + BOOST_CHECK_EQUAL(sKey13.getKeySize(), 0); + + // save key in base64-encoded pkcs8 format + OBufferStream os14; + BOOST_REQUIRE_NO_THROW(sKey.savePkcs8Base64(os14, password.data(), password.size())); + checkPkcs8Base64Encoding(os14.buf(), password, sKeyPkcs1Buf); + + OBufferStream os15; + BOOST_REQUIRE_NO_THROW(sKey.savePkcs8Base64(os15, pwCallback)); + checkPkcs8Base64Encoding(os15.buf(), password, sKeyPkcs1Buf); + + // save key in pkcs8 format + OBufferStream os16; + BOOST_REQUIRE_NO_THROW(sKey.savePkcs8(os16, password.data(), password.size())); + checkPkcs8Encoding(os16.buf(), password, sKeyPkcs1Buf); + + OBufferStream os17; + BOOST_REQUIRE_NO_THROW(sKey.savePkcs8(os17, pwCallback)); + checkPkcs8Encoding(os17.buf(), password, sKeyPkcs1Buf); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(DerivePublicKey, T, KeyTestDataSets) +{ + T dataSet; + + const uint8_t* sKeyPkcs1Base64 = reinterpret_cast(dataSet.privateKeyPkcs1.data()); + size_t sKeyPkcs1Base64Len = dataSet.privateKeyPkcs1.size(); + PrivateKey sKey; + sKey.loadPkcs1Base64(sKeyPkcs1Base64, sKeyPkcs1Base64Len); + + // derive public key and compare + ConstBufferPtr pKeyBits = sKey.derivePublicKey(); + OBufferStream os; + bufferSource(dataSet.publicKeyPkcs8) >> base64Decode() >> streamSink(os); + BOOST_CHECK_EQUAL_COLLECTIONS(pKeyBits->begin(), pKeyBits->end(), + os.buf()->begin(), os.buf()->end()); +} + +BOOST_AUTO_TEST_CASE(RsaDecryption) +{ + RsaKeyTestData dataSet; + + PrivateKey sKey; + sKey.loadPkcs1Base64(reinterpret_cast(dataSet.privateKeyPkcs1.data()), + dataSet.privateKeyPkcs1.size()); + BOOST_CHECK_EQUAL(sKey.getKeyType(), KeyType::RSA); + + const uint8_t plainText[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; + + const std::string cipherTextBase64 = + "i2XNpZ2JbLa4JmBTdDrGmsd4/0C+p+BSCpW3MuPBNe5uChQ0eRO1dvjTnEqwSECY\n" + "38en9JZwcyb0It/TSFNXHlq+Z1ZpffnjIJxQR9HcgwvwQJh6WRH0vu38tvGkGuNv\n" + "60Rdn85hqSy1CikmXCeWXL9yCqeqcP21R94G/T3FuA+c1FtFko8KOzCwvrTXMO6n\n" + "5PNsqlLXabSGr+jz4EwOsSCgPkiDf9U6tXoSPRA2/YvqFQdaiUXIVlomESvaqqZ8\n" + "FxPs2BON0lobM8gT+xdzbRKofp+rNjNK+5uWyeOnXJwzCszh17cdJl2BH1dZwaVD\n" + "PmTiSdeDQXZ94U5boDQ4Aw==\n"; + OBufferStream os; + bufferSource(cipherTextBase64) >> base64Decode() >> streamSink(os); + + auto decrypted = sKey.decrypt(os.buf()->data(), os.buf()->size()); + BOOST_CHECK_EQUAL_COLLECTIONS(plainText, plainText + sizeof(plainText), + decrypted->begin(), decrypted->end()); +} + +BOOST_AUTO_TEST_CASE(RsaEncryptDecrypt) +{ + RsaKeyTestData dataSet; + + PublicKey pKey; + pKey.loadPkcs8Base64(reinterpret_cast(dataSet.publicKeyPkcs8.data()), + dataSet.publicKeyPkcs8.size()); + BOOST_CHECK_EQUAL(pKey.getKeyType(), KeyType::RSA); + + PrivateKey sKey; + sKey.loadPkcs1Base64(reinterpret_cast(dataSet.privateKeyPkcs1.data()), + dataSet.privateKeyPkcs1.size()); + BOOST_CHECK_EQUAL(sKey.getKeyType(), KeyType::RSA); + + const uint8_t plainText[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; + + auto cipherText = pKey.encrypt(plainText, sizeof(plainText)); + auto decrypted = sKey.decrypt(cipherText->data(), cipherText->size()); + BOOST_CHECK_EQUAL_COLLECTIONS(plainText, plainText + sizeof(plainText), + decrypted->begin(), decrypted->end()); +} + +BOOST_AUTO_TEST_CASE(UnsupportedDecryption) +{ + OBufferStream os; + bufferSource("Y2lhbyFob2xhIWhlbGxvIQ==") >> base64Decode() >> streamSink(os); + + auto ecKey = generatePrivateKey(EcKeyParams()); + BOOST_CHECK_THROW(ecKey->decrypt(os.buf()->data(), os.buf()->size()), PrivateKey::Error); + + auto hmacKey = generatePrivateKey(HmacKeyParams()); + BOOST_CHECK_THROW(hmacKey->decrypt(os.buf()->data(), os.buf()->size()), PrivateKey::Error); +} + +struct RsaKeyGenParams +{ + using Params = RsaKeyParams; + using hasPublicKey = std::true_type; + using canSavePkcs1 = std::true_type; +}; + +struct EcKeyGenParams +{ + using Params = EcKeyParams; + using hasPublicKey = std::true_type; + using canSavePkcs1 = std::true_type; +}; + +struct HmacKeyGenParams +{ + using Params = HmacKeyParams; + using hasPublicKey = std::false_type; + using canSavePkcs1 = std::false_type; +}; + +using KeyGenParams = boost::mpl::vector; + +BOOST_AUTO_TEST_CASE_TEMPLATE(GenerateKey, T, KeyGenParams) +{ + typename T::Params params; + auto sKey = generatePrivateKey(params); + BOOST_CHECK_EQUAL(sKey->getKeyType(), params.getKeyType()); + BOOST_CHECK_EQUAL(sKey->getKeySize(), params.getKeySize()); + + const uint8_t data[] = {0x01, 0x02, 0x03, 0x04}; + OBufferStream os; + BOOST_REQUIRE_NO_THROW(bufferSource(data, sizeof(data)) >> + signerFilter(DigestAlgorithm::SHA256, *sKey) >> + streamSink(os)); + auto sig = os.buf(); + + bool result = false; + if (typename T::hasPublicKey()) { + auto pKeyBits = sKey->derivePublicKey(); + PublicKey pKey; + pKey.loadPkcs8(pKeyBits->data(), pKeyBits->size()); + BOOST_CHECK_NO_THROW(bufferSource(data, sizeof(data)) >> + verifierFilter(DigestAlgorithm::SHA256, pKey, sig->data(), sig->size()) >> + boolSink(result)); + } + else { +#if OPENSSL_VERSION_NUMBER >= 0x1010100fL + BOOST_CHECK_THROW(sKey->derivePublicKey(), PrivateKey::Error); +#endif + BOOST_CHECK_NO_THROW(bufferSource(data, sizeof(data)) >> + verifierFilter(DigestAlgorithm::SHA256, *sKey, sig->data(), sig->size()) >> + boolSink(result)); + } + BOOST_CHECK(result); + + if (typename T::canSavePkcs1()) { + auto sKey2 = generatePrivateKey(params); + + OBufferStream os1; + sKey->savePkcs1(os1); + OBufferStream os2; + sKey2->savePkcs1(os2); + + BOOST_CHECK(*os1.buf() != *os2.buf()); + } + else { +#if OPENSSL_VERSION_NUMBER >= 0x1010100fL + OBufferStream os1; + BOOST_CHECK_THROW(sKey->savePkcs1(os1), PrivateKey::Error); +#endif + } +} + +BOOST_AUTO_TEST_CASE(GenerateKeyUnsupportedType) +{ + BOOST_CHECK_THROW(generatePrivateKey(AesKeyParams()), std::invalid_argument); +} + +BOOST_AUTO_TEST_SUITE_END() // TestPrivateKey +BOOST_AUTO_TEST_SUITE_END() // Transform +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace transform +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/transform/public-key.t.cpp b/tests/unit/security/transform/public-key.t.cpp new file mode 100644 index 000000000..ae234b300 --- /dev/null +++ b/tests/unit/security/transform/public-key.t.cpp @@ -0,0 +1,133 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/transform/public-key.hpp" + +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/transform.hpp" + +#include "tests/boost-test.hpp" + +#include + +#include + +namespace ndn { +namespace security { +namespace transform { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(Transform) +BOOST_AUTO_TEST_SUITE(TestPublicKey) + +struct RsaKeyTestData +{ + const std::string publicKeyPkcs8 = + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw0WM1/WhAxyLtEqsiAJg\n" + "WDZWuzkYpeYVdeeZcqRZzzfRgBQTsNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobw\n" + "s3iigohnM9yTK+KKiayPhIAm/+5HGT6SgFJhYhqo1/upWdueojil6RP4/AgavHho\n" + "pxlAVbk6G9VdVnlQcQ5Zv0OcGi73c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9g\n" + "ZwIL5PuE9BiO6I39cL9z7EK1SfZhOWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA\n" + "9rH58ynaAix0tcR/nBMRLUX+e3rURHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0\n" + "ywIDAQAB\n"; +}; + +struct EcKeyTestData +{ + const std::string publicKeyPkcs8 = + "MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\n" + "AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////\n" + "///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd\n" + "NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5\n" + "RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n" + "//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABGhuFibgwLdEJBDOLdvSg1Hc\n" + "5EJTDxq6ls5FoYLfThp8HOjuwGSz0qw8ocMqyku1y0V5peQ4rEPd0bwcpZd9svA=\n"; +}; + +using KeyTestDataSets = boost::mpl::vector; + +BOOST_AUTO_TEST_CASE_TEMPLATE(SaveLoad, T, KeyTestDataSets) +{ + T dataSet; + + const uint8_t* pKeyPkcs8Base64 = reinterpret_cast(dataSet.publicKeyPkcs8.c_str()); + size_t pKeyPkcs8Base64Len = dataSet.publicKeyPkcs8.size(); + OBufferStream os; + bufferSource(pKeyPkcs8Base64, pKeyPkcs8Base64Len) >> base64Decode() >> streamSink(os); + ConstBufferPtr pKeyPkcs8Buf = os.buf(); + const uint8_t* pKeyPkcs8 = pKeyPkcs8Buf->data(); + size_t pKeyPkcs8Len = pKeyPkcs8Buf->size(); + + PublicKey pKey1; + BOOST_CHECK_NO_THROW(pKey1.loadPkcs8Base64(pKeyPkcs8Base64, pKeyPkcs8Base64Len)); + + std::stringstream ss2(dataSet.publicKeyPkcs8); + PublicKey pKey2; + BOOST_CHECK_NO_THROW(pKey2.loadPkcs8Base64(ss2)); + + PublicKey pKey3; + BOOST_CHECK_NO_THROW(pKey3.loadPkcs8(pKeyPkcs8, pKeyPkcs8Len)); + + std::stringstream ss4; + ss4.write(reinterpret_cast(pKeyPkcs8), pKeyPkcs8Len); + PublicKey pKey4; + BOOST_CHECK_NO_THROW(pKey4.loadPkcs8(ss4)); + + OBufferStream os5; + BOOST_REQUIRE_NO_THROW(pKey1.savePkcs8Base64(os5)); + BOOST_CHECK_EQUAL_COLLECTIONS(pKeyPkcs8Base64, pKeyPkcs8Base64 + pKeyPkcs8Base64Len, + os5.buf()->begin(), os5.buf()->end()); + + OBufferStream os6; + BOOST_REQUIRE_NO_THROW(pKey1.savePkcs8(os6)); + BOOST_CHECK_EQUAL_COLLECTIONS(pKeyPkcs8, pKeyPkcs8 + pKeyPkcs8Len, + os6.buf()->begin(), os6.buf()->end()); +} + +// NOTE: We cannot test RSA encryption by comparing the computed ciphertext to +// a known-good one, because OAEP padding is randomized and would produce +// different results every time. An encrypt/decrypt round-trip test is +// performed in private-key.t.cpp + +BOOST_AUTO_TEST_CASE(UnsupportedEcEncryption) +{ + EcKeyTestData dataSet; + + PublicKey pKey; + pKey.loadPkcs8Base64(reinterpret_cast(dataSet.publicKeyPkcs8.c_str()), + dataSet.publicKeyPkcs8.size()); + BOOST_CHECK_EQUAL(pKey.getKeyType(), KeyType::EC); + + OBufferStream os; + bufferSource("Y2lhbyFob2xhIWhlbGxvIQ==") >> base64Decode() >> streamSink(os); + + BOOST_CHECK_THROW(pKey.encrypt(os.buf()->data(), os.buf()->size()), PublicKey::Error); +} + +BOOST_AUTO_TEST_SUITE_END() // TestPublicKey +BOOST_AUTO_TEST_SUITE_END() // Transform +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace transform +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/transform/signer-filter.t.cpp b/tests/unit/security/transform/signer-filter.t.cpp new file mode 100644 index 000000000..4f3fa04c2 --- /dev/null +++ b/tests/unit/security/transform/signer-filter.t.cpp @@ -0,0 +1,248 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/transform/signer-filter.hpp" + +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/key-params.hpp" +#include "ndn-cxx/security/transform/base64-decode.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/private-key.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" +#include "ndn-cxx/security/verification-helpers.hpp" + +#include "tests/boost-test.hpp" + +namespace ndn { +namespace security { +namespace transform { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(Transform) +BOOST_AUTO_TEST_SUITE(TestSignerFilter) + +const uint8_t DATA[] = {0x01, 0x02, 0x03, 0x04}; + +BOOST_AUTO_TEST_CASE(Rsa) +{ + const std::string publicKeyPkcs8 = + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw0WM1/WhAxyLtEqsiAJg\n" + "WDZWuzkYpeYVdeeZcqRZzzfRgBQTsNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobw\n" + "s3iigohnM9yTK+KKiayPhIAm/+5HGT6SgFJhYhqo1/upWdueojil6RP4/AgavHho\n" + "pxlAVbk6G9VdVnlQcQ5Zv0OcGi73c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9g\n" + "ZwIL5PuE9BiO6I39cL9z7EK1SfZhOWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA\n" + "9rH58ynaAix0tcR/nBMRLUX+e3rURHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0\n" + "ywIDAQAB\n"; + const std::string privateKeyPkcs1 = + "MIIEpAIBAAKCAQEAw0WM1/WhAxyLtEqsiAJgWDZWuzkYpeYVdeeZcqRZzzfRgBQT\n" + "sNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobws3iigohnM9yTK+KKiayPhIAm/+5H\n" + "GT6SgFJhYhqo1/upWdueojil6RP4/AgavHhopxlAVbk6G9VdVnlQcQ5Zv0OcGi73\n" + "c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9gZwIL5PuE9BiO6I39cL9z7EK1SfZh\n" + "OWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA9rH58ynaAix0tcR/nBMRLUX+e3rU\n" + "RHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0ywIDAQABAoIBADQkckOIl4IZMUTn\n" + "W8LFv6xOdkJwMKC8G6bsPRFbyY+HvC2TLt7epSvfS+f4AcYWaOPcDu2E49vt2sNr\n" + "cASly8hgwiRRAB3dHH9vcsboiTo8bi2RFvMqvjv9w3tK2yMxVDtmZamzrrnaV3YV\n" + "Q+5nyKo2F/PMDjQ4eUAKDOzjhBuKHsZBTFnA1MFNI+UKj5X4Yp64DFmKlxTX/U2b\n" + "wzVywo5hzx2Uhw51jmoLls4YUvMJXD0wW5ZtYRuPogXvXb/of9ef/20/wU11WFKg\n" + "Xb4gfR8zUXaXS1sXcnVm3+24vIs9dApUwykuoyjOqxWqcHRec2QT2FxVGkFEraze\n" + "CPa4rMECgYEA5Y8CywomIcTgerFGFCeMHJr8nQGqY2V/owFb3k9maczPnC9p4a9R\n" + "c5szLxA9FMYFxurQZMBWSEG2JS1HR2mnjigx8UKjYML/A+rvvjZOMe4M6Sy2ggh4\n" + "SkLZKpWTzjTe07ByM/j5v/SjNZhWAG7sw4/LmPGRQkwJv+KZhGojuOkCgYEA2cOF\n" + "T6cJRv6kvzTz9S0COZOVm+euJh/BXp7oAsAmbNfOpckPMzqHXy8/wpdKl6AAcB57\n" + "OuztlNfV1D7qvbz7JuRlYwQ0cEfBgbZPcz1p18HHDXhwn57ZPb8G33Yh9Omg0HNA\n" + "Imb4LsVuSqxA6NwSj7cpRekgTedrhLFPJ+Ydb5MCgYEAsM3Q7OjILcIg0t6uht9e\n" + "vrlwTsz1mtCV2co2I6crzdj9HeI2vqf1KAElDt6G7PUHhglcr/yjd8uEqmWRPKNX\n" + "ddnnfVZB10jYeP/93pac6z/Zmc3iU4yKeUe7U10ZFf0KkiiYDQd59CpLef/2XScS\n" + "HB0oRofnxRQjfjLc4muNT+ECgYEAlcDk06MOOTly+F8lCc1bA1dgAmgwFd2usDBd\n" + "Y07a3e0HGnGLN3Kfl7C5i0tZq64HvxLnMd2vgLVxQlXGPpdQrC1TH+XLXg+qnlZO\n" + "ivSH7i0/gx75bHvj75eH1XK65V8pDVDEoSPottllAIs21CxLw3N1ObOZWJm2EfmR\n" + "cuHICmsCgYAtFJ1idqMoHxES3mlRpf2JxyQudP3SCm2WpGmqVzhRYInqeatY5sUd\n" + "lPLHm/p77RT7EyxQHTlwn8FJPuM/4ZH1rQd/vB+Y8qAtYJCexDMsbvLW+Js+VOvk\n" + "jweEC0nrcL31j9mF0vz5E6tfRu4hhJ6L4yfWs0gSejskeVB/w8QY4g==\n"; + + OBufferStream os1; + bufferSource(publicKeyPkcs8) >> base64Decode() >> streamSink(os1); + auto pubKey = os1.buf(); + + PrivateKey sKey; + sKey.loadPkcs1Base64(reinterpret_cast(privateKeyPkcs1.data()), privateKeyPkcs1.size()); + + BOOST_CHECK_THROW(SignerFilter(DigestAlgorithm::NONE, sKey), Error); + + OBufferStream os2; + bufferSource(DATA, sizeof(DATA)) >> signerFilter(DigestAlgorithm::SHA256, sKey) >> streamSink(os2); + auto sig = os2.buf(); + + BOOST_CHECK(verifySignature(DATA, sizeof(DATA), sig->data(), sig->size(), pubKey->data(), pubKey->size())); +} + +BOOST_AUTO_TEST_CASE(Ecdsa) +{ + const std::string privateKeyPkcs1 = + "MIIBaAIBAQQgRxwcbzK9RV6AHYFsDcykI86o3M/a1KlJn0z8PcLMBZOggfowgfcC\n" + "AQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA////////////////\n" + "MFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57Pr\n" + "vVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEE\n" + "axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54W\n" + "K84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8\n" + "YyVRAgEBoUQDQgAEaG4WJuDAt0QkEM4t29KDUdzkQlMPGrqWzkWhgt9OGnwc6O7A\n" + "ZLPSrDyhwyrKS7XLRXml5DisQ93RvByll32y8A==\n"; + const std::string publicKeyPkcs8 = + "MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\n" + "AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////\n" + "///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd\n" + "NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5\n" + "RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n" + "//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABGhuFibgwLdEJBDOLdvSg1Hc\n" + "5EJTDxq6ls5FoYLfThp8HOjuwGSz0qw8ocMqyku1y0V5peQ4rEPd0bwcpZd9svA=\n"; + + OBufferStream os1; + bufferSource(publicKeyPkcs8) >> base64Decode() >> streamSink(os1); + auto pubKey = os1.buf(); + + PrivateKey sKey; + sKey.loadPkcs1Base64(reinterpret_cast(privateKeyPkcs1.data()), privateKeyPkcs1.size()); + + BOOST_CHECK_THROW(SignerFilter(DigestAlgorithm::NONE, sKey), Error); + + OBufferStream os2; + bufferSource(DATA, sizeof(DATA)) >> signerFilter(DigestAlgorithm::SHA256, sKey) >> streamSink(os2); + auto sig = os2.buf(); + + BOOST_CHECK(verifySignature(DATA, sizeof(DATA), sig->data(), sig->size(), pubKey->data(), pubKey->size())); +} + +BOOST_AUTO_TEST_SUITE(Hmac) + +// Test vectors from RFC 4231 +// https://tools.ietf.org/html/rfc4231#section-4 +BOOST_AUTO_TEST_CASE(Rfc4231Test1) +{ + // Test case 1 + const uint8_t rawKey[] = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b}; + const std::string data("Hi There"); + const uint8_t hmacSha224[] = {0x89, 0x6f, 0xb1, 0x12, 0x8a, 0xbb, 0xdf, 0x19, 0x68, 0x32, + 0x10, 0x7c, 0xd4, 0x9d, 0xf3, 0x3f, 0x47, 0xb4, 0xb1, 0x16, + 0x99, 0x12, 0xba, 0x4f, 0x53, 0x68, 0x4b, 0x22}; + const uint8_t hmacSha256[] = {0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, + 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, + 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, + 0xcf, 0xf7}; + const uint8_t hmacSha384[] = {0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62, 0x6b, 0x08, + 0x25, 0xf4, 0xab, 0x46, 0x90, 0x7f, 0x15, 0xf9, 0xda, 0xdb, + 0xe4, 0x10, 0x1e, 0xc6, 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, + 0xc5, 0x9c, 0xfa, 0xea, 0x9e, 0xa9, 0x07, 0x6e, 0xde, 0x7f, + 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6}; + const uint8_t hmacSha512[] = {0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, 0x4f, 0xf0, + 0xb4, 0x24, 0x1a, 0x1d, 0x6c, 0xb0, 0x23, 0x79, 0xf4, 0xe2, + 0xce, 0x4e, 0xc2, 0x78, 0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1, + 0x7c, 0xde, 0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7, 0x02, + 0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4, 0xbe, 0x9d, + 0x91, 0x4e, 0xeb, 0x61, 0xf1, 0x70, 0x2e, 0x69, 0x6c, 0x20, + 0x3a, 0x12, 0x68, 0x54}; + + PrivateKey key; + key.loadRaw(KeyType::HMAC, rawKey, sizeof(rawKey)); + + BOOST_CHECK_THROW(SignerFilter(DigestAlgorithm::NONE, key), Error); + + OBufferStream os224; + bufferSource(data) >> signerFilter(DigestAlgorithm::SHA224, key) >> streamSink(os224); + auto sig = os224.buf(); + BOOST_CHECK_EQUAL_COLLECTIONS(sig->begin(), sig->end(), hmacSha224, hmacSha224 + sizeof(hmacSha224)); + + OBufferStream os256; + bufferSource(data) >> signerFilter(DigestAlgorithm::SHA256, key) >> streamSink(os256); + sig = os256.buf(); + BOOST_CHECK_EQUAL_COLLECTIONS(sig->begin(), sig->end(), hmacSha256, hmacSha256 + sizeof(hmacSha256)); + + OBufferStream os384; + bufferSource(data) >> signerFilter(DigestAlgorithm::SHA384, key) >> streamSink(os384); + sig = os384.buf(); + BOOST_CHECK_EQUAL_COLLECTIONS(sig->begin(), sig->end(), hmacSha384, hmacSha384 + sizeof(hmacSha384)); + + OBufferStream os512; + bufferSource(data) >> signerFilter(DigestAlgorithm::SHA512, key) >> streamSink(os512); + sig = os512.buf(); + BOOST_CHECK_EQUAL_COLLECTIONS(sig->begin(), sig->end(), hmacSha512, hmacSha512 + sizeof(hmacSha512)); +} + +BOOST_AUTO_TEST_CASE(Rfc4231Test2) +{ + // Test case 2 (HMAC-SHA-256 only) + const char rawKey[] = "Jefe"; + const std::string data("what do ya want for nothing?"); + const uint8_t hmacSha256[] = {0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, + 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, + 0x9d, 0x27, 0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, + 0x38, 0x43}; + + PrivateKey key; + key.loadRaw(KeyType::HMAC, reinterpret_cast(rawKey), std::strlen(rawKey)); + + OBufferStream os256; + bufferSource(data) >> signerFilter(DigestAlgorithm::SHA256, key) >> streamSink(os256); + auto sig = os256.buf(); + BOOST_CHECK_EQUAL_COLLECTIONS(sig->begin(), sig->end(), hmacSha256, hmacSha256 + sizeof(hmacSha256)); +} + +BOOST_AUTO_TEST_CASE(Rfc4231Test3) +{ + // Test case 3 (HMAC-SHA-256 only) + const uint8_t rawKey[] = {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}; + const uint8_t data[] = {0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd}; + const uint8_t hmacSha256[] = {0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, + 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, + 0x3e, 0xf8, 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, + 0x65, 0xfe}; + + PrivateKey key; + key.loadRaw(KeyType::HMAC, rawKey, sizeof(rawKey)); + + OBufferStream os256; + bufferSource(data, sizeof(data)) >> signerFilter(DigestAlgorithm::SHA256, key) >> streamSink(os256); + auto sig = os256.buf(); + BOOST_CHECK_EQUAL_COLLECTIONS(sig->begin(), sig->end(), hmacSha256, hmacSha256 + sizeof(hmacSha256)); +} + +BOOST_AUTO_TEST_SUITE_END() // Hmac + +BOOST_AUTO_TEST_CASE(InvalidKey) +{ + PrivateKey key; + BOOST_CHECK_THROW(SignerFilter(DigestAlgorithm::SHA256, key), Error); +} + +BOOST_AUTO_TEST_SUITE_END() // TestSignerFilter +BOOST_AUTO_TEST_SUITE_END() // Transform +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace transform +} // namespace security +} // namespace ndn diff --git a/tests/unit-tests/security/transform/step-source.t.cpp b/tests/unit/security/transform/step-source.t.cpp similarity index 85% rename from tests/unit-tests/security/transform/step-source.t.cpp rename to tests/unit/security/transform/step-source.t.cpp index 321a3dc0f..d8aae4749 100644 --- a/tests/unit-tests/security/transform/step-source.t.cpp +++ b/tests/unit/security/transform/step-source.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,10 +19,12 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "security/transform/step-source.hpp" -#include "security/transform/stream-sink.hpp" +#include "ndn-cxx/security/transform/step-source.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" + +#include namespace ndn { namespace security { @@ -35,7 +37,7 @@ BOOST_AUTO_TEST_SUITE(TestStepSource) BOOST_AUTO_TEST_CASE(Basic) { - std::string input = + const std::string input = "0123456701234567012345670123456701234567012345670123456701234567" "0123456701234567012345670123456701234567012345670123456701234567" "0123456701234567012345670123456701234567012345670123456701234567" @@ -58,7 +60,7 @@ BOOST_AUTO_TEST_CASE(Basic) "0123456701234567012345670123456701234567012345670123456701234567"; const uint8_t* buf = reinterpret_cast(input.data()); - std::stringstream os; + std::ostringstream os; StepSource ss; ss >> streamSink(os); BOOST_CHECK_EQUAL(ss.write(buf, 320), 320); @@ -66,9 +68,17 @@ BOOST_AUTO_TEST_CASE(Basic) BOOST_CHECK_EQUAL(ss.write(buf + 640, 320), 320); BOOST_CHECK_EQUAL(ss.write(buf + 960, 320), 320); ss.end(); - BOOST_REQUIRE_THROW(ss.write(buf + 960, 320), transform::Error); - std::string output = os.str(); - BOOST_CHECK_EQUAL(input, output); + BOOST_CHECK_THROW(ss.write(buf + 960, 320), transform::Error); + BOOST_CHECK_EQUAL(os.str(), input); +} + +BOOST_AUTO_TEST_CASE(EmptyInput) +{ + std::ostringstream os; + StepSource ss; + ss >> streamSink(os); + ss.end(); + BOOST_CHECK_EQUAL(os.str(), ""); } BOOST_AUTO_TEST_SUITE_END() // TestStepSource diff --git a/tests/unit-tests/security/transform/stream-sink.t.cpp b/tests/unit/security/transform/stream-sink.t.cpp similarity index 92% rename from tests/unit-tests/security/transform/stream-sink.t.cpp rename to tests/unit/security/transform/stream-sink.t.cpp index e9185d3e5..4704b019c 100644 --- a/tests/unit-tests/security/transform/stream-sink.t.cpp +++ b/tests/unit/security/transform/stream-sink.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,9 +19,9 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "security/transform/stream-sink.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace security { diff --git a/tests/unit-tests/security/transform/stream-source.t.cpp b/tests/unit/security/transform/stream-source.t.cpp similarity index 94% rename from tests/unit-tests/security/transform/stream-source.t.cpp rename to tests/unit/security/transform/stream-source.t.cpp index edce9f180..1446bc94a 100644 --- a/tests/unit-tests/security/transform/stream-source.t.cpp +++ b/tests/unit/security/transform/stream-source.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,10 +19,11 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "security/transform/stream-source.hpp" -#include "security/transform/stream-sink.hpp" +#include "ndn-cxx/security/transform/stream-source.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" + +#include "tests/boost-test.hpp" -#include "boost-test.hpp" #include #include diff --git a/tests/unit-tests/security/transform/strip-space.t.cpp b/tests/unit/security/transform/strip-space.t.cpp similarity index 87% rename from tests/unit-tests/security/transform/strip-space.t.cpp rename to tests/unit/security/transform/strip-space.t.cpp index d916f8d34..29c2e7eaa 100644 --- a/tests/unit-tests/security/transform/strip-space.t.cpp +++ b/tests/unit/security/transform/strip-space.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,13 +19,13 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "security/transform/strip-space.hpp" -#include "security/transform/step-source.hpp" -#include "security/transform/stream-sink.hpp" -#include "encoding/buffer-stream.hpp" -#include +#include "ndn-cxx/security/transform/strip-space.hpp" -#include "boost-test.hpp" +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/transform/step-source.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" + +#include "tests/boost-test.hpp" namespace ndn { namespace security { @@ -65,7 +65,7 @@ BOOST_AUTO_TEST_CASE(Basic) "velitessecillumdoloreeufugiatnullapariatur.Excepteursintoccaecatcupidatatnonproi" "dent,suntinculpaquiofficiadeseruntmollitanimidestlaborum."); ConstBufferPtr buf = os.buf(); - BOOST_CHECK_EQUAL(std::string(reinterpret_cast(buf->get()), buf->size()), expected); + BOOST_CHECK_EQUAL(std::string(buf->get(), buf->size()), expected); } BOOST_AUTO_TEST_SUITE_END() // TestStripSpace diff --git a/tests/unit/security/transform/verifier-filter.t.cpp b/tests/unit/security/transform/verifier-filter.t.cpp new file mode 100644 index 000000000..8d733d3ff --- /dev/null +++ b/tests/unit/security/transform/verifier-filter.t.cpp @@ -0,0 +1,188 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/transform/verifier-filter.hpp" + +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/key-params.hpp" +#include "ndn-cxx/security/transform/base64-decode.hpp" +#include "ndn-cxx/security/transform/bool-sink.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/private-key.hpp" +#include "ndn-cxx/security/transform/public-key.hpp" +#include "ndn-cxx/security/transform/signer-filter.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" + +#include "tests/boost-test.hpp" + +namespace ndn { +namespace security { +namespace transform { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(Transform) +BOOST_AUTO_TEST_SUITE(TestVerifierFilter) + +const uint8_t DATA[] = {0x01, 0x02, 0x03, 0x04}; + +BOOST_AUTO_TEST_CASE(Rsa) +{ + const std::string publicKeyPkcs8 = + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw0WM1/WhAxyLtEqsiAJg\n" + "WDZWuzkYpeYVdeeZcqRZzzfRgBQTsNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobw\n" + "s3iigohnM9yTK+KKiayPhIAm/+5HGT6SgFJhYhqo1/upWdueojil6RP4/AgavHho\n" + "pxlAVbk6G9VdVnlQcQ5Zv0OcGi73c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9g\n" + "ZwIL5PuE9BiO6I39cL9z7EK1SfZhOWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA\n" + "9rH58ynaAix0tcR/nBMRLUX+e3rURHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0\n" + "ywIDAQAB\n"; + const std::string privateKeyPkcs1 = + "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDDRYzX9aEDHIu0\n" + "SqyIAmBYNla7ORil5hV155lypFnPN9GAFBOw2jNLm3gefBNmHDBdsfuTdA3SRFNX\n" + "zbpehvCzeKKCiGcz3JMr4oqJrI+EgCb/7kcZPpKAUmFiGqjX+6lZ256iOKXpE/j8\n" + "CBq8eGinGUBVuTob1V1WeVBxDlm/Q5waLvdz4SdgP9iBRFgZKeBSL9ieyHvv2nZT\n" + "r3+172BnAgvk+4T0GI7ojf1wv3PsQrVJ9mE5a8N7+oftiEP8EfBxaK3wWNHDDWCX\n" + "BFVMmwD2sfnzKdoCLHS1xH+cExEtRf57etREeDpRtKMlt1v2qYozV9MYcpTMv/mk\n" + "wbq4FTTLAgMBAAECggEANCRyQ4iXghkxROdbwsW/rE52QnAwoLwbpuw9EVvJj4e8\n" + "LZMu3t6lK99L5/gBxhZo49wO7YTj2+3aw2twBKXLyGDCJFEAHd0cf29yxuiJOjxu\n" + "LZEW8yq+O/3De0rbIzFUO2ZlqbOuudpXdhVD7mfIqjYX88wONDh5QAoM7OOEG4oe\n" + "xkFMWcDUwU0j5QqPlfhinrgMWYqXFNf9TZvDNXLCjmHPHZSHDnWOaguWzhhS8wlc\n" + "PTBblm1hG4+iBe9dv+h/15//bT/BTXVYUqBdviB9HzNRdpdLWxdydWbf7bi8iz10\n" + "ClTDKS6jKM6rFapwdF5zZBPYXFUaQUStrN4I9riswQKBgQDljwLLCiYhxOB6sUYU\n" + "J4wcmvydAapjZX+jAVveT2ZpzM+cL2nhr1FzmzMvED0UxgXG6tBkwFZIQbYlLUdH\n" + "aaeOKDHxQqNgwv8D6u++Nk4x7gzpLLaCCHhKQtkqlZPONN7TsHIz+Pm/9KM1mFYA\n" + "buzDj8uY8ZFCTAm/4pmEaiO46QKBgQDZw4VPpwlG/qS/NPP1LQI5k5Wb564mH8Fe\n" + "nugCwCZs186lyQ8zOodfLz/Cl0qXoABwHns67O2U19XUPuq9vPsm5GVjBDRwR8GB\n" + "tk9zPWnXwccNeHCfntk9vwbfdiH06aDQc0AiZvguxW5KrEDo3BKPtylF6SBN52uE\n" + "sU8n5h1vkwKBgQCwzdDs6MgtwiDS3q6G316+uXBOzPWa0JXZyjYjpyvN2P0d4ja+\n" + "p/UoASUO3obs9QeGCVyv/KN3y4SqZZE8o1d12ed9VkHXSNh4//3elpzrP9mZzeJT\n" + "jIp5R7tTXRkV/QqSKJgNB3n0Kkt5//ZdJxIcHShGh+fFFCN+Mtzia41P4QKBgQCV\n" + "wOTTow45OXL4XyUJzVsDV2ACaDAV3a6wMF1jTtrd7QcacYs3cp+XsLmLS1mrrge/\n" + "Eucx3a+AtXFCVcY+l1CsLVMf5cteD6qeVk6K9IfuLT+DHvlse+Pvl4fVcrrlXykN\n" + "UMShI+i22WUAizbULEvDc3U5s5lYmbYR+ZFy4cgKawKBgC0UnWJ2oygfERLeaVGl\n" + "/YnHJC50/dIKbZakaapXOFFgiep5q1jmxR2U8seb+nvtFPsTLFAdOXCfwUk+4z/h\n" + "kfWtB3+8H5jyoC1gkJ7EMyxu8tb4mz5U6+SPB4QLSetwvfWP2YXS/PkTq19G7iGE\n" + "novjJ9azSBJ6OyR5UH/DxBji\n"; + + OBufferStream os1; + bufferSource(publicKeyPkcs8) >> base64Decode() >> streamSink(os1); + auto pubKey = os1.buf(); + + PublicKey pKey; + pKey.loadPkcs8(pubKey->data(), pubKey->size()); + + PrivateKey sKey; + sKey.loadPkcs1Base64(reinterpret_cast(privateKeyPkcs1.data()), privateKeyPkcs1.size()); + + OBufferStream os2; + bufferSource(DATA, sizeof(DATA)) >> signerFilter(DigestAlgorithm::SHA256, sKey) >> streamSink(os2); + auto sig = os2.buf(); + + BOOST_CHECK_THROW(VerifierFilter(DigestAlgorithm::NONE, pKey, sig->data(), sig->size()), Error); + BOOST_CHECK_THROW(VerifierFilter(DigestAlgorithm::SHA256, sKey, sig->data(), sig->size()), Error); + + bool result = false; + bufferSource(DATA, sizeof(DATA)) >> + verifierFilter(DigestAlgorithm::SHA256, pKey, sig->data(), sig->size()) >> + boolSink(result); + + BOOST_CHECK_EQUAL(result, true); +} + +BOOST_AUTO_TEST_CASE(Ecdsa) +{ + const std::string privateKeyPkcs1 = + "MIIBeQIBADCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAAB\n" + "AAAAAAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA\n" + "///////////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMV\n" + "AMSdNgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg\n" + "9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8A\n" + "AAAA//////////+85vqtpxeehPO5ysL8YyVRAgEBBG0wawIBAQQgRxwcbzK9RV6A\n" + "HYFsDcykI86o3M/a1KlJn0z8PcLMBZOhRANCAARobhYm4MC3RCQQzi3b0oNR3ORC\n" + "Uw8aupbORaGC304afBzo7sBks9KsPKHDKspLtctFeaXkOKxD3dG8HKWXfbLw\n"; + const std::string publicKeyPkcs8 = + "MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\n" + "AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////\n" + "///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd\n" + "NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5\n" + "RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n" + "//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABGhuFibgwLdEJBDOLdvSg1Hc\n" + "5EJTDxq6ls5FoYLfThp8HOjuwGSz0qw8ocMqyku1y0V5peQ4rEPd0bwcpZd9svA=\n"; + + OBufferStream os1; + bufferSource(publicKeyPkcs8) >> base64Decode() >> streamSink(os1); + auto pubKey = os1.buf(); + + PublicKey pKey; + pKey.loadPkcs8(pubKey->data(), pubKey->size()); + + PrivateKey sKey; + sKey.loadPkcs1Base64(reinterpret_cast(privateKeyPkcs1.data()), privateKeyPkcs1.size()); + + OBufferStream os2; + bufferSource(DATA, sizeof(DATA)) >> signerFilter(DigestAlgorithm::SHA256, sKey) >> streamSink(os2); + auto sig = os2.buf(); + + BOOST_CHECK_THROW(VerifierFilter(DigestAlgorithm::NONE, pKey, sig->data(), sig->size()), Error); + BOOST_CHECK_THROW(VerifierFilter(DigestAlgorithm::SHA256, sKey, sig->data(), sig->size()), Error); + + bool result = false; + bufferSource(DATA, sizeof(DATA)) >> + verifierFilter(DigestAlgorithm::SHA256, pKey, sig->data(), sig->size()) >> + boolSink(result); + + BOOST_CHECK_EQUAL(result, true); +} + +BOOST_AUTO_TEST_CASE(Hmac) +{ + auto sKey = generatePrivateKey(HmacKeyParams()); + + OBufferStream os; + bufferSource(DATA, sizeof(DATA)) >> signerFilter(DigestAlgorithm::SHA256, *sKey) >> streamSink(os); + auto sig = os.buf(); + + BOOST_CHECK_THROW(VerifierFilter(DigestAlgorithm::NONE, *sKey, sig->data(), sig->size()), Error); + + bool result = false; + bufferSource(DATA, sizeof(DATA)) >> + verifierFilter(DigestAlgorithm::SHA256, *sKey, sig->data(), sig->size()) >> + boolSink(result); + + BOOST_CHECK_EQUAL(result, true); +} + +BOOST_AUTO_TEST_CASE(InvalidKey) +{ + PublicKey pubKey; + BOOST_CHECK_THROW(VerifierFilter(DigestAlgorithm::SHA256, pubKey, nullptr, 0), Error); + PrivateKey privKey; + BOOST_CHECK_THROW(VerifierFilter(DigestAlgorithm::SHA256, privKey, nullptr, 0), Error); +} + +BOOST_AUTO_TEST_SUITE_END() // TestVerifierFilter +BOOST_AUTO_TEST_SUITE_END() // Transform +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace transform +} // namespace security +} // namespace ndn diff --git a/tests/unit-tests/security/v2/additional-description.t.cpp b/tests/unit/security/v2/additional-description.t.cpp similarity index 91% rename from tests/unit-tests/security/v2/additional-description.t.cpp rename to tests/unit/security/v2/additional-description.t.cpp index 98431b69d..86a3a9091 100644 --- a/tests/unit-tests/security/v2/additional-description.t.cpp +++ b/tests/unit/security/v2/additional-description.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,9 +19,9 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "security/v2/additional-description.hpp" +#include "ndn-cxx/security/v2/additional-description.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace security { @@ -44,7 +44,7 @@ const uint8_t description[] = { 0x76, 0x61, 0x6c, 0x32, // "val2" }; -const std::string text = "((key1:val1), (key2:val2))"; +const std::string text = "[(key1:val1), (key2:val2)]"; BOOST_AUTO_TEST_CASE(Basic) { @@ -82,13 +82,13 @@ BOOST_AUTO_TEST_CASE(Basic) BOOST_REQUIRE_NO_THROW(AdditionalDescription(Block(description, sizeof(description)))); AdditionalDescription aDescription2(Block(description, sizeof(description))); - BOOST_CHECK(aDescription2 == aDescription); + BOOST_CHECK_EQUAL(aDescription2, aDescription); AdditionalDescription aDescription3; aDescription3.set("key3", "val3"); aDescription3.set("key2", "val2"); - BOOST_CHECK(aDescription2 != aDescription3); + BOOST_CHECK_NE(aDescription2, aDescription3); std::ostringstream os; os << aDescription; diff --git a/tests/unit/security/v2/certificate-bundle-fetcher.t.cpp b/tests/unit/security/v2/certificate-bundle-fetcher.t.cpp new file mode 100644 index 000000000..cd9630006 --- /dev/null +++ b/tests/unit/security/v2/certificate-bundle-fetcher.t.cpp @@ -0,0 +1,191 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/certificate-bundle-fetcher.hpp" +#include "ndn-cxx/security/v2/validation-policy-simple-hierarchy.hpp" +#include "ndn-cxx/util/regex/regex-pattern-list-matcher.hpp" +#include "ndn-cxx/lp/nack.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/v2/validator-fixture.hpp" + +namespace ndn { +namespace security { +namespace v2 { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) +BOOST_AUTO_TEST_SUITE(TestCertificateBundleFetcher) + +class CertificateBundleFetcherWrapper : public CertificateBundleFetcher +{ +public: + CertificateBundleFetcherWrapper(Face& face) + : CertificateBundleFetcher(make_unique(face), face) + { + } +}; + +class Bundle +{ +}; + +class Cert +{ +}; + +class Timeout +{ +}; + +class Nack +{ +}; + +template +class CertificateBundleFetcherFixture : public HierarchicalValidatorFixture +{ +public: + CertificateBundleFetcherFixture() + : data("/Security/V2/ValidatorFixture/Sub1/Sub3/Data") + { + subSubIdentity = addSubCertificate("/Security/V2/ValidatorFixture/Sub1/Sub3", subIdentity); + cache.insert(subSubIdentity.getDefaultKey().getDefaultCertificate()); + + m_keyChain.sign(data, signingByIdentity(subSubIdentity)); + bundleRegexMatcher = make_shared("<>*<_BUNDLE><>*", nullptr); + processInterest = [this] (const Interest& interest) { + // check if the interest is for Bundle or individual certificates + if (bundleRegexMatcher->match(interest.getName(), 0, interest.getName().size())) { + makeResponse(interest); + } + else { + auto cert = cache.find(interest); + if (cert == nullptr) { + return; + } + face.receive(*cert); + } + }; + } + + void + makeResponse(const Interest& interest); + +public: + Data data; + Identity subSubIdentity; + shared_ptr bundleRegexMatcher; +}; + +template<> +void +CertificateBundleFetcherFixture::makeResponse(const Interest& interest) +{ + Block certList = Block(tlv::Content); + Name bundleName(interest.getName()); + + if (!bundleName.get(-1).isSegment() || bundleName.get(-1).toSegment() == 0) { + Block subSubCert = subSubIdentity.getDefaultKey().getDefaultCertificate().wireEncode(); + certList.push_back(subSubCert); + + if (!bundleName.get(-1).isSegment()) { + bundleName + .appendVersion() + .appendSegment(0); + } + } + else { + Block subCert = subIdentity.getDefaultKey().getDefaultCertificate().wireEncode(); + Block anchor = identity.getDefaultKey().getDefaultCertificate().wireEncode(); + certList.push_back(subCert); + certList.push_back(anchor); + } + + shared_ptr certBundle = make_shared(); + certBundle->setName(bundleName); + certBundle->setFreshnessPeriod(100_s); + certBundle->setContent(certList); + certBundle->setFinalBlock(name::Component::fromSegment(1)); + + m_keyChain.sign(*certBundle, signingWithSha256()); + + face.receive(*certBundle); +} + +template<> +void +CertificateBundleFetcherFixture::makeResponse(const Interest& interest) +{ + this->advanceClocks(200_s); +} + +template<> +void +CertificateBundleFetcherFixture::makeResponse(const Interest& interest) +{ + lp::Nack nack(interest); + nack.setHeader(lp::NackHeader().setReason(lp::NackReason::NO_ROUTE)); + face.receive(nack); +} + +BOOST_FIXTURE_TEST_CASE(ValidateSuccessWithBundle, CertificateBundleFetcherFixture) +{ + VALIDATE_SUCCESS(this->data, "Should get accepted, as interest brings the bundle segments"); + BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 2); // produced bundle has 2 segments + + for (const auto& sentInterest : this->face.sentInterests) { + BOOST_CHECK(this->bundleRegexMatcher->match(sentInterest.getName(), 0, sentInterest.getName().size())); + } +} + +using SuccessWithoutBundle = boost::mpl::vector; + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateSuccessWithoutBundle, T, SuccessWithoutBundle, CertificateBundleFetcherFixture) +{ + VALIDATE_SUCCESS(this->data, "Should get accepted, as interest brings the certs"); + BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 4); // since interest for Bundle fails, each cert is retrieved + + bool toggle = true; + for (const auto& sentInterest : this->face.sentInterests) { + if (toggle) { + // every alternate interest is going to be that of a bundle + BOOST_CHECK(this->bundleRegexMatcher->match(sentInterest.getName(), 0, sentInterest.getName().size())); + } + else { + BOOST_CHECK(!this->bundleRegexMatcher->match(sentInterest.getName(), 0, sentInterest.getName().size())); + } + toggle = !toggle; + } +} + +BOOST_AUTO_TEST_SUITE_END() // TestCertificateBundleFetcher +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/certificate-cache.t.cpp b/tests/unit/security/v2/certificate-cache.t.cpp new file mode 100644 index 000000000..8062c1891 --- /dev/null +++ b/tests/unit/security/v2/certificate-cache.t.cpp @@ -0,0 +1,93 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/certificate-cache.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/identity-management-time-fixture.hpp" + +namespace ndn { +namespace security { +namespace v2 { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) + +class CertificateCacheFixture : public ndn::tests::IdentityManagementTimeFixture +{ +public: + CertificateCacheFixture() + : certCache(10_s) + { + identity = addIdentity("/TestCertificateCache/"); + cert = identity.getDefaultKey().getDefaultCertificate(); + } + +public: + CertificateCache certCache; + Identity identity; + Certificate cert; +}; + +BOOST_FIXTURE_TEST_SUITE(TestCertificateCache, CertificateCacheFixture) + +BOOST_AUTO_TEST_CASE(RemovalTime) +{ + // Cache lifetime is capped to 10 seconds during cache construction + + BOOST_CHECK_NO_THROW(certCache.insert(cert)); + BOOST_CHECK(certCache.find(cert.getName()) != nullptr); + + advanceClocks(11_s, 1); + BOOST_CHECK(certCache.find(cert.getName()) == nullptr); + + BOOST_CHECK_NO_THROW(certCache.insert(cert)); + BOOST_CHECK(certCache.find(cert.getName()) != nullptr); + + advanceClocks(5_s); + BOOST_CHECK(certCache.find(cert.getName()) != nullptr); + + advanceClocks(15_s); + BOOST_CHECK(certCache.find(cert.getName()) == nullptr); +} + +BOOST_AUTO_TEST_CASE(FindByInterest) +{ + BOOST_CHECK_NO_THROW(certCache.insert(cert)); + + // Find by interest + BOOST_CHECK(certCache.find(Interest(cert.getIdentity())) != nullptr); + BOOST_CHECK(certCache.find(Interest(cert.getKeyName())) != nullptr); + BOOST_CHECK(certCache.find(Interest(Name(cert.getName()).appendVersion())) == nullptr); + + advanceClocks(12_s); + BOOST_CHECK(certCache.find(Interest(cert.getIdentity())) == nullptr); +} + +BOOST_AUTO_TEST_SUITE_END() // TestCertificateCache +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/certificate-fetcher-direct-fetch.t.cpp b/tests/unit/security/v2/certificate-fetcher-direct-fetch.t.cpp new file mode 100644 index 000000000..7e513c6a7 --- /dev/null +++ b/tests/unit/security/v2/certificate-fetcher-direct-fetch.t.cpp @@ -0,0 +1,267 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/certificate-fetcher-direct-fetch.hpp" +#include "ndn-cxx/security/v2/validation-policy-simple-hierarchy.hpp" +#include "ndn-cxx/lp/nack.hpp" +#include "ndn-cxx/lp/tags.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/v2/validator-fixture.hpp" + +#include +#include + +namespace ndn { +namespace security { +namespace v2 { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) +BOOST_AUTO_TEST_SUITE(TestCertificateFetcherDirectFetch) + +class Cert +{ +}; + +class Timeout +{ +}; + +class Nack +{ +}; + +template +class CertificateFetcherDirectFetchFixture : public HierarchicalValidatorFixture +{ +public: + enum class ResponseType { + INFRASTRUCTURE, + DIRECT, + BOTH + }; + +public: + CertificateFetcherDirectFetchFixture() + : data("/Security/V2/ValidatorFixture/Sub1/Sub3/Data") + , interest("/Security/V2/ValidatorFixture/Sub1/Sub3/Interest") + , interestNoTag("/Security/V2/ValidatorFixture/Sub1/Sub3/Interest2") + { + Identity subSubIdentity = addSubCertificate("/Security/V2/ValidatorFixture/Sub1/Sub3", subIdentity); + cache.insert(subSubIdentity.getDefaultKey().getDefaultCertificate()); + + m_keyChain.sign(data, signingByIdentity(subSubIdentity)); + m_keyChain.sign(interest, signingByIdentity(subSubIdentity)); + m_keyChain.sign(interestNoTag, signingByIdentity(subSubIdentity)); + + data.setTag(make_shared(123)); + interest.setTag(make_shared(123)); + + processInterest = [this] (const Interest& interest) { + auto nextHopFaceIdTag = interest.template getTag(); + if (nextHopFaceIdTag == nullptr) { + if (responseType == ResponseType::INFRASTRUCTURE || responseType == ResponseType::BOTH) { + makeResponse(interest); + } + } + else { + if (responseType == ResponseType::DIRECT || responseType == ResponseType::BOTH) { + makeResponse(interest); + } + } + }; + } + + void + makeResponse(const Interest& interest); + + void + setResponseType(ResponseType type) + { + responseType = type; + } + +public: + Data data; + Interest interest; + Interest interestNoTag; + ResponseType responseType = ResponseType::INFRASTRUCTURE; +}; + +template<> +void +CertificateFetcherDirectFetchFixture::makeResponse(const Interest& interest) +{ + auto cert = cache.find(interest); + if (cert == nullptr) { + return; + } + face.receive(*cert); +} + +template<> +void +CertificateFetcherDirectFetchFixture::makeResponse(const Interest& interest) +{ + // do nothing +} + +template<> +void +CertificateFetcherDirectFetchFixture::makeResponse(const Interest& interest) +{ + lp::Nack nack(interest); + nack.setHeader(lp::NackHeader().setReason(lp::NackReason::NO_ROUTE)); + face.receive(nack); +} + +using Failures = boost::mpl::vector; + +BOOST_FIXTURE_TEST_CASE(ValidateSuccessData, CertificateFetcherDirectFetchFixture) +{ + VALIDATE_SUCCESS(this->data, "Should get accepted, normal and/or direct interests bring certs"); + BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 4); + + // odd interests + for (const auto& sentInterest : this->face.sentInterests | boost::adaptors::strided(2)) { + BOOST_CHECK(sentInterest.template getTag() != nullptr); + } + + // even interests + for (const auto& sentInterest : this->face.sentInterests | + boost::adaptors::sliced(1, this->face.sentInterests.size()) | + boost::adaptors::strided(2)) { + BOOST_CHECK(sentInterest.template getTag() == nullptr); + } +} + +BOOST_FIXTURE_TEST_CASE(ValidateSuccessDataDirectOnly, CertificateFetcherDirectFetchFixture) +{ + setResponseType(ResponseType::DIRECT); + static_cast(validator.getFetcher()).setSendDirectInterestOnly(true); + + VALIDATE_SUCCESS(this->data, "Should get accepted, direct interests bring certs"); + BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 2); + + for (const auto& sentInterest : this->face.sentInterests) { + BOOST_CHECK(sentInterest.template getTag() != nullptr); + } +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateFailureData, T, Failures, CertificateFetcherDirectFetchFixture) +{ + VALIDATE_FAILURE(this->data, "Should fail, as all interests either NACKed or timeout"); + // Direct fetcher sends two interests each time - to network and face + // 3 retries on nack or timeout (2 * (1 + 3) = 8) + BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 8); + + // odd interests + for (const auto& sentInterest : this->face.sentInterests | boost::adaptors::strided(2)) { + BOOST_CHECK(sentInterest.template getTag() != nullptr); + } + + // even interests + for (const auto& sentInterest : this->face.sentInterests | + boost::adaptors::sliced(1, this->face.sentInterests.size()) | + boost::adaptors::strided(2)) { + BOOST_CHECK(sentInterest.template getTag() == nullptr); + } +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateFailureDataDirectOnly, T, Failures, CertificateFetcherDirectFetchFixture) +{ + this->setResponseType(CertificateFetcherDirectFetchFixture::ResponseType::DIRECT); + static_cast(this->validator.getFetcher()).setSendDirectInterestOnly(true); + + VALIDATE_FAILURE(this->data, "Should fail, as all interests either NACKed or timeout"); + // Direct fetcher sends two interests each time - to network and face + // 3 retries on nack or timeout (1 + 3 = 4) + BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 4); + + for (const auto& sentInterest : this->face.sentInterests) { + BOOST_CHECK(sentInterest.template getTag() != nullptr); + } +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateFailureDataNoTagDirectOnly, T, Failures, CertificateFetcherDirectFetchFixture) +{ + this->setResponseType(CertificateFetcherDirectFetchFixture::ResponseType::DIRECT); + static_cast(this->validator.getFetcher()).setSendDirectInterestOnly(true); + + this->data.template removeTag(); + this->interest.template removeTag(); + + VALIDATE_FAILURE(this->data, "Should fail, as no interests are expected"); + BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 0); + BOOST_CHECK(this->lastError.getCode() != ValidationError::Code::IMPLEMENTATION_ERROR); +} + +BOOST_FIXTURE_TEST_CASE(ValidateSuccessInterest, CertificateFetcherDirectFetchFixture) +{ + VALIDATE_SUCCESS(this->interest, "Should get accepted, normal and/or direct interests bring certs"); + BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 4); + + // odd interests + for (const auto& sentInterest : this->face.sentInterests | boost::adaptors::strided(2)) { + BOOST_CHECK(sentInterest.template getTag() != nullptr); + } + + // even interests + for (const auto& sentInterest : this->face.sentInterests | + boost::adaptors::sliced(1, this->face.sentInterests.size()) | + boost::adaptors::strided(2)) { + BOOST_CHECK(sentInterest.template getTag() == nullptr); + } +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateFailureInterest, T, Failures, CertificateFetcherDirectFetchFixture) +{ + VALIDATE_FAILURE(this->interest, "Should fail, as all interests either NACKed or timeout"); + // Direct fetcher sends two interests each time - to network and face + // 3 retries on nack or timeout (2 * (1 + 3) = 4) + BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 8); + + // odd interests + for (const auto& sentInterest : this->face.sentInterests | boost::adaptors::strided(2)) { + BOOST_CHECK(sentInterest.template getTag() != nullptr); + } + + // even interests + for (const auto& sentInterest : this->face.sentInterests | + boost::adaptors::sliced(1, this->face.sentInterests.size()) | + boost::adaptors::strided(2)) { + BOOST_CHECK(sentInterest.template getTag() == nullptr); + } +} + +BOOST_AUTO_TEST_SUITE_END() // TestCertificateFetcherDirectFetch +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/certificate-fetcher-from-network.t.cpp b/tests/unit/security/v2/certificate-fetcher-from-network.t.cpp new file mode 100644 index 000000000..a7b138844 --- /dev/null +++ b/tests/unit/security/v2/certificate-fetcher-from-network.t.cpp @@ -0,0 +1,140 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/certificate-fetcher-from-network.hpp" +#include "ndn-cxx/security/v2/validation-policy-simple-hierarchy.hpp" +#include "ndn-cxx/lp/nack.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/v2/validator-fixture.hpp" + +namespace ndn { +namespace security { +namespace v2 { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) +BOOST_AUTO_TEST_SUITE(TestCertificateFetcherFromNetwork) + +class Cert +{ +}; + +class Timeout +{ +}; + +class Nack +{ +}; + +template +class CertificateFetcherFromNetworkFixture : public HierarchicalValidatorFixture +{ +public: + CertificateFetcherFromNetworkFixture() + : data("/Security/V2/ValidatorFixture/Sub1/Sub3/Data") + , interest("/Security/V2/ValidatorFixture/Sub1/Sub3/Interest") + { + Identity subSubIdentity = addSubCertificate("/Security/V2/ValidatorFixture/Sub1/Sub3", subIdentity); + cache.insert(subSubIdentity.getDefaultKey().getDefaultCertificate()); + + m_keyChain.sign(data, signingByIdentity(subSubIdentity)); + m_keyChain.sign(interest, signingByIdentity(subSubIdentity)); + + processInterest = bind(&CertificateFetcherFromNetworkFixture::makeResponse, this, _1); + } + + void + makeResponse(const Interest& interest); + +public: + Data data; + Interest interest; +}; + +template<> +void +CertificateFetcherFromNetworkFixture::makeResponse(const Interest& interest) +{ + auto cert = cache.find(interest); + if (cert == nullptr) { + return; + } + face.receive(*cert); +} + +template<> +void +CertificateFetcherFromNetworkFixture::makeResponse(const Interest& interest) +{ + // do nothing +} + +template<> +void +CertificateFetcherFromNetworkFixture::makeResponse(const Interest& interest) +{ + lp::Nack nack(interest); + nack.setHeader(lp::NackHeader().setReason(lp::NackReason::NO_ROUTE)); + face.receive(nack); +} + +using Failures = boost::mpl::vector; + +BOOST_FIXTURE_TEST_CASE(ValidateSuccess, CertificateFetcherFromNetworkFixture) +{ + VALIDATE_SUCCESS(this->data, "Should get accepted, as normal interests bring cert"); + BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 2); + this->face.sentInterests.clear(); + + this->advanceClocks(1_h, 2); // expire validator caches + + VALIDATE_SUCCESS(this->interest, "Should get accepted, as interests bring certs"); + BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 2); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateFailure, T, Failures, CertificateFetcherFromNetworkFixture) +{ + VALIDATE_FAILURE(this->data, "Should fail, as interests don't bring data"); + // first interest + 3 retries + BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 4); + + this->face.sentInterests.clear(); + + this->advanceClocks(1_h, 2); // expire validator caches + + VALIDATE_FAILURE(this->interest, "Should fail, as interests don't bring data"); + BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 4); +} + +BOOST_AUTO_TEST_SUITE_END() // TestCertificateFetcherFromNetwork +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/certificate-fetcher-offline.t.cpp b/tests/unit/security/v2/certificate-fetcher-offline.t.cpp new file mode 100644 index 000000000..bdf61c6fe --- /dev/null +++ b/tests/unit/security/v2/certificate-fetcher-offline.t.cpp @@ -0,0 +1,75 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/certificate-fetcher-offline.hpp" +#include "ndn-cxx/security/v2/validation-policy-simple-hierarchy.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/v2/validator-fixture.hpp" + +namespace ndn { +namespace security { +namespace v2 { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) + +class CertificateFetcherOfflineWrapper : public CertificateFetcherOffline +{ +public: + CertificateFetcherOfflineWrapper(Face&) + { + } +}; + +using CertificateFetcherOfflineFixture = HierarchicalValidatorFixture; + +BOOST_FIXTURE_TEST_SUITE(TestCertificateFetcherOffline, CertificateFetcherOfflineFixture) + +typedef boost::mpl::vector Packets; + +BOOST_AUTO_TEST_CASE_TEMPLATE(Validate, Packet, Packets) +{ + Packet unsignedPacket("/Security/V2/ValidatorFixture/Sub1/Packet"); + + Packet packet = unsignedPacket; + m_keyChain.sign(packet, signingByIdentity(subIdentity)); + VALIDATE_FAILURE(packet, "Should fail, as no cert should be requested"); + BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 0); + + packet = unsignedPacket; + m_keyChain.sign(packet, signingByIdentity(identity)); + VALIDATE_SUCCESS(packet, "Should succeed, as signed by trust anchor"); + BOOST_CHECK_EQUAL(this->face.sentInterests.size(), 0); +} + +BOOST_AUTO_TEST_SUITE_END() // TestCertificateFetcherOffline +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/certificate.t.cpp b/tests/unit/security/v2/certificate.t.cpp new file mode 100644 index 000000000..9d04b6dbd --- /dev/null +++ b/tests/unit/security/v2/certificate.t.cpp @@ -0,0 +1,291 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + * + * @author Zhiyi Zhang + */ + +#include "ndn-cxx/security/v2/certificate.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/unit-test-time-fixture.hpp" + +#include + +namespace ndn { +namespace security { +namespace v2 { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) +BOOST_FIXTURE_TEST_SUITE(TestCertificate, UnitTestTimeFixture) + +const uint8_t PUBLIC_KEY[] = { + 0x30, 0x81, 0x9d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x81, 0x8b, 0x00, 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e, + 0x06, 0x3e, 0x47, 0x85, 0xb2, 0x34, 0x37, 0xaa, 0x85, 0x47, 0xac, 0x03, 0x24, 0x83, 0xb5, + 0x9c, 0xa8, 0x05, 0x3a, 0x24, 0x1e, 0xeb, 0x89, 0x01, 0xbb, 0xe9, 0x9b, 0xb2, 0xc3, 0x22, + 0xac, 0x68, 0xe3, 0xf0, 0x6c, 0x02, 0xce, 0x68, 0xa6, 0xc4, 0xd0, 0xa7, 0x06, 0x90, 0x9c, + 0xaa, 0x1b, 0x08, 0x1d, 0x8b, 0x43, 0x9a, 0x33, 0x67, 0x44, 0x6d, 0x21, 0xa3, 0x1b, 0x88, + 0x9a, 0x97, 0x5e, 0x59, 0xc4, 0x15, 0x0b, 0xd9, 0x2c, 0xbd, 0x51, 0x07, 0x61, 0x82, 0xad, + 0xc1, 0xb8, 0xd7, 0xbf, 0x9b, 0xcf, 0x7d, 0x24, 0xc2, 0x63, 0xf3, 0x97, 0x17, 0xeb, 0xfe, + 0x62, 0x25, 0xba, 0x5b, 0x4d, 0x8a, 0xc2, 0x7a, 0xbd, 0x43, 0x8a, 0x8f, 0xb8, 0xf2, 0xf1, + 0xc5, 0x6a, 0x30, 0xd3, 0x50, 0x8c, 0xc8, 0x9a, 0xdf, 0xef, 0xed, 0x35, 0xe7, 0x7a, 0x62, + 0xea, 0x76, 0x7c, 0xbb, 0x08, 0x26, 0xc7, 0x02, 0x01, 0x11 +}; + +const uint8_t SIG_INFO[] = { + 0x16, 0x55, 0x1B, 0x01, 0x01, 0x1C, 0x26, 0x07, 0x24, 0x08, 0x03, 0x6E, 0x64, 0x6E, 0x08, 0x05, + 0x73, 0x69, 0x74, 0x65, 0x31, 0x08, 0x11, 0x6B, 0x73, 0x6B, 0x2D, 0x32, 0x35, 0x31, 0x36, 0x34, + 0x32, 0x35, 0x33, 0x37, 0x37, 0x30, 0x39, 0x34, 0x08, 0x03, 0x4B, 0x45, 0x59, 0xFD, 0x00, 0xFD, + 0x26, 0xFD, 0x00, 0xFE, 0x0F, 0x32, 0x30, 0x31, 0x35, 0x30, 0x38, 0x31, 0x34, 0x54, 0x32, 0x32, + 0x33, 0x37, 0x33, 0x39, 0xFD, 0x00, 0xFF, 0x0F, 0x32, 0x30, 0x31, 0x35, 0x30, 0x38, 0x31, 0x38, + 0x54, 0x32, 0x32, 0x33, 0x37, 0x33, 0x38 +}; + +const uint8_t SIG_VALUE[] = { + 0x17, 0x80, // SignatureValue + 0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec, + 0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6, + 0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38, + 0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc, + 0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf, + 0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9, + 0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8, + 0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7, + 0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3, + 0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1 +}; + +const uint8_t CERT[] = { + 0x06, 0xFD, 0x01, 0xBB, // Data + 0x07, 0x33, // Name /ndn/site1/KEY/ksk-1416425377094/0123/%FD%00%00%01I%C9%8B + 0x08, 0x03, 0x6E, 0x64, 0x6E, + 0x08, 0x05, 0x73, 0x69, 0x74, 0x65, 0x31, + 0x08, 0x03, 0x4B, 0x45, 0x59, + 0x08, 0x11, + 0x6B, 0x73, 0x6B, 0x2D, 0x31, 0x34, 0x31, 0x36, 0x34, 0x32, 0x35, 0x33, 0x37, 0x37, 0x30, 0x39, + 0x34, + 0x08, 0x04, 0x30, 0x31, 0x32, 0x33, + 0x08, 0x07, 0xFD, 0x00, 0x00, 0x01, 0x49, 0xC9, 0x8B, + 0x14, 0x09, // MetaInfo + 0x18, 0x01, 0x02, // ContentType = Key + 0x19, 0x04, 0x00, 0x36, 0xEE, 0x80, // FreshnessPeriod = 3600000 ms + 0x15, 0xA0, // Content + 0x30, 0x81, 0x9D, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x81, 0x8B, 0x00, 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9E, 0x06, 0x3E, + 0x47, 0x85, 0xB2, 0x34, 0x37, 0xAA, 0x85, 0x47, 0xAC, 0x03, 0x24, 0x83, 0xB5, 0x9C, 0xA8, 0x05, + 0x3A, 0x24, 0x1E, 0xEB, 0x89, 0x01, 0xBB, 0xE9, 0x9B, 0xB2, 0xC3, 0x22, 0xAC, 0x68, 0xE3, 0xF0, + 0x6C, 0x02, 0xCE, 0x68, 0xA6, 0xC4, 0xD0, 0xA7, 0x06, 0x90, 0x9C, 0xAA, 0x1B, 0x08, 0x1D, 0x8B, + 0x43, 0x9A, 0x33, 0x67, 0x44, 0x6D, 0x21, 0xA3, 0x1B, 0x88, 0x9A, 0x97, 0x5E, 0x59, 0xC4, 0x15, + 0x0B, 0xD9, 0x2C, 0xBD, 0x51, 0x07, 0x61, 0x82, 0xAD, 0xC1, 0xB8, 0xD7, 0xBF, 0x9B, 0xCF, 0x7D, + 0x24, 0xC2, 0x63, 0xF3, 0x97, 0x17, 0xEB, 0xFE, 0x62, 0x25, 0xBA, 0x5B, 0x4D, 0x8A, 0xC2, 0x7A, + 0xBD, 0x43, 0x8A, 0x8F, 0xB8, 0xF2, 0xF1, 0xC5, 0x6A, 0x30, 0xD3, 0x50, 0x8C, 0xC8, 0x9A, 0xDF, + 0xEF, 0xED, 0x35, 0xE7, 0x7A, 0x62, 0xEA, 0x76, 0x7C, 0xBB, 0x08, 0x26, 0xC7, 0x02, 0x01, 0x11, + 0x16, 0x55, // SignatureInfo + 0x1B, 0x01, 0x01, // SignatureType + 0x1C, 0x26, // KeyLocator: /ndn/site1/KEY/ksk-2516425377094 + 0x07, 0x24, + 0x08, 0x03, 0x6E, 0x64, 0x6E, + 0x08, 0x05, 0x73, 0x69, 0x74, 0x65, 0x31, + 0x08, 0x03, 0x4B, 0x45, 0x59, + 0x08, 0x11, + 0x6B, 0x73, 0x6B, 0x2D, 0x32, 0x35, 0x31, 0x36, 0x34, 0x32, 0x35, 0x33, 0x37, 0x37, 0x30, 0x39, + 0x34, + 0xFD, 0x00, 0xFD, 0x26, // ValidityPeriod: (20150814T223739, 20150818T223738) + 0xFD, 0x00, 0xFE, 0x0F, + 0x32, 0x30, 0x31, 0x35, 0x30, 0x38, 0x31, 0x34, 0x54, 0x32, 0x32, 0x33, 0x37, 0x33, 0x39, + 0xFD, 0x00, 0xFF, 0x0F, + 0x32, 0x30, 0x31, 0x35, 0x30, 0x38, 0x31, 0x38, 0x54, 0x32, 0x32, 0x33, 0x37, 0x33, 0x38, + 0x17, 0x80, // SignatureValue + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +Signature +generateFakeSignature() +{ + Block block1(SIG_INFO, sizeof(SIG_INFO)); + SignatureInfo signatureInfo(block1); + + Name keyLocatorName("/ndn/site1/KEY/ksk-2516425377094"); + KeyLocator keyLocator(keyLocatorName); + signatureInfo.setKeyLocator(keyLocator); + + ValidityPeriod period(time::fromIsoString("20141111T050000"), time::fromIsoString("20141111T060000")); + signatureInfo.setValidityPeriod(period); + + Signature signature(signatureInfo); + Block block2(SIG_VALUE, sizeof(SIG_VALUE)); + signature.setValue(block2); + + return signature; +} + +BOOST_AUTO_TEST_CASE(Construction) +{ + Block block(CERT, sizeof(CERT)); + Certificate certificate(block); + + BOOST_CHECK_EQUAL(certificate.getName(), "/ndn/site1/KEY/ksk-1416425377094/0123/%FD%00%00%01I%C9%8B"); + BOOST_CHECK_EQUAL(certificate.getKeyName(), "/ndn/site1/KEY/ksk-1416425377094"); + BOOST_CHECK_EQUAL(certificate.getIdentity(), "/ndn/site1"); + BOOST_CHECK_EQUAL(certificate.getIssuerId(), name::Component("0123")); + BOOST_CHECK_EQUAL(certificate.getKeyId(), name::Component("ksk-1416425377094")); + BOOST_CHECK_EQUAL(certificate.getSignature().getKeyLocator().getName(), "/ndn/site1/KEY/ksk-2516425377094"); + BOOST_CHECK_EQUAL(boost::lexical_cast(certificate.getValidityPeriod()), "(20150814T223739, 20150818T223738)"); + + BOOST_CHECK_THROW(certificate.getExtension(12345), ndn::SignatureInfo::Error); + BOOST_CHECK_NO_THROW(certificate.getPublicKey()); + + Data data(block); + Certificate certificate2(std::move(data)); + BOOST_CHECK_EQUAL(certificate, certificate2); +} + +BOOST_AUTO_TEST_CASE(Setters) +{ + Certificate certificate; + certificate.setName("/ndn/site1/KEY/ksk-1416425377094/0123/%FD%00%00%01I%C9%8B"); + certificate.setFreshnessPeriod(1_h); + certificate.setContent(PUBLIC_KEY, sizeof(PUBLIC_KEY)); + certificate.setSignature(generateFakeSignature()); + + BOOST_CHECK_EQUAL(certificate.getName(), "/ndn/site1/KEY/ksk-1416425377094/0123/%FD%00%00%01I%C9%8B"); + BOOST_CHECK_EQUAL(certificate.getKeyName(), "/ndn/site1/KEY/ksk-1416425377094"); + BOOST_CHECK_EQUAL(certificate.getIdentity(), "/ndn/site1"); + BOOST_CHECK_EQUAL(certificate.getIssuerId(), name::Component("0123")); + BOOST_CHECK_EQUAL(certificate.getKeyId(), name::Component("ksk-1416425377094")); + BOOST_CHECK_EQUAL(certificate.getSignature().getKeyLocator().getName(), "/ndn/site1/KEY/ksk-2516425377094"); + BOOST_CHECK_EQUAL(boost::lexical_cast(certificate.getValidityPeriod()), "(20141111T050000, 20141111T060000)"); + + BOOST_CHECK_THROW(certificate.getExtension(12345), ndn::SignatureInfo::Error); + BOOST_CHECK_NO_THROW(certificate.getPublicKey()); +} + +BOOST_AUTO_TEST_CASE(ValidityPeriodChecking) +{ + Certificate certificate; + certificate.setName("/ndn/site1/KEY/ksk-1416425377094/0123/%FD%00%00%01I%C9%8B"); + certificate.setFreshnessPeriod(1_h); + certificate.setContent(PUBLIC_KEY, sizeof(PUBLIC_KEY)); + certificate.setSignature(generateFakeSignature()); + + BOOST_CHECK_EQUAL(certificate.isValid(), true); + BOOST_CHECK_EQUAL(certificate.isValid(time::fromIsoString("20141111T045959")), false); + BOOST_CHECK_EQUAL(certificate.isValid(time::fromIsoString("20141111T060001")), false); +} + +// This fixture prepares a well-formed certificate. A test case then modifies one of the +// fields, and verifies the Certificate class correctly identifies the certificate as +// malformed. +class InvalidCertFixture +{ +public: + InvalidCertFixture() + { + Certificate certBase(Block(CERT, sizeof(CERT))); + BOOST_CHECK_NO_THROW((Certificate(certBase))); + + m_certBase = Data(certBase); + m_certBase.setSignature(generateFakeSignature()); + + BOOST_CHECK_NO_THROW((Certificate(m_certBase))); + } + +public: + Data m_certBase; +}; + +BOOST_FIXTURE_TEST_CASE(InvalidName, InvalidCertFixture) +{ + Data data(m_certBase); + data.setName("/ndn/site1/ksk-1416425377094/0123/%FD%00%00%01I%C9%8B"); + data.setSignature(generateFakeSignature()); + + BOOST_CHECK_THROW((Certificate(data)), Certificate::Error); + BOOST_CHECK_THROW((Certificate(std::move(data))), Certificate::Error); +} + +BOOST_FIXTURE_TEST_CASE(InvalidType, InvalidCertFixture) +{ + Data data(m_certBase); + data.setContentType(tlv::ContentType_Blob); + data.setSignature(generateFakeSignature()); + + BOOST_CHECK_THROW((Certificate(data)), Certificate::Error); + BOOST_CHECK_THROW((Certificate(std::move(data))), Certificate::Error); +} + +BOOST_FIXTURE_TEST_CASE(EmptyContent, InvalidCertFixture) +{ + Data data(m_certBase); + data.setContent(nullptr, 0); + data.setSignature(generateFakeSignature()); + + BOOST_CHECK_THROW((Certificate(data)), Certificate::Error); + BOOST_CHECK_THROW((Certificate(std::move(data))), Certificate::Error); + + Certificate cert(m_certBase); + cert.setContent(nullptr, 0); + cert.setSignature(generateFakeSignature()); + BOOST_CHECK_THROW(cert.getPublicKey(), Certificate::Error); +} + +BOOST_AUTO_TEST_CASE(PrintCertificateInfo) +{ + const std::string expectedCertificateInfo = std::string(R"INFO( +Certificate name: + /ndn/site1/KEY/ksk-1416425377094/0123/%FD%00%00%01I%C9%8B +Validity: + NotBefore: 20150814T223739 + NotAfter: 20150818T223738 +Public key bits: + MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCeBj5HhbI0N6qFR6wDJIO1nKgF + OiQe64kBu+mbssMirGjj8GwCzmimxNCnBpCcqhsIHYtDmjNnRG0hoxuImpdeWcQV + C9ksvVEHYYKtwbjXv5vPfSTCY/OXF+v+YiW6W02Kwnq9Q4qPuPLxxWow01CMyJrf + 7+0153pi6nZ8uwgmxwIBEQ== +Signature Information: + Signature Type: SignatureSha256WithRsa + Key Locator: Name=/ndn/site1/KEY/ksk-2516425377094 +)INFO").substr(1); + + Certificate certificate(Block(CERT, sizeof(CERT))); + BOOST_CHECK_EQUAL(boost::lexical_cast(certificate), expectedCertificateInfo); + + // @todo Check output formats of other certificates +} + +BOOST_AUTO_TEST_SUITE_END() // TestCertificate +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/key-chain.t.cpp b/tests/unit/security/v2/key-chain.t.cpp new file mode 100644 index 000000000..1d25e59d1 --- /dev/null +++ b/tests/unit/security/v2/key-chain.t.cpp @@ -0,0 +1,468 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/key-chain.hpp" +#include "ndn-cxx/security/signing-helpers.hpp" +#include "ndn-cxx/security/verification-helpers.hpp" +#include "ndn-cxx/security/transform/private-key.hpp" + +#include "tests/boost-test.hpp" +#include "tests/identity-management-fixture.hpp" +#include "tests/unit/test-home-env-saver.hpp" + +namespace ndn { +namespace security { +namespace v2 { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) +BOOST_FIXTURE_TEST_SUITE(TestKeyChain, TestHomeEnvSaver) + +template +class TestHomeAndPibFixture : public TestHomeFixture +{ +public: + TestHomeAndPibFixture() + { + unsetenv("NDN_CLIENT_PIB"); + unsetenv("NDN_CLIENT_TPM"); + } + + ~TestHomeAndPibFixture() + { + try { + const_cast(KeyChain::getDefaultPibLocator()).clear(); + } + catch (const KeyChain::Error&) { + // ignore + } + + try { + const_cast(KeyChain::getDefaultTpmLocator()).clear(); + } + catch (const KeyChain::Error&) { + // ignore + } + } +}; + +struct PibPathConfigFileHome +{ + const std::string PATH = "build/config-file-home/"; +}; + +BOOST_FIXTURE_TEST_CASE(ConstructorNormalConfig, TestHomeAndPibFixture) +{ + createClientConf({"pib=pib-memory:", "tpm=tpm-memory:"}); + + BOOST_REQUIRE_NO_THROW(KeyChain()); + + KeyChain keyChain; + BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-memory:"); + BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-memory:"); + BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-memory:"); +} + +struct PibPathConfigFileEmptyHome +{ + const std::string PATH = "build/config-file-empty-home/"; +}; + +BOOST_FIXTURE_TEST_CASE(ConstructorEmptyConfig, TestHomeAndPibFixture) +{ + createClientConf({"pib=pib-memory:"}); + +#if defined(NDN_CXX_HAVE_OSX_FRAMEWORKS) + std::string oldHOME; + if (std::getenv("OLD_HOME")) + oldHOME = std::getenv("OLD_HOME"); + + std::string HOME; + if (std::getenv("HOME")) + HOME = std::getenv("HOME"); + + if (!oldHOME.empty()) + setenv("HOME", oldHOME.c_str(), 1); + else + unsetenv("HOME"); +#endif + + BOOST_REQUIRE_NO_THROW(KeyChain()); + KeyChain keyChain; + BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-memory:"); + +#if defined(NDN_CXX_HAVE_OSX_FRAMEWORKS) + BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-osxkeychain:"); + BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-osxkeychain:"); +#else + BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-file:"); + BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-file:"); +#endif + +#if defined(NDN_CXX_HAVE_OSX_FRAMEWORKS) + if (!HOME.empty()) + setenv("HOME", HOME.c_str(), 1); + else + unsetenv("HOME"); + + if (!oldHOME.empty()) + setenv("OLD_HOME", oldHOME.c_str(), 1); + else + unsetenv("OLD_HOME"); +#endif +} + +struct PibPathConfigFileEmpty2Home +{ + const std::string PATH = "build/config-file-empty2-home/"; +}; + +BOOST_FIXTURE_TEST_CASE(ConstructorEmpty2Config, TestHomeAndPibFixture) +{ + createClientConf({"tpm=tpm-memory:"}); + + BOOST_REQUIRE_NO_THROW(KeyChain()); + + KeyChain keyChain; + BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-sqlite3:"); + BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-memory:"); + BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-memory:"); +} + +struct PibPathConfigFileMalformedHome +{ + const std::string PATH = "build/config-file-malformed-home/"; +}; + +BOOST_FIXTURE_TEST_CASE(ConstructorMalConfig, TestHomeAndPibFixture) +{ + createClientConf({"pib=lord", "tpm=ring"}); + + BOOST_REQUIRE_THROW(KeyChain(), KeyChain::Error); // Wrong configuration. Error expected. +} + +struct PibPathConfigFileMalformed2Home +{ + const std::string PATH = "build/config-file-malformed2-home/"; +}; + +BOOST_FIXTURE_TEST_CASE(ConstructorMal2Config, TestHomeAndPibFixture) +{ + createClientConf({"pib=pib-sqlite3:%PATH%", "tpm=just-wrong"}); + + BOOST_REQUIRE_THROW(KeyChain(), KeyChain::Error); // Wrong configuration. Error expected. +} + +struct PibPathConfigFileNonCanonicalTpm +{ + const std::string PATH = "build/config-file-non-canonical-tpm/"; +}; + +BOOST_FIXTURE_TEST_CASE(ConstructorNonCanonicalTpm, TestHomeAndPibFixture) // Bug 4297 +{ + createClientConf({"pib=pib-sqlite3:", "tpm=tpm-file"}); + + { + KeyChain keyChain; + keyChain.createIdentity("/test"); + BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-sqlite3:"); + BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-file:"); + } + + { + KeyChain keyChain; + BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-sqlite3:"); + BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-file:"); + BOOST_CHECK(keyChain.getPib().getIdentities().find("/test") != keyChain.getPib().getIdentities().end()); + } +} + +BOOST_AUTO_TEST_CASE(KeyChainWithCustomTpmAndPib) +{ + BOOST_REQUIRE_NO_THROW((KeyChain("pib-memory", "tpm-memory"))); + BOOST_REQUIRE_NO_THROW((KeyChain("pib-memory:", "tpm-memory:"))); + BOOST_REQUIRE_NO_THROW((KeyChain("pib-memory:/something", "tpm-memory:/something"))); + + KeyChain keyChain("pib-memory", "tpm-memory"); + BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-memory:"); + BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-memory:"); + BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-memory:"); +} + +BOOST_FIXTURE_TEST_CASE(Management, IdentityManagementFixture) +{ + Name identityName("/test/id"); + Name identity2Name("/test/id2"); + + BOOST_CHECK_EQUAL(m_keyChain.getPib().getIdentities().size(), 0); + BOOST_REQUIRE_THROW(m_keyChain.getPib().getDefaultIdentity(), Pib::Error); + + // Create identity + Identity id = m_keyChain.createIdentity(identityName); + BOOST_CHECK(id); + BOOST_CHECK(m_keyChain.getPib().getIdentities().find(identityName) != m_keyChain.getPib().getIdentities().end()); + // The first added identity becomes the default identity + BOOST_CHECK_NO_THROW(m_keyChain.getPib().getDefaultIdentity()); + // The default key of the added identity must exist + Key key = id.getDefaultKey(); + // The default certificate of the default key must exist + BOOST_CHECK_NO_THROW(key.getDefaultCertificate()); + + // Delete key + Name key1Name = key.getName(); + BOOST_CHECK_NO_THROW(id.getKey(key1Name)); + BOOST_CHECK_EQUAL(id.getKeys().size(), 1); + m_keyChain.deleteKey(id, key); + // The key instance should not be valid any more + BOOST_CHECK(!key); + BOOST_CHECK_THROW(id.getKey(key1Name), Pib::Error); + BOOST_CHECK_EQUAL(id.getKeys().size(), 0); + + // Create another key + m_keyChain.createKey(id); + // The added key becomes the default key. + Key key2 = id.getDefaultKey(); + BOOST_REQUIRE(key2); + BOOST_CHECK_NE(key2.getName(), key1Name); + BOOST_CHECK_EQUAL(id.getKeys().size(), 1); + BOOST_CHECK_NO_THROW(key2.getDefaultCertificate()); + + // Create the third key + Key key3 = m_keyChain.createKey(id); + BOOST_CHECK_NE(key3.getName(), key2.getName()); + // The added key will not be the default key, because the default key already exists + BOOST_CHECK_EQUAL(id.getDefaultKey().getName(), key2.getName()); + BOOST_CHECK_EQUAL(id.getKeys().size(), 2); + BOOST_CHECK_NO_THROW(key3.getDefaultCertificate()); + + // Delete cert + BOOST_CHECK_EQUAL(key3.getCertificates().size(), 1); + Certificate key3Cert1 = *key3.getCertificates().begin(); + Name key3CertName = key3Cert1.getName(); + m_keyChain.deleteCertificate(key3, key3CertName); + BOOST_CHECK_EQUAL(key3.getCertificates().size(), 0); + BOOST_REQUIRE_THROW(key3.getDefaultCertificate(), Pib::Error); + + // Add cert + m_keyChain.addCertificate(key3, key3Cert1); + BOOST_CHECK_EQUAL(key3.getCertificates().size(), 1); + BOOST_CHECK_NO_THROW(key3.getDefaultCertificate()); + m_keyChain.addCertificate(key3, key3Cert1); // overwriting the cert should work + BOOST_CHECK_EQUAL(key3.getCertificates().size(), 1); + // Add another cert + Certificate key3Cert2 = key3Cert1; + Name key3Cert2Name = key3.getName(); + key3Cert2Name.append("Self"); + key3Cert2Name.appendVersion(); + key3Cert2.setName(key3Cert2Name); + m_keyChain.addCertificate(key3, key3Cert2); + BOOST_CHECK_EQUAL(key3.getCertificates().size(), 2); + + // Default certificate setting + BOOST_CHECK_EQUAL(key3.getDefaultCertificate().getName(), key3CertName); + m_keyChain.setDefaultCertificate(key3, key3Cert2); + BOOST_CHECK_EQUAL(key3.getDefaultCertificate().getName(), key3Cert2Name); + + // Default key setting + BOOST_CHECK_EQUAL(id.getDefaultKey().getName(), key2.getName()); + m_keyChain.setDefaultKey(id, key3); + BOOST_CHECK_EQUAL(id.getDefaultKey().getName(), key3.getName()); + + // Default identity setting + Identity id2 = m_keyChain.createIdentity(identity2Name); + BOOST_CHECK_EQUAL(m_keyChain.getPib().getDefaultIdentity().getName(), id.getName()); + m_keyChain.setDefaultIdentity(id2); + BOOST_CHECK_EQUAL(m_keyChain.getPib().getDefaultIdentity().getName(), id2.getName()); + + // Delete identity + m_keyChain.deleteIdentity(id); + // The identity instance should not be valid any more + BOOST_CHECK(!id); + BOOST_REQUIRE_THROW(m_keyChain.getPib().getIdentity(identityName), Pib::Error); + BOOST_CHECK(m_keyChain.getPib().getIdentities().find(identityName) == m_keyChain.getPib().getIdentities().end()); +} + +BOOST_FIXTURE_TEST_CASE(GeneralSigningInterface, IdentityManagementFixture) +{ + Identity id = addIdentity("/id"); + Key key = id.getDefaultKey(); + Certificate cert = key.getDefaultCertificate(); + + Name hmacKeyName = m_keyChain.createHmacKey(); + const Tpm& tpm = m_keyChain.getTpm(); + + std::vector signingInfos = { + SigningInfo(), + + SigningInfo(SigningInfo::SIGNER_TYPE_ID, id.getName()), + signingByIdentity(id.getName()), + + SigningInfo(id), + signingByIdentity(id), + + SigningInfo(SigningInfo::SIGNER_TYPE_KEY, key.getName()), + signingByKey(key.getName()), + + SigningInfo(key), + signingByKey(key), + + SigningInfo(SigningInfo::SIGNER_TYPE_CERT, cert.getName()), + signingByCertificate(cert.getName()), + signingByCertificate(cert), + + SigningInfo(SigningInfo::SIGNER_TYPE_HMAC, hmacKeyName), + SigningInfo("hmac-sha256:QjM3NEEyNkE3MTQ5MDQzN0FBMDI0RTRGQURENUI0OTdGREZGMUE4RUE2RkYxMkY2RkI2NUFGMjcyMEI1OUNDRg=="), + + SigningInfo(SigningInfo::SIGNER_TYPE_SHA256), + signingWithSha256() + }; + + for (const auto& signingInfo : signingInfos) { + BOOST_TEST_MESSAGE("SigningInfo: " << signingInfo); + Data data("/data"); + Interest interest("/interest"); + + if (signingInfo.getSignerType() == SigningInfo::SIGNER_TYPE_NULL) { + m_keyChain.sign(data); + m_keyChain.sign(interest); + } + else { + m_keyChain.sign(data, signingInfo); + m_keyChain.sign(interest, signingInfo); + } + + Signature interestSignature(interest.getName()[-2].blockFromValue(), interest.getName()[-1].blockFromValue()); + + if (signingInfo.getSignerType() == SigningInfo::SIGNER_TYPE_SHA256) { + BOOST_CHECK_EQUAL(data.getSignature().getType(), tlv::DigestSha256); + BOOST_CHECK_EQUAL(interestSignature.getType(), tlv::DigestSha256); + + BOOST_CHECK(verifyDigest(data, DigestAlgorithm::SHA256)); + BOOST_CHECK(verifyDigest(interest, DigestAlgorithm::SHA256)); + } + else if (signingInfo.getSignerType() == SigningInfo::SIGNER_TYPE_HMAC) { + Name keyName = signingInfo.getSignerName(); + BOOST_CHECK_EQUAL(data.getSignature().getType(), tlv::SignatureHmacWithSha256); + BOOST_CHECK_EQUAL(interestSignature.getType(), tlv::SignatureHmacWithSha256); + + BOOST_CHECK(bool(verifySignature(data, tpm, keyName, DigestAlgorithm::SHA256))); + BOOST_CHECK(bool(verifySignature(interest, tpm, keyName, DigestAlgorithm::SHA256))); + } + else { + BOOST_CHECK_EQUAL(data.getSignature().getType(), tlv::SignatureSha256WithEcdsa); + BOOST_CHECK_EQUAL(interestSignature.getType(), tlv::SignatureSha256WithEcdsa); + + BOOST_CHECK_EQUAL(data.getSignature().getKeyLocator().getName(), cert.getName().getPrefix(-2)); + BOOST_CHECK_EQUAL(interestSignature.getKeyLocator().getName(), cert.getName().getPrefix(-2)); + + BOOST_CHECK(verifySignature(data, key)); + BOOST_CHECK(verifySignature(interest, key)); + } + } +} + +BOOST_FIXTURE_TEST_CASE(PublicKeySigningDefaults, IdentityManagementFixture) +{ + Data data("/test/data"); + + // Identity will be created with generated key and self-signed cert with default parameters + BOOST_CHECK_THROW(m_keyChain.sign(data, signingByIdentity("/non-existing/identity")), KeyChain::InvalidSigningInfoError); + + // Create identity with EC key and the corresponding self-signed certificate + Identity id = addIdentity("/ndn/test/ec", EcKeyParams()); + BOOST_CHECK_NO_THROW(m_keyChain.sign(data, signingByIdentity(id.getName()))); + BOOST_CHECK_EQUAL(data.getSignature().getType(), + KeyChain::getSignatureType(EcKeyParams().getKeyType(), DigestAlgorithm::SHA256)); + BOOST_CHECK(id.getName().isPrefixOf(data.getSignature().getKeyLocator().getName())); + + // Create identity with RSA key and the corresponding self-signed certificate + id = addIdentity("/ndn/test/rsa", RsaKeyParams()); + BOOST_CHECK_NO_THROW(m_keyChain.sign(data, signingByIdentity(id.getName()))); + BOOST_CHECK_EQUAL(data.getSignature().getType(), + KeyChain::getSignatureType(RsaKeyParams().getKeyType(), DigestAlgorithm::SHA256)); + BOOST_CHECK(id.getName().isPrefixOf(data.getSignature().getKeyLocator().getName())); +} + +BOOST_FIXTURE_TEST_CASE(ImportPrivateKey, IdentityManagementFixture) +{ + Name keyName("/test/device2"); + std::string rawKey("nPSNOHyZKsg2WLqHAs7MXGb0sjQb4zCT"); + auto key = make_shared(); + key->loadRaw(KeyType::HMAC, reinterpret_cast(rawKey.data()), rawKey.size()); + + m_keyChain.importPrivateKey(keyName, key); + BOOST_CHECK_EQUAL(m_keyChain.getTpm().hasKey(keyName), true); + BOOST_CHECK_THROW(m_keyChain.importPrivateKey(keyName, key), KeyChain::Error); +} + +BOOST_FIXTURE_TEST_CASE(ExportImport, IdentityManagementFixture) +{ + Identity id = addIdentity("/TestKeyChain/ExportIdentity"); + Certificate cert = id.getDefaultKey().getDefaultCertificate(); + + shared_ptr exported = m_keyChain.exportSafeBag(cert, "1234", 4); + Block block = exported->wireEncode(); + + m_keyChain.deleteIdentity(id); + BOOST_CHECK_THROW(m_keyChain.exportSafeBag(cert, "1234", 4), KeyChain::Error); + + BOOST_CHECK_EQUAL(m_keyChain.getTpm().hasKey(cert.getKeyName()), false); + BOOST_CHECK_EQUAL(m_keyChain.getPib().getIdentities().size(), 0); + + SafeBag imported; + imported.wireDecode(block); + m_keyChain.importSafeBag(imported, "1234", 4); + BOOST_CHECK_THROW(m_keyChain.importSafeBag(imported, "1234", 4), KeyChain::Error); + + BOOST_CHECK_EQUAL(m_keyChain.getTpm().hasKey(cert.getKeyName()), true); + BOOST_CHECK_EQUAL(m_keyChain.getPib().getIdentities().size(), 1); + Identity newId = m_keyChain.getPib().getIdentity(cert.getIdentity()); + BOOST_CHECK_EQUAL(newId.getKeys().size(), 1); + Key newKey = newId.getKey(cert.getKeyName()); + BOOST_CHECK_EQUAL(newKey.getCertificates().size(), 1); + BOOST_CHECK_NO_THROW(newKey.getCertificate(cert.getName())); + + m_keyChain.deleteIdentity(newId); + BOOST_CHECK_EQUAL(m_keyChain.getPib().getIdentities().size(), 0); + BOOST_CHECK_EQUAL(m_keyChain.getTpm().hasKey(cert.getKeyName()), false); +} + +BOOST_FIXTURE_TEST_CASE(SelfSignedCertValidity, IdentityManagementFixture) +{ + Certificate cert = addIdentity("/Security/V2/TestKeyChain/SelfSignedCertValidity") + .getDefaultKey() + .getDefaultCertificate(); + BOOST_CHECK(cert.isValid()); + BOOST_CHECK(cert.isValid(time::system_clock::now() + 10 * 365_days)); + BOOST_CHECK_GT(cert.getValidityPeriod().getPeriod().second, time::system_clock::now() + 10 * 365_days); +} + +BOOST_AUTO_TEST_SUITE_END() // TestKeyChain +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/trust-anchor-container.t.cpp b/tests/unit/security/v2/trust-anchor-container.t.cpp new file mode 100644 index 000000000..8ed4cecfc --- /dev/null +++ b/tests/unit/security/v2/trust-anchor-container.t.cpp @@ -0,0 +1,192 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/trust-anchor-container.hpp" +#include "ndn-cxx/util/io.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/identity-management-time-fixture.hpp" + +#include + +namespace ndn { +namespace security { +namespace v2 { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) + +/** + * This fixture creates a directory and prepares two certificates. + * cert1 is written to a file under the directory, while cert2 is not. + */ +class AnchorContainerTestFixture : public IdentityManagementTimeFixture +{ +public: + AnchorContainerTestFixture() + { + namespace fs = boost::filesystem; + + fs::create_directory(fs::path(UNIT_TEST_CONFIG_PATH)); + + certDirPath = fs::path(UNIT_TEST_CONFIG_PATH) / "test-cert-dir"; + fs::create_directory(certDirPath); + + certPath1 = fs::path(UNIT_TEST_CONFIG_PATH) / "test-cert-dir" / "trust-anchor-1.cert"; + certPath2 = fs::path(UNIT_TEST_CONFIG_PATH) / "test-cert-dir" / "trust-anchor-2.cert"; + + identity1 = addIdentity("/TestAnchorContainer/First"); + cert1 = identity1.getDefaultKey().getDefaultCertificate(); + saveCertToFile(cert1, certPath1.string()); + + identity2 = addIdentity("/TestAnchorContainer/Second"); + cert2 = identity2.getDefaultKey().getDefaultCertificate(); + saveCertToFile(cert2, certPath2.string()); + } + + ~AnchorContainerTestFixture() + { + boost::filesystem::remove_all(UNIT_TEST_CONFIG_PATH); + } + +public: + TrustAnchorContainer anchorContainer; + + boost::filesystem::path certDirPath; + boost::filesystem::path certPath1; + boost::filesystem::path certPath2; + + Identity identity1; + Identity identity2; + + Certificate cert1; + Certificate cert2; +}; + +BOOST_FIXTURE_TEST_SUITE(TestTrustAnchorContainer, AnchorContainerTestFixture) + +// one static group and one dynamic group created from file +BOOST_AUTO_TEST_CASE(Insert) +{ + // Static + anchorContainer.insert("group1", Certificate(cert1)); + BOOST_CHECK(anchorContainer.find(cert1.getName()) != nullptr); + BOOST_CHECK(anchorContainer.find(identity1.getName()) != nullptr); + const Certificate* cert = anchorContainer.find(cert1.getName()); + BOOST_CHECK_NO_THROW(anchorContainer.insert("group1", Certificate(cert1))); + BOOST_CHECK_EQUAL(cert, anchorContainer.find(cert1.getName())); // still the same instance of the certificate + // cannot add dynamic group when static already exists + BOOST_CHECK_THROW(anchorContainer.insert("group1", certPath1.string(), 1_s), TrustAnchorContainer::Error); + BOOST_CHECK_EQUAL(anchorContainer.getGroup("group1").size(), 1); + BOOST_CHECK_EQUAL(anchorContainer.size(), 1); + + // From file + anchorContainer.insert("group2", certPath2.string(), 1_s); + BOOST_CHECK(anchorContainer.find(cert2.getName()) != nullptr); + BOOST_CHECK(anchorContainer.find(identity2.getName()) != nullptr); + BOOST_CHECK_THROW(anchorContainer.insert("group2", Certificate(cert2)), TrustAnchorContainer::Error); + BOOST_CHECK_THROW(anchorContainer.insert("group2", certPath2.string(), 1_s), TrustAnchorContainer::Error); + BOOST_CHECK_EQUAL(anchorContainer.getGroup("group2").size(), 1); + BOOST_CHECK_EQUAL(anchorContainer.size(), 2); + + boost::filesystem::remove(certPath2); + advanceClocks(1_s, 11); + + BOOST_CHECK(anchorContainer.find(identity2.getName()) == nullptr); + BOOST_CHECK(anchorContainer.find(cert2.getName()) == nullptr); + BOOST_CHECK_EQUAL(anchorContainer.getGroup("group2").size(), 0); + BOOST_CHECK_EQUAL(anchorContainer.size(), 1); + + TrustAnchorGroup& group = anchorContainer.getGroup("group1"); + auto staticGroup = dynamic_cast(&group); + BOOST_REQUIRE(staticGroup != nullptr); + BOOST_CHECK_EQUAL(staticGroup->size(), 1); + staticGroup->remove(cert1.getName()); + BOOST_CHECK_EQUAL(staticGroup->size(), 0); + BOOST_CHECK_EQUAL(anchorContainer.size(), 0); + + BOOST_CHECK_THROW(anchorContainer.getGroup("non-existing-group"), TrustAnchorContainer::Error); +} + +BOOST_AUTO_TEST_CASE(DynamicAnchorFromDir) +{ + boost::filesystem::remove(certPath2); + + anchorContainer.insert("group", certDirPath.string(), 1_s, true /* isDir */); + + BOOST_CHECK(anchorContainer.find(identity1.getName()) != nullptr); + BOOST_CHECK(anchorContainer.find(identity2.getName()) == nullptr); + BOOST_CHECK_EQUAL(anchorContainer.getGroup("group").size(), 1); + + saveCertToFile(cert2, certPath2.string()); + + advanceClocks(100_ms, 11); + + BOOST_CHECK(anchorContainer.find(identity1.getName()) != nullptr); + BOOST_CHECK(anchorContainer.find(identity2.getName()) != nullptr); + BOOST_CHECK_EQUAL(anchorContainer.getGroup("group").size(), 2); + + boost::filesystem::remove_all(certDirPath); + + advanceClocks(100_ms, 11); + + BOOST_CHECK(anchorContainer.find(identity1.getName()) == nullptr); + BOOST_CHECK(anchorContainer.find(identity2.getName()) == nullptr); + BOOST_CHECK_EQUAL(anchorContainer.getGroup("group").size(), 0); +} + +BOOST_FIXTURE_TEST_CASE(FindByInterest, AnchorContainerTestFixture) +{ + anchorContainer.insert("group1", certPath1.string(), 1_s); + Interest interest(identity1.getName()); + BOOST_CHECK(anchorContainer.find(interest) != nullptr); + Interest interest1(identity1.getName().getPrefix(-1)); + BOOST_CHECK(anchorContainer.find(interest1) != nullptr); + Interest interest2(Name(identity1.getName()).appendVersion()); + BOOST_CHECK(anchorContainer.find(interest2) == nullptr); + + Certificate cert3 = addCertificate(identity1.getDefaultKey(), "3"); + Certificate cert4 = addCertificate(identity1.getDefaultKey(), "4"); + Certificate cert5 = addCertificate(identity1.getDefaultKey(), "5"); + + Certificate cert3Copy = cert3; + anchorContainer.insert("group2", std::move(cert3Copy)); + anchorContainer.insert("group3", std::move(cert4)); + anchorContainer.insert("group4", std::move(cert5)); + + Interest interest3(cert3.getKeyName()); + const Certificate* foundCert = anchorContainer.find(interest3); + BOOST_REQUIRE(foundCert != nullptr); + BOOST_CHECK(interest3.getName().isPrefixOf(foundCert->getName())); + BOOST_CHECK_EQUAL(foundCert->getName(), cert3.getName()); +} + +BOOST_AUTO_TEST_SUITE_END() // TestTrustAnchorContainer +BOOST_AUTO_TEST_SUITE_END() // Detail +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/validation-error.t.cpp b/tests/unit/security/v2/validation-error.t.cpp new file mode 100644 index 000000000..21821eecf --- /dev/null +++ b/tests/unit/security/v2/validation-error.t.cpp @@ -0,0 +1,61 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validation-error.hpp" + +#include "tests/boost-test.hpp" +#include + +namespace ndn { +namespace security { +namespace v2 { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) +BOOST_AUTO_TEST_SUITE(TestValidationError) + +BOOST_AUTO_TEST_CASE(Basic) +{ + ValidationError e1{ValidationError::Code::INVALID_SIGNATURE}; + BOOST_CHECK_EQUAL(e1.getCode(), 1); + BOOST_CHECK_EQUAL(e1.getInfo(), ""); + BOOST_CHECK_EQUAL(boost::lexical_cast(e1), "Invalid signature"); + + ValidationError e2{ValidationError::Code::NO_SIGNATURE, "message"}; + BOOST_CHECK_EQUAL(e2.getCode(), 2); + BOOST_CHECK_EQUAL(e2.getInfo(), "message"); + BOOST_CHECK_EQUAL(boost::lexical_cast(e2), "Missing signature (message)"); + + ValidationError e3{65535, "other message"}; + BOOST_CHECK_EQUAL(e3.getCode(), 65535); + BOOST_CHECK_EQUAL(e3.getInfo(), "other message"); + BOOST_CHECK_EQUAL(boost::lexical_cast(e3), "Custom error code 65535 (other message)"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestValidationError +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/validation-policy-accept-all.t.cpp b/tests/unit/security/v2/validation-policy-accept-all.t.cpp new file mode 100644 index 000000000..9d7d92700 --- /dev/null +++ b/tests/unit/security/v2/validation-policy-accept-all.t.cpp @@ -0,0 +1,79 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validation-policy-accept-all.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/v2/validator-fixture.hpp" + +#include + +namespace ndn { +namespace security { +namespace v2 { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) + +class ValidationPolicyAcceptAllFixture : public ValidatorFixture +{ +public: + ValidationPolicyAcceptAllFixture() + { + identity = addIdentity("/Security/V2/TestValidationPolicyAcceptAll"); + // don't add trust anchors + } + +public: + Identity identity; +}; + +BOOST_FIXTURE_TEST_SUITE(TestValidationPolicyAcceptAll, ValidationPolicyAcceptAllFixture) + +typedef boost::mpl::vector Packets; + +BOOST_AUTO_TEST_CASE_TEMPLATE(Validate, Packet, Packets) +{ + Packet unsignedPacket("/Security/V2/TestValidationPolicyAcceptAll/Sub/Packet"); + + Packet packet = unsignedPacket; + VALIDATE_SUCCESS(packet, "Should accept unsigned"); + + packet = unsignedPacket; + m_keyChain.sign(packet, signingWithSha256()); + VALIDATE_SUCCESS(packet, "Should accept Sha256Digest signature"); + + packet = unsignedPacket; + m_keyChain.sign(packet, signingByIdentity(identity)); + VALIDATE_SUCCESS(packet, "Should accept signature while no trust anchors configured"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestValidationPolicyAcceptAll +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/validation-policy-command-interest.t.cpp b/tests/unit/security/v2/validation-policy-command-interest.t.cpp new file mode 100644 index 000000000..a061a274c --- /dev/null +++ b/tests/unit/security/v2/validation-policy-command-interest.t.cpp @@ -0,0 +1,485 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validation-policy-command-interest.hpp" +#include "ndn-cxx/security/v2/validation-policy-simple-hierarchy.hpp" +#include "ndn-cxx/security/v2/validation-policy-accept-all.hpp" +#include "ndn-cxx/security/command-interest-signer.hpp" +#include "ndn-cxx/security/signing-helpers.hpp" + +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" +#include "tests/unit/security/v2/validator-fixture.hpp" + +#include +#include + +namespace ndn { +namespace security { +namespace v2 { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) + +class DefaultOptions +{ +public: + static ValidationPolicyCommandInterest::Options + getOptions() + { + return {}; + } +}; + +template +class CommandInterestPolicyWrapper : public ValidationPolicyCommandInterest +{ +public: + CommandInterestPolicyWrapper() + : ValidationPolicyCommandInterest(make_unique(), T::getOptions()) + { + } +}; + +template +class ValidationPolicyCommandInterestFixture : public HierarchicalValidatorFixture> +{ +public: + ValidationPolicyCommandInterestFixture() + : m_signer(this->m_keyChain) + { + } + + Interest + makeCommandInterest(const Identity& identity) + { + return m_signer.makeCommandInterest(Name(identity.getName()).append("CMD"), + signingByIdentity(identity)); + } + +public: + CommandInterestSigner m_signer; +}; + +BOOST_FIXTURE_TEST_SUITE(TestValidationPolicyCommandInterest, ValidationPolicyCommandInterestFixture) + +BOOST_AUTO_TEST_SUITE(Accepts) + +BOOST_AUTO_TEST_CASE(Basic) +{ + auto i1 = makeCommandInterest(identity); + VALIDATE_SUCCESS(i1, "Should succeed (within grace period)"); + VALIDATE_FAILURE(i1, "Should fail (replay attack)"); + + advanceClocks(5_ms); + auto i2 = makeCommandInterest(identity); + VALIDATE_SUCCESS(i2, "Should succeed (timestamp larger than previous)"); + + auto i3 = m_signer.makeCommandInterest(Name(identity.getName()).append("CMD"), signingWithSha256()); + VALIDATE_FAILURE(i3, "Should fail (Sha256 signature violates policy)"); +} + +BOOST_AUTO_TEST_CASE(DataPassthru) +{ + Data d1("/Security/V2/ValidatorFixture/Sub1"); + m_keyChain.sign(d1); + VALIDATE_SUCCESS(d1, "Should succeed (fallback on inner validation policy for data)"); +} + +using ValidationPolicyAcceptAllCommands = ValidationPolicyCommandInterestFixture; + +BOOST_FIXTURE_TEST_CASE(SignedWithSha256, ValidationPolicyAcceptAllCommands) // Bug 4635 +{ + auto i1 = m_signer.makeCommandInterest("/hello/world/CMD", signingWithSha256()); + VALIDATE_SUCCESS(i1, "Should succeed (within grace period)"); + VALIDATE_FAILURE(i1, "Should fail (replay attack)"); + + advanceClocks(5_ms); + auto i2 = m_signer.makeCommandInterest("/hello/world/CMD", signingWithSha256()); + VALIDATE_SUCCESS(i2, "Should succeed (timestamp larger than previous)"); +} + +BOOST_AUTO_TEST_SUITE_END() // Accepts + +BOOST_AUTO_TEST_SUITE(Rejects) + +BOOST_AUTO_TEST_CASE(NameTooShort) +{ + auto i1 = makeInterest("/name/too/short"); + VALIDATE_FAILURE(*i1, "Should fail (name is too short)"); +} + +BOOST_AUTO_TEST_CASE(BadTimestamp) +{ + auto i1 = makeCommandInterest(identity); + setNameComponent(i1, command_interest::POS_TIMESTAMP, "not-timestamp"); + VALIDATE_FAILURE(i1, "Should fail (timestamp is missing)"); +} + +BOOST_AUTO_TEST_CASE(BadSigInfo) +{ + auto i1 = makeCommandInterest(identity); + setNameComponent(i1, command_interest::POS_SIG_INFO, "not-SignatureInfo"); + VALIDATE_FAILURE(i1, "Should fail (signature info is missing)"); +} + +BOOST_AUTO_TEST_CASE(MissingKeyLocator) +{ + auto i1 = makeCommandInterest(identity); + SignatureInfo sigInfo(tlv::SignatureSha256WithRsa); + setNameComponent(i1, command_interest::POS_SIG_INFO, + sigInfo.wireEncode().begin(), sigInfo.wireEncode().end()); + VALIDATE_FAILURE(i1, "Should fail (missing KeyLocator)"); +} + +BOOST_AUTO_TEST_CASE(BadKeyLocatorType) +{ + auto i1 = makeCommandInterest(identity); + KeyLocator kl; + kl.setKeyDigest(makeBinaryBlock(tlv::KeyDigest, "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD", 8)); + SignatureInfo sigInfo(tlv::SignatureSha256WithRsa); + sigInfo.setKeyLocator(kl); + setNameComponent(i1, command_interest::POS_SIG_INFO, + sigInfo.wireEncode().begin(), sigInfo.wireEncode().end()); + VALIDATE_FAILURE(i1, "Should fail (bad KeyLocator type)"); +} + +BOOST_AUTO_TEST_CASE(BadCertName) +{ + auto i1 = makeCommandInterest(identity); + KeyLocator kl; + kl.setName("/bad/cert/name"); + SignatureInfo sigInfo(tlv::SignatureSha256WithRsa); + sigInfo.setKeyLocator(kl); + setNameComponent(i1, command_interest::POS_SIG_INFO, + sigInfo.wireEncode().begin(), sigInfo.wireEncode().end()); + VALIDATE_FAILURE(i1, "Should fail (bad certificate name)"); +} + +BOOST_AUTO_TEST_CASE(InnerPolicyReject) +{ + auto i1 = makeCommandInterest(otherIdentity); + VALIDATE_FAILURE(i1, "Should fail (inner policy should reject)"); +} + +class GracePeriod15Sec +{ +public: + static ValidationPolicyCommandInterest::Options + getOptions() + { + ValidationPolicyCommandInterest::Options options; + options.gracePeriod = 15_s; + return options; + } +}; + +BOOST_FIXTURE_TEST_CASE(TimestampOutOfGracePositive, ValidationPolicyCommandInterestFixture) +{ + auto i1 = makeCommandInterest(identity); // signed at 0s + advanceClocks(16_s); // verifying at +16s + VALIDATE_FAILURE(i1, "Should fail (timestamp outside the grace period)"); + rewindClockAfterValidation(); + + auto i2 = makeCommandInterest(identity); // signed at +16s + VALIDATE_SUCCESS(i2, "Should succeed"); +} + +BOOST_FIXTURE_TEST_CASE(TimestampOutOfGraceNegative, ValidationPolicyCommandInterestFixture) +{ + auto i1 = makeCommandInterest(identity); // signed at 0s + advanceClocks(1_s); + auto i2 = makeCommandInterest(identity); // signed at +1s + advanceClocks(1_s); + auto i3 = makeCommandInterest(identity); // signed at +2s + + systemClock->advance(-18_s); // verifying at -16s + VALIDATE_FAILURE(i1, "Should fail (timestamp outside the grace period)"); + rewindClockAfterValidation(); + + // CommandInterestValidator should not remember i1's timestamp + VALIDATE_FAILURE(i2, "Should fail (timestamp outside the grace period)"); + rewindClockAfterValidation(); + + // CommandInterestValidator should not remember i2's timestamp, and should treat i3 as initial + advanceClocks(18_s); // verifying at +2s + VALIDATE_SUCCESS(i3, "Should succeed"); +} + +BOOST_AUTO_TEST_CASE(TimestampReorderEqual) +{ + auto i1 = makeCommandInterest(identity); // signed at 0s + VALIDATE_SUCCESS(i1, "Should succeed"); + + auto i2 = makeCommandInterest(identity); // signed at 0s + setNameComponent(i2, command_interest::POS_TIMESTAMP, + i1.getName()[command_interest::POS_TIMESTAMP]); + VALIDATE_FAILURE(i2, "Should fail (timestamp reordered)"); + + advanceClocks(2_s); + auto i3 = makeCommandInterest(identity); // signed at +2s + VALIDATE_SUCCESS(i3, "Should succeed"); +} + +BOOST_AUTO_TEST_CASE(TimestampReorderNegative) +{ + auto i2 = makeCommandInterest(identity); // signed at 0ms + advanceClocks(200_ms); + auto i3 = makeCommandInterest(identity); // signed at +200ms + advanceClocks(900_ms); + auto i1 = makeCommandInterest(identity); // signed at +1100ms + advanceClocks(300_ms); + auto i4 = makeCommandInterest(identity); // signed at +1400ms + + systemClock->advance(-300_ms); // verifying at +1100ms + VALIDATE_SUCCESS(i1, "Should succeed"); + rewindClockAfterValidation(); + + systemClock->advance(-1100_ms); // verifying at 0ms + VALIDATE_FAILURE(i2, "Should fail (timestamp reordered)"); + rewindClockAfterValidation(); + + // CommandInterestValidator should not remember i2's timestamp + advanceClocks(200_ms); // verifying at +200ms + VALIDATE_FAILURE(i3, "Should fail (timestamp reordered)"); + rewindClockAfterValidation(); + + advanceClocks(1200_ms); // verifying at 1400ms + VALIDATE_SUCCESS(i4, "Should succeed"); +} + +BOOST_AUTO_TEST_SUITE_END() // Rejects + +BOOST_AUTO_TEST_SUITE(Options) + +template +class GracePeriod +{ +public: + static ValidationPolicyCommandInterest::Options + getOptions() + { + ValidationPolicyCommandInterest::Options options; + options.gracePeriod = time::seconds(T::value); + return options; + } +}; + +typedef boost::mpl::vector< + GracePeriod>, + GracePeriod> +> GraceNonPositiveValues; + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(GraceNonPositive, GracePeriod, GraceNonPositiveValues, + ValidationPolicyCommandInterestFixture) +{ + auto i1 = this->makeCommandInterest(this->identity); // signed at 0ms + auto i2 = this->makeCommandInterest(this->subIdentity); // signed at 0ms + for (auto interest : {&i1, &i2}) { + setNameComponent(*interest, command_interest::POS_TIMESTAMP, + name::Component::fromNumber(time::toUnixTimestamp(time::system_clock::now()).count())); + } // ensure timestamps are exactly 0ms + + VALIDATE_SUCCESS(i1, "Should succeed when validating at 0ms"); + this->rewindClockAfterValidation(); + + this->advanceClocks(1_ms); + VALIDATE_FAILURE(i2, "Should fail when validating at 1ms"); +} + +class LimitedRecordsOptions +{ +public: + static ValidationPolicyCommandInterest::Options + getOptions() + { + ValidationPolicyCommandInterest::Options options; + options.gracePeriod = 15_s; + options.maxRecords = 3; + return options; + } +}; + +BOOST_FIXTURE_TEST_CASE(LimitedRecords, ValidationPolicyCommandInterestFixture) +{ + Identity id1 = this->addSubCertificate("/Security/V2/ValidatorFixture/Sub1", identity); + this->cache.insert(id1.getDefaultKey().getDefaultCertificate()); + Identity id2 = this->addSubCertificate("/Security/V2/ValidatorFixture/Sub2", identity); + this->cache.insert(id2.getDefaultKey().getDefaultCertificate()); + Identity id3 = this->addSubCertificate("/Security/V2/ValidatorFixture/Sub3", identity); + this->cache.insert(id3.getDefaultKey().getDefaultCertificate()); + Identity id4 = this->addSubCertificate("/Security/V2/ValidatorFixture/Sub4", identity); + this->cache.insert(id4.getDefaultKey().getDefaultCertificate()); + + auto i1 = makeCommandInterest(id2); + auto i2 = makeCommandInterest(id3); + auto i3 = makeCommandInterest(id4); + auto i00 = makeCommandInterest(id1); // signed at 0s + advanceClocks(1_s); + auto i01 = makeCommandInterest(id1); // signed at 1s + advanceClocks(1_s); + auto i02 = makeCommandInterest(id1); // signed at 2s + + VALIDATE_SUCCESS(i00, "Should succeed"); + rewindClockAfterValidation(); + + VALIDATE_SUCCESS(i02, "Should succeed"); + rewindClockAfterValidation(); + + VALIDATE_SUCCESS(i1, "Should succeed"); + rewindClockAfterValidation(); + + VALIDATE_SUCCESS(i2, "Should succeed"); + rewindClockAfterValidation(); + + VALIDATE_SUCCESS(i3, "Should succeed, forgets identity id1"); + rewindClockAfterValidation(); + + VALIDATE_SUCCESS(i01, "Should succeed despite timestamp is reordered, because record has been evicted"); +} + +class UnlimitedRecordsOptions +{ +public: + static ValidationPolicyCommandInterest::Options + getOptions() + { + ValidationPolicyCommandInterest::Options options; + options.gracePeriod = 15_s; + options.maxRecords = -1; + return options; + } +}; + +BOOST_FIXTURE_TEST_CASE(UnlimitedRecords, ValidationPolicyCommandInterestFixture) +{ + std::vector identities; + for (int i = 0; i < 20; ++i) { + Identity id = this->addSubCertificate("/Security/V2/ValidatorFixture/Sub" + to_string(i), identity); + this->cache.insert(id.getDefaultKey().getDefaultCertificate()); + identities.push_back(id); + } + + auto i1 = makeCommandInterest(identities.at(0)); // signed at 0s + advanceClocks(1_s); + for (int i = 0; i < 20; ++i) { + auto i2 = makeCommandInterest(identities.at(i)); // signed at +1s + + VALIDATE_SUCCESS(i2, "Should succeed"); + rewindClockAfterValidation(); + } + VALIDATE_FAILURE(i1, "Should fail (timestamp reorder)"); +} + +class ZeroRecordsOptions +{ +public: + static ValidationPolicyCommandInterest::Options + getOptions() + { + ValidationPolicyCommandInterest::Options options; + options.gracePeriod = 15_s; + options.maxRecords = 0; + return options; + } +}; + +BOOST_FIXTURE_TEST_CASE(ZeroRecords, ValidationPolicyCommandInterestFixture) +{ + auto i1 = makeCommandInterest(identity); // signed at 0s + advanceClocks(1_s); + auto i2 = makeCommandInterest(identity); // signed at +1s + VALIDATE_SUCCESS(i2, "Should succeed"); + rewindClockAfterValidation(); + + VALIDATE_SUCCESS(i1, "Should succeed despite timestamp is reordered, because record isn't kept"); +} + +class LimitedRecordLifetimeOptions +{ +public: + static ValidationPolicyCommandInterest::Options + getOptions() + { + ValidationPolicyCommandInterest::Options options; + options.gracePeriod = 400_s; + options.recordLifetime = 300_s; + return options; + } +}; + +BOOST_FIXTURE_TEST_CASE(LimitedRecordLifetime, ValidationPolicyCommandInterestFixture) +{ + auto i1 = makeCommandInterest(identity); // signed at 0s + advanceClocks(240_s); + auto i2 = makeCommandInterest(identity); // signed at +240s + advanceClocks(120_s); + auto i3 = makeCommandInterest(identity); // signed at +360s + + systemClock->advance(-360_s); // rewind system clock to 0s + VALIDATE_SUCCESS(i1, "Should succeed"); + rewindClockAfterValidation(); + + VALIDATE_SUCCESS(i3, "Should succeed"); + rewindClockAfterValidation(); + + advanceClocks(30_s, 301_s); // advance steady clock by 301s, and system clock to +301s + VALIDATE_SUCCESS(i2, "Should succeed despite timestamp is reordered, because record has been expired"); +} + +class ZeroRecordLifetimeOptions +{ +public: + static ValidationPolicyCommandInterest::Options + getOptions() + { + ValidationPolicyCommandInterest::Options options; + options.gracePeriod = 15_s; + options.recordLifetime = time::seconds::zero(); + return options; + } +}; + +BOOST_FIXTURE_TEST_CASE(ZeroRecordLifetime, ValidationPolicyCommandInterestFixture) +{ + auto i1 = makeCommandInterest(identity); // signed at 0s + advanceClocks(1_s); + auto i2 = makeCommandInterest(identity); // signed at +1s + VALIDATE_SUCCESS(i2, "Should succeed"); + rewindClockAfterValidation(); + + VALIDATE_SUCCESS(i1, "Should succeed despite timestamp is reordered, because record has been expired"); +} + +BOOST_AUTO_TEST_SUITE_END() // Options + +BOOST_AUTO_TEST_SUITE_END() // TestValidationPolicyCommandInterest +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/validation-policy-config.t.cpp b/tests/unit/security/v2/validation-policy-config.t.cpp new file mode 100644 index 000000000..f7a450634 --- /dev/null +++ b/tests/unit/security/v2/validation-policy-config.t.cpp @@ -0,0 +1,558 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validation-policy-config.hpp" +#include "ndn-cxx/security/transform/base64-encode.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" +#include "ndn-cxx/util/logger.hpp" +#include "ndn-cxx/util/io.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/v2/validator-config/common.hpp" +#include "tests/unit/security/v2/validator-fixture.hpp" + +namespace ndn { +namespace security { +namespace v2 { +namespace validator_config { +namespace tests { + +using namespace ndn::tests; +using namespace ndn::security::v2::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) +BOOST_AUTO_TEST_SUITE(TestValidationPolicyConfig) + +BOOST_FIXTURE_TEST_CASE(EmptyConfig, HierarchicalValidatorFixture) +{ + this->policy.load(ConfigSection{}, ""); + + BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true); + BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, false); + BOOST_CHECK_EQUAL(this->policy.m_dataRules.size(), 0); + BOOST_CHECK_EQUAL(this->policy.m_interestRules.size(), 0); + + Data d("/Security/V2/ValidationPolicyConfig/D"); + this->m_keyChain.sign(d, signingByIdentity(this->identity)); + VALIDATE_FAILURE(d, "Empty policy should reject everything"); + + Interest i("/Security/V2/ValidationPolicyConfig/I"); + this->m_keyChain.sign(i, signingByIdentity(this->identity)); + VALIDATE_FAILURE(i, "Empty policy should reject everything"); +} + +template +class PacketName; + +template<> +class PacketName +{ +public: + static std::string + getName() + { + return "interest"; + } +}; + +template<> +class PacketName +{ +public: + static std::string + getName() + { + return "data"; + } +}; + +template +class ValidationPolicyConfigFixture : public HierarchicalValidatorFixture +{ +public: + ValidationPolicyConfigFixture() + : path(boost::filesystem::path(UNIT_TEST_CONFIG_PATH) / "security" / "v2" / "validation-policy-config") + { + boost::filesystem::create_directories(path); + baseConfig = R"CONF( + rule + { + id test-rule-id + for )CONF" + PacketName::getName() + R"CONF( + filter + { + type name + name )CONF" + identity.getName().toUri() + R"CONF( + relation is-prefix-of + } + checker + { + type hierarchical + sig-type rsa-sha256 + } + } + )CONF"; + } + + ~ValidationPolicyConfigFixture() + { + boost::system::error_code ec; + boost::filesystem::remove_all(path, ec); + } + +protected: + using Packet = PacketType; + + const boost::filesystem::path path; + std::string baseConfig; +}; + +template +class LoadStringWithFileAnchor : public ValidationPolicyConfigFixture +{ +public: + LoadStringWithFileAnchor() + { + BOOST_CHECK_EQUAL(this->policy.m_isConfigured, false); + + this->saveCertificate(this->identity, (this->path / "identity.ndncert").string()); + this->policy.load(this->baseConfig + R"CONF( + trust-anchor + { + type file + file-name "trust-anchor.ndncert" + } + )CONF", (this->path / "test-config").string()); + + BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true); + BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, false); + } +}; + +template +class LoadFileWithFileAnchor : public ValidationPolicyConfigFixture +{ +public: + LoadFileWithFileAnchor() + { + std::string configFile = (this->path / "config.conf").string(); + { + std::ofstream config(configFile); + config << this->baseConfig << R"CONF( + trust-anchor + { + type file + file-name "trust-anchor.ndncert" + } + )CONF"; + } + + this->saveCertificate(this->identity, (this->path / "identity.ndncert").string()); + + BOOST_CHECK_EQUAL(this->policy.m_isConfigured, false); + + this->policy.load(configFile); + + BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true); + BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, false); + } +}; + +template +class LoadSectionWithFileAnchor : public ValidationPolicyConfigFixture +{ +public: + LoadSectionWithFileAnchor() + { + auto section = makeSection(this->baseConfig + R"CONF( + trust-anchor + { + type file + file-name "trust-anchor.ndncert" + } + )CONF"); + + this->saveCertificate(this->identity, (this->path / "identity.ndncert").string()); + + BOOST_CHECK_EQUAL(this->policy.m_isConfigured, false); + + this->policy.load(section, (this->path / "test-config").string()); + + BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true); + BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, false); + } +}; + +template +class LoadStringWithBase64Anchor : public ValidationPolicyConfigFixture +{ +public: + LoadStringWithBase64Anchor() + { + BOOST_CHECK_EQUAL(this->policy.m_isConfigured, false); + + std::ostringstream os; + { + using namespace ndn::security::transform; + const auto& cert = this->identity.getDefaultKey().getDefaultCertificate().wireEncode(); + bufferSource(cert.wire(), cert.size()) >> base64Encode(false) >> streamSink(os); + } + + this->policy.load(this->baseConfig + R"CONF( + trust-anchor + { + type base64 + base64-string ")CONF" + os.str() + R"CONF(" + } + )CONF", (this->path / "test-config").string()); + + BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true); + BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, false); + } +}; + +class NoRefresh +{ +public: + static std::string + getRefreshString() + { + return ""; + } +}; + +class Refresh1h +{ +public: + static std::string + getRefreshString() + { + return "refresh 1h"; + } + + static time::milliseconds + getRefreshTime() + { + return 1_h; + } +}; + +class Refresh1m +{ +public: + static std::string + getRefreshString() + { + return "refresh 1m"; + } + + static time::milliseconds + getRefreshTime() + { + return 1_min; + } +}; + +class Refresh1s +{ +public: + static std::string + getRefreshString() + { + return "refresh 1s"; + } + + static time::milliseconds + getRefreshTime() + { + return 1_s; + } +}; + +template +class LoadStringWithDirAnchor : public ValidationPolicyConfigFixture +{ +public: + LoadStringWithDirAnchor() + { + BOOST_CHECK_EQUAL(this->policy.m_isConfigured, false); + + boost::filesystem::create_directories(this->path / "keys"); + this->saveCertificate(this->identity, (this->path / "keys" / "identity.ndncert").string()); + + this->policy.load(this->baseConfig + R"CONF( + trust-anchor + { + type dir + dir keys + )CONF" + Refresh::getRefreshString() + R"CONF( + } + )CONF", (this->path / "test-config").string()); + + BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true); + BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, false); + } +}; + +using DataPolicies = boost::mpl::vector, + LoadFileWithFileAnchor, + LoadSectionWithFileAnchor, + LoadStringWithBase64Anchor, + LoadStringWithDirAnchor, + LoadStringWithDirAnchor, + LoadStringWithDirAnchor, + LoadStringWithDirAnchor + >; + +using InterestPolicies = boost::mpl::vector, + LoadFileWithFileAnchor, + LoadSectionWithFileAnchor, + LoadStringWithBase64Anchor, + LoadStringWithDirAnchor, + LoadStringWithDirAnchor, + LoadStringWithDirAnchor, + LoadStringWithDirAnchor + >; + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateData, Policy, DataPolicies, Policy) +{ + BOOST_CHECK_EQUAL(this->policy.m_dataRules.size(), 1); + BOOST_CHECK_EQUAL(this->policy.m_interestRules.size(), 0); + + using Packet = typename Policy::Packet; + Packet unsignedPacket("/Security/V2/ValidatorFixture/Sub1/Sub2/Packet"); + + Packet packet = unsignedPacket; + VALIDATE_FAILURE(packet, "Unsigned"); + + packet = unsignedPacket; + this->m_keyChain.sign(packet, signingWithSha256()); + VALIDATE_FAILURE(packet, "Policy doesn't accept Sha256Digest signature"); + + packet = unsignedPacket; + this->m_keyChain.sign(packet, signingByIdentity(this->identity)); + VALIDATE_SUCCESS(packet, "Should get accepted, as signed by the anchor"); + + packet = unsignedPacket; + this->m_keyChain.sign(packet, signingByIdentity(this->subIdentity)); + VALIDATE_SUCCESS(packet, "Should get accepted, as signed by the policy-compliant cert"); + + packet = unsignedPacket; + this->m_keyChain.sign(packet, signingByIdentity(this->otherIdentity)); + VALIDATE_FAILURE(packet, "Should fail, as signed by the policy-violating cert"); + + packet = unsignedPacket; + this->m_keyChain.sign(packet, signingByIdentity(this->subSelfSignedIdentity)); + VALIDATE_FAILURE(packet, "Should fail, because subSelfSignedIdentity is not a trust anchor"); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateInterest, Policy, InterestPolicies, Policy) +{ + BOOST_CHECK_EQUAL(this->policy.m_dataRules.size(), 0); + BOOST_CHECK_EQUAL(this->policy.m_interestRules.size(), 1); + + using Packet = typename Policy::Packet; + Packet unsignedPacket("/Security/V2/ValidatorFixture/Sub1/Sub2/Packet"); + + Packet packet = unsignedPacket; + VALIDATE_FAILURE(packet, "Unsigned"); + + packet = unsignedPacket; + this->m_keyChain.sign(packet, signingWithSha256()); + VALIDATE_FAILURE(packet, "Policy doesn't accept Sha256Digest signature"); + + packet = unsignedPacket; + this->m_keyChain.sign(packet, signingByIdentity(this->identity)); + VALIDATE_SUCCESS(packet, "Should get accepted, as signed by the anchor"); + + packet = unsignedPacket; + this->m_keyChain.sign(packet, signingByIdentity(this->subIdentity)); + VALIDATE_FAILURE(packet, "Should fail, as there is no matching rule for data"); + + packet = unsignedPacket; + this->m_keyChain.sign(packet, signingByIdentity(this->otherIdentity)); + VALIDATE_FAILURE(packet, "Should fail, as signed by the policy-violating cert"); + + packet = unsignedPacket; + this->m_keyChain.sign(packet, signingByIdentity(this->subSelfSignedIdentity)); + VALIDATE_FAILURE(packet, "Should fail, because subSelfSignedIdentity is not a trust anchor"); +} + +BOOST_FIXTURE_TEST_CASE(Reload, HierarchicalValidatorFixture) +{ + BOOST_CHECK_EQUAL(this->policy.m_isConfigured, false); + this->policy.load(R"CONF( + rule + { + id test-rule-data-id + for data + filter + { + type name + name /foo/bar + relation is-prefix-of + } + checker + { + type hierarchical + sig-type rsa-sha256 + } + } + rule + { + id test-rule-interest-id + for interest + filter + { + type name + name /foo/bar + relation is-prefix-of + } + checker + { + type hierarchical + sig-type rsa-sha256 + } + } + trust-anchor + { + type dir + dir keys + refresh 1h + } + )CONF", "test-config"); + BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true); + BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, false); + BOOST_CHECK_EQUAL(this->policy.m_dataRules.size(), 1); + BOOST_CHECK_EQUAL(this->policy.m_interestRules.size(), 1); + + this->policy.load(R"CONF( + trust-anchor + { + type any + } + )CONF", "test-config"); + BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true); + BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, true); + BOOST_CHECK_EQUAL(this->policy.m_dataRules.size(), 0); + BOOST_CHECK_EQUAL(this->policy.m_interestRules.size(), 0); +} + +using Packets = boost::mpl::vector; + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(TrustAnchorWildcard, Packet, Packets, ValidationPolicyConfigFixture) +{ + this->policy.load(R"CONF( + trust-anchor + { + type any + } + )CONF", "test-config"); + + BOOST_CHECK_EQUAL(this->policy.m_isConfigured, true); + BOOST_CHECK_EQUAL(this->policy.m_shouldBypass, true); + BOOST_CHECK_EQUAL(this->policy.m_dataRules.size(), 0); + BOOST_CHECK_EQUAL(this->policy.m_interestRules.size(), 0); + + Packet unsignedPacket("/Security/V2/ValidatorFixture/Sub1/Sub2/Packet"); + + Packet packet = unsignedPacket; + VALIDATE_SUCCESS(packet, "Policy should accept everything"); + + packet = unsignedPacket; + this->m_keyChain.sign(packet, signingWithSha256()); + VALIDATE_SUCCESS(packet, "Policy should accept everything"); + + packet = unsignedPacket; + this->m_keyChain.sign(packet, signingByIdentity(this->identity)); + VALIDATE_SUCCESS(packet, "Policy should accept everything"); + + packet = unsignedPacket; + this->m_keyChain.sign(packet, signingByIdentity(this->subIdentity)); + VALIDATE_SUCCESS(packet, "Policy should accept everything"); + + packet = unsignedPacket; + this->m_keyChain.sign(packet, signingByIdentity(this->otherIdentity)); + VALIDATE_SUCCESS(packet, "Policy should accept everything"); + + packet = unsignedPacket; + this->m_keyChain.sign(packet, signingByIdentity(this->subSelfSignedIdentity)); + VALIDATE_SUCCESS(packet, "Policy should accept everything"); +} + +using RefreshPolicies = boost::mpl::vector; + +template +class RefreshPolicyFixture : public LoadStringWithDirAnchor +{ +}; + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(ValidateRefresh, Refresh, RefreshPolicies, RefreshPolicyFixture) +{ + using Packet = Data; + Packet unsignedPacket("/Security/V2/ValidatorFixture/Sub1/Sub2/Packet"); + + boost::filesystem::remove(this->path / "keys" / "identity.ndncert"); + this->advanceClocks(Refresh::getRefreshTime(), 3); + + Packet packet = unsignedPacket; + this->m_keyChain.sign(packet, signingByIdentity(this->identity)); + VALIDATE_FAILURE(packet, "Should fail, as the trust anchor should no longer exist"); + + packet = unsignedPacket; + this->m_keyChain.sign(packet, signingByIdentity(this->subIdentity)); + VALIDATE_FAILURE(packet, "Should fail, as the trust anchor should no longer exist"); +} + +BOOST_FIXTURE_TEST_CASE(OrphanedPolicyLoad, HierarchicalValidatorFixture) // Bug #4758 +{ + ValidationPolicyConfig policy1; + BOOST_CHECK_THROW(policy1.load("trust-anchor { type any }", "test-config"), Error); + + // Reloading would have triggered a segfault + BOOST_CHECK_THROW(policy1.load("trust-anchor { type any }", "test-config"), Error); + + ValidationPolicyConfig policy2; + + std::string config = R"CONF( + trust-anchor + { + type dir + dir keys + refresh 1h + } + )CONF"; + + // Inserting trust anchor would have triggered a segfault + BOOST_CHECK_THROW(policy2.load(config, "test-config"), Error); +} + +BOOST_AUTO_TEST_SUITE_END() // TestValidationPolicyConfig +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace validator_config +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/validation-policy-simple-hierarchy.t.cpp b/tests/unit/security/v2/validation-policy-simple-hierarchy.t.cpp new file mode 100644 index 000000000..96f936e0e --- /dev/null +++ b/tests/unit/security/v2/validation-policy-simple-hierarchy.t.cpp @@ -0,0 +1,80 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validation-policy-simple-hierarchy.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/v2/validator-fixture.hpp" + +#include + +namespace ndn { +namespace security { +namespace v2 { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) +BOOST_FIXTURE_TEST_SUITE(TestValidationPolicySimpleHierarchy, + HierarchicalValidatorFixture) + +typedef boost::mpl::vector Packets; + +BOOST_AUTO_TEST_CASE_TEMPLATE(Validate, Packet, Packets) +{ + Packet unsignedPacket("/Security/V2/ValidatorFixture/Sub1/Sub2/Packet"); + + Packet packet = unsignedPacket; + VALIDATE_FAILURE(packet, "Unsigned"); + + packet = unsignedPacket; + m_keyChain.sign(packet, signingWithSha256()); + VALIDATE_FAILURE(packet, "Policy doesn't accept Sha256Digest signature"); + + packet = unsignedPacket; + m_keyChain.sign(packet, signingByIdentity(identity)); + VALIDATE_SUCCESS(packet, "Should get accepted, as signed by the anchor"); + + packet = unsignedPacket; + m_keyChain.sign(packet, signingByIdentity(subIdentity)); + VALIDATE_SUCCESS(packet, "Should get accepted, as signed by the policy-compliant cert"); + + packet = unsignedPacket; + m_keyChain.sign(packet, signingByIdentity(otherIdentity)); + VALIDATE_FAILURE(packet, "Should fail, as signed by the policy-violating cert"); + + packet = unsignedPacket; + m_keyChain.sign(packet, signingByIdentity(subSelfSignedIdentity)); + VALIDATE_FAILURE(packet, "Should fail, because subSelfSignedIdentity is not a trust anchor"); + + // TODO add checks with malformed packets +} + +BOOST_AUTO_TEST_SUITE_END() // TestValidator +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/validator-config/checker.t.cpp b/tests/unit/security/v2/validator-config/checker.t.cpp new file mode 100644 index 000000000..675ec2308 --- /dev/null +++ b/tests/unit/security/v2/validator-config/checker.t.cpp @@ -0,0 +1,368 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validator-config/checker.hpp" +#include "ndn-cxx/security/command-interest-signer.hpp" +#include "ndn-cxx/security/v2/validation-policy.hpp" +#include "ndn-cxx/security/v2/validation-state.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/v2/validator-fixture.hpp" +#include "tests/unit/security/v2/validator-config/common.hpp" + +namespace ndn { +namespace security { +namespace v2 { +namespace validator_config { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) +BOOST_AUTO_TEST_SUITE(ValidatorConfig) + +class CheckerFixture : public IdentityManagementFixture +{ +public: + CheckerFixture() + { + names.push_back("/foo/bar"); + names.push_back("/foo/bar/bar"); + names.push_back("/foo"); + names.push_back("/other/prefix"); + } + + static Name + makeSignedInterestName(const Name& name) + { + return Name(name).append("SignatureInfo").append("SignatureValue"); + } + + static Name + makeKeyLocatorName(const Name& name) + { + return Name(name).append("KEY").append("v=1"); + } + +public: + std::vector names; +}; + +BOOST_FIXTURE_TEST_SUITE(TestChecker, CheckerFixture) + +class NameRelationEqual : public CheckerFixture +{ +public: + NameRelationEqual() + : checker("/foo/bar", NameRelation::EQUAL) + { + } + +public: + NameRelationChecker checker; + std::vector> outcomes = {{true, false, false, false}, + {true, false, false, false}, + {true, false, false, false}, + {true, false, false, false}}; +}; + +class NameRelationIsPrefixOf : public CheckerFixture +{ +public: + NameRelationIsPrefixOf() + : checker("/foo/bar", NameRelation::IS_PREFIX_OF) + { + } + +public: + NameRelationChecker checker; + std::vector> outcomes = {{true, true, false, false}, + {true, true, false, false}, + {true, true, false, false}, + {true, true, false, false}}; +}; + +class NameRelationIsStrictPrefixOf : public CheckerFixture +{ +public: + NameRelationIsStrictPrefixOf() + : checker("/foo/bar", NameRelation::IS_STRICT_PREFIX_OF) + { + } + +public: + NameRelationChecker checker; + std::vector> outcomes = {{false, true, false, false}, + {false, true, false, false}, + {false, true, false, false}, + {false, true, false, false}}; +}; + +class RegexEqual : public CheckerFixture +{ +public: + RegexEqual() + : checker(Regex("^<>$")) + { + } + +public: + RegexChecker checker; + std::vector> outcomes = {{true, false, false, false}, + {true, false, false, false}, + {true, false, false, false}, + {true, false, false, false}}; +}; + +class RegexIsPrefixOf : public CheckerFixture +{ +public: + RegexIsPrefixOf() + : checker(Regex("^<>*<>$")) + { + } + +public: + RegexChecker checker; + std::vector> outcomes = {{true, true, false, false}, + {true, true, false, false}, + {true, true, false, false}, + {true, true, false, false}}; +}; + +class RegexIsStrictPrefixOf : public CheckerFixture +{ +public: + RegexIsStrictPrefixOf() + : checker(Regex("^<>+<>$")) + { + } + +public: + RegexChecker checker; + std::vector> outcomes = {{false, true, false, false}, + {false, true, false, false}, + {false, true, false, false}, + {false, true, false, false}}; +}; + +class HyperRelationEqual : public CheckerFixture +{ +public: + HyperRelationEqual() + : checker("^(<>+)$", "\\1", "^(<>+)<>$", "\\1", NameRelation::EQUAL) + { + } + +public: + HyperRelationChecker checker; + std::vector> outcomes = {{true, false, false, false}, + {false, true, false, false}, + {false, false, true, false}, + {false, false, false, true}}; +}; + +class HyperRelationIsPrefixOf : public CheckerFixture +{ +public: + HyperRelationIsPrefixOf() + : checker("^(<>+)$", "\\1", "^(<>+)<>$", "\\1", NameRelation::IS_PREFIX_OF) + { + } + +public: + HyperRelationChecker checker; + std::vector> outcomes = {{true, false, true, false}, + {true, true, true, false}, + {false, false, true, false}, + {false, false, false, true}}; +}; + +class HyperRelationIsStrictPrefixOf : public CheckerFixture +{ +public: + HyperRelationIsStrictPrefixOf() + : checker("^(<>+)$", "\\1", "^(<>+)<>$", "\\1", NameRelation::IS_STRICT_PREFIX_OF) + { + } + +public: + HyperRelationChecker checker; + std::vector> outcomes = {{false, false, true, false}, + {true, false, true, false}, + {false, false, false, false}, + {false, false, false, false}}; +}; + +class Hierarchical : public CheckerFixture +{ +public: + Hierarchical() + : checkerPtr(Checker::create(makeSection(R"CONF( + type hierarchical + sig-type rsa-sha256 + )CONF"), "test-config")) + , checker(*checkerPtr) + { + } + +public: + std::unique_ptr checkerPtr; + Checker& checker; + + std::vector> outcomes = {{true, false, true, false}, + {true, true, true, false}, + {false, false, true, false}, + {false, false, false, true}}; +}; + +class CustomizedNameRelation : public CheckerFixture +{ +public: + CustomizedNameRelation() + : checkerPtr(Checker::create(makeSection(R"CONF( + type customized + sig-type rsa-sha256 + key-locator + { + type name + name /foo/bar + relation equal + } + )CONF"), "test-config")) + , checker(*checkerPtr) + { + } + +public: + std::unique_ptr checkerPtr; + Checker& checker; + + std::vector> outcomes = {{true, false, false, false}, + {true, false, false, false}, + {true, false, false, false}, + {true, false, false, false}}; +}; + +class CustomizedRegex : public CheckerFixture +{ +public: + CustomizedRegex() + : checkerPtr(Checker::create(makeSection(R"CONF( + type customized + sig-type rsa-sha256 + key-locator + { + type name + regex ^<>$ + } + )CONF"), "test-config")) + , checker(*checkerPtr) + { + } + +public: + std::unique_ptr checkerPtr; + Checker& checker; + + std::vector> outcomes = {{true, false, false, false}, + {true, false, false, false}, + {true, false, false, false}, + {true, false, false, false}}; +}; + +class CustomizedHyperRelation : public CheckerFixture +{ +public: + CustomizedHyperRelation() + : checkerPtr(Checker::create(makeSection(R"CONF( + type customized + sig-type rsa-sha256 + key-locator + { + type name + hyper-relation + { + k-regex ^(<>+)<>$ + k-expand \\1 + h-relation is-prefix-of + p-regex ^(<>+)$ + p-expand \\1 + } + } + )CONF"), "test-config")) + , checker(*checkerPtr) + { + } + +public: + std::unique_ptr checkerPtr; + Checker& checker; + + std::vector> outcomes = {{true, false, true, false}, + {true, true, true, false}, + {false, false, true, false}, + {false, false, false, true}}; +}; + +using Tests = boost::mpl::vector; + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(Checks, T, Tests, T) +{ + using namespace ndn::security::v2::tests; + + BOOST_REQUIRE_EQUAL(this->outcomes.size(), this->names.size()); + for (size_t i = 0; i < this->names.size(); ++i) { + BOOST_REQUIRE_EQUAL(this->outcomes[i].size(), this->names.size()); + for (size_t j = 0; j < this->names.size(); ++j) { + const Name& pktName = this->names[i]; + Name klName = this->makeKeyLocatorName(this->names[j]); + bool expectedOutcome = this->outcomes[i][j]; + + auto dataState = make_shared(); + BOOST_CHECK_EQUAL(this->checker.check(tlv::Data, pktName, klName, dataState), expectedOutcome); + BOOST_CHECK_EQUAL(boost::logic::indeterminate(dataState->getOutcome()), expectedOutcome); + BOOST_CHECK_EQUAL(bool(dataState->getOutcome()), false); + + auto interestState = make_shared(); + BOOST_CHECK_EQUAL(this->checker.check(tlv::Interest, this->makeSignedInterestName(pktName), + klName, interestState), expectedOutcome); + BOOST_CHECK_EQUAL(boost::logic::indeterminate(interestState->getOutcome()), expectedOutcome); + BOOST_CHECK_EQUAL(bool(interestState->getOutcome()), false); + } + } +} + +BOOST_AUTO_TEST_SUITE_END() // TestChecker +BOOST_AUTO_TEST_SUITE_END() // ValidatorConfig +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace validator_config +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/validator-config/common.hpp b/tests/unit/security/v2/validator-config/common.hpp new file mode 100644 index 000000000..1083eb5fd --- /dev/null +++ b/tests/unit/security/v2/validator-config/common.hpp @@ -0,0 +1,50 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TESTS_SECURITY_V2_VALIDATOR_CONFIG_COMMON_HPP +#define NDN_TESTS_SECURITY_V2_VALIDATOR_CONFIG_COMMON_HPP + +#include "ndn-cxx/security/v2/validator-config/common.hpp" + +#include + +namespace ndn { +namespace security { +namespace v2 { +namespace validator_config { +namespace tests { + +inline ConfigSection +makeSection(const std::string& config) +{ + std::istringstream inputStream(config); + ConfigSection section; + boost::property_tree::read_info(inputStream, section); + return section; +} + +} // namespace tests +} // namespace validator_config +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_TESTS_SECURITY_V2_VALIDATOR_CONFIG_COMMON_HPP diff --git a/tests/unit/security/v2/validator-config/filter.t.cpp b/tests/unit/security/v2/validator-config/filter.t.cpp new file mode 100644 index 000000000..d02d74575 --- /dev/null +++ b/tests/unit/security/v2/validator-config/filter.t.cpp @@ -0,0 +1,201 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validator-config/filter.hpp" +#include "ndn-cxx/security/command-interest-signer.hpp" + +#include "tests/boost-test.hpp" +#include "tests/identity-management-fixture.hpp" +#include "tests/unit/security/v2/validator-config/common.hpp" + +namespace ndn { +namespace security { +namespace v2 { +namespace validator_config { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) +BOOST_AUTO_TEST_SUITE(ValidatorConfig) + +class FilterFixture : public IdentityManagementFixture +{ +public: + Interest + makeSignedInterest(const Name& name) + { + Interest interest(name); + m_keyChain.sign(interest); + return interest; + } +}; + +BOOST_FIXTURE_TEST_SUITE(TestFilter, FilterFixture) + +#define CHECK_FOR_MATCHES(filter, same, longer, shorter, different) \ + BOOST_CHECK_EQUAL(filter.match(tlv::Interest, makeSignedInterest("/foo/bar").getName()), same); \ + BOOST_CHECK_EQUAL(filter.match(tlv::Data, Data("/foo/bar").getName()), same); \ + BOOST_CHECK_EQUAL(filter.match(tlv::Interest, makeSignedInterest("/foo/bar/bar").getName()), longer); \ + BOOST_CHECK_EQUAL(filter.match(tlv::Data, Data("/foo/bar/bar").getName()), longer); \ + BOOST_CHECK_EQUAL(filter.match(tlv::Interest, makeSignedInterest("/foo").getName()), shorter); \ + BOOST_CHECK_EQUAL(filter.match(tlv::Data, Data("/foo").getName()), shorter); \ + BOOST_CHECK_EQUAL(filter.match(tlv::Interest, makeSignedInterest("/other/prefix").getName()), different); \ + BOOST_CHECK_EQUAL(filter.match(tlv::Data, Data("/other/prefix").getName()), different); + +BOOST_AUTO_TEST_CASE(RelationName) +{ + RelationNameFilter f1("/foo/bar", NameRelation::EQUAL); + CHECK_FOR_MATCHES(f1, true, false, false, false); + + RelationNameFilter f2("/foo/bar", NameRelation::IS_PREFIX_OF); + CHECK_FOR_MATCHES(f2, true, true, false, false); + + RelationNameFilter f3("/foo/bar", NameRelation::IS_STRICT_PREFIX_OF); + CHECK_FOR_MATCHES(f3, false, true, false, false); +} + +BOOST_AUTO_TEST_CASE(RegexName) +{ + RegexNameFilter f1(Regex("^$")); + CHECK_FOR_MATCHES(f1, true, false, false, false); + + RegexNameFilter f2(Regex("^<>*$")); + CHECK_FOR_MATCHES(f2, true, true, false, false); + + RegexNameFilter f3(Regex("^<>+$")); + CHECK_FOR_MATCHES(f3, false, true, false, false); +} + +BOOST_FIXTURE_TEST_SUITE(Create, FilterFixture) + +BOOST_AUTO_TEST_CASE(Errors) +{ + BOOST_CHECK_THROW(Filter::create(makeSection(""), "test-config"), Error); + BOOST_CHECK_THROW(Filter::create(makeSection("type unknown"), "test-config"), Error); + BOOST_CHECK_THROW(Filter::create(makeSection("type name"), "test-config"), Error); + + std::string config = R"CONF( + type name + not-name-or-regex stuff + )CONF"; + BOOST_CHECK_THROW(Filter::create(makeSection(config), "test-config"), Error); + + config = R"CONF( + type name + name /foo/bar + )CONF"; + BOOST_CHECK_THROW(Filter::create(makeSection(config), "test-config"), Error); + + config = R"CONF( + type name + name /foo/bar + not-relation stuff + )CONF"; + BOOST_CHECK_THROW(Filter::create(makeSection(config), "test-config"), Error); + + config = R"CONF( + type name + name /foo/bar + relation equal + not-end stuff + )CONF"; + BOOST_CHECK_THROW(Filter::create(makeSection(config), "test-config"), Error); + + config = R"CONF( + type name + regex ^$ + not-end stuff + )CONF"; + BOOST_CHECK_THROW(Filter::create(makeSection(config), "test-config"), Error); +} + +BOOST_AUTO_TEST_CASE(NameFilter) +{ + std::string config = R"CONF( + type name + name /foo/bar + relation equal + )CONF"; + auto f1 = Filter::create(makeSection(config), "test-config"); + CHECK_FOR_MATCHES((*f1), true, false, false, false); + + config = R"CONF( + type name + name /foo/bar + relation is-prefix-of + )CONF"; + auto f2 = Filter::create(makeSection(config), "test-config"); + CHECK_FOR_MATCHES((*f2), true, true, false, false); + + config = R"CONF( + type name + name /foo/bar + relation is-strict-prefix-of + )CONF"; + auto f3 = Filter::create(makeSection(config), "test-config"); + CHECK_FOR_MATCHES((*f3), false, true, false, false); +} + +BOOST_AUTO_TEST_CASE(RegexFilter) +{ + std::string config = R"CONF( + type name + regex ^$ + )CONF"; + auto f1 = Filter::create(makeSection(config), "test-config"); + CHECK_FOR_MATCHES((*f1), true, false, false, false); + + config = R"CONF( + type name + regex ^<>*$ + )CONF"; + auto f2 = Filter::create(makeSection(config), "test-config"); + CHECK_FOR_MATCHES((*f2), true, true, false, false); + + config = R"CONF( + type name + regex ^<>+$ + )CONF"; + auto f3 = Filter::create(makeSection(config), "test-config"); + CHECK_FOR_MATCHES((*f3), false, true, false, false); + + config = R"CONF( + type name + regex ^<>*$ + )CONF"; + auto f4 = Filter::create(makeSection(config), "test-config"); + CHECK_FOR_MATCHES((*f4), true, true, true, true); +} + +BOOST_AUTO_TEST_SUITE_END() // Create + +BOOST_AUTO_TEST_SUITE_END() // TestFilter +BOOST_AUTO_TEST_SUITE_END() // ValidatorConfig +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace validator_config +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/validator-config/name-relation.t.cpp b/tests/unit/security/v2/validator-config/name-relation.t.cpp new file mode 100644 index 000000000..ff23348a5 --- /dev/null +++ b/tests/unit/security/v2/validator-config/name-relation.t.cpp @@ -0,0 +1,79 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validator-config/name-relation.hpp" + +#include "tests/boost-test.hpp" + +#include + +namespace ndn { +namespace security { +namespace v2 { +namespace validator_config { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) +BOOST_AUTO_TEST_SUITE(ValidatorConfig) +BOOST_AUTO_TEST_SUITE(TestNameRelation) + +BOOST_AUTO_TEST_CASE(ToString) +{ + BOOST_CHECK_EQUAL(boost::lexical_cast(NameRelation::EQUAL), "equal"); + BOOST_CHECK_EQUAL(boost::lexical_cast(NameRelation::IS_PREFIX_OF), + "is-prefix-of"); + BOOST_CHECK_EQUAL(boost::lexical_cast(NameRelation::IS_STRICT_PREFIX_OF), + "is-strict-prefix-of"); +} + +BOOST_AUTO_TEST_CASE(FromString) +{ + BOOST_CHECK_EQUAL(getNameRelationFromString("equal"), NameRelation::EQUAL); + BOOST_CHECK_EQUAL(getNameRelationFromString("is-prefix-of"), NameRelation::IS_PREFIX_OF); + BOOST_CHECK_EQUAL(getNameRelationFromString("is-strict-prefix-of"), NameRelation::IS_STRICT_PREFIX_OF); + BOOST_CHECK_THROW(getNameRelationFromString("unknown"), validator_config::Error); +} + +BOOST_AUTO_TEST_CASE(CheckRelation) +{ + BOOST_CHECK(checkNameRelation(NameRelation::EQUAL, "/prefix", "/prefix")); + BOOST_CHECK(!checkNameRelation(NameRelation::EQUAL, "/prefix", "/prefix/other")); + + BOOST_CHECK(checkNameRelation(NameRelation::IS_PREFIX_OF, "/prefix", "/prefix")); + BOOST_CHECK(checkNameRelation(NameRelation::IS_PREFIX_OF, "/prefix", "/prefix/other")); + BOOST_CHECK(!checkNameRelation(NameRelation::IS_PREFIX_OF, "/prefix/other", "/prefix")); + + BOOST_CHECK(!checkNameRelation(NameRelation::IS_STRICT_PREFIX_OF, "/prefix", "/prefix")); + BOOST_CHECK(checkNameRelation(NameRelation::IS_STRICT_PREFIX_OF, "/prefix", "/prefix/other")); + BOOST_CHECK(!checkNameRelation(NameRelation::IS_STRICT_PREFIX_OF, "/prefix/other", "/prefix")); +} + +BOOST_AUTO_TEST_SUITE_END() // TestNameRelation +BOOST_AUTO_TEST_SUITE_END() // ValidatorConfig +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace validator_config +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/validator-config/rule.t.cpp b/tests/unit/security/v2/validator-config/rule.t.cpp new file mode 100644 index 000000000..558ffb45d --- /dev/null +++ b/tests/unit/security/v2/validator-config/rule.t.cpp @@ -0,0 +1,208 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validator-config/rule.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/v2/validator-fixture.hpp" +#include "tests/unit/security/v2/validator-config/common.hpp" + +#include + +namespace ndn { +namespace security { +namespace v2 { +namespace validator_config { +namespace tests { + +using namespace ndn::tests; +using namespace ndn::security::v2::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) +BOOST_AUTO_TEST_SUITE(ValidatorConfig) + +template +class RuleFixture : public IdentityManagementFixture +{ +public: + RuleFixture() + : rule(ruleId, PktType) + , pktName("/foo/bar") + { + if (PktType == tlv::Interest) { + pktName = Name("/foo/bar/SigInfo/SigValue"); + } + } + +public: + const std::string ruleId = "rule-id"; + Rule rule; + Name pktName; +}; + +using PktTypes = boost::mpl::vector_c; + +BOOST_AUTO_TEST_SUITE(TestRule) + +BOOST_FIXTURE_TEST_CASE(Errors, RuleFixture) +{ + BOOST_CHECK_THROW(rule.match(tlv::Interest, this->pktName), Error); + + auto state = make_shared(); + BOOST_CHECK_THROW(rule.check(tlv::Interest, this->pktName, "/foo/bar", state), Error); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(Constructor, PktType, PktTypes, RuleFixture) +{ + BOOST_CHECK_EQUAL(this->rule.getId(), this->ruleId); + BOOST_CHECK_EQUAL(this->rule.getPktType(), PktType::value); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(EmptyRule, PktType, PktTypes, RuleFixture) +{ + BOOST_CHECK_EQUAL(this->rule.match(PktType::value, this->pktName), true); + + auto state = make_shared(); + BOOST_CHECK_EQUAL(this->rule.check(PktType::value, this->pktName, "/foo/bar", state), false); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(Filters, PktType, PktTypes, RuleFixture) +{ + this->rule.addFilter(make_unique(Regex("^$"))); + + BOOST_CHECK_EQUAL(this->rule.match(PktType::value, this->pktName), true); + BOOST_CHECK_EQUAL(this->rule.match(PktType::value, "/not" + this->pktName.toUri()), false); + + this->rule.addFilter(make_unique(Regex("^$"))); + + BOOST_CHECK_EQUAL(this->rule.match(PktType::value, this->pktName), true); + BOOST_CHECK_EQUAL(this->rule.match(PktType::value, "/not" + this->pktName.toUri()), true); + + auto state = make_shared(); + BOOST_CHECK_EQUAL(this->rule.check(PktType::value, this->pktName, "/foo/bar", state), false); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(Checkers, PktType, PktTypes, RuleFixture) +{ + this->rule.addChecker(make_unique("^(<>+)$", "\\1", + "^?(<>+)$", "\\1", + NameRelation::EQUAL)); + + auto state = make_shared(); + BOOST_CHECK_EQUAL(this->rule.check(PktType::value, this->pktName, "/foo/bar", state), true); + + state = make_shared(); + BOOST_CHECK_EQUAL(this->rule.check(PktType::value, this->pktName, "/not/foo/bar", state), true); + + this->rule.addChecker(make_unique("^(<>+)$", "\\1", + "^(<>+)$", "\\1", + NameRelation::EQUAL)); + state = make_shared(); + BOOST_CHECK_EQUAL(this->rule.check(PktType::value, this->pktName, "/foo/bar", state), true); + + state = make_shared(); + BOOST_CHECK_EQUAL(this->rule.check(PktType::value, this->pktName, "/not/foo/bar", state), false); +} + +BOOST_AUTO_TEST_SUITE(Create) + +BOOST_AUTO_TEST_CASE(Errors) +{ + BOOST_CHECK_THROW(Rule::create(makeSection(""), "test-config"), Error); + + std::string config = R"CONF( + id rule-id + for something + )CONF"; + BOOST_CHECK_THROW(Rule::create(makeSection(config), "test-config"), Error); + + config = R"CONF( + id rule-id + for data + )CONF"; + BOOST_CHECK_THROW(Rule::create(makeSection(config), "test-config"), Error); // at least one checker required + + config = R"CONF( + id rule-id + for data + checker + { + type hierarchical + sig-type rsa-sha256 + } + other stuff + )CONF"; + BOOST_CHECK_THROW(Rule::create(makeSection(config), "test-config"), Error); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(FilterAndChecker, PktType, PktTypes, RuleFixture) +{ + std::string config = R"CONF( + id rule-id + for )CONF" + (PktType::value == tlv::Data ? "data"s : "interest"s) + R"CONF( + filter + { + type name + regex ^$ + } + checker + { + type customized + sig-type rsa-sha256 + key-locator + { + type name + hyper-relation + { + k-regex ^(<>+)$ + k-expand \\1 + h-relation equal + p-regex ^(<>+)$ + p-expand \\1 + } + } + } + )CONF"; + auto rule = Rule::create(makeSection(config), "test-config"); + + BOOST_CHECK_EQUAL(rule->match(PktType::value, this->pktName), true); + BOOST_CHECK_EQUAL(rule->match(PktType::value, "/not" + this->pktName.toUri()), false); + + auto state = make_shared(); + BOOST_CHECK_EQUAL(rule->check(PktType::value, this->pktName, "/foo/bar", state), true); + + state = make_shared(); + BOOST_CHECK_EQUAL(rule->check(PktType::value, this->pktName, "/not/foo/bar", state), false); +} + +BOOST_AUTO_TEST_SUITE_END() // Create + +BOOST_AUTO_TEST_SUITE_END() // TestRule +BOOST_AUTO_TEST_SUITE_END() // ValidatorConfig +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace validator_config +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/v2/validator-fixture.hpp b/tests/unit/security/v2/validator-fixture.hpp new file mode 100644 index 000000000..e5079bc9c --- /dev/null +++ b/tests/unit/security/v2/validator-fixture.hpp @@ -0,0 +1,187 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TESTS_UNIT_SECURITY_V2_VALIDATOR_FIXTURE_HPP +#define NDN_TESTS_UNIT_SECURITY_V2_VALIDATOR_FIXTURE_HPP + +#include "ndn-cxx/security/v2/validator.hpp" +#include "ndn-cxx/security/v2/certificate-fetcher-from-network.hpp" +#include "ndn-cxx/util/dummy-client-face.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/identity-management-time-fixture.hpp" + +#include + +namespace ndn { +namespace security { +namespace v2 { +namespace tests { + +template +class ValidatorFixture : public ndn::tests::IdentityManagementTimeFixture +{ +public: + ValidatorFixture() + : face(io, {true, true}) + , validator(make_unique(), make_unique(face)) + , policy(static_cast(validator.getPolicy())) + , cache(100_days) + , lastError(ValidationError::Code::NO_ERROR) + { + processInterest = [this] (const Interest& interest) { + auto cert = cache.find(interest); + if (cert != nullptr) { + face.receive(*cert); + } + }; + } + + virtual + ~ValidatorFixture() = default; + + template + void + validate(const Packet& packet, const std::string& msg, bool expectSuccess, int line) + { + std::string detailedInfo = msg + " on line " + to_string(line); + size_t nCallbacks = 0; + this->validator.validate(packet, + [&] (const Packet&) { + ++nCallbacks; + BOOST_CHECK_MESSAGE(expectSuccess, + (expectSuccess ? "OK: " : "FAILED: ") + detailedInfo); + }, + [&] (const Packet&, const ValidationError& error) { + lastError = error; + ++nCallbacks; + BOOST_CHECK_MESSAGE(!expectSuccess, + (!expectSuccess ? "OK: " : "FAILED: ") + detailedInfo + + (expectSuccess ? " (" + boost::lexical_cast(error) + ")" : "")); + }); + + mockNetworkOperations(); + BOOST_CHECK_EQUAL(nCallbacks, 1); + } + + void + mockNetworkOperations() + { + util::signal::ScopedConnection connection = face.onSendInterest.connect([this] (const Interest& interest) { + if (processInterest != nullptr) { + io.post(bind(processInterest, interest)); + } + }); + advanceClocks(time::milliseconds(s_mockPeriod), s_mockTimes); + } + + /** \brief undo clock advancement of mockNetworkOperations + */ + void + rewindClockAfterValidation() + { + this->systemClock->advance(time::milliseconds(s_mockPeriod * s_mockTimes * -1)); + } + +public: + util::DummyClientFace face; + std::function processInterest; + Validator validator; + ValidationPolicy& policy; + + CertificateCache cache; + ValidationError lastError; + +private: + const static int s_mockPeriod; + const static int s_mockTimes; +}; + +template +const int ValidatorFixture::s_mockPeriod = 250; + +template +const int ValidatorFixture::s_mockTimes = 200; + +template +class HierarchicalValidatorFixture : public ValidatorFixture +{ +public: + HierarchicalValidatorFixture() + { + identity = this->addIdentity("/Security/V2/ValidatorFixture"); + subIdentity = this->addSubCertificate("/Security/V2/ValidatorFixture/Sub1", identity); + subSelfSignedIdentity = this->addIdentity("/Security/V2/ValidatorFixture/Sub1/Sub2"); + otherIdentity = this->addIdentity("/Security/V2/OtherIdentity"); + + this->validator.loadAnchor("", Certificate(identity.getDefaultKey().getDefaultCertificate())); + + this->cache.insert(identity.getDefaultKey().getDefaultCertificate()); + this->cache.insert(subIdentity.getDefaultKey().getDefaultCertificate()); + this->cache.insert(subSelfSignedIdentity.getDefaultKey().getDefaultCertificate()); + this->cache.insert(otherIdentity.getDefaultKey().getDefaultCertificate()); + } + +public: + Identity identity; + Identity subIdentity; + Identity subSelfSignedIdentity; + Identity otherIdentity; +}; + +#define VALIDATE_SUCCESS(packet, message) this->template validate(packet, message, true, __LINE__) +#define VALIDATE_FAILURE(packet, message) this->template validate(packet, message, false, __LINE__) + +class DummyValidationState : public ValidationState +{ +public: + ~DummyValidationState() + { + m_outcome = false; + } + + void + fail(const ValidationError& error) override + { + // BOOST_TEST_MESSAGE(error); + m_outcome = false; + } + +private: + void + verifyOriginalPacket(const Certificate& trustedCert) override + { + // do nothing + } + + void + bypassValidation() override + { + // do nothing + } +}; + +} // namespace tests +} // namespace v2 +} // namespace security +} // namespace ndn + +#endif // NDN_TESTS_UNIT_SECURITY_V2_VALIDATOR_FIXTURE_HPP diff --git a/tests/unit/security/v2/validator.t.cpp b/tests/unit/security/v2/validator.t.cpp new file mode 100644 index 000000000..934492f56 --- /dev/null +++ b/tests/unit/security/v2/validator.t.cpp @@ -0,0 +1,344 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/v2/validator.hpp" +#include "ndn-cxx/security/v2/validation-policy-simple-hierarchy.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/security/v2/validator-fixture.hpp" + +namespace ndn { +namespace security { +namespace v2 { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(V2) +BOOST_FIXTURE_TEST_SUITE(TestValidator, HierarchicalValidatorFixture) + +BOOST_AUTO_TEST_CASE(ConstructorSetValidator) +{ + auto middlePolicy = make_unique(); + auto innerPolicy = make_unique(); + + validator.getPolicy().setInnerPolicy(std::move(middlePolicy)); + validator.getPolicy().setInnerPolicy(std::move(innerPolicy)); + + BOOST_CHECK(validator.getPolicy().m_validator != nullptr); + BOOST_CHECK(validator.getPolicy().getInnerPolicy().m_validator != nullptr); + BOOST_CHECK(validator.getPolicy().getInnerPolicy().getInnerPolicy().m_validator != nullptr); +} + +BOOST_AUTO_TEST_CASE(Timeouts) +{ + processInterest = nullptr; // no response for all interests + + Data data("/Security/V2/ValidatorFixture/Sub1/Sub2/Data"); + m_keyChain.sign(data, signingByIdentity(subIdentity)); + + VALIDATE_FAILURE(data, "Should fail to retrieve certificate"); + BOOST_CHECK_GT(face.sentInterests.size(), 1); +} + +BOOST_AUTO_TEST_CASE(NackedInterests) +{ + processInterest = [this] (const Interest& interest) { + lp::Nack nack(interest); + nack.setReason(lp::NackReason::NO_ROUTE); + face.receive(nack); + }; + + Data data("/Security/V2/ValidatorFixture/Sub1/Sub2/Data"); + m_keyChain.sign(data, signingByIdentity(subIdentity)); + + VALIDATE_FAILURE(data, "All interests should get NACKed"); + // 1 for the first interest, 3 for the retries on nack + BOOST_CHECK_EQUAL(face.sentInterests.size(), 4); +} + +BOOST_AUTO_TEST_CASE(MalformedCert) +{ + Data malformedCert = subIdentity.getDefaultKey().getDefaultCertificate(); + malformedCert.setContentType(tlv::ContentType_Blob); + m_keyChain.sign(malformedCert, signingByIdentity(identity)); + // wrong content type & missing ValidityPeriod + BOOST_REQUIRE_THROW(Certificate(malformedCert.wireEncode()), tlv::Error); + + auto originalProcessInterest = processInterest; + processInterest = [this, &originalProcessInterest, &malformedCert] (const Interest& interest) { + if (interest.getName().isPrefixOf(malformedCert.getName())) { + face.receive(malformedCert); + } + else { + originalProcessInterest(interest); + } + }; + + Data data("/Security/V2/ValidatorFixture/Sub1/Sub2/Data"); + m_keyChain.sign(data, signingByIdentity(subIdentity)); + + VALIDATE_FAILURE(data, "Signed by a malformed certificate"); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); +} + +BOOST_AUTO_TEST_CASE(ExpiredCert) +{ + Data expiredCert = subIdentity.getDefaultKey().getDefaultCertificate(); + SignatureInfo info; + info.setValidityPeriod(ValidityPeriod(time::system_clock::now() - 2_h, + time::system_clock::now() - 1_h)); + m_keyChain.sign(expiredCert, signingByIdentity(identity).setSignatureInfo(info)); + BOOST_REQUIRE_NO_THROW(Certificate(expiredCert.wireEncode())); + + auto originalProcessInterest = processInterest; + processInterest = [this, &originalProcessInterest, &expiredCert] (const Interest& interest) { + if (interest.getName().isPrefixOf(expiredCert.getName())) { + face.receive(expiredCert); + } + else { + originalProcessInterest(interest); + } + }; + + Data data("/Security/V2/ValidatorFixture/Sub1/Sub2/Data"); + m_keyChain.sign(data, signingByIdentity(subIdentity)); + + VALIDATE_FAILURE(data, "Signed by an expired certificate"); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); +} + +BOOST_AUTO_TEST_CASE(ResetAnchors) +{ + validator.resetAnchors(); + + Data data("/Security/V2/ValidatorFixture/Sub1/Sub2/Data"); + m_keyChain.sign(data, signingByIdentity(subIdentity)); + VALIDATE_FAILURE(data, "Should fail, as no anchors configured"); +} + +BOOST_AUTO_TEST_CASE(TrustedCertCaching) +{ + Data data("/Security/V2/ValidatorFixture/Sub1/Sub2/Data"); + m_keyChain.sign(data, signingByIdentity(subIdentity)); + + VALIDATE_SUCCESS(data, "Should get accepted, as signed by the policy-compliant cert"); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); + face.sentInterests.clear(); + + processInterest = nullptr; // disable data responses from mocked network + + VALIDATE_SUCCESS(data, "Should get accepted, based on the cached trusted cert"); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 0); + face.sentInterests.clear(); + + advanceClocks(1_h, 2); // expire trusted cache + + VALIDATE_FAILURE(data, "Should try and fail to retrieve certs"); + BOOST_CHECK_GT(face.sentInterests.size(), 1); + face.sentInterests.clear(); +} + +BOOST_AUTO_TEST_CASE(ResetVerifiedCertificates) +{ + Data data("/Security/V2/ValidatorFixture/Sub1/Sub2/Data"); + m_keyChain.sign(data, signingByIdentity(subIdentity)); + VALIDATE_SUCCESS(data, "Should get accepted, as signed by the policy-compliant cert"); + + // reset anchors + validator.resetAnchors(); + VALIDATE_SUCCESS(data, "Should get accepted, as signed by the cert in trusted cache"); + + // reset trusted cache + validator.resetVerifiedCertificates(); + VALIDATE_FAILURE(data, "Should fail, as no trusted cache or anchors"); +} + +BOOST_AUTO_TEST_CASE(UntrustedCertCaching) +{ + Data data("/Security/V2/ValidatorFixture/Sub1/Sub2/Data"); + m_keyChain.sign(data, signingByIdentity(subSelfSignedIdentity)); + + VALIDATE_FAILURE(data, "Should fail, as signed by the policy-violating cert"); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); + face.sentInterests.clear(); + + processInterest = nullptr; // disable data responses from mocked network + + VALIDATE_FAILURE(data, "Should fail again, but no network operations expected"); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 0); + face.sentInterests.clear(); + + advanceClocks(10_min, 2); // expire untrusted cache + + VALIDATE_FAILURE(data, "Should try and fail to retrieve certs"); + BOOST_CHECK_GT(face.sentInterests.size(), 1); + face.sentInterests.clear(); +} + +class ValidationPolicySimpleHierarchyForInterestOnly : public ValidationPolicySimpleHierarchy +{ +public: + void + checkPolicy(const Data& data, const shared_ptr& state, + const ValidationContinuation& continueValidation) override + { + continueValidation(nullptr, state); + } +}; + +BOOST_FIXTURE_TEST_CASE(ValidateInterestsButBypassForData, + HierarchicalValidatorFixture) +{ + Interest interest("/Security/V2/ValidatorFixture/Sub1/Sub2/Interest"); + Data data("/Security/V2/ValidatorFixture/Sub1/Sub2/Interest"); + + VALIDATE_FAILURE(interest, "Unsigned"); + VALIDATE_SUCCESS(data, "Policy requests validation bypassing for all data"); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 0); + face.sentInterests.clear(); + + interest = Interest("/Security/V2/ValidatorFixture/Sub1/Sub2/Interest"); + m_keyChain.sign(interest, signingWithSha256()); + m_keyChain.sign(data, signingWithSha256()); + VALIDATE_FAILURE(interest, "Required KeyLocator/Name missing (not passed to policy)"); + VALIDATE_SUCCESS(data, "Policy requests validation bypassing for all data"); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 0); + face.sentInterests.clear(); + + m_keyChain.sign(interest, signingByIdentity(identity)); + m_keyChain.sign(data, signingByIdentity(identity)); + VALIDATE_SUCCESS(interest, "Should get accepted, as signed by the anchor"); + VALIDATE_SUCCESS(data, "Policy requests validation bypassing for all data"); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 0); + face.sentInterests.clear(); + + m_keyChain.sign(interest, signingByIdentity(subIdentity)); + m_keyChain.sign(data, signingByIdentity(subIdentity)); + VALIDATE_FAILURE(interest, "Should fail, as policy is not allowed to create new trust anchors"); + VALIDATE_SUCCESS(data, "Policy requests validation bypassing for all data"); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); + face.sentInterests.clear(); + + m_keyChain.sign(interest, signingByIdentity(otherIdentity)); + m_keyChain.sign(data, signingByIdentity(otherIdentity)); + VALIDATE_FAILURE(interest, "Should fail, as signed by the policy-violating cert"); + VALIDATE_SUCCESS(data, "Policy requests validation bypassing for all data"); + // no network operations expected, as certificate is not validated by the policy + BOOST_CHECK_EQUAL(face.sentInterests.size(), 0); + face.sentInterests.clear(); + + advanceClocks(1_h, 2); // expire trusted cache + + m_keyChain.sign(interest, signingByIdentity(subSelfSignedIdentity)); + m_keyChain.sign(data, signingByIdentity(subSelfSignedIdentity)); + VALIDATE_FAILURE(interest, "Should fail, as policy is not allowed to create new trust anchors"); + VALIDATE_SUCCESS(data, "Policy requests validation bypassing for all data"); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); + face.sentInterests.clear(); +} + +BOOST_AUTO_TEST_CASE(InfiniteCertChain) +{ + processInterest = [this] (const Interest& interest) { + // create another key for the same identity and sign it properly + Key parentKey = m_keyChain.createKey(subIdentity); + Key requestedKey = subIdentity.getKey(interest.getName()); + + Name certificateName = requestedKey.getName(); + certificateName + .append("looper") + .appendVersion(); + v2::Certificate certificate; + certificate.setName(certificateName); + + // set metainfo + certificate.setContentType(tlv::ContentType_Key); + certificate.setFreshnessPeriod(1_h); + + // set content + certificate.setContent(requestedKey.getPublicKey().data(), requestedKey.getPublicKey().size()); + + // set signature-info + SignatureInfo info; + info.setValidityPeriod(security::ValidityPeriod(time::system_clock::now() - 10_days, + time::system_clock::now() + 10_days)); + + m_keyChain.sign(certificate, signingByKey(parentKey).setSignatureInfo(info)); + face.receive(certificate); + }; + + Data data("/Security/V2/ValidatorFixture/Sub1/Sub2/Data"); + m_keyChain.sign(data, signingByIdentity(subIdentity)); + + validator.setMaxDepth(40); + BOOST_CHECK_EQUAL(validator.getMaxDepth(), 40); + VALIDATE_FAILURE(data, "Should fail, as certificate should be looped"); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 40); + face.sentInterests.clear(); + + advanceClocks(1_h, 5); // expire caches + + validator.setMaxDepth(30); + BOOST_CHECK_EQUAL(validator.getMaxDepth(), 30); + VALIDATE_FAILURE(data, "Should fail, as certificate chain is infinite"); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 30); +} + +BOOST_AUTO_TEST_CASE(LoopedCertChain) +{ + auto s1 = addIdentity("/loop"); + auto k1 = m_keyChain.createKey(s1, RsaKeyParams(name::Component("key1"))); + auto k2 = m_keyChain.createKey(s1, RsaKeyParams(name::Component("key2"))); + auto k3 = m_keyChain.createKey(s1, RsaKeyParams(name::Component("key3"))); + + auto makeCert = [this] (Key& key, const Key& signer) { + v2::Certificate request = key.getDefaultCertificate(); + request.setName(Name(key.getName()).append("looper").appendVersion()); + + SignatureInfo info; + info.setValidityPeriod({time::system_clock::now() - 100_days, + time::system_clock::now() + 100_days}); + m_keyChain.sign(request, signingByKey(signer).setSignatureInfo(info)); + m_keyChain.addCertificate(key, request); + + cache.insert(request); + }; + + makeCert(k1, k2); + makeCert(k2, k3); + makeCert(k3, k1); + + Data data("/loop/Data"); + m_keyChain.sign(data, signingByKey(k1)); + VALIDATE_FAILURE(data, "Should fail, as certificate chain loops"); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 3); +} + +BOOST_AUTO_TEST_SUITE_END() // TestValidator +BOOST_AUTO_TEST_SUITE_END() // V2 +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace v2 +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/validator-config.t.cpp b/tests/unit/security/validator-config.t.cpp new file mode 100644 index 000000000..06e66b020 --- /dev/null +++ b/tests/unit/security/validator-config.t.cpp @@ -0,0 +1,159 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/validator-config.hpp" +#include "ndn-cxx/security/command-interest-signer.hpp" +#include "ndn-cxx/security/v2/certificate-fetcher-offline.hpp" +#include "ndn-cxx/util/dummy-client-face.hpp" + +#include "tests/boost-test.hpp" +#include "tests/identity-management-fixture.hpp" +#include "tests/unit/security/v2/validator-config/common.hpp" + +namespace ndn { +namespace security { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_FIXTURE_TEST_SUITE(TestValidatorConfig, IdentityManagementFixture) + +// This test only for API, actual tests are in ValidationPolicyConfig and corresponding CertificateFetchers + +BOOST_AUTO_TEST_CASE(Construct) +{ + util::DummyClientFace face; + + ValidatorConfig v1(face); + BOOST_CHECK_EQUAL(v1.m_policyConfig.m_isConfigured, false); + + ValidatorConfig v2(make_unique()); + BOOST_CHECK_EQUAL(v2.m_policyConfig.m_isConfigured, false); +} + +class ValidatorConfigFixture : public IdentityManagementFixture +{ +public: + ValidatorConfigFixture() + : path(boost::filesystem::path(UNIT_TEST_CONFIG_PATH) / "security" / "validator-config") + , validator(make_unique()) + { + boost::filesystem::create_directories(path); + config = R"CONF( + trust-anchor + { + type any + } + )CONF"; + configFile = (this->path / "config.conf").string(); + std::ofstream f(configFile.c_str()); + f << config; + } + + ~ValidatorConfigFixture() + { + boost::filesystem::remove_all(path); + } + +public: + const boost::filesystem::path path; + std::string config; + std::string configFile; + ValidatorConfig validator; +}; + +BOOST_FIXTURE_TEST_SUITE(Loads, ValidatorConfigFixture) + +BOOST_AUTO_TEST_CASE(FromFile) +{ + validator.load(configFile); + BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true); + + // should reload policy + validator.load(configFile); + BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true); +} + +BOOST_AUTO_TEST_CASE(FromString) +{ + validator.load(config, "config-file-from-string"); + BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true); + + // should reload policy + validator.load(config, "config-file-from-string"); + BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true); +} + +BOOST_AUTO_TEST_CASE(FromIstream) +{ + std::istringstream is(config); + validator.load(is, "config-file-from-istream"); + BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true); + + // should reload policy + std::istringstream is2(config); + validator.load(is2, "config-file-from-istream"); + BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true); +} + +BOOST_AUTO_TEST_CASE(FromSection) +{ + validator.load(v2::validator_config::tests::makeSection(config), "config-file-from-section"); + BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true); + + // should reload policy + validator.load(v2::validator_config::tests::makeSection(config), "config-file-from-section"); + BOOST_CHECK_EQUAL(validator.m_policyConfig.m_isConfigured, true); +} + +BOOST_AUTO_TEST_SUITE_END() // Loads + + +BOOST_FIXTURE_TEST_CASE(ValidateCommandInterestWithDigestSha256, ValidatorConfigFixture) // Bug 4635 +{ + validator.load(configFile); + + CommandInterestSigner signer(m_keyChain); + auto i = signer.makeCommandInterest("/hello/world/CMD", signingWithSha256()); + size_t nValidated = 0, nFailed = 0; + + validator.validate(i, [&] (auto&&...) { ++nValidated; }, [&] (auto&&...) { ++nFailed; }); + BOOST_CHECK_EQUAL(nValidated, 1); + BOOST_CHECK_EQUAL(nFailed, 0); + + validator.validate(i, [&] (auto&&...) { ++nValidated; }, [&] (auto&&...) { ++nFailed; }); + BOOST_CHECK_EQUAL(nValidated, 1); + BOOST_CHECK_EQUAL(nFailed, 1); + + i = signer.makeCommandInterest("/hello/world/CMD", signingWithSha256()); + validator.validate(i, [&] (auto&&...) { ++nValidated; }, [&] (auto&&...) { ++nFailed; }); + BOOST_CHECK_EQUAL(nValidated, 2); + BOOST_CHECK_EQUAL(nFailed, 1); +} + + +BOOST_AUTO_TEST_SUITE_END() // TestValidatorConfig +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace security +} // namespace ndn diff --git a/tests/unit/security/validator-null.t.cpp b/tests/unit/security/validator-null.t.cpp new file mode 100644 index 000000000..103f8f78d --- /dev/null +++ b/tests/unit/security/validator-null.t.cpp @@ -0,0 +1,66 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/validator-null.hpp" + +#include "tests/boost-test.hpp" +#include "tests/identity-management-fixture.hpp" +#include "tests/make-interest-data.hpp" + +namespace ndn { +namespace security { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_FIXTURE_TEST_SUITE(TestValidatorNull, IdentityManagementFixture) + +BOOST_AUTO_TEST_CASE(ValidateData) +{ + auto identity = addIdentity("/TestValidator/Null"); + Data data("/Some/Other/Data/Name"); + m_keyChain.sign(data, signingByIdentity(identity)); + + ValidatorNull validator; + validator.validate(data, + bind([] { BOOST_CHECK_MESSAGE(true, "Validation should succeed"); }), + bind([] { BOOST_CHECK_MESSAGE(false, "Validation should not have failed"); })); +} + +BOOST_AUTO_TEST_CASE(ValidateInterest) +{ + auto identity = addIdentity("/TestValidator/Null"); + Interest interest("/Some/Other/Interest/Name"); + m_keyChain.sign(interest, signingByIdentity(identity)); + + ValidatorNull validator; + validator.validate(interest, + bind([] { BOOST_CHECK_MESSAGE(true, "Validation should succeed"); }), + bind([] { BOOST_CHECK_MESSAGE(false, "Validation should not have failed"); })); +} + +BOOST_AUTO_TEST_SUITE_END() // TestValidatorNull +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace security +} // namespace ndn diff --git a/tests/unit-tests/security/validity-period.t.cpp b/tests/unit/security/validity-period.t.cpp similarity index 84% rename from tests/unit-tests/security/validity-period.t.cpp rename to tests/unit/security/validity-period.t.cpp index db22b9ecb..768e7742f 100644 --- a/tests/unit-tests/security/validity-period.t.cpp +++ b/tests/unit/security/validity-period.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,53 +19,60 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "security/validity-period.hpp" +#include "ndn-cxx/security/validity-period.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/unit-test-time-fixture.hpp" -#include "boost-test.hpp" #include namespace ndn { namespace security { -namespace test { +namespace tests { + +using namespace ndn::tests; BOOST_AUTO_TEST_SUITE(Security) BOOST_AUTO_TEST_SUITE(TestValidityPeriod) -BOOST_AUTO_TEST_CASE(ConstructorSetter) +BOOST_FIXTURE_TEST_CASE(ConstructorSetter, UnitTestTimeFixture) { - time::system_clock::TimePoint notBefore = time::system_clock::now() - time::days(1); - time::system_clock::TimePoint notAfter = notBefore + time::days(2); + time::system_clock::TimePoint now = this->systemClock->getNow(); + + time::system_clock::TimePoint notBefore = now - 1_day; + time::system_clock::TimePoint notAfter = notBefore + 2_days; ValidityPeriod validity1 = ValidityPeriod(notBefore, notAfter); auto period = validity1.getPeriod(); BOOST_CHECK_GE(period.first, notBefore); // fractional seconds will be removed - BOOST_CHECK_LT(period.first, notBefore + time::seconds(1)); + BOOST_CHECK_LT(period.first, notBefore + 1_s); BOOST_CHECK_LE(period.second, notAfter); // fractional seconds will be removed - BOOST_CHECK_GT(period.second, notAfter - time::seconds(1)); + BOOST_CHECK_GT(period.second, notAfter - 1_s); BOOST_CHECK_EQUAL(validity1.isValid(), true); - BOOST_CHECK_EQUAL(ValidityPeriod(time::system_clock::now() - time::days(2), - time::system_clock::now() - time::days(1)).isValid(), - false); + BOOST_CHECK_EQUAL(ValidityPeriod(now - 2_days, now - 1_day).isValid(), false); BOOST_CHECK_NO_THROW((ValidityPeriod())); ValidityPeriod validity2; - BOOST_CHECK(validity2.getPeriod() == std::make_pair(time::getUnixEpoch(), time::getUnixEpoch())); + BOOST_CHECK_EQUAL(validity2.isValid(), false); validity2.setPeriod(notBefore, notAfter); BOOST_CHECK(validity2.getPeriod() != std::make_pair(time::getUnixEpoch(), time::getUnixEpoch())); BOOST_CHECK_EQUAL(validity2, validity1); - validity1.setPeriod(time::getUnixEpoch(), time::getUnixEpoch() + time::days(10 * 365)); + validity1.setPeriod(time::getUnixEpoch(), time::getUnixEpoch() + 10 * 365_days); BOOST_CHECK_EQUAL(boost::lexical_cast(validity1), "(19700101T000000, 19791230T000000)"); - validity1.setPeriod(time::getUnixEpoch() + time::nanoseconds(1), - time::getUnixEpoch() + time::days(10 * 365) + time::nanoseconds(1)); + validity1.setPeriod(time::getUnixEpoch() + 1_ns, + time::getUnixEpoch() + (10 * 365_days) + 1_ns); BOOST_CHECK_EQUAL(boost::lexical_cast(validity1), "(19700101T000001, 19791230T000000)"); + + BOOST_CHECK_EQUAL(ValidityPeriod(now, now).isValid(), true); + BOOST_CHECK_EQUAL(ValidityPeriod(now + 1_s, now).isValid(), false); } const uint8_t VP1[] = { @@ -81,7 +88,7 @@ const uint8_t VP1[] = { BOOST_AUTO_TEST_CASE(EncodingDecoding) { time::system_clock::TimePoint notBefore = time::getUnixEpoch(); - time::system_clock::TimePoint notAfter = notBefore + time::days(1); + time::system_clock::TimePoint notAfter = notBefore + 1_day; ValidityPeriod v1(notBefore, notAfter); @@ -174,8 +181,8 @@ BOOST_AUTO_TEST_CASE(DecodingError) BOOST_AUTO_TEST_CASE(Comparison) { time::system_clock::TimePoint notBefore = time::getUnixEpoch(); - time::system_clock::TimePoint notAfter = notBefore + time::days(1); - time::system_clock::TimePoint notAfter2 = notBefore + time::days(2); + time::system_clock::TimePoint notAfter = notBefore + 1_day; + time::system_clock::TimePoint notAfter2 = notBefore + 2_days; ValidityPeriod validity1(notBefore, notAfter); ValidityPeriod validity2(notBefore, notAfter); @@ -188,6 +195,6 @@ BOOST_AUTO_TEST_CASE(Comparison) BOOST_AUTO_TEST_SUITE_END() // TestValidityPeriod BOOST_AUTO_TEST_SUITE_END() // Security -} // namespace test +} // namespace tests } // namespace security } // namespace ndn diff --git a/tests/unit/security/verification-helpers.t.cpp b/tests/unit/security/verification-helpers.t.cpp new file mode 100644 index 000000000..c0c6b5aa3 --- /dev/null +++ b/tests/unit/security/verification-helpers.t.cpp @@ -0,0 +1,523 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/security/verification-helpers.hpp" +#include "ndn-cxx/security/transform/public-key.hpp" +// #include "ndn-cxx/util/string-helper.hpp" + +#include "tests/boost-test.hpp" +#include "tests/identity-management-fixture.hpp" +#include "tests/make-interest-data.hpp" + +#include + +namespace ndn { +namespace security { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Security) +BOOST_AUTO_TEST_SUITE(TestVerificationHelpers) + +// // Using this test case to generate dataset if signature format changes +// BOOST_FIXTURE_TEST_CASE(Generator, IdentityManagementV2Fixture) +// { +// Identity wrongIdentity = addIdentity("/Security/TestVerificationHelpers/Wrong"); +// std::map identities = { +// {"Ecdsa", signingByIdentity(addIdentity("/Security/TestVerificationHelpers/EC", EcKeyParams()))}, +// {"Rsa", signingByIdentity(addIdentity("/Security/TestVerificationHelpers/RSA", RsaKeyParams()))}, +// {"Sha256", signingWithSha256()} +// }; + +// auto print = [] (const std::string& name, const uint8_t* buf, size_t size) { +// std::cout << " std::vector " + name + " = {\n "; + +// std::string hex = toHex(buf, size); + +// for (size_t i = 0; i < hex.size(); i++) { +// if (i > 0 && i % 32 == 0) +// std::cout << "\n "; + +// std::cout << "0x" << hex[i]; +// std::cout << hex[++i]; + +// if ((i + 1) != hex.size()) +// std::cout << ", "; +// } +// std::cout << "\n };"; +// }; + +// for (const auto& i : identities) { +// const std::string& type = i.first; +// const SigningInfo& signingInfo = i.second; + +// std::cout << "struct " + type + "Dataset\n{\n"; +// std::cout << " const std::string name = \"" << type << "\";\n"; + +// if (signingInfo.getSignerType() == SigningInfo::SIGNER_TYPE_ID) { +// print("cert", signingInfo.getPibIdentity().getDefaultKey().getDefaultCertificate().wireEncode().wire(), +// signingInfo.getPibIdentity().getDefaultKey().getDefaultCertificate().wireEncode().size()); +// } +// else { +// print("cert", nullptr, 0); +// } +// std::cout << "\n"; + +// // Create data that can be verified by cert +// Data data(Name("/test/data").append(type)); +// m_keyChain.sign(data, signingInfo); +// print("goodData", data.wireEncode().wire(), data.wireEncode().size()); +// std::cout << "\n"; + +// // Create data that cannot be verified by cert +// m_keyChain.sign(data, signingByIdentity(wrongIdentity)); +// print("badSigData", data.wireEncode().wire(), data.wireEncode().size()); +// std::cout << "\n"; + +// // Create interest that can be verified by cert +// Interest interest(Name("/test/interest/").append(type)); +// m_keyChain.sign(interest, signingInfo); +// print("goodInterest", interest.wireEncode().wire(), interest.wireEncode().size()); +// std::cout << "\n"; + +// // Create interest that cannot be verified by cert +// m_keyChain.sign(interest, signingByIdentity(wrongIdentity)); +// print("badSigInterest", interest.wireEncode().wire(), interest.wireEncode().size()); +// std::cout << "\n};\n\n"; +// } +// } + +struct EcdsaDataset +{ + const std::string name = "Ecdsa"; + std::vector cert = { + 0x06, 0xFD, 0x02, 0x59, 0x07, 0x47, 0x08, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, + 0x08, 0x17, 0x54, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6F, 0x6E, 0x48, 0x65, 0x6C, 0x70, 0x65, 0x72, 0x73, 0x08, 0x02, 0x45, 0x43, 0x08, 0x03, 0x4B, + 0x45, 0x59, 0x08, 0x08, 0xDC, 0x9E, 0x3B, 0x11, 0x2A, 0x81, 0x7E, 0x92, 0x08, 0x04, 0x73, 0x65, + 0x6C, 0x66, 0x08, 0x09, 0xFD, 0x00, 0x00, 0x01, 0x59, 0x90, 0x5F, 0x6F, 0x4F, 0x14, 0x09, 0x18, + 0x01, 0x02, 0x19, 0x04, 0x00, 0x36, 0xEE, 0x80, 0x15, 0xFD, 0x01, 0x4F, 0x30, 0x82, 0x01, 0x4B, + 0x30, 0x82, 0x01, 0x03, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x30, 0x81, 0xF7, + 0x02, 0x01, 0x01, 0x30, 0x2C, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01, 0x01, 0x02, 0x21, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x30, 0x5B, 0x04, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x04, 0x20, 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, + 0xEB, 0xBD, 0x55, 0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, 0x3B, + 0xCE, 0x3C, 0x3E, 0x27, 0xD2, 0x60, 0x4B, 0x03, 0x15, 0x00, 0xC4, 0x9D, 0x36, 0x08, 0x86, 0xE7, + 0x04, 0x93, 0x6A, 0x66, 0x78, 0xE1, 0x13, 0x9D, 0x26, 0xB7, 0x81, 0x9F, 0x7E, 0x90, 0x04, 0x41, + 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, + 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, + 0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, + 0x16, 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, + 0xF5, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, + 0xFC, 0x63, 0x25, 0x51, 0x02, 0x01, 0x01, 0x03, 0x42, 0x00, 0x04, 0x78, 0xF2, 0x68, 0x89, 0x92, + 0x8D, 0x84, 0x17, 0xF1, 0x2B, 0x50, 0x4C, 0x9B, 0xFA, 0x6C, 0x4D, 0x8D, 0x29, 0x7D, 0x85, 0xDC, + 0x03, 0x09, 0x72, 0xFA, 0x06, 0xD4, 0x5C, 0xCB, 0xA6, 0x62, 0x0A, 0x7E, 0x2D, 0x50, 0xF0, 0x07, + 0xDE, 0xE0, 0x34, 0xF6, 0xC2, 0xAE, 0xA9, 0x32, 0x9B, 0x2C, 0xBD, 0x25, 0xAF, 0xB7, 0xE1, 0x7C, + 0xCD, 0x85, 0xF4, 0x6D, 0x31, 0xD6, 0xC0, 0x01, 0xC3, 0xEF, 0xB3, 0x16, 0x67, 0x1B, 0x01, 0x03, + 0x1C, 0x38, 0x07, 0x36, 0x08, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x08, 0x17, + 0x54, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x48, 0x65, 0x6C, 0x70, 0x65, 0x72, 0x73, 0x08, 0x02, 0x45, 0x43, 0x08, 0x03, 0x4B, 0x45, 0x59, + 0x08, 0x08, 0xDC, 0x9E, 0x3B, 0x11, 0x2A, 0x81, 0x7E, 0x92, 0xFD, 0x00, 0xFD, 0x26, 0xFD, 0x00, + 0xFE, 0x0F, 0x31, 0x39, 0x37, 0x30, 0x30, 0x31, 0x30, 0x31, 0x54, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0xFD, 0x00, 0xFF, 0x0F, 0x32, 0x30, 0x33, 0x37, 0x30, 0x31, 0x30, 0x37, 0x54, 0x30, 0x31, + 0x35, 0x31, 0x33, 0x30, 0x17, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xC3, 0xB4, 0x2A, 0x00, 0x58, + 0x97, 0x42, 0xDA, 0x54, 0x4C, 0xA6, 0xEF, 0x0C, 0x40, 0x51, 0x88, 0x5C, 0x86, 0x99, 0xF2, 0xBC, + 0x15, 0xEA, 0x06, 0x64, 0xA5, 0xD5, 0xFF, 0x2B, 0xFA, 0xD1, 0xD3, 0x02, 0x20, 0x35, 0x4C, 0xC0, + 0x0D, 0x0F, 0x8E, 0x43, 0x56, 0x12, 0x60, 0x8C, 0x98, 0xF1, 0x5F, 0xC4, 0xD5, 0xF2, 0x25, 0x21, + 0xD4, 0x9C, 0x94, 0x55, 0x0D, 0x4F, 0xDE, 0x14, 0x51, 0x82, 0xB3, 0x8E, 0xA1 + }; + std::vector goodData = { + 0x06, 0x9E, 0x07, 0x10, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x08, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x08, 0x02, 0x45, 0x63, 0x14, 0x00, 0x15, 0x00, 0x16, 0x3D, 0x1B, 0x01, 0x03, 0x1C, 0x38, 0x07, + 0x36, 0x08, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x08, 0x17, 0x54, 0x65, 0x73, + 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x48, 0x65, 0x6C, + 0x70, 0x65, 0x72, 0x73, 0x08, 0x02, 0x45, 0x43, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x08, 0xDC, + 0x9E, 0x3B, 0x11, 0x2A, 0x81, 0x7E, 0x92, 0x17, 0x47, 0x30, 0x45, 0x02, 0x20, 0x29, 0x8B, 0xE5, + 0x0B, 0xD4, 0x24, 0x92, 0xA7, 0x5A, 0x36, 0x73, 0x5A, 0xC2, 0xBE, 0x17, 0x0D, 0xCA, 0x6C, 0xBB, + 0xF9, 0x15, 0x60, 0xBD, 0x08, 0x8E, 0xA9, 0x5B, 0x31, 0x94, 0xF2, 0xB7, 0x97, 0x02, 0x21, 0x00, + 0xA9, 0x02, 0xEF, 0x0F, 0x45, 0xCB, 0xC8, 0x5C, 0xF5, 0xD6, 0xCB, 0x90, 0x8E, 0x42, 0x07, 0xA0, + 0xA0, 0x34, 0x6A, 0x61, 0xAD, 0x24, 0x9E, 0xB7, 0x73, 0x98, 0xA4, 0x6C, 0x2D, 0xD6, 0x12, 0xE2 + }; + std::vector badSigData = { + 0x06, 0xA2, 0x07, 0x10, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x08, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x08, 0x02, 0x45, 0x63, 0x14, 0x00, 0x15, 0x00, 0x16, 0x40, 0x1B, 0x01, 0x03, 0x1C, 0x3B, 0x07, + 0x39, 0x08, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x08, 0x17, 0x54, 0x65, 0x73, + 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x48, 0x65, 0x6C, + 0x70, 0x65, 0x72, 0x73, 0x08, 0x05, 0x57, 0x72, 0x6F, 0x6E, 0x67, 0x08, 0x03, 0x4B, 0x45, 0x59, + 0x08, 0x08, 0x57, 0x76, 0xDC, 0x93, 0x8D, 0x34, 0x59, 0x9C, 0x17, 0x48, 0x30, 0x46, 0x02, 0x21, + 0x00, 0xB9, 0x4B, 0x40, 0x62, 0xAD, 0xAD, 0xFA, 0x75, 0x69, 0xDE, 0x48, 0x90, 0xC4, 0x11, 0x6B, + 0xC7, 0x9E, 0x6C, 0x3E, 0x04, 0x78, 0x53, 0xAB, 0xF2, 0x18, 0x16, 0x9F, 0x8D, 0x1A, 0x14, 0x68, + 0x57, 0x02, 0x21, 0x00, 0xC1, 0xA4, 0xC8, 0x00, 0x0B, 0x61, 0xA0, 0x2C, 0x88, 0x33, 0x7C, 0xE1, + 0x84, 0xE7, 0xF8, 0xAC, 0x8B, 0x46, 0x19, 0x9C, 0x03, 0xE4, 0xF1, 0xBE, 0x83, 0x09, 0x97, 0xD5, + 0xA8, 0x98, 0x1A, 0x47 + }; + std::vector goodInterest = { + 0x05, 0xA9, 0x07, 0xA1, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x08, 0x08, 0x69, 0x6E, 0x74, 0x65, + 0x72, 0x65, 0x73, 0x74, 0x08, 0x02, 0x45, 0x63, 0x08, 0x3F, 0x16, 0x3D, 0x1B, 0x01, 0x03, 0x1C, + 0x38, 0x07, 0x36, 0x08, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x08, 0x17, 0x54, + 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x48, + 0x65, 0x6C, 0x70, 0x65, 0x72, 0x73, 0x08, 0x02, 0x45, 0x43, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, + 0x08, 0xDC, 0x9E, 0x3B, 0x11, 0x2A, 0x81, 0x7E, 0x92, 0x08, 0x4A, 0x17, 0x48, 0x30, 0x46, 0x02, + 0x21, 0x00, 0xE9, 0x35, 0xF0, 0x7B, 0x51, 0xB5, 0x2E, 0xB7, 0xE8, 0x6B, 0xE8, 0xAC, 0xC7, 0xC1, + 0x90, 0x35, 0x64, 0x21, 0x53, 0x0F, 0x6D, 0x03, 0xB5, 0x1A, 0x58, 0xEA, 0xC4, 0x8A, 0xCA, 0xAF, + 0xDB, 0x4B, 0x02, 0x21, 0x00, 0x95, 0xF3, 0xEB, 0xF9, 0xF9, 0x66, 0x51, 0x87, 0x97, 0xB0, 0xBF, + 0xF8, 0x07, 0x5F, 0xF0, 0x70, 0x90, 0x36, 0xD8, 0x57, 0x65, 0xEA, 0xDB, 0x91, 0x79, 0x0E, 0x7E, + 0x0E, 0xD0, 0x20, 0x96, 0x19, 0x0A, 0x04, 0xF7, 0x2C, 0x8A, 0x4B + }; + std::vector badSigInterest = { + 0x05, 0xFD, 0x01, 0x3A, 0x07, 0xFD, 0x01, 0x30, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x08, 0x08, + 0x69, 0x6E, 0x74, 0x65, 0x72, 0x65, 0x73, 0x74, 0x08, 0x02, 0x45, 0x63, 0x08, 0x3F, 0x16, 0x3D, + 0x1B, 0x01, 0x03, 0x1C, 0x38, 0x07, 0x36, 0x08, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, + 0x79, 0x08, 0x17, 0x54, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6F, 0x6E, 0x48, 0x65, 0x6C, 0x70, 0x65, 0x72, 0x73, 0x08, 0x02, 0x45, 0x43, 0x08, 0x03, + 0x4B, 0x45, 0x59, 0x08, 0x08, 0xDC, 0x9E, 0x3B, 0x11, 0x2A, 0x81, 0x7E, 0x92, 0x08, 0x4A, 0x17, + 0x48, 0x30, 0x46, 0x02, 0x21, 0x00, 0xE9, 0x35, 0xF0, 0x7B, 0x51, 0xB5, 0x2E, 0xB7, 0xE8, 0x6B, + 0xE8, 0xAC, 0xC7, 0xC1, 0x90, 0x35, 0x64, 0x21, 0x53, 0x0F, 0x6D, 0x03, 0xB5, 0x1A, 0x58, 0xEA, + 0xC4, 0x8A, 0xCA, 0xAF, 0xDB, 0x4B, 0x02, 0x21, 0x00, 0x95, 0xF3, 0xEB, 0xF9, 0xF9, 0x66, 0x51, + 0x87, 0x97, 0xB0, 0xBF, 0xF8, 0x07, 0x5F, 0xF0, 0x70, 0x90, 0x36, 0xD8, 0x57, 0x65, 0xEA, 0xDB, + 0x91, 0x79, 0x0E, 0x7E, 0x0E, 0xD0, 0x20, 0x96, 0x19, 0x08, 0x42, 0x16, 0x40, 0x1B, 0x01, 0x03, + 0x1C, 0x3B, 0x07, 0x39, 0x08, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x08, 0x17, + 0x54, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x48, 0x65, 0x6C, 0x70, 0x65, 0x72, 0x73, 0x08, 0x05, 0x57, 0x72, 0x6F, 0x6E, 0x67, 0x08, 0x03, + 0x4B, 0x45, 0x59, 0x08, 0x08, 0x57, 0x76, 0xDC, 0x93, 0x8D, 0x34, 0x59, 0x9C, 0x08, 0x49, 0x17, + 0x47, 0x30, 0x45, 0x02, 0x20, 0x30, 0x34, 0xB8, 0x9C, 0x33, 0x4C, 0x54, 0x56, 0xF0, 0x34, 0x7A, + 0x95, 0x72, 0x20, 0xEC, 0xF5, 0x0F, 0xBB, 0x90, 0x3D, 0xC4, 0x21, 0x90, 0xB8, 0x3D, 0xA1, 0x10, + 0x5A, 0x56, 0x71, 0xC3, 0x3F, 0x02, 0x21, 0x00, 0xAE, 0xE0, 0x60, 0xCF, 0x2C, 0xF7, 0x54, 0xC2, + 0x1C, 0xC5, 0x54, 0x88, 0xDA, 0x31, 0xD2, 0xDE, 0x53, 0x56, 0xEC, 0xE2, 0xC6, 0x4F, 0xDD, 0xF2, + 0x78, 0x5D, 0xB3, 0xD4, 0x8E, 0x45, 0x36, 0x23, 0x0A, 0x04, 0xF7, 0x2C, 0x8A, 0x4B + }; +}; + +struct RsaDataset +{ + const std::string name = "Rsa"; + std::vector cert = { + 0x06, 0xFD, 0x02, 0xED, 0x07, 0x48, 0x08, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, + 0x08, 0x17, 0x54, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6F, 0x6E, 0x48, 0x65, 0x6C, 0x70, 0x65, 0x72, 0x73, 0x08, 0x03, 0x52, 0x53, 0x41, 0x08, 0x03, + 0x4B, 0x45, 0x59, 0x08, 0x08, 0xE1, 0x7A, 0x42, 0xD0, 0x60, 0x6F, 0x0F, 0xDF, 0x08, 0x04, 0x73, + 0x65, 0x6C, 0x66, 0x08, 0x09, 0xFD, 0x00, 0x00, 0x01, 0x59, 0x90, 0x5F, 0x6F, 0x9F, 0x14, 0x09, + 0x18, 0x01, 0x02, 0x19, 0x04, 0x00, 0x36, 0xEE, 0x80, 0x15, 0xFD, 0x01, 0x26, 0x30, 0x82, 0x01, + 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xE7, 0x7B, + 0x1F, 0x75, 0x3C, 0xCD, 0xB4, 0x62, 0x80, 0xC3, 0xA4, 0x5E, 0xA9, 0x8A, 0x7B, 0xC6, 0x4C, 0x43, + 0x27, 0x0D, 0xA4, 0x54, 0xEB, 0x67, 0x4F, 0xB4, 0x6E, 0xEF, 0x6D, 0x54, 0x9B, 0x85, 0x44, 0xE9, + 0x6B, 0x4D, 0x09, 0x31, 0xC0, 0xDC, 0xC5, 0x06, 0x5E, 0x88, 0x6B, 0xFC, 0x0B, 0x08, 0xDE, 0x14, + 0x0F, 0xAB, 0xE8, 0xA7, 0xED, 0x93, 0x5D, 0x17, 0x19, 0x4B, 0x2D, 0x7D, 0x29, 0xE7, 0x43, 0x42, + 0x19, 0xE0, 0x3C, 0xBA, 0x8D, 0xAB, 0xE9, 0x4A, 0xBF, 0x21, 0x1E, 0x13, 0xD5, 0x0D, 0x9A, 0xC5, + 0xD8, 0x67, 0x4A, 0x7F, 0x2D, 0xA6, 0xA9, 0xCE, 0x31, 0x82, 0x62, 0x6B, 0x89, 0xB1, 0x78, 0xE0, + 0x6E, 0x19, 0x8B, 0xE6, 0x5C, 0x1A, 0x10, 0x8B, 0xC2, 0x9D, 0xF4, 0xB6, 0x66, 0xE9, 0x73, 0xD0, + 0x93, 0xE9, 0x0A, 0xA8, 0xDA, 0x68, 0xC1, 0x23, 0xBC, 0xBE, 0x17, 0xA0, 0x8E, 0x88, 0xC6, 0x71, + 0xFF, 0x25, 0x83, 0x75, 0x2C, 0x0E, 0x49, 0x76, 0x27, 0xA0, 0x9E, 0x08, 0x55, 0xA2, 0xE1, 0x60, + 0xAC, 0x5E, 0x03, 0xC3, 0x9E, 0xF3, 0x2B, 0x56, 0x80, 0xE0, 0x30, 0xD8, 0x0A, 0x5A, 0xAB, 0x92, + 0xA4, 0x32, 0xF2, 0xEC, 0xE8, 0xFB, 0x6D, 0xE2, 0xE6, 0x2F, 0x87, 0x94, 0xEA, 0xA3, 0x39, 0x47, + 0x70, 0x71, 0x08, 0xBC, 0x11, 0x0B, 0xC5, 0x9A, 0xCF, 0x13, 0xCA, 0x68, 0x7C, 0x22, 0xF8, 0x33, + 0xCA, 0x5F, 0xEB, 0x98, 0xF3, 0x29, 0x12, 0xF0, 0x33, 0xDE, 0x30, 0xC4, 0x56, 0xB5, 0x3B, 0x0B, + 0x0C, 0x23, 0xF2, 0x0F, 0x93, 0x3D, 0x60, 0xC9, 0xD2, 0xAA, 0x5A, 0x94, 0x3E, 0xAB, 0xFB, 0xD5, + 0x9B, 0xF0, 0xC9, 0x79, 0x11, 0xAD, 0x78, 0x4E, 0xE9, 0x91, 0x1E, 0x62, 0x8D, 0x81, 0x71, 0xC9, + 0xE4, 0x5D, 0x41, 0xDD, 0x19, 0xC6, 0x77, 0x81, 0xF6, 0xA7, 0x38, 0xD4, 0xE1, 0xB3, 0x02, 0x03, + 0x01, 0x00, 0x01, 0x16, 0x68, 0x1B, 0x01, 0x01, 0x1C, 0x39, 0x07, 0x37, 0x08, 0x08, 0x53, 0x65, + 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x08, 0x17, 0x54, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x48, 0x65, 0x6C, 0x70, 0x65, 0x72, 0x73, 0x08, + 0x03, 0x52, 0x53, 0x41, 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x08, 0xE1, 0x7A, 0x42, 0xD0, 0x60, + 0x6F, 0x0F, 0xDF, 0xFD, 0x00, 0xFD, 0x26, 0xFD, 0x00, 0xFE, 0x0F, 0x31, 0x39, 0x37, 0x30, 0x30, + 0x31, 0x30, 0x31, 0x54, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xFD, 0x00, 0xFF, 0x0F, 0x32, 0x30, + 0x33, 0x37, 0x30, 0x31, 0x30, 0x37, 0x54, 0x30, 0x31, 0x35, 0x31, 0x33, 0x30, 0x17, 0xFD, 0x01, + 0x00, 0xD1, 0xEB, 0xB4, 0x09, 0x2B, 0x9D, 0xFA, 0x82, 0x88, 0x1A, 0xB6, 0x71, 0x99, 0xD0, 0x14, + 0x2B, 0xB5, 0xD8, 0xB8, 0x36, 0xA5, 0x70, 0xC0, 0xDD, 0x7E, 0xD1, 0xAD, 0x93, 0xEC, 0xCE, 0x9F, + 0x3E, 0x75, 0x1F, 0x7F, 0x95, 0x0A, 0x34, 0xCC, 0x8C, 0x5A, 0x45, 0x37, 0xE2, 0x65, 0xE4, 0x1D, + 0xEC, 0xE2, 0xC2, 0x39, 0x7F, 0xD7, 0xB7, 0x9B, 0x78, 0xDF, 0x0B, 0x39, 0x2B, 0xC6, 0x5E, 0x49, + 0x6F, 0xDB, 0xB0, 0x44, 0xFD, 0xC7, 0x5B, 0x00, 0xB4, 0xDD, 0x23, 0xBC, 0xA8, 0xC8, 0x9C, 0xCB, + 0xAD, 0x63, 0x3C, 0x40, 0x57, 0x07, 0x09, 0xC7, 0x26, 0x84, 0xBF, 0x49, 0x8B, 0xD0, 0x5A, 0xFD, + 0xBA, 0xA0, 0x0C, 0x06, 0xE5, 0x84, 0xA3, 0x9B, 0x36, 0x5E, 0x95, 0xBF, 0x34, 0xF5, 0x5A, 0x70, + 0x31, 0x3B, 0x70, 0x3E, 0x99, 0x84, 0xBA, 0x03, 0xE7, 0x5A, 0x9D, 0x6F, 0x46, 0x33, 0xA3, 0x95, + 0xAD, 0xB5, 0xC9, 0x20, 0x28, 0xA8, 0x6E, 0x52, 0x02, 0x97, 0x49, 0xDA, 0x89, 0x55, 0x6B, 0x5D, + 0xCB, 0x84, 0x75, 0x5F, 0x1F, 0x51, 0x0C, 0x59, 0x49, 0xC8, 0xCE, 0x2D, 0xC3, 0xA2, 0x2F, 0x7F, + 0x42, 0x71, 0x26, 0x4F, 0xF4, 0x1F, 0xBB, 0x09, 0x7D, 0xF8, 0x7E, 0x6D, 0x44, 0x74, 0xB1, 0x7F, + 0x76, 0xAE, 0x7B, 0x1C, 0x56, 0x75, 0x9B, 0xE7, 0x23, 0xF4, 0xF3, 0xA0, 0x3C, 0x47, 0xF0, 0x98, + 0x2B, 0xC1, 0x54, 0xDA, 0x75, 0x1B, 0x2E, 0x94, 0xFB, 0xB5, 0xDD, 0x44, 0xE9, 0x16, 0x27, 0xE5, + 0xE9, 0xB5, 0xA5, 0x70, 0x5E, 0xBC, 0x48, 0xB1, 0x02, 0x92, 0x64, 0x73, 0x08, 0x8A, 0x5C, 0xD8, + 0xF7, 0x58, 0x07, 0x66, 0xEF, 0x4A, 0x9E, 0xB5, 0x77, 0xDF, 0xDE, 0x54, 0xF1, 0x0A, 0xDF, 0xE1, + 0xE1, 0xF1, 0x76, 0x91, 0xEB, 0x78, 0xB6, 0x9A, 0x40, 0x57, 0x97, 0x9C, 0x2C, 0x8C, 0x00, 0x05, + 0x01 + }; + std::vector goodData = { + 0x06, 0xFD, 0x01, 0x5B, 0x07, 0x11, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x08, 0x04, 0x64, 0x61, + 0x74, 0x61, 0x08, 0x03, 0x52, 0x73, 0x61, 0x14, 0x00, 0x15, 0x00, 0x16, 0x3E, 0x1B, 0x01, 0x01, + 0x1C, 0x39, 0x07, 0x37, 0x08, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x08, 0x17, + 0x54, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x48, 0x65, 0x6C, 0x70, 0x65, 0x72, 0x73, 0x08, 0x03, 0x52, 0x53, 0x41, 0x08, 0x03, 0x4B, 0x45, + 0x59, 0x08, 0x08, 0xE1, 0x7A, 0x42, 0xD0, 0x60, 0x6F, 0x0F, 0xDF, 0x17, 0xFD, 0x01, 0x00, 0x88, + 0xEA, 0x30, 0x2E, 0xF2, 0x40, 0xA4, 0x2F, 0xF6, 0x95, 0x83, 0x1B, 0xD7, 0x89, 0xB2, 0xDB, 0x73, + 0xB8, 0x88, 0x97, 0x48, 0xDC, 0xC4, 0x8F, 0xBD, 0x83, 0x49, 0x5E, 0x39, 0x14, 0xE5, 0x15, 0xE2, + 0x94, 0xB3, 0x7A, 0x4A, 0x46, 0x1F, 0xEE, 0x50, 0xF5, 0x1F, 0x46, 0xE9, 0xAB, 0x31, 0x94, 0x9C, + 0x41, 0xF1, 0xA7, 0x1E, 0xA7, 0x2F, 0x2C, 0x26, 0x5E, 0x97, 0x7D, 0x06, 0x86, 0x77, 0x63, 0x4B, + 0xD0, 0x38, 0x91, 0x0F, 0xB6, 0x2B, 0xFD, 0xF0, 0x77, 0xB1, 0xA8, 0x73, 0xBB, 0xF9, 0x8A, 0xED, + 0x8D, 0xDD, 0x32, 0x8E, 0x8A, 0xC2, 0xEE, 0x83, 0xA6, 0x72, 0xFF, 0xDB, 0x91, 0xA8, 0x83, 0x1D, + 0xDC, 0x37, 0x1F, 0x58, 0xF6, 0x16, 0x5D, 0x89, 0x50, 0xDD, 0x1D, 0x42, 0x96, 0x81, 0x75, 0x94, + 0xA7, 0x8D, 0x2E, 0x8C, 0xB2, 0x75, 0x36, 0x99, 0x7A, 0x65, 0x34, 0x07, 0xC8, 0x28, 0x98, 0xA2, + 0x46, 0x9D, 0x6F, 0x30, 0x8E, 0x32, 0x49, 0x20, 0xE6, 0xFC, 0x1A, 0x05, 0x4F, 0x6F, 0xE8, 0x5D, + 0x34, 0x1D, 0x8D, 0x7F, 0x09, 0xA8, 0xDD, 0xA7, 0x48, 0xB1, 0x14, 0xDC, 0x5A, 0xAF, 0xAA, 0x12, + 0xEA, 0x57, 0xDE, 0x47, 0x6C, 0xC6, 0x07, 0xBC, 0x6B, 0x76, 0xB1, 0x40, 0x56, 0x3B, 0x12, 0x47, + 0x1D, 0x89, 0x66, 0x12, 0x81, 0xE8, 0x8B, 0xBA, 0x70, 0x8A, 0x3E, 0x78, 0x64, 0x00, 0x3E, 0x56, + 0x3B, 0xCF, 0x26, 0xF0, 0x3D, 0x09, 0x1D, 0xB9, 0x22, 0x9E, 0xED, 0x67, 0xB8, 0x86, 0x1F, 0x44, + 0x92, 0x0A, 0x08, 0xE1, 0x8F, 0x4C, 0x6D, 0x9C, 0x11, 0x5F, 0x26, 0xEA, 0x3E, 0x95, 0x32, 0x13, + 0x20, 0x51, 0x95, 0x24, 0x37, 0x18, 0x13, 0x92, 0xBD, 0x22, 0xF0, 0x0E, 0xAF, 0x34, 0x37, 0x9B, + 0xDC, 0x61, 0x03, 0x29, 0x09, 0x9A, 0x45, 0x92, 0x1B, 0xA0, 0x29, 0x9E, 0xD8, 0x98, 0x54 + }; + std::vector badSigData = { + 0x06, 0xA1, 0x07, 0x11, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x08, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x08, 0x03, 0x52, 0x73, 0x61, 0x14, 0x00, 0x15, 0x00, 0x16, 0x40, 0x1B, 0x01, 0x03, 0x1C, 0x3B, + 0x07, 0x39, 0x08, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x08, 0x17, 0x54, 0x65, + 0x73, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x48, 0x65, + 0x6C, 0x70, 0x65, 0x72, 0x73, 0x08, 0x05, 0x57, 0x72, 0x6F, 0x6E, 0x67, 0x08, 0x03, 0x4B, 0x45, + 0x59, 0x08, 0x08, 0x57, 0x76, 0xDC, 0x93, 0x8D, 0x34, 0x59, 0x9C, 0x17, 0x46, 0x30, 0x44, 0x02, + 0x20, 0x5E, 0xF9, 0x02, 0xF4, 0x78, 0xE7, 0x5E, 0x1B, 0xB9, 0x3B, 0x23, 0xDE, 0x9D, 0xB7, 0x87, + 0xC6, 0x30, 0x7F, 0x4A, 0xE2, 0xBE, 0x11, 0xFE, 0x29, 0xC7, 0x6F, 0x70, 0x97, 0xAF, 0x45, 0xE1, + 0x0B, 0x02, 0x20, 0x67, 0x45, 0x47, 0x52, 0xBE, 0x13, 0x59, 0x76, 0x16, 0x28, 0x70, 0xF6, 0x50, + 0x13, 0xB2, 0xC0, 0xFA, 0x8F, 0xF3, 0x05, 0xFF, 0xBC, 0x92, 0xAC, 0xF7, 0xD0, 0x12, 0x3A, 0x6E, + 0x31, 0x76, 0x02 + }; + std::vector goodInterest = { + 0x05, 0xFD, 0x01, 0x69, 0x07, 0xFD, 0x01, 0x5F, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x08, 0x08, + 0x69, 0x6E, 0x74, 0x65, 0x72, 0x65, 0x73, 0x74, 0x08, 0x03, 0x52, 0x73, 0x61, 0x08, 0x40, 0x16, + 0x3E, 0x1B, 0x01, 0x01, 0x1C, 0x39, 0x07, 0x37, 0x08, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, + 0x74, 0x79, 0x08, 0x17, 0x54, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x48, 0x65, 0x6C, 0x70, 0x65, 0x72, 0x73, 0x08, 0x03, 0x52, 0x53, 0x41, + 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x08, 0xE1, 0x7A, 0x42, 0xD0, 0x60, 0x6F, 0x0F, 0xDF, 0x08, + 0xFD, 0x01, 0x04, 0x17, 0xFD, 0x01, 0x00, 0x9C, 0x44, 0x23, 0xF4, 0x3A, 0x9F, 0xDD, 0x62, 0xD2, + 0x47, 0xE4, 0x73, 0x9E, 0x58, 0x54, 0xF5, 0xE7, 0x72, 0x8D, 0x2E, 0x1B, 0x26, 0xE7, 0xA2, 0xA1, + 0x56, 0x23, 0xBD, 0xB8, 0x75, 0x17, 0x78, 0x01, 0x67, 0xF9, 0x4D, 0xA9, 0xCC, 0xB8, 0x00, 0xF6, + 0xCD, 0xC4, 0xB9, 0xF6, 0x50, 0xC7, 0xAB, 0x57, 0xD8, 0xA7, 0x8B, 0xA8, 0x5C, 0xED, 0xD0, 0xCC, + 0x29, 0xC3, 0x5D, 0x80, 0x2B, 0xFA, 0xAF, 0x0D, 0xCB, 0x29, 0x1E, 0x74, 0xA8, 0x41, 0x80, 0xDE, + 0x52, 0x94, 0xDD, 0xE8, 0xAA, 0xA9, 0x61, 0x83, 0xC1, 0x5F, 0xA3, 0x11, 0x48, 0x0B, 0xB6, 0x53, + 0xB8, 0xE3, 0x77, 0x6A, 0xED, 0xF0, 0xFA, 0xED, 0x79, 0x43, 0x10, 0x10, 0x79, 0x98, 0x5D, 0xFD, + 0x66, 0xBF, 0x2F, 0x14, 0x9F, 0x7D, 0xA4, 0x3C, 0xBA, 0x67, 0x5F, 0xDB, 0xE3, 0x67, 0x13, 0x96, + 0x60, 0xC6, 0x69, 0x78, 0x5A, 0x8D, 0x52, 0xB7, 0xB7, 0x6B, 0x7F, 0xEE, 0xF4, 0x22, 0x3A, 0x64, + 0xE4, 0xB4, 0xA1, 0x8B, 0xDD, 0x3F, 0x80, 0xCD, 0xF4, 0x9E, 0x92, 0x06, 0x98, 0x23, 0x47, 0x58, + 0x70, 0xF0, 0xAC, 0x79, 0x76, 0x91, 0x7A, 0x78, 0xDF, 0xAD, 0xDD, 0x81, 0x30, 0x01, 0x5D, 0xCE, + 0x37, 0xEC, 0x7E, 0xDA, 0xDA, 0x36, 0x75, 0x50, 0x52, 0x57, 0x95, 0xBF, 0xCF, 0x3A, 0xC4, 0x9F, + 0x52, 0x97, 0x17, 0x15, 0x99, 0xA5, 0x2F, 0x68, 0x35, 0x91, 0x70, 0xDE, 0x98, 0x8A, 0xB0, 0x5F, + 0xF4, 0x63, 0x14, 0xB9, 0xCC, 0x76, 0x81, 0x87, 0xAE, 0x10, 0x8E, 0x9F, 0xEC, 0xCB, 0xF2, 0x33, + 0x1D, 0x50, 0xD4, 0xAB, 0x5B, 0xBB, 0xB9, 0x7F, 0x8C, 0xAD, 0xEC, 0xE3, 0xF8, 0xE1, 0x63, 0xDA, + 0x4E, 0x0D, 0x17, 0x28, 0xCD, 0x8D, 0x16, 0x00, 0x22, 0x4A, 0x51, 0x5C, 0xB2, 0x8C, 0xE7, 0x4B, + 0x3B, 0x00, 0x16, 0x92, 0xAD, 0x3A, 0xAB, 0x0A, 0x04, 0x10, 0x04, 0xFB, 0x38 + }; + std::vector badSigInterest = { + 0x05, 0xFD, 0x01, 0xF7, 0x07, 0xFD, 0x01, 0xED, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x08, 0x08, + 0x69, 0x6E, 0x74, 0x65, 0x72, 0x65, 0x73, 0x74, 0x08, 0x03, 0x52, 0x73, 0x61, 0x08, 0x40, 0x16, + 0x3E, 0x1B, 0x01, 0x01, 0x1C, 0x39, 0x07, 0x37, 0x08, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, + 0x74, 0x79, 0x08, 0x17, 0x54, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x48, 0x65, 0x6C, 0x70, 0x65, 0x72, 0x73, 0x08, 0x03, 0x52, 0x53, 0x41, + 0x08, 0x03, 0x4B, 0x45, 0x59, 0x08, 0x08, 0xE1, 0x7A, 0x42, 0xD0, 0x60, 0x6F, 0x0F, 0xDF, 0x08, + 0xFD, 0x01, 0x04, 0x17, 0xFD, 0x01, 0x00, 0x9C, 0x44, 0x23, 0xF4, 0x3A, 0x9F, 0xDD, 0x62, 0xD2, + 0x47, 0xE4, 0x73, 0x9E, 0x58, 0x54, 0xF5, 0xE7, 0x72, 0x8D, 0x2E, 0x1B, 0x26, 0xE7, 0xA2, 0xA1, + 0x56, 0x23, 0xBD, 0xB8, 0x75, 0x17, 0x78, 0x01, 0x67, 0xF9, 0x4D, 0xA9, 0xCC, 0xB8, 0x00, 0xF6, + 0xCD, 0xC4, 0xB9, 0xF6, 0x50, 0xC7, 0xAB, 0x57, 0xD8, 0xA7, 0x8B, 0xA8, 0x5C, 0xED, 0xD0, 0xCC, + 0x29, 0xC3, 0x5D, 0x80, 0x2B, 0xFA, 0xAF, 0x0D, 0xCB, 0x29, 0x1E, 0x74, 0xA8, 0x41, 0x80, 0xDE, + 0x52, 0x94, 0xDD, 0xE8, 0xAA, 0xA9, 0x61, 0x83, 0xC1, 0x5F, 0xA3, 0x11, 0x48, 0x0B, 0xB6, 0x53, + 0xB8, 0xE3, 0x77, 0x6A, 0xED, 0xF0, 0xFA, 0xED, 0x79, 0x43, 0x10, 0x10, 0x79, 0x98, 0x5D, 0xFD, + 0x66, 0xBF, 0x2F, 0x14, 0x9F, 0x7D, 0xA4, 0x3C, 0xBA, 0x67, 0x5F, 0xDB, 0xE3, 0x67, 0x13, 0x96, + 0x60, 0xC6, 0x69, 0x78, 0x5A, 0x8D, 0x52, 0xB7, 0xB7, 0x6B, 0x7F, 0xEE, 0xF4, 0x22, 0x3A, 0x64, + 0xE4, 0xB4, 0xA1, 0x8B, 0xDD, 0x3F, 0x80, 0xCD, 0xF4, 0x9E, 0x92, 0x06, 0x98, 0x23, 0x47, 0x58, + 0x70, 0xF0, 0xAC, 0x79, 0x76, 0x91, 0x7A, 0x78, 0xDF, 0xAD, 0xDD, 0x81, 0x30, 0x01, 0x5D, 0xCE, + 0x37, 0xEC, 0x7E, 0xDA, 0xDA, 0x36, 0x75, 0x50, 0x52, 0x57, 0x95, 0xBF, 0xCF, 0x3A, 0xC4, 0x9F, + 0x52, 0x97, 0x17, 0x15, 0x99, 0xA5, 0x2F, 0x68, 0x35, 0x91, 0x70, 0xDE, 0x98, 0x8A, 0xB0, 0x5F, + 0xF4, 0x63, 0x14, 0xB9, 0xCC, 0x76, 0x81, 0x87, 0xAE, 0x10, 0x8E, 0x9F, 0xEC, 0xCB, 0xF2, 0x33, + 0x1D, 0x50, 0xD4, 0xAB, 0x5B, 0xBB, 0xB9, 0x7F, 0x8C, 0xAD, 0xEC, 0xE3, 0xF8, 0xE1, 0x63, 0xDA, + 0x4E, 0x0D, 0x17, 0x28, 0xCD, 0x8D, 0x16, 0x00, 0x22, 0x4A, 0x51, 0x5C, 0xB2, 0x8C, 0xE7, 0x4B, + 0x3B, 0x00, 0x16, 0x92, 0xAD, 0x3A, 0xAB, 0x08, 0x42, 0x16, 0x40, 0x1B, 0x01, 0x03, 0x1C, 0x3B, + 0x07, 0x39, 0x08, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x08, 0x17, 0x54, 0x65, + 0x73, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x48, 0x65, + 0x6C, 0x70, 0x65, 0x72, 0x73, 0x08, 0x05, 0x57, 0x72, 0x6F, 0x6E, 0x67, 0x08, 0x03, 0x4B, 0x45, + 0x59, 0x08, 0x08, 0x57, 0x76, 0xDC, 0x93, 0x8D, 0x34, 0x59, 0x9C, 0x08, 0x48, 0x17, 0x46, 0x30, + 0x44, 0x02, 0x20, 0x48, 0x87, 0xFE, 0x7D, 0x43, 0x35, 0x3C, 0x55, 0xCB, 0x4A, 0x4B, 0x83, 0x50, + 0xC2, 0x10, 0xAD, 0x01, 0x4A, 0x99, 0xED, 0x6C, 0x29, 0x38, 0xEF, 0xE4, 0x9E, 0x10, 0x23, 0x4D, + 0x57, 0xC3, 0xE4, 0x02, 0x20, 0x7B, 0x35, 0xDC, 0xF2, 0x98, 0xD8, 0xFE, 0x13, 0x4D, 0x3B, 0x5D, + 0xE7, 0xCE, 0xFF, 0x02, 0xBD, 0x6B, 0x50, 0x30, 0x8B, 0x93, 0x91, 0x7A, 0xC9, 0xE0, 0x95, 0x21, + 0x5F, 0x91, 0xB6, 0xEE, 0x4E, 0x0A, 0x04, 0x10, 0x04, 0xFB, 0x38 + }; +}; + +struct Sha256Dataset +{ + const std::string name = "Sha256"; + std::vector cert = { + + }; + std::vector goodData = { + 0x06, 0x41, 0x07, 0x14, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x08, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x08, 0x06, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x14, 0x00, 0x15, 0x00, 0x16, 0x03, 0x1B, 0x01, + 0x00, 0x17, 0x20, 0xE2, 0xE2, 0x2F, 0x02, 0x70, 0xA7, 0xF7, 0x48, 0x70, 0x45, 0x29, 0x46, 0xBD, + 0xD2, 0x62, 0x24, 0xA6, 0x1E, 0x1D, 0x75, 0x2A, 0x26, 0x98, 0x04, 0xAD, 0x9C, 0x47, 0x63, 0xF8, + 0x98, 0x5A, 0x49 + }; + std::vector badSigData = { + 0x06, 0xA5, 0x07, 0x14, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x08, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x08, 0x06, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x14, 0x00, 0x15, 0x00, 0x16, 0x40, 0x1B, 0x01, + 0x03, 0x1C, 0x3B, 0x07, 0x39, 0x08, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x08, + 0x17, 0x54, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, + 0x6E, 0x48, 0x65, 0x6C, 0x70, 0x65, 0x72, 0x73, 0x08, 0x05, 0x57, 0x72, 0x6F, 0x6E, 0x67, 0x08, + 0x03, 0x4B, 0x45, 0x59, 0x08, 0x08, 0x57, 0x76, 0xDC, 0x93, 0x8D, 0x34, 0x59, 0x9C, 0x17, 0x47, + 0x30, 0x45, 0x02, 0x20, 0x5F, 0x5E, 0x1E, 0xC0, 0xB5, 0xAC, 0x13, 0xF9, 0x51, 0x2F, 0x22, 0x33, + 0xFB, 0xDE, 0x57, 0xF6, 0xC8, 0xBF, 0xAE, 0x55, 0x3A, 0xDC, 0x30, 0x8A, 0x12, 0x61, 0xB3, 0x5D, + 0xB9, 0x31, 0x95, 0xD3, 0x02, 0x21, 0x00, 0xFA, 0xEC, 0x54, 0xEB, 0x35, 0x4D, 0xBF, 0x87, 0x4C, + 0xD8, 0x20, 0x3A, 0xE5, 0x05, 0x2C, 0xA1, 0x70, 0x74, 0x2E, 0xF9, 0x1E, 0xE1, 0xEF, 0xB9, 0x47, + 0xC4, 0x53, 0x57, 0xED, 0xB5, 0xB7, 0x60 + }; + std::vector goodInterest = { + 0x05, 0x4B, 0x07, 0x43, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x08, 0x08, 0x69, 0x6E, 0x74, 0x65, + 0x72, 0x65, 0x73, 0x74, 0x08, 0x06, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x08, 0x05, 0x16, 0x03, + 0x1B, 0x01, 0x00, 0x08, 0x22, 0x17, 0x20, 0x38, 0x65, 0xB5, 0x37, 0x8A, 0xF4, 0xEB, 0xB9, 0xCD, + 0xEF, 0x18, 0x49, 0xF5, 0x79, 0x85, 0xE5, 0x76, 0x6F, 0x3C, 0x72, 0x63, 0x0E, 0x4F, 0x5D, 0xC7, + 0x42, 0x6B, 0xDF, 0xB0, 0xE1, 0x75, 0x2C, 0x0A, 0x04, 0xEE, 0x0A, 0x69, 0x16 + }; + std::vector badSigInterest = { + 0x05, 0xD9, 0x07, 0xD1, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x08, 0x08, 0x69, 0x6E, 0x74, 0x65, + 0x72, 0x65, 0x73, 0x74, 0x08, 0x06, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x08, 0x05, 0x16, 0x03, + 0x1B, 0x01, 0x00, 0x08, 0x22, 0x17, 0x20, 0x38, 0x65, 0xB5, 0x37, 0x8A, 0xF4, 0xEB, 0xB9, 0xCD, + 0xEF, 0x18, 0x49, 0xF5, 0x79, 0x85, 0xE5, 0x76, 0x6F, 0x3C, 0x72, 0x63, 0x0E, 0x4F, 0x5D, 0xC7, + 0x42, 0x6B, 0xDF, 0xB0, 0xE1, 0x75, 0x2C, 0x08, 0x42, 0x16, 0x40, 0x1B, 0x01, 0x03, 0x1C, 0x3B, + 0x07, 0x39, 0x08, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x08, 0x17, 0x54, 0x65, + 0x73, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x48, 0x65, + 0x6C, 0x70, 0x65, 0x72, 0x73, 0x08, 0x05, 0x57, 0x72, 0x6F, 0x6E, 0x67, 0x08, 0x03, 0x4B, 0x45, + 0x59, 0x08, 0x08, 0x57, 0x76, 0xDC, 0x93, 0x8D, 0x34, 0x59, 0x9C, 0x08, 0x48, 0x17, 0x46, 0x30, + 0x44, 0x02, 0x20, 0x73, 0xB7, 0x0E, 0x17, 0x6C, 0x98, 0xB5, 0x6B, 0x25, 0x99, 0x2C, 0x6E, 0x41, + 0x26, 0xE6, 0x08, 0xCF, 0x81, 0xB9, 0x51, 0x53, 0x6A, 0x6B, 0x21, 0xF3, 0x2D, 0x4D, 0x62, 0x53, + 0x86, 0x85, 0xEE, 0x02, 0x20, 0x7D, 0x9D, 0xFF, 0xE3, 0x18, 0xF7, 0xBD, 0x7F, 0x9B, 0xC6, 0x4D, + 0x76, 0x09, 0x58, 0x74, 0x69, 0x67, 0x9B, 0x51, 0xBC, 0x14, 0xF0, 0x1C, 0x46, 0xA7, 0xA3, 0xA7, + 0xCC, 0x9A, 0xBB, 0x33, 0x07, 0x0A, 0x04, 0xEE, 0x0A, 0x69, 0x16 + }; +}; + +// Note about the datasets: +// - .cert a valid certificate +// - .goodData is a data packet that can be verified by .cert +// - .badSigData a valid and signed data packet that cannot be verified by cert (signed by a +// different private key) +// - .goodInterest is an interest packet that can be verified by .cert +// - .badSigInterest a valid and signed interest packet that cannot be verified by cert +// (signed by a different private key) + +using SignatureDatasets = boost::mpl::vector; + +BOOST_AUTO_TEST_CASE_TEMPLATE(VerifySignature, Dataset, SignatureDatasets) +{ + Dataset dataset; + v2::Certificate cert(Block(dataset.cert.data(), dataset.cert.size())); + Buffer keyRaw = cert.getPublicKey(); + transform::PublicKey key; + key.loadPkcs8(keyRaw.data(), keyRaw.size()); + Data data(Block(dataset.goodData.data(), dataset.goodData.size())); + Data badSigData(Block(dataset.badSigData.data(), dataset.badSigData.size())); + Interest interest(Block(dataset.goodInterest.data(), dataset.goodInterest.size())); + Interest badSigInterest(Block(dataset.badSigInterest.data(), dataset.badSigInterest.size())); + + BOOST_CHECK(verifySignature(data, key)); + BOOST_CHECK(verifySignature(data, keyRaw.data(), keyRaw.size())); + BOOST_CHECK(verifySignature(data, cert)); + BOOST_CHECK(verifySignature(interest, key)); + BOOST_CHECK(verifySignature(interest, keyRaw.data(), keyRaw.size())); + BOOST_CHECK(verifySignature(interest, cert)); + + BOOST_CHECK(!verifySignature(badSigData, key)); + BOOST_CHECK(!verifySignature(badSigData, keyRaw.data(), keyRaw.size())); + BOOST_CHECK(!verifySignature(badSigData, cert)); + BOOST_CHECK(!verifySignature(badSigInterest, key)); + BOOST_CHECK(!verifySignature(badSigInterest, keyRaw.data(), keyRaw.size())); + BOOST_CHECK(!verifySignature(badSigInterest, cert)); + + Data unsignedData("/some/data"); + Interest unsignedInterest1("/some/interest/with/several/name/components"); + Interest unsignedInterest2("/interest-with-one-name-component"); + + BOOST_CHECK(!verifySignature(unsignedData, cert)); + BOOST_CHECK(!verifySignature(unsignedData, key)); + BOOST_CHECK(!verifySignature(unsignedInterest1, cert)); + BOOST_CHECK(!verifySignature(unsignedInterest1, key)); + BOOST_CHECK(!verifySignature(unsignedInterest2, cert)); + BOOST_CHECK(!verifySignature(unsignedInterest2, key)); + + uint8_t invalidKey[] = {0x00, 0x00}; + BOOST_CHECK(!verifySignature(unsignedData, invalidKey, sizeof(invalidKey))); + BOOST_CHECK(!verifySignature(unsignedInterest1, invalidKey, sizeof(invalidKey))); + + // - base version of verifySignature is tested transitively + // - pib::Key version is tested as part of v2/key-chain.t.cpp (Security/V2/TestKeyChain) +} + +BOOST_FIXTURE_TEST_CASE(VerifyHmac, IdentityManagementFixture) +{ + const Tpm& tpm = m_keyChain.getTpm(); + Data data("/data"); + Interest interest("/interest"); + SigningInfo signingInfo; + signingInfo.setSigningHmacKey("QjM3NEEyNkE3MTQ5MDQzN0FBMDI0RTRGQURENUI0OTdGREZGMUE4RUE2RkYxMkY2" + "RkI2NUFGMjcyMEI1OUNDRg=="); + signingInfo.setDigestAlgorithm(DigestAlgorithm::SHA256); + + BOOST_CHECK(!verifySignature(data, tpm, signingInfo.getSignerName(), DigestAlgorithm::SHA256)); + BOOST_CHECK(!verifySignature(interest, tpm, signingInfo.getSignerName(), DigestAlgorithm::SHA256)); + + m_keyChain.sign(data, signingInfo); + m_keyChain.sign(interest, signingInfo); + BOOST_CHECK(verifySignature(data, tpm, signingInfo.getSignerName(), DigestAlgorithm::SHA256)); + BOOST_CHECK(verifySignature(interest, tpm, signingInfo.getSignerName(), DigestAlgorithm::SHA256)); +} + +using DigestDatasets = boost::mpl::vector; + +BOOST_AUTO_TEST_CASE_TEMPLATE(VerifyDigest, Dataset, DigestDatasets) +{ + Dataset dataset; + Data data(Block(dataset.goodData.data(), dataset.goodData.size())); + Data badSigData(Block(dataset.badSigData.data(), dataset.badSigData.size())); + Interest interest(Block(dataset.goodInterest.data(), dataset.goodInterest.size())); + Interest badSigInterest(Block(dataset.badSigInterest.data(), dataset.badSigInterest.size())); + + BOOST_CHECK(verifyDigest(data, DigestAlgorithm::SHA256)); + BOOST_CHECK(verifyDigest(interest, DigestAlgorithm::SHA256)); + + BOOST_CHECK(!verifyDigest(badSigData, DigestAlgorithm::SHA256)); + BOOST_CHECK(!verifyDigest(badSigInterest, DigestAlgorithm::SHA256)); + + Data unsignedData("/some/data"); + Interest unsignedInterest1("/some/interest/with/several/name/components"); + Interest unsignedInterest2("/interest-with-one-name-component"); + + BOOST_CHECK(!verifyDigest(unsignedData, DigestAlgorithm::SHA256)); + BOOST_CHECK(!verifyDigest(unsignedInterest1, DigestAlgorithm::SHA256)); + BOOST_CHECK(!verifyDigest(unsignedInterest2, DigestAlgorithm::SHA256)); + + // - base version of verifyDigest is tested transitively +} + +BOOST_AUTO_TEST_SUITE_END() // TestVerificationHelpers +BOOST_AUTO_TEST_SUITE_END() // Security + +} // namespace tests +} // namespace security +} // namespace ndn diff --git a/tests/unit-tests/signature-info.t.cpp b/tests/unit/signature-info.t.cpp similarity index 81% rename from tests/unit-tests/signature-info.t.cpp rename to tests/unit/signature-info.t.cpp index 1eaa665cb..270228224 100644 --- a/tests/unit-tests/signature-info.t.cpp +++ b/tests/unit/signature-info.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,9 +19,10 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "signature-info.hpp" +#include "ndn-cxx/signature-info.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" +#include namespace ndn { namespace tests { @@ -49,11 +50,15 @@ BOOST_AUTO_TEST_CASE(Constructor) BOOST_CHECK_EQUAL(info.hasKeyLocator(), false); BOOST_CHECK_THROW(info.getKeyLocator(), SignatureInfo::Error); + BOOST_CHECK_EQUAL(boost::lexical_cast(info), "Invalid SignatureInfo"); + SignatureInfo sha256Info(tlv::DigestSha256); BOOST_CHECK_EQUAL(sha256Info.getSignatureType(), tlv::DigestSha256); BOOST_CHECK_EQUAL(sha256Info.hasKeyLocator(), false); BOOST_CHECK_THROW(sha256Info.getKeyLocator(), SignatureInfo::Error); + BOOST_CHECK_EQUAL(boost::lexical_cast(sha256Info), "DigestSha256"); + KeyLocator keyLocator("/test/key/locator"); SignatureInfo sha256RsaInfo(tlv::SignatureSha256WithRsa, keyLocator); BOOST_CHECK_EQUAL(sha256RsaInfo.getSignatureType(), tlv::SignatureSha256WithRsa); @@ -61,6 +66,8 @@ BOOST_AUTO_TEST_CASE(Constructor) BOOST_CHECK_NO_THROW(sha256RsaInfo.getKeyLocator()); BOOST_CHECK_EQUAL(sha256RsaInfo.getKeyLocator().getName(), Name("/test/key/locator")); + BOOST_CHECK_EQUAL(boost::lexical_cast(sha256RsaInfo), "SignatureSha256WithRsa Name=/test/key/locator"); + const Block& encoded = sha256RsaInfo.wireEncode(); Block sigInfoBlock(sigInfoRsa, sizeof(sigInfoRsa)); @@ -179,7 +186,7 @@ BOOST_AUTO_TEST_CASE(ValidityPeriodExtension) }; time::system_clock::TimePoint notBefore = time::getUnixEpoch(); - time::system_clock::TimePoint notAfter = notBefore + time::days(1); + time::system_clock::TimePoint notAfter = notBefore + 1_day; security::ValidityPeriod vp1(notBefore, notAfter); // encode @@ -188,7 +195,7 @@ BOOST_AUTO_TEST_CASE(ValidityPeriodExtension) info.setKeyLocator(KeyLocator("/test/key/locator")); info.setValidityPeriod(vp1); - BOOST_CHECK(info.getValidityPeriod() == vp1); + BOOST_CHECK_EQUAL(info.getValidityPeriod(), vp1); const Block& encoded = info.wireEncode(); @@ -199,7 +206,7 @@ BOOST_AUTO_TEST_CASE(ValidityPeriodExtension) Block block(sigInfo, sizeof(sigInfo)); SignatureInfo info2; info2.wireDecode(block); - BOOST_CHECK(info2.getValidityPeriod() == vp1); + BOOST_CHECK_EQUAL(info2.getValidityPeriod(), vp1); const security::ValidityPeriod& validityPeriod = info2.getValidityPeriod(); BOOST_CHECK(validityPeriod.getPeriod() == std::make_pair(notBefore, notAfter)); @@ -224,6 +231,33 @@ BOOST_AUTO_TEST_CASE(OtherTlvs) BOOST_REQUIRE_NO_THROW(info.getTypeSpecificTlv(0x81)); } +BOOST_AUTO_TEST_CASE(OtherTlvsEncoding) // Bug #3914 +{ + SignatureInfo info1(tlv::SignatureSha256WithRsa); + info1.appendTypeSpecificTlv(makeStringBlock(101, "First")); + info1.appendTypeSpecificTlv(makeStringBlock(102, "Second")); + info1.appendTypeSpecificTlv(makeStringBlock(103, "Third")); + + BOOST_CHECK_EQUAL(boost::lexical_cast(info1), "SignatureSha256WithRsa { 101 102 103 }"); + + SignatureInfo info2; + info2.wireDecode(info1.wireEncode()); + BOOST_CHECK_EQUAL(info1, info2); + + const uint8_t infoBytes[] = { + 0x16, 0x19, // SignatureInfo + 0x1b, 0x01, 0x01, // SignatureType=1 + 0x65, 0x05, 0x46, 0x69, 0x72, 0x73, 0x74, // 101 "First" + 0x66, 0x06, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, // 102 "Second" + 0x67, 0x05, 0x54, 0x68, 0x69, 0x72, 0x64 // 103 "Third" + }; + + SignatureInfo info3(Block(infoBytes, sizeof(infoBytes))); + BOOST_CHECK_EQUAL(info3, info1); + BOOST_CHECK_EQUAL_COLLECTIONS(infoBytes, infoBytes + sizeof(infoBytes), + info1.wireEncode().begin(), info1.wireEncode().end()); +} + BOOST_AUTO_TEST_SUITE_END() // TestSignatureInfo } // namespace tests diff --git a/tests/unit-tests/tag.t.cpp b/tests/unit/tag.t.cpp similarity index 91% rename from tests/unit-tests/tag.t.cpp rename to tests/unit/tag.t.cpp index 994449a83..0cbae2293 100644 --- a/tests/unit-tests/tag.t.cpp +++ b/tests/unit/tag.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,9 +19,9 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "tag.hpp" +#include "ndn-cxx/tag.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace tests { diff --git a/tests/unit-tests/test-home-env-saver.hpp b/tests/unit/test-home-env-saver.hpp similarity index 83% rename from tests/unit-tests/test-home-env-saver.hpp rename to tests/unit/test-home-env-saver.hpp index 9976b9627..732c2d8b6 100644 --- a/tests/unit-tests/test-home-env-saver.hpp +++ b/tests/unit/test-home-env-saver.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,11 +19,11 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#ifndef NDN_TESTS_UNIT_TESTS_TEST_HOME_ENV_SAVER_HPP -#define NDN_TESTS_UNIT_TESTS_TEST_HOME_ENV_SAVER_HPP +#ifndef NDN_TESTS_UNIT_TEST_HOME_ENV_SAVER_HPP +#define NDN_TESTS_UNIT_TEST_HOME_ENV_SAVER_HPP -#include #include +#include namespace ndn { namespace tests { @@ -41,7 +41,7 @@ class TestHomeEnvSaver ~TestHomeEnvSaver() { if (!m_HOME.empty()) - setenv("TEST_HOME", m_HOME.c_str(), 1); + setenv("TEST_HOME", m_HOME.data(), 1); else unsetenv("TEST_HOME"); } @@ -53,4 +53,4 @@ class TestHomeEnvSaver } // namespace tests } // namespace ndn -#endif // NDN_TESTS_UNIT_TESTS_TEST_HOME_ENV_SAVER_HPP +#endif // NDN_TESTS_UNIT_TEST_HOME_ENV_SAVER_HPP diff --git a/tests/unit-tests/transport/tcp-transport.t.cpp b/tests/unit/transport/tcp-transport.t.cpp similarity index 84% rename from tests/unit-tests/transport/tcp-transport.t.cpp rename to tests/unit/transport/tcp-transport.t.cpp index 2386553b2..991bf1c5d 100644 --- a/tests/unit-tests/transport/tcp-transport.t.cpp +++ b/tests/unit/transport/tcp-transport.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,10 +19,10 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "transport/tcp-transport.hpp" -#include "transport-fixture.hpp" +#include "ndn-cxx/transport/tcp-transport.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" +#include "tests/unit/transport/transport-fixture.hpp" namespace ndn { namespace tests { @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(GetDefaultSocketHostAndPortBadMissingHost) BOOST_CHECK_EXCEPTION(TcpTransport::getSocketHostAndPortFromUri("tcp://:6000"), Transport::Error, [] (const Transport::Error& error) { - return error.what() == std::string("Malformed URI: tcp://:6000"); + return error.what() == "Malformed URI: tcp://:6000"s; }); } @@ -70,8 +70,7 @@ BOOST_AUTO_TEST_CASE(GetDefaultSocketHostAndPortBadWrongTransport) BOOST_CHECK_EXCEPTION(TcpTransport::getSocketHostAndPortFromUri("unix://"), Transport::Error, [] (const Transport::Error& error) { - return error.what() == std::string("Cannot create TcpTransport " - "from \"unix\" URI"); + return error.what() == "Cannot create TcpTransport from \"unix\" URI"s; }); } @@ -80,7 +79,7 @@ BOOST_AUTO_TEST_CASE(GetDefaultSocketHostAndPortBadMalformedUri) BOOST_CHECK_EXCEPTION(TcpTransport::getSocketHostAndPortFromUri("tcp"), Transport::Error, [] (const Transport::Error& error) { - return error.what() == std::string("Malformed URI: tcp"); + return error.what() == "Malformed URI: tcp"s; }); } diff --git a/tests/unit-tests/transport/transport-fixture.hpp b/tests/unit/transport/transport-fixture.hpp similarity index 79% rename from tests/unit-tests/transport/transport-fixture.hpp rename to tests/unit/transport/transport-fixture.hpp index 602ba5f97..6c84fd156 100644 --- a/tests/unit-tests/transport/transport-fixture.hpp +++ b/tests/unit/transport/transport-fixture.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,11 +19,12 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "util/config-file.hpp" -#include "../test-home-env-saver.hpp" +#ifndef NDN_TESTS_UNIT_TRANSPORT_TRANSPORT_FIXTURE_HPP +#define NDN_TESTS_UNIT_TRANSPORT_TRANSPORT_FIXTURE_HPP -#ifndef NDN_TESTS_UNIT_TESTS_TRANSPORT_FIXTURE_HPP -#define NDN_TESTS_UNIT_TESTS_TRANSPORT_FIXTURE_HPP +#include "ndn-cxx/util/config-file.hpp" + +#include "tests/unit/test-home-env-saver.hpp" namespace ndn { namespace tests { @@ -45,4 +46,4 @@ class TransportFixture : public TestHomeEnvSaver } // namespace tests } // namespace ndn -#endif // NDN_TESTS_UNIT_TESTS_TRANSPORT_FIXTURE_HPP +#endif // NDN_TESTS_UNIT_TRANSPORT_TRANSPORT_FIXTURE_HPP diff --git a/tests/unit-tests/transport/unix-transport.t.cpp b/tests/unit/transport/unix-transport.t.cpp similarity index 83% rename from tests/unit-tests/transport/unix-transport.t.cpp rename to tests/unit/transport/unix-transport.t.cpp index f3d4cac6e..41c46b917 100644 --- a/tests/unit-tests/transport/unix-transport.t.cpp +++ b/tests/unit/transport/unix-transport.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,10 +19,10 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "transport/unix-transport.hpp" -#include "transport-fixture.hpp" +#include "ndn-cxx/transport/unix-transport.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" +#include "tests/unit/transport/transport-fixture.hpp" namespace ndn { namespace tests { @@ -47,8 +47,7 @@ BOOST_AUTO_TEST_CASE(GetDefaultSocketNameBadWrongTransport) BOOST_CHECK_EXCEPTION(UnixTransport::getSocketNameFromUri("tcp://"), Transport::Error, [] (const Transport::Error& error) { - return error.what() == std::string("Cannot create UnixTransport " - "from \"tcp\" URI"); + return error.what() == "Cannot create UnixTransport from \"tcp\" URI"s; }); } @@ -57,7 +56,7 @@ BOOST_AUTO_TEST_CASE(GetDefaultSocketNameBadMalformedUri) BOOST_CHECK_EXCEPTION(UnixTransport::getSocketNameFromUri("unix"), Transport::Error, [] (const Transport::Error& error) { - return error.what() == std::string("Malformed URI: unix"); + return error.what() == "Malformed URI: unix"s; }); } diff --git a/tests/unit-tests/unit-test-time-fixture.hpp b/tests/unit/unit-test-time-fixture.hpp similarity index 91% rename from tests/unit-tests/unit-test-time-fixture.hpp rename to tests/unit/unit-test-time-fixture.hpp index 9f43258d3..fcbaa77f6 100644 --- a/tests/unit-tests/unit-test-time-fixture.hpp +++ b/tests/unit/unit-test-time-fixture.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,10 +19,10 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#ifndef NDN_TESTS_UNIT_TESTS_UNIT_TEST_TIME_FIXTURE_HPP -#define NDN_TESTS_UNIT_TESTS_UNIT_TEST_TIME_FIXTURE_HPP +#ifndef NDN_TESTS_UNIT_UNIT_TEST_TIME_FIXTURE_HPP +#define NDN_TESTS_UNIT_UNIT_TEST_TIME_FIXTURE_HPP -#include "util/time-unit-test-clock.hpp" +#include "ndn-cxx/util/time-unit-test-clock.hpp" #include @@ -103,4 +103,4 @@ class UnitTestTimeFixture } // namespace tests } // namespace ndn -#endif // NDN_TESTS_UNIT_TESTS_UNIT_TEST_TIME_FIXTURE_HPP +#endif // NDN_TESTS_UNIT_UNIT_TEST_TIME_FIXTURE_HPP diff --git a/tests/unit/util/backports.t.cpp b/tests/unit/util/backports.t.cpp new file mode 100644 index 000000000..b73465bc7 --- /dev/null +++ b/tests/unit/util/backports.t.cpp @@ -0,0 +1,100 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/backports.hpp" +#include "ndn-cxx/util/ostream-joiner.hpp" + +#include "tests/boost-test.hpp" + +#include + +#if BOOST_VERSION >= 105900 +#include +#else +#include +#endif + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Util) +BOOST_AUTO_TEST_SUITE(TestBackports) + +BOOST_AUTO_TEST_CASE(Clamp) +{ + int x = clamp(5, 1, 10); + BOOST_CHECK_EQUAL(x, 5); + + x = clamp(-5, 1, 10); + BOOST_CHECK_EQUAL(x, 1); + + x = clamp(15, 1, 10); + BOOST_CHECK_EQUAL(x, 10); + + x = clamp(5, 10, 1, std::greater()); + BOOST_CHECK_EQUAL(x, 5); + + x = clamp(-5, 10, 1, std::greater()); + BOOST_CHECK_EQUAL(x, 1); + + x = clamp(15, 10, 1, std::greater()); + BOOST_CHECK_EQUAL(x, 10); +} + +BOOST_AUTO_TEST_CASE(OstreamJoiner) +{ + boost::test_tools::output_test_stream os; + + auto joiner1 = ostream_joiner(os, ' '); + auto joiner2 = make_ostream_joiner(os, ' '); + static_assert(std::is_same::value, ""); + + std::vector v(5); + std::iota(v.begin(), v.end(), 1); + std::copy(v.begin(), v.end(), joiner2); + BOOST_CHECK(os.is_equal("1 2 3 4 5")); + + auto joiner3 = make_ostream_joiner(os, "..."); + std::copy(v.begin(), v.end(), joiner3); + BOOST_CHECK(os.is_equal("1...2...3...4...5")); + + joiner3 = "one"; + BOOST_CHECK(os.is_equal("one")); + joiner3 = "two"; + BOOST_CHECK(os.is_equal("...two")); + ++joiner3 = "three"; + BOOST_CHECK(os.is_equal("...three")); + joiner3++ = "four"; + BOOST_CHECK(os.is_equal("...four")); + + std::copy(v.begin(), v.end(), make_ostream_joiner(os, "")); + BOOST_CHECK(os.is_equal("12345")); + + std::string delimiter("_"); + std::copy(v.begin(), v.end(), make_ostream_joiner(os, delimiter)); + BOOST_CHECK(os.is_equal("1_2_3_4_5")); +} + +BOOST_AUTO_TEST_SUITE_END() // TestBackports +BOOST_AUTO_TEST_SUITE_END() // Util + +} // namespace tests +} // namespace ndn diff --git a/tests/unit-tests/util/concepts.t.cpp b/tests/unit/util/concepts.t.cpp similarity index 94% rename from tests/unit-tests/util/concepts.t.cpp rename to tests/unit/util/concepts.t.cpp index 522e737b8..997f86a72 100644 --- a/tests/unit-tests/util/concepts.t.cpp +++ b/tests/unit/util/concepts.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California, +/* + * Copyright (c) 2014-2018 Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -25,7 +25,7 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "util/concepts.hpp" +#include "ndn-cxx/util/concepts.hpp" namespace ndn { namespace tests { diff --git a/tests/unit-tests/util/config-file-home/.ndn/client.conf b/tests/unit/util/config-file-home/.ndn/client.conf similarity index 100% rename from tests/unit-tests/util/config-file-home/.ndn/client.conf rename to tests/unit/util/config-file-home/.ndn/client.conf diff --git a/tests/unit-tests/util/config-file-malformed-home/.ndn/client.conf b/tests/unit/util/config-file-malformed-home/.ndn/client.conf similarity index 100% rename from tests/unit-tests/util/config-file-malformed-home/.ndn/client.conf rename to tests/unit/util/config-file-malformed-home/.ndn/client.conf diff --git a/tests/unit-tests/util/config-file.t.cpp b/tests/unit/util/config-file.t.cpp similarity index 83% rename from tests/unit-tests/util/config-file.t.cpp rename to tests/unit/util/config-file.t.cpp index e72d0f2f5..78b80be66 100644 --- a/tests/unit-tests/util/config-file.t.cpp +++ b/tests/unit/util/config-file.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,10 +19,10 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "util/config-file.hpp" -#include "../test-home-env-saver.hpp" +#include "ndn-cxx/util/config-file.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" +#include "tests/unit/test-home-env-saver.hpp" #include @@ -36,7 +36,7 @@ BOOST_AUTO_TEST_CASE(Parse) { namespace fs = boost::filesystem; - setenv("TEST_HOME", "tests/unit-tests/util/config-file-home", 1); + setenv("TEST_HOME", "tests/unit/util/config-file-home", 1); fs::path homePath(fs::absolute(std::getenv("TEST_HOME"))); homePath /= ".ndn/client.conf"; @@ -51,14 +51,14 @@ BOOST_AUTO_TEST_CASE(Parse) BOOST_AUTO_TEST_CASE(ParseEmptyPath) { - setenv("TEST_HOME", "tests/unit-tests/util/does/not/exist", 1); + setenv("TEST_HOME", "tests/unit/util/does/not/exist", 1); BOOST_CHECK_NO_THROW(ConfigFile config); } BOOST_AUTO_TEST_CASE(ParseMalformed) { - setenv("TEST_HOME", "tests/unit-tests/util/config-file-malformed-home", 1); + setenv("TEST_HOME", "tests/unit/util/config-file-malformed-home", 1); BOOST_CHECK_THROW(ConfigFile config, ConfigFile::Error); } diff --git a/tests/unit/util/dummy-client-face.t.cpp b/tests/unit/util/dummy-client-face.t.cpp new file mode 100644 index 000000000..acd629730 --- /dev/null +++ b/tests/unit/util/dummy-client-face.t.cpp @@ -0,0 +1,132 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/dummy-client-face.hpp" + +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" +#include "tests/unit/identity-management-time-fixture.hpp" + +namespace ndn { +namespace util { +namespace tests { + +using namespace ndn::tests; + +BOOST_AUTO_TEST_SUITE(Util) +BOOST_FIXTURE_TEST_SUITE(TestDummyClientFace, ndn::tests::IdentityManagementTimeFixture) + +BOOST_AUTO_TEST_CASE(ProcessEventsOverride) +{ + bool isOverrideInvoked = false; + auto override = [&] (time::milliseconds timeout) { + isOverrideInvoked = true; + BOOST_CHECK_EQUAL(timeout, 200_ms); + }; + + DummyClientFace face(io, {false, false, override}); + face.processEvents(200_ms); + BOOST_CHECK(isOverrideInvoked); +} + +BOOST_AUTO_TEST_CASE(BroadcastLink) +{ + DummyClientFace face1(io, m_keyChain, DummyClientFace::Options{true, true}); + DummyClientFace face2(io, m_keyChain, DummyClientFace::Options{true, true}); + face1.linkTo(face2); + + int nFace1Interest = 0; + int nFace2Interest = 0; + face1.setInterestFilter("/face1", + [&] (const InterestFilter&, const Interest& interest) { + BOOST_CHECK_EQUAL(interest.getName().toUri(), "/face1/data"); + nFace1Interest++; + face1.put(ndn::tests::makeNack(interest, lp::NackReason::NO_ROUTE)); + }, nullptr, nullptr); + face2.setInterestFilter("/face2", + [&] (const InterestFilter&, const Interest& interest) { + BOOST_CHECK_EQUAL(interest.getName().toUri(), "/face2/data"); + nFace2Interest++; + face2.put(*ndn::tests::makeData("/face2/data")); + return; + }, nullptr, nullptr); + + advanceClocks(25_ms, 4); + + int nFace1Data = 0; + int nFace2Nack = 0; + face1.expressInterest(*makeInterest("/face2/data"), + [&] (const Interest& i, const Data& d) { + BOOST_CHECK_EQUAL(d.getName().toUri(), "/face2/data"); + nFace1Data++; + }, nullptr, nullptr); + face2.expressInterest(*makeInterest("/face1/data"), + [&] (const Interest& i, const Data& d) { + BOOST_CHECK(false); + }, + [&] (const Interest& i, const lp::Nack& n) { + BOOST_CHECK_EQUAL(n.getInterest().getName().toUri(), "/face1/data"); + nFace2Nack++; + }, nullptr); + + advanceClocks(10_ms, 100); + + BOOST_CHECK_EQUAL(nFace1Data, 1); + BOOST_CHECK_EQUAL(nFace2Nack, 1); + BOOST_CHECK_EQUAL(nFace1Interest, 1); + BOOST_CHECK_EQUAL(nFace2Interest, 1); +} + +BOOST_AUTO_TEST_CASE(BroadcastLinkDestroy) +{ + DummyClientFace face1(io, m_keyChain, DummyClientFace::Options{true, true}); + DummyClientFace face2(io, m_keyChain, DummyClientFace::Options{true, true}); + + face1.linkTo(face2); + face2.unlink(); + BOOST_CHECK(face1.m_bcastLink == nullptr); + + DummyClientFace face3(io, m_keyChain, DummyClientFace::Options{true, true}); + face1.linkTo(face2); + face3.linkTo(face1); + face2.unlink(); + BOOST_CHECK(face1.m_bcastLink != nullptr); +} + +BOOST_AUTO_TEST_CASE(AlreadyLinkException) +{ + DummyClientFace face1(io, m_keyChain, DummyClientFace::Options{true, true}); + DummyClientFace face2(io, m_keyChain, DummyClientFace::Options{true, true}); + DummyClientFace face3(io, m_keyChain, DummyClientFace::Options{true, true}); + DummyClientFace face4(io, m_keyChain, DummyClientFace::Options{true, true}); + + face1.linkTo(face2); + face3.linkTo(face4); + + BOOST_CHECK_THROW(face2.linkTo(face3), DummyClientFace::AlreadyLinkedError); +} + +BOOST_AUTO_TEST_SUITE_END() // TestDummyClientFace +BOOST_AUTO_TEST_SUITE_END() // Util + +} // namespace tests +} // namespace util +} // namespace ndn diff --git a/tests/unit/util/exception.t.cpp b/tests/unit/util/exception.t.cpp new file mode 100644 index 000000000..33884dcc9 --- /dev/null +++ b/tests/unit/util/exception.t.cpp @@ -0,0 +1,111 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/exception.hpp" + +#include "tests/boost-test.hpp" + +#include +#include + +namespace ndn { +namespace exception { +namespace test { + +BOOST_AUTO_TEST_SUITE(Util) +BOOST_AUTO_TEST_SUITE(TestException) + +BOOST_AUTO_TEST_CASE(Throw) +{ + auto f = [] { NDN_THROW(std::invalid_argument("test")); }; + + BOOST_CHECK_THROW(f(), boost::exception); + BOOST_CHECK_THROW(f(), std::exception); + BOOST_CHECK_THROW(f(), std::invalid_argument); + + try { + f(); + } + catch (const boost::exception& ex) { + BOOST_CHECK(boost::get_error_info(ex) != nullptr); + BOOST_CHECK(boost::get_error_info(ex) != nullptr); + BOOST_CHECK(boost::get_error_info(ex) != nullptr); + +#ifdef NDN_CXX_HAVE_STACKTRACE + auto stack = boost::get_error_info(ex); + BOOST_REQUIRE(stack != nullptr); + auto info = boost::diagnostic_information(ex); + BOOST_TEST_MESSAGE(info); + BOOST_CHECK(stack->empty() || info.find("===== Stacktrace =====") != std::string::npos); +#endif + } +} + +BOOST_AUTO_TEST_CASE(ThrowErrno) +{ + auto f = [] { + errno = ERANGE; + NDN_THROW_ERRNO(std::out_of_range("test")); + }; + + BOOST_CHECK_THROW(f(), boost::exception); + BOOST_CHECK_THROW(f(), std::exception); + BOOST_CHECK_THROW(f(), std::out_of_range); + + try { + f(); + } + catch (const boost::exception& ex) { + auto errPtr = boost::get_error_info(ex); + BOOST_REQUIRE(errPtr != nullptr); + BOOST_CHECK_EQUAL(*errPtr, ERANGE); + } +} + +BOOST_AUTO_TEST_CASE(ThrowNested) +{ + auto f = [] { + try { + NDN_THROW(std::overflow_error("inner")); + } + catch (...) { + NDN_THROW_NESTED(std::domain_error("outer")); + } + }; + + BOOST_CHECK_THROW(f(), boost::exception); + BOOST_CHECK_THROW(f(), std::exception); + BOOST_CHECK_THROW(f(), std::domain_error); + + try { + f(); + } + catch (const boost::exception& ex) { + BOOST_CHECK(boost::get_error_info(ex) != nullptr); + } +} + +BOOST_AUTO_TEST_SUITE_END() // TestException +BOOST_AUTO_TEST_SUITE_END() // Util + +} // namespace test +} // namespace exception +} // namespace ndn diff --git a/tests/unit-tests/util/indented-stream.t.cpp b/tests/unit/util/indented-stream.t.cpp similarity index 90% rename from tests/unit-tests/util/indented-stream.t.cpp rename to tests/unit/util/indented-stream.t.cpp index bc033ff44..f07990aba 100644 --- a/tests/unit-tests/util/indented-stream.t.cpp +++ b/tests/unit/util/indented-stream.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,10 +19,15 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "util/indented-stream.hpp" +#include "ndn-cxx/util/indented-stream.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" + +#if BOOST_VERSION >= 105900 +#include +#else #include +#endif namespace ndn { namespace util { diff --git a/tests/unit/util/io.t.cpp b/tests/unit/util/io.t.cpp new file mode 100644 index 000000000..934027998 --- /dev/null +++ b/tests/unit/util/io.t.cpp @@ -0,0 +1,354 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/io.hpp" + +#include "tests/boost-test.hpp" +#include "tests/identity-management-fixture.hpp" + +#include +#include + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Util) +BOOST_AUTO_TEST_SUITE(TestIo) + +struct NoEncoding +{ + const io::IoEncoding encoding{io::NO_ENCODING}; + const std::vector blob{0xd1, 0x0, 0xb0, 0x1a}; + std::istringstream stream{std::string("\xd1\x00\xb0\x1a", 4), std::ios_base::binary}; +}; + +struct Base64Encoding +{ + const io::IoEncoding encoding = io::BASE64; + const std::vector blob{0x42, 0x61, 0x73, 0x65, 0x36, 0x34, 0x45, 0x6e, 0x63}; + std::istringstream stream{"QmFzZTY0RW5j\n", std::ios_base::binary}; +}; + +struct HexEncoding +{ + const io::IoEncoding encoding = io::HEX; + const std::vector blob{0x48, 0x65, 0x78, 0x45, 0x6e, 0x63}; + std::istringstream stream{"486578456E63", std::ios_base::binary}; +}; + +using Encodings = boost::mpl::vector; + +BOOST_AUTO_TEST_CASE_TEMPLATE(LoadBuffer, T, Encodings) +{ + T t; + shared_ptr buf = io::loadBuffer(t.stream, t.encoding); + BOOST_CHECK_EQUAL_COLLECTIONS(buf->begin(), buf->end(), t.blob.begin(), t.blob.end()); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(SaveBuffer, T, Encodings) +{ + T t; + std::ostringstream os(std::ios_base::binary); + io::saveBuffer(t.blob.data(), t.blob.size(), os, t.encoding); + BOOST_CHECK_EQUAL(os.str(), t.stream.str()); +} + +BOOST_AUTO_TEST_CASE(LoadBufferException) +{ + std::ifstream in("this-file-does-not-exist", std::ios_base::binary); + BOOST_CHECK_THROW(io::loadBuffer(in, io::NO_ENCODING), io::Error); +} + +BOOST_AUTO_TEST_CASE(SaveBufferException) +{ + class NullStreambuf : public std::streambuf + { + }; + + NullStreambuf nullbuf; + std::ostream out(&nullbuf); + const Buffer buffer(1); + BOOST_CHECK_THROW(io::saveBuffer(buffer.data(), buffer.size(), out, io::NO_ENCODING), io::Error); +} + +BOOST_AUTO_TEST_CASE(UnknownIoEncoding) +{ + std::stringstream ss; + BOOST_CHECK_THROW(io::loadBuffer(ss, static_cast(5)), std::invalid_argument); + BOOST_CHECK_THROW(io::saveBuffer(nullptr, 0, ss, static_cast(5)), std::invalid_argument); +} + +class FileIoFixture +{ +protected: + FileIoFixture() + : filepath(boost::filesystem::path(UNIT_TEST_CONFIG_PATH) / "TestIo") + , filename(filepath.string()) + { + boost::filesystem::create_directories(filepath.parent_path()); + } + + ~FileIoFixture() + { + boost::system::error_code ec; + boost::filesystem::remove(filepath, ec); // ignore error + } + + /** \brief create a directory at filename, so that it's neither readable nor writable as a file + */ + void + mkdir() const + { + boost::filesystem::create_directory(filepath); + } + + template + Container + readFile() const + { + Container container; + std::ifstream fs(filename, std::ios_base::binary); + BOOST_REQUIRE_MESSAGE(fs, "error opening file"); + char ch; + while (fs.get(ch)) { + container.push_back(static_cast(ch)); + } + return container; + } + + template + void + writeFile(const Container& content) const + { + std::ofstream fs(filename, std::ios_base::binary); + BOOST_REQUIRE_MESSAGE(fs, "error opening file"); + for (auto ch : content) { + fs.put(static_cast(ch)); + } + BOOST_REQUIRE_MESSAGE(fs, "error writing file"); + } + +protected: + const boost::filesystem::path filepath; + const std::string filename; +}; + +BOOST_FIXTURE_TEST_SUITE(FileIo, FileIoFixture) + +class EncodableType +{ +public: + Block + wireEncode() const + { + if (shouldThrow) { + NDN_THROW(tlv::Error("encode error")); + } + + // block will be 0xAA, 0x01, 0xDD + return makeNonNegativeIntegerBlock(0xAA, 0xDD); + } + +public: + bool shouldThrow = false; +}; + +template +class DecodableTypeTpl +{ +public: + DecodableTypeTpl() = default; + + explicit + DecodableTypeTpl(const Block& block) + { + this->wireDecode(block); + } + + void + wireDecode(const Block& block) + { + if (SHOULD_THROW) { + NDN_THROW(tlv::Error("decode error")); + } + + // block must be 0xBB, 0x01, 0xEE + BOOST_CHECK_EQUAL(block.type(), 0xBB); + BOOST_REQUIRE_EQUAL(block.value_size(), 1); + BOOST_CHECK_EQUAL(block.value()[0], 0xEE); + } +}; + +using DecodableType = DecodableTypeTpl; +using DecodableTypeThrow = DecodableTypeTpl; + +BOOST_AUTO_TEST_CASE(LoadNoEncoding) +{ + this->writeFile>({0xBB, 0x01, 0xEE}); + shared_ptr decoded = io::load(filename, io::NO_ENCODING); + BOOST_CHECK(decoded != nullptr); +} + +BOOST_AUTO_TEST_CASE(LoadBase64) +{ + this->writeFile("uwHu\n"); // printf '\xBB\x01\xEE' | base64 + shared_ptr decoded = io::load(filename, io::BASE64); + BOOST_CHECK(decoded != nullptr); +} + +BOOST_AUTO_TEST_CASE(LoadBase64Newline64) +{ + this->writeFile( + "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n" + "AAAAAAAAAAAA\n"); + // printf '\x08\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 + // \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 + // \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 + // \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | base64 + shared_ptr decoded = io::load(filename, io::BASE64); + BOOST_CHECK(decoded != nullptr); +} + +BOOST_AUTO_TEST_CASE(LoadBase64Newline32) +{ + this->writeFile( + "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n" + "AAAAAAAAAAAA\n"); + shared_ptr decoded = io::load(filename, io::BASE64); + BOOST_CHECK(decoded != nullptr); +} + +BOOST_AUTO_TEST_CASE(LoadBase64NewlineEnd) +{ + this->writeFile( + "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"); + shared_ptr decoded = io::load(filename, io::BASE64); + BOOST_CHECK(decoded != nullptr); +} + +BOOST_AUTO_TEST_CASE(LoadBase64NoNewline) +{ + this->writeFile( + "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + shared_ptr decoded = io::load(filename, io::BASE64); + BOOST_CHECK(decoded != nullptr); +} + +BOOST_AUTO_TEST_CASE(LoadHex) +{ + this->writeFile("BB01EE"); + shared_ptr decoded = io::load(filename, io::HEX); + BOOST_CHECK(decoded != nullptr); +} + +BOOST_AUTO_TEST_CASE(LoadException) +{ + this->writeFile>({0xBB, 0x01, 0xEE}); + shared_ptr decoded; + BOOST_CHECK_NO_THROW(decoded = io::load(filename, io::NO_ENCODING)); + BOOST_CHECK(decoded == nullptr); +} + +BOOST_AUTO_TEST_CASE(LoadNotHex) +{ + this->writeFile("not-hex"); + shared_ptr decoded; + BOOST_CHECK_NO_THROW(decoded = io::load(filename, io::HEX)); + BOOST_CHECK(decoded == nullptr); +} + +BOOST_AUTO_TEST_CASE(LoadFileNotReadable) +{ + shared_ptr decoded; + BOOST_CHECK_NO_THROW(decoded = io::load(filename, io::NO_ENCODING)); + BOOST_CHECK(decoded == nullptr); +} + +BOOST_AUTO_TEST_CASE(SaveNoEncoding) +{ + EncodableType encoded; + BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::NO_ENCODING)); + auto content = this->readFile>(); + uint8_t expected[] = {0xAA, 0x01, 0xDD}; + BOOST_CHECK_EQUAL_COLLECTIONS(content.begin(), content.end(), + expected, expected + sizeof(expected)); +} + +BOOST_AUTO_TEST_CASE(SaveBase64) +{ + EncodableType encoded; + BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::BASE64)); + auto content = this->readFile(); + BOOST_CHECK_EQUAL(content, "qgHd\n"); // printf '\xAA\x01\xDD' | base64 +} + +BOOST_AUTO_TEST_CASE(SaveHex) +{ + EncodableType encoded; + BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::HEX)); + auto content = this->readFile(); + BOOST_CHECK_EQUAL(content, "AA01DD"); +} + +BOOST_AUTO_TEST_CASE(SaveException) +{ + EncodableType encoded; + encoded.shouldThrow = true; + BOOST_CHECK_THROW(io::save(encoded, filename, io::NO_ENCODING), io::Error); +} + +BOOST_AUTO_TEST_CASE(SaveFileNotWritable) +{ + this->mkdir(); + EncodableType encoded; + encoded.shouldThrow = true; + BOOST_CHECK_THROW(io::save(encoded, filename, io::NO_ENCODING), io::Error); +} + +BOOST_AUTO_TEST_SUITE_END() // FileIo + +class IdCertFixture : public FileIoFixture + , public IdentityManagementFixture +{ +}; + +BOOST_FIXTURE_TEST_CASE(IdCert, IdCertFixture) +{ + auto identity = addIdentity("/TestIo/IdCert", RsaKeyParams()); + const auto& cert = identity.getDefaultKey().getDefaultCertificate(); + io::save(cert, filename); + + auto readCert = io::load(filename); + + BOOST_REQUIRE(readCert != nullptr); + BOOST_CHECK_EQUAL(cert.getName(), readCert->getName()); + + this->writeFile(""); + readCert = io::load(filename); + BOOST_REQUIRE(readCert == nullptr); +} + +BOOST_AUTO_TEST_SUITE_END() // TestIo +BOOST_AUTO_TEST_SUITE_END() // Util + +} // namespace tests +} // namespace ndn diff --git a/tests/unit/util/log-filter-module.cpp b/tests/unit/util/log-filter-module.cpp new file mode 100644 index 000000000..ab5572849 --- /dev/null +++ b/tests/unit/util/log-filter-module.cpp @@ -0,0 +1,44 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/logger.hpp" + +NDN_LOG_INIT(fm.FilterModule); + +namespace ndn { +namespace util { +namespace tests { + +void +logFromFilterModule() +{ + NDN_LOG_TRACE("traceFM"); + NDN_LOG_DEBUG("debugFM"); + NDN_LOG_INFO("infoFM"); + NDN_LOG_WARN("warnFM"); + NDN_LOG_ERROR("errorFM"); + NDN_LOG_FATAL("fatalFM"); +} + +} // namespace tests +} // namespace util +} // namespace ndn + diff --git a/tests/unit-tests/util/log-module1.cpp b/tests/unit/util/log-module1.cpp similarity index 92% rename from tests/unit-tests/util/log-module1.cpp rename to tests/unit/util/log-module1.cpp index 9641ef20d..4f71102ca 100644 --- a/tests/unit-tests/util/log-module1.cpp +++ b/tests/unit/util/log-module1.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,7 +19,7 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "util/logger.hpp" +#include "ndn-cxx/util/logger.hpp" NDN_LOG_INIT(Module1); diff --git a/tests/unit-tests/util/log-module2.cpp b/tests/unit/util/log-module2.cpp similarity index 92% rename from tests/unit-tests/util/log-module2.cpp rename to tests/unit/util/log-module2.cpp index 37e86d0e5..994e14295 100644 --- a/tests/unit-tests/util/log-module2.cpp +++ b/tests/unit/util/log-module2.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,7 +19,7 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "util/logger.hpp" +#include "ndn-cxx/util/logger.hpp" NDN_LOG_INIT(Module2); diff --git a/tests/unit/util/logger.t.cpp b/tests/unit/util/logger.t.cpp new file mode 100644 index 000000000..ad742bb58 --- /dev/null +++ b/tests/unit/util/logger.t.cpp @@ -0,0 +1,82 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/logger.hpp" +#include "ndn-cxx/util/logging.hpp" + +#include "tests/boost-test.hpp" + +namespace ndn { +namespace util { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Util) +BOOST_AUTO_TEST_SUITE(TestLogger) + +BOOST_AUTO_TEST_CASE(LegalAlphanumeric) +{ + Logger logger("ndnTest123"); + auto mNames = Logging::getLoggerNames(); + BOOST_CHECK_EQUAL(mNames.count("ndnTest123"), 1); + BOOST_CHECK(logger.isLevelEnabled(LogLevel::NONE)); + Logging::get().removeLogger(logger); +} + +BOOST_AUTO_TEST_CASE(AllLegalSymbols) +{ + Logger logger("ndn.~#%.test_1-2-3"); + auto mNames = Logging::getLoggerNames(); + BOOST_CHECK_EQUAL(mNames.count("ndn.~#%.test_1-2-3"), 1); + BOOST_CHECK(logger.isLevelEnabled(LogLevel::NONE)); + Logging::get().removeLogger(logger); +} + +BOOST_AUTO_TEST_CASE(EmptyLogger) +{ + BOOST_CHECK_THROW(Logger logger(""), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(InvalidSymbol) +{ + BOOST_CHECK_THROW(Logger logger("ndn.test.*"), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(StartsWithPeriod) +{ + BOOST_CHECK_THROW(Logger logger(".ndn.test"), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(EndsWithPeriod) +{ + BOOST_CHECK_THROW(Logger logger("ndn.test."), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(ConsecutivePeriods) +{ + BOOST_CHECK_THROW(Logger logger("ndn..test"), std::invalid_argument); +} + +BOOST_AUTO_TEST_SUITE_END() // TestLogger +BOOST_AUTO_TEST_SUITE_END() // Util + +} // namespace tests +} // namespace util +} // namespace ndn diff --git a/tests/unit/util/logging.t.cpp b/tests/unit/util/logging.t.cpp new file mode 100644 index 000000000..8bbc638da --- /dev/null +++ b/tests/unit/util/logging.t.cpp @@ -0,0 +1,711 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/logging.hpp" +#include "ndn-cxx/util/logger.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/unit-test-time-fixture.hpp" + +#if BOOST_VERSION >= 105900 +#include +#else +#include +#endif + +namespace ndn { +namespace util { +namespace tests { + +NDN_LOG_INIT(ndn.util.tests.Logging); + +void +logFromModule1(); + +void +logFromModule2(); + +void +logFromFilterModule(); + +static void +logFromNewLogger(const char* moduleName) +{ + Logger logger(moduleName); + auto ndn_cxx_getLogger = [&logger] () -> Logger& { return logger; }; + + NDN_LOG_TRACE("trace" << moduleName); + NDN_LOG_DEBUG("debug" << moduleName); + NDN_LOG_INFO("info" << moduleName); + NDN_LOG_WARN("warn" << moduleName); + NDN_LOG_ERROR("error" << moduleName); + NDN_LOG_FATAL("fatal" << moduleName); + + BOOST_CHECK(Logging::get().removeLogger(logger)); +} + +namespace ns1 { + +NDN_LOG_INIT(ndn.util.tests.ns1); + +static void +logFromNamespace1() +{ + NDN_LOG_INFO("hello world from ns1"); +} + +} // namespace ns1 + +namespace ns2 { + +NDN_LOG_INIT(ndn.util.tests.ns2); + +static void +logFromNamespace2() +{ + NDN_LOG_INFO("hi there from ns2"); +} + +} // namespace ns2 + +class ClassWithLogger +{ +public: + void + logFromConstMemberFunction() const + { + NDN_LOG_INFO("const member function"); + } + + static void + logFromStaticMemberFunction() + { + NDN_LOG_INFO("static member function"); + } + +private: + NDN_LOG_MEMBER_DECL(); +}; + +NDN_LOG_MEMBER_INIT(ClassWithLogger, ndn.util.tests.ClassWithLogger); + +class AbstractClassWithLogger +{ +public: + virtual + ~AbstractClassWithLogger() = default; + + void + logFromConstMemberFunction() const + { + NDN_LOG_INFO("const member function"); + } + + virtual void + logFromVirtualFunction() = 0; + +protected: + NDN_LOG_MEMBER_DECL(); +}; + +// Check that the macro can cope with abstract types +NDN_LOG_MEMBER_INIT(AbstractClassWithLogger, ndn.util.tests.AbstractClassWithLogger); + +class DerivedClass : public AbstractClassWithLogger +{ +public: + void + logFromVirtualFunction() final + { + NDN_LOG_INFO("overridden virtual function"); + } +}; + +template +class ClassTemplateWithLogger +{ +public: + void + logFromMemberFunction() + { + NDN_LOG_INFO("class template non-static member function"); + } + + static void + logFromStaticMemberFunction() + { + NDN_LOG_INFO("class template static member function"); + } + +private: + NDN_LOG_MEMBER_DECL(); +}; + +// Technically this declaration is not necessary in this case, +// but we want to test that the macro expands to well-formed code +NDN_LOG_MEMBER_DECL_SPECIALIZED((ClassTemplateWithLogger)); + +NDN_LOG_MEMBER_INIT_SPECIALIZED((ClassTemplateWithLogger), ndn.util.tests.Specialized1); +NDN_LOG_MEMBER_INIT_SPECIALIZED((ClassTemplateWithLogger), ndn.util.tests.Specialized2); + +const time::microseconds LOG_SYSTIME(1468108800311239LL); +const std::string LOG_SYSTIME_STR("1468108800.311239"); + +class LoggingFixture : public ndn::tests::UnitTestTimeFixture +{ +protected: + LoggingFixture() + : m_oldEnabledLevel(Logging::get().getLevels()) + , m_oldDestination(Logging::get().getDestination()) + { + this->systemClock->setNow(LOG_SYSTIME); + Logging::get().resetLevels(); + Logging::setDestination(os); + } + + ~LoggingFixture() + { + Logging::get().setLevelImpl(m_oldEnabledLevel); + Logging::setDestination(m_oldDestination); + } + +protected: + boost::test_tools::output_test_stream os; + +private: + std::unordered_map m_oldEnabledLevel; + boost::shared_ptr m_oldDestination; +}; + +BOOST_AUTO_TEST_SUITE(Util) +BOOST_FIXTURE_TEST_SUITE(TestLogging, LoggingFixture) + +BOOST_AUTO_TEST_CASE(GetLoggerNames) +{ + // check that all names are registered from the start even if + // logger instances are lazily created on first use + auto n = Logging::getLoggerNames().size(); + NDN_LOG_TRACE("GetLoggerNames"); + auto names = Logging::getLoggerNames(); + BOOST_CHECK_EQUAL(names.size(), n); + BOOST_CHECK_EQUAL(names.count("ndn.util.tests.Logging"), 1); +} + +BOOST_AUTO_TEST_SUITE(Severity) + +BOOST_AUTO_TEST_CASE(None) +{ + Logging::setLevel("Module1", LogLevel::NONE); + logFromModule1(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + )); +} + +BOOST_AUTO_TEST_CASE(Error) +{ + Logging::setLevel("Module1", LogLevel::ERROR); + logFromModule1(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + )); +} + +BOOST_AUTO_TEST_CASE(Warn) +{ + Logging::setLevel("Module1", LogLevel::WARN); + logFromModule1(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" + + LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + )); +} + +BOOST_AUTO_TEST_CASE(Info) +{ + Logging::setLevel("Module1", LogLevel::INFO); + logFromModule1(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " INFO: [Module1] info1\n" + + LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" + + LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + )); +} + +BOOST_AUTO_TEST_CASE(Debug) +{ + Logging::setLevel("Module1", LogLevel::DEBUG); + logFromModule1(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " DEBUG: [Module1] debug1\n" + + LOG_SYSTIME_STR + " INFO: [Module1] info1\n" + + LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" + + LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + )); +} + +BOOST_AUTO_TEST_CASE(Trace) +{ + Logging::setLevel("Module1", LogLevel::TRACE); + logFromModule1(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " TRACE: [Module1] trace1\n" + + LOG_SYSTIME_STR + " DEBUG: [Module1] debug1\n" + + LOG_SYSTIME_STR + " INFO: [Module1] info1\n" + + LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" + + LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + )); +} + +BOOST_AUTO_TEST_CASE(All) +{ + Logging::setLevel("Module1", LogLevel::ALL); + logFromModule1(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " TRACE: [Module1] trace1\n" + + LOG_SYSTIME_STR + " DEBUG: [Module1] debug1\n" + + LOG_SYSTIME_STR + " INFO: [Module1] info1\n" + + LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" + + LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + )); +} + +BOOST_AUTO_TEST_SUITE_END() // Severity + +BOOST_AUTO_TEST_CASE(NamespaceLogger) +{ + Logging::setLevel("ndn.util.tests.ns1", LogLevel::INFO); + Logging::setLevel("ndn.util.tests.ns2", LogLevel::DEBUG); + + const auto& levels = Logging::get().getLevels(); + BOOST_CHECK_EQUAL(levels.size(), 2); + BOOST_CHECK_EQUAL(levels.at("ndn.util.tests.ns1"), LogLevel::INFO); + BOOST_CHECK_EQUAL(levels.at("ndn.util.tests.ns2"), LogLevel::DEBUG); + + const auto& names = Logging::getLoggerNames(); + BOOST_CHECK_EQUAL(names.count("ndn.util.tests.ns1"), 1); + BOOST_CHECK_EQUAL(names.count("ndn.util.tests.ns2"), 1); + + ns1::logFromNamespace1(); + ns2::logFromNamespace2(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " INFO: [ndn.util.tests.ns1] hello world from ns1\n" + + LOG_SYSTIME_STR + " INFO: [ndn.util.tests.ns2] hi there from ns2\n" + )); +} + +BOOST_AUTO_TEST_CASE(MemberLogger) +{ + Logging::setLevel("ndn.util.tests.ClassWithLogger", LogLevel::INFO); + Logging::setLevel("ndn.util.tests.AbstractClassWithLogger", LogLevel::INFO); + Logging::setLevel("ndn.util.tests.Specialized1", LogLevel::INFO); + // ndn.util.tests.Specialized2 is not enabled + + const auto& names = Logging::getLoggerNames(); + BOOST_CHECK_EQUAL(names.count("ndn.util.tests.ClassWithLogger"), 1); + BOOST_CHECK_EQUAL(names.count("ndn.util.tests.AbstractClassWithLogger"), 1); + BOOST_CHECK_EQUAL(names.count("ndn.util.tests.Specialized1"), 1); + BOOST_CHECK_EQUAL(names.count("ndn.util.tests.Specialized2"), 1); + + ClassWithLogger::logFromStaticMemberFunction(); + ClassWithLogger{}.logFromConstMemberFunction(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " INFO: [ndn.util.tests.ClassWithLogger] static member function\n" + + LOG_SYSTIME_STR + " INFO: [ndn.util.tests.ClassWithLogger] const member function\n" + )); + + DerivedClass{}.logFromConstMemberFunction(); + DerivedClass{}.logFromVirtualFunction(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " INFO: [ndn.util.tests.AbstractClassWithLogger] const member function\n" + + LOG_SYSTIME_STR + " INFO: [ndn.util.tests.AbstractClassWithLogger] overridden virtual function\n" + )); + + ClassTemplateWithLogger::logFromStaticMemberFunction(); + ClassTemplateWithLogger{}.logFromMemberFunction(); + ClassTemplateWithLogger::logFromStaticMemberFunction(); + ClassTemplateWithLogger{}.logFromMemberFunction(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " INFO: [ndn.util.tests.Specialized1] class template static member function\n" + + LOG_SYSTIME_STR + " INFO: [ndn.util.tests.Specialized1] class template non-static member function\n" + )); +} + +BOOST_AUTO_TEST_CASE(SameNameLoggers) +{ + Logging::setLevel("Module1", LogLevel::WARN); + logFromModule1(); + logFromNewLogger("Module1"); + + BOOST_CHECK_EQUAL(Logging::getLoggerNames().count("Module1"), 1); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" + + LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + + LOG_SYSTIME_STR + " WARN: [Module1] warnModule1\n" + + LOG_SYSTIME_STR + " ERROR: [Module1] errorModule1\n" + + LOG_SYSTIME_STR + " FATAL: [Module1] fatalModule1\n" + )); +} + +BOOST_AUTO_TEST_CASE(LateRegistration) +{ + Logging::setLevel("Module3", LogLevel::DEBUG); + logFromNewLogger("Module3"); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " DEBUG: [Module3] debugModule3\n" + + LOG_SYSTIME_STR + " INFO: [Module3] infoModule3\n" + + LOG_SYSTIME_STR + " WARN: [Module3] warnModule3\n" + + LOG_SYSTIME_STR + " ERROR: [Module3] errorModule3\n" + + LOG_SYSTIME_STR + " FATAL: [Module3] fatalModule3\n" + )); +} + +BOOST_AUTO_TEST_SUITE(DefaultSeverity) + +BOOST_AUTO_TEST_CASE(Unset) +{ + logFromModule1(); + logFromModule2(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + + LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" + )); +} + +BOOST_AUTO_TEST_CASE(NoOverride) +{ + Logging::setLevel("*", LogLevel::WARN); + logFromModule1(); + logFromModule2(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" + + LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + + LOG_SYSTIME_STR + " WARN: [Module2] warn2\n" + + LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" + + LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" + )); +} + +BOOST_AUTO_TEST_CASE(Override) +{ + Logging::setLevel("*", LogLevel::WARN); + Logging::setLevel("Module2", LogLevel::DEBUG); + logFromModule1(); + logFromModule2(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" + + LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + + LOG_SYSTIME_STR + " DEBUG: [Module2] debug2\n" + + LOG_SYSTIME_STR + " INFO: [Module2] info2\n" + + LOG_SYSTIME_STR + " WARN: [Module2] warn2\n" + + LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" + + LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" + )); +} + +BOOST_AUTO_TEST_SUITE_END() // DefaultSeverity + +BOOST_AUTO_TEST_SUITE(SeverityConfig) + +BOOST_AUTO_TEST_CASE(SetEmpty) +{ + Logging::setLevel(""); + const auto& prefixMap = Logging::get().getLevels(); + BOOST_CHECK_EQUAL(prefixMap.size(), 0); + logFromModule1(); + logFromModule2(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + + LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" + )); +} + +BOOST_AUTO_TEST_CASE(SetDefault) +{ + Logging::setLevel("*=WARN"); + const auto& prefixMap = Logging::get().getLevels(); + // "*" is treated as "" internally + BOOST_CHECK_EQUAL(prefixMap.size(), 1); + BOOST_CHECK_EQUAL(prefixMap.at(""), LogLevel::WARN); + logFromModule1(); + logFromModule2(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" + + LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + + LOG_SYSTIME_STR + " WARN: [Module2] warn2\n" + + LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" + + LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" + )); +} + +BOOST_AUTO_TEST_CASE(SetModule) +{ + Logging::setLevel("Module1=ERROR"); + const auto& prefixMap = Logging::get().getLevels(); + BOOST_CHECK_EQUAL(prefixMap.size(), 1); + BOOST_CHECK_EQUAL(prefixMap.at("Module1"), LogLevel::ERROR); + logFromModule1(); + logFromModule2(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + + LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" + )); +} + +BOOST_AUTO_TEST_CASE(SetOverride) +{ + Logging::setLevel("*=WARN:Module2=DEBUG"); + const auto& prefixMap = Logging::get().getLevels(); + BOOST_CHECK_EQUAL(prefixMap.size(), 2); + // "*" is treated as "" internally + BOOST_CHECK_EQUAL(prefixMap.at(""), LogLevel::WARN); + BOOST_CHECK_EQUAL(prefixMap.at("Module2"), LogLevel::DEBUG); + logFromModule1(); + logFromModule2(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" + + LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + + LOG_SYSTIME_STR + " DEBUG: [Module2] debug2\n" + + LOG_SYSTIME_STR + " INFO: [Module2] info2\n" + + LOG_SYSTIME_STR + " WARN: [Module2] warn2\n" + + LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" + + LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" + )); +} + +BOOST_AUTO_TEST_CASE(SetTwice) +{ + Logging::setLevel("*=WARN"); + Logging::setLevel("Module2=DEBUG"); + const auto& prefixMap = Logging::get().getLevels(); + BOOST_CHECK_EQUAL(prefixMap.size(), 2); + // "*" is treated as "" internally + BOOST_CHECK_EQUAL(prefixMap.at(""), LogLevel::WARN); + BOOST_CHECK_EQUAL(prefixMap.at("Module2"), LogLevel::DEBUG); + logFromModule1(); + logFromModule2(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" + + LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + + LOG_SYSTIME_STR + " DEBUG: [Module2] debug2\n" + + LOG_SYSTIME_STR + " INFO: [Module2] info2\n" + + LOG_SYSTIME_STR + " WARN: [Module2] warn2\n" + + LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" + + LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" + )); +} + +BOOST_AUTO_TEST_CASE(Reset) +{ + Logging::setLevel("Module2=DEBUG"); + Logging::setLevel("*=ERROR"); + const auto& prefixMap = Logging::get().getLevels(); + BOOST_CHECK_EQUAL(prefixMap.size(), 1); + // "*" is treated as "" internally + BOOST_CHECK_EQUAL(prefixMap.at(""), LogLevel::ERROR); + logFromModule1(); + logFromModule2(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" + + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + + LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" + + LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" + )); +} + +BOOST_AUTO_TEST_CASE(Malformed) +{ + BOOST_CHECK_THROW(Logging::setLevel("Module1=INVALID-LEVEL"), std::invalid_argument); + BOOST_CHECK_THROW(Logging::setLevel("Module1-MISSING-EQUAL-SIGN"), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(SetFilter) +{ + Logging::setLevel("*=FATAL:fm.*=DEBUG"); + const auto& prefixMap = Logging::get().getLevels(); + BOOST_CHECK_EQUAL(prefixMap.size(), 2); + // "*" is treated as "" internally + BOOST_CHECK_EQUAL(prefixMap.at(""), LogLevel::FATAL); + // "name.*" is treated as "name." internally + BOOST_CHECK_EQUAL(prefixMap.at("fm."), LogLevel::DEBUG); + logFromModule1(); + logFromFilterModule(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + + LOG_SYSTIME_STR + " DEBUG: [fm.FilterModule] debugFM\n" + + LOG_SYSTIME_STR + " INFO: [fm.FilterModule] infoFM\n" + + LOG_SYSTIME_STR + " WARN: [fm.FilterModule] warnFM\n" + + LOG_SYSTIME_STR + " ERROR: [fm.FilterModule] errorFM\n" + + LOG_SYSTIME_STR + " FATAL: [fm.FilterModule] fatalFM\n" + )); +} + +BOOST_AUTO_TEST_CASE(SetOverrideFilter) +{ + Logging::setLevel("*=FATAL:fm.FilterModule=DEBUG"); + Logging::setLevel("fm.*", LogLevel::INFO); + const auto& prefixMap = Logging::get().getLevels(); + BOOST_CHECK_EQUAL(prefixMap.size(), 2); + // "*" is treated as "" internally + BOOST_CHECK_EQUAL(prefixMap.at(""), LogLevel::FATAL); + // "name.*" is treated as "name." internally + BOOST_CHECK_EQUAL(prefixMap.at("fm."), LogLevel::INFO); + logFromModule1(); + logFromFilterModule(); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + + LOG_SYSTIME_STR + " INFO: [fm.FilterModule] infoFM\n" + + LOG_SYSTIME_STR + " WARN: [fm.FilterModule] warnFM\n" + + LOG_SYSTIME_STR + " ERROR: [fm.FilterModule] errorFM\n" + + LOG_SYSTIME_STR + " FATAL: [fm.FilterModule] fatalFM\n" + )); +} + +BOOST_AUTO_TEST_CASE(FindPrefixRule) +{ + Logging::setLevel("*=FATAL:fm.a.*=ERROR:fm.a.b=INFO"); + logFromNewLogger("fm.a.b"); + logFromNewLogger("fm.a.b.c"); + logFromNewLogger("fm.a.b.d"); + logFromNewLogger("fm.b"); + + Logging::flush(); + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " INFO: [fm.a.b] infofm.a.b\n" + + LOG_SYSTIME_STR + " WARN: [fm.a.b] warnfm.a.b\n" + + LOG_SYSTIME_STR + " ERROR: [fm.a.b] errorfm.a.b\n" + + LOG_SYSTIME_STR + " FATAL: [fm.a.b] fatalfm.a.b\n" + + LOG_SYSTIME_STR + " ERROR: [fm.a.b.c] errorfm.a.b.c\n" + + LOG_SYSTIME_STR + " FATAL: [fm.a.b.c] fatalfm.a.b.c\n" + + LOG_SYSTIME_STR + " ERROR: [fm.a.b.d] errorfm.a.b.d\n" + + LOG_SYSTIME_STR + " FATAL: [fm.a.b.d] fatalfm.a.b.d\n" + + LOG_SYSTIME_STR + " FATAL: [fm.b] fatalfm.b\n" + )); +} + +BOOST_AUTO_TEST_SUITE_END() // SeverityConfig + +BOOST_AUTO_TEST_CASE(ChangeDestination) +{ + using boost::test_tools::output_test_stream; + + logFromModule1(); + + auto os2 = make_shared(); + Logging::setDestination(Logging::makeDefaultStreamDestination(os2)); + weak_ptr os2weak(os2); + os2.reset(); + + logFromModule2(); + + Logging::flush(); + os2 = os2weak.lock(); + BOOST_REQUIRE(os2 != nullptr); + + BOOST_CHECK(os.is_equal( + LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" + )); + BOOST_CHECK(os2->is_equal( + LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n" + )); + + os2.reset(); + Logging::setDestination(os); + BOOST_CHECK(os2weak.expired()); +} + +BOOST_AUTO_TEST_CASE(NullDestination) +{ + Logging::setDestination(nullptr); + logFromModule1(); + + Logging::flush(); + BOOST_CHECK(os.is_equal("")); + // The default Boost.Log output is still expected +} + +BOOST_AUTO_TEST_SUITE_END() // TestLogging +BOOST_AUTO_TEST_SUITE_END() // Util + +} // namespace tests +} // namespace util +} // namespace ndn diff --git a/tests/unit/util/notification-stream.t.cpp b/tests/unit/util/notification-stream.t.cpp new file mode 100644 index 000000000..ada10c5e1 --- /dev/null +++ b/tests/unit/util/notification-stream.t.cpp @@ -0,0 +1,76 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014-2018 Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/notification-stream.hpp" +#include "ndn-cxx/util/dummy-client-face.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/identity-management-time-fixture.hpp" +#include "tests/unit/util/simple-notification.hpp" + +namespace ndn { +namespace util { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Util) +BOOST_FIXTURE_TEST_SUITE(TestNotificationStream, ndn::tests::IdentityManagementTimeFixture) + +BOOST_AUTO_TEST_CASE(Post) +{ + DummyClientFace face(io, m_keyChain); + util::NotificationStream notificationStream(face, + "/localhost/nfd/NotificationStreamTest", m_keyChain); + + SimpleNotification event1("msg1"); + notificationStream.postNotification(event1); + + advanceClocks(1_ms); + + BOOST_REQUIRE_EQUAL(face.sentData.size(), 1); + BOOST_CHECK_EQUAL(face.sentData[0].getName(), "/localhost/nfd/NotificationStreamTest/%FE%00"); + SimpleNotification decoded1; + BOOST_CHECK_NO_THROW(decoded1.wireDecode(face.sentData[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(decoded1.getMessage(), "msg1"); + + SimpleNotification event2("msg2"); + notificationStream.postNotification(event2); + + advanceClocks(1_ms); + + BOOST_REQUIRE_EQUAL(face.sentData.size(), 2); + BOOST_CHECK_EQUAL(face.sentData[1].getName(), "/localhost/nfd/NotificationStreamTest/%FE%01"); + SimpleNotification decoded2; + BOOST_CHECK_NO_THROW(decoded2.wireDecode(face.sentData[1].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(decoded2.getMessage(), "msg2"); +} + +BOOST_AUTO_TEST_SUITE_END() // TestNotificationStream +BOOST_AUTO_TEST_SUITE_END() // Util + +} // namespace tests +} // namespace util +} // namespace ndn diff --git a/tests/unit-tests/util/notification-subscriber.t.cpp b/tests/unit/util/notification-subscriber.t.cpp similarity index 85% rename from tests/unit-tests/util/notification-subscriber.t.cpp rename to tests/unit/util/notification-subscriber.t.cpp index 309afadd9..e3b7aa9b1 100644 --- a/tests/unit-tests/util/notification-subscriber.t.cpp +++ b/tests/unit/util/notification-subscriber.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California, +/* + * Copyright (c) 2014-2019 Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -25,13 +25,13 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "util/notification-subscriber.hpp" -#include "simple-notification.hpp" -#include "util/dummy-client-face.hpp" +#include "ndn-cxx/util/notification-subscriber.hpp" +#include "ndn-cxx/util/dummy-client-face.hpp" -#include "../identity-management-time-fixture.hpp" -#include "../make-interest-data.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" +#include "tests/unit/identity-management-time-fixture.hpp" +#include "tests/unit/util/simple-notification.hpp" namespace ndn { namespace util { @@ -45,7 +45,7 @@ class NotificationSubscriberFixture : public IdentityManagementTimeFixture NotificationSubscriberFixture() : streamPrefix("ndn:/NotificationSubscriberTest") , subscriberFace(io, m_keyChain) - , subscriber(subscriberFace, streamPrefix, time::seconds(1)) + , subscriber(subscriberFace, streamPrefix, 1_s) , nextSendNotificationNo(0) { } @@ -61,10 +61,10 @@ class NotificationSubscriberFixture : public IdentityManagementTimeFixture dataName.appendSequenceNumber(nextSendNotificationNo); Data data(dataName); data.setContent(notification.wireEncode()); - data.setFreshnessPeriod(time::seconds(1)); + data.setFreshnessPeriod(1_s); m_keyChain.sign(data); - lastDeliveredSeqNo = nextSendNotificationNo; + lastDeliveredSeqNum = nextSendNotificationNo; lastNotification.setMessage(""); ++nextSendNotificationNo; subscriberFace.receive(data); @@ -133,7 +133,7 @@ class NotificationSubscriberFixture : public IdentityManagementTimeFixture const Interest& interest = subscriberFace.sentInterests[0]; return interest.getName() == streamPrefix && - interest.getChildSelector() == 1 && + interest.getCanBePrefix() && interest.getMustBeFresh() && interest.getInterestLifetime() == subscriber.getInterestLifetime(); } @@ -142,7 +142,7 @@ class NotificationSubscriberFixture : public IdentityManagementTimeFixture * or 0 if there's no such request as sole sent Interest */ uint64_t - getRequestSeqNo() const + getRequestSeqNum() const { if (subscriberFace.sentInterests.size() != 1) return 0; @@ -164,7 +164,7 @@ class NotificationSubscriberFixture : public IdentityManagementTimeFixture util::signal::Connection notificationConn; util::signal::Connection nackConn; uint64_t nextSendNotificationNo; - uint64_t lastDeliveredSeqNo; + uint64_t lastDeliveredSeqNum; SimpleNotification lastNotification; lp::Nack lastNack; bool hasTimeout; @@ -185,7 +185,7 @@ BOOST_AUTO_TEST_CASE(StartStop) this->connectHandlers(); subscriber.start(); BOOST_REQUIRE_EQUAL(subscriber.isRunning(), true); - advanceClocks(time::milliseconds(1)); + advanceClocks(1_ms); BOOST_CHECK(this->hasInitialRequest()); subscriberFace.sentInterests.clear(); @@ -198,38 +198,38 @@ BOOST_AUTO_TEST_CASE(Notifications) { this->connectHandlers(); subscriber.start(); - advanceClocks(time::milliseconds(1)); + advanceClocks(1_ms); // respond to initial request subscriberFace.sentInterests.clear(); this->deliverNotification("n1"); - advanceClocks(time::milliseconds(1)); + advanceClocks(1_ms); BOOST_CHECK_EQUAL(lastNotification.getMessage(), "n1"); - BOOST_CHECK_EQUAL(this->getRequestSeqNo(), lastDeliveredSeqNo + 1); + BOOST_CHECK_EQUAL(this->getRequestSeqNum(), lastDeliveredSeqNum + 1); // respond to continuation request subscriberFace.sentInterests.clear(); this->deliverNotification("n2"); - advanceClocks(time::milliseconds(1)); + advanceClocks(1_ms); BOOST_CHECK_EQUAL(lastNotification.getMessage(), "n2"); - BOOST_CHECK_EQUAL(this->getRequestSeqNo(), lastDeliveredSeqNo + 1); + BOOST_CHECK_EQUAL(this->getRequestSeqNum(), lastDeliveredSeqNum + 1); } BOOST_AUTO_TEST_CASE(Nack) { this->connectHandlers(); subscriber.start(); - advanceClocks(time::milliseconds(1)); + advanceClocks(1_ms); // send the first Nack to initial request BOOST_REQUIRE_EQUAL(subscriberFace.sentInterests.size(), 1); Interest interest = subscriberFace.sentInterests[0]; subscriberFace.sentInterests.clear(); this->deliverNack(interest, lp::NackReason::CONGESTION); - advanceClocks(time::milliseconds(1)); + advanceClocks(1_ms); BOOST_CHECK_EQUAL(lastNack.getReason(), lp::NackReason::CONGESTION); BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), false); - advanceClocks(time::milliseconds(300)); + advanceClocks(300_ms); BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), true); // send the second Nack to initial request @@ -237,25 +237,25 @@ BOOST_AUTO_TEST_CASE(Nack) interest = subscriberFace.sentInterests[0]; subscriberFace.sentInterests.clear(); this->deliverNack(interest, lp::NackReason::CONGESTION); - advanceClocks(time::milliseconds(301)); + advanceClocks(301_ms); BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), false); - advanceClocks(time::milliseconds(200)); + advanceClocks(200_ms); BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), true); // send a notification to initial request subscriberFace.sentInterests.clear(); this->deliverNotification("n1"); - advanceClocks(time::milliseconds(1)); + advanceClocks(1_ms); // send a Nack to subsequent request BOOST_REQUIRE_EQUAL(subscriberFace.sentInterests.size(), 1); interest = subscriberFace.sentInterests[0]; subscriberFace.sentInterests.clear(); this->deliverNack(interest, lp::NackReason::CONGESTION); - advanceClocks(time::milliseconds(1)); + advanceClocks(1_ms); BOOST_CHECK_EQUAL(lastNack.getReason(), lp::NackReason::CONGESTION); BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), false); - advanceClocks(time::milliseconds(300)); + advanceClocks(300_ms); BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), true); } @@ -263,7 +263,7 @@ BOOST_AUTO_TEST_CASE(Timeout) { this->connectHandlers(); subscriber.start(); - advanceClocks(time::milliseconds(1)); + advanceClocks(1_ms); subscriberFace.sentInterests.clear(); lastNotification.setMessage(""); @@ -274,7 +274,7 @@ BOOST_AUTO_TEST_CASE(Timeout) subscriberFace.sentInterests.clear(); this->deliverNotification("n1"); - advanceClocks(time::milliseconds(1)); + advanceClocks(1_ms); BOOST_CHECK_EQUAL(lastNotification.getMessage(), "n1"); } @@ -282,16 +282,17 @@ BOOST_AUTO_TEST_CASE(SequenceError) { this->connectHandlers(); subscriber.start(); - advanceClocks(time::milliseconds(1)); + advanceClocks(1_ms); Name wrongName = streamPrefix; wrongName.append("%07%07"); Data wrongData(wrongName); + wrongData.setFreshnessPeriod(1_s); m_keyChain.sign(wrongData); subscriberFace.receive(wrongData); subscriberFace.sentInterests.clear(); lastNotification.setMessage(""); - advanceClocks(time::milliseconds(1)); + advanceClocks(1_ms); BOOST_CHECK(lastNotification.getMessage().empty()); BOOST_CHECK_EQUAL(lastDecodeErrorData.getName(), wrongName); BOOST_CHECK(this->hasInitialRequest()); @@ -301,12 +302,12 @@ BOOST_AUTO_TEST_CASE(PayloadError) { this->connectHandlers(); subscriber.start(); - advanceClocks(time::milliseconds(1)); + advanceClocks(1_ms); subscriberFace.sentInterests.clear(); lastNotification.setMessage(""); this->deliverNotification("\x07n4"); - advanceClocks(time::milliseconds(1)); + advanceClocks(1_ms); BOOST_CHECK(lastNotification.getMessage().empty()); BOOST_CHECK(this->hasInitialRequest()); } diff --git a/tests/unit-tests/util/placeholders.t.cpp b/tests/unit/util/placeholders.t.cpp similarity index 87% rename from tests/unit-tests/util/placeholders.t.cpp rename to tests/unit/util/placeholders.t.cpp index 032b088b3..16dece5cc 100644 --- a/tests/unit-tests/util/placeholders.t.cpp +++ b/tests/unit/util/placeholders.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,11 +22,11 @@ // Bug 2109 test case // interest.hpp includes common.hpp; common.hpp shouldn't be used from external program -#include "interest.hpp" +#include "ndn-cxx/interest.hpp" -// validator-config.hpp indirectly includes +// util/config-file.hpp indirectly includes // which in turn imports Boost placeholders -#include "security/validator-config.hpp" +#include "ndn-cxx/util/config-file.hpp" // It's intentional to write "using namespace", // to simulate an external program linked against ndn-cxx. diff --git a/tests/unit-tests/util/placeholders2.t.cpp b/tests/unit/util/placeholders2.t.cpp similarity index 92% rename from tests/unit-tests/util/placeholders2.t.cpp rename to tests/unit/util/placeholders2.t.cpp index ada739aa7..d8b8c935c 100644 --- a/tests/unit-tests/util/placeholders2.t.cpp +++ b/tests/unit/util/placeholders2.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -22,7 +22,7 @@ // Bug 2109 test case // interest.hpp includes common.hpp; common.hpp shouldn't be used from external program -#include "interest.hpp" +#include "ndn-cxx/interest.hpp" #include diff --git a/tests/unit/util/random.t.cpp b/tests/unit/util/random.t.cpp new file mode 100644 index 000000000..c81c09e05 --- /dev/null +++ b/tests/unit/util/random.t.cpp @@ -0,0 +1,135 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/random.hpp" +#include "ndn-cxx/security/impl/openssl.hpp" + +#include "tests/boost-test.hpp" + +#include +#include + +namespace ndn { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Util) +BOOST_AUTO_TEST_SUITE(TestRandom) + +BOOST_AUTO_TEST_CASE(ThreadLocalEngine) +{ + random::RandomNumberEngine* r1 = &random::getRandomNumberEngine(); + random::RandomNumberEngine* r2 = nullptr; + std::thread t([&r2] { r2 = &random::getRandomNumberEngine(); }); + t.join(); + random::RandomNumberEngine* r3 = &random::getRandomNumberEngine(); + + BOOST_CHECK(r2 != nullptr); + BOOST_CHECK_NE(r1, r2); + BOOST_CHECK_EQUAL(r1, r3); +} + +// This fixture uses OpenSSL routines to set a dummy random generator that always fails +class FailRandMethodFixture +{ +public: + FailRandMethodFixture() + : m_dummyRandMethod{&FailRandMethodFixture::seed, + &FailRandMethodFixture::bytes, + &FailRandMethodFixture::cleanup, + &FailRandMethodFixture::add, + &FailRandMethodFixture::pseudorand, + &FailRandMethodFixture::status} + { + m_origRandMethod = RAND_get_rand_method(); + RAND_set_rand_method(&m_dummyRandMethod); + } + + ~FailRandMethodFixture() + { + RAND_set_rand_method(m_origRandMethod); + } + +private: // RAND_METHOD callbacks +#if OPENSSL_VERSION_NUMBER < 0x1010000fL + static void + seed(const void* buf, int num) + { + } +#else + static int + seed(const void* buf, int num) + { + return 0; + } +#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL + + static int + bytes(unsigned char* buf, int num) + { + return 0; + } + + static void + cleanup() + { + } + +#if OPENSSL_VERSION_NUMBER < 0x1010000fL + static void + add(const void* buf, int num, double entropy) + { + } +#else + static int + add(const void* buf, int num, double entropy) + { + return 0; + } +#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL + + static int + pseudorand(unsigned char* buf, int num) + { + return 0; + } + + static int + status() + { + return 0; + } + +private: + const RAND_METHOD* m_origRandMethod; + RAND_METHOD m_dummyRandMethod; +}; + +BOOST_FIXTURE_TEST_CASE(Error, FailRandMethodFixture) +{ + std::array buf; + BOOST_CHECK_THROW(random::generateSecureBytes(buf.data(), buf.size()), std::runtime_error); +} + +BOOST_AUTO_TEST_SUITE_END() // TestRandom +BOOST_AUTO_TEST_SUITE_END() // Util + +} // namespace tests +} // namespace ndn diff --git a/tests/unit-tests/util/regex.t.cpp b/tests/unit/util/regex.t.cpp similarity index 94% rename from tests/unit-tests/util/regex.t.cpp rename to tests/unit/util/regex.t.cpp index fc46c23ea..2804cc463 100644 --- a/tests/unit-tests/util/regex.t.cpp +++ b/tests/unit/util/regex.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -21,16 +21,16 @@ * @author Yingdi Yu */ -#include "util/regex/regex-backref-manager.hpp" -#include "util/regex/regex-component-matcher.hpp" -#include "util/regex/regex-component-set-matcher.hpp" -#include "util/regex/regex-pattern-list-matcher.hpp" -#include "util/regex/regex-repeat-matcher.hpp" -#include "util/regex/regex-backref-matcher.hpp" -#include "util/regex/regex-top-matcher.hpp" -#include "util/regex.hpp" +#include "ndn-cxx/util/regex.hpp" +#include "ndn-cxx/util/regex/regex-backref-manager.hpp" +#include "ndn-cxx/util/regex/regex-backref-matcher.hpp" +#include "ndn-cxx/util/regex/regex-component-matcher.hpp" +#include "ndn-cxx/util/regex/regex-component-set-matcher.hpp" +#include "ndn-cxx/util/regex/regex-pattern-list-matcher.hpp" +#include "ndn-cxx/util/regex/regex-repeat-matcher.hpp" +#include "ndn-cxx/util/regex/regex-top-matcher.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace tests { @@ -111,7 +111,7 @@ BOOST_AUTO_TEST_CASE(RepeatMatcher) BOOST_CHECK_EQUAL(res, true); BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 0); - cm->match(Name("/a/b/c"), 0, 2); + res = cm->match(Name("/a/b/c"), 0, 2); BOOST_CHECK_EQUAL(res, true); BOOST_CHECK_EQUAL(cm->getMatchResult().size(), 2); BOOST_CHECK_EQUAL(cm->getMatchResult()[0].toUri(), string("a")); @@ -439,6 +439,23 @@ BOOST_AUTO_TEST_CASE(TopMatcherAdvanced) BOOST_CHECK_EQUAL(cm->expand(), Name("/ndn/edu/ucla/yingdi/mac/")); } +BOOST_AUTO_TEST_CASE(RegexBackrefManagerMemoryLeak) +{ + auto re = make_unique("^(<>)$"); + + weak_ptr m1(re->m_primaryMatcher); + weak_ptr m2(re->m_secondaryMatcher); + weak_ptr b1(re->m_primaryBackrefManager); + weak_ptr b2(re->m_secondaryBackrefManager); + + re.reset(); + + BOOST_CHECK_EQUAL(m1.use_count(), 0); + BOOST_CHECK_EQUAL(m2.use_count(), 0); + BOOST_CHECK_EQUAL(b1.use_count(), 0); + BOOST_CHECK_EQUAL(b2.use_count(), 0); +} + BOOST_AUTO_TEST_SUITE_END() // TestRegex BOOST_AUTO_TEST_SUITE_END() // Util diff --git a/tests/unit/util/rtt-estimator.t.cpp b/tests/unit/util/rtt-estimator.t.cpp new file mode 100644 index 000000000..b819c9b6e --- /dev/null +++ b/tests/unit/util/rtt-estimator.t.cpp @@ -0,0 +1,173 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2016-2019, Regents of the University of California, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/rtt-estimator.hpp" + +#include "tests/boost-test.hpp" + +#include + +namespace ndn { +namespace util { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Util) +BOOST_AUTO_TEST_SUITE(TestRttEstimator) + +BOOST_AUTO_TEST_CASE(CopyAssign) +{ + RttEstimator est1; + RttEstimator est2; + + est1.addMeasurement(100_ms); + est1.addMeasurement(150_ms); + est2.addMeasurement(75_ms); + est2.addMeasurement(70_ms); + + BOOST_CHECK_NE(est1.getEstimatedRto(), est2.getEstimatedRto()); + BOOST_CHECK_NE(est1.getRttVariation(), est2.getRttVariation()); + BOOST_CHECK_NE(est1.getSmoothedRtt(), est2.getSmoothedRtt()); + + est1 = est2; + + BOOST_CHECK_EQUAL(est1.getEstimatedRto(), est2.getEstimatedRto()); + BOOST_CHECK_EQUAL(est1.getRttVariation(), est2.getRttVariation()); + BOOST_CHECK_EQUAL(est1.getSmoothedRtt(), est2.getSmoothedRtt()); +} + +BOOST_AUTO_TEST_CASE(EstimatedRto) +{ + auto opts = make_shared(); + opts->initialRto = 400_ms; + opts->maxRto = 2_s; + RttEstimator rttEstimator(opts); + + // check initial values + BOOST_CHECK_EQUAL(rttEstimator.hasSamples(), false); + BOOST_CHECK_EQUAL(rttEstimator.getSmoothedRtt(), -1_ns); + BOOST_CHECK_EQUAL(rttEstimator.getRttVariation(), -1_ns); + BOOST_CHECK_EQUAL(rttEstimator.getEstimatedRto(), opts->initialRto); + + // first measurement + rttEstimator.addMeasurement(200_ms); + + BOOST_CHECK_EQUAL(rttEstimator.hasSamples(), true); + BOOST_CHECK_EQUAL(rttEstimator.getSmoothedRtt(), 200_ms); + BOOST_CHECK_EQUAL(rttEstimator.getRttVariation(), 100_ms); + BOOST_CHECK_EQUAL(rttEstimator.getEstimatedRto(), 600_ms); + + rttEstimator.addMeasurement(100_ms, 1); + + BOOST_CHECK_EQUAL(rttEstimator.hasSamples(), true); + BOOST_CHECK_EQUAL(rttEstimator.getSmoothedRtt(), 187500_us); + BOOST_CHECK_EQUAL(rttEstimator.getRttVariation(), 100000_us); + BOOST_CHECK_EQUAL(rttEstimator.getEstimatedRto(), 587500_us); + + // expected samples larger than 1 + rttEstimator.addMeasurement(50_ms, 5); + + BOOST_CHECK_EQUAL(rttEstimator.hasSamples(), true); + BOOST_CHECK_EQUAL(rttEstimator.getSmoothedRtt(), 184062500_ns); + BOOST_CHECK_EQUAL(rttEstimator.getRttVariation(), 101875000_ns); + BOOST_CHECK_EQUAL(rttEstimator.getEstimatedRto(), 591562500_ns); + + // check if minRto works + for (int i = 0; i < 20; i++) { + rttEstimator.addMeasurement(10_ms); + } + + BOOST_CHECK_EQUAL(rttEstimator.getSmoothedRtt(), 22046646_ns); + BOOST_CHECK_EQUAL(rttEstimator.getEstimatedRto(), opts->minRto); + + // check if maxRto works + for (int i = 0; i < 10; i++) { + rttEstimator.addMeasurement(1_s); + rttEstimator.addMeasurement(10_ms); + } + + BOOST_CHECK_EQUAL(rttEstimator.getSmoothedRtt(), 440859284_ns); + BOOST_CHECK_EQUAL(rttEstimator.getEstimatedRto(), opts->maxRto); +} + +BOOST_AUTO_TEST_CASE(BackoffRto) +{ + auto opts = make_shared(); + opts->initialRto = 500_ms; + opts->maxRto = 4_s; + RttEstimator rttEstimator(opts); + + rttEstimator.backoffRto(); + BOOST_CHECK_EQUAL(rttEstimator.getEstimatedRto(), 1_s); + + // check if minRto works + for (int i = 0; i < 10; i++) { + rttEstimator.addMeasurement(5_ms); + } + rttEstimator.backoffRto(); + BOOST_CHECK_EQUAL(rttEstimator.getEstimatedRto(), 400_ms); + + // check if maxRto works + for (int i = 0; i < 10; i++) { + rttEstimator.addMeasurement(5_s); + } + rttEstimator.backoffRto(); + BOOST_CHECK_EQUAL(rttEstimator.getEstimatedRto(), 4_s); +} + +BOOST_AUTO_TEST_CASE(Stats) +{ + RttEstimatorWithStats rttEstimator; + + // check initial values + BOOST_CHECK_EQUAL(rttEstimator.getMinRtt().count(), std::numeric_limits::max()); + BOOST_CHECK_EQUAL(rttEstimator.getAvgRtt().count(), 0); + BOOST_CHECK_EQUAL(rttEstimator.getMaxRtt().count(), std::numeric_limits::min()); + + // start with three samples + rttEstimator.addMeasurement(100_ms); + rttEstimator.addMeasurement(400_ms); + rttEstimator.addMeasurement(250_ms); + + BOOST_CHECK_EQUAL(rttEstimator.getMinRtt(), 100_ms); + BOOST_CHECK_EQUAL(rttEstimator.getAvgRtt(), 250_ms); + BOOST_CHECK_EQUAL(rttEstimator.getMaxRtt(), 400_ms); + + // add another sample (new minimum) + rttEstimator.addMeasurement(50_ms, 2); + BOOST_CHECK_EQUAL(rttEstimator.getMinRtt(), 50_ms); + BOOST_CHECK_EQUAL(rttEstimator.getAvgRtt(), 200_ms); + BOOST_CHECK_EQUAL(rttEstimator.getMaxRtt(), 400_ms); + + // add another sample (new maximum) + rttEstimator.addMeasurement(700_ms, 1); + BOOST_CHECK_EQUAL(rttEstimator.getMinRtt(), 50_ms); + BOOST_CHECK_EQUAL(rttEstimator.getAvgRtt(), 300_ms); + BOOST_CHECK_EQUAL(rttEstimator.getMaxRtt(), 700_ms); +} + +BOOST_AUTO_TEST_SUITE_END() // TestRttEstimator +BOOST_AUTO_TEST_SUITE_END() // Util + +} // namespace tests +} // namespace util +} // namespace ndn diff --git a/tests/unit/util/scheduler.t.cpp b/tests/unit/util/scheduler.t.cpp new file mode 100644 index 000000000..021c1f0ac --- /dev/null +++ b/tests/unit/util/scheduler.t.cpp @@ -0,0 +1,396 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/scheduler.hpp" + +#include "tests/boost-test.hpp" +#include "tests/unit/unit-test-time-fixture.hpp" + +#include + +namespace ndn { +namespace scheduler { +namespace tests { + +class SchedulerFixture : public ndn::tests::UnitTestTimeFixture +{ +public: + SchedulerFixture() + : scheduler(io) + { + } + +public: + Scheduler scheduler; +}; + +BOOST_AUTO_TEST_SUITE(Util) +BOOST_FIXTURE_TEST_SUITE(TestScheduler, SchedulerFixture) + +BOOST_AUTO_TEST_SUITE(General) + +BOOST_AUTO_TEST_CASE(Events) +{ + size_t count1 = 0; + size_t count2 = 0; + + scheduler.schedule(500_ms, [&] { + ++count1; + BOOST_CHECK_EQUAL(count2, 1); + }); + + EventId i = scheduler.schedule(1_s, [] { BOOST_ERROR("This event should not have been fired"); }); + i.cancel(); + + scheduler.schedule(250_ms, [&] { + BOOST_CHECK_EQUAL(count1, 0); + ++count2; + }); + + i = scheduler.schedule(50_ms, [&] { BOOST_ERROR("This event should not have been fired"); }); + i.cancel(); + + advanceClocks(25_ms, 1000_ms); + BOOST_CHECK_EQUAL(count1, 1); + BOOST_CHECK_EQUAL(count2, 1); +} + +BOOST_AUTO_TEST_CASE(CallbackException) +{ + class MyException : public std::exception + { + }; + scheduler.schedule(10_ms, [] { + // use plain 'throw' to ensure that Scheduler does not depend on the + // internal machinery of NDN_THROW and that it can catch all exceptions + // regardless of how they are thrown by the application + throw MyException{}; + }); + + bool isCallbackInvoked = false; + scheduler.schedule(20_ms, [&isCallbackInvoked] { isCallbackInvoked = true; }); + + BOOST_CHECK_THROW(this->advanceClocks(6_ms, 2), MyException); + this->advanceClocks(6_ms, 2); + BOOST_CHECK(isCallbackInvoked); +} + +BOOST_AUTO_TEST_CASE(CancelEmptyEvent) +{ + EventId i; + i.cancel(); + + // avoid "test case [...] did not check any assertions" message from Boost.Test + BOOST_CHECK(true); +} + +BOOST_AUTO_TEST_CASE(SelfCancel) +{ + EventId selfEventId; + selfEventId = scheduler.schedule(100_ms, [&] { selfEventId.cancel(); }); + BOOST_REQUIRE_NO_THROW(advanceClocks(100_ms, 10)); +} + +class SelfRescheduleFixture : public SchedulerFixture +{ +public: + void + reschedule() + { + EventId eventId = scheduler.schedule(100_ms, bind(&SelfRescheduleFixture::reschedule, this)); + selfEventId.cancel(); + selfEventId = eventId; + + if (count < 5) + count++; + else + selfEventId.cancel(); + } + + void + reschedule2() + { + selfEventId.cancel(); + + if (count < 5) { + selfEventId = scheduler.schedule(100_ms, bind(&SelfRescheduleFixture::reschedule2, this)); + count++; + } + } + + void + reschedule3() + { + selfEventId.cancel(); + + scheduler.schedule(100_ms, [&] { ++count; }); + scheduler.schedule(100_ms, [&] { ++count; }); + scheduler.schedule(100_ms, [&] { ++count; }); + scheduler.schedule(100_ms, [&] { ++count; }); + scheduler.schedule(100_ms, [&] { ++count; }); + scheduler.schedule(100_ms, [&] { ++count; }); + } + +public: + EventId selfEventId; + size_t count = 0; +}; + +BOOST_FIXTURE_TEST_CASE(Reschedule, SelfRescheduleFixture) +{ + selfEventId = scheduler.schedule(0_s, bind(&SelfRescheduleFixture::reschedule, this)); + BOOST_REQUIRE_NO_THROW(advanceClocks(50_ms, 1000_ms)); + BOOST_CHECK_EQUAL(count, 5); +} + +BOOST_FIXTURE_TEST_CASE(Reschedule2, SelfRescheduleFixture) +{ + selfEventId = scheduler.schedule(0_s, bind(&SelfRescheduleFixture::reschedule2, this)); + BOOST_REQUIRE_NO_THROW(advanceClocks(50_ms, 1000_ms)); + BOOST_CHECK_EQUAL(count, 5); +} + +BOOST_FIXTURE_TEST_CASE(Reschedule3, SelfRescheduleFixture) +{ + selfEventId = scheduler.schedule(0_s, bind(&SelfRescheduleFixture::reschedule3, this)); + BOOST_REQUIRE_NO_THROW(advanceClocks(50_ms, 1000_ms)); + BOOST_CHECK_EQUAL(count, 6); +} + +class CancelAllFixture : public SchedulerFixture +{ +public: + void + event() + { + ++count; + scheduler.schedule(1_s, [&] { event(); }); + } + +public: + uint32_t count = 0; +}; + +BOOST_FIXTURE_TEST_CASE(CancelAll, CancelAllFixture) +{ + scheduler.schedule(500_ms, [&] { scheduler.cancelAllEvents(); }); + scheduler.schedule(1_s, [&] { event(); }); + scheduler.schedule(3_s, [] { BOOST_ERROR("This event should have been cancelled" ); }); + + advanceClocks(100_ms, 100); + BOOST_CHECK_EQUAL(count, 0); +} + +BOOST_AUTO_TEST_CASE(CancelAllWithScopedEventId) // Bug 3691 +{ + Scheduler sched(io); + ScopedEventId eid = sched.schedule(10_ms, []{}); + sched.cancelAllEvents(); + eid.cancel(); // should not crash + + // avoid "test case [...] did not check any assertions" message from Boost.Test + BOOST_CHECK(true); +} + +BOOST_AUTO_TEST_SUITE_END() // General + +BOOST_AUTO_TEST_SUITE(EventId) + +using scheduler::EventId; + +BOOST_AUTO_TEST_CASE(ConstructEmpty) +{ + EventId eid; + BOOST_CHECK(!eid); +} + +BOOST_AUTO_TEST_CASE(Equality) +{ + EventId eid, eid2; + BOOST_CHECK(eid == eid2); + + eid = scheduler.schedule(10_ms, []{}); + BOOST_CHECK(eid != eid2); + + eid2 = scheduler.schedule(10_ms, []{}); + BOOST_CHECK(eid != eid2); + + eid.cancel(); + BOOST_CHECK(eid != eid2); + BOOST_CHECK(eid == EventId{}); + + eid2.cancel(); + BOOST_CHECK(eid == eid2); + + eid = eid2 = scheduler.schedule(20_ms, []{}); + BOOST_CHECK(eid == eid2); + BOOST_CHECK(eid != EventId{}); + + eid.cancel(); + BOOST_CHECK(eid == eid2); + BOOST_CHECK(eid == EventId{}); +} + +BOOST_AUTO_TEST_CASE(OperatorBool) +{ + EventId eid; + BOOST_CHECK_EQUAL(static_cast(eid), false); + BOOST_CHECK_EQUAL(!eid, true); + + eid = scheduler.schedule(10_ms, []{}); + BOOST_CHECK_EQUAL(static_cast(eid), true); + BOOST_CHECK_EQUAL(!eid, false); + + EventId eid2 = eid; + eid2.cancel(); + BOOST_CHECK(!eid); + BOOST_CHECK(!eid2); +} + +BOOST_AUTO_TEST_CASE(DuringCallback) +{ + EventId eid; + EventId eid2 = scheduler.schedule(20_ms, []{}); + + bool isCallbackInvoked = false; + eid = scheduler.schedule(10_ms, [&eid, &eid2, &isCallbackInvoked] { + isCallbackInvoked = true; + + // eid is "expired" during callback execution + BOOST_CHECK(!eid); + BOOST_CHECK_NE(eid, eid2); + + eid2.cancel(); + BOOST_CHECK_EQUAL(eid, eid2); + }); + + this->advanceClocks(6_ms, 2); + BOOST_CHECK(isCallbackInvoked); +} + +BOOST_AUTO_TEST_CASE(Reset) +{ + bool isCallbackInvoked = false; + EventId eid = scheduler.schedule(10_ms, [&isCallbackInvoked] { isCallbackInvoked = true; }); + eid.reset(); + BOOST_CHECK(!eid); + + this->advanceClocks(6_ms, 2); + BOOST_CHECK(isCallbackInvoked); +} + +BOOST_AUTO_TEST_CASE(ToString) +{ + std::string nullString = boost::lexical_cast(shared_ptr()); + + EventId eid; + BOOST_CHECK_EQUAL(boost::lexical_cast(eid), nullString); + + eid = scheduler.schedule(10_ms, []{}); + BOOST_TEST_MESSAGE("eid=" << eid); + BOOST_CHECK_NE(boost::lexical_cast(eid), nullString); +} + +BOOST_AUTO_TEST_SUITE_END() // EventId + +BOOST_AUTO_TEST_SUITE(ScopedEventId) + +using scheduler::ScopedEventId; + +BOOST_AUTO_TEST_CASE(Destruct) +{ + int hit = 0; + { + ScopedEventId se = scheduler.schedule(10_ms, [&] { ++hit; }); + } // se goes out of scope + this->advanceClocks(1_ms, 15); + BOOST_CHECK_EQUAL(hit, 0); +} + +BOOST_AUTO_TEST_CASE(Assign) +{ + int hit1 = 0, hit2 = 0; + ScopedEventId se1 = scheduler.schedule(10_ms, [&] { ++hit1; }); + se1 = scheduler.schedule(10_ms, [&] { ++hit2; }); + this->advanceClocks(1_ms, 15); + BOOST_CHECK_EQUAL(hit1, 0); + BOOST_CHECK_EQUAL(hit2, 1); +} + +BOOST_AUTO_TEST_CASE(Release) +{ + int hit = 0; + { + ScopedEventId se = scheduler.schedule(10_ms, [&] { ++hit; }); + se.release(); + } // se goes out of scope + this->advanceClocks(1_ms, 15); + BOOST_CHECK_EQUAL(hit, 1); +} + +BOOST_AUTO_TEST_CASE(Move) +{ + int hit = 0; + unique_ptr se2; + { + ScopedEventId se = scheduler.schedule(10_ms, [&] { ++hit; }); + se2 = make_unique(std::move(se)); // move constructor + } // se goes out of scope + this->advanceClocks(1_ms, 15); + BOOST_CHECK_EQUAL(hit, 1); + + ScopedEventId se3; + { + ScopedEventId se = scheduler.schedule(10_ms, [&] { ++hit; }); + se3 = std::move(se); // move assignment + } // se goes out of scope + this->advanceClocks(1_ms, 15); + BOOST_CHECK_EQUAL(hit, 2); +} + +BOOST_AUTO_TEST_CASE(OperatorBool) +{ + ScopedEventId se; + BOOST_CHECK_EQUAL(static_cast(se), false); + BOOST_CHECK_EQUAL(!se, true); + + se = scheduler.schedule(10_ms, []{}); + BOOST_CHECK_EQUAL(static_cast(se), true); + BOOST_CHECK_EQUAL(!se, false); + + se.cancel(); + BOOST_CHECK(!se); + + se = scheduler.schedule(10_ms, []{}); + BOOST_CHECK(se); + + se.release(); + BOOST_CHECK(!se); +} + +BOOST_AUTO_TEST_SUITE_END() // ScopedEventId + +BOOST_AUTO_TEST_SUITE_END() // TestScheduler +BOOST_AUTO_TEST_SUITE_END() // Util + +} // namespace tests +} // namespace scheduler +} // namespace ndn diff --git a/tests/unit/util/segment-fetcher.t.cpp b/tests/unit/util/segment-fetcher.t.cpp new file mode 100644 index 000000000..9f65f493c --- /dev/null +++ b/tests/unit/util/segment-fetcher.t.cpp @@ -0,0 +1,887 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/segment-fetcher.hpp" + +#include "ndn-cxx/data.hpp" +#include "ndn-cxx/lp/nack.hpp" +#include "ndn-cxx/util/dummy-client-face.hpp" + +#include "tests/boost-test.hpp" +#include "tests/make-interest-data.hpp" +#include "tests/unit/dummy-validator.hpp" +#include "tests/unit/identity-management-time-fixture.hpp" + +#include + +namespace ndn { +namespace util { +namespace tests { + +using namespace ndn::tests; + +class Fixture : public IdentityManagementTimeFixture +{ +public: + Fixture() + : face(io, m_keyChain) + { + } + + static shared_ptr + makeDataSegment(const Name& baseName, uint64_t segment, bool isFinal) + { + const uint8_t buffer[] = "Hello, world!"; + + auto data = make_shared(Name(baseName).appendSegment(segment)); + data->setFreshnessPeriod(1_s); + data->setContent(buffer, sizeof(buffer)); + if (isFinal) { + data->setFinalBlock(data->getName()[-1]); + } + + return signData(data); + } + + void + onError(uint32_t errorCode) + { + ++nErrors; + lastError = errorCode; + } + + void + onComplete(ConstBufferPtr data) + { + ++nCompletions; + dataSize = data->size(); + dataBuf = data; + } + + void + nackLastInterest(lp::NackReason nackReason) + { + const Interest& lastInterest = face.sentInterests.back(); + lp::Nack nack = makeNack(lastInterest, nackReason); + face.receive(nack); + advanceClocks(10_ms); + } + + void + connectSignals(const shared_ptr& fetcher) + { + fetcher->onComplete.connect(bind(&Fixture::onComplete, this, _1)); + fetcher->onError.connect(bind(&Fixture::onError, this, _1)); + } + + void + onInterest(const Interest& interest) + { + if (interest.getName().get(-1).isSegment()) { + if (segmentsToDropOrNack.size() > 0 && + interest.getName().get(-1).toSegment() == segmentsToDropOrNack.front()) { + segmentsToDropOrNack.pop(); + if (sendNackInsteadOfDropping) { + lp::Nack nack = makeNack(interest, nackReason); + face.receive(nack); + } + return; + } + + auto data = makeDataSegment("/hello/world/version0", + interest.getName().get(-1).toSegment(), + interest.getName().get(-1).toSegment() == nSegments - 1); + face.receive(*data); + + uniqSegmentsSent.insert(interest.getName().get(-1).toSegment()); + if (uniqSegmentsSent.size() == nSegments) { + io.stop(); + } + } + else { + if (segmentsToDropOrNack.size() > 0 && + segmentsToDropOrNack.front() == 0) { + segmentsToDropOrNack.pop(); + if (sendNackInsteadOfDropping) { + lp::Nack nack = makeNack(interest, nackReason); + face.receive(nack); + } + return; + } + + auto data = makeDataSegment("/hello/world/version0", defaultSegmentToSend, nSegments == 1); + face.receive(*data); + uniqSegmentsSent.insert(defaultSegmentToSend); + } + } + +public: + DummyClientFace face; + std::set uniqSegmentsSent; + + int nErrors = 0; + uint32_t lastError = 0; + int nCompletions = 0; + size_t dataSize = 0; + ConstBufferPtr dataBuf; + + // number of segments in fetched object + uint64_t nSegments = 0; + std::queue segmentsToDropOrNack; + bool sendNackInsteadOfDropping = false; + lp::NackReason nackReason = lp::NackReason::NONE; + // segment that is sent in response to an Interest w/o a segment component in its name + uint64_t defaultSegmentToSend = 0; +}; + +BOOST_AUTO_TEST_SUITE(Util) +BOOST_FIXTURE_TEST_SUITE(TestSegmentFetcher, Fixture) + +BOOST_AUTO_TEST_CASE(InvalidOptions) +{ + SegmentFetcher::Options options; + options.mdCoef = 1.5; + DummyValidator acceptValidator; + BOOST_CHECK_THROW(SegmentFetcher::start(face, Interest("/hello/world"), acceptValidator, options), + std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(ExceedMaxTimeout) +{ + DummyValidator acceptValidator; + size_t nAfterSegmentTimedOut = 0; + SegmentFetcher::Options options; + options.maxTimeout = 100_ms; + shared_ptr fetcher = SegmentFetcher::start(face, Interest("/hello/world"), + acceptValidator, options); + connectSignals(fetcher); + fetcher->afterSegmentTimedOut.connect(bind([&nAfterSegmentTimedOut] { ++nAfterSegmentTimedOut; })); + + advanceClocks(1_ms); + BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1); + + const Interest& interest = face.sentInterests[0]; + BOOST_CHECK_EQUAL(interest.getName(), "/hello/world"); + BOOST_CHECK_EQUAL(interest.getMustBeFresh(), true); + BOOST_CHECK_EQUAL(interest.getCanBePrefix(), true); + + advanceClocks(98_ms); + BOOST_CHECK_EQUAL(nErrors, 0); + BOOST_CHECK_EQUAL(nCompletions, 0); + BOOST_CHECK_EQUAL(face.sentData.size(), 0); + BOOST_CHECK_EQUAL(nAfterSegmentTimedOut, 0); + + advanceClocks(1_ms, 2); + BOOST_CHECK_EQUAL(nErrors, 1); + BOOST_CHECK_EQUAL(lastError, static_cast(SegmentFetcher::INTEREST_TIMEOUT)); + BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1); + BOOST_CHECK_EQUAL(face.sentData.size(), 0); + BOOST_CHECK_EQUAL(nAfterSegmentTimedOut, 1); +} + +BOOST_AUTO_TEST_CASE(BasicSingleSegment) +{ + DummyValidator acceptValidator; + size_t nAfterSegmentReceived = 0; + size_t nAfterSegmentValidated = 0; + size_t nAfterSegmentNacked = 0; + size_t nAfterSegmentTimedOut = 0; + shared_ptr fetcher = SegmentFetcher::start(face, Interest("/hello/world"), + acceptValidator); + connectSignals(fetcher); + fetcher->afterSegmentReceived.connect(bind([&nAfterSegmentReceived] { ++nAfterSegmentReceived; })); + fetcher->afterSegmentValidated.connect(bind([&nAfterSegmentValidated] { ++nAfterSegmentValidated; })); + fetcher->afterSegmentNacked.connect(bind([&nAfterSegmentNacked] { ++nAfterSegmentNacked; })); + fetcher->afterSegmentTimedOut.connect(bind([&nAfterSegmentTimedOut] { ++nAfterSegmentTimedOut; })); + + advanceClocks(10_ms); + + face.receive(*makeDataSegment("/hello/world/version0", 0, true)); + + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(nErrors, 0); + BOOST_CHECK_EQUAL(nCompletions, 1); + BOOST_CHECK_EQUAL(nAfterSegmentReceived, 1); + BOOST_CHECK_EQUAL(nAfterSegmentValidated, 1); + BOOST_CHECK_EQUAL(nAfterSegmentNacked, 0); + BOOST_CHECK_EQUAL(nAfterSegmentTimedOut, 0); +} + +BOOST_AUTO_TEST_CASE(ConstantCwnd) +{ + SegmentFetcher::Options options; + options.useConstantCwnd = true; + DummyValidator acceptValidator; + size_t nAfterSegmentReceived = 0; + size_t nAfterSegmentValidated = 0; + size_t nAfterSegmentNacked = 0; + size_t nAfterSegmentTimedOut = 0; + shared_ptr fetcher = SegmentFetcher::start(face, Interest("/hello/world"), + acceptValidator, options); + connectSignals(fetcher); + fetcher->afterSegmentReceived.connect(bind([&nAfterSegmentReceived] { ++nAfterSegmentReceived; })); + fetcher->afterSegmentValidated.connect(bind([&nAfterSegmentValidated] { ++nAfterSegmentValidated; })); + fetcher->afterSegmentNacked.connect(bind([&nAfterSegmentNacked] { ++nAfterSegmentNacked; })); + fetcher->afterSegmentTimedOut.connect(bind([&nAfterSegmentTimedOut] { ++nAfterSegmentTimedOut; })); + + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(fetcher->m_cwnd, 1.0); + BOOST_CHECK_EQUAL(fetcher->m_nSegmentsInFlight, 1); + + face.receive(*makeDataSegment("/hello/world/version0", 0, false)); + + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(fetcher->m_cwnd, 1.0); + BOOST_CHECK_EQUAL(fetcher->m_nSegmentsInFlight, 1); + BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2); + BOOST_CHECK_EQUAL(face.sentInterests.back().getName().get(-1).toSegment(), 1); + face.receive(*makeDataSegment("/hello/world/version0", 1, false)); + + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(fetcher->m_cwnd, 1.0); + BOOST_CHECK_EQUAL(fetcher->m_nSegmentsInFlight, 1); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 3); + BOOST_CHECK_EQUAL(face.sentInterests.back().getName().get(-1).toSegment(), 2); + face.receive(*makeDataSegment("/hello/world/version0", 2, false)); + + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(fetcher->m_cwnd, 1.0); + BOOST_CHECK_EQUAL(fetcher->m_nSegmentsInFlight, 1); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 4); + BOOST_CHECK_EQUAL(face.sentInterests.back().getName().get(-1).toSegment(), 3); + face.receive(*makeDataSegment("/hello/world/version0", 3, false)); + + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(fetcher->m_cwnd, 1.0); + BOOST_CHECK_EQUAL(fetcher->m_nSegmentsInFlight, 1); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 5); + BOOST_CHECK_EQUAL(face.sentInterests.back().getName().get(-1).toSegment(), 4); + nackLastInterest(lp::NackReason::CONGESTION); + + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(fetcher->m_cwnd, 1.0); + BOOST_CHECK_EQUAL(fetcher->m_nSegmentsInFlight, 1); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 6); + BOOST_CHECK_EQUAL(face.sentInterests.back().getName().get(-1).toSegment(), 4); + face.receive(*makeDataSegment("/hello/world/version0", 4, true)); + + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(nErrors, 0); + BOOST_CHECK_EQUAL(nCompletions, 1); + BOOST_CHECK_EQUAL(nAfterSegmentReceived, 5); + BOOST_CHECK_EQUAL(nAfterSegmentValidated, 5); + BOOST_CHECK_EQUAL(nAfterSegmentNacked, 1); + BOOST_CHECK_EQUAL(nAfterSegmentTimedOut, 0); + BOOST_CHECK_EQUAL(fetcher->m_cwnd, 1.0); +} + +BOOST_AUTO_TEST_CASE(BasicMultipleSegments) +{ + DummyValidator acceptValidator; + size_t nAfterSegmentReceived = 0; + size_t nAfterSegmentValidated = 0; + size_t nAfterSegmentNacked = 0; + size_t nAfterSegmentTimedOut = 0; + nSegments = 401; + sendNackInsteadOfDropping = false; + face.onSendInterest.connect(bind(&Fixture::onInterest, this, _1)); + + shared_ptr fetcher = SegmentFetcher::start(face, Interest("/hello/world"), + acceptValidator); + connectSignals(fetcher); + fetcher->afterSegmentReceived.connect(bind([&nAfterSegmentReceived] { ++nAfterSegmentReceived; })); + fetcher->afterSegmentValidated.connect(bind([&nAfterSegmentValidated] { ++nAfterSegmentValidated; })); + fetcher->afterSegmentNacked.connect(bind([&nAfterSegmentNacked] { ++nAfterSegmentNacked; })); + fetcher->afterSegmentTimedOut.connect(bind([&nAfterSegmentTimedOut] { ++nAfterSegmentTimedOut; })); + + face.processEvents(1_s); + + BOOST_CHECK_EQUAL(nErrors, 0); + BOOST_CHECK_EQUAL(nCompletions, 1); + BOOST_CHECK_EQUAL(dataSize, 14 * 401); + BOOST_CHECK_EQUAL(nAfterSegmentReceived, 401); + BOOST_CHECK_EQUAL(nAfterSegmentValidated, 401); + BOOST_CHECK_EQUAL(nAfterSegmentNacked, 0); + BOOST_CHECK_EQUAL(nAfterSegmentTimedOut, 0); +} + +BOOST_AUTO_TEST_CASE(FirstSegmentNotZero) +{ + DummyValidator acceptValidator; + size_t nAfterSegmentReceived = 0; + size_t nAfterSegmentValidated = 0; + size_t nAfterSegmentNacked = 0; + size_t nAfterSegmentTimedOut = 0; + nSegments = 401; + sendNackInsteadOfDropping = false; + defaultSegmentToSend = 47; + face.onSendInterest.connect(bind(&Fixture::onInterest, this, _1)); + + shared_ptr fetcher = SegmentFetcher::start(face, Interest("/hello/world"), + acceptValidator); + connectSignals(fetcher); + fetcher->afterSegmentReceived.connect(bind([&nAfterSegmentReceived] { ++nAfterSegmentReceived; })); + fetcher->afterSegmentValidated.connect(bind([&nAfterSegmentValidated] { ++nAfterSegmentValidated; })); + fetcher->afterSegmentNacked.connect(bind([&nAfterSegmentNacked] { ++nAfterSegmentNacked; })); + fetcher->afterSegmentTimedOut.connect(bind([&nAfterSegmentTimedOut] { ++nAfterSegmentTimedOut; })); + + face.processEvents(1_s); + + BOOST_CHECK_EQUAL(nErrors, 0); + BOOST_CHECK_EQUAL(nCompletions, 1); + BOOST_CHECK_EQUAL(dataSize, 14 * 401); + BOOST_CHECK_EQUAL(nAfterSegmentReceived, 401); + BOOST_CHECK_EQUAL(nAfterSegmentValidated, 401); + BOOST_CHECK_EQUAL(nAfterSegmentNacked, 0); + BOOST_CHECK_EQUAL(nAfterSegmentTimedOut, 0); +} + +BOOST_AUTO_TEST_CASE(WindowSize) +{ + DummyValidator acceptValidator; + size_t nAfterSegmentReceived = 0; + size_t nAfterSegmentValidated = 0; + shared_ptr fetcher = SegmentFetcher::start(face, Interest("/hello/world"), + acceptValidator); + connectSignals(fetcher); + fetcher->afterSegmentReceived.connect(bind([&nAfterSegmentReceived] { ++nAfterSegmentReceived; })); + fetcher->afterSegmentValidated.connect(bind([&nAfterSegmentValidated] { ++nAfterSegmentValidated; })); + + advanceClocks(10_ms); // T+10ms + + BOOST_CHECK_EQUAL(fetcher->m_timeLastSegmentReceived, time::steady_clock::now() - 10_ms); + BOOST_CHECK_EQUAL(fetcher->m_retxQueue.size(), 0); + BOOST_CHECK_EQUAL(fetcher->m_nextSegmentNum, 0); + BOOST_CHECK_EQUAL(fetcher->m_cwnd, 1.0); + BOOST_CHECK_EQUAL(fetcher->m_ssthresh, std::numeric_limits::max()); + BOOST_CHECK_EQUAL(fetcher->m_nSegmentsInFlight, 1); + BOOST_CHECK_EQUAL(fetcher->m_nSegments, 0); + BOOST_CHECK_EQUAL(fetcher->m_nBytesReceived, 0); + BOOST_CHECK_EQUAL(fetcher->m_highInterest, 0); + BOOST_CHECK_EQUAL(fetcher->m_highData, 0); + BOOST_CHECK_EQUAL(fetcher->m_recPoint, 0); + BOOST_CHECK_EQUAL(fetcher->m_nReceived, 0); + BOOST_CHECK_EQUAL(fetcher->m_receivedSegments.size(), 0); + BOOST_CHECK_EQUAL(fetcher->m_pendingSegments.size(), 1); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); + + double oldCwnd = fetcher->m_cwnd; + double oldSsthresh = fetcher->m_ssthresh; + uint64_t oldNextSegmentNum = fetcher->m_nextSegmentNum; + + face.receive(*makeDataSegment("/hello/world/version0", 0, false)); + + advanceClocks(10_ms); //T+20ms + + BOOST_CHECK_EQUAL(fetcher->m_timeLastSegmentReceived, time::steady_clock::now() - 10_ms); + BOOST_CHECK_EQUAL(fetcher->m_retxQueue.size(), 0); + BOOST_CHECK_EQUAL(fetcher->m_versionedDataName, "/hello/world/version0"); + // +2 below because m_nextSegmentNum will be incremented in the receive callback if segment 0 is + // the first received + BOOST_CHECK_EQUAL(fetcher->m_nextSegmentNum, oldNextSegmentNum + fetcher->m_options.aiStep + 2); + BOOST_CHECK_EQUAL(fetcher->m_cwnd, oldCwnd + fetcher->m_options.aiStep); + BOOST_CHECK_EQUAL(fetcher->m_ssthresh, oldSsthresh); + BOOST_CHECK_EQUAL(fetcher->m_nSegmentsInFlight, oldCwnd + fetcher->m_options.aiStep); + BOOST_CHECK_EQUAL(fetcher->m_nSegments, 0); + BOOST_CHECK_EQUAL(fetcher->m_nBytesReceived, 14); + BOOST_CHECK_EQUAL(fetcher->m_highInterest, fetcher->m_nextSegmentNum - 1); + BOOST_CHECK_EQUAL(fetcher->m_highData, 0); + BOOST_CHECK_EQUAL(fetcher->m_recPoint, 0); + BOOST_CHECK_EQUAL(fetcher->m_receivedSegments.size(), 1); + BOOST_CHECK_EQUAL(fetcher->m_pendingSegments.size(), fetcher->m_cwnd); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 1 + fetcher->m_cwnd); + + oldCwnd = fetcher->m_cwnd; + oldNextSegmentNum = fetcher->m_nextSegmentNum; + + face.receive(*makeDataSegment("/hello/world/version0", 2, false)); + + advanceClocks(10_ms); //T+30ms + + BOOST_CHECK_EQUAL(fetcher->m_timeLastSegmentReceived, time::steady_clock::now() - 10_ms); + BOOST_CHECK_EQUAL(fetcher->m_retxQueue.size(), 0); + BOOST_CHECK_EQUAL(fetcher->m_versionedDataName, "/hello/world/version0"); + BOOST_CHECK_EQUAL(fetcher->m_nextSegmentNum, oldNextSegmentNum + fetcher->m_options.aiStep + 1); + BOOST_CHECK_EQUAL(fetcher->m_cwnd, oldCwnd + fetcher->m_options.aiStep); + BOOST_CHECK_EQUAL(fetcher->m_ssthresh, oldSsthresh); + BOOST_CHECK_EQUAL(fetcher->m_nSegmentsInFlight, fetcher->m_cwnd); + BOOST_CHECK_EQUAL(fetcher->m_nSegments, 0); + BOOST_CHECK_EQUAL(fetcher->m_nBytesReceived, 28); + BOOST_CHECK_EQUAL(fetcher->m_highInterest, fetcher->m_nextSegmentNum - 1); + BOOST_CHECK_EQUAL(fetcher->m_highData, 2); + BOOST_CHECK_EQUAL(fetcher->m_recPoint, 0); + BOOST_CHECK_EQUAL(fetcher->m_receivedSegments.size(), 2); + BOOST_CHECK_EQUAL(fetcher->m_pendingSegments.size(), fetcher->m_cwnd); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 2 + fetcher->m_cwnd); + + oldCwnd = fetcher->m_cwnd; + oldNextSegmentNum = fetcher->m_nextSegmentNum; + + face.receive(*makeDataSegment("/hello/world/version0", 1, false)); + + advanceClocks(10_ms); //T+40ms + + BOOST_CHECK_EQUAL(fetcher->m_timeLastSegmentReceived, time::steady_clock::now() - 10_ms); + BOOST_CHECK_EQUAL(fetcher->m_retxQueue.size(), 0); + BOOST_CHECK_EQUAL(fetcher->m_versionedDataName, "/hello/world/version0"); + BOOST_CHECK_EQUAL(fetcher->m_nextSegmentNum, oldNextSegmentNum + fetcher->m_options.aiStep + 1); + BOOST_CHECK_EQUAL(fetcher->m_cwnd, oldCwnd + fetcher->m_options.aiStep); + BOOST_CHECK_EQUAL(fetcher->m_ssthresh, oldSsthresh); + BOOST_CHECK_EQUAL(fetcher->m_nSegmentsInFlight, fetcher->m_cwnd); + BOOST_CHECK_EQUAL(fetcher->m_nSegments, 0); + BOOST_CHECK_EQUAL(fetcher->m_nBytesReceived, 42); + BOOST_CHECK_EQUAL(fetcher->m_highInterest, fetcher->m_nextSegmentNum - 1); + BOOST_CHECK_EQUAL(fetcher->m_highData, 2); + BOOST_CHECK_EQUAL(fetcher->m_recPoint, 0); + BOOST_CHECK_EQUAL(fetcher->m_receivedSegments.size(), 3); + BOOST_CHECK_EQUAL(fetcher->m_pendingSegments.size(), fetcher->m_cwnd); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 3 + fetcher->m_cwnd); + + oldCwnd = fetcher->m_cwnd; + oldSsthresh = fetcher->m_ssthresh; + oldNextSegmentNum = fetcher->m_nextSegmentNum; + size_t oldSentInterestsSize = face.sentInterests.size(); + + nackLastInterest(lp::NackReason::CONGESTION); //T+50ms + + BOOST_CHECK_EQUAL(fetcher->m_timeLastSegmentReceived, time::steady_clock::now() - 20_ms); + BOOST_CHECK_EQUAL(fetcher->m_retxQueue.size(), 1); + BOOST_CHECK_EQUAL(fetcher->m_versionedDataName, "/hello/world/version0"); + BOOST_CHECK_EQUAL(fetcher->m_nextSegmentNum, oldNextSegmentNum); + BOOST_CHECK_EQUAL(fetcher->m_cwnd, oldCwnd / 2.0); + BOOST_CHECK_EQUAL(fetcher->m_ssthresh, oldCwnd / 2.0); + BOOST_CHECK_EQUAL(fetcher->m_nSegmentsInFlight, oldCwnd - 1); + BOOST_CHECK_EQUAL(fetcher->m_nSegments, 0); + BOOST_CHECK_EQUAL(fetcher->m_nBytesReceived, 42); + BOOST_CHECK_EQUAL(fetcher->m_highInterest, fetcher->m_nextSegmentNum - 1); + BOOST_CHECK_EQUAL(fetcher->m_highData, 2); + BOOST_CHECK_EQUAL(fetcher->m_recPoint, fetcher->m_nextSegmentNum - 1); + BOOST_CHECK_EQUAL(fetcher->m_receivedSegments.size(), 3); + // The Nacked segment will remain in pendingSegments, so the size of the structure doesn't change + BOOST_CHECK_EQUAL(fetcher->m_pendingSegments.size(), oldCwnd); + BOOST_CHECK_EQUAL(face.sentInterests.size(), oldSentInterestsSize); + + advanceClocks(10_ms); //T+60ms + + BOOST_CHECK_EQUAL(fetcher->m_timeLastSegmentReceived, time::steady_clock::now() - 30_ms); + BOOST_CHECK_EQUAL(fetcher->m_retxQueue.size(), 1); + BOOST_CHECK_EQUAL(fetcher->m_versionedDataName, "/hello/world/version0"); + BOOST_CHECK_EQUAL(fetcher->m_nextSegmentNum, oldNextSegmentNum); + BOOST_CHECK_EQUAL(fetcher->m_cwnd, oldCwnd / 2.0); + BOOST_CHECK_EQUAL(fetcher->m_ssthresh, oldCwnd / 2.0); + BOOST_CHECK_EQUAL(fetcher->m_nSegmentsInFlight, oldCwnd - 1); + BOOST_CHECK_EQUAL(fetcher->m_nSegments, 0); + BOOST_CHECK_EQUAL(fetcher->m_nBytesReceived, 42); + BOOST_CHECK_EQUAL(fetcher->m_highInterest, fetcher->m_nextSegmentNum - 1); + BOOST_CHECK_EQUAL(fetcher->m_highData, 2); + BOOST_CHECK_EQUAL(fetcher->m_recPoint, fetcher->m_nextSegmentNum - 1); + BOOST_CHECK_EQUAL(fetcher->m_receivedSegments.size(), 3); + BOOST_CHECK_EQUAL(fetcher->m_pendingSegments.size(), oldCwnd); + BOOST_CHECK_EQUAL(face.sentInterests.size(), oldSentInterestsSize); + + // Properly end test case + lp::Nack nack = makeNack(face.sentInterests[face.sentInterests.size() - 2], lp::NackReason::NO_ROUTE); + face.receive(nack); + advanceClocks(10_ms); //T+70ms + + BOOST_CHECK_EQUAL(nErrors, 1); + BOOST_CHECK_EQUAL(lastError, static_cast(SegmentFetcher::NACK_ERROR)); + BOOST_CHECK_EQUAL(nCompletions, 0); +} + +BOOST_AUTO_TEST_CASE(MissingSegmentNum) +{ + DummyValidator acceptValidator; + shared_ptr fetcher = SegmentFetcher::start(face, Interest("/hello/world"), + acceptValidator); + connectSignals(fetcher); + + advanceClocks(10_ms); + + const uint8_t buffer[] = "Hello, world!"; + auto data = makeData("/hello/world/version0/no-segment"); + data->setFreshnessPeriod(1_s); + data->setContent(buffer, sizeof(buffer)); + + face.receive(*data); + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(nErrors, 1); + BOOST_CHECK_EQUAL(lastError, static_cast(SegmentFetcher::DATA_HAS_NO_SEGMENT)); + BOOST_CHECK_EQUAL(nCompletions, 0); +} + +BOOST_AUTO_TEST_CASE(MoreSegmentsThanNSegments) +{ + DummyValidator acceptValidator; + size_t nAfterSegmentReceived = 0; + size_t nAfterSegmentValidated = 0; + size_t nAfterSegmentNacked = 0; + size_t nAfterSegmentTimedOut = 0; + shared_ptr fetcher = SegmentFetcher::start(face, Interest("/hello/world"), + acceptValidator); + connectSignals(fetcher); + fetcher->afterSegmentReceived.connect(bind([&nAfterSegmentReceived] { ++nAfterSegmentReceived; })); + fetcher->afterSegmentValidated.connect(bind([&nAfterSegmentValidated] { ++nAfterSegmentValidated; })); + fetcher->afterSegmentNacked.connect(bind([&nAfterSegmentNacked] { ++nAfterSegmentNacked; })); + fetcher->afterSegmentTimedOut.connect(bind([&nAfterSegmentTimedOut] { ++nAfterSegmentTimedOut; })); + + advanceClocks(10_ms); + + face.receive(*makeDataSegment("/hello/world/version0", 0, false)); + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(nErrors, 0); + BOOST_CHECK_EQUAL(nCompletions, 0); + + face.receive(*makeDataSegment("/hello/world/version0", 1, false)); + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(nErrors, 0); + BOOST_CHECK_EQUAL(nCompletions, 0); + + face.receive(*makeDataSegment("/hello/world/version0", 2, false)); + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(nErrors, 0); + BOOST_CHECK_EQUAL(nCompletions, 0); + + face.receive(*makeDataSegment("/hello/world/version0", 3, false)); + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(nErrors, 0); + BOOST_CHECK_EQUAL(nCompletions, 0); + + auto data4 = makeDataSegment("/hello/world/version0", 4, false); + data4->setFinalBlock(name::Component::fromSegment(2)); + face.receive(*data4); + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(nErrors, 0); + BOOST_CHECK_EQUAL(nCompletions, 1); + BOOST_CHECK_EQUAL(dataSize, 14 * 3); + BOOST_CHECK_EQUAL(nAfterSegmentReceived, 5); + BOOST_CHECK_EQUAL(nAfterSegmentValidated, 5); + BOOST_CHECK_EQUAL(nAfterSegmentNacked, 0); + BOOST_CHECK_EQUAL(nAfterSegmentTimedOut, 0); +} + +BOOST_AUTO_TEST_CASE(DuplicateNack) +{ + DummyValidator acceptValidator; + size_t nAfterSegmentReceived = 0; + size_t nAfterSegmentValidated = 0; + size_t nAfterSegmentNacked = 0; + size_t nAfterSegmentTimedOut = 0; + nSegments = 401; + segmentsToDropOrNack.push(0); + segmentsToDropOrNack.push(200); + sendNackInsteadOfDropping = true; + nackReason = lp::NackReason::DUPLICATE; + face.onSendInterest.connect(bind(&Fixture::onInterest, this, _1)); + + shared_ptr fetcher = SegmentFetcher::start(face, Interest("/hello/world"), + acceptValidator); + connectSignals(fetcher); + fetcher->afterSegmentReceived.connect(bind([&nAfterSegmentReceived] { ++nAfterSegmentReceived; })); + fetcher->afterSegmentValidated.connect(bind([&nAfterSegmentValidated] { ++nAfterSegmentValidated; })); + fetcher->afterSegmentNacked.connect(bind([&nAfterSegmentNacked] { ++nAfterSegmentNacked; })); + fetcher->afterSegmentTimedOut.connect(bind([&nAfterSegmentTimedOut] { ++nAfterSegmentTimedOut; })); + + face.processEvents(1_s); + + BOOST_CHECK_EQUAL(nErrors, 0); + BOOST_CHECK_EQUAL(nCompletions, 1); + BOOST_CHECK_EQUAL(dataSize, 14 * 401); + BOOST_CHECK_EQUAL(nAfterSegmentReceived, 401); + BOOST_CHECK_EQUAL(nAfterSegmentValidated, 401); + BOOST_CHECK_EQUAL(nAfterSegmentNacked, 2); + BOOST_CHECK_EQUAL(nAfterSegmentTimedOut, 0); +} + +BOOST_AUTO_TEST_CASE(CongestionNack) +{ + DummyValidator acceptValidator; + size_t nAfterSegmentReceived = 0; + size_t nAfterSegmentValidated = 0; + size_t nAfterSegmentNacked = 0; + size_t nAfterSegmentTimedOut = 0; + nSegments = 401; + segmentsToDropOrNack.push(0); + segmentsToDropOrNack.push(200); + sendNackInsteadOfDropping = true; + nackReason = lp::NackReason::CONGESTION; + face.onSendInterest.connect(bind(&Fixture::onInterest, this, _1)); + + shared_ptr fetcher = SegmentFetcher::start(face, Interest("/hello/world"), + acceptValidator); + connectSignals(fetcher); + fetcher->afterSegmentReceived.connect(bind([&nAfterSegmentReceived] { ++nAfterSegmentReceived; })); + fetcher->afterSegmentValidated.connect(bind([&nAfterSegmentValidated] { ++nAfterSegmentValidated; })); + fetcher->afterSegmentNacked.connect(bind([&nAfterSegmentNacked] { ++nAfterSegmentNacked; })); + fetcher->afterSegmentTimedOut.connect(bind([&nAfterSegmentTimedOut] { ++nAfterSegmentTimedOut; })); + + face.processEvents(1_s); + + BOOST_CHECK_EQUAL(nErrors, 0); + BOOST_CHECK_EQUAL(nCompletions, 1); + BOOST_CHECK_EQUAL(dataSize, 14 * 401); + BOOST_CHECK_EQUAL(nAfterSegmentReceived, 401); + BOOST_CHECK_EQUAL(nAfterSegmentValidated, 401); + BOOST_CHECK_EQUAL(nAfterSegmentNacked, 2); + BOOST_CHECK_EQUAL(nAfterSegmentTimedOut, 0); +} + +BOOST_AUTO_TEST_CASE(OtherNackReason) +{ + DummyValidator acceptValidator; + size_t nAfterSegmentReceived = 0; + size_t nAfterSegmentValidated = 0; + size_t nAfterSegmentNacked = 0; + size_t nAfterSegmentTimedOut = 0; + segmentsToDropOrNack.push(0); + sendNackInsteadOfDropping = true; + nackReason = lp::NackReason::NO_ROUTE; + face.onSendInterest.connect(bind(&Fixture::onInterest, this, _1)); + + shared_ptr fetcher = SegmentFetcher::start(face, Interest("/hello/world"), + acceptValidator); + connectSignals(fetcher); + fetcher->afterSegmentReceived.connect(bind([&nAfterSegmentReceived] { ++nAfterSegmentReceived; })); + fetcher->afterSegmentValidated.connect(bind([&nAfterSegmentValidated] { ++nAfterSegmentValidated; })); + fetcher->afterSegmentNacked.connect(bind([&nAfterSegmentNacked] { ++nAfterSegmentNacked; })); + fetcher->afterSegmentTimedOut.connect(bind([&nAfterSegmentTimedOut] { ++nAfterSegmentTimedOut; })); + + face.processEvents(1_s); + + BOOST_CHECK_EQUAL(nErrors, 1); + BOOST_CHECK_EQUAL(nCompletions, 0); + BOOST_CHECK_EQUAL(nAfterSegmentReceived, 0); + BOOST_CHECK_EQUAL(nAfterSegmentValidated, 0); + BOOST_CHECK_EQUAL(nAfterSegmentNacked, 1); + BOOST_CHECK_EQUAL(nAfterSegmentTimedOut, 0); + BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); +} + +BOOST_AUTO_TEST_CASE(ValidationFailure) +{ + DummyValidator validator; + validator.getPolicy().setResultCallback([] (const Name& name) { + return name.at(-1).toSegment() % 2 == 0; + }); + shared_ptr fetcher = SegmentFetcher::start(face, Interest("/hello/world"), + validator); + connectSignals(fetcher); + + auto data1 = makeDataSegment("/hello/world", 0, false); + auto data2 = makeDataSegment("/hello/world", 1, true); + + size_t nRecvSegments = 0; + fetcher->afterSegmentReceived.connect([&nRecvSegments] (const Data& receivedSegment) { + ++nRecvSegments; + }); + + size_t nValidatedSegments = 0; + fetcher->afterSegmentValidated.connect([&nValidatedSegments] (const Data& validatedSegment) { + ++nValidatedSegments; + }); + + advanceClocks(10_ms, 10); + + BOOST_CHECK_EQUAL(fetcher->m_timeLastSegmentReceived, time::steady_clock::now() - 100_ms); + + face.receive(*data1); + + advanceClocks(10_ms, 10); + + BOOST_CHECK_EQUAL(fetcher->m_timeLastSegmentReceived, time::steady_clock::now() - 100_ms); + + face.receive(*data2); + + advanceClocks(10_ms, 10); + + BOOST_CHECK_EQUAL(fetcher->m_timeLastSegmentReceived, time::steady_clock::now() - 200_ms); + BOOST_CHECK_EQUAL(nRecvSegments, 2); + BOOST_CHECK_EQUAL(nValidatedSegments, 1); + BOOST_CHECK_EQUAL(nErrors, 1); +} + +BOOST_AUTO_TEST_CASE(Stop) +{ + DummyValidator acceptValidator; + + auto fetcher = SegmentFetcher::start(face, Interest("/hello/world"), acceptValidator); + connectSignals(fetcher); + BOOST_CHECK_EQUAL(fetcher.use_count(), 2); + + fetcher->stop(); + advanceClocks(10_ms); + BOOST_CHECK_EQUAL(fetcher.use_count(), 1); + + face.receive(*makeDataSegment("/hello/world/version0", 0, true)); + advanceClocks(10_ms); + BOOST_CHECK_EQUAL(nErrors, 0); + BOOST_CHECK_EQUAL(nCompletions, 0); + + fetcher.reset(); + BOOST_CHECK_EQUAL(fetcher.use_count(), 0); + + // Make sure we can re-assign w/o any complains from ASan + fetcher = SegmentFetcher::start(face, Interest("/hello/world"), acceptValidator); + connectSignals(fetcher); + BOOST_CHECK_EQUAL(fetcher.use_count(), 2); + + advanceClocks(10_ms); + + face.receive(*makeDataSegment("/hello/world/version0", 0, true)); + + advanceClocks(10_ms); + BOOST_CHECK_EQUAL(nErrors, 0); + BOOST_CHECK_EQUAL(nCompletions, 1); + BOOST_CHECK_EQUAL(fetcher.use_count(), 1); + + // Stop from callback + bool fetcherStopped = false; + + fetcher = SegmentFetcher::start(face, Interest("/hello/world"), acceptValidator); + fetcher->afterSegmentReceived.connect([&fetcher, &fetcherStopped] (const Data& data) { + fetcherStopped = true; + fetcher->stop(); + }); + BOOST_CHECK_EQUAL(fetcher.use_count(), 2); + + advanceClocks(10_ms); + + face.receive(*makeDataSegment("/hello/world/version0", 0, true)); + + advanceClocks(10_ms); + BOOST_CHECK(fetcherStopped); + BOOST_CHECK_EQUAL(fetcher.use_count(), 1); +} + +BOOST_AUTO_TEST_CASE(Lifetime) +{ + // BasicSingleSegment, but with scoped fetcher + + DummyValidator acceptValidator; + size_t nAfterSegmentReceived = 0; + size_t nAfterSegmentValidated = 0; + size_t nAfterSegmentNacked = 0; + size_t nAfterSegmentTimedOut = 0; + + weak_ptr weakFetcher; + { + auto fetcher = SegmentFetcher::start(face, Interest("/hello/world"), acceptValidator); + weakFetcher = fetcher; + connectSignals(fetcher); + + fetcher->afterSegmentReceived.connect(bind([&nAfterSegmentReceived] { ++nAfterSegmentReceived; })); + fetcher->afterSegmentValidated.connect(bind([&nAfterSegmentValidated] { ++nAfterSegmentValidated; })); + fetcher->afterSegmentNacked.connect(bind([&nAfterSegmentNacked] { ++nAfterSegmentNacked; })); + fetcher->afterSegmentTimedOut.connect(bind([&nAfterSegmentTimedOut] { ++nAfterSegmentTimedOut; })); + } + + advanceClocks(10_ms); + BOOST_CHECK_EQUAL(weakFetcher.expired(), false); + + face.receive(*makeDataSegment("/hello/world/version0", 0, true)); + + advanceClocks(10_ms); + + BOOST_CHECK_EQUAL(nErrors, 0); + BOOST_CHECK_EQUAL(nCompletions, 1); + BOOST_CHECK_EQUAL(nAfterSegmentReceived, 1); + BOOST_CHECK_EQUAL(nAfterSegmentValidated, 1); + BOOST_CHECK_EQUAL(nAfterSegmentNacked, 0); + BOOST_CHECK_EQUAL(nAfterSegmentTimedOut, 0); + BOOST_CHECK_EQUAL(weakFetcher.expired(), true); +} + +BOOST_AUTO_TEST_CASE(OutOfScopeTimeout) +{ + DummyValidator acceptValidator; + SegmentFetcher::Options options; + options.maxTimeout = 3000_ms; + + size_t nAfterSegmentReceived = 0; + size_t nAfterSegmentValidated = 0; + size_t nAfterSegmentNacked = 0; + size_t nAfterSegmentTimedOut = 0; + + weak_ptr weakFetcher; + { + auto fetcher = SegmentFetcher::start(face, Interest("/localhost/nfd/faces/list"), + acceptValidator, options); + weakFetcher = fetcher; + connectSignals(fetcher); + fetcher->afterSegmentReceived.connect(bind([&nAfterSegmentReceived] { ++nAfterSegmentReceived; })); + fetcher->afterSegmentValidated.connect(bind([&nAfterSegmentValidated] { ++nAfterSegmentValidated; })); + fetcher->afterSegmentNacked.connect(bind([&nAfterSegmentNacked] { ++nAfterSegmentNacked; })); + fetcher->afterSegmentTimedOut.connect(bind([&nAfterSegmentTimedOut] { ++nAfterSegmentTimedOut; })); + } + + advanceClocks(500_ms, 7); + BOOST_CHECK_EQUAL(weakFetcher.expired(), true); + + BOOST_CHECK_EQUAL(nErrors, 1); + BOOST_CHECK_EQUAL(nCompletions, 0); + BOOST_CHECK_EQUAL(nAfterSegmentReceived, 0); + BOOST_CHECK_EQUAL(nAfterSegmentValidated, 0); + BOOST_CHECK_EQUAL(nAfterSegmentNacked, 0); + BOOST_CHECK_EQUAL(nAfterSegmentTimedOut, 2); +} + +BOOST_AUTO_TEST_CASE(UncanceledPendingInterestBug) // Bug #4770 +{ + DummyValidator acceptValidator; + auto fetcher = SegmentFetcher::start(face, Interest("/hello/world"), acceptValidator); + connectSignals(fetcher); + + // Fetcher will send the first interest immediately + // and the second interest after 1 second by default + advanceClocks(1100_ms); + + // Face will give data to the fetcher twice if the first interest is not canceled. + // isFinal=false to keep fetcher alive so that it can receive the second data. + face.receive(*makeDataSegment("/hello/world/version0", 0, false)); + + advanceClocks(1100_ms); + + face.receive(*makeDataSegment("/hello/world/version0", 1, true)); + + BOOST_CHECK_EQUAL(nErrors, 0); + BOOST_CHECK_EQUAL(nCompletions, 1); +} + +BOOST_AUTO_TEST_SUITE_END() // TestSegmentFetcher +BOOST_AUTO_TEST_SUITE_END() // Util + +} // namespace tests +} // namespace util +} // namespace ndn diff --git a/tests/unit/util/sha256.t.cpp b/tests/unit/util/sha256.t.cpp new file mode 100644 index 000000000..f6e0ec378 --- /dev/null +++ b/tests/unit/util/sha256.t.cpp @@ -0,0 +1,214 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2018 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/sha256.hpp" +#include "ndn-cxx/util/string-helper.hpp" + +#include "tests/boost-test.hpp" + +#include +#include + +namespace ndn { +namespace util { +namespace test { + +BOOST_AUTO_TEST_SUITE(Util) +BOOST_AUTO_TEST_SUITE(TestSha256) + +BOOST_AUTO_TEST_CASE(Basic) +{ + const uint8_t input[] = {0x01, 0x02, 0x03, 0x04}; + auto expected = fromHex("9f64a747e1b97f131fabb6b447296c9b6f0201e79fb3c5356e6c77e89b6a806a"); + + Sha256 statefulSha256; + BOOST_CHECK_EQUAL(statefulSha256.empty(), true); + + statefulSha256.update(input, 1); + statefulSha256.update(input + 1, 1); + statefulSha256.update(input + 2, 1); + statefulSha256.update(input + 3, 1); + ConstBufferPtr digest = statefulSha256.computeDigest(); + BOOST_CHECK_EQUAL(digest->size(), Sha256::DIGEST_SIZE); + BOOST_CHECK_EQUAL_COLLECTIONS(expected->data(), expected->data() + expected->size(), + digest->data(), digest->data() + digest->size()); +} + +BOOST_AUTO_TEST_CASE(ConstructFromStream) +{ + const std::string input = "Hello, world!"; + auto expected = fromHex("315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3"); + + std::istringstream is(input); + Sha256 sha(is); + BOOST_CHECK_EQUAL(sha.empty(), false); + BOOST_CHECK_EQUAL(sha.toString(), "315F5BDB76D078C43B8AC0064E4A0164612B1FCE77C869345BFC94C75894EDD3"); + + ConstBufferPtr digest = sha.computeDigest(); + BOOST_CHECK_EQUAL_COLLECTIONS(expected->data(), expected->data() + expected->size(), + digest->data(), digest->data() + digest->size()); +} + +BOOST_AUTO_TEST_CASE(Compare) +{ + const uint8_t origin[] = {0x01, 0x02, 0x03, 0x04}; + + Sha256 digest1; + digest1.update(origin, sizeof(origin)); + digest1.computeDigest(); + + Sha256 digest2; + digest2.update(origin, 1); + digest2.update(origin + 1, 1); + digest2.update(origin + 2, 1); + digest2.update(origin + 3, 1); + digest2.computeDigest(); + + BOOST_CHECK_EQUAL(digest1 == digest2, true); + BOOST_CHECK_EQUAL(digest1 != digest2, false); +} + +BOOST_AUTO_TEST_CASE(InsertionOperatorSha256) +{ + auto expected = fromHex("d7bd34bfe44a18d2aa755a344fe3e6b06ed0473772e6dfce16ac71ba0b0a241c"); + + Sha256 innerDigest; + innerDigest << "TEST"; + + Sha256 statefulSha256; + statefulSha256 << innerDigest; + ConstBufferPtr digest = statefulSha256.computeDigest(); + + BOOST_CHECK_EQUAL(statefulSha256.empty(), false); + BOOST_CHECK_EQUAL_COLLECTIONS(expected->data(), expected->data() + expected->size(), + digest->data(), digest->data() + digest->size()); +} + +BOOST_AUTO_TEST_CASE(InsertionOperatorString) +{ + const std::string input = "Hello, world!"; + auto expected = fromHex("315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3"); + + Sha256 statefulSha256; + statefulSha256 << input; + ConstBufferPtr digest = statefulSha256.computeDigest(); + + BOOST_CHECK_EQUAL(statefulSha256.empty(), false); + BOOST_CHECK_EQUAL_COLLECTIONS(expected->data(), expected->data() + expected->size(), + digest->data(), digest->data() + digest->size()); +} + +BOOST_AUTO_TEST_CASE(InsertionOperatorBlock) +{ + const uint8_t input[] = { + 0x16, 0x1b, // SignatureInfo + 0x1b, 0x01, // SignatureType + 0x01, // Sha256WithRsa + 0x1c, 0x16, // KeyLocator + 0x07, 0x14, // Name + 0x08, 0x04, + 0x74, 0x65, 0x73, 0x74, + 0x08, 0x03, + 0x6b, 0x65, 0x79, + 0x08, 0x07, + 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72 + }; + auto expected = fromHex("b372edfd4d6a4db2cfeaeead6c34fdee9b9e759f7b8d799cf8067e39e7f2886c"); + + Sha256 statefulSha256; + statefulSha256 << Block{input, sizeof(input)}; + ConstBufferPtr digest = statefulSha256.computeDigest(); + + BOOST_CHECK_EQUAL(statefulSha256.empty(), false); + BOOST_CHECK_EQUAL_COLLECTIONS(expected->data(), expected->data() + expected->size(), + digest->data(), digest->data() + digest->size()); +} + +BOOST_AUTO_TEST_CASE(InsertionOperatorUint64t) +{ + const uint64_t input[] = {1, 2, 3, 4}; + auto expected = fromHex("7236c00c170036c6de133a878210ddd58567aa1d0619a0f70f69e38ae6f916e9"); + + Sha256 statefulSha256; + for (size_t i = 0; i < sizeof(input) / sizeof(uint64_t); ++i) { + statefulSha256 << boost::endian::native_to_big(input[i]); + } + ConstBufferPtr digest = statefulSha256.computeDigest(); + + BOOST_CHECK_EQUAL(statefulSha256.empty(), false); + BOOST_CHECK_EQUAL_COLLECTIONS(expected->data(), expected->data() + expected->size(), + digest->data(), digest->data() + digest->size()); +} + +BOOST_AUTO_TEST_CASE(Reset) +{ + Sha256 sha; + BOOST_CHECK_EQUAL(sha.empty(), true); + + sha << 42; + BOOST_CHECK_EQUAL(sha.empty(), false); + + sha.computeDigest(); // finalize + sha.reset(); + BOOST_CHECK_EQUAL(sha.empty(), true); + BOOST_CHECK_NO_THROW(sha << 42); +} + +BOOST_AUTO_TEST_CASE(Error) +{ + Sha256 sha; + sha << 42; + sha.computeDigest(); // finalize + BOOST_CHECK_THROW(sha << 42, Sha256::Error); +} + +BOOST_AUTO_TEST_CASE(StaticComputeDigest) +{ + const uint8_t input[] = {0x01, 0x02, 0x03, 0x04}; + auto expected = fromHex("9f64a747e1b97f131fabb6b447296c9b6f0201e79fb3c5356e6c77e89b6a806a"); + + ConstBufferPtr digest = Sha256::computeDigest(input, sizeof(input)); + BOOST_CHECK_EQUAL_COLLECTIONS(expected->data(), expected->data() + expected->size(), + digest->data(), digest->data() + digest->size()); +} + +BOOST_AUTO_TEST_CASE(Print) +{ + const uint8_t origin[] = {0x94, 0xEE, 0x05, 0x93, 0x35, 0xE5, 0x87, 0xE5, + 0x01, 0xCC, 0x4B, 0xF9, 0x06, 0x13, 0xE0, 0x81, + 0x4F, 0x00, 0xA7, 0xB0, 0x8B, 0xC7, 0xC6, 0x48, + 0xFD, 0x86, 0x5A, 0x2A, 0xF6, 0xA2, 0x2C, 0xC2}; + std::string expected = toHex(origin, sizeof(origin)); + + Sha256 digest; + digest << "TEST"; + std::ostringstream os; + os << digest; + BOOST_CHECK_EQUAL(os.str(), expected); + BOOST_CHECK_EQUAL(digest.toString(), expected); +} + +BOOST_AUTO_TEST_SUITE_END() // TestSha256 +BOOST_AUTO_TEST_SUITE_END() // Util + +} // namespace test +} // namespace util +} // namespace ndn diff --git a/tests/unit-tests/util/signal.t.cpp b/tests/unit/util/signal.t.cpp similarity index 82% rename from tests/unit-tests/util/signal.t.cpp rename to tests/unit/util/signal.t.cpp index eb02324ca..2c53336cf 100644 --- a/tests/unit-tests/util/signal.t.cpp +++ b/tests/unit/util/signal.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,9 +19,9 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "util/signal.hpp" +#include "ndn-cxx/util/signal.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" namespace ndn { namespace util { @@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(OneArgument) BOOST_AUTO_TEST_CASE(TwoArguments) { - Signal::type, int, int> sig; + Signal, int, int> sig; int hit = 0; sig.connect([&hit] (int a, int b) { @@ -138,8 +138,8 @@ BOOST_AUTO_TEST_CASE(HandlerByVal) RefObject refObject; RefObject::s_copyCount = 0; - Signal::type, RefObject> sig; - sig.connect([] (RefObject ro) {}); + Signal, RefObject> sig; + sig.connect([] (RefObject) {}); sig(refObject); BOOST_CHECK_EQUAL(RefObject::s_copyCount, 1); @@ -152,8 +152,8 @@ BOOST_AUTO_TEST_CASE(HandlerByRef) RefObject refObject; RefObject::s_copyCount = 0; - Signal::type, RefObject> sig; - sig.connect([] (const RefObject& ro) {}); + Signal, RefObject> sig; + sig.connect([] (const RefObject&) {}); sig(refObject); BOOST_CHECK_EQUAL(RefObject::s_copyCount, 0); @@ -289,9 +289,9 @@ BOOST_AUTO_TEST_CASE(AutoDisconnectRelease) BOOST_AUTO_TEST_CASE(AutoDisconnectMove) { SignalOwner0 so; - unique_ptr sc2; - int hit = 0; + + unique_ptr sc2; { ScopedConnection sc = so.sig.connect([&hit] { ++hit; }); @@ -299,15 +299,35 @@ BOOST_AUTO_TEST_CASE(AutoDisconnectMove) BOOST_CHECK_EQUAL(hit, 1); // handler called BOOST_CHECK_EQUAL(sc.isConnected(), true); - sc2.reset(new ScopedConnection(std::move(sc))); + sc2 = make_unique(std::move(sc)); // move constructor BOOST_CHECK_EQUAL(sc.isConnected(), false); BOOST_CHECK_EQUAL(sc2->isConnected(), true); - // sc goes out of scope, but not disconnecting + // sc goes out of scope, but without disconnecting } so.emitSignal(sig); BOOST_CHECK_EQUAL(hit, 2); // handler called + sc2.reset(); + + ScopedConnection sc3; + { + ScopedConnection sc = so.sig.connect([&hit] { ++hit; }); + + so.emitSignal(sig); + BOOST_CHECK_EQUAL(hit, 3); // handler called + BOOST_CHECK_EQUAL(sc.isConnected(), true); + BOOST_CHECK_EQUAL(sc3.isConnected(), false); + + sc3 = std::move(sc); // move assignment + BOOST_CHECK_EQUAL(sc.isConnected(), false); + BOOST_CHECK_EQUAL(sc3.isConnected(), true); + + // sc goes out of scope, but without disconnecting + } + + so.emitSignal(sig); + BOOST_CHECK_EQUAL(hit, 4); // handler called } BOOST_AUTO_TEST_CASE(ConnectSingleShot) @@ -404,14 +424,17 @@ BOOST_AUTO_TEST_CASE(ThrowInHandler) { SignalOwner0 so; - struct HandlerError : public std::exception + class HandlerError : public std::exception { }; int hit = 0; so.sig.connect([&] { ++hit; - BOOST_THROW_EXCEPTION(HandlerError()); + // use plain 'throw' to ensure that Signal does not depend on the internal + // machinery of NDN_THROW and that it can catch all exceptions regardless + // of how they are thrown by the application + throw HandlerError{}; }); BOOST_CHECK_THROW(so.emitSignal(sig), HandlerError); @@ -421,6 +444,35 @@ BOOST_AUTO_TEST_CASE(ThrowInHandler) BOOST_CHECK_EQUAL(hit, 2); // handler called } +BOOST_AUTO_TEST_CASE(ConnectionEquality) +{ + SignalOwner0 so; + + Connection conn1, conn2; + BOOST_CHECK(conn1 == conn2); + + conn1 = so.sig.connect([]{}); + BOOST_CHECK(conn1 != conn2); + + conn2 = so.sig.connect([]{}); + BOOST_CHECK(conn1 != conn2); + + conn1.disconnect(); + BOOST_CHECK(conn1 != conn2); + BOOST_CHECK(conn1 == Connection{}); + + conn2.disconnect(); + BOOST_CHECK(conn1 == conn2); + + conn1 = conn2 = so.sig.connect([]{}); + BOOST_CHECK(conn1 == conn2); + BOOST_CHECK(conn1 != Connection{}); + + conn1.disconnect(); + BOOST_CHECK(conn1 == conn2); + BOOST_CHECK(conn1 == Connection{}); +} + BOOST_AUTO_TEST_SUITE_END() // TestSignal BOOST_AUTO_TEST_SUITE_END() // Util diff --git a/tests/unit/util/simple-notification.hpp b/tests/unit/util/simple-notification.hpp new file mode 100644 index 000000000..431b8c289 --- /dev/null +++ b/tests/unit/util/simple-notification.hpp @@ -0,0 +1,94 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014-2019 Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TESTS_UNIT_UTIL_SIMPLE_NOTIFICATION_HPP +#define NDN_TESTS_UNIT_UTIL_SIMPLE_NOTIFICATION_HPP + +#include "ndn-cxx/encoding/encoding-buffer.hpp" + +namespace ndn { +namespace util { +namespace tests { + +class SimpleNotification +{ +public: + SimpleNotification() = default; + + explicit + SimpleNotification(const Block& block) + { + wireDecode(block); + } + + SimpleNotification(const std::string& message) + : m_message(message) + { + } + + Block + wireEncode() const + { + ndn::EncodingBuffer buffer; + buffer.prependByteArrayBlock(0x8888, + reinterpret_cast(m_message.c_str()), + m_message.size()); + return buffer.block(); + } + + void + wireDecode(const Block& block) + { + m_message.assign(reinterpret_cast(block.value()), + block.value_size()); + + // error for testing + if (!m_message.empty() && m_message[0] == '\x07') + NDN_THROW(tlv::Error("0x07 error")); + } + + const std::string& + getMessage() const + { + return m_message; + } + + void + setMessage(const std::string& message) + { + m_message = message; + } + +private: + std::string m_message; +}; + +} // namespace tests +} // namespace util +} // namespace ndn + +#endif // NDN_TESTS_UNIT_UTIL_SIMPLE_NOTIFICATION_HPP diff --git a/tests/unit-tests/util/sqlite3-statement.t.cpp b/tests/unit/util/sqlite3-statement.t.cpp similarity index 94% rename from tests/unit-tests/util/sqlite3-statement.t.cpp rename to tests/unit/util/sqlite3-statement.t.cpp index b440f7a80..c5ee8b6ee 100644 --- a/tests/unit-tests/util/sqlite3-statement.t.cpp +++ b/tests/unit/util/sqlite3-statement.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,11 +19,12 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "util/sqlite3-statement.hpp" +#include "ndn-cxx/util/sqlite3-statement.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" #include +#include #include namespace ndn { @@ -134,10 +135,9 @@ BOOST_AUTO_TEST_CASE(Basic) BOOST_CHECK_EQUAL(stmt.step(), SQLITE_ROW); BOOST_CHECK_EQUAL(stmt.getInt(0), 4); - Block newBlock; - BOOST_CHECK_NO_THROW(newBlock = stmt.getBlock(1)); + Block newBlock = stmt.getBlock(1); BOOST_CHECK_EQUAL(newBlock.type(), 100); - BOOST_CHECK(newBlock == block); + BOOST_CHECK_EQUAL(newBlock, block); BOOST_CHECK_EQUAL(stmt.step(), SQLITE_ROW); BOOST_CHECK_EQUAL(stmt.getInt(0), 5); diff --git a/tests/unit/util/string-helper.t.cpp b/tests/unit/util/string-helper.t.cpp new file mode 100644 index 000000000..8747301da --- /dev/null +++ b/tests/unit/util/string-helper.t.cpp @@ -0,0 +1,214 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/string-helper.hpp" +#include "ndn-cxx/encoding/buffer.hpp" + +#include "tests/boost-test.hpp" + +#include +#include + +#if BOOST_VERSION >= 105900 +#include +#else +#include +#endif + +namespace ndn { +namespace util { +namespace test { + +using boost::test_tools::output_test_stream; + +BOOST_AUTO_TEST_SUITE(Util) +BOOST_AUTO_TEST_SUITE(TestStringHelper) + +BOOST_AUTO_TEST_CASE(PrintHex) +{ + output_test_stream os; + + printHex(os, 0); + BOOST_CHECK(os.is_equal("0x0")); + + printHex(os, 42); + BOOST_CHECK(os.is_equal("0x2a")); + + printHex(os, 2748, true); + BOOST_CHECK(os.is_equal("0xABC")); + + printHex(os, static_cast(-1)); + BOOST_CHECK(os.is_equal("0xffffffffffffffff")); + + printHex(os, ~0U, true); + BOOST_CHECK(os.is_equal("0xFFFFFFFF")); + + printHex(os, ~0ULL, true); + BOOST_CHECK(os.is_equal("0xFFFFFFFFFFFFFFFF")); +} + +BOOST_AUTO_TEST_CASE(AsHex) +{ + using ndn::AsHex; + output_test_stream os; + + os << AsHex{0}; + BOOST_CHECK(os.is_equal("0x0")); + + os << AsHex{42}; + BOOST_CHECK(os.is_equal("0x2a")); + + os << std::uppercase << AsHex{~0U}; + BOOST_CHECK(os.is_equal("0xFFFFFFFF")); + + os << std::nouppercase << AsHex{~0U}; + BOOST_CHECK(os.is_equal("0xffffffff")); +} + +BOOST_AUTO_TEST_CASE(ToHex) +{ + std::string test = "Hello, world!"; + BOOST_CHECK_EQUAL(toHex(reinterpret_cast(test.data()), test.size()), + "48656C6C6F2C20776F726C6421"); + BOOST_CHECK_EQUAL(toHex(reinterpret_cast(test.data()), test.size(), false), + "48656c6c6f2c20776f726c6421"); + BOOST_CHECK_EQUAL(toHex(nullptr, 0), ""); + + Buffer buffer(test.data(), test.size()); + BOOST_CHECK_EQUAL(toHex(buffer, false), "48656c6c6f2c20776f726c6421"); + BOOST_CHECK_EQUAL(toHex(Buffer{}), ""); +} + +BOOST_AUTO_TEST_CASE(FromHex) +{ + BOOST_CHECK(*fromHex("") == Buffer{}); + BOOST_CHECK(*fromHex("48656c6c6f2c20776f726c6421") == + (std::vector{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, + 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21})); + BOOST_CHECK(*fromHex("012a3Bc4defAB5CdEF") == + (std::vector{0x01, 0x2a, 0x3b, 0xc4, 0xde, + 0xfa, 0xb5, 0xcd, 0xef})); + + BOOST_CHECK_THROW(fromHex("1"), StringHelperError); + BOOST_CHECK_THROW(fromHex("zz"), StringHelperError); + BOOST_CHECK_THROW(fromHex("00az"), StringHelperError); + BOOST_CHECK_THROW(fromHex("1234z"), StringHelperError); +} + +BOOST_AUTO_TEST_CASE(ToHexChar) +{ + static const std::vector> hexMap{ + {0, '0'}, {1, '1'}, {2, '2'}, {3, '3'}, {4, '4'}, {5, '5'}, {6, '6'}, {7, '7'}, + {8, '8'}, {9, '9'}, {10, 'A'}, {11, 'B'}, {12, 'C'}, {13, 'D'}, {14, 'E'}, {15, 'F'} + }; + + for (const auto& i : hexMap) { + BOOST_CHECK_EQUAL(toHexChar(i.first), i.second); + BOOST_CHECK_EQUAL(toHexChar(i.first + 16), i.second); + BOOST_CHECK_EQUAL(toHexChar(i.first + 32), i.second); + BOOST_CHECK_EQUAL(toHexChar(i.first + 240), i.second); + BOOST_CHECK_EQUAL(toHexChar(i.first, false), std::tolower(static_cast(i.second))); + } +} + +BOOST_AUTO_TEST_CASE(FromHexChar) +{ + // for (int ch = 0; ch <= std::numeric_limits::max(); ++ch) { + // std::cout << "{0x" << std::hex << ch << ", " + // << std::dec << fromHexChar(static_cast(ch)) << "}, "; + // if (ch % 8 == 7) + // std::cout << std::endl; + // } + static const std::vector> hexMap{ + {0x0, -1}, {0x1, -1}, {0x2, -1}, {0x3, -1}, {0x4, -1}, {0x5, -1}, {0x6, -1}, {0x7, -1}, + {0x8, -1}, {0x9, -1}, {0xa, -1}, {0xb, -1}, {0xc, -1}, {0xd, -1}, {0xe, -1}, {0xf, -1}, + {0x10, -1}, {0x11, -1}, {0x12, -1}, {0x13, -1}, {0x14, -1}, {0x15, -1}, {0x16, -1}, {0x17, -1}, + {0x18, -1}, {0x19, -1}, {0x1a, -1}, {0x1b, -1}, {0x1c, -1}, {0x1d, -1}, {0x1e, -1}, {0x1f, -1}, + {0x20, -1}, {0x21, -1}, {0x22, -1}, {0x23, -1}, {0x24, -1}, {0x25, -1}, {0x26, -1}, {0x27, -1}, + {0x28, -1}, {0x29, -1}, {0x2a, -1}, {0x2b, -1}, {0x2c, -1}, {0x2d, -1}, {0x2e, -1}, {0x2f, -1}, + {0x30, 0}, {0x31, 1}, {0x32, 2}, {0x33, 3}, {0x34, 4}, {0x35, 5}, {0x36, 6}, {0x37, 7}, + {0x38, 8}, {0x39, 9}, {0x3a, -1}, {0x3b, -1}, {0x3c, -1}, {0x3d, -1}, {0x3e, -1}, {0x3f, -1}, + {0x40, -1}, {0x41, 10}, {0x42, 11}, {0x43, 12}, {0x44, 13}, {0x45, 14}, {0x46, 15}, {0x47, -1}, + {0x48, -1}, {0x49, -1}, {0x4a, -1}, {0x4b, -1}, {0x4c, -1}, {0x4d, -1}, {0x4e, -1}, {0x4f, -1}, + {0x50, -1}, {0x51, -1}, {0x52, -1}, {0x53, -1}, {0x54, -1}, {0x55, -1}, {0x56, -1}, {0x57, -1}, + {0x58, -1}, {0x59, -1}, {0x5a, -1}, {0x5b, -1}, {0x5c, -1}, {0x5d, -1}, {0x5e, -1}, {0x5f, -1}, + {0x60, -1}, {0x61, 10}, {0x62, 11}, {0x63, 12}, {0x64, 13}, {0x65, 14}, {0x66, 15}, {0x67, -1}, + {0x68, -1}, {0x69, -1}, {0x6a, -1}, {0x6b, -1}, {0x6c, -1}, {0x6d, -1}, {0x6e, -1}, {0x6f, -1}, + {0x70, -1}, {0x71, -1}, {0x72, -1}, {0x73, -1}, {0x74, -1}, {0x75, -1}, {0x76, -1}, {0x77, -1}, + {0x78, -1}, {0x79, -1}, {0x7a, -1}, {0x7b, -1}, {0x7c, -1}, {0x7d, -1}, {0x7e, -1}, {0x7f, -1}, + {0x80, -1}, {0x81, -1}, {0x82, -1}, {0x83, -1}, {0x84, -1}, {0x85, -1}, {0x86, -1}, {0x87, -1}, + {0x88, -1}, {0x89, -1}, {0x8a, -1}, {0x8b, -1}, {0x8c, -1}, {0x8d, -1}, {0x8e, -1}, {0x8f, -1}, + {0x90, -1}, {0x91, -1}, {0x92, -1}, {0x93, -1}, {0x94, -1}, {0x95, -1}, {0x96, -1}, {0x97, -1}, + {0x98, -1}, {0x99, -1}, {0x9a, -1}, {0x9b, -1}, {0x9c, -1}, {0x9d, -1}, {0x9e, -1}, {0x9f, -1}, + {0xa0, -1}, {0xa1, -1}, {0xa2, -1}, {0xa3, -1}, {0xa4, -1}, {0xa5, -1}, {0xa6, -1}, {0xa7, -1}, + {0xa8, -1}, {0xa9, -1}, {0xaa, -1}, {0xab, -1}, {0xac, -1}, {0xad, -1}, {0xae, -1}, {0xaf, -1}, + {0xb0, -1}, {0xb1, -1}, {0xb2, -1}, {0xb3, -1}, {0xb4, -1}, {0xb5, -1}, {0xb6, -1}, {0xb7, -1}, + {0xb8, -1}, {0xb9, -1}, {0xba, -1}, {0xbb, -1}, {0xbc, -1}, {0xbd, -1}, {0xbe, -1}, {0xbf, -1}, + {0xc0, -1}, {0xc1, -1}, {0xc2, -1}, {0xc3, -1}, {0xc4, -1}, {0xc5, -1}, {0xc6, -1}, {0xc7, -1}, + {0xc8, -1}, {0xc9, -1}, {0xca, -1}, {0xcb, -1}, {0xcc, -1}, {0xcd, -1}, {0xce, -1}, {0xcf, -1}, + {0xd0, -1}, {0xd1, -1}, {0xd2, -1}, {0xd3, -1}, {0xd4, -1}, {0xd5, -1}, {0xd6, -1}, {0xd7, -1}, + {0xd8, -1}, {0xd9, -1}, {0xda, -1}, {0xdb, -1}, {0xdc, -1}, {0xdd, -1}, {0xde, -1}, {0xdf, -1}, + {0xe0, -1}, {0xe1, -1}, {0xe2, -1}, {0xe3, -1}, {0xe4, -1}, {0xe5, -1}, {0xe6, -1}, {0xe7, -1}, + {0xe8, -1}, {0xe9, -1}, {0xea, -1}, {0xeb, -1}, {0xec, -1}, {0xed, -1}, {0xee, -1}, {0xef, -1}, + {0xf0, -1}, {0xf1, -1}, {0xf2, -1}, {0xf3, -1}, {0xf4, -1}, {0xf5, -1}, {0xf6, -1}, {0xf7, -1}, + {0xf8, -1}, {0xf9, -1}, {0xfa, -1}, {0xfb, -1}, {0xfc, -1}, {0xfd, -1}, {0xfe, -1}, {0xff, -1} + }; + + for (const auto& item : hexMap) { + BOOST_CHECK_EQUAL(fromHexChar(item.first), item.second); + } +} + +BOOST_AUTO_TEST_CASE(Escape) +{ + BOOST_CHECK_EQUAL(escape(""), ""); + BOOST_CHECK_EQUAL(escape("foo42"), "foo42"); + BOOST_CHECK_EQUAL(escape("foo%bar"), "foo%25bar"); + BOOST_CHECK_EQUAL(escape("lower UPPER"), "lower%20UPPER"); + BOOST_CHECK_EQUAL(escape("-._~"), "-._~"); + BOOST_CHECK_EQUAL(escape(":/?#[]@"), "%3A%2F%3F%23%5B%5D%40"); + + output_test_stream os; + const char str[] = "\x01\x2a\x3b\xc4\xde\xfa\xb5\xcd\xef"; + escape(os, str, std::strlen(str)); + BOOST_CHECK(os.is_equal("%01%2A%3B%C4%DE%FA%B5%CD%EF")); +} + +BOOST_AUTO_TEST_CASE(Unescape) +{ + BOOST_CHECK_EQUAL(unescape(""), ""); + BOOST_CHECK_EQUAL(unescape("Hello%01, world!%AA "), "Hello\x01, world!\xAA "); + BOOST_CHECK_EQUAL(unescape("Bad %ZZ (not a hex value)"), "Bad %ZZ (not a hex value)"); + BOOST_CHECK_EQUAL(unescape("Bad %a (should be two hex chars)"), "Bad %a (should be two hex chars)"); + BOOST_CHECK_EQUAL(unescape("Bad %a"), "Bad %a"); + + output_test_stream os; + const char str[] = "%01%2a%3B%c4%de%fA%B5%Cd%EF"; + unescape(os, str, std::strlen(str)); + BOOST_CHECK(os.is_equal("\x01\x2a\x3b\xc4\xde\xfa\xb5\xcd\xef")); +} + +BOOST_AUTO_TEST_SUITE_END() // TestStringHelper +BOOST_AUTO_TEST_SUITE_END() // Util + +} // namespace test +} // namespace util +} // namespace ndn diff --git a/tests/unit-tests/util/time-unit-test-clock.t.cpp b/tests/unit/util/time-unit-test-clock.t.cpp similarity index 82% rename from tests/unit-tests/util/time-unit-test-clock.t.cpp rename to tests/unit/util/time-unit-test-clock.t.cpp index 17ceb3912..b65c9f966 100644 --- a/tests/unit-tests/util/time-unit-test-clock.t.cpp +++ b/tests/unit/util/time-unit-test-clock.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,11 +19,11 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "util/time-unit-test-clock.hpp" -#include "util/scheduler.hpp" +#include "ndn-cxx/util/time-unit-test-clock.hpp" +#include "ndn-cxx/util/scheduler.hpp" -#include "boost-test.hpp" -#include "../unit-test-time-fixture.hpp" +#include "tests/boost-test.hpp" +#include "tests/unit/unit-test-time-fixture.hpp" #include #include @@ -43,11 +43,11 @@ BOOST_AUTO_TEST_CASE(SystemClock) BOOST_CHECK_EQUAL(time::system_clock::now().time_since_epoch(), time::UnitTestClockTraits::getDefaultStartTime()); - steadyClock->advance(time::days(1)); + steadyClock->advance(1_day); BOOST_CHECK_EQUAL(time::system_clock::now().time_since_epoch(), time::UnitTestClockTraits::getDefaultStartTime()); - systemClock->advance(time::days(1)); + systemClock->advance(1_day); BOOST_CHECK_GT(time::system_clock::now().time_since_epoch(), time::UnitTestClockTraits::getDefaultStartTime()); @@ -59,7 +59,7 @@ BOOST_AUTO_TEST_CASE(SystemClock) BOOST_CHECK_EQUAL(time::system_clock::now(), referenceTime); BOOST_CHECK_EQUAL(boost::lexical_cast(time::system_clock::now()), - "1390966967032000000 nanoseconds since unit test clock advancements"); + "1390966967032000000 nanoseconds since unit test beginning"); BOOST_CHECK_EQUAL(time::toIsoString(referenceTime), "20140129T034247.032000"); BOOST_CHECK_EQUAL(time::toString(referenceTime), "2014-01-29 03:42:47"); @@ -77,16 +77,16 @@ BOOST_AUTO_TEST_CASE(SystemClock) BOOST_CHECK_EQUAL(time::fromIsoString("20140129T034247.032000"), referenceTime); BOOST_CHECK_EQUAL(time::fromIsoString("20140129T034247.032000Z"), referenceTime); BOOST_CHECK_EQUAL(time::fromString("2014-01-29 03:42:47"), - time::fromUnixTimestamp(time::seconds(1390966967))); + time::fromUnixTimestamp(1390966967_s)); // Unfortunately, not all systems has lv_LV locale installed :( // BOOST_CHECK_EQUAL(time::fromString("2014. gada 29. Janvāris", "%Y. gada %d. %B", // std::locale("lv_LV.UTF-8")), - // time::fromUnixTimestamp(time::seconds(1390953600))); + // time::fromUnixTimestamp(1390953600_s)); BOOST_CHECK_EQUAL(time::fromString("2014 -- 29 -- January", "%Y -- %d -- %B", std::locale("C")), - time::fromUnixTimestamp(time::seconds(1390953600))); + time::fromUnixTimestamp(1390953600_s)); } BOOST_AUTO_TEST_CASE(SteadyClock) @@ -98,21 +98,21 @@ BOOST_AUTO_TEST_CASE(SteadyClock) BOOST_CHECK_EQUAL(time::steady_clock::now().time_since_epoch(), time::steady_clock::duration::zero()); - systemClock->advance(time::days(36500)); + systemClock->advance(36500_days); BOOST_CHECK_EQUAL(time::steady_clock::now().time_since_epoch(), time::steady_clock::duration::zero()); - steadyClock->advance(time::nanoseconds(100)); - BOOST_CHECK_EQUAL(time::steady_clock::now().time_since_epoch(), time::nanoseconds(100)); + steadyClock->advance(100_ns); + BOOST_CHECK_EQUAL(time::steady_clock::now().time_since_epoch(), 100_ns); - steadyClock->advance(time::microseconds(100)); - BOOST_CHECK_EQUAL(time::steady_clock::now().time_since_epoch(), time::nanoseconds(100100)); + steadyClock->advance(100_us); + BOOST_CHECK_EQUAL(time::steady_clock::now().time_since_epoch(), 100100_ns); - steadyClock->setNow(time::nanoseconds(100)); - BOOST_CHECK_EQUAL(time::steady_clock::now().time_since_epoch(), time::nanoseconds(100)); + steadyClock->setNow(1_ms); + BOOST_CHECK_EQUAL(time::steady_clock::now().time_since_epoch(), 1000000_ns); BOOST_CHECK_EQUAL(boost::lexical_cast(time::steady_clock::now()), - "100 nanoseconds since unit test clock advancements"); + "1000000 nanoseconds since unit test beginning"); } BOOST_AUTO_TEST_CASE(Scheduler) @@ -120,12 +120,12 @@ BOOST_AUTO_TEST_CASE(Scheduler) ndn::Scheduler scheduler(io); bool hasFired = false; - scheduler.scheduleEvent(time::seconds(100), [&] { hasFired = true; }); + scheduler.schedule(100_s, [&] { hasFired = true; }); io.poll(); BOOST_CHECK_EQUAL(hasFired, false); - steadyClock->advance(time::seconds(100)); + steadyClock->advance(100_s); io.poll(); BOOST_CHECK_EQUAL(hasFired, true); diff --git a/tests/unit/util/time.t.cpp b/tests/unit/util/time.t.cpp new file mode 100644 index 000000000..3f5f531a7 --- /dev/null +++ b/tests/unit/util/time.t.cpp @@ -0,0 +1,141 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndn-cxx/util/time.hpp" + +#include "tests/boost-test.hpp" + +#include +#include + +namespace ndn { +namespace time { +namespace tests { + +BOOST_AUTO_TEST_SUITE(Util) +BOOST_AUTO_TEST_SUITE(TestTime) + +BOOST_AUTO_TEST_CASE(SystemClock) +{ + system_clock::TimePoint value = system_clock::now(); + system_clock::TimePoint referenceTime = fromUnixTimestamp(milliseconds(1390966967032LL)); + + BOOST_CHECK_GT(value, referenceTime); + + BOOST_CHECK_EQUAL(toIsoString(referenceTime), "20140129T034247.032000"); + BOOST_CHECK_EQUAL(toString(referenceTime), "2014-01-29 03:42:47"); + BOOST_CHECK_EQUAL(toString(referenceTime), "2014-01-29 03:42:47"); + + // Unfortunately, not all systems has lv_LV locale installed :( + // BOOST_CHECK_EQUAL(toString(referenceTime, "%Y. gada %d. %B", std::locale("lv_LV.UTF-8")), + // "2014. gada 29. Janvāris"); + + BOOST_CHECK_EQUAL(toString(referenceTime, "%Y -- %d -- %B", std::locale("C")), + "2014 -- 29 -- January"); + + BOOST_CHECK_EQUAL(fromIsoString("20140129T034247.032000"), referenceTime); + BOOST_CHECK_EQUAL(fromIsoString("20140129T034247.032000Z"), referenceTime); + BOOST_CHECK_EQUAL(fromString("2014-01-29 03:42:47"), fromUnixTimestamp(1390966967_s)); + + // Unfortunately, not all systems has lv_LV locale installed :( + // BOOST_CHECK_EQUAL(fromString("2014. gada 29. Janvāris", "%Y. gada %d. %B", std::locale("lv_LV.UTF-8")), + // fromUnixTimestamp(1390953600_s)); + + BOOST_CHECK_EQUAL(fromString("2014 -- 29 -- January", "%Y -- %d -- %B", std::locale("C")), + fromUnixTimestamp(1390953600_s)); +} + +BOOST_AUTO_TEST_CASE(SteadyClock) +{ + steady_clock::TimePoint oldValue = steady_clock::now(); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + steady_clock::TimePoint newValue = steady_clock::now(); + BOOST_CHECK_GT(newValue, oldValue); +} + +BOOST_AUTO_TEST_CASE(Abs) +{ + BOOST_CHECK_EQUAL(abs(nanoseconds(24422)), nanoseconds(24422)); + BOOST_CHECK_EQUAL(abs(microseconds(0)), microseconds(0)); + BOOST_CHECK_EQUAL(abs(milliseconds(-15583)), milliseconds(15583)); +} + +BOOST_AUTO_TEST_CASE(LargeDates) +{ + auto value = fromUnixTimestamp(1390966967032_ms); + BOOST_CHECK_EQUAL(toIsoString(value), "20140129T034247.032000"); + BOOST_CHECK_EQUAL(fromIsoString("20140129T034247.032000"), value); + BOOST_CHECK_EQUAL(toString(value, "%Y-%m-%d %H:%M:%S%F"), "2014-01-29 03:42:47.032000"); + BOOST_CHECK_EQUAL(fromString("2014-01-29 03:42:47.032000", "%Y-%m-%d %H:%M:%S%F"), value); + + value += 36524_days; + BOOST_CHECK_EQUAL(toIsoString(value), "21140129T034247.032000"); + BOOST_CHECK_EQUAL(fromIsoString("21140129T034247.032000"), value); + BOOST_CHECK_EQUAL(toString(value, "%Y-%m-%d %H:%M:%S%F"), "2114-01-29 03:42:47.032000"); + BOOST_CHECK_EQUAL(fromString("2114-01-29 03:42:47.03200", "%Y-%m-%d %H:%M:%S%F"), value); +} + +BOOST_AUTO_TEST_CASE(Literals) +{ + BOOST_CHECK_EQUAL(42_s, seconds(42)); + + BOOST_CHECK_EQUAL(1_day, 24_h); + BOOST_CHECK_EQUAL(2_days, 48_h); + BOOST_CHECK_EQUAL(0.5_day, 12_h); + BOOST_CHECK_EQUAL(.5_days, 12_h); + + BOOST_CHECK_EQUAL(1_h, 60_min); + BOOST_CHECK_EQUAL(0.5_h, 30_min); + + BOOST_CHECK_EQUAL(1_min, 60_s); + BOOST_CHECK_EQUAL(0.5_min, 30_s); + + BOOST_CHECK_EQUAL(1_s, 1000_ms); + BOOST_CHECK_EQUAL(0.5_s, 500_ms); + + BOOST_CHECK_EQUAL(1_ms, 1000_us); + BOOST_CHECK_EQUAL(0.5_ms, 500_us); + + BOOST_CHECK_EQUAL(1_us, 1000_ns); + BOOST_CHECK_EQUAL(0.5_us, 500_ns); + + BOOST_CHECK_EQUAL(1_ns, nanoseconds(1)); + BOOST_CHECK_EQUAL(5.5_ns, 0.0055_us); +} + +BOOST_AUTO_TEST_CASE(Year2038) +{ + auto year2042 = fromIsoString("20420101T000001.042000"); + auto year2010 = fromIsoString("20100101T000001.042000"); + + BOOST_CHECK_EQUAL(boost::lexical_cast(year2010), + "1262304001042000000 nanoseconds since Jan 1, 1970"); + BOOST_CHECK_EQUAL(boost::lexical_cast(year2042), + "2272147201042000000 nanoseconds since Jan 1, 1970"); + BOOST_CHECK_GT(year2042, year2010); +} + +BOOST_AUTO_TEST_SUITE_END() // TestTime +BOOST_AUTO_TEST_SUITE_END() // Util + +} // namespace tests +} // namespace time +} // namespace ndn diff --git a/tests/unit-tests/version.t.cpp b/tests/unit/version.t.cpp similarity index 92% rename from tests/unit-tests/version.t.cpp rename to tests/unit/version.t.cpp index 5cb6622ee..a56769511 100644 --- a/tests/unit-tests/version.t.cpp +++ b/tests/unit/version.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2018 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -19,10 +19,10 @@ * See AUTHORS.md for complete list of ndn-cxx authors and contributors. */ -#include "version.hpp" -#include "common.hpp" +#include "ndn-cxx/version.hpp" +#include "ndn-cxx/detail/common.hpp" -#include "boost-test.hpp" +#include "tests/boost-test.hpp" #include diff --git a/tests/unit/wscript b/tests/unit/wscript new file mode 100644 index 000000000..bc7ce0f47 --- /dev/null +++ b/tests/unit/wscript @@ -0,0 +1,29 @@ +# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +top = '../..' + +def build(bld): + configPath = 'UNIT_TEST_CONFIG_PATH="%s"' % bld.bldnode.make_node('tmp-files') + + # unit test objects + srcFiles = bld.path.ant_glob('**/*.cpp', excl=['main.cpp', + '**/*-osx.t.cpp', + '**/*-sqlite3.t.cpp']) + + if bld.env['HAVE_OSX_FRAMEWORKS']: + srcFiles += bld.path.ant_glob('**/*-osx.t.cpp') + + # In case we want to make it optional later + srcFiles += bld.path.ant_glob('**/*-sqlite3.t.cpp') + + bld.objects(target='unit-tests-objects', + source=srcFiles, + use='tests-common', + defines=[configPath]) + + # unit test binary + bld.program(target='../../unit-tests', + name='unit-tests', + source=['main.cpp'], + use='unit-tests-objects', + install_path=None) diff --git a/tests/wscript b/tests/wscript index ad31f19ff..8e269f080 100644 --- a/tests/wscript +++ b/tests/wscript @@ -1,50 +1,14 @@ # -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -from waflib import Utils - top = '..' def build(bld): - # precompiled headers (if enabled) - bld(features=['cxx', 'pch'], - name='tests-base', - target='tests-base', - headers=['../src/common-pch.hpp', 'boost-test.hpp'], - use='ndn-cxx BOOST', - includes='.') - - # core modules that can be shared between unit and integrated tests - bld(features="cxx", - target="boost-tests-base", - source="key-chain-fixture.cpp identity-management-fixture.cpp", - use='ndn-cxx tests-base BOOST', - includes='.', - install_path=None) - - # unit test objects - unit_tests = bld( - target="unit-test-objects", - name="unit-test-objects", - features="cxx", - source=bld.path.ant_glob(['unit-tests/**/*.cpp'], - excl=['**/*-osx.t.cpp', '**/*-sqlite3.t.cpp']), - use='ndn-cxx tests-base BOOST', - includes='.', - defines='UNIT_TEST_CONFIG_PATH=\"%s/tmp-files/\"' %(bld.bldnode), - install_path=None) - - if bld.env['HAVE_OSX_SECURITY']: - unit_tests.source += bld.path.ant_glob('unit-tests/**/*-osx.t.cpp') - - # In case we want to make it optional later - unit_tests.source += bld.path.ant_glob('unit-tests/**/*-sqlite3.t.cpp') - - # unit test app - bld(features='cxx cxxprogram', - target='../unit-tests', - name='unit-tests-main-unit', - source="main.cpp", - use='ndn-cxx unit-test-objects boost-tests-base BOOST', - install_path=None) + # common objects that can be shared between unit and integrated tests + bld.objects(target='tests-common', + features='pch', + source=bld.path.ant_glob('*.cpp'), + headers=['../ndn-cxx/impl/common-pch.hpp', 'boost-test.hpp'], + use='ndn-cxx BOOST') bld.recurse('integrated') + bld.recurse('unit') diff --git a/tools/ndnsec/cert-dump.cpp b/tools/ndnsec/cert-dump.cpp new file mode 100644 index 000000000..52b9f9f8a --- /dev/null +++ b/tools/ndnsec/cert-dump.cpp @@ -0,0 +1,166 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndnsec.hpp" +#include "util.hpp" + +#include +#if BOOST_VERSION < 106700 +#include +#endif // BOOST_VERSION < 106700 + +namespace ndn { +namespace ndnsec { + +int +ndnsec_cert_dump(int argc, char** argv) +{ + namespace po = boost::program_options; + + std::string name; + bool isIdentityName = false; + bool isKeyName = false; + bool isFileName = false; + bool isPretty = false; + bool isRepoOut = false; + std::string repoHost; + std::string repoPort; + + po::options_description description( + "Usage: ndnsec cert-dump [-h] [-p] [-r [-H HOST] [-P PORT]] [-i|-k|-f] [-n] NAME\n" + "\n" + "Options"); + description.add_options() + ("help,h", "produce help message") + ("pretty,p", po::bool_switch(&isPretty), "display certificate in human readable format") + ("identity,i", po::bool_switch(&isIdentityName), + "treat the NAME argument as an identity name (e.g., /ndn/edu/ucla/alice)") + ("key,k", po::bool_switch(&isKeyName), + "treat the NAME argument as a key name (e.g., /ndn/edu/ucla/alice/ksk-123456789)") + ("file,f", po::bool_switch(&isFileName), + "treat the NAME argument as the name of a file containing a base64-encoded " + "certificate, '-' for stdin") + ("name,n", po::value(&name), + "unless overridden by -i/-k/-f, the name of the certificate to be exported " + "(e.g., /ndn/edu/ucla/KEY/cs/alice/ksk-1234567890/ID-CERT/%FD%FF%FF%FF%FF%FF%FF%FF)") + ("repo-output,r", po::bool_switch(&isRepoOut), + "publish the certificate into a repo-ng instance") + ("repo-host,H", po::value(&repoHost)->default_value("localhost"), + "repo hostname if --repo-output is specified") + ("repo-port,P", po::value(&repoPort)->default_value("7376"), + "repo port number if --repo-output is specified") + ; + + po::positional_options_description p; + p.add("name", 1); + + po::variables_map vm; + try { + po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm); + po::notify(vm); + } + catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << "\n\n" + << description << std::endl; + return 2; + } + + if (vm.count("help") > 0) { + std::cout << description << std::endl; + return 0; + } + + if (vm.count("name") == 0) { + std::cerr << "ERROR: you must specify a name" << std::endl; + return 2; + } + + if (isIdentityName + isKeyName + isFileName > 1) { + std::cerr << "ERROR: at most one of '--identity', '--key', " + "or '--file' may be specified" << std::endl; + return 2; + } + + if (isPretty && isRepoOut) { + std::cerr << "ERROR: '--pretty' is incompatible with '--repo-output'" << std::endl; + return 2; + } + + security::v2::KeyChain keyChain; + + security::v2::Certificate certificate; + try { + if (isIdentityName) { + certificate = keyChain.getPib() + .getIdentity(name) + .getDefaultKey() + .getDefaultCertificate(); + } + else if (isKeyName) { + certificate = keyChain.getPib() + .getIdentity(security::v2::extractIdentityFromKeyName(name)) + .getKey(name) + .getDefaultCertificate(); + } + else if (isFileName) { + certificate = loadCertificate(name); + } + else { + certificate = keyChain.getPib() + .getIdentity(security::v2::extractIdentityFromCertName(name)) + .getKey(security::v2::extractKeyNameFromCertName(name)) + .getCertificate(name); + } + } + catch (const CannotLoadCertificate&) { + std::cerr << "ERROR: Cannot load the certificate from `" << name << "`" << std::endl; + return 1; + } + + if (isPretty) { + std::cout << certificate << std::endl; + return 0; + } + + if (isRepoOut) { + boost::asio::ip::tcp::iostream requestStream; +#if BOOST_VERSION >= 106700 + requestStream.expires_after(std::chrono::seconds(10)); +#else + requestStream.expires_from_now(boost::posix_time::seconds(10)); +#endif // BOOST_VERSION >= 106700 + requestStream.connect(repoHost, repoPort); + if (!requestStream) { + std::cerr << "ERROR: Failed to connect to repo instance" << std::endl; + return 1; + } + requestStream.write(reinterpret_cast(certificate.wireEncode().wire()), + certificate.wireEncode().size()); + return 0; + } + + io::save(certificate, std::cout); + + return 0; +} + +} // namespace ndnsec +} // namespace ndn diff --git a/tools/ndnsec/cert-dump.hpp b/tools/ndnsec/cert-dump.hpp deleted file mode 100644 index cd56e6e44..000000000 --- a/tools/ndnsec/cert-dump.hpp +++ /dev/null @@ -1,187 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_CERT_DUMP_HPP -#define NDN_TOOLS_NDNSEC_CERT_DUMP_HPP - -#include "util.hpp" - -int -ndnsec_cert_dump(int argc, char** argv) -{ - using namespace ndn; - using namespace ndn::security; - namespace po = boost::program_options; - - std::string name; - bool isKeyName = false; - bool isIdentityName = false; - bool isCertName = true; - // bool isFileName = false; - bool isPretty = false; - bool isStdOut = true; - bool isRepoOut = false; - std::string repoHost; - std::string repoPort; - // bool isDnsOut = false; - - po::options_description description("General Usage\n" - " ndnsec cert-dump [-h] [-p] [-d] [-r [-H repo-host] " - "[-P repo-port] ] [-i|k|f] name\n" - "General options"); - description.add_options() - ("help,h", "produce help message") - ("pretty,p", "display certificate in human readable format") - ("identity,i", "treat the name parameter as identity name (e.g., /ndn/edu/ucla/alice") - ("key,k", "treat the name parameter as key name " - "(e.g., /ndn/edu/ucla/alice/ksk-123456789)") - ("file,f", "treat the name parameter as file name with base64 encoded certificate, " - "- for stdin") - ("repo-output,r", "publish the certificate to the repo-ng") - ("repo-host,H", po::value(&repoHost)->default_value("localhost"), - "the repo host if repo-output is specified") - ("repo-port,P", po::value(&repoPort)->default_value("7376"), - "the repo port if repo-output is specified") - // ("dns-output,d", "published the certificate to NDNS") - ("name,n", po::value(&name), - "unless overridden with --identity or --key parameter, the certificate name, " - "for example, /ndn/edu/ucla/KEY/cs/alice/ksk-1234567890" - "/ID-CERT/%FD%FF%FF%FF%FF%FF%FF%FF") - ; - - po::positional_options_description p; - p.add("name", 1); - - po::variables_map vm; - try { - po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), - 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; - } - - if (vm.count("name") == 0) { - std::cerr << "identity_name must be specified" << std::endl; - std::cerr << description << std::endl; - return 1; - } - - if (vm.count("key") != 0) { - isCertName = false; - isKeyName = true; - } - else if (vm.count("identity") != 0) { - isCertName = false; - isIdentityName = true; - } - else if (vm.count("file") != 0) { - isCertName = false; - // isFileName = true; - } - - if (vm.count("pretty") != 0) - isPretty = true; - - if (vm.count("repo-output") != 0) { - isRepoOut = true; - isStdOut = false; - } - else if (vm.count("dns-output") != 0) { - // isDnsOut = true; - isStdOut = false; - std::cerr << "Error: DNS output is not supported yet!" << std::endl; - return 1; - } - - if (isPretty && !isStdOut) { - std::cerr << "Error: pretty option can only be specified when other " - << "output option is specified" << std::endl; - return 1; - } - - shared_ptr certificate; - - KeyChain keyChain; - - if (isIdentityName || isKeyName || isCertName) { - if (isIdentityName) { - Name certName = keyChain.getDefaultCertificateNameForIdentity(name); - certificate = keyChain.getCertificate(certName); - } - else if (isKeyName) { - Name certName = keyChain.getDefaultCertificateNameForKey(name); - certificate = keyChain.getCertificate(certName); - } - else - certificate = keyChain.getCertificate(name); - - if (!static_cast(certificate)) { - std::cerr << "No certificate found!" << std::endl; - return 1; - } - } - else { - certificate = getIdentityCertificate(name); - if (!static_cast(certificate)) - { - std::cerr << "No certificate read!" << std::endl; - return 1; - } - } - - if (isPretty) { - std::cout << *certificate << std::endl; - } - else { - if (isStdOut) { - io::save(*certificate, std::cout); - return 0; - } - if (isRepoOut) { - using namespace boost::asio::ip; - tcp::iostream request_stream; - request_stream.expires_from_now(boost::posix_time::milliseconds(3000)); - request_stream.connect(repoHost, repoPort); - if (!request_stream) { - std::cerr << "fail to open the stream!" << std::endl; - return 1; - } - request_stream.write(reinterpret_cast(certificate->wireEncode().wire()), - certificate->wireEncode().size()); - - return 0; - } - } - return 0; -} - -#endif // NDN_TOOLS_NDNSEC_CERT_DUMP_HPP diff --git a/tools/ndnsec/cert-gen.cpp b/tools/ndnsec/cert-gen.cpp new file mode 100644 index 000000000..ec630c93b --- /dev/null +++ b/tools/ndnsec/cert-gen.cpp @@ -0,0 +1,177 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndnsec.hpp" +#include "util.hpp" + +#include "ndn-cxx/security/transform/base64-encode.hpp" +#include "ndn-cxx/security/transform/buffer-source.hpp" +#include "ndn-cxx/security/transform/public-key.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" + +namespace ndn { +namespace ndnsec { + +int +ndnsec_cert_gen(int argc, char** argv) +{ + namespace po = boost::program_options; + + std::string requestFile; + std::string notBeforeStr; + std::string notAfterStr; + std::vector infos; + Name signId; + std::string issuerId; + + po::options_description description( + "Usage: ndnsec cert-gen [-h] [-S TIMESTAMP] [-E TIMESTAMP] [-I INFO]...\n" + " [-s IDENTITY] [-i ISSUER] [-r] FILE\n" + "\n" + "Options"); + description.add_options() + ("help,h", "produce help message") + ("request,r", po::value(&requestFile)->default_value("-"), + "request file name, '-' for stdin (the default)") + ("not-before,S", po::value(¬BeforeStr), + "certificate validity start date/time in YYYYMMDDhhmmss format (default: now)") + ("not-after,E", po::value(¬AfterStr), + "certificate validity end date/time in YYYYMMDDhhmmss format (default: " + "365 days after the --not-before timestamp)") + ("info,I", po::value>(&infos), + "key and value (must be separated by a single space) of the additional " + "description to be included in the issued certificate (e.g., " + "\"affiliation University of California, Los Angeles\"); " + "this option may be repeated multiple times") + ("sign-id,s", po::value(&signId), "signing identity") + ("issuer-id,i", po::value(&issuerId)->default_value("NA"), + "issuer's ID to be included in the issued certificate name") + ; + + po::positional_options_description p; + p.add("request", 1); + + po::variables_map vm; + try { + po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm); + po::notify(vm); + } + catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << "\n\n" + << description << std::endl; + return 2; + } + + if (vm.count("help") > 0) { + std::cout << description << std::endl; + return 0; + } + + security::v2::AdditionalDescription additionalDescription; + + for (const auto& info : infos) { + auto pos = info.find(" "); + if (pos == std::string::npos) { + std::cerr << "ERROR: incorrectly formatted info block [" << info << "]" << std::endl; + return 2; + } + std::string key = info.substr(0, pos); + std::string value = info.substr(pos + 1); + + additionalDescription.set(key, value); + } + + time::system_clock::TimePoint notBefore; + time::system_clock::TimePoint notAfter; + + if (vm.count("not-before") == 0) { + notBefore = time::system_clock::now(); + } + else { + notBefore = time::fromIsoString(notBeforeStr.substr(0, 8) + "T" + notBeforeStr.substr(8, 6)); + } + + if (vm.count("not-after") == 0) { + notAfter = notBefore + 365_days; + } + else { + notAfter = time::fromIsoString(notAfterStr.substr(0, 8) + "T" + notAfterStr.substr(8, 6)); + + if (notAfter < notBefore) { + std::cerr << "ERROR: '--not-before' cannot be later than '--not-after'" << std::endl; + return 2; + } + } + + security::v2::KeyChain keyChain; + + security::v2::Certificate certRequest; + try { + certRequest = loadCertificate(requestFile); + } + catch (const CannotLoadCertificate&) { + std::cerr << "ERROR: Cannot load the request from `" << requestFile << "`" << std::endl; + return 1; + } + + // validate that the content is a public key + Buffer keyContent = certRequest.getPublicKey(); + security::transform::PublicKey pubKey; + pubKey.loadPkcs8(keyContent.data(), keyContent.size()); + + Name certName = certRequest.getKeyName(); + certName + .append(issuerId) + .appendVersion(); + + security::v2::Certificate cert; + cert.setName(certName); + cert.setContent(certRequest.getContent()); + // TODO: add ability to customize + cert.setFreshnessPeriod(1_h); + + SignatureInfo signatureInfo; + signatureInfo.setValidityPeriod(security::ValidityPeriod(notBefore, notAfter)); + if (!additionalDescription.empty()) { + signatureInfo.appendTypeSpecificTlv(additionalDescription.wireEncode()); + } + + security::Identity identity; + if (vm.count("sign-id") == 0) { + identity = keyChain.getPib().getDefaultIdentity(); + } + else { + identity = keyChain.getPib().getIdentity(signId); + } + + keyChain.sign(cert, security::SigningInfo(identity).setSignatureInfo(signatureInfo)); + + const Block& wire = cert.wireEncode(); + { + using namespace security::transform; + bufferSource(wire.wire(), wire.size()) >> base64Encode(true) >> streamSink(std::cout); + } + + return 0; +} + +} // namespace ndnsec +} // namespace ndn diff --git a/tools/ndnsec/cert-gen.hpp b/tools/ndnsec/cert-gen.hpp deleted file mode 100644 index 04da04014..000000000 --- a/tools/ndnsec/cert-gen.hpp +++ /dev/null @@ -1,234 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_CERT_GEN_HPP -#define NDN_TOOLS_NDNSEC_CERT_GEN_HPP - -#include "util.hpp" - -int -ndnsec_cert_gen(int argc, char** argv) -{ - using boost::tokenizer; - using boost::escaped_list_separator; - - using namespace ndn; - using namespace ndn::time; - using namespace ndn::security; - namespace po = boost::program_options; - - KeyChain keyChain; - - std::string notBeforeStr; - std::string notAfterStr; - std::string subjectName; - std::string requestFile("-"); - Name signId; - std::string subjectInfo; - std::vector signedInfo; - Name certPrefix = KeyChain::DEFAULT_PREFIX; // to avoid displaying the default value - - po::options_description description( - "General Usage\n" - " ndnsec cert-gen [-h] [-S date] [-E date] [-N subject-name] [-I subject-info] " - "[-s sign-id] [-p cert-prefix] request\n" - "General options"); - - description.add_options() - ("help,h", "produce help message") - ("not-before,S", po::value(¬BeforeStr), - "certificate starting date, YYYYMMDDhhmmss (default: now)") - ("not-after,E", po::value(¬AfterStr), - "certificate ending date, YYYYMMDDhhmmss (default: now + 365 days)") - ("subject-name,N", po::value(&subjectName), - "subject name") - ("subject-info,I", po::value(&subjectInfo), - "(deprecated, uses 'signed-info') subject info, pairs of OID and string " - " description: \"2.5.4.10 'University of California, Los Angeles'\"") - ("signed-info", po::value >(&signedInfo), - "a pair of OID and string (must be separated by a single space), e.g., " - "\"2.5.4.10 University of California, Los Angeles\". " - "May be repeated multiple times") - ("sign-id,s", po::value(&signId)->default_value(keyChain.getDefaultIdentity()), - "signing identity") - ("cert-prefix,p", po::value(&certPrefix), - "cert prefix, which is the part of certificate name before " - "KEY component") - ("request,r", po::value(&requestFile)->default_value("-"), - "request file name, - for stdin") - ; - - po::positional_options_description p; - p.add("request", 1); - - po::variables_map vm; - try - { - po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), - vm); - po::notify(vm); - } - catch (const std::exception& e) - { - std::cerr << "ERROR: " << e.what() << std::endl; - return 1; - } - - if (vm.count("help") != 0) - { - std::cout << description << std::endl; - return 0; - } - - if (vm.count("subject-name") == 0) - { - std::cerr << "ERROR: subject name must be specified" << std::endl - << std::endl - << description << std::endl; - return 1; - } - - std::vector subjectDescription; - subjectDescription.push_back(v1::CertificateSubjectDescription(oid::ATTRIBUTE_NAME, subjectName)); - - // 'subjectInfo' is deprecated and the following block will be removed eventually - tokenizer > subjectInfoItems - (subjectInfo, escaped_list_separator("\\", " \t", "'\"")); - - tokenizer >::iterator it = - subjectInfoItems.begin(); - - while (it != subjectInfoItems.end()) - { - std::string oid = *it; - - it++; - if (it == subjectInfoItems.end()) - { - std::cerr << "ERROR: unmatched info for oid [" << oid << "]" << std::endl; - return 1; - } - - std::string value = *it; - - subjectDescription.push_back(v1::CertificateSubjectDescription(Oid(oid), value)); - - it++; - } - - // new 'signedInfo' processing - for (std::vector::const_iterator info = signedInfo.begin(); - info != signedInfo.end(); ++info) { - size_t pos = info->find(" "); - if (pos == std::string::npos) { - std::cerr << "ERROR: incorrectly formatted signed info block [" << *info << "]" << std::endl; - return 1; - } - Oid oid(info->substr(0, pos)); - std::string value = info->substr(pos + 1); - - subjectDescription.push_back(v1::CertificateSubjectDescription(oid, value)); - } - - system_clock::TimePoint notBefore; - system_clock::TimePoint notAfter; - - if (vm.count("not-before") == 0) - { - notBefore = system_clock::now(); - } - else - { - notBefore = fromIsoString(notBeforeStr.substr(0, 8) + "T" + - notBeforeStr.substr(8, 6)); - } - - if (vm.count("not-after") == 0) - { - notAfter = notBefore + days(365); - } - else - { - notAfter = fromIsoString(notAfterStr.substr(0, 8) + "T" + - notAfterStr.substr(8, 6)); - - if (notAfter < notBefore) - { - std::cerr << "ERROR: not-before cannot be later than not-after" << std::endl - << std::endl - << description << std::endl; - return 1; - } - } - - if (vm.count("request") == 0) - { - std::cerr << "ERROR: request file must be specified" << std::endl - << std::endl - << description << std::endl; - return 1; - } - - shared_ptr selfSignedCertificate - = getIdentityCertificate(requestFile); - - if (!static_cast(selfSignedCertificate)) - { - std::cerr << "ERROR: input error" << std::endl; - return 1; - } - - Name keyName = selfSignedCertificate->getPublicKeyName(); - - shared_ptr certificate = - keyChain.prepareUnsignedIdentityCertificate(keyName, selfSignedCertificate->getPublicKeyInfo(), - signId, notBefore, notAfter, - subjectDescription, certPrefix); - - if (!static_cast(certificate)) - { - std::cerr << "ERROR: key name is not formated correctly or does not match certificate name" - << std::endl; - return 1; - } - - keyChain.createIdentity(signId); - Name signingCertificateName = keyChain.getDefaultCertificateNameForIdentity(signId); - keyChain.sign(*certificate, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_CERT, - signingCertificateName)); - - Block wire = certificate->wireEncode(); - - try { - transform::bufferSource(wire.wire(), wire.size()) >> transform::base64Encode(true) >> transform::streamSink(std::cout); - } - catch (const transform::Error& e) { - std::cerr << "ERROR: " << e.what() << std::endl; - return 1; - } - - return 0; -} - -#endif // NDN_TOOLS_NDNSEC_CERT_GEN_HPP diff --git a/tools/ndnsec/cert-install.cpp b/tools/ndnsec/cert-install.cpp new file mode 100644 index 000000000..9ee4d8750 --- /dev/null +++ b/tools/ndnsec/cert-install.cpp @@ -0,0 +1,226 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndnsec.hpp" +#include "util.hpp" + +#include "ndn-cxx/encoding/buffer-stream.hpp" +#include "ndn-cxx/security/transform/base64-decode.hpp" +#include "ndn-cxx/security/transform/stream-sink.hpp" +#include "ndn-cxx/security/transform/stream-source.hpp" + +#include +#if BOOST_VERSION < 106700 +#include +#endif // BOOST_VERSION < 106700 + +namespace ndn { +namespace ndnsec { + +class HttpException : public std::runtime_error +{ +public: + explicit + HttpException(const std::string& what) + : std::runtime_error(what) + { + } +}; + +security::v2::Certificate +getCertificateHttp(const std::string& host, const std::string& port, const std::string& path) +{ + boost::asio::ip::tcp::iostream requestStream; +#if BOOST_VERSION >= 106700 + requestStream.expires_after(std::chrono::seconds(10)); +#else + requestStream.expires_from_now(boost::posix_time::seconds(10)); +#endif // BOOST_VERSION >= 106700 + + requestStream.connect(host, port); + if (!requestStream) { + NDN_THROW(HttpException("HTTP connection error")); + } + + requestStream << "GET " << path << " HTTP/1.0\r\n"; + requestStream << "Host: " << host << "\r\n"; + requestStream << "Accept: */*\r\n"; + requestStream << "Cache-Control: no-cache\r\n"; + requestStream << "Connection: close\r\n\r\n"; + requestStream.flush(); + + std::string statusLine; + std::getline(requestStream, statusLine); + if (!requestStream) { + NDN_THROW(HttpException("HTTP communication error")); + } + + std::stringstream responseStream(statusLine); + std::string httpVersion; + responseStream >> httpVersion; + unsigned int statusCode; + responseStream >> statusCode; + std::string statusMessage; + + std::getline(responseStream, statusMessage); + if (!requestStream || httpVersion.substr(0, 5) != "HTTP/") { + NDN_THROW(HttpException("HTTP communication error")); + } + if (statusCode != 200) { + NDN_THROW(HttpException("HTTP server error")); + } + std::string header; + while (std::getline(requestStream, header) && header != "\r") + ; + + OBufferStream os; + { + using namespace ndn::security::transform; + streamSource(requestStream) >> base64Decode(true) >> streamSink(os); + } + + return security::v2::Certificate(Block(os.buf())); +} + +int +ndnsec_cert_install(int argc, char** argv) +{ + namespace po = boost::program_options; + + std::string certFile; + bool isIdentityDefault = false; + bool isKeyDefault = false; + bool isNoDefault = false; + + po::options_description description( + "Usage: ndnsec cert-install [-h] [-I|-K|-N] [-f] FILE\n" + "\n" + "Options"); + description.add_options() + ("help,h", "produce help message") + ("cert-file,f", po::value(&certFile), + "file name of the certificate to be imported, '-' for stdin; " + "if it starts with 'http://', the certificate will be fetched " + "using a plain HTTP/1.0 GET request") + ("identity-default,I", po::bool_switch(&isIdentityDefault), + "set the imported certificate as the default certificate for the identity") + ("key-default,K", po::bool_switch(&isKeyDefault), + "set the imported certificate as the default certificate for the key") + ("no-default,N", po::bool_switch(&isNoDefault), + "do not change any default settings") + ; + + po::positional_options_description p; + p.add("cert-file", 1); + + po::variables_map vm; + try { + po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm); + po::notify(vm); + } + catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << "\n\n" + << description << std::endl; + return 2; + } + + if (vm.count("help") > 0) { + std::cout << description << std::endl; + return 0; + } + + if (vm.count("cert-file") == 0) { + std::cerr << "ERROR: you must specify a file name" << std::endl; + return 2; + } + + if (isIdentityDefault + isKeyDefault + isNoDefault > 1) { + std::cerr << "ERROR: at most one of '--identity-default', '--key-default', " + "or '--no-default' may be specified" << std::endl; + return 2; + } + + security::v2::Certificate cert; + try { + if (certFile.find("http://") == 0) { + std::string host; + std::string port; + std::string path; + + size_t pos = 7; // offset of "http://" + size_t posSlash = certFile.find("/", pos); + + if (posSlash == std::string::npos) + NDN_THROW(HttpException("Request line is not correctly formatted")); + + size_t posPort = certFile.find(":", pos); + + if (posPort != std::string::npos && posPort < posSlash) { + // port is specified + port = certFile.substr(posPort + 1, posSlash - posPort - 1); + host = certFile.substr(pos, posPort - pos); + } + else { + port = "80"; + host = certFile.substr(pos, posSlash - pos); + } + + path = certFile.substr(posSlash, certFile.size() - posSlash); + + cert = getCertificateHttp(host, port, path); + } + else { + cert = loadCertificate(certFile); + } + } + catch (const CannotLoadCertificate&) { + std::cerr << "ERROR: Cannot load the certificate from `" << certFile << "`" << std::endl; + return 1; + } + + security::v2::KeyChain keyChain; + + auto id = keyChain.getPib().getIdentity(cert.getIdentity()); + auto key = id.getKey(cert.getKeyName()); + + keyChain.addCertificate(key, cert); + + if (isIdentityDefault) { + keyChain.setDefaultKey(id, key); + keyChain.setDefaultCertificate(key, cert); + } + else if (isKeyDefault) { + keyChain.setDefaultCertificate(key, cert); + } + else if (!isNoDefault) { + keyChain.setDefaultIdentity(id); + keyChain.setDefaultKey(id, key); + keyChain.setDefaultCertificate(key, cert); + } + + std::cerr << "OK: certificate with name [" << cert.getName().toUri() << "] " + << "has been successfully installed" << std::endl; + + return 0; +} + +} // namespace ndnsec +} // namespace ndn diff --git a/tools/ndnsec/cert-install.hpp b/tools/ndnsec/cert-install.hpp deleted file mode 100644 index a1416ff1f..000000000 --- a/tools/ndnsec/cert-install.hpp +++ /dev/null @@ -1,217 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_CERT_INSTALL_HPP -#define NDN_TOOLS_NDNSEC_CERT_INSTALL_HPP - -#include "util.hpp" - -class HttpException : public std::runtime_error -{ -public: - explicit - HttpException(const std::string& what) - : std::runtime_error(what) - { - } -}; - -ndn::shared_ptr -getCertificateHttp(const std::string& host, const std::string& port, const std::string& path) -{ - using namespace boost::asio::ip; - tcp::iostream requestStream; - - requestStream.expires_from_now(boost::posix_time::milliseconds(3000)); - - requestStream.connect(host, port); - if (!static_cast(requestStream)) { - throw HttpException("HTTP connection error"); - } - requestStream << "GET " << path << " HTTP/1.0\r\n"; - requestStream << "Host: " << host << "\r\n"; - requestStream << "Accept: */*\r\n"; - requestStream << "Cache-Control: no-cache\r\n"; - requestStream << "Connection: close\r\n\r\n"; - requestStream.flush(); - - std::string statusLine; - std::getline(requestStream, statusLine); - if (!static_cast(requestStream)) - { - throw HttpException("HTTP communication error"); - } - - std::stringstream responseStream(statusLine); - std::string httpVersion; - responseStream >> httpVersion; - unsigned int statusCode; - responseStream >> statusCode; - std::string statusMessage; - - std::getline(responseStream, statusMessage); - if (!static_cast(requestStream) || httpVersion.substr(0, 5) != "HTTP/") { - throw HttpException("HTTP communication error"); - } - if (statusCode != 200) { - throw HttpException("HTTP server error"); - } - std::string header; - while (std::getline(requestStream, header) && header != "\r") - ; - - ndn::OBufferStream os; - { - using namespace ndn::security::transform; - streamSource(requestStream) >> base64Decode(true) >> streamSink(os); - } - - auto identityCertificate = std::make_shared(); - identityCertificate->wireDecode(ndn::Block(os.buf())); - - return identityCertificate; -} - -int -ndnsec_cert_install(int argc, char** argv) -{ - using namespace ndn; - using namespace ndn::security; - namespace po = boost::program_options; - - std::string certFileName; - bool isSystemDefault = true; - bool isIdentityDefault = false; - bool isKeyDefault = false; - - po::options_description description("General Usage\n ndnsec cert-install [-h] [-I|K|N] cert-file\nGeneral options"); - description.add_options() - ("help,h", "produce help message") - ("cert-file,f", po::value(&certFileName), "file name of the ceritificate, - for stdin. " - "If starts with http://, will try to fetch " - "the certificate using HTTP GET request") - ("identity-default,I", "optional, if specified, the certificate will be set as the default certificate of the identity") - ("key-default,K", "optional, if specified, the certificate will be set as the default certificate of the key") - ("no-default,N", "optional, if specified, the certificate will be simply installed") - ; - po::positional_options_description p; - p.add("cert-file", 1); - - po::variables_map vm; - try { - po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), - vm); - po::notify(vm); - } - catch (const std::exception& e) { - std::cerr << "ERROR: " << e.what() << std::endl; - return 1; - } - - if (vm.count("help") != 0) { - std::cerr << description << std::endl; - return 0; - } - - if (vm.count("cert-file") == 0) { - std::cerr << "cert_file must be specified" << std::endl; - std::cerr << description << std::endl; - return 1; - } - - if (vm.count("identity-default") != 0) { - isIdentityDefault = true; - isSystemDefault = false; - } - else if (vm.count("key-default") != 0) { - isKeyDefault = true; - isSystemDefault = false; - } - else if (vm.count("no-default") != 0) { - // noDefault = true; - isSystemDefault = false; - } - - shared_ptr cert; - - if (certFileName.find("http://") == 0) { - std::string host; - std::string port; - std::string path; - - size_t pos = 7; // offset of "http://" - size_t posSlash = certFileName.find("/", pos); - - if (posSlash == std::string::npos) - throw HttpException("Request line is not correctly formatted"); - - size_t posPort = certFileName.find(":", pos); - - if (posPort != std::string::npos && posPort < posSlash) { - // port is specified - port = certFileName.substr(posPort + 1, posSlash - posPort - 1); - host = certFileName.substr(pos, posPort - pos); - } - else { - port = "80"; - host = certFileName.substr(pos, posSlash - pos); - } - - path = certFileName.substr(posSlash, certFileName.size () - posSlash); - - cert = getCertificateHttp(host, port, path); - } - else { - cert = getIdentityCertificate(certFileName); - } - - if (!static_cast(cert)) - return 1; - - KeyChain keyChain; - - if (isSystemDefault) { - keyChain.addCertificateAsIdentityDefault(*cert); - Name keyName = cert->getPublicKeyName(); - Name identity = keyName.getSubName(0, keyName.size()-1); - keyChain.setDefaultIdentity(identity); - } - else if (isIdentityDefault) { - keyChain.addCertificateAsIdentityDefault(*cert); - } - else if (isKeyDefault) { - keyChain.addCertificateAsKeyDefault(*cert); - } - else { - keyChain.addCertificate(*cert); - } - - std::cerr << "OK: certificate with name [" - << cert->getName().toUri() - << "] has been successfully installed" - << std::endl; - - return 0; -} - -#endif // NDN_TOOLS_NDNSEC_CERT_INSTALL_HPP diff --git a/tools/ndnsec/cert-revoke.hpp b/tools/ndnsec/cert-revoke.hpp deleted file mode 100644 index 6aa8d02d9..000000000 --- a/tools/ndnsec/cert-revoke.hpp +++ /dev/null @@ -1,176 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_CERT_REVOKE_HPP -#define NDN_TOOLS_NDNSEC_CERT_REVOKE_HPP - -#include "util.hpp" - -int -ndnsec_cert_revoke(int argc, char** argv) -{ - using namespace ndn; - using namespace ndn::security; - namespace po = boost::program_options; - - KeyChain keyChain; - - std::string requestFile("-"); - Name signId = keyChain.getDefaultIdentity(); - bool hasSignId = false; - Name certPrefix = KeyChain::DEFAULT_PREFIX; - - po::options_description description("General Usage\n ndnsec cert-revoke [-h] request\n" - "General options"); - description.add_options() - ("help,h", "produce help message") - ("sign-id,s", po::value(&signId), - "signing identity (default: use the same as in the revoked certificate)") - ("cert-prefix,p", po::value(&certPrefix), - "cert prefix, which is the part of certificate name before " - "KEY component (default: use the same as in the revoked certificate)") - ("request,r", po::value(&requestFile)->default_value("-"), - "request file name, - for stdin") - ; - - po::positional_options_description p; - p.add("request", 1); - - po::variables_map vm; - try { - po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), - vm); - po::notify(vm); - } - catch (const std::exception& e) { - std::cerr << "ERROR: " << e.what() << std::endl; - return 1; - } - - if (vm.count("help") != 0) { - std::cerr << description << std::endl; - return 0; - } - - hasSignId = (vm.count("sign-id") != 0); - - if (vm.count("request") == 0) { - std::cerr << "request file must be specified" << std::endl; - return 1; - } - - shared_ptr revokedCertificate = getIdentityCertificate(requestFile); - - if (!static_cast(revokedCertificate)) { - std::cerr << "ERROR: input error" << std::endl; - return 1; - } - - Block wire; - - try { - Name keyName; - - if (hasSignId) { - keyName = keyChain.getDefaultKeyNameForIdentity(signId); - } - else { - const Signature& signature = revokedCertificate->getSignature(); - if (!signature.hasKeyLocator() || - signature.getKeyLocator().getType() != KeyLocator::KeyLocator_Name) - { - std::cerr << "ERROR: Invalid certificate to revoke" << std::endl; - return 1; - } - - keyName = v1::IdentityCertificate::certificateNameToPublicKeyName( - signature.getKeyLocator().getName()); - } - - Name certName; - if (certPrefix == KeyChain::DEFAULT_PREFIX) { - certName = revokedCertificate->getName().getPrefix(-1); - } - else { - Name revokedKeyName = revokedCertificate->getPublicKeyName(); - - if (certPrefix.isPrefixOf(revokedKeyName) && certPrefix != revokedKeyName) { - certName.append(certPrefix) - .append("KEY") - .append(revokedKeyName.getSubName(certPrefix.size())) - .append("ID-CERT"); - } - else { - std::cerr << "ERROR: certificate prefix does not match the revoked certificate" - << std::endl; - return 1; - } - } - certName - .appendVersion() - .append("REVOKED"); - - Data revocationCert; - revocationCert.setName(certName); - - if (keyChain.doesPublicKeyExist(keyName)) { - Name signingCertificateName = keyChain.getDefaultCertificateNameForKey(keyName); - keyChain.sign(revocationCert, - SigningInfo(SigningInfo::SIGNER_TYPE_CERT, signingCertificateName)); - } - else { - std::cerr << "ERROR: Cannot find the signing key!" << std::endl; - return 1; - } - - wire = revocationCert.wireEncode(); - } - catch (const Signature::Error& e) { - std::cerr << "ERROR: No valid signature!" << std::endl; - return 1; - } - catch (const KeyLocator::Error& e) { - std::cerr << "ERROR: No valid KeyLocator!" << std::endl; - return 1; - } - catch (const v1::IdentityCertificate::Error& e) { - std::cerr << "ERROR: Cannot determine the signing key!" << std::endl; - return 1; - } - catch (const SecPublicInfo::Error& e) { - std::cerr << "ERROR: Incomplete or corrupted PIB (" << e.what() << ")" << std::endl; - return 1; - } - - try { - transform::bufferSource(wire.wire(), wire.size()) >> transform::base64Encode(true) >> transform::streamSink(std::cout); - } - catch (const transform::Error& e) { - std::cerr << "ERROR: " << e.what() << std::endl; - return 1; - } - - return 0; -} - -#endif // NDN_TOOLS_NDNSEC_CERT_REVOKE_HPP diff --git a/tools/ndnsec/delete.cpp b/tools/ndnsec/delete.cpp new file mode 100644 index 000000000..376e3e3c5 --- /dev/null +++ b/tools/ndnsec/delete.cpp @@ -0,0 +1,116 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndnsec.hpp" +#include "util.hpp" + +namespace ndn { +namespace ndnsec { + +int +ndnsec_delete(int argc, char** argv) +{ + namespace po = boost::program_options; + + bool wantDeleteKey = false; + bool wantDeleteCert = false; + std::string name; + + po::options_description description( + "Usage: ndnsec delete [-h] [-k|-c] [-n] NAME\n" + "\n" + "Options"); + description.add_options() + ("help,h", "produce help message") + ("delete-key,k", po::bool_switch(&wantDeleteKey), "delete a key") + ("delete-cert,c", po::bool_switch(&wantDeleteCert), "delete a certificate") + ("name,n", po::value(&name), + "name of the item to delete. By default, it refers to an identity. " + "If -k is specified, it refers to a key. " + "If -c is specified, it refers to a certificate."); + ; + + po::positional_options_description p; + p.add("name", 1); + + po::variables_map vm; + try { + po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm); + po::notify(vm); + } + catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << "\n\n" + << description << std::endl; + return 2; + } + + if (vm.count("help") > 0) { + std::cout << description << std::endl; + return 0; + } + + if (vm.count("name") == 0) { + std::cerr << "ERROR: you must specify a name" << std::endl; + return 2; + } + + if (wantDeleteKey && wantDeleteCert) { + std::cerr << "ERROR: cannot specify both '--delete-key' and '--delete-cert'" << std::endl; + return 2; + } + + security::v2::KeyChain keyChain; + + try { + if (wantDeleteCert) { + security::Key key = keyChain.getPib() + .getIdentity(security::v2::extractIdentityFromCertName(name)) + .getKey(security::v2::extractKeyNameFromCertName(name)); + + keyChain.deleteCertificate(key, key.getCertificate(name).getName()); + std::cerr << "OK: certificate deleted: " << name << std::endl; + } + else if (wantDeleteKey) { + security::Identity identity = keyChain.getPib() + .getIdentity(security::v2::extractIdentityFromKeyName(name)); + + keyChain.deleteKey(identity, identity.getKey(name)); + std::cerr << "OK: key deleted: " << name << std::endl; + } + else { + keyChain.deleteIdentity(keyChain.getPib().getIdentity(name)); + std::cerr << "OK: identity deleted: " << name << std::endl; + } + } + catch (const security::Pib::Error& e) { + std::cerr << "ERROR: Cannot delete the item: " << e.what() << std::endl; + return 1; + } + catch (const security::Tpm::Error& e) { + std::cerr << "ERROR: Cannot delete the item: " << e.what() << std::endl; + return 1; + } + + return 0; +} + +} // namespace ndnsec +} // namespace ndn diff --git a/tools/ndnsec/delete.hpp b/tools/ndnsec/delete.hpp deleted file mode 100644 index 0c96af4bf..000000000 --- a/tools/ndnsec/delete.hpp +++ /dev/null @@ -1,133 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_DELETE_HPP -#define NDN_TOOLS_NDNSEC_DELETE_HPP - -#include "util.hpp" - -int -ndnsec_delete(int argc, char** argv) -{ - using namespace ndn; - namespace po = boost::program_options; - - bool isDeleteKey = false; - bool isDeleteCert = false; - std::string name; - - po::options_description description("General Usage\n" - "ndnsec delete [-h] [-k|c] name\n" - "General options"); - description.add_options() - ("help,h", "produce help message") - ("delete-key,k", "(Optional) delete a key if specified.") - ("delete-key2,K", "(Optional) delete a key if specified.") - ("delete-cert,c", "(Optional) delete a certificate if specified.") - ("delete-cert2,C", "(Optional) delete a certificate if specified.") - ("name,n", po::value(&name), "By default, it refers to an identity." - "If -k is specified, it refers to a key." - "If -c is specified, it refers to a certificate."); - ; - - po::positional_options_description p; - p.add("name", 1); - - po::variables_map vm; - try { - po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), - vm); - po::notify(vm); - } - catch (const std::exception& e) { - std::cerr << "ERROR: " << e.what() << std::endl; - std::cerr << description << std::endl; - return 2; - } - - if (vm.count("help") != 0) { - std::cerr << description << std::endl;; - return 0; - } - - if (vm.count("name") == 0) { - std::cerr << "ERROR: name must be specified" << std::endl; - std::cerr << description << std::endl; - return 2; - } - - if (vm.count("delete-cert") != 0 || vm.count("delete-cert2") != 0) - isDeleteCert = true; - - else if (vm.count("delete-key") != 0 || vm.count("delete-key2") != 0) - isDeleteKey = true; - - KeyChain keyChain; - - try { - if (isDeleteCert) { - if (!keyChain.doesCertificateExist(name)) { - std::cerr << "ERROR: Certificate does not exist: " << name << std::endl; - return 1; - } - - keyChain.deleteCertificate(name); - std::cerr << "OK: Delete certificate: " << name << std::endl; - } - else if (isDeleteKey) { - if (!keyChain.doesPublicKeyExist(name) && - !keyChain.doesKeyExistInTpm(name, KeyClass::PRIVATE)) { - std::cerr << "ERROR: Key does not exist: " << name << std::endl; - return 1; - } - - keyChain.deleteKey(name); - std::cerr << "OK: Delete key: " << name << std::endl; - } - else { - if (!keyChain.doesIdentityExist(name)) { - std::cerr << "ERROR: Identity does not exist: " << name << std::endl; - return 1; - } - - keyChain.deleteIdentity(name); - std::cerr << "OK: Delete identity: " << name << std::endl; - } - } - catch (const SecPublicInfo::Error& e) { - std::cerr << "ERROR: Cannot delete the item: " << e.what() << std::endl; - return 2; - } - catch (const SecTpm::Error& e) { - std::cerr << "ERROR: Cannot delete the item: " << e.what() << std::endl; - return 2; - } - catch (const KeyChain::Error& e) { - std::cerr << "ERROR: " << e.what() << std::endl; - return 2; - } - - return 0; -} - -#endif // NDN_TOOLS_NDNSEC_DELETE_HPP diff --git a/tools/ndnsec/dsk-gen.hpp b/tools/ndnsec/dsk-gen.hpp deleted file mode 100644 index 4f994c36a..000000000 --- a/tools/ndnsec/dsk-gen.hpp +++ /dev/null @@ -1,186 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_DSK_GEN_HPP -#define NDN_TOOLS_NDNSEC_DSK_GEN_HPP - -#include "util.hpp" - -int -ndnsec_dsk_gen(int argc, char** argv) -{ - using namespace ndn; - using namespace ndn::security; - namespace po = boost::program_options; - - std::string identityName; - char keyType = 'r'; - - po::options_description description("General Usage\n" - " ndnsec dsk-gen [-h] [-t keyType] identity\n" - "General options"); - description.add_options() - ("help,h", "produce help message") - ("identity,i", po::value(&identityName), - "identity name, for example, /ndn/ucla.edu/alice") - ("type,t", po::value(&keyType)->default_value('r'), - "optional, key type, r for RSA key (default), e for ECDSA key.") - // ("size,s", po::value(&keySize)->default_value(2048), - // "optional, key size, 2048 (default)") - ; - - po::positional_options_description p; - p.add("identity", 1); - - po::variables_map vm; - try { - po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), 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; - } - - if (vm.count("identity") == 0) { - std::cerr << "identity must be specified" << std::endl; - std::cerr << description << std::endl; - return 1; - } - - shared_ptr kskCert; - Name signingCertName; - - KeyChain keyChain; - - try { - Name defaultCertName = keyChain.getDefaultCertificateNameForIdentity(identityName); - bool isDefaultDsk = false; - std::string keyUsageTag = defaultCertName.get(-3).toUri().substr(0,4); - if (keyUsageTag == "ksk-") - isDefaultDsk = false; - else if (keyUsageTag == "dsk-") - isDefaultDsk = true; - else { - std::cerr << "ERROR: Unknown key usage tag: " << keyUsageTag << std::endl; - return 1; - } - - if (isDefaultDsk) { - shared_ptr dskCert = keyChain.getCertificate(defaultCertName); - - if (static_cast(dskCert)) { - SignatureSha256WithRsa sha256sig(dskCert->getSignature()); - - Name keyLocatorName = sha256sig.getKeyLocator().getName(); - - Name kskName = v1::IdentityCertificate::certificateNameToPublicKeyName(keyLocatorName); - Name kskCertName = keyChain.getDefaultCertificateNameForKey(kskName); - signingCertName = kskCertName; - kskCert = keyChain.getCertificate(kskCertName); - } - else { - std::cerr << "ERROR: The default certificate is missing." << std::endl; - return 1; - } - } - else { - signingCertName = defaultCertName; - kskCert = keyChain.getCertificate(defaultCertName); - } - - if (!static_cast(kskCert)) { - std::cerr << "ERROR: KSK certificate is missing." << std::endl; - return 1; - } - - Name newKeyName; - switch (keyType) { - case 'r': - { - RsaKeyParams params; - newKeyName = keyChain.generateRsaKeyPair(Name(identityName), false, params.getKeySize()); - if (0 == newKeyName.size()) { - std::cerr << "ERROR: Fail to generate RSA key!" << std::endl; - return 1; - } - break; - } - case 'e': - { - EcdsaKeyParams params; - newKeyName = keyChain.generateEcdsaKeyPair(Name(identityName), false, params.getKeySize()); - if (0 == newKeyName.size()) { - std::cerr << "ERROR: Fail to generate ECDSA key!" << std::endl; - return 1; - } - break; - } - default: - std::cerr << "ERROR: Unrecongized key type" << "\n"; - std::cerr << description << std::endl; - return 1; - } - - Name certName = newKeyName.getPrefix(-1); - certName.append("KEY") - .append(newKeyName.get(-1)) - .append("ID-CERT") - .appendVersion(); - - shared_ptr certificate = - keyChain.prepareUnsignedIdentityCertificate(newKeyName, - Name(identityName), - kskCert->getNotBefore(), - kskCert->getNotAfter(), - kskCert->getSubjectDescriptionList()); - - if (static_cast(certificate)) - certificate->encode(); - else { - std::cerr << "ERROR: Cannot format the certificate of the requested dsk." << "\n"; - return 1; - } - - keyChain.sign(*certificate, - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_CERT, signingCertName)); - - keyChain.addCertificateAsIdentityDefault(*certificate); - - std::cerr << "OK: dsk certificate with name [" << certificate->getName() << - "] has been successfully installed\n"; - return 0; - } - catch (std::runtime_error& e) { - std::cerr << "ERROR: other runtime errors: " << e.what() << "\n"; - return 1; - } -} - -#endif // NDN_TOOLS_NDNSEC_DSK_GEN_HPP diff --git a/tools/ndnsec/export.cpp b/tools/ndnsec/export.cpp new file mode 100644 index 000000000..a11459d01 --- /dev/null +++ b/tools/ndnsec/export.cpp @@ -0,0 +1,110 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndnsec.hpp" +#include "util.hpp" + +#include "ndn-cxx/security/impl/openssl.hpp" + +#include + +namespace ndn { +namespace ndnsec { + +int +ndnsec_export(int argc, char** argv) +{ + namespace po = boost::program_options; + + Name identityName; + std::string output; + std::string password; + + BOOST_SCOPE_EXIT(&password) { + OPENSSL_cleanse(&password.front(), password.size()); + } BOOST_SCOPE_EXIT_END + + po::options_description description( + "Usage: ndnsec export [-h] [-o FILE] [-P PASSPHRASE] [-i] IDENTITY\n" + "\n" + "Options"); + description.add_options() + ("help,h", "produce help message") + ("identity,i", po::value(&identityName), "name of the identity to export") + ("output,o", po::value(&output)->default_value("-"), + "output file, '-' for stdout (the default)") + ("password,P", po::value(&password), + "passphrase, will prompt if empty or not specified") + ; + + po::positional_options_description p; + p.add("identity", 1); + + po::variables_map vm; + try { + po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm); + po::notify(vm); + } + catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << "\n\n" + << description << std::endl; + return 2; + } + + if (vm.count("help") > 0) { + std::cout << description << std::endl; + return 0; + } + + if (vm.count("identity") == 0) { + std::cerr << "ERROR: you must specify an identity" << std::endl; + return 2; + } + + security::v2::KeyChain keyChain; + + auto id = keyChain.getPib().getIdentity(identityName); + + if (password.empty()) { + int count = 3; + while (!getPassword(password, "Passphrase for the private key: ")) { + count--; + if (count <= 0) { + std::cerr << "ERROR: invalid password" << std::endl; + return 1; + } + } + } + + // TODO: export all certificates, selected key pair, selected certificate + auto safeBag = keyChain.exportSafeBag(id.getDefaultKey().getDefaultCertificate(), + password.data(), password.size()); + + if (output == "-") + io::save(*safeBag, std::cout); + else + io::save(*safeBag, output); + + return 0; +} + +} // namespace ndnsec +} // namespace ndn diff --git a/tools/ndnsec/export.hpp b/tools/ndnsec/export.hpp deleted file mode 100644 index cd0c786e0..000000000 --- a/tools/ndnsec/export.hpp +++ /dev/null @@ -1,125 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_EXPORT_HPP -#define NDN_TOOLS_NDNSEC_EXPORT_HPP - -#include "util.hpp" - -int -ndnsec_export(int argc, char** argv) -{ - using namespace ndn; - namespace po = boost::program_options; - - std::string identityStr; - std::string output; - std::string exportPassword; - bool isPrivateExport = false; - - po::options_description description("General Usage\n ndnsec export [-h] [-o output] [-p] identity \nGeneral options"); - description.add_options() - ("help,h", "Produce help message") - ("output,o", po::value(&output), "(Optional) output file, stdout if not specified") - ("private,p", "export info contains private key") - ("identity,i", po::value(&identityStr), "Identity to export") - ; - - po::positional_options_description p; - p.add("identity", 1); - - po::variables_map vm; - try { - po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), - 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; - } - - if (vm.count("identity") == 0) { - std::cerr << "ERROR: identity must be specified" << std::endl; - std::cerr << description << std::endl; - return 1; - } - - if (vm.count("private") != 0) - isPrivateExport = true; - - if (vm.count("output") == 0) - output = "-"; - - Name identity(identityStr); - if (!isPrivateExport) { - KeyChain keyChain; - shared_ptr cert - = keyChain.getCertificate(keyChain.getDefaultCertificateNameForIdentity(identity)); - - if (output == "-") - io::save(*cert, std::cout); - else - io::save(*cert, output); - - return 0; - } - else { - Block wire; - try { - KeyChain keyChain; - - int count = 3; - while (!getPassword(exportPassword, "Passphrase for the private key: ")) { - count--; - if (count <= 0) { - std::cerr << "ERROR: invalid password" << std::endl; - memset(const_cast(exportPassword.c_str()), 0, exportPassword.size()); - return 1; - } - } - shared_ptr securedBag = keyChain.exportIdentity(identity, exportPassword); - memset(const_cast(exportPassword.c_str()), 0, exportPassword.size()); - - if (output == "-") - io::save(*securedBag, std::cout); - else - io::save(*securedBag, output); - - return 0; - } - catch (const std::runtime_error& e) { - std::cerr << "ERROR: " << e.what() << std::endl; - memset(const_cast(exportPassword.c_str()), 0, exportPassword.size()); - return 1; - } - } -} - -#endif // NDN_TOOLS_NDNSEC_EXPORT_HPP diff --git a/tools/ndnsec/get-default.cpp b/tools/ndnsec/get-default.cpp new file mode 100644 index 000000000..d59cfba6b --- /dev/null +++ b/tools/ndnsec/get-default.cpp @@ -0,0 +1,131 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndnsec.hpp" +#include "util.hpp" + +namespace ndn { +namespace ndnsec { + +int +ndnsec_get_default(int argc, char** argv) +{ + namespace po = boost::program_options; + + bool wantDefaultKey = false; + bool wantDefaultCert = false; + bool isQuiet = false; + Name identityName; + Name keyName; + + po::options_description description( + "Usage: ndnsec get-default [-h] [-k|-c] [-i ID|-K KEY] [-q]\n" + "\n" + "Options"); + description.add_options() + ("help,h", "produce help message") + ("default-key,k", po::bool_switch(&wantDefaultKey), "show default key, instead of identity") + ("default-cert,c", po::bool_switch(&wantDefaultCert), "show default certificate, instead of identity") + ("identity,i", po::value(&identityName), "target identity") + ("key,K", po::value(&keyName), "target key") + ("quiet,q", po::bool_switch(&isQuiet), "do not print trailing newline") + ; + + 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() << "\n\n" + << description << std::endl; + return 2; + } + + if (vm.count("help") > 0) { + std::cout << description << std::endl; + return 0; + } + + if (wantDefaultKey && wantDefaultCert) { + std::cerr << "ERROR: cannot specify both '--default-key' and '--default-cert'" << std::endl; + return 2; + } + + if (vm.count("identity") && vm.count("key")) { + std::cerr << "ERROR: cannot specify both '--identity' and '--key'" << std::endl; + return 2; + } + + security::v2::KeyChain keyChain; + + if (vm.count("key") > 0) { + if (wantDefaultCert) { + auto cert = keyChain.getPib() + .getIdentity(security::v2::extractIdentityFromKeyName(keyName)) + .getKey(keyName) + .getDefaultCertificate(); + std::cout << cert.getName(); + if (!isQuiet) { + std::cout << std::endl; + } + return 0; + } + return 2; + } + else if (vm.count("identity") > 0) { + auto key = keyChain.getPib() + .getIdentity(identityName) + .getDefaultKey(); + if (wantDefaultKey) { + std::cout << key.getName(); + if (!isQuiet) + std::cout << std::endl; + return 0; + } + if (wantDefaultCert) { + std::cout << key.getDefaultCertificate().getName(); + if (!isQuiet) + std::cout << std::endl; + return 0; + } + return 2; + } + else { + auto identity = keyChain.getPib() + .getDefaultIdentity(); + if (wantDefaultKey) { + std::cout << identity.getDefaultKey().getName(); + } + else if (wantDefaultCert) { + std::cout << identity.getDefaultKey().getDefaultCertificate().getName(); + } + else { + std::cout << identity.getName(); + } + if (!isQuiet) + std::cout << std::endl; + return 0; + } +} + +} // namespace ndnsec +} // namespace ndn diff --git a/tools/ndnsec/get-default.hpp b/tools/ndnsec/get-default.hpp deleted file mode 100644 index 41f4f2a5b..000000000 --- a/tools/ndnsec/get-default.hpp +++ /dev/null @@ -1,148 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_GET_DEFAULT_HPP -#define NDN_TOOLS_NDNSEC_GET_DEFAULT_HPP - -#include "util.hpp" - - -int -ndnsec_get_default(int argc, char** argv) -{ - using namespace ndn; - namespace po = boost::program_options; - - bool isGetDefaultId = true; - bool isGetDefaultKey = false; - bool isGetDefaultCert = false; - bool isQuiet = false; - std::string identityString; - std::string keyName; - - po::options_description description("General Usage\n ndnsec get-default [-h] [-k|c] [-i identity|-K key] [-q]\nGeneral options"); - description.add_options() - ("help,h", "produce help message") - ("default_key,k", "get default key") - ("default_cert,c", "get default certificate") - ("identity,i", po::value(&identityString), "target identity") - ("key,K", po::value(&keyName), "target key") - ("quiet,q", "don't output trailing newline") - ; - - 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; - } - - if (vm.count("default_cert") != 0) - { - isGetDefaultCert = true; - isGetDefaultId = false; - } - else if (vm.count("default_key") != 0) - { - isGetDefaultKey = true; - isGetDefaultId = false; - } - - if (vm.count("quiet") != 0) - { - isQuiet = true; - } - - KeyChain keyChain; - - if (vm.count("key") != 0) - { - Name keyNdnName(keyName); - if (isGetDefaultCert) - { - std::cout << keyChain.getDefaultCertificateNameForKey(keyNdnName); - if (!isQuiet) std::cout << std::endl; - return 0; - } - return 1; - } - else if (vm.count("identity") != 0) - { - Name identity(identityString); - - if (isGetDefaultKey) - { - std::cout << keyChain.getDefaultKeyNameForIdentity(identity); - if (!isQuiet) - std::cout << std::endl; - - return 0; - } - if (isGetDefaultCert) - { - std::cout << keyChain.getDefaultCertificateNameForIdentity(identity); - if (!isQuiet) - std::cout << std::endl; - - return 0; - } - return 1; - } - else - { - Name identity = keyChain.getDefaultIdentity(); - if (isGetDefaultId) - { - std::cout << identity; - if (!isQuiet) std::cout << std::endl; - return 0; - } - if (isGetDefaultKey) - { - std::cout << keyChain.getDefaultKeyNameForIdentity(identity); - if (!isQuiet) std::cout << std::endl; - return 0; - } - if (isGetDefaultCert) - { - std::cout << keyChain.getDefaultCertificateNameForIdentity(identity); - if (!isQuiet) std::cout << std::endl; - return 0; - } - return 1; - } -} - -#endif // NDN_TOOLS_NDNSEC_GET_DEFAULT_HPP diff --git a/tools/ndnsec/import.cpp b/tools/ndnsec/import.cpp new file mode 100644 index 000000000..f59ce938b --- /dev/null +++ b/tools/ndnsec/import.cpp @@ -0,0 +1,100 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndnsec.hpp" +#include "util.hpp" + +#include "ndn-cxx/security/impl/openssl.hpp" + +#include + +namespace ndn { +namespace ndnsec { + +int +ndnsec_import(int argc, char** argv) +{ + namespace po = boost::program_options; + + std::string input; + std::string password; + + BOOST_SCOPE_EXIT(&password) { + OPENSSL_cleanse(&password.front(), password.size()); + } BOOST_SCOPE_EXIT_END + + po::options_description description( + "Usage: ndnsec import [-h] [-P PASSPHRASE] [-i] FILE\n" + "\n" + "Options"); + description.add_options() + ("help,h", "produce help message") + ("input,i", po::value(&input)->default_value("-"), + "input file, '-' for stdin (the default)") + ("password,P", po::value(&password), + "passphrase, will prompt if empty or not specified") + ; + + po::positional_options_description p; + p.add("input", 1); + + po::variables_map vm; + try { + po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm); + po::notify(vm); + } + catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << "\n\n" + << description << std::endl; + return 2; + } + + if (vm.count("help") > 0) { + std::cout << description << std::endl; + return 0; + } + + security::v2::KeyChain keyChain; + + shared_ptr safeBag; + if (input == "-") + safeBag = io::load(std::cin); + else + safeBag = io::load(input); + + if (password.empty()) { + int count = 3; + while (!getPassword(password, "Passphrase for the private key: ", false)) { + count--; + if (count <= 0) { + std::cerr << "ERROR: invalid password" << std::endl; + return 1; + } + } + } + + keyChain.importSafeBag(*safeBag, password.data(), password.size()); + + return 0; +} + +} // namespace ndnsec +} // namespace ndn diff --git a/tools/ndnsec/import.hpp b/tools/ndnsec/import.hpp deleted file mode 100644 index 3a42c1b8b..000000000 --- a/tools/ndnsec/import.hpp +++ /dev/null @@ -1,115 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_IMPORT_HPP -#define NDN_TOOLS_NDNSEC_IMPORT_HPP - -#include "util.hpp" - -int -ndnsec_import(int argc, char** argv) -{ - using namespace ndn; - namespace po = boost::program_options; - - std::string input("-"); - std::string importPassword; - bool isPrivateImport = false; - - po::options_description description("General Usage\n ndnsec import [-h] [-p] input \nGeneral options"); - description.add_options() - ("help,h", "produce help message") - ("private,p", "import info contains private key") - ("input,i", po::value(&input), "input source, stdin if -") - ; - - po::positional_options_description p; - p.add("input", 1); - - po::variables_map vm; - try - { - po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), - 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; - } - - if (vm.count("private") != 0) - isPrivateImport = true; - - if (!isPrivateImport) - { - std::cerr << "You are trying to import certificate!\n" - << "Please use ndnsec cert-install!" << std::endl; - return 1; - } - else - { - try - { - KeyChain keyChain; - - shared_ptr securedBag; - if (input == "-") - securedBag = io::load(std::cin); - else - securedBag = io::load(input); - - int count = 3; - while (!getPassword(importPassword, "Passphrase for the private key: ")) - { - count--; - if (count <= 0) - { - std::cerr << "ERROR: Fail to get password" << std::endl; - memset(const_cast(importPassword.c_str()), 0, importPassword.size()); - return 1; - } - } - keyChain.importIdentity(*securedBag, importPassword); - memset(const_cast(importPassword.c_str()), 0, importPassword.size()); - } - catch (const std::runtime_error& e) - { - std::cerr << "ERROR: " << e.what() << std::endl; - memset(const_cast(importPassword.c_str()), 0, importPassword.size()); - return 1; - } - - return 0; - } -} - -#endif // NDN_TOOLS_NDNSEC_IMPORT_HPP diff --git a/tools/ndnsec/key-gen.cpp b/tools/ndnsec/key-gen.cpp new file mode 100644 index 000000000..6d4e3977f --- /dev/null +++ b/tools/ndnsec/key-gen.cpp @@ -0,0 +1,162 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndnsec.hpp" +#include "util.hpp" + +namespace ndn { +namespace ndnsec { + +int +ndnsec_key_gen(int argc, char** argv) +{ + namespace po = boost::program_options; + + Name identityName; + bool wantNotDefault = false; + char keyTypeChoice; + char keyIdTypeChoice; + std::string userKeyId; + + po::options_description description( + "Usage: ndnsec key-gen [-h] [-n] [-t TYPE] [-k IDTYPE] [-i] IDENTITY\n" + "\n" + "Options"); + description.add_options() + ("help,h", "produce help message") + ("identity,i", po::value(&identityName), "identity name, e.g., /ndn/edu/ucla/alice") + ("not-default,n", po::bool_switch(&wantNotDefault), "do not set the identity as default") + ("type,t", po::value(&keyTypeChoice)->default_value('r'), + "key type, 'r' for RSA, 'e' for ECDSA") + ("keyid-type,k", po::value(&keyIdTypeChoice)->default_value('r'), + "key id type, 'r' for 64-bit random number, 'h' for SHA256 of the public key") + ("keyid", po::value(&userKeyId), "user-specified key id") + //("size,s", po::value(&keySize)->default_value(2048), "key size in bits") + ; + + po::positional_options_description p; + p.add("identity", 1); + + po::variables_map vm; + try { + po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm); + po::notify(vm); + } + catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << "\n\n" + << description << std::endl; + return 2; + } + + if (vm.count("help") > 0) { + std::cout << description << std::endl; + return 0; + } + + if (vm.count("identity") == 0) { + std::cerr << "ERROR: you must specify an identity" << std::endl; + return 2; + } + + KeyIdType keyIdType = KeyIdType::RANDOM; + Name::Component userKeyIdComponent; + + if (vm.count("keyid") > 0) { + keyIdType = KeyIdType::USER_SPECIFIED; + userKeyIdComponent = name::Component::fromEscapedString(userKeyId); + if (userKeyIdComponent.empty()) { + std::cerr << "ERROR: key id cannot be an empty name component" << std::endl; + return 2; + } + if (!userKeyIdComponent.isGeneric()) { + std::cerr << "ERROR: key id must be a GenericNameComponent" << std::endl; + return 2; + } + } + + if (vm.count("keyid-type") > 0) { + if (keyIdType == KeyIdType::USER_SPECIFIED) { + std::cerr << "ERROR: cannot specify both '--keyid' and '--keyid-type'" << std::endl; + return 2; + } + + switch (keyIdTypeChoice) { + case 'r': + // KeyIdType::RANDOM is the default + break; + case 'h': + keyIdType = KeyIdType::SHA256; + break; + default: + std::cerr << "ERROR: unrecognized key id type '" << keyIdTypeChoice << "'" << std::endl; + return 2; + } + } + + unique_ptr params; + switch (keyTypeChoice) { + case 'r': + if (keyIdType == KeyIdType::USER_SPECIFIED) { + params = make_unique(userKeyIdComponent); + } + else { + params = make_unique(detail::RsaKeyParamsInfo::getDefaultSize(), keyIdType); + } + break; + case 'e': + if (keyIdType == KeyIdType::USER_SPECIFIED) { + params = make_unique(userKeyIdComponent); + } + else { + params = make_unique(detail::EcKeyParamsInfo::getDefaultSize(), keyIdType); + } + break; + default: + std::cerr << "ERROR: unrecognized key type '" << keyTypeChoice << "'" << std::endl; + return 2; + } + + security::v2::KeyChain keyChain; + + security::Identity identity; + security::Key key; + try { + identity = keyChain.getPib().getIdentity(identityName); + key = keyChain.createKey(identity, *params); + } + catch (const security::Pib::Error&) { + // identity doesn't exist, so create it and generate key + identity = keyChain.createIdentity(identityName, *params); + key = identity.getDefaultKey(); + } + + if (!wantNotDefault) { + keyChain.setDefaultKey(identity, key); + keyChain.setDefaultIdentity(identity); + } + + io::save(key.getDefaultCertificate(), std::cout); + + return 0; +} + +} // namespace ndnsec +} // namespace ndn diff --git a/tools/ndnsec/key-gen.hpp b/tools/ndnsec/key-gen.hpp deleted file mode 100644 index 1384ac827..000000000 --- a/tools/ndnsec/key-gen.hpp +++ /dev/null @@ -1,126 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_KEY_GEN_HPP -#define NDN_TOOLS_NDNSEC_KEY_GEN_HPP - -#include "util.hpp" - -int -ndnsec_key_gen(int argc, char** argv) -{ - using namespace ndn; - namespace po = boost::program_options; - - std::string identityName; - bool isDefault = true; - char keyType = 'r'; - std::string outputFilename; - - po::options_description description("General Usage\n" - " ndnsec key-gen [-h] [-n] identity\n" - "General options"); - description.add_options() - ("help,h", "produce help message") - ("identity,i", po::value(&identityName), - "identity name, for example, /ndn/edu/ucla/alice") - ("not_default,n", - "optional, if not specified, the target identity will be set as " - "the default identity of the system") - ("dsk,d", "generate Data-Signing-Key (DSK) instead of the default Key-Signing-Key (KSK)") - ("type,t", po::value(&keyType)->default_value('r'), - "optional, key type, r for RSA key (default), e for ECDSA key") - // ("size,s", po::value(&keySize)->default_value(2048), - // "optional, key size, 2048 (default)") - ; - - po::positional_options_description p; - p.add("identity", 1); - - po::variables_map vm; - try { - po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), - 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; - } - - if (vm.count("identity") == 0) { - std::cerr << "identity must be specified" << std::endl; - std::cerr << description << std::endl; - return 1; - } - - if (vm.count("not_default") != 0) - isDefault = false; - - bool isKsk = (vm.count("dsk") == 0); - - KeyChain keyChain; - Name keyName; - - try { - switch (keyType) { - case 'r': - keyName = keyChain.generateRsaKeyPair(Name(identityName), isKsk, RsaKeyParams().getKeySize()); - break; - case 'e': - keyName = keyChain.generateEcdsaKeyPair(Name(identityName), isKsk, - EcdsaKeyParams().getKeySize()); - break; - default: - std::cerr << "Unrecongized key type" << "\n"; - std::cerr << description << std::endl; - return 1; - } - - if (0 == keyName.size()) { - std::cerr << "Error: failed to generate key" << "\n"; - return 1; - } - - keyChain.setDefaultKeyNameForIdentity(keyName); - - shared_ptr identityCert = keyChain.selfSign(keyName); - - if (isDefault) - keyChain.setDefaultIdentity(Name(identityName)); - - io::save(*identityCert, std::cout); - } - catch (const std::exception& e) { - std::cerr << "Error: " << e.what() << std::endl; - } - return 0; -} - -#endif // NDN_TOOLS_NDNSEC_KEY_GEN_HPP diff --git a/tools/ndnsec/list.cpp b/tools/ndnsec/list.cpp new file mode 100644 index 000000000..1aa2d4ece --- /dev/null +++ b/tools/ndnsec/list.cpp @@ -0,0 +1,174 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndnsec.hpp" +#include "util.hpp" + +#include "ndn-cxx/util/indented-stream.hpp" + +namespace ndn { +namespace ndnsec { + +class Printer +{ +public: + explicit + Printer(int verboseLevel) + : m_verboseLevel(verboseLevel) + { + } + + void + printIdentity(const security::Identity& identity, bool isDefault) const + { + if (isDefault) + std::cout << "* "; + else + std::cout << " "; + + std::cout << identity.getName() << std::endl; + + if (m_verboseLevel >= 1) { + security::Key defaultKey; + try { + defaultKey = identity.getDefaultKey(); + } + catch (const security::Pib::Error&) { + // no default key + } + + for (const auto& key : identity.getKeys()) { + printKey(key, key == defaultKey); + } + + std::cout << std::endl; + } + } + + void + printKey(const security::Key& key, bool isDefault) const + { + if (isDefault) + std::cout << " +->* "; + else + std::cout << " +-> "; + + std::cout << key.getName() << std::endl; + + if (m_verboseLevel >= 2) { + security::v2::Certificate defaultCert; + try { + defaultCert = key.getDefaultCertificate(); + } + catch (const security::Pib::Error&) { + // no default certificate + } + + for (const auto& cert : key.getCertificates()) { + printCertificate(cert, cert == defaultCert); + } + } + } + + void + printCertificate(const security::v2::Certificate& cert, bool isDefault) const + { + if (isDefault) + std::cout << " +->* "; + else + std::cout << " +-> "; + + std::cout << cert.getName() << std::endl; + + if (m_verboseLevel >= 3) { + util::IndentedStream os(std::cout, " "); + os << cert; + } + } + +private: + int m_verboseLevel; +}; + +int +ndnsec_list(int argc, char** argv) +{ + namespace po = boost::program_options; + + bool wantKey = false; + bool wantCert = false; + int verboseLevel = 0; // 0 print identity only + // 1 print key name + // 2 print cert name + // 3 print cert content + + po::options_description description( + "Usage: ndnsec list [-h] [-k] [-c] [-v]\n" + "\n" + "Options"); + description.add_options() + ("help,h", "produce help message") + ("key,k", po::bool_switch(&wantKey), "list all keys associated with each identity") + ("cert,c", po::bool_switch(&wantCert), "list all certificates associated with each key") + ("verbose,v", accumulator(&verboseLevel), + "verbose mode, can be repeated for increased verbosity: -v is equivalent to -k, " + "-vv is equivalent to -c, -vvv shows detailed information for each certificate") + ; + + 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() << "\n\n" + << description << std::endl; + return 2; + } + + if (vm.count("help") > 0) { + std::cout << description << std::endl; + return 0; + } + + verboseLevel = std::max(verboseLevel, wantCert ? 2 : wantKey ? 1 : 0); + + security::v2::KeyChain keyChain; + + // TODO: add API to check for default identity (may be from the identity itself) + security::Identity defaultIdentity; + try { + defaultIdentity = keyChain.getPib().getDefaultIdentity(); + } + catch (const security::Pib::Error&) { + // no default identity + } + + Printer printer(verboseLevel); + for (const auto& identity : keyChain.getPib().getIdentities()) { + printer.printIdentity(identity, identity == defaultIdentity); + } + + return 0; +} + +} // namespace ndnsec +} // namespace ndn diff --git a/tools/ndnsec/list.hpp b/tools/ndnsec/list.hpp deleted file mode 100644 index 8a750f270..000000000 --- a/tools/ndnsec/list.hpp +++ /dev/null @@ -1,174 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_LIST_HPP -#define NDN_TOOLS_NDNSEC_LIST_HPP - -#include "util.hpp" - -void -printCertificate(ndn::KeyChain& keyChain, - const ndn::Name& certName, - bool isDefault, - int verboseLevel) -{ - if (isDefault) - std::cout << " +->* "; - else - std::cout << " +-> "; - - std::cout << certName << std::endl; - - if (verboseLevel >= 3) { - ndn::shared_ptr certificate = keyChain.getCertificate(certName); - if (static_cast(certificate)) - certificate->printCertificate(std::cout, " "); - } -} - -void -printKey(ndn::KeyChain& keyChain, - const ndn::Name& keyName, - bool isDefault, - int verboseLevel) -{ - if (isDefault) - std::cout << " +->* "; - else - std::cout << " +-> "; - - std::cout << keyName << std::endl; - - if (verboseLevel >= 2) { - std::vector defaultCertificates; - keyChain.getAllCertificateNamesOfKey(keyName, defaultCertificates, true); - - for (const auto& certName : defaultCertificates) - printCertificate(keyChain, certName, true, verboseLevel); - - std::vector otherCertificates; - keyChain.getAllCertificateNamesOfKey(keyName, otherCertificates, false); - for (const auto& certName : otherCertificates) - printCertificate(keyChain, certName, false, verboseLevel); - } -} - -void -printIdentity(ndn::KeyChain& keyChain, - const ndn::Name& identity, - bool isDefault, - int verboseLevel) -{ - if (isDefault) - std::cout << "* "; - else - std::cout << " "; - - std::cout << identity << std::endl; - - if (verboseLevel >= 1) { - std::vector defaultKeys; - keyChain.getAllKeyNamesOfIdentity(identity, defaultKeys, true); - for (const auto& keyName : defaultKeys) - printKey(keyChain, keyName, true, verboseLevel); - - std::vector otherKeys; - keyChain.getAllKeyNamesOfIdentity(identity, otherKeys, false); - for (const auto& keyName : otherKeys) { - printKey(keyChain, keyName, false, verboseLevel); - } - - std::cout << std::endl; - } -} - -int -ndnsec_list(int argc, char** argv) -{ - using namespace ndn; - namespace po = boost::program_options; - - int verboseLevel = 0; // 0 print identity only - // 1 print key name - // 2 print cert name - // 3 print cert content - - po::options_description options("General Usage\n ndnsec list [-h] [-k|c]\nGeneral options"); - options.add_options() - ("help,h", "produce help message") - ("key,k", "granularity: key") - ("cert,c", "granularity: certificate") - ("verbose,v", accumulator(&verboseLevel), - "verbose mode: -v is equivalent to -k, -vv is equivalent to -c") - ; - - po::options_description oldOptions; - oldOptions.add_options() - ("key2,K", "granularity: key") - ("cert2,C", "granularity: certificate"); - - po::options_description allOptions; - allOptions.add(options).add(oldOptions); - - po::variables_map vm; - try { - po::store(po::parse_command_line(argc, argv, allOptions), vm); - po::notify(vm); - } - catch (const std::exception& e) { - std::cerr << "ERROR: " << e.what() << std::endl; - std::cerr << options << std::endl; - return 1; - } - - if (vm.count("help") != 0) { - std::cerr << options << std::endl;; - return 0; - } - - int tmpVerboseLevel = 0; - if (vm.count("cert") != 0 || vm.count("cert2") != 0) - tmpVerboseLevel = 2; - else if(vm.count("key") != 0 || vm.count("key2") != 0) - tmpVerboseLevel = 1; - - verboseLevel = std::max(verboseLevel, tmpVerboseLevel); - - KeyChain keyChain; - - std::vector defaultIdentities; - keyChain.getAllIdentities(defaultIdentities, true); - for (const auto& identity : defaultIdentities) { - printIdentity(keyChain, identity, true, verboseLevel); - } - - std::vector otherIdentities; - keyChain.getAllIdentities(otherIdentities, false); - for (const auto& identity : otherIdentities) { - printIdentity(keyChain, identity, false, verboseLevel); - } - - return 0; -} - -#endif // NDN_TOOLS_NDNSEC_LIST_HPP diff --git a/tools/ndnsec/main.cpp b/tools/ndnsec/main.cpp index f0c97b767..8548748ab 100644 --- a/tools/ndnsec/main.cpp +++ b/tools/ndnsec/main.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -17,98 +17,76 @@ * . * * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu */ -#include "version.hpp" - +#include "ndnsec.hpp" #include "util.hpp" -#include "list.hpp" -#include "get-default.hpp" -#include "set-default.hpp" -#include "key-gen.hpp" -#include "dsk-gen.hpp" -#include "sign-req.hpp" -#include "cert-gen.hpp" -#include "cert-revoke.hpp" -#include "cert-dump.hpp" -#include "cert-install.hpp" -#include "export.hpp" -#include "import.hpp" -#include "delete.hpp" -#include "sig-verify.hpp" -#include "set-acl.hpp" -#include "unlock-tpm.hpp" -#include "op-tool.hpp" -using namespace ndn; +#include "ndn-cxx/util/logger.hpp" +#include "ndn-cxx/version.hpp" + +#include + +NDN_LOG_INIT(ndnsec); + +const char NDNSEC_HELP_TEXT[] = R"STR(Usage: ndnsec COMMAND [OPTION]... -std::string ndnsec_helper("\ - help Show all commands.\n\ - version Show version and exit.\n\ - list Display information in PublicInfo.\n\ - get-default Get default setting info.\n\ - set-default Configure default setting.\n\ - key-gen Generate a Key-Signing-Key for an identity.\n\ - dsk-gen Generate a Data-Signing-Key for an identity.\n\ - sign-req Generate a certificate signing request.\n\ - cert-gen Generate an identity certificate.\n\ - cert-revoke Revoke an identity certificate.\n\ - cert-dump Dump a certificate from PublicInfo.\n\ - cert-install Install a certificate into PublicInfo.\n\ - delete Delete identity/key/certificate.\n\ - export Export an identity package.\n\ - import Import an identity package.\n\ - sig-verify Verify the signature of a Data packet.\n\ - set-acl Configure ACL of a private key.\n\ - unlock-tpm Unlock Tpm.\n\ - op-tool Operator tool.\n\ -"); +Available commands: + help Print this help text + version Print program version + list List all known identities/keys/certificates + get-default Show the default identity/key/certificate + set-default Change the default identity/key/certificate + delete Delete an identity/key/certificate + key-gen Generate a key for an identity + sign-req Generate a certificate signing request + cert-gen Create a certificate for an identity + cert-dump Export a certificate + cert-install Import a certificate from a file + export Export an identity as a SafeBag + import Import an identity from a SafeBag + unlock-tpm Unlock the TPM + +Try 'ndnsec COMMAND --help' for more information on each command.)STR"; int -main(int argc, char** argv) +main(int argc, char* argv[]) { - if (argc < 2) - { - std::cerr << ndnsec_helper << std::endl; - return 1; - } + if (argc < 2) { + std::cerr << NDNSEC_HELP_TEXT << std::endl; + return 2; + } - std::string command(argv[1]); + using namespace ndn::ndnsec; - try - { - if (command == "help") { std::cout << ndnsec_helper << std::endl; } - else if (command == "version") { std::cout << NDN_CXX_VERSION_BUILD_STRING - << std::endl; } - else if (command == "list") { return ndnsec_list(argc - 1, argv + 1); } - else if (command == "get-default") { return ndnsec_get_default(argc - 1, argv + 1); } - else if (command == "set-default") { return ndnsec_set_default(argc - 1, argv + 1); } - else if (command == "key-gen") { return ndnsec_key_gen(argc - 1, argv + 1); } - else if (command == "dsk-gen") { return ndnsec_dsk_gen(argc - 1, argv + 1); } - else if (command == "sign-req") { return ndnsec_sign_req(argc - 1, argv + 1); } - else if (command == "cert-gen") { return ndnsec_cert_gen(argc - 1, argv + 1); } - else if (command == "cert-revoke") { return ndnsec_cert_revoke(argc - 1, argv + 1); } - else if (command == "cert-dump") { return ndnsec_cert_dump(argc - 1, argv + 1); } - else if (command == "cert-install") { return ndnsec_cert_install(argc - 1, argv + 1); } - else if (command == "delete") { return ndnsec_delete(argc - 1, argv + 1); } - else if (command == "export") { return ndnsec_export(argc - 1, argv + 1); } - else if (command == "import") { return ndnsec_import(argc - 1, argv + 1); } - else if (command == "sig-verify") { return ndnsec_sig_verify(argc - 1, argv + 1); } - else if (command == "set-acl") { return ndnsec_set_acl(argc - 1, argv + 1); } - else if (command == "unlock-tpm") { return ndnsec_unlock_tpm(argc - 1, argv + 1); } - else if (command == "op-tool") { return ndnsec_op_tool(argc - 1, argv + 1); } - else { - std::cerr << ndnsec_helper << std::endl; - return 1; - } - } - catch (const std::runtime_error& e) - { - std::cerr << "ERROR: " << e.what() << std::endl; - return 1; + std::string command(argv[1]); + try { + if (command == "help") { std::cout << NDNSEC_HELP_TEXT << std::endl; } + else if (command == "version") { std::cout << NDN_CXX_VERSION_BUILD_STRING << std::endl; } + else if (command == "list") { return ndnsec_list(argc - 1, argv + 1); } + else if (command == "get-default") { return ndnsec_get_default(argc - 1, argv + 1); } + else if (command == "set-default") { return ndnsec_set_default(argc - 1, argv + 1); } + else if (command == "delete") { return ndnsec_delete(argc - 1, argv + 1); } + else if (command == "key-gen") { return ndnsec_key_gen(argc - 1, argv + 1); } + else if (command == "sign-req") { return ndnsec_sign_req(argc - 1, argv + 1); } + else if (command == "cert-gen") { return ndnsec_cert_gen(argc - 1, argv + 1); } + else if (command == "cert-dump") { return ndnsec_cert_dump(argc - 1, argv + 1); } + else if (command == "cert-install") { return ndnsec_cert_install(argc - 1, argv + 1); } + else if (command == "export") { return ndnsec_export(argc - 1, argv + 1); } + else if (command == "import") { return ndnsec_import(argc - 1, argv + 1); } + else if (command == "unlock-tpm") { return ndnsec_unlock_tpm(argc - 1, argv + 1); } + else { + std::cerr << "ERROR: Unknown command '" << command << "'\n" + << "\n" + << NDNSEC_HELP_TEXT << std::endl; + return 2; } + } + catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << std::endl; + NDN_LOG_ERROR(boost::diagnostic_information(e)); + return 1; + } return 0; } diff --git a/tools/ndnsec/ndnsec.hpp b/tools/ndnsec/ndnsec.hpp new file mode 100644 index 000000000..dd34dd9c7 --- /dev/null +++ b/tools/ndnsec/ndnsec.hpp @@ -0,0 +1,69 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2013-2017 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#ifndef NDN_TOOLS_NDNSEC_NDNSEC_HPP +#define NDN_TOOLS_NDNSEC_NDNSEC_HPP + +namespace ndn { +namespace ndnsec { + +// TODO convert to tool registry (may be) + +int +ndnsec_list(int argc, char** argv); + +int +ndnsec_get_default(int argc, char** argv); + +int +ndnsec_set_default(int argc, char** argv); + +int +ndnsec_key_gen(int argc, char** argv); + +int +ndnsec_sign_req(int argc, char** argv); + +int +ndnsec_cert_gen(int argc, char** argv); + +int +ndnsec_cert_dump(int argc, char** argv); + +int +ndnsec_cert_install(int argc, char** argv); + +int +ndnsec_delete(int argc, char** argv); + +int +ndnsec_export(int argc, char** argv); + +int +ndnsec_import(int argc, char** argv); + +int +ndnsec_unlock_tpm(int argc, char** argv); + +} // namespace ndnsec +} // namespace ndn + +#endif // NDN_TOOLS_NDNSEC_NDNSEC_HPP diff --git a/tools/ndnsec/op-tool.hpp b/tools/ndnsec/op-tool.hpp deleted file mode 100644 index 576694942..000000000 --- a/tools/ndnsec/op-tool.hpp +++ /dev/null @@ -1,96 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_OP_TOOL_HPP -#define NDN_TOOLS_NDNSEC_OP_TOOL_HPP - -#include "util.hpp" - -int -ndnsec_op_tool(int argc, char** argv) -{ - using namespace ndn; - namespace po = boost::program_options; - - std::string command; - - po::options_description description("General options"); - description.add_options() - ("help,h", "produce this help message") - ("command", po::value(&command), "command") - ; - - po::positional_options_description p; - p.add("command", 1); - - po::variables_map vm; - try - { - po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), - 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; - } - - if (vm.count("command") == 0) - { - std::cerr << "command must be specified" << std::endl; - std::cerr << description << std::endl; - return 1; - } - - if (command == "sign") // the content to be signed from stdin - { - KeyChain keyChain; - - Buffer dataToSign((std::istreambuf_iterator(std::cin)), std::istreambuf_iterator()); - - Block value = keyChain.sign(dataToSign.buf(), dataToSign.size(), - security::SigningInfo(security::SigningInfo::SIGNER_TYPE_CERT, - keyChain.getDefaultCertificateName())); - - if (value.value_size() == 0) - { - std::cerr << "Error signing with default key" << std::endl; - return -1; - } - - value.encode(); - std::cout.write(reinterpret_cast(value.wire()), value.size()); - } - - return 0; -} - -#endif // NDN_TOOLS_NDNSEC_OP_TOOL_HPP diff --git a/tools/ndnsec/set-acl.hpp b/tools/ndnsec/set-acl.hpp deleted file mode 100644 index ca639b6e7..000000000 --- a/tools/ndnsec/set-acl.hpp +++ /dev/null @@ -1,88 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_SET_ACL_HPP -#define NDN_TOOLS_NDNSEC_SET_ACL_HPP - -#include "util.hpp" - -int -ndnsec_set_acl(int argc, char** argv) -{ - using namespace ndn; - namespace po = boost::program_options; - - std::string keyName; - std::string appPath; - - po::options_description description("General Usage\n ndnsec set-acl [-h] keyName appPath \nGeneral options"); - description.add_options() - ("help,h", "produce help message") - ("keyName,k", po::value(&keyName), "Key name.") - ("appPath,p", po::value(&appPath), "Application path.") - ; - - po::positional_options_description p; - p.add("keyName", 1); - p.add("appPath", 1); - - po::variables_map vm; - try - { - po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), - vm); - po::notify(vm); - } - catch (std::exception& e) - { - std::cerr << "ERROR: " << e.what() << std::endl; - return 1; - } - - if (vm.count("help") != 0) - { - std::cerr << description << std::endl; - return 0; - } - - if (vm.count("keyName") == 0) - { - std::cerr << "ERROR: keyName is required!" << std::endl; - std::cerr << description << std::endl; - return 1; - } - - if (vm.count("appPath") == 0) - { - std::cerr << "ERROR: appPath is required!" << std::endl; - std::cerr << description << std::endl; - return 1; - } - - KeyChain keyChain; - keyChain.addAppToAcl(keyName, KeyClass::PRIVATE, appPath, AclType::PRIVATE); - - return 0; -} - -#endif // NDN_TOOLS_NDNSEC_SET_ACL_HPP diff --git a/tools/ndnsec/set-default.cpp b/tools/ndnsec/set-default.cpp new file mode 100644 index 000000000..d1647ed95 --- /dev/null +++ b/tools/ndnsec/set-default.cpp @@ -0,0 +1,99 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndnsec.hpp" +#include "util.hpp" + +namespace ndn { +namespace ndnsec { + +int +ndnsec_set_default(int argc, char** argv) +{ + namespace po = boost::program_options; + + Name name; + bool wantSetDefaultKey = false; + bool wantSetDefaultCert = false; + + po::options_description description( + "Usage: ndnsec set-default [-h] [-k|-c] [-n] NAME\n" + "\n" + "Options"); + description.add_options() + ("help,h", "produce help message") + ("name,n", po::value(&name), "the identity/key/certificate name to set") + ("default-key,k", po::bool_switch(&wantSetDefaultKey), "set default key of the identity") + ("default-cert,c", po::bool_switch(&wantSetDefaultCert), "set default certificate of the key") + ; + + po::positional_options_description p; + p.add("name", 1); + + po::variables_map vm; + try { + po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm); + po::notify(vm); + } + catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << "\n\n" + << description << std::endl; + return 2; + } + + if (vm.count("help") > 0) { + std::cout << description << std::endl; + return 0; + } + + if (vm.count("name") == 0) { + std::cerr << "ERROR: you must specify a name" << std::endl; + return 2; + } + + if (wantSetDefaultKey && wantSetDefaultCert) { + std::cerr << "ERROR: cannot specify both '--default-key' and '--default-cert'" << std::endl; + return 2; + } + + security::v2::KeyChain keyChain; + + if (wantSetDefaultKey) { + auto identity = keyChain.getPib().getIdentity(security::v2::extractIdentityFromKeyName(name)); + auto key = identity.getKey(name); + keyChain.setDefaultKey(identity, key); + } + else if (wantSetDefaultCert) { + auto identity = keyChain.getPib().getIdentity(security::v2::extractIdentityFromCertName(name)); + auto key = identity.getKey(security::v2::extractKeyNameFromCertName(name)); + auto cert = key.getCertificate(name); + keyChain.setDefaultCertificate(key, cert); + } + else { + auto identity = keyChain.getPib().getIdentity(name); + keyChain.setDefaultIdentity(identity); + } + + return 0; +} + +} // namespace ndnsec +} // namespace ndn diff --git a/tools/ndnsec/set-default.hpp b/tools/ndnsec/set-default.hpp deleted file mode 100644 index ed23b6fdf..000000000 --- a/tools/ndnsec/set-default.hpp +++ /dev/null @@ -1,110 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_SET_DEFAULT_HPP -#define NDN_TOOLS_NDNSEC_SET_DEFAULT_HPP - -int -ndnsec_set_default(int argc, char** argv) -{ - using namespace ndn; - namespace po = boost::program_options; - - std::string certFileName; - bool isSetDefaultId = true; - bool isSetDefaultKey = false; - bool isSetDefaultCert = false; - std::string name; - - po::options_description description("General Usage\n ndnsec set-default [-h] [-k|c] name\nGeneral options"); - description.add_options() - ("help,h", "produce help message") - ("default_key,k", "set default key of the identity") - ("default_cert,c", "set default certificate of the key") - ("name,n", po::value(&name), "the name to set") - ; - - po::positional_options_description p; - p.add("name", 1); - po::variables_map vm; - try - { - po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), - 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; - } - - if (vm.count("name") == 0) - { - std::cerr << "ERROR: name is required!" << std::endl; - std::cerr << description << std::endl; - return 1; - } - - KeyChain keyChain; - - if (vm.count("default_key") != 0) - { - isSetDefaultKey = true; - isSetDefaultId = false; - } - else if (vm.count("default_cert") != 0) - { - isSetDefaultCert = true; - isSetDefaultId = false; - } - - if (isSetDefaultId) - { - Name idName(name); - keyChain.setDefaultIdentity(idName); - return 0; - } - if (isSetDefaultKey) - { - Name keyName(name); - keyChain.setDefaultKeyNameForIdentity(keyName); - return 0; - } - - if (isSetDefaultCert) - { - keyChain.setDefaultCertificateNameForKey(name); - return 0; - } - - return 1; -} -#endif // NDN_TOOLS_NDNSEC_SET_DEFAULT_HPP diff --git a/tools/ndnsec/sig-verify.hpp b/tools/ndnsec/sig-verify.hpp deleted file mode 100644 index 28107ce3c..000000000 --- a/tools/ndnsec/sig-verify.hpp +++ /dev/null @@ -1,128 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_SIG_VERIFY_HPP -#define NDN_TOOLS_NDNSEC_SIG_VERIFY_HPP - -#include "util.hpp" - -// using namespace ndn; -// namespace po = boost::program_options; - -// shared_ptr -// getCertificate(const std::string& certString) -// { -// std::string decoded; -// CryptoPP::StringSource ss2(reinterpret_cast(certString.c_str()), certString.size(), true, -// new CryptoPP::Base64Decoder(new CryptoPP::StringSink(decoded))); - -// Data data; -// data.wireDecode(Block(make_shared(decoded.begin(), decoded.end()))); - -// shared_ptr identityCertificate = make_shared(data); - -// return identityCertificate; -// } - -// bool -// verifySignature(shared_ptr certificate, bool isDataPacket) -// { -// throw std::runtime_error("Not supported yet"); -// // if(isDataPacket) -// // { -// // std::string decoded; -// // CryptoPP::FileSource ss2(cin, true, -// // new CryptoPP::Base64Decoder(new CryptoPP::StringSink(decoded))); - -// // Data data; -// // data.wireDecode(make_shared(decoded.c_str(), decoded.size())); -// // return PolicyManager::verifySignature(data, certificate->getPublicKeyInfo()); -// // } -// // else -// // { -// // // The first two bytes indicates the boundary of the of the signed data and signature. -// // // for example, if the size of the signed data is 300, then the boundary should be 300, so the first two bytes should be: 0x01 0x2C -// // shared_ptr input = shared_ptr(new Blob ((istreambuf_iterator(cin)), istreambuf_iterator())); -// // size_t size = input->at(0); -// // size = ((size << 8) + input->at(1)); - -// // Blob signedBlob(input->buf()+2, size); -// // Blob signature(input->buf()+2+size, input->size()-2-size); - -// // return PolicyManager::verifySignature(signedBlob, signature, certificate->getPublicKeyInfo()); -// // } -// } - -int -ndnsec_sig_verify(int argc, char** argv) -{ - std::cerr << "Not supported yet" << std::endl; - return 1; - // bool isDataPacket = false; - // std::string certString; - - // po::options_description desc("General Usage\n ndn-sig-verify [-h] [-d] certificate\nGeneral options"); - // desc.add_options() - // ("help,h", "produce help message") - // ("data,d", "if specified, input from stdin will be treated as a Data packet, otherwise binary data") - // ("certificate,c", po::value(&certString), "the certificate bits") - // ; - - // po::positional_options_description p; - // p.add("certificate", 1); - - // po::variables_map vm; - // try - // { - // po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm); - // po::notify(vm); - // } - // catch( const std::exception& e) - // { - // std::cerr << e.what() << std::endl; - // std::cerr << desc << std::endl; - // return 1; - // } - - // if (vm.count("help") || vm.count("certificate")==0) - // { - // std::cerr << desc << std::endl; - // return 1; - // } - // if (vm.count("data")) - // isDataPacket = true; - - // try - // { - // shared_ptr certificate = getCertificate(certString); - // bool res = verifySignature(certificate, isDataPacket); - // return (res ? 0 : 1); - // } - // catch(const std::exception &e) - // { - // std::cerr << "ERROR: " << e.what() << std::endl; - // return 1; - // } -} - -#endif // NDN_TOOLS_NDNSEC_SIG_VERIFY_HPP diff --git a/tools/ndnsec/sign-req.cpp b/tools/ndnsec/sign-req.cpp new file mode 100644 index 000000000..d8d7486d8 --- /dev/null +++ b/tools/ndnsec/sign-req.cpp @@ -0,0 +1,113 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndnsec.hpp" +#include "util.hpp" + +namespace ndn { +namespace ndnsec { + +int +ndnsec_sign_req(int argc, char** argv) +{ + namespace po = boost::program_options; + + Name name; + bool isKeyName = false; + + po::options_description description( + "Usage: ndnsec sign-req [-h] [-k] [-n] NAME\n" + "\n" + "Options"); + description.add_options() + ("help,h", "produce help message") + ("name,n", po::value(&name), "identity or key name, e.g., /ndn/edu/ucla/alice") + ("key,k", po::bool_switch(&isKeyName), "the specified name is a key name rather than an identity") + ; + + po::positional_options_description p; + p.add("name", 1); + + po::variables_map vm; + try { + po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), vm); + po::notify(vm); + } + catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << "\n\n" + << description << std::endl; + return 2; + } + + if (vm.count("help") > 0) { + std::cout << description << std::endl; + return 0; + } + + if (vm.count("name") == 0) { + std::cerr << "ERROR: you must specify a name" << std::endl; + return 2; + } + + security::v2::KeyChain keyChain; + + security::Identity identity; + security::Key key; + if (!isKeyName) { + identity = keyChain.getPib().getIdentity(name); + key = identity.getDefaultKey(); + } + else { + identity = keyChain.getPib().getIdentity(security::v2::extractIdentityFromKeyName(name)); + key = identity.getKey(name); + } + + // Create signing request (similar to self-signed certificate) + security::v2::Certificate certificate; + + // set name + Name certificateName = key.getName(); + certificateName + .append("cert-request") + .appendVersion(); + certificate.setName(certificateName); + + // set metainfo + certificate.setContentType(tlv::ContentType_Key); + certificate.setFreshnessPeriod(1_h); + + // set content + certificate.setContent(key.getPublicKey().data(), key.getPublicKey().size()); + + // set signature-info + SignatureInfo signatureInfo; + auto now = time::system_clock::now(); + signatureInfo.setValidityPeriod(security::ValidityPeriod(now, now + 10_days)); + + keyChain.sign(certificate, security::SigningInfo(key).setSignatureInfo(signatureInfo)); + + io::save(certificate, std::cout); + + return 0; +} + +} // namespace ndnsec +} // namespace ndn diff --git a/tools/ndnsec/sign-req.hpp b/tools/ndnsec/sign-req.hpp deleted file mode 100644 index bb8906e07..000000000 --- a/tools/ndnsec/sign-req.hpp +++ /dev/null @@ -1,100 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_SIGN_REQ_HPP -#define NDN_TOOLS_NDNSEC_SIGN_REQ_HPP - -#include "util.hpp" - -int -ndnsec_sign_req(int argc, char** argv) -{ - using namespace ndn; - using namespace ndn::security; - namespace po = boost::program_options; - - std::string name; - bool isKeyName = false; - - po::options_description description("General Usage\n ndnsec sign-req [-h] [-k] name\nGeneral options"); - description.add_options() - ("help,h", "produce help message") - ("key,k", "optional, if specified, name is keyName (e.g. /ndn/edu/ucla/alice/ksk-123456789), otherwise identity name") - ("name,n", po::value(&name), "name, for example, /ndn/edu/ucla/alice") - ; - - po::positional_options_description p; - p.add("name", 1); - - po::variables_map vm; - try - { - po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(), - 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; - } - - if (vm.count("name") == 0) - { - std::cerr << "ERROR: name must be specified" << std::endl; - std::cerr << description << std::endl; - return 1; - } - - if (vm.count("key") != 0) - isKeyName = true; - - shared_ptr selfSignCert; - - KeyChain keyChain; - - if (isKeyName) - selfSignCert = keyChain.selfSign(name); - else { - Name keyName = keyChain.getDefaultKeyNameForIdentity(name); - selfSignCert = keyChain.selfSign(keyName); - } - - if (static_cast(selfSignCert)) { - io::save(*selfSignCert, std::cout); - return 0; - } - else { - std::cerr << "ERROR: Public key does not exist" << std::endl; - return 1; - } -} - -#endif // NDN_TOOLS_NDNSEC_SIGN_REQ_HPP diff --git a/tools/ndnsec/unlock-tpm.cpp b/tools/ndnsec/unlock-tpm.cpp new file mode 100644 index 000000000..d79db7f95 --- /dev/null +++ b/tools/ndnsec/unlock-tpm.cpp @@ -0,0 +1,90 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "ndnsec.hpp" +#include "util.hpp" + +#include "ndn-cxx/security/impl/openssl.hpp" + +#include +#include +#include + +namespace ndn { +namespace ndnsec { + +int +ndnsec_unlock_tpm(int argc, char** argv) +{ + namespace po = boost::program_options; + + po::options_description description( + "Usage: ndnsec unlock-tpm [-h]\n" + "\n" + "Options"); + description.add_options() + ("help,h", "produce help message") + ; + + 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() << "\n\n" + << description << std::endl; + return 2; + } + + if (vm.count("help") > 0) { + std::cout << description << std::endl; + return 0; + } + +#ifdef NDN_CXX_HAVE_GETPASS + security::v2::KeyChain keyChain; + + char* password = ::getpass("Password to unlock the TPM: "); + if (password == nullptr) { + std::cerr << "ERROR: getpass() failed: " << std::strerror(errno) << std::endl; + return 1; + } + + bool isUnlocked = keyChain.getTpm().unlockTpm(password, std::strlen(password)); + OPENSSL_cleanse(password, std::strlen(password)); + + if (isUnlocked) { + std::cerr << "OK: TPM is unlocked" << std::endl; + return 0; + } + else { + std::cerr << "ERROR: TPM is still locked" << std::endl; + return 1; + } +#else + std::cerr << "ERROR: Command not supported on this platform" << std::endl; + return 1; +#endif // NDN_CXX_HAVE_GETPASS +} + +} // namespace ndnsec +} // namespace ndn diff --git a/tools/ndnsec/unlock-tpm.hpp b/tools/ndnsec/unlock-tpm.hpp deleted file mode 100644 index 2127848f5..000000000 --- a/tools/ndnsec/unlock-tpm.hpp +++ /dev/null @@ -1,88 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2015 Regents of the University of California. - * - * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). - * - * ndn-cxx library is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * ndn-cxx library 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 Lesser General Public License for more details. - * - * You should have received copies of the GNU General Public License and GNU Lesser - * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see - * . - * - * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu - */ - -#ifndef NDN_TOOLS_NDNSEC_UNLOCK_TPM_HPP -#define NDN_TOOLS_NDNSEC_UNLOCK_TPM_HPP - -#include "util.hpp" - -int -ndnsec_unlock_tpm(int argc, char** argv) -{ -#ifdef NDN_CXX_HAVE_GETPASS - using namespace ndn; - namespace po = boost::program_options; - - std::string keyName; - - po::options_description description("General Usage\n ndnsec unlock-tpm [-h] \nGeneral options"); - description.add_options() - ("help,h", "produce help message") - ; - - 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; - } - - bool isUnlocked = false; - - KeyChain keyChain; - - char* password; - password = getpass("Password to unlock the TPM: "); - isUnlocked = keyChain.unlockTpm(password, strlen(password), true); - memset(password, 0, strlen(password)); - - if (isUnlocked) - { - std::cerr << "OK: TPM is unlocked" << std::endl; - return 0; - } - else - { - std::cerr << "ERROR: TPM is still locked" << std::endl; - return 1; - } -#else - std::cerr << "ERROR: Command not supported on this platform" << std::endl; - return 1; -#endif // NDN_CXX_HAVE_GETPASS -} - -#endif // NDN_TOOLS_NDNSEC_UNLOCK_TPM_HPP diff --git a/tools/ndnsec/util.cpp b/tools/ndnsec/util.cpp new file mode 100644 index 000000000..4895ed3b1 --- /dev/null +++ b/tools/ndnsec/util.cpp @@ -0,0 +1,86 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013-2019 Regents of the University of California. + * + * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). + * + * ndn-cxx library is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * ndn-cxx library 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 Lesser General Public License for more details. + * + * You should have received copies of the GNU General Public License and GNU Lesser + * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see + * . + * + * See AUTHORS.md for complete list of ndn-cxx authors and contributors. + */ + +#include "util.hpp" + +#include "ndn-cxx/security/impl/openssl.hpp" + +#include + +namespace ndn { +namespace ndnsec { + +bool +getPassword(std::string& password, const std::string& prompt, bool shouldConfirm) +{ +#ifdef NDN_CXX_HAVE_GETPASS + char* pw0 = getpass(prompt.c_str()); + if (!pw0 || strlen(pw0) == 0) { + return false; + } + std::string password1 = pw0; + OPENSSL_cleanse(pw0, strlen(pw0)); + + if (!shouldConfirm) { + password.swap(password1); + return true; + } + + pw0 = getpass("Confirm: "); + if (!pw0) { + OPENSSL_cleanse(&password1.front(), password1.size()); + return false; + } + + bool isReady = false; + if (password1.size() == strlen(pw0) && + CRYPTO_memcmp(password1.data(), pw0, password1.size()) == 0) { + isReady = true; + password.swap(password1); + } + else { + OPENSSL_cleanse(&password1.front(), password1.size()); + } + OPENSSL_cleanse(pw0, strlen(pw0)); + + return isReady; +#else + return false; +#endif // NDN_CXX_HAVE_GETPASS +} + +security::v2::Certificate +loadCertificate(const std::string& fileName) +{ + shared_ptr cert; + if (fileName == "-") + cert = io::load(std::cin); + else + cert = io::load(fileName); + + if (cert == nullptr) { + NDN_THROW(CannotLoadCertificate(fileName)); + } + return *cert; +} + +} // namespace ndnsec +} // namespace ndn diff --git a/tools/ndnsec/util.hpp b/tools/ndnsec/util.hpp index f09651569..90c328469 100644 --- a/tools/ndnsec/util.hpp +++ b/tools/ndnsec/util.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2013-2016 Regents of the University of California. +/* + * Copyright (c) 2013-2019 Regents of the University of California. * * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). * @@ -17,82 +17,40 @@ * . * * See AUTHORS.md for complete list of ndn-cxx authors and contributors. - * - * @author Yingdi Yu */ #ifndef NDN_TOOLS_NDNSEC_UTIL_HPP #define NDN_TOOLS_NDNSEC_UTIL_HPP -#include +#include "ndn-cxx/security/key-chain.hpp" +#include "ndn-cxx/security/v2/additional-description.hpp" +#include "ndn-cxx/util/io.hpp" + #include +#include #include -#include #include -#include #include -#include -#include -#include -#include +#include -#include "encoding/buffer-stream.hpp" -#include "security/key-chain.hpp" -#include "security/transform.hpp" -#include "util/io.hpp" +namespace ndn { +namespace ndnsec { -bool -getPassword(std::string& password, const std::string& prompt) -{ -#ifdef NDN_CXX_HAVE_GETPASS - bool isReady = false; - - char* pw0 = 0; - - pw0 = getpass(prompt.c_str()); - if (!pw0) - return false; - std::string password1 = pw0; - memset(pw0, 0, strlen(pw0)); - - pw0 = getpass("Confirm:"); - if (!pw0) - { - char* pw1 = const_cast(password1.c_str()); - memset(pw1, 0, password1.size()); - return false; - } - - if (!password1.compare(pw0)) - { - isReady = true; - password.swap(password1); - } - - char* pw1 = const_cast(password1.c_str()); - memset(pw1, 0, password1.size()); - memset(pw0, 0, strlen(pw0)); - - if (password.empty()) - return false; - - return isReady; -#else - return false; -#endif // NDN_CXX_HAVE_GETPASS -} - -ndn::shared_ptr -getIdentityCertificate(const std::string& fileName) +class CannotLoadCertificate : public std::runtime_error { +public: + CannotLoadCertificate(const std::string& msg) + : std::runtime_error(msg) + { + } +}; - if (fileName == "-") - return ndn::io::load(std::cin); - else - return ndn::io::load(fileName); -} +bool +getPassword(std::string& password, const std::string& prompt, bool shouldConfirm = true); +security::v2::Certificate +loadCertificate(const std::string& fileName); /** * @brief An accumulating option value to handle multiple incrementing options. @@ -112,11 +70,6 @@ class AccumulatorType : public boost::program_options::value_semantic { } - virtual - ~AccumulatorType() - { - } - /// @brief Set the default value for this option. AccumulatorType* setDefaultValue(const T& t) @@ -132,39 +85,40 @@ class AccumulatorType : public boost::program_options::value_semantic * to be applied on each occurrence of the option. */ AccumulatorType* - setInterval(const T& t) { + setInterval(const T& t) + { m_interval = t; return this; } - virtual std::string + std::string name() const final { return std::string(); } // There are no tokens for an AccumulatorType - virtual unsigned + unsigned min_tokens() const final { return 0; } - virtual unsigned + unsigned max_tokens() const final { return 0; } // Accumulating from different sources is silly. - virtual bool + bool is_composing() const final { return false; } // Requiring one or more appearances is unlikely. - virtual bool + bool is_required() const final { return false; @@ -176,10 +130,8 @@ class AccumulatorType : public boost::program_options::value_semantic * Every appearance of the option simply increments the value * There should never be any tokens. */ - virtual void - parse(boost::any& value_store, - const std::vector& new_tokens, - bool utf8) const final + void + parse(boost::any& value_store, const std::vector& new_tokens, bool utf8) const final { if (value_store.empty()) value_store = T(); @@ -189,7 +141,7 @@ class AccumulatorType : public boost::program_options::value_semantic /** * @brief If the option doesn't appear, this is the default value. */ - virtual bool + bool apply_default(boost::any& value_store) const final { value_store = m_default; @@ -199,7 +151,7 @@ class AccumulatorType : public boost::program_options::value_semantic /** * @brief Notify the user function with the value of the value store. */ - virtual void + void notify(const boost::any& value_store) const final { const T* val = boost::any_cast(&value_store); @@ -207,30 +159,35 @@ class AccumulatorType : public boost::program_options::value_semantic *m_store = *val; } -#if BOOST_VERSION >= 105900 - virtual bool +#if (BOOST_VERSION >= 105900) && (BOOST_VERSION < 106500) + bool adjacent_tokens_only() const final { return false; } -#endif // BOOST_VERSION >= 105900 +#endif // (BOOST_VERSION >= 105900) && (BOOST_VERSION < 106500) private: - T* m_store; - T m_interval; - T m_default; + T* m_store; + T m_interval; + T m_default; }; -template -AccumulatorType* accumulator() +template +AccumulatorType* +accumulator() { return new AccumulatorType(0); } -template -AccumulatorType* accumulator(T* store) +template +AccumulatorType* +accumulator(T* store) { return new AccumulatorType(store); } +} // namespace ndnsec +} // namespace ndn + #endif // NDN_TOOLS_NDNSEC_UTIL_HPP diff --git a/tools/wrapper/ndnsec-cert-revoke.sh b/tools/wrapper/ndnsec-cert-revoke.sh deleted file mode 100644 index 9c610b5fb..000000000 --- a/tools/wrapper/ndnsec-cert-revoke.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!@SH@ - -`dirname "$0"`/ndnsec cert-revoke "$@" diff --git a/tools/wrapper/ndnsec-dsk-gen.sh b/tools/wrapper/ndnsec-dsk-gen.sh deleted file mode 100644 index 31e485c8d..000000000 --- a/tools/wrapper/ndnsec-dsk-gen.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!@SH@ - -`dirname "$0"`/ndnsec dsk-gen "$@" \ No newline at end of file diff --git a/tools/wrapper/ndnsec-dskgen.sh b/tools/wrapper/ndnsec-dskgen.sh deleted file mode 100644 index c256026d9..000000000 --- a/tools/wrapper/ndnsec-dskgen.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!@SH@ - -#to accomodate the old command -`dirname "$0"`/ndnsec dsk-gen "$@" \ No newline at end of file diff --git a/tools/wrapper/ndnsec-op-tool.sh b/tools/wrapper/ndnsec-op-tool.sh deleted file mode 100644 index 2db363dcb..000000000 --- a/tools/wrapper/ndnsec-op-tool.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!@SH@ - -`dirname "$0"`/ndnsec op-tool "$@" \ No newline at end of file diff --git a/tools/wrapper/ndnsec-operator-tool.sh b/tools/wrapper/ndnsec-operator-tool.sh deleted file mode 100644 index 503d0ea30..000000000 --- a/tools/wrapper/ndnsec-operator-tool.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!@SH@ - -#to accomodate the old command -`dirname "$0"`/ndnsec op-tool "$@" \ No newline at end of file diff --git a/tools/wrapper/ndnsec-set-acl.sh b/tools/wrapper/ndnsec-set-acl.sh deleted file mode 100644 index 5a651fd93..000000000 --- a/tools/wrapper/ndnsec-set-acl.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!@SH@ - -`dirname "$0"`/ndnsec set-acl "$@" \ No newline at end of file diff --git a/tools/wrapper/ndnsec-sig-verify.sh b/tools/wrapper/ndnsec-sig-verify.sh deleted file mode 100644 index 214fcfb19..000000000 --- a/tools/wrapper/ndnsec-sig-verify.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!@SH@ - -`dirname "$0"`/ndnsec sig-verify "$@" \ No newline at end of file diff --git a/tools/wscript b/tools/wscript index 6bbe96f20..29b853683 100644 --- a/tools/wscript +++ b/tools/wscript @@ -4,32 +4,53 @@ from waflib import Utils top = '..' -def configure(conf): - conf.find_program('sh') - def build(bld): - # List all .cpp files (whole tool should be in one .cpp) - for i in bld.path.ant_glob(['*.cpp']): - name = str(i)[:-len(".cpp")] - bld(features=['cxx', 'cxxprogram'], - target="../bin/%s" % name, - source=[i] + bld.path.ant_glob(['%s/**/*.cpp' % name]), - use='ndn-cxx' - ) - - # List all directories files (tool can has multiple .cpp in the directory) - for name in bld.path.ant_glob(['*'], dir=True, src=False, excl=['wrapper']): - bld(features=['cxx', 'cxxprogram'], - target="../bin/%s" % name, - source=bld.path.ant_glob(['%s/**/*.cpp' % name]), - use='ndn-cxx', - includes='%s' % name, - ) - - bld(features="subst", - source=bld.path.ant_glob(['wrapper/*.sh']), - target=['%s' % node.change_ext('', '.sh') - for node in bld.path.ant_glob(['wrapper/*.sh'])], - install_path="${BINDIR}", - chmod=Utils.O755, - ) + # Single object tools: + # tools/example-tool.cpp is a self-contained tool with a main() function + # and is built as build/bin/example-tool. + # These tools cannot be unit-tested. + for tool in bld.path.ant_glob('*.cpp'): + name = tool.change_ext('').path_from(bld.path.get_bld()) + bld.program(name='tool-%s' % name, + target='../bin/%s' % name, + source=[tool], + use='ndn-cxx') + + # Sub-directory tools: + # tools/example-tool/**/*.cpp is compiled and linked into build/bin/example-tool. + # tools/example-tool/main.cpp must exist and must contain the main() function. + # All other objects are collected into 'tools-objects' and can be unit-tested. + testableObjects = [] + for subdir in bld.path.ant_glob('*', dir=True, src=False): + mainFile = subdir.find_node('main.cpp') + if mainFile is None: + continue # not a C++ tool + + name = subdir.path_from(bld.path) + srcFiles = subdir.ant_glob('**/*.cpp', excl=['main.cpp']) + srcObjects = '' + if srcFiles: + srcObjects = 'tool-%s-objects' % name + bld.objects(target=srcObjects, + source=srcFiles, + use='ndn-cxx') + testableObjects.append(srcObjects) + + bld.program(name='tool-%s' % name, + target='../bin/%s' % name, + source=[mainFile], + use='ndn-cxx ' + srcObjects) + + bld.objects(target='tools-objects', + source=[], + use=testableObjects) + + # Tool wrappers + wrapperFiles = bld.path.ant_glob('wrapper/*.sh') + bld(name='tool-wrappers', + features='subst', + source=wrapperFiles, + target=['../bin/%s' % node.change_ext('', '.sh').path_from(bld.path.find_dir('wrapper').get_bld()) + for node in wrapperFiles], + install_path='${BINDIR}', + chmod=Utils.O755) diff --git a/waf b/waf old mode 100755 new mode 100644 index aa0aed10f..20e97337c --- a/waf +++ b/waf @@ -1,7 +1,7 @@ #!/usr/bin/env python -# encoding: ISO8859-1 -# Thomas Nagy, 2005-2015 - +# encoding: latin-1 +# Thomas Nagy, 2005-2018 +# """ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -32,12 +32,12 @@ POSSIBILITY OF SUCH DAMAGE. import os, sys, inspect -VERSION="1.8.9" -REVISION="849024857bd41c3cf8e87dc01ecf79b0" -GIT="2b3bb0af33c07b93a72803a332ea8286427006bc" +VERSION="2.0.14" +REVISION="a8a9afc5d151494252697f8fa4ba3fbc" +GIT="353ffefa21e6f8795469d118d8059aa16ef49109" INSTALL='' -C1='#-' -C2='#*' +C1='#.' +C2='#+' C3='#&' cwd = os.getcwd() join = os.path.join @@ -165,5 +165,5 @@ if __name__ == '__main__': Scripting.waf_entry_point(cwd, VERSION, wafdir) #==> -#BZh91AY&SY*AD #&"D H8a<8#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&DeX2MҎm5͛gش>U/+gGm#-)tRǵPp%Gn]czv{]WUӥWo]sosvGws'vΎ;gא#&#&#-#&#&#&>&#-h#&>έ#&.w7^=;GCwz]#&(kAAхDI#-ݺEh(@(%!]"ӺN}muycjr; -R_wlQ^z[7x5{f[#.ϭ>Ko}>#&o<#&#&(kA{2#*#&hzEGM{xҀQ@#-B=@۴i^SÓ]<;}hM ]:}pޚ6{W:tvw|5#&}}^t+4az#&A8a㾼U=kwwzi{{tmԻ7wQmϦ̼wkP]\zdtNC݊诂^AD)j3{N}kݾKmO/=݇K{tzۧ5#*^5w;:#-y*%(6]*eWsh#&sA'Sy۵^hY8nJ#&o;@Gۭc/=}ǜ]O=ݹ{ڧC ޴׻ɏwyn6}>g>U[{ϣ)#-Zsxdo{{]ܾ3_aKo,4 j>hr8WgP]ti{^qzvϽ#&Q+V#*sힼۮ#*}Ϟν.{}r/_#*wf]w6[=}ϫfuѠR:4Mwo^3T}.[F#&h"+#&;luJHiײgyro}q2X4={XvΘicƜy>w+_ZcΟ0L?HY$社@V"d)ݘ]DE53`cm'_(|zfn"Y$% u:'h^JjCfPK{_jZGc)>w;]YNO Уb~vNe/qۆٌCc}W}?@Dc#2O 2&Rڐm1œdC ueP < %|<ٻc5?Y/(yHl5ymϱDҙvA ULiR_49k[JZ(mЂ3_$#-αڈgNd%8.R#=~\ 5q^khLVie1o] :I6CS;ds#&J>&^|jdPCr+eoNْh'ɕMW<]Wg[E0̦˯p}u;yQ7T::C~p[$]cdfU߳-ZKp4-#[Pv;"$iy-ظca42tCL)TݸA{]>,6HOȺllQ\+<U0Mo7Dc}#*޻'[HǦXD#-{<$@J#kctdj0]JptQ?tV튅coD0oTa-v2&p\BqOdnVH!4]F/_tWa0#v|mbG>{]GeSQШ}a.^sM}ݺƂl,堿!D5_Fiՠ$EOQu` @h: hYt=m<}/\5xҾ?97F0lş.Zcꉞ/ŦT((^-caJOb{5iōIICFBa4#&R>>{i{@##|Sb:~?8iȔ@WP,C55T<[_ƪ.@43Cț ^\=4MTo-"+LGV{#-Gpۦi7mQp'!f;?͠|>z<& e${t58سh=fy9ó#-~uWTo4mG2QSDU쐥ǶzV"Ȫ:&ALg(9*0EႱ\cz:mĘ[&.@ Ae!OY m뭸GHvI/kR.'6D1K-u!̔/=FNj!,μ0%/cg[f邧}yQW3]\y!Pĭ:y:ۃY3 L4*Z`Qn&\ȯ[X6g:2}tnЯgǫYFyTĵVΨ6#*ƹѼr0cE(ϝa,Dd|PǍԙ-W*Ys^ &f|7*s[Nefݘ_*tvU_>ikgihWhhMhsMdpp!lGᙡ#-6Q|!Υ' osSۋ2j&dQ!#*z#I5࠱z#-Vpw8뱂>kSR)V_5B+-vwP֑_wOi@,4?[zf[2J ޡV䒌ɾJkRZC%/,zQ?3)LGD~LvD}E IKk H-c^hQHxÅ&},hAփ|:׹ʺDVm37a0XpI=td/V.|J?J4 YQj<>Q܁8Ӭq2%'/e!*U5oKveN3]HB**e=IKqɼԱ#-仯\H5C*7֡ *EwWq@҅GWa\" CBjwCLO/-t%jm3>1ovp䊿bTXyoYxDEoU}A|Kғ+Egt@RTE;x:"CxfӷM5X;g7_#-捘(GPZBMKϹS Adif-#-+T^h<%VglD8x`?a[V@SN"^r*޳]FÍxjRމjQ5F0ߛsbMd/ݱ Sz%ET)rNNU#)v9M,Piuv]*,#-vjGGտGnMiZ<#&tM$?7AUv={M7''.TOrnOȩ-XdJ7m>I$ 4EX@6&עm2~- @lY8(h`tsˎ ;6}Pb.o31.dS3gdj^o1CǦ0>>һJB\>I(t7P*ۖiUZcWh941f ppu|2jI4WRR[48yb&c/T+۲ L'o 6zs/M!#-Й ގ}Pa]Z)y[ \"172/y|`G !\!E[lO]n1OPr)OP߫ݦVGѢN1o$ d5vEYr.#*#*ft:1AEY2HyƧ1o>3}e2ՔS}']AP"é9ruMMTbo3W#-#*ys&;OEVBJ#*bI 0&WE-5٣(Ct،fwetp_̮#LChZqӞq^HQٗi)HϿHzJHW|Ϯ#*-|b]]ɿ.xJqR ';ɭ=h4jwH7nAL`ϜU1>릡ϯ{lVlnؾV\~dSli>S&0?+xMi(svGMǝӘ1=XYCBT8@]!9 #-<5i8zSr߿Fg􍏆WNpovM#*b2#-{헪&tY=FyQίs;"_d5py+RUnrd'FJe#*L3w_kBl/gn*[6?zR#&˵47OljNC;< 8R0Tx2^_R9>ZaNqãsKA+~MEyfw tՖNe Ì1-w8?}zbe};QLk"|PI<:4Z3OOį0Nk:wGT"gbg4BM~O&ab7guM\v[2g$M( 0=[a{}=$yl-;Vo (i&n\L [ 5r"Z.S;4vsQ#*lDɤ67`1Bv:MI}qq3u/XݯfȈ H1X} MJƧ)_&f`6 0ۜ`6^$ѲFcWrBU1uJaZ+IpImPcif@ zCe,۴3ϭilkюt8w%:鴒3/OŗzԺSD΢1UPgqϯ8ilLHR6$MI`q8@zo.s l`+dbݩ^;Sz.ަR_GM۵;wgpзn>w.x港>-cht<)(ͽwڌ{3C.\L#-*<1#&cr-̛%lXr,#-*j/>bWkw"P]V8w>MXjj;bHZQZIH#-Ek|oA3Z5\_vpi#* 04QcVj)V14{做&]j($eJy.a<ιvmذȫCa6jS5]ӄ?cy(pp]Ä75kl"1Wٍ٪dGA6m-լy2uANk"."b Q@30zqhm1֩GW[֌atɝsM\Ѳ/)8E7lVHvgjO]u+gdק{pTF fq5dhpј^4,hL_#&#-[U8I&bBf7##*Eh@(BqB0U @HZ*ۂKE UXVKC#ۚ'jîq M^Z*-͍f#-2aBˁBѨ@:PKUdjZM tZK;!#&iVڥsY-R$)ج鈋ފ%_.AVecnAh;qkyL{uUu$5B1ݎ YTLOF9"pc63}Yvʾ/@0$lbƑFF(FE4^,ʳ=Y7YѪKUn] *@bÜD%t3~UX'#-#*FrدU8Y#-zTzuU5By$.ja$=:H=Tf#*AiS0hroWl672;ff`#*dH|[` #*f R-%6ipJCoI(}OS916q(">uDC rʃ,`Kg{yZ5yg!z\l!GE$tH)-F7>^t*%iiJv 桉ibܕ`=aө؞jQ]#&T(PRJ @)Zm+MTDl"m&$dL&fEadhP)r¢H4I#* I0;S@I/c3~xO:AW荿emGv\'lZ1N&$B13Uo8ÐBq4L:C>*Lv#d Ѳj[!* .kY7`(l &a( +P-(Y `$酇RżJ*i ^ ᦴȨfKX\˧lc# Qmy(t3d-Ɗ0_Gy a(",C.=ydwy96I܂`I)w|S1B0`FLom[Ɂ_kldkd\qfd$w>m1\1)"hwkKq5oᙘ?.4ޭɕi"1ED@ciqU70EB ٟv^RxQ3|e+xr'#- -x&Vي|'Y%mʝοxCϔBWi.ףq6+- ~GXEowڌ涹ksZ6ܵmLu=m0")vE.;`X&.>9= #Ĥ_J3NQjAOff#*Lz| sP}M{q%r0vz+cZ:f.g#Y}V5Xm%bͤy-;ݳ;tCz,uf+y_ϰdꌻ2S״`WrcSΎ&e~gF(%>**OW ;ADx{rybTZNA(8#&ۏݜ$au1q\,KH'N'>~Qy9oɣ9e5[&3D6-H:'_qmtaZbe$ :rٝ/a;/WKwAh_0T#-n߿Oyo||z|oљ5a;WB(H6F"Q ]jH=<}n!dF&7'&p.tS*BҒb &wbO]z5tm,^FVDaG`īPL*XDAi#*7w( dPqg_H;RH#%_zff#-Y`@%||v81=#xk9Pnb-I(3$%Bb3vL%+1!*X'14_{sbt;a3A$&|vð['nzMve-SZi My+~>71wuEIl'1QH#*:sE [' $FDgӇ?;QwhDtDƠ\Rkz#mƿW_2V6DFE#*L=aK#-!".lC ɐBD'~l~DU[LR 2KeTw>$"?ě1閰VPā! ,dQ{VLeSb׹?tm,k6N?j?u$zW$bB#*=`Ķ}np<(ws8L/>.WGv,#I@TFdp:R*(t^d3芘R=e-<矻Ѿh|<>U;WxZ=>:>I_w9u/g2>V>_9 [ >ϟ/˞9U8Bosㅷ_uQ`VH7(9+o3bAKN4m!?dWnzgxYjX$Ƨv}0e2C#-;z7k[J4aA#*B^0Oؚj~+B}l;VZ\\-ywV@n:y4foty1Az~cJ {IKRCt4S4H1q-=^VjKB0MU;j+Xɯv@Yr#v#*i@Nع.7[5Vzb;L2zb>_'>1oMI#"c׸8Ԛ6$֏D=jHۤ$!&B/jC}6IC$R>')ʓE#*TB=$jĝ^oYeQǜ#-!)b40 ij~.c@!bBpVm.g@"]zv5$[ylv4$ʸc\*^fnBKS<㙞X̏e(`J7g,׃all$#&0|2a I6!DbR+'Կѩxng-yo}(>;9[թw7>m+:\Yd[F~:\Wh#*vKaYs<5qnrKUg5^U^dvw46_֙j.%^{zvm割XثW]GG]U9ƭ\uX9lvLm,Uz( tUCiOD.mkܴFݼӤ#-A>+cmZu_ӾM#qwV?2wΏ-[t<C;{o志M+9oꣵLEz9BZ|473S[kc|o#oI~W\&iFo}TWi\:OA s֕JP_MxQoAPc Ɲ^Ɲ{珴/7k~o')Gs4tb?>M߳F-t7`UR_y^_=:*^ʷȰթ>+q K #-.\a_b{^{hYps%5k#mm[h3|f|Ն|uks:I-A|ͷvtX~c6a,jp?'n (w B)ȓ 8#SA2- =c|~0Sqӫqv {OWqDw=Gj#dU_Sf}_е!so_mGQaݚćnG{z{MkxORWޠ_kJW}wS/1=rcϴSm~/A>jaP,Cݎ3U#*Ӳ#*Ot_ZLVZ[Eo![,˨AmOJֺ:WN:%VTS{vl2)s Qnm)hO$`iI$-$7?Y-amߣEz7{Y_fwS#*NCO媢Vgg2xSF˷u9])She;g+sF;W۫ԙ#-?7!n순YLG)c#-ېtaNhQ8BR.%4$.m.w/pŮAvEc,gaw"YG`}-Cg^l_\ᯌe'hߎJߠ:6UVlU]&P%#-@#58 L!v0+οxA}o)^]Un_/:ԎKRU/#-C{eM3\f#l_ٺ`zIo?/._쿌[S乗0n7]}F8#*ǟە{hc5G27)uHsJ\?Q`0Glr Wb*eD9kMG#*7fe̍܄E>8D<>b1PaX#ia4(*I&a J76#*tX42-`l44b,n) X$cn180,'152fx!ZY6b#*#&"?8Ld?>-#*j3,qܺ9#50D@#\@'9מE8\+$IeB,2&TJbYCQIjpyl@D`@D8<)d ,|>|s^C xY~tj=R7Tkk>WgO+x^|.#-h3)>u-N[3i8wê={GK*4(RCUNws42DdOLUIB 3%v zKCpkyjS_#* [)#Z5c Q$NViGXSd+21\ypq#Wri42X_KH65˴GƃUqVuGnb&0)H+C25Z2VbdK8<#**gW32Xx-=hg{zv6!5#*%rQeh)P5ڔ2r.pHjEIpmщx* f0С$oCs84EQPYU6s"ҁA>nadla 2N*+:`ZXuճTw3[V/q$i0 >aYHA%]gkLeN`@J1aqbA-(QcbnF7hHx< 3/y@cTґH݃MhB4QGƋʪ8>=dz)/>Cfg|r ;M@cz oIrҁH:oV/hE/N5ɧWJa CdֆF616Q#KrkI! +HXQ2Qk8*^*{*Y`i'mukfajb3&`Y)%`vo43M+fCEZU`oF?e\p;,.1u6N4iYCS . oM4pa(u#-dlZe㉗"Qe:) cOK Qؤݒ10'S=leGэ۽ێD$7z1~v8Q?)5[#*ܬ˜jLTF`&9c`E%D@xQj?.ū~9#CiX@WY^%JI*6637AA #&81VEM19٨Qp.8V> m6Ս1RL4HUJAH#*6m,k߻]J]È.#*4 Dݒ#*#-ERRksuI4y7)+L$i5mDB'#*amƘv;E 9e9#*ȉX~evdȍa3tvˇ<3ڇњp׌fD#*:}H1Z\pr8ȲaCBoX6k󝷼@IyԺBʶK)Bڪ;2d4}#-;.m[e;p6VДg0QG]Ug!$fŒ:F*)0ш?]wy-x2:2"Ss/9-a3:H#-'錙xu]ynQ`wrS..}iگm6<݇|<ƞilk#-R¯kï5o\{q3!3F0E6zjGZe˿!)j߳]a*/݋9Z,;|.wꙀd(.Y488`M˩e2fLQ`s15,pF\FvMtsV)MWs}GGUS6HQчNq0[ǠJE#-k d(G|4i%IQU_[/3}<#&qN,h:(ގ,5s*ȵ]kpPoyf"4mPPR Wv_A1#-uZȔe#-6Kҳk7z>-F0m^HO(gbXy|$t;7J#*LSOm; tqYJmrnk#*eU dpYiTrtΓ֐ܺ!=V%$ܯdn=aHtfdǗM1ɬf3ݟ_[d̻M0O!yLc̯5O眔F#y8gсv}jNP4=_J#-\.#*|WנvCޖX\ULP!p<=9I0T2L- Î΋z'u#&[>.}nY4F vbb I7A.},Zaڷ[fn7¢Zٶ/(Ui}mRyi],E<=rJbyr$ҭ0(X~F0Ym;/9|o'Wsl/6HRY!s>mc\|ljѡ}ΟTMygdnAޕ]},J©UR>}[rrXƧ#lj5Z%gq?Y9ZmwW15v6mCXT؍/3Z o/>J/usC#*f^ξMtGs툨3^Ƙx1{{>}ta]-쪪CX*\jzF3tԪH8WˏU4#?o|zvFI}!^3)c>#*<-n=6a$%䤎8~,l;`sZಛW܇ډ8TPbaF8q͗U6ӆ_cIB]6wc?秭mk8 M"mv~ȅoʍ~:Y%稆f@Dި##*WeK主\#Dc)#SVtK%[m֛m!ö3muh ,F\;65M>OtDv4Qp僐dsYqΓ׷I^.SHp<4mq+/gq\˦g/HIg7{%X+-|mRCoc#*i.(ٰK*g\134d}R$kŨD?b#*9'"6#&mL$tu;T:t-'ګӺwOUJjtpH{J#&ԣ}L8{`GC=z_W%KM,HKK-,V@yTcTwR9)Pߛ#*k0Z>&qm7سh\tyE²[PD#p٦v: 0Ć7ׯ)k Ai*|H|5"t%>V>}i*l `<#-S2[`[deįqh>DkQwLJo;dd]F&E3Sy93<Reю)L#-#gkVaЌКTw/fV0v"&'zw~6v*ҼzK|5]](]>P5_J"]Uv5FR#-8I <,Ӵw."IRmѢpjR`\su'Kk"#-Ѵ,4Yb)W/ I-} -^;#*M]sOIqs_ןG+Ϡ#zxC1{e'nuE^MXo|1L]y#*a1tsÜ65XR/~YZmX-5Eay-3XС/Ҏz&} "9Gyrfk?ﲰƦ.y^/<@1Dmm1Q~V(Xڼ[E>58()Z9.TV{39[\޵"!+[tQxKPT߲iu㾥kk"IsƛP!ky90s^˷Z EM"Բg '羳+WxTWOI;K襱ZfKnjlƽ- ~la}PѯMĬE(uJR[nh- q_KNPWHsy^xUp|<7BmD|Y)? ngpkӳvd\mΠ̓tpmmŖqsm!q] f{ֈܩ•Fcu2ƿڷ-kCޙۯ]mYVQy_wûV7,:iӺdy9ɋf‘2sacީӭc<|K ߟh.gO?i~3QG@鍽wcd߾ד7O+yqNB4;*nҍ}cƣvqmmB5HI#-Ր{]sSCcՕUg!עЇֶ&Llme'4ni"ThʧLo6_?m'A r_-¡`e;<4㡡R,Xj"bgTqb6i{:-bleQ؝tOv#--Ϲ%qM]uXןs;{gUf5g/PMuD#%Y#[{C)һ9m^S춃prB4zf">nmE#-צU">1+鄅BW0,!Î+pA#-ϟ,㘨Т6F/(${ս%4F쯮`CʜZjNuLO-a'\ẫN-F+TEsmgECWfUE pA>ʦS|v_29bpt\6#-\_qV<sۆ~)vh#-xqm1ݍ 炶Ѝ^NrGjtʀG\1te*>ܗh*ox>>~7=I_,%4B޻E1ݮcq~l ]QZEyFmMd$h!B*_HJ=_E:GQL[ĮC%3!ikh!پRMdêڴ; [Vr(4,i^n(|"{qR>⹤\S^SO{|N\hǔ[nȷ#*V|ЅVWϜ|il]V޽`8 ei!^tjw\wa⸢L6?ht MXXR\no#ωBJE&jq-eEu0WE+,vD!|>WzE%}T1!hGiCnPj%[bXdfg:#-ѲAR#-)m׾(wO΍*lzD;6YQ\o4w#*Q )xUVq$u߆zE_nl7_oW%y9Me<d9 xc=&PjtU]Uo{>r !Q4I%MANǭVwV$Bֹq̼>S;.F&Uz`kzrjO֑KyNkrIwuWl7n O׿]ё;}s3&yvʊƇ$Fa\mvs"wUN# r4K!x-8"w͍COG~Ȗ&gdC!'7UH[$XhҖH& a351.'~=-g!l#* #&9 nM %Q/X] ךҰv;(zl "Ҍc͊IڝEES"]3 IzL%]:FL]I7d>8t]c1!3d*Oey=9>nT(9β.Qj"Anyg26mIiT;=0PBs:D%muZ50v릻N712ni(cCS}G#*{k9İ]ܾxǭs;ؤ0D类NZ)/~Ɯ'K+;Ӵe,imxܜ%o0#PN1ct#-z'ۼԺ_SѦ3N&wJw ȒPA8'IE&T JwDs0ӱoBs>yvBs{lK>UAm${=P~yGU]i9.dYbf}oR?yqД\K]ʬ/D:wNI kn>a'twj"qCj̤˹lIi~50VQFDF@B#*V`s2hPN,?O3 Mpa%#-g#M K#-ھ_Uh!4|`cEU'0kkk_w].55`@Z}C'$>gv=B$hp>yE~\:8@#*p7o#;gĴի[ӾkR$i J`|Dd$*} XJ}+ga̤O7DIcԤU#&@f< CcFTx}-L9泞ͽʡnOح3JBRB %mNvya pFpc_du=M(bZIm|&دͱa!]BE&Nk6>7~H4;#*X#&AFIE92VqvbECV8aV]9qb+]+I& {'&WU9dPa-|ȍVƠMCPȴU!K:6ؼFwT>7㶖RWANT9t@QQ;'MmuJ$E(OYn-6fIh:nDyc(k] t^xщ[rOz*)z/ZhDːPq!&f24=1Fi}f iۍ)HAO Fا(\h*4ѻ`e=aQgmH6DŽɴr2ن3cjJm8lF#-Տ:uYikquY-У{F#--yu`<IJnWOp #*#*%%$h ݕZ™;rbعag3uaR%kaՙ!F !@v_e00T=/זRQ[j(oy=1ӟ~/Ӝ5g^[8**L£u)lܳYkQ4=CĒܣ}J_,mJlO 7S:M>2((:!Yݻaq4RCg;uCi{q(?Ix)qpH8X [99Mc>xeCϫזQUUP? DHR#/9yoDݫ樐m\SL.{v:]Im $ךkNDX&,vAnW:,$U'D%q囐kb}">żA#-n_W`75#$6Hgq.qE,َDTLD,& o9c#-םڄTȁ v>Cpssl.z #*%>] M[?\#&*ί?< eE ?ʫOm4"wqȖx/#*K .${M\=*橄.Qm#*?VeM7bxم_R=rOpFe{!$%>} $򺖤G'FT aQ\YY֧#L^v'rgCh r嵗ي_axuLKPX(V n;.)rjY'atwd~rEsR<#*c`<*!]D\ըP7(ˢk\S#*"ޅCvN:UZHgM097٭GWY5Ϲ?a۱_#-5GSg#*3bK`L#*ZX( dH "H1X"s8ֈTT1AJ*gfźŹh;ݲ7k+fdA8!PXP"l/"Zn5X#&gnjMk~$N'> g=bMuR,PԈ&6YPp 9Q6 WvfW-]xE]Ţv氁x#煽װ/t5#-C9 ҩ&bv>/w/]w-~N:*ʵAg͉d ݛ!ۦy6Yndąiמ+1Oiig#F8vx#*޼vf1#* 1thiP1|$]Afa&u+8&7tCW3 q6Tśh"Zaq Qbci~gÕg}'#&ja 6N{nMkb\'qԹHB)- -ꤳiLj+ ubaةERC¦#*#&@{\ZNj[Ŭ rN-3nQ2LdjDCen:QȖEbu\ܺpCۗ N-bMCskiDH _)jj~O@7뤛&`8g].T3[gXo 'ן[|'O=#9# Gb(1F=DX}`i+ g#?w:gq;xE.=TUP;ԃɺ2}#-k݉N-OJYy}[`"IGXBi(n☹4A[#&Ą nM`LeUC?\K}%[WvCHT$#**iE[r7~' PXk1tY }+gΞ[E[{uL9T\/SdWsh?X$ᬅ{q,+??I_YQGɋ,̅ P:z52ȏlv&~ߗ{CaGP#-uTx?##&ZPM,ãhX7Ƿ\\Wԟii#-~Zss >ix)yx,6hٲ csi.L:o܇G+Gfs{\9O1z=B#&&~|H8,nAd|0 Ciiҫqsjtov6D7O^tkzx?%ۮ+feޛkLff< WZEqwٮCv)o%̀֒P?h0y(B= rwq&3a)(ʿ gE$v{zʩj[~qD"I#&Dո9Ihu yw: Hcظݱ;76]}y{^#gIQ#(9οVϋG-Mx6.߳R%~6;i 3n#*lLLT>#)@D]~0gUnᄪJ3cǰ-yg#&qdL407qNا ֲ mc oHcy:f`$AI/cG^>A!,G٩mlgeu"rtxK\_+H8(kz/ʬO-nUPM٠>pq?v6#-?Nyퟙ/Ea}bBHf >.6s#*X3yc?9o0 NRe0btƖȌ𝨠]WUNJ nߘxw[`wzO^j89ٳKs6'C37o#-j:՝1!r,+3?|yW#-}n\*99׷(iIN}tw?QC$"Hrٗ2ꁋ0_/"?[Q 3&00#&ԆyNESd"b/U]0tkF0mE=eeW;w2(^1uϸ&}׬YUz9v˚ `aljxLg@D{(GT ?|tۺah|#Kp=q|c׿D̐HԔ$`2o\p{E>o.␯wFig*#*S@E 7%oa3]-c? 4"Z`2HQ_WaV5,*{ZiLOqPҋJ[Y)N-T*a$-Qs7rxm|`smorz#Phcy:UT`_(EM,m{uVg3U일CB  z&`z=Vkܒ0iQKz}XhKF4TP"!LgoZ_aiAS9'á>θzΠGaGNVOtK&:Psrkg!5!jZJ=l'5or8o0I-fEB,⭂%e"7,=|7.9}\Oxe<>ix4!LjA[5MA!bt98Zkp3*a8z1[>/ OTD-m=Ojc.wxt}yo82CF11JӯlS!5oU;7HHF3Q^^[Ŀ8xgw{pc'WJss债%g$v\Qdt,YuNAO\w{r*<*.XtM}8Mm %݋=gX0S:@xGQlʾ ѷOix< `zƢ"3!EyJWȟQLiЅ֘_U߇ I#-5ALIG_\~;Ix5s'}˗v'l3~:~R~͗w1>KA;n_N%Nh;ʼn9p#<ࣤ;%.g˺<#*>g|&zf~J=1vi"Wl++fʎS*}vbLL@?)7dc9;#-1Vc:Iz~E/W]7gD''ۇA4gYqⰝAKu(tpV&rIGyE,9o4B%tuwu=x5= wYf9#qͫij1(%ˋcȧ^OR{fvt_כmhIp.m>]uF~[\VU4h~}6s[G:+!rMlhvM2uĵyGpS _.Ч?|1nXsUO\NOd` C dLߢG`K$C4 ~#*:~Ff58'ApBk؇Yݭ?kli>_ ?|O!Vgcy<wYMQHt8ICXR-^~u*sEZ&l v#!0Lf!1\4F،Q7TLJ 45_z7(ҙ?OO.5|uJGOQ@ӿ[UV<>LWpș826?Ãs'Bbxk7;:na2{z"QWyl=p!EfS!dlfdjDWIa|Dx/v϶>xAmvEG]5:4wƬDu"nřMoZkeI Lw`"`ײV#&DEpޏ.6[#*H:s5Ibۄ#*@L98$|~}m^ͿG3^36#g!.N6&rGD#l>Ȍ Pt#-\U&}f@+"%ϭpjNÔfu9"0ws$rI,Iʳ{NLmn#-z-WYxZR@4V}Y uk9IãlkT{*Cm\y\k'd*2R6Grf \\]7?J?Kިy#-M3ٻro^H<}S?'BI+j%6Gf2鮕3ŗ?PFx:GD>k29mzc8`c,dfѕb5,nIӅ*gǞpc*+MӄգetBt?X*_dVF^67ysCR>,35Wh#-ii2*+ΘB>9 MoUJ*^Hv|.#-nE ң /6LIݱ]i#*[_O4&d[J2=9\eV,,Y95i@~nUQMQ-0RDXz00ile#-#--,^)j4hVũU#-{n׍z,9#f >ԛK۽_;O+]t;pkMkHio׎-ir+Tg:{u7Gs%is*Rϟ14i|s*VVFc$="&x2'V#*M0V߱~aRR*njt|)[~;xDqxw1,q#-[uƉ n_ͱգl0In2cs#-Mc>n. Eh9%{N½Ha-8lfXɚ (o_Zg_x۰ssa5m2Kj(V東KsLP]/1!9-:[̼%6ΪR*|!%HPI;QFb3u]f-G]wª8]ِĦlÒ^ iUnjj ,un{ltӠ2Ruu1%W靰PꞂY_#l7\dQř,'Y^sϤZn8#*&BV1'LtJ؅1ao<+v瞴59p8HdC`&[p/[;9kqlR6KC~~Rva3s<7bSh,:FMИU @2E}[҈=ǣ3C!砳{].RcZNJ77EczO9,:zv nG}#VBhFWe7-7vnt?ಭ>q"&2}H-L+_2onα>P۹0^A<)(QOP0 U10E~ZVXInVW4e^F;4f)KYS9{DT-kPE4Uj[j\[µEtNUt٦,ɹa}&la1kD _2c;!AÍ̬\{ON!`AUTyao3D1:=v;[w#&j_y'V%7?f-H:@1@'Y40F6HH:CIЗׁsSlu u*J-`}j#&Bux^үA/ïř"B5AZh# `3X>oe #-ʂ%aD7Ƹ6:mW,:lk=%,B?E$]#E7ui>2S]+ZfQE˯'7@ $7{̌Txtܝ"oFk]t <6L/8LrPb*e?m>: (8cD#*_.EA:|[7ndA!4O)*4vAT]?|nfӚUHo% (B( ,g6y;ԏIgW:r,cITT5)\ҟݽ$,+0nI!a4%~Ovka݌Y׼?VF{^4#*xo7LE^AbTBcQ!6aY>rw!5 ?s?LJ"(2,WZ2f.l9 7R^Kݼ?GWd t.:QІߴ>>B%RBS jn7d029!w#&n2^APŠjђ+LRω&.5p}Q[۞',)"$@4EؠU0N%fjG#s{NdVYH6/MbCGY,]L1a]H@C?yѵ&D ?\C CdFCc5Q#-4Ɔ$$u1,f4-/bZ'Цe SYFkjFten*[=2i!$*#-oFsc?v@{yflj<|2N4-8R|J6.GJ*Ƣbd#-*օI,]>|'s"H#&h/٘,X1?vnvxǩlkW/U?AHÃ5UUnTW a\ٻS ]04#-A#- X8QvBEKxl(}Wȶ3BCa!^2U& JhM馉}y$pwyyWy>s:I;BJj1#-:FFƻ ne[ZS=O")꾁݊OFBd?PPF Y9p~O}9#*ؑ#*W:H5"$R~s<~Vo$;&Q"}NuV8`Т#LxCt̞#&a$=c#-,v}Dc5 Hqݹ~} \ÉHP-}Q8y}'A< P$R$,b08v7 p9XMw]-:(,C#&?Yqmp>oʡF|> \49b$ Yϝxd/Me>=o`Y#-Cȡ>%'C?I F@-DHXǠ$xl{<ƜûO6U9oطCmޟCz1D"#*&A&&kFb#&q^)'{F<6+Q  ȦTMDo|#-E!{u̳֧Ktx"ȡoJ #*#*`fzLad109#&tGV=#&vx^?k>P&zmuox??r)apY7 bBI)CҡT \%M#@H  >f9Il,ڎԟmAIrtofRD_X*o>|D:]'H#-ҷ̈ ]iUXt?$'#&;,yW< Ij:wr=8kn0Z2#*;f2c- mvPeWaD㳩BC+=ߌbf#TLH`%XX3zhv=F! DO D>=BHzc#-#"H]қZI$j6y }zD|@3pv:Ox~)`9čR>>ߛfEN~ަo bI#* miy#*r 1ӍfD6R%# γZkVˠܖ=ǃF"fTwbnnD-W1W0QMz5N0H@@ I F!1?:ϗptSs2bM!GĎ?UrCK]OB#&#&?D=v ԋ!P†@+#! (D6&gϒA:&!R;B?r&l8|3#-AoU(ae:[~1)L}J#-$#&';?$ C5Rd*{~@%|B<CT4gߢ;J#*h]эœU]W-{m^o.Hd:54B@}#-XZOni8$~anT.SLS@͋#*Z-.aw#*H9nx~@NUNPq -ژ!#ͧ~b7@4{kwuq {Vzu=<ۆ#{%-kΛ)1n14`0!V}[^n5!yLh&i# $mݟAh85ֆ0!)ָԘ Y._ !EJ'DžQhSfbpNʓLiSWi# ]AeB'#-OW/&IFzNnWz$&#܍9|ʆf!\q<[#-Ĭ^;i"( ~hT#-=,S*Fx/? ~ hc ޜRA@ƤO2%C~3:y]Uޙ RC(F҅?ǣyW<:Z-bEJ AIZr-tK?uB|BB,DNp1P~@x#*C"#i4`#-@#&yѢ7k#&Qo]HLL)H@tM "eLM@#bო,gZ%u^ޤºQUdh?Xv\y@1K I2m&[LƸd:yxu4/N0lWզH܉#-(]arWߞ1%:4YQD!.bi\&]S4k9 ;/Fœvrmߩs(yJi47V NrniO#&7u6/YIv+[8 r*B%jw.#*`v!MS i!)|w/َSҤc ԭ4xs7e4uyEfw/3q$#&b%vC|] ql#*#*|IĆZ*stFA(6lxT(O6w≜8̄>C(@}S o0QKp>)bbls@ȧP&e&bc㳂=:PHySƽZjޛ$ vv9i9$7l*;';LG+?ggX\pb~Caݐx1mھ&|71|kز/rQb+-5BӻSXh78Ba-5#0Hu%'>^:Iڠ&\ B1B'>@#*zjgPd(PkzNT>ɫa'u99_ϐp7Vy&K`xNߚC nbN#*!@{NB9`}g0Z,B {SB-j^k>k{lɡCxғ8y-I4w1YƲ\b?7CV2e > / $maI#&X#-1oy1zצy""^EWgԎs  1vcߦ /h!X ;=uK #&m3b}#&#o@>w:xX@$>x51`Vϯ]Qyv#uJo#-L{ ]Ky7#&&]_u4`0^[&\v]fxF:(Ooz3P&˫DX#B4FF6l?SD6(F'?ieĊ(8Т(E@8D˫=V$V{oAFB<_}!*ХGjoA=u ɴ"e^6ޕorX͑}qto:C?{#BG#f3RaL.]$R@~}!5bŗI?Yj[z bʍffgog `Ó#-$pH{wJs.M̨?+/>Odb {eZgq!-z] Uwߨz(t#*ࠐ&}*i\ݠF#*˟)j2ܖo5Ls;̤1[J~DjЖȰӓS=@b*!q^?zBO\ʁL4fC#&!#%H-ʨË狼0֯nT427xQȫ;{OtR #-Fd?#L{4yc~E^e5hQP3.L`&j!% +DFd(;xI3dyb9PƲo39D#*\VO,ٴlWZ1#-1#Du`䑣:*;0pj8cY=ݮ;l\ NHן${p<Fߑ}ɌF#&!vئ'#*N`H)#-R"u!hR0#8S(Vi 797^Eb)Շ:fMO[ckW?->;iG9*vWKmQ=w"cxg,. ISj"v[)3$AhlTkT[O+ en݂b wWJo9.25JNX,R8JKX_,A$JL1^HI*-a̘rm!rY~˜5'l5LԪ2*Err2'oi7~9EеϢS`"㑭ك1l8^Uq`.j+O3y,̷(tK^Fx<_D"TyWʦH(DpȾckSΊⵞM?=cm%SP7 W=[9;~rMn|lAR7+hb-hot۾v~/2!GU|goo"d\@E1R`2Ct4kΕ,ۯ1څy;:Zlâ>k)tS 3XM]u֡7LTO2ވsIys"Qq|cNj&gm&lwz[&u˹X9F;3pd,_(o4Ԛ%ELхX" '.4i^[W!r(.NK {<5lZ:+U/T51>G)+ќh[G6LY[#5K3VzN5 G]!<[Mb⎜Ulmn]>tNwPI_X}k?a7uUK߃ߓˎXˉ8BMǕ#Z<ɥt4* &+5‘rgIzS4k|I3s>n<3|ia:8cOc!CĈ9WgCw\m9!Y_wKop&q~31Va t<@kV8d[#*9 !H2.,mZH8]v{-<=åi>!סb:]h0hAi8e8 #&\"C b_ \(SB*#-qAnU;!p [;hQ;1A0!9iQŬwb|T Om)u#&x X.$Z]hzh!gy\.GEBtiMgdZw[t1;a|Jmqϑ&%ʉT%E.{~Kiea$BdWQÙ\#*0:BWZ$?Oov@.Xk 14L.^p١@?w@I)&w|54! pAă:7H?kro|tS3'v#-UU[G h8Ƶ~L* tw3SBHl ;t0ox$b0j<\xvɽCx='ɣ &#*5k=pq'rHd#* w Ck'#*0d;1&#}Ao|À=DR`QA["\f?q7W#&Xe@N0{|o p#B˅JP.EKSysx(>f''>wʆ񉃷#rBcÚe'ͱ-`τSMTO(xG]6d>{HvݨShG̗!jfA(Z`y#-K3_#&JƔq&B[f G򱵕uтtOkJBUikG#*|'Tl\ݟk2VC' #&I#-#-2<C&Iis,hJ69#*C[#-^I VBG!꽘bK׊BEZv 8Fr#*54b82$OuAVz#*0ox!QY8Zy#-+.J#&F QD?jLccmޡ!OgyeLnmk5d-hOo5ì9#-#*NTef-ΰk;&~?v T?!bJ_!7#&9/J\⸛$:#*xLFPM;[9hQBTcs#-7%Qȉ=>W#*I"q#*ѹew.f@ Mf@t8 I7z$H8riQ?yw:0&^ꆖ$9^10X66b;&gq'G`b9=b#*#*ɰ&uқdPH့7aDTj&ޠypc2D%lIyOnFc"[uqGoXD#-d67#e|jT۔K'59Ќ`qh=(F#-,#,=#*S";v.̻bm"ÉynnC?ԾVsușX(*eN-PP:zÆrLO^*f DDJy32s33,mrYs12%ߡѪf{ eBbX, @a쑰.9fo{8eB2xvYqoB<ꄯjhia2(w~6}=m"tmlݡ4ΰL.:jeb*FXC$G+l>v{5f`Vgt7ƏM{))q(.Ι)ys˪jȲ22\kz#&#&nR'bBh,.00Uݩu0OFLe2Tn73?`=~ !`EG7 6ԐiXNF‘x1kj 5D]v$bWWXÎGjxr.8427`H6Ͱ(#- =9#`g,$fw<S_BV[MRf;ٽI C2,9'3%A\s9ӷNB涙X,@]Z)du ;|+~"VEK%UjqsX*2vy`fQ11FId<ԇFD( xJCOh#-(.!`>Sǂ|{F~ϖPS;}tAF^UYf1BY=JHm=#*)#& 3!2,e&wBk)6R[<9ppFjQߣ\h-9p#-*Bevr`$ި߂HbPT#&!<^+Xu@vr!/̂p h/1Lz$!3~#&Th;>#- `"5&@2S2ZTPkbμf-EEJЊ( 닄ҾTb& X,bd&0z(<{bô$eJ|}@^`1Wft>j|- 8fvp(%p}wg>f#-*G[<H@d@$ n!#&:#&AaTc#&FQ`#&N#&C;`LDTFZ(B՚WueKRr2;)@`E-ADhxԏR&k%:Ƹ=黮1.Sy]u܇^dgYHBAqF6#-^^m__^H}N``Ԗ\{̊թ2{:a`Ƥ8J:6n=PĶ{>'~nI(0^wiQ4UFm350R4q[\~恽pAAS8p@h$c"Sgi@skKu*#-#&sv\&fB_#*yV#*F>2 d3B;ۑذ(03"(qD1sԏ0Dg֪JD 0wY#*lu,660#&{(-V{a .~sO?i~KPS.tZW#-~ï4h<}ᇢR#}z~T(E'WgYGX =R>!FaF/Hٙ !ziQ*q#-jQuJ,'IחYmar~ƗU{OKi.ke,P-;N,eTJ$hdTx@i = h-QR-6Zd)JKm#*)5ZkZ߯}z8όo*Np^@Q" !Gp18D^4-c#*"4J5VX^˽@AYH6!rbut2&)آBf4#&zqa"D 0h!_0dw4&j{aQ#&P늛^QZzFtPd[JM/H=^)@J#-B)pD #&.ďrrP#*1Y2ӖLۖJҙѶ< EB(2~*I;93Pއ&#-d#&bA}/mmޓًr7Ha&xթa=OTz2 !|oo?9!\IDI / )2›X-q"ץPuR!E0*,E|Cjc7dѠRI,aK@ C劶ݐ]CPNE?SOHpC|ʳǰND47v "4׭u iEK67tt| ;w@n(X< v!~HJI!]Wp#!ڿѹ[{~8xE\T엝sfZ lF!D #*p<Dzy<.9>N,v2\] z_޾,f'LD7#&/4aLTjư _iECnbÏLF#-BR&Ќi8zǧ4Py8ey%n2T Bf^ ,$xE$U@WRTT<#&T;h+`{O\EϢU~_'|`+ aS*coөQHzQPIQ@ d #-EQ\lclteHp G4\:6ǼW)``9#&Y!^qIUoh_wf?.xDݗㄛF}p%Yi<.lнL)|Ų4l8cc |IYw*7{|.7ƍ?b`ٺ_Di\tLA޵曎sn; /g6!D0&8/}{:.1k:gfG^ں-Sd癌j M&xe,ʫVW48ϵƺ.έyz-xeٜ|<{ =/1XcMmU 1PgX*jpÆ #*`ўV'a{C#&l0\Z+ )[b.Rd̯$#*iP郌Fŀ¶FuvUPq,I4A vl ez6W165ÒzaAc$8tp;J$`ܧ%U4،"2D1Fs+`TRzAݷ`Ȉ0H!~{}xU5/DĐak&V7[g ,nFcAahftRQ(#*$TZS!4SR7őBPv5B,ٚmN)NLzRD5嗫y`|d :xs^#-Cz(#&klo5sYJM]5;ԳDի5g7]ZF]y"as)ȋ哓 ]øߋ%@l+[tvp4AX("#&N]C#*|hj߁pxtkkqZͷ~[/%1fdWK |7|,"M"$PJ8 oL|IO֨#-#&My%!ێA[r-QjNtQ#&#-8m5X) tHnnhW4$GSD%S?Œv>)ARY#*V+]7#*ͪz~p+c$q:%%j$:BzJ6gLIÚ'=c~νȘ5JK9PNsqMB{r %q #-d)#->KR8k|@9w.p.Nr\)L dJ#-, 5r7*6(IB< d e+gƋ3ء/&VDzJQE4΢Ab$(7(Pd#-(@ŘûY!"8(@(߀EºN ( mst%#*$#&mhi52HMzʃqz_q6'v8),|abG^VD*.5bL=ar"wi#{Z+xJ)ڄ:OcWK+B'#t8HP#DI[G.Óhb6P#* ^pC EvPSPo#*GZ!#*(B"]H$@t*V|gB4`+>O,ZmZ%%{}v@JAuvzLQ9$ U}S#-0J#*63$̖blZL+iC$Qҡ )3J#_>12VF)k,(FZMXaH)%%Fddbe-d&Yɤd)HeP,X3ځju;#&4L|B0Bm |DOYݘ{ّ Ө5F|#*#V߫f  L݉`&́.4TO>ʒɿ#-7z9K^ZU84iO㖽,VN${BM#&ʉShl1#-n .b#&#&s1 "`%"i-i*#*21b"Q[x|1 Qq;/XǸרk47x.M"W `,T#*4)!#-e"AОrC]=ί6|c\M-z,m}:͛:dMs F0%Do2#*hN#f]_VW,ޜ\.F$zXfqMލfLRL"Lt ϝ-!3Naj{u[KA$ 2v(j.**e;hjV3~+#& $SxV͸ wqfm$Ś8fެ#{wR@ڏ:;r=SOYƎIg=mXS1#*{ {Fa7 XI~"hi#-=0j6R~=zoӼf -0#*o;F|B3tRtՎgD:>nVFׅY- #&t931w"(ztڛG#*NTWC,!ZO."+'Uwv{nULY+"O4R6Q/B jOGxk6čtRDSF^zU2KaїO4u).]41-)lR+ҔhDZoKK'fhztI~$Ľ&<2Xff3F_L:#-.N1pg&Q L.ij<"QCNk߉1.Ls/5 Q{3d/t#*Q' CVu"yj=uԛ~lne*$y#tk H4In#-#>%Ѣ0!\M#*4=Vj#*(l1 eHihwQm#.ř*G{W@!Ѭ$|^te:SGN;t缺BZ#* $$(12YJ8D@B $i4ָP#-}X5&FX#- +pݴ?)Щ-HHR,% с%3n̅8nHL(JpSxqw%?Q)Cl|GFae6{) #*F )8a,`(NFMR9FDf HurXdY]x:(wo)8f7B&ҥ$,4Ȥ!l B#*3 K xfտ!,_ G20 ;LnѬ50P1TԠp=F9I$)ۖD6:+TTIv](;.44 7niršlT26$˕J%#&?, #-k#&MKD#*#-ZP@k0m_usL֌!>p Rv"#PPtHWA D#*"J64l--$YP.i({iχ31]jtt9"_S}qs=nmihvbjn*Y-8̚gLcz]ۮ.9+QBD+^G@G^H%'6تqaD)B\% 8岑Q[4JrվĖ&)*5c1#&h4xynQt$`iJ@#ܹ,Kf%E2^(!".# GAuY N#&0H e~,R%j~rGZ-J+&ɲM{AT HWQzvH^*oӕy\HB$!3=*hYPU WV'R)mFƴRRz몂Iƶ2ݶilK6bS,S&QXa%2mYSjISj(kRqEMWwMYֻWbF2LJQ[dJZW䊦i&+cRklJy^i2K(ٵk-UҦut4rjx.Yi16%[1Y[S y^_%;pg^7ʒ1Y_+K"x/اψ}4ݚL&-kc!:}lXF!ȅ`o=(Se"#!/4hWLTM4Ze1m)*<>m^mn˲Kru^SjQ\J8P d PM(o oikZ[51KIIjiB5+e6զ٦VViM-(UJ؛B)L%6$J6S2)Q%E6ڤ֔,M-K4eji261)TkeTBI&Y)21&dK6lbDMJjͲfLlҌ"&C#&Y#&@PEUjm&k浵ҥ6Rd֭٫͚bբMUmRL9Q?f-`G\Ů3C#-׶oifvQƅN僙VC1-/DܒDsz̶"'#*l4"P65XER]>&̮b`@+Lf_vFz.MrZ:9dxc޷{6([V}ddUd R*UbCu,TW0z}_N`#+KX'ިzMftح!<>CTS#&JNԙO"4nHs <ɚ_*?C ]Ry+/Soȁ2C1<|.0(YdQDﴺu uljpر{oMjhhn;0iETҝ 3Tq5ٝ"NYiKe<. dЛ`5 T!˸#&*m65]VbP;@$5dOHAJg#1<#*%UF:+x#&L@9.BF0cJv#-[*h7թeӌj5k9Chaۻܪ9xyIﮰb;5YzgDyE\#- HH)!3뱯Ke".rչrJUQ(,̢b"UU6(Dum!h#-cȥJ*ѣFerFkD8pYd#9i7PVhuj8mcE*lh#0\\4ܠx4( 0k\-\z"mG>q߰!_U8{95as@~b;~IuP(pHkӲ,Ȉm˥y_D |@RJA7+\R~)/zj^ FA8Bd#*#*16;(j,#&X1QĨxdoUȕhf/ip3צ\fSSd[\6HQ{AȮu0uy\_VCГ(*:TyMpڦAU/IV#*$X)#x;jXx>*bzEł ̊*SbKI#*pŻD1{`[9<|q̔_!ELĩ4=bEAz`rE4'&jR T1QК0hq:YfSɠ0^ϱ쭱jSLmDkm\Ͳ›7]6JZ+QXX-XBV1ab@-#-a'}[!@A "%(oLF3fXi,eDӉ鶺E$dsL(T(pBґ,)C= >jD#,#*jpyHPkE"n#*NR.$b P7z*c pZAaD"RYmTm%uD$QhŘ"TH#-H#&ѝ}Q([K8JUZhXADJ0|Mp;~{=/bb Ot0{R\kzIY+ήIh#*5TUFH+@eP`,LsbqBA,;r,:@`emJh15A (H?`" dMĸr#&0"E5 ndꮵɾ{x$8!q [xyUy2RK@0ta DMdֳf[bXخ 3#!b!i"baI4& ;0mS#-$4d#&kr2@~\;MC"-rtp#&Y,ԊQ#&b)"b#&X"/mb_uȗ#&GI\8?GQhc10. \(VjÂĤ=(0>Súwւg}\9ʪ3eFXUS ќzvtɤd2fٯlPC@`a#&z@@"otq dvhs੸CРCޖ{#-O(ٚZ6if+ie<5TH(40P=zt)@;@Xryվ2̏=+66 sCZ4ʼ&S9Wga3!tƆdL2c@%F1i"fEPdFMA 1r'`u$M#&A1la}6a>'Ol;2`uƛGe .$/VіD 1lc$T-fm=FS}#-Gs$^a Ʉ}Pqu-acҀb"8fL|#*/cY,2RANԥ(#L1C·]pP(f#-c50*Zbg>JQ 1lm%ʣg`pjHȚh"3?[ǝƉmy5HJ4?s#&T4d; B1h s"7%rqXB؄T >t?v!4CD:ؚ,#&^$DېI̟sM7D52>J s#yƁ:fRC%6p/! 闆n8bTA< \pe7,o:HMo$hzH.$!Ae6K,V!#-(h,#&O!鿍%7#&?%.=.3Td!~U%UpM#&lF](Sw@{B0yYc11$#-,_^,ч&apطl6ޗlZmҦ qs8[)% aiiZ-39`Xw|ޭPlftqnkC솁2çGzCS#&>I=җ&w88{I'o{F.獐y^A^;%lmא-)7#-`tmrUT‚["7-iI\;"nj@&a0>-#o!HY#*3 U!K_M 4N묖8mÒiѪ?'7m/Mrs^b=rK:f;^"}=>:4F V%T< BRD$bK[HatA;#*iQoTUp7o(|B.CʺĹ }6#-77O#&!#&Si܃ ȧ^PIVQ !x p5P`q]FOU;7Uy*Q4`08X#-#*Ejmw퇝u&mYe)$ R(Pϴ9P[OPcG!VtxEa#FC$AL(ČBduh#&^SLIiu7ecۄ+ϣJo%jq h千xӛI'ZBJЂ5HM\&X&LVj%d W, ƞB]@#*ڰDMFl`EXV 4|nl)H RC&Tqrx 2x!#PY*].SΖ#-؉>eaKj7lۆUpiEm,{S#,YP#~)2sҺ6Dg4tN(\\#*-V_ţע@\ "u#xMsܒ 0ajBP(Èm$QQZB14m6Jjeiiklʶ4nI#&dD*t\91 > RaÄb6#HQ@M}hHix>uH"Zf\{iH>={mu%)RUqm1cnH Z]h9j0#*yZR5cAw;kǕv⌍.W#*pl2ed48{kݳQbo# ܗo[8C9yu~mV>ǃݾIJ&@ wS1cmV~Fy:R&Á1LLyX"[D*v#--?37x#-ۋL_KZlHH[T G<*T4 Fؘqp) j%{5y#mr#- 3*jq0L!lx_l0fm=U068)ud\`:w)1x}WK!!L#-ΰE;mNC.Fot]ʤO0Fb]oW0!j`yr8b0=Pׯ ܐdW|#*fF}#$vJTtf

ǁk"EKA-t#-ѹ#p>h7S 4iIQD*'LW閃hj#*`T/ ") yt)VEA1% ؝#*aZs`J!J[@eYaeFR{auKtvwr*h(ewmv_{6LomuRjB9ej!#*y)H)0Тy'Ci#*Bc.;r6ʹ/:vRɥwv]'ozi [nYIƥ BJP9ne1FZKKYbRJ2ci*#-Mh-F&KKqvwwUɱ"ܢ{u^yo]P =on YKCσcmTJlƏ6UULF:a:=i  CjYSdkuRq»ѵHePF(  WYL#*{#A⛂,y 2aQiҥB52L,-I{mpYgD0=s5TUv]es{-^MoiK!˩TF-#&#*rMȘV1$RőJuP,R0WZV m$WS4LĘf;kfsb8a .262X #VBi4@a~7!}&¨ž"<d<"fZeh_fc3*GEª.Mv[)#-d *Y#*Ed u&ΪޤAJK|*B]0 -3K%4C6CFK[ biY#-kzވM"o'0霢q2ȇgP5֙!]f=(Z `8v`iu;cde#-)ߒb0BRi&0!AC`AM*EBd!b,)e bL!wB Tǫ:Ӫ'B:a7_[sXXfu>UQ2bT!.z=.W3Z}]]ҫd(b2AOySl([$\{&OFcܚY#Md50n>C۬5_"j⒊[pxxiK3SMTdYo>d;Ѳ[‚0@rs7VC(BݬΏ9ާBDcg#&"`/UNGj#-w#*ȠH7E<`H :}UTך7YoN7־#*aUZ/܁} P~~Rn;+7Rmk3$6r"='4^VAAEaIxB}*Plv]wRbֻ˶I~O[A5:ʣ}SV+x}e(&(ݵ %`ɛIxyu[kM&"QA%@"iAOÂhf'Q+J$%R$"0PhQ 0{SX#*tExAV@")#&`ŀ,HEdU $8x[> fVljLcU߇π|8 s?U 4&ڿkQMh[U#&ˆ\EZM|j)X>QaH[]!7w$b! %}2Ì , `Al EPAtLwvs5>(D7[@ZDz`ZѤMTHXq#&Ւ02Mf#-8H 6jʠГj(BK@!Hm,,ɺ !*!]#*5ק5EjTFW]zZZ|@+HMA^>s f O"mx>'رFҪ#*j8ʾli.3޶Wu.mWkAK&8R4у0L53B*Wgi43 JitRoAĕao&mGd{:a;r#-vy )Oaxn4;$ɤ*Z Gj7@ jH :8" @_#-#&HR@#&',`#-EdUd+M-QHA9 }[^{~fu!HI4X!)~$Ta791D5*HtϩE$;*!B ;Q.1ܡ}ScWߛ#*#-㡂sqp,_TaI#-ˍ_Ip.XN^]'#*N0 @#-a3ͣyECwۖ'DԫxZ!È肸ؓ~!`wFRA+#SOE6|UQ2.1C*會IaLC7#Y[΅Y<JawhkFrL]hXHaH kG0ڊo[F63I 0$%GdD<0凜> 1Tݣ8 0J/OnB]^?\WKǠZ][,B+Ѕ8 }F sh+;_Ԏp)SHbIH3\_#=bzAʄD$L !#i3#0`NcJa#u#-T).%"If:CuP6[O.r:}z *8hcBiMI) !>zn/5lm~=KVh^K&ڣ iу#-)#&##-U?RG@_W`  vuChsŸCL 8'T\ {]pvE3=W1 _vմ0#pݭ街 0(0;u$OEՊ%_Ƣ;!> (>Lx{HioC0:-1';`g]OZ<#*ۍAޯ@6@U#-& fƳ H0"wXb;!b\qG>!`6̴FT Вbcʇ&B##*ٚg>tSa 7VRDZijr:߻o2EAB@#**9,2_\a'k7υ4ϵ3.hl8r_/TfSrS4/5WKAP09[cA@/#&=\Gs#-[:2oݭ#&A T"`ePAqZ4X{z|6ofBBFi>D̈jO=k!\EmyÝ#bÙaUU}nYy‰l`$(;07PAmVT $O#n]ˡ+Z)GN /SְѠV+g%-JiYSkP$"Ν,}q2ɀTE}߇)ޥKUD 4a#-%#e32eA&5)SHRkv'Ϋ_kBBA#3iOT嬾Q"XֵQp6LaQ1pc]Gꬓ%];3#C+*qcn)'YAyQarH7 B'yؚŪˡ[D,ŭ`r29EAXacY70`o*tBO3&ű#*QYfp<ӋBk'A̫2sg~ x1ǿ0Ucޢ֠pY""|۝Ҳub,4#-O(ajVA+LW6*R-HD288#*j]Jݜ7Wm'{^]-`FbAXa"+HB$w!hh!Bڈw26hjsm3jfrMӖw[Е 9oL'e\hhAXiA=4OЪxbYp#-+{M`d}a0.5SEAh ~+ .h+ ,qCE#d#*i#*Ez5Qi66fW.dS!<qD@z$m)M6H-BM5dBD7Di1 dj)"j0RcTQ E3Hp22eQ2UZtA+0nF$$Fn",T4@GJm-(HcqD)4(A_#*<4lֵ'f;Pd)˥KK<6z `NE[V%ҚA󒷃AZ9!Fe j2#}#&{jk f*ؽyA7 PM(J8;50q #*1f&⎒- sp9t;HUc@`R3j4j#* b#-fٔdIEd2I&)J<4 O;&b%7D"l`,#*81dXVC, 48xP*,`DUd((e:2G!HOmh֢g/ CY+]fחmuM,)^P:CѬ46xU"?K 3^ǓWC ` 2 3f&Zkt /4odhʀ,Ȅ#&8#-$V#& DTI;vUrsOZx%#-إ"#&a5?!IV>*u"M$Y*y|K[K]ŷ]7eDww#-[K@CRdj*j&dHl)0#*'#wD"s" 2B>!#&_PTT/PU#*ИӘHsb@@9Ѓf,2 M͙=a~H'M/I"&P}#- Hme((I#-46ehLmڬUm6٨X EY0 vfA\6—528J4aXk! %h ,nd(`#*eldEqAUdZaC,@q 00#*$H DV1P`]A3`#&!q#&-| .t.z$#-d @DO0:$ y ңߒg'>"vTLwVVz򄐩Q^|68{v6Dyo A:b}#*ٯ*>G ɊRCcSkn!c&$5EP ~ny&Cة$c HBRĔ35>ļ*#" #-QVW,.܈ux8,t DlǶ`k5mb#-35Hz㡶4!zS>Pԇ!yx1u$rL_G[}M?_L_tm&zrcs#*>pF۞G`A8@Wm# D5'ߩ[NTw"B;?k:'u$snv0I3NTv=C:<C]6^o!6i61.#-{oԌg>{vE[LKd7ɝqf馧jr͸:pITd㺥W%n,.=^bH'cjG  L۴2Ŝt7Dwwj% ]kkEF^\=|#*@&ͯK/wHRP!$"KuHK˿]o_oW1K(y^GlJ<'JIJ9XaZMqώڝ[ϧКoyߺL\u5;t|<U8v#Tuw޴o7Ž3}TVJ\י{?ܤ#(FDL 'KI;C:@w01km/xs%뇸}xFutI1d7uJ[AY86q!un:q Hwts+J*#-6qQ!ѷqp1mPn#*8tacEar#CI#0l  mWC‘7[7'Z3-4xVv#/ֶ@ne<$Bx4늏JD5p5#*X*-״V$Xu;#*eAX9 ˋ&/#*=.ݏÓnvܓ_w$xDzu]Pw3s.)0FU&q*s(#-3<zCFAZa0IRdv:H!r ܎ɵkm4;1d;?BCg!n8#-66cz"jX⎤8D%s8cC&&q?=RA  D 1ii7¸f( "bZ_4cMѩ[`DG40w!ahr2C) ]@[aq taB7{6#-8!lpa049}'m׆cV2<\bYF\Q7煒Y5-#*5LX]μNU.Fɓmaaue"#*iè LxG}tL%$/.ѻmy>Jm٭#*nz@#nHx"a潰G#*#&{\b0J2iT!YysG6eRX`q0Ƞ]0WiKRbf2u;\mHjkl \r(3_NrxrLq25! \}tcK>}%όNxעM ^(x{ؽsC3ܖ !FN)胨uG\>edH#-a|d!.3 ՠ#*Td464Fhq(#N8qD@vޛh56y-bR6ƨk(6P`*QU,B-J[{u.8St0"<5+]-畑Kiz"$"1vX<H®>fxEJPfP#-8p׆Ғ`vZ#-E#*>tL8[$VtL4*$MwhQ&0kƠR^M $dQ6T`|Ԏᗋ *۠!\0i4FiUp•6&=CX2G#*e*Xúe.$Y+O5 7AdlJn,1Q1zI1e#V[/s16pdX\k#*jt377"nov#mE)Z6"m,7-zԑBWip>epГ\Kꛦ]P.$05 ij21uxdCÀugAZau*MD #*hR$[aj7T)!1Zg\ 5CD{ 6p m5I@UE#-74`±Yp$n^xZ8aw"11gi50um#*7I -9 hrbq$hӑqYJ¢-ц(Fܑ*-V#-Lg+8]ݚ6MJEsR*L*P.BhmFLF%ǡjcmO#*elկT̎IÙ&FԡeGʪ@ցސʯ.n*0b$`GګzpMW~p02p@}In9i?5Z#*malSiB&0#-ՙR4'NM# gtU&%.(.E"]ujHupkC{{Rg@=$1ֿ.} SId\ _m?+*"٦#RT8%4 Ѭ+<%4i'$)$]=u#&Leg9Hdc;|@#.zLTn=hWC|T5{|$eēDRϐ7+Ll~8]z19vʛJ?O{/6]Bt=]wIH"L7Mq+FT`ƳpIBP3YLcqG$! gt8sC'(Q 6o-A#Ow&p'E=0-#&#&+uRRETblmjoj*!@'t7{'pգwQPqPYQIVZQIPd#-ͬK6-k,T&4TRjiRLT-TliR,TA&XY2j1[[;]O,Lju!}mƃv34ݽQSfEr9M8+h 1Ad;J"9OqtS/4eHvg@M3Rފ@5Q#%=vF1#&Q|y̶KGAu}zk$"RV(䐯oX3ǩ6eISZZMhZ“U-NXXJ`)$@epayI@iUpy7.2SO#*sˣEi+9-&"F͍Hy&]`L$`.0-ЋkS=립wPJIc-}Q`ьOZ%MQVZw%(0F1" X%BEz#*Q3@?#%ȃcHgYl%F,DbS!JX3k11oعY3R4FdW#*aǒ]6UHDCt.aTB[$"I$#-w:hҔR$}u?!ߤaCzGG#*Z#-/Lt7(6)/b`A(AҰt?@j&uM17 JELvҶF@g8ɛ+3q#& &a2͸J)QE$AկZJL㤪-yA:0n OKz^'-#S'rO]+V1{4cL\t#-i#&#-uyr "'N0pSr4k>J2BA"jP n]h|srکK}eECkԟkbX5{n c ҨvbkvPkyyOn}T<#'߿Fm#*kMh2&Ay#ԽJ-;L_gXF$ڠXXg7P{نN䮚,1CV <(?^sd4Ǯ0c{9o!ffci82HC>S#-7w龼Unhțc߫Aɭl,QgM!y7G M[mU"|<.+eY‘*Z⣇Mc'+rDQ(ʁdU&ۋ2&A4$H͵?_#&@&}Kdi,)c v!$8!!dB TaƟ#-:!3CI&-Hr5-{:r#*d0bKi۝,"atf#*&yh j4JH0# E1TA[vZB#i%FLJ@[D)l̹+"E[p#*1AlY,L2mgY`H<(֧O6Y ۝C4ҬUjYa-?~`1<TXrx:#8ۀLĽnӤ(ANبC#*i#*͙g0!K)V,rLX$B#*8B=\6S=yULu1/O*™]`1YF GiѲ:PqdW]1nL-,dʊaiP#&yCyΣ+aPpE9&w.ۈ)S:%NˤATLJ#A_a*xM^2}HY鵛2':CSt;RiW5"Lػk έRlf6FVKxR.UN*1( PwI8!WgxmQ-(b&_3,#-'LѴ+#*!#*FNk\I@5 zyj;+6}Tc0ܤqx&ߩŖY r5-&CfF#۲$$u;~+> ~t҇#**ja`f^.8/LBsb+c(~kL[g1t%ӝЛo `9v3U;Y {3~haZ3 IkSK˱E&j!qF2U-+V&XDóYp"[yfƠ}VàVʅ@HAΖQ E&I4FI5mϔTL^QO`!PN#*-W5޼yUljtNZ΀b{7a#*2Y"Vf'p!+#*Tѻ:fHHBu:NQJ1%ѳ^lhfMʠ͜87NBƕӄGd1DIZ;BQ:;"#0 ٥GBm,#*ߓ}̝`;hVCTЋ΂4EqT5;g5>hZ@d*;#*Iə}\dLJffLMXU@j%79ADUeԲ3mZmu؋!{asP]!b#@ᦶei3!AJc0 5wQF2H:#p]`6LLK*%DsI#`ID2$T!ުlu!.&jSQlU)(`X\@0]ÄDa==')rfܤ&~dDUv S`#&5#&W?ms藯=:nɞA\6X"p%78wYᘱIF[b-.7li3t1&S{;a1MǰQJ(k|wkaFΛ*T}e(guPܰURspCt7aF-Ν,GQcm/kk'_l#-y&1](,hȞߨJS-k@YP@,&KUn^v)tN6DYع|,NP/@¯D8|s9]CO)2r>:d!2`P&%T"`]A(E* ! :NSc5IMƌY,JC(Q11,DK#-bdxTQ#& TuP,)#*#&J4“1>dkF,t*b(r٨d24#-ٕE`?Xvv'ewp4 c303Qr4*"cj(AtB#*ؚHͯL%uByu'IđC!6D^gyQV:4*dYyH=t;!<6tN'*  a#&4lTR{D-40@p\D^U Bc2 U a7dxi^/8uTK7Ͷ-,(A)=X1@$DI],{΃,Bn bwp3{ \#&цmB+.e%yqgtxsE]%Q]˦̵h#-E W,@Ԩ!3#&#*#*2,t_zs#aыhc[MLMy-^:X!a=ѡXـPhNU@R!a Yώi e%q({oJI$F=CHXV 'fgL(l}F}O@&jU7=Ǡ\f*㑐j@shKq9cZt5v $e͌#&zT=|D$P4 #d{;|TP#*#2aV$i5a1@4MIALCDpA9#-1hYıF<70yifPM4F+ 5c:^,~ .fEV94< 5Q U5Xv8f#*ךoqs/V譫\7ΛP! IiaM㩩emwz|`(db,(nH(<1n TҴJ-]X)*d, .5%*=g[nԕ@*5 EX#џ.i)S:iN#-x$ D@p*AWsXOFY ##`y@"WAWnjc}FBγ#l_t .Ei,>!ذ;Ԥgi 0aME0F;#&==}v"`Y[-EV浫DRdI%di%loUR(C*-%FҔҵ~j#-C O#-DM>JZn>-7"'9ț5k6-"z5RZk[!n7uw}?aّ$WM<>#* ,Cpm D" rHv(91'~8WUZAIIͧ}zу>9 [ X1K/҃p5=e!) vߞYƷ(z#-d"u'h/)JMēu%,6rmTFl֚Dh"H66Ę1DU"BŒ #&In3{dp!kl'(Lx;[:rґ9P?!X$dI`O^Jݣm șjdc+Ԇ#-6a~`\,{?B}Q G}"#&m^mF&ԡa"AR$EC۹o4G$w߇-]#*~liBEB#&%Kdq֓|\lSovV#ymi( 8pdS#&dnҢMڍwǯiW|ub+B(.g$9 #*Tc["bi`1D2I_^Fo%Ԥ?2C(,%LipCt셶+;feW׮n7uXffUw:iRC^m*jB$Tu (7\&ݗ6RQj)[2MwV+Q+}7c:Nz \ AU^pa!̣D nw,z#*@AP;V6v [ݺxqqPU]zqfTx Ry ߼guW!xh8/[l,4-ipMV!û.|X-JTnI:{E34q)53eV{/#&4"-sQR+T~Lcsk2n\L"m̽9xPq mopXȆ#&><;afk".,dOFd#-LDGۙv'IgK9zJC.%2g,#-Idl+-:#* 9w94n m+J#*a=ծ@k¸2c?#-).]-n4'ojuk:4.ЃCykhߵ#&;d"zLN,_ƀFG~@RmHH[n܉5{׵aڋAj^57oT{ ?4FP8bށד'OZKEPrmCݗv͞馷и#&fSw5pLT|O?rp?-OOM?wWχg}?{?/ϻ9`T`*@G#&ȦWP2z*"ŇC wL Iϫ[콵U#&#zd$hAwiC\xY5 %.H"nO ָ$$fRsDר7/kLfv̧#&c/ЂxMy~GK'/biQlLP xL}⠱H.4$ FjN}w_kIؙ!2JQYqv֘U!dkٵ65MiY#-0p;q1?F*QȻ:8tı`u]\ibX`3AiP3ƣ1kUsrZL7B4]Z7hm"95x1uoWbYMJ4RcdVHlC vl w]lYŐK4Las30`pֆGkܮx[FKkw5fV Hb^Ev(q<Fxʳ[m%`U#*rGN4\$#Мp|5mٰ\YWdǧNLkEdf#!oT&9p.]#d$df|dGjPd # tYy"H@99&"?bXGx:a`(!8n#* ‡=o[N `T(TQ2VZ,F;J@E:""a'0Q#&EUxr($L1`sJEoOT>A箨~܌dOXC֞C<7̽U,Wr2A,QB'(6~52;JVnZ+{,Io+H.'}ͩuc](,#*Ʉt.1DaڋCclo2e͖Kk`%A#*cL#*'4DH,c׍^6$X$#-HP'#*nf4ir_G ( 55P?$dJD clR2Q.?Q\,*s#-'ݑGD8XvIDGD׸!Gz9BxC rO@BD$E7;vMCHUdkm]5}Ce3^Uk#EbԘ䝾o3CϩB=^(Yr0m?{nx-]X%gĤ?#-v˚H:ObtꠐUq~a?9ڋoe/=dts#΂P=#-޿oC_\|^so|7P!?,J~SdY^NzNe66w K%+ӨIiGG-{`t12U32`þA؝;hLed0~e7 g~qQ-fшBsϞH<Z:g .0"AƣgBwm$$.dc#&?ܑN$i +#BZh91AY&SYl#+T?5ģ 0E(b&T#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&}^kJT{] he-vXZ{K"r{}ݦC]v<>7Miݻ9[.nFC=o{CGd^{u6=k{㽦Smup#&#&#&' tz=<>OxKfuwcڏpviM#&4 u^#&]$((m(: $*=9IDt@#&j(U[=x"{=Z}ь^nUl능Gljuk]^&ﺮowNםTy}l۹[izǼo^uΪVgAH*H^==9WC;=nOwtvIͦ%{@#&BH4<ҊznΨ5}v>=C'-mk}1Kv#+|#&pw}\O{k=={NJu䵭'_],whmݦNvܸw7u;ort#+n;uﰭxRyPO7*tٯgl^_n%y1\ٽ}r<ǔ7FqSo/X#&]ևz=){(#&R**]Ov@a;#+]Ol#TUeB\1SqCu滙#&#+v#&Qwy^yYhYly`ϭ4-!ˮ\عwۏWm8x *vezv^my}|4ڴo1ϗ3#+{\9bitY4g P6k=@n>{Π]ʮ>-3zz9b#&@ ׶\5kSztt;9#.齽M^W{:7a}>eP=]59!ی@!ݣsyk K0gwh@'wzyO{݅PV7o#.v'=vfc#+ݚ%h;@IBJnۻw%ibz%I{= >B`ɦi8heqr۝ۻέvfͨܣū\nttoM#&#&#&&F4#!1iSe4hy @hmOC' MA#&##A1z7i<#&P#&#&#&#&#&  hiiSU='*=(z#&@#& h#&#&#&("x<4ш@&i4#&#&#&#&#&$#&@ FК4ȩ2ʞ&#&#&#&#&MDA#&!0!IbF6S=(ޤ=O=CG#&2#&#&:]ďSת $VtL$Q#&R Q#&ړ~:Xpx4JKOǜELL*xn㓙*_#{@C(D"-i#.%J6ѢwS}rNB~"'>eaR"#.pa\CMTW+ZkZɶ[m*֫{U#&%D@BVPHe$b P$qYP#+*IUm5kim-d(d(0#.Qil1E&D"XԥQM L&QmњK&DhD"jR@#+Rƀ4ŕ6IZ6(JYiM5!e6h& 31IFd#+)E i%aK-#JZ54V[kC6$2DPem-hRQS[jm6e3A5&%ȣdH"EEFIQ bTD)BDIb$mHA#+42"bHd4F"MdѨ*EdҚ`RdQI&TiHScDb()&ƲC6"LSC3`X,K+EJMAjJ()"JIR(, C%0&PI)5fƍa6MILB!-)IKbLYfQHْQ6fFLؙJ3df M1$"PlX $iJd%HLi& *i,hЄRK( j4mM4Q5,YŒ"h&H3 J6A! "1F4, &T̫1FKbQ2LBe#.h"0E$ld٤jf#)!IL%b#ERiL) eHY*lQfJRSE!2c&E6I#.DQbI6&HCHʍ4țAc0eLcH 2 )LR,!-f͍$Ɍ A"k#.D lf$FPjK,DтԦ#.-L4$̤0&Ȍ Fa#+ABi2&R`BjfF&RLȈ-K4YM#(K,DZhHb#.QaBSk]5H# Fmcb6Qe3ME*ICKHZlQjLe"`%Iȃ134dKcj) FM0bk1cBƤ2eI66UhVɖERY6lf35lX#[&YYMe%#j,SYbKHdAUCQFJ6(։&H"ыF6dUQH%ZdV[6[$XITլPLjZɢJm"$mjUcҩe*eT"5Y)jh؅$SYcCeYd+fH(eF$,Q, "D6BcjBTPj+$FɓIEbMdEeH2Bf(ZdFm6F6S2$1(Ff1fS"h,#&Fa)S,FBͨQ)$ hRE0MIXFXB bM,lJYJ2V0H؆5"jњ"4#+1RfQj4  2A&ĕ%I1cdd5lfɱM6b%#+(iDiS4@XbDB#+0D1l6(Y)XhQZ35#+$,FZ#.6K!D#+RTȋh5Q$BeE$Ԛ`Ɇ!a)CV6JiB4ILjb2EJ*cI"ɢ)BԢ̔ISbQ6Qd0,ҋdXִ66JdJ#+DDdj̘4қ3bb)jY5BI(i%bI,lh& "4ZYhj$Ze(Ml!TmIEE4&E23#1F#S6IIb5%K*ɭ61lj cc$UE2X61mIQ f-F+iQQJkJ3B6P4hDMY$Z,e&ZiLh6mXLTLIDbD4lSI6*ضŦj1eRɶ j4Չ(#FFJ(6I36YQj$Ēe$ȌFB-6f1/Ey//~oю%`S .) ŠѤ;7?תa2i*6\S4a%q8ģE G.)$$*ᱢqhI(R+|F"9,[s*l=_:YA;V-;brwx͍IHN(mcջfI«#.ƣ#1$vl1#+sɣwHLoywU{/Y=ןg5r ֡LD&hTƗ2J "E7n(WH{ruچ_V呕sIY AL^,0q޲wp1#Bw^M5zIlF1IvPx=1ZlE#.m#.EIlϏ1؞jxcԱ9;l#.Pa4WUuіwOesfIxM %kQ,3w,mFDE%#.)-ݭӓ_*$E#.d9 #b;St΍AIFy&,:l^I{;U`ek]S (TA@rɨ6m%~YB((b~) G^1Jj)>0q#&8#.3lf EsQ[D Y*7rƢj[cu6 _?Ow|tulZ6MoK~G@Cb|3ad`4L"#J8Ih\ "1YIJmC#Y6+wUдe$HalAHPŤ'mHC.IuVV7SJ]+)/N,8P8Vp(Wňd(F. HEPU'-b#K9!G F!}:+<#+t&XK|3D9z~`c!kUeJaс2<,""fF߫~.i1#Ӻ4AM\UN̳)EP#(D{N#+)|˻룀󲻒f(F(;.D##+ɦgvA8Ͻ5^]O&]AKk8ڏ#.RJ#.˜(>lNZֻ8(Q̊E }BuBl|=]#5d?9IgАO6繅QhX}G 둚F^LzG 9Ï<ԘtI҇\^WӖoxâDn$g esƴzG1a?N*FJݕiBL8#.MjfAvmbtqC69|^&#ZN]ed#DIkG6guTy7uvC#)94=Fj/nvfgɣ=u8Ծ8SGm~<^tM&6tvq Z̷ՅpkU呛m=."SxQ#&H-ܔv6y-zrRHO>#+z}:섒H0H uBdN>٢ܸ9¼S'ڋ*#ӗ7WkS/=CtT]8J6<ȁNr w{,&׮,cȶ_͚-w[9޼M?)o|c@7=RK*ɐ*V_kB#. ͥ#+}/֐A5}#+#clB׾>kuI_kQ_k[y'Q#.(3XnmU([V=l5ٕ[LP_-"{[eQ#.ѨjvYH!ު3KC9@ik&0fZFSm.v(J|g5/7kL+&*z/B>?|\ c9ŞTUSL~wCV&:)S7ΊD^jER,)9߃VnSь:ٿVoƉ2$L/WjPJC^kEX).Om8rfAt'¹lbm\S)\#.E?SkSRn(PbRfWIS ꑏ\TGXl +@$ 3HaP AmToݥbRhrJRi^WGv$3J}T{=YwͰ!~vxzYC p/ѻ)R"1zPEk\:'?٭<*#+:-<R唠MѕY\ׯdt(FΌnǻcMd_?u1-bLr_&3#.(:}6KD|!Y5H-)pkhz ^-u~9Ie1g&?#.]ɼ$c3Rz˕*ꐨk,XD컵}[q~淪41Sv馫Z`ܘJ%ׇT-V˂¤X#+4$~|ac?͖wcF%$WT%e\{9~(JShFO߇7•rJdOɝx82(5Bʪ8ҫ'dzKg`g˓}UN$ͿpyluƜXȘ8giֺ uP&NBBKN+U0D|ϵ2*ӯĒTGWЇC6:ЫNأ=tKbN[x6=V1KWhIZn z`z7;.U<]^Øs `8}4VSZT߽R)9:sIG# U Kdg~wz=x,Kgor4:ŒŘ*K+ҏf#.X?wLؕU1ȫ:=#+ΥY|Zڧ$>ݚ:b; ocbk%{% CMJ*Ϋ!#++W?+2(7Dfd7(Mp{TVa!~R펑ơ_:ĸp#*s[RTm3vO#x`{?p`IU,'@YqT. Afv2 b>6{p(}:CGqscgjFY(&ݍ\xZo@lXo3)vmf=PAi*/AA]٬w|`AlBgc WxQG5z})#+2¿3]:tg:``z%-Y#.֫S)E)g܉۳6=A>~֫.j=.w;Y˯bd1YI:,"%4WBGWE|i%43#'A(ƴhq;?j1B#.8wy$۷.L'Aiem.55I5F>}uReLJPĴYKAپx7=߻@};ϛAp׽_-_lx=ZQ>yCYd(9xr"pc#.7{`,Q)rH X1&IlS-.6-s0.0.( HHDyHE.^|nk5Z2_[7EDy+It!&E2:(;G B^:ի@X\0Yl}HI; 7[n}B8!._Mosf1nS<\Y{;zؘo';u}]/l1ha3 K^96s! &tz?m91%^?F:َ#+ 1Rmhxt@MY`(e􁿕5 ML_f,DdiAyظ G%\ϾZ.pՄ[F+*'iNQ(.Qv`\l9#&>ņPQѐZb4{#N]E3crĞ٧L^(.uM2y蕠^0v˜lvD<"rVsYvkAXmtmҡ=!h傥$BP|/oww*aWEr>KFPr@NkolK"/l0)}q:acDŅWb}o#&#&A[0#&Ag\CX)a?WL])]UGZY"E6I#o*9G(䟩:O5鶉u^__׬mD@{T#Gz/28Bn$(0{ّ2u$@v?`w}GwD;DA2!"\[Qo{k-Ȩ#.:&ͷjQjbuPE 'S#&#&|՜f*@S,E'^"#AsKٻ|nz8#&=/Z|={̣]@訉.qb7ЦZ>#+Y% 5Ät%;M#.PigfߊL#&Jv#&b1ޟe%`xFyp-쏿De:?/|#&#."H|wՈ\ޫ~4܉ dG%${ul<}T#.w#&X kȵxz˦f<`m#+c߇jNNr.ّ:;}%?z?~`0 5+Gunw?}(#.:.rA [Zn"lh ;zzg>l5 v#.}YLA:Ǟ5J1(Q&B$i[1!MҺ)(>ٌjń+sȄ#WEH;;e$ bŔ BT2. rܫpg_`E;uIsUJHLɝ5%U󐨎i7ư )@5V5_>,̕Ac:wgi1s"ˏ=%Sd2JPw>m يő䔫w4:,PѼ~˖93O~6Fpq+jfUF#+1x/WX3Ɂ00SfՒ`zklSgX[0v*6 -eϒുN9Ǖms"|;O$#IaiuL[#+:@Hc #+ ?GI,-K|xMCĭ޲Ɔ+gLynb _P;c'X4CLvP#.ɽ~ɮF5#Tjd.A8)5 $׻?Gv>p'-=H0:#'0Jgj%fܱMLYj#&˶$IwͿ#mp5U4Ѯӏ0Dj?#.oK0,&QZ$"6SdB"3uW6T^R#t(5 ꮚ'fșv%Nc?I緶1ՒPt;K_@:he;eXz3HKj6e}zCYP~ri¶#+sRdnAIsr㍇d#f+aðDba;]>= DS08F␻Bew8Qd,s,Š ҃ LkG=Z#+j?00^,ͅwT!$硵e o?#&cV#&YCA#.ˉE.7^Ex:PS=Q#&<% #.PƐ  5”@#sl͡Ih`燗 #&h:q#.E`Ai$Υ-J\ K$:)PUGe@N'aWy#.h);#+Bc}Rf{\xĸ$<+h:]"P(A#C K=ɧ;B2Z!(lNE fR4udQb=#:4x}ѹfuCBeP:ݼ!#+lBA:= h t!yfW9#uJ1 S#.]( G<\%usɍ")X:?(ت#.iF/x! C h|ƃ bM/uYd,x5o)e-W?C\bjz7 W}idd͔1-! !Y.DQQDT*v>;5We#{U XgpΆȎk`ި КI(\Pb0`C[! Mڗ$? C[.8TT)h7xɐ#.x!1o,5C*a t"|~<,dδУ< t2oZ:#.Aj(}C@cq3&k˿+Vpc괌`ߛ6hpdG4i*bƂ/ M 8Y:YZ*1M0%s0V[u,}M#BhCQ#+51b >FY{m#+E4a(2[C, &a+cuRƅDQ¤(iƦZNN[c#+^Y/ۭY\D!V Ҽ<)X,_C[ReH Gxcjk =rX"%F 8lMx/*'$\\m#+2!1M&F)dXU4IC"́'GZ,!86#+1(dʒn%и EiQHlm P0MZFRM##+V,Mf,LH8[puhƣR#+Dc0 ؐ1i%ن~/ghHS`d4K= 0Pc@hDssoSGrࡥp#3Ärphfďr\dܮ6r/ROH#NE3 T1ck~E,Jkа[WeDdK" XX#.GJ#+Pp#;-Nc  .Iۭ#+oQuyيxq= [n)ert³%GQe ~ŝkx'.SSmwF.IR7ɸ5]!Kn.,4>4}dHj*sQy?t1d0'g9+f!V?>wU@4sR'P aˆiOr[u(WNR#74$N-ƕ!Z.tnlݮc|m~#&:@yDɕi"1E#.Dd ~~r* q}Ol7TdU=أ>{p#.yhDPيUdyȪ'}vvzv|rieGY`IZ·% ͨG}~Mt5c%-Zd\ۦ[rtM"4YadvwTD@Y"@a4ۚ癵dITՇyپ;GOv3MYOo*zx#& %#&&G"ߊ¸{ >M~(,=ϗx9ᆑBf2PA`,gliւͪ )i瀰Tzr }៿x3s0u ?I*ҬQؽ/8ܔ_9B/r[CB$sWfR#.ep2a[C =%: @]_pzFcn6;75s::7>_\L7of<_~mkd F0OS|tpqrB;$ yv#+zF>uNc@L%M#+WQ*eR,1#};}~Lj8+YURqqVI[r؏({#&Az|(|{e#&NtP)w7MBv0yQᇹ;o HG"9?9QQlF{;ZmId& 3eK3FzvݨY5RhT ITKg_뷏ۯ7 nzˇ?,)|.J<>oh"II)R Wt/bkӍ}ܿC~X(DjrxO}Ov4ee%0##+"$,Dj)"s–~)4J:3#'$!B-A[Wz6صV"]TUS!_رP(ډ2i#+ݝ($*Rh!0VJ@-sg#+N=(>Do=~߾.E}+2Z^q2c.Q4ǜ?]> >R5|#&#+Iӟ8^0*fx~9*E,{l\Aȃ^޵pX.q_.'mϿEGΛr5m2#+y~8)]D#+m],9;t7WFp+P8=_-$?{`uz3xҗbUУMopÖp iwׅ!U`1"to"GGG?1 ?ώc>K!?̦=e>?AfwJe}#+zëq.#+˂dF׮zyz'f8#oВS%.IO+ۡ]RSb,}OM{%6HKL8b<[(nlfz׾nd>m6> qA:rNXsIU[_GٷLn`,-9[5v˺ZR;'DG7؃}f]w\(yļxFM4F5/b;ԋ3?kk_jY@rzxDPXck|G12_E:=wb]8}A6 F~G|Nɇ6#=qNMc;"0~(mEW]}:_-a%ob%}7dc0?o wiGo_i@ehƘ}2punC彾!#>$m#.(TH~Z>+|?ΌEͬv'{,~:8BKEݘv45_ |8}~ph>^8(vfĶ_|Ϟß͜>N0ZY+g|xINpTX||~VFpK":G0O?iߣend)~wYg*= f34<m_?)FFUŰG<^H2(nhPa!\#+!|b@#.P( 1^s?ZjyF#+oo53EͯvݏzDv_R}:h]ZWH]z9~APh<]-w ??o=#yx.[Sl&{w?f@_4c>[>5U~oջzo87 T{Vqҟ(څ=ZDq?g}jw#&UhI_Slg!PȉۈMDH"n#+Ǚvy;׈o?OHXn.-G3)ɒG;i(O0"y_!(N+~4hWU/4uFB<&gl7-'kml6C'в?\?-Ff\ڭ Y`#ŸQj 4#+*GGjQR7l@Fhs UiAY,gwCWw)2'0L0ZGb`SX ƣ#+2J`B#+YCCt!IՊ"ca>j0XIFOaFf#&fUI1KB{1Z8du߶["?fs΂PP}??%)% f䖆jJ-zBðQQ"/S?E@ӐQM H@bi71lXTQ&FCV6ƛfJPU(Z,g:?>q;eo_N36YXNs[7宺rW%[>߳ќ X׿x)+nv}~̤ lw~I\e[*k+=owT8XQSADzDT}m_^jAW\#&pjm8 m:|YG^pxYu.sWI`aha^#.ԷS?ɽF.n:M>MYK &Ey_XR>ΐh(h4R-DP9+:䧝Z!y;[Ua M\ H{ ~qa"k3@z)z?@2_;eԊ#.#.[7֫=cyozt7xLюRdF;5X^/D"l:<=t޼g&SM?PP9#\S1#_4Ԏ0f6T>qM4\˥AU$̪4#e $#yP9r} "o7@R%aϵ95I P#.EAqx>5ۨ,fɝg}d>YnK`G6Φ*IHK#.ק^0둀wn|#`WTVS-ZʨmJ8HKحOD::(%##[g/cY#.1~4:ˢ0H#6"e_+48b0D8H\ݺoE#h\ ũEs,aIfk*0d+Pdb$`pfaQ(EU=Gz"15"FcVգyaa6w69RFC4FQw2="6nV lrYbTVmӬ!ڴ]TJ5j&FUD!"$İIh-mcQzD[ѥm]#. Gjneɶ*=SFv>{뾛ώ#+zeuҁDoNМ#x̐8$tAb'Aݻp;O~5!pPL41i 0~BBGG4t79nP(;X'}᧛W Fgp{<#lQU?M*N0_;1ŘH^4D>,Y%ө Hȑ#u0UV:EA1ѢO^3[P6=&ӡC;B+z5#+%KD FcaBmnsjUZ*Aی{B|R)6lp9+l!5og]}qsrcN"xI<^.ߣEJ} >sgA"v KSKA12 -s)uw_3t:1L$>X#; kyB`\4=G|گ97x[ie4POvcl :L,s!!k¨:#qdؔ%]ƛonڍ29A,ǡ׋ ~#&K $ǓqgEw\5]zfcx}ۓrEJRcmV0xHoZGp.gh#i^n/|ƹ:4R#w,"4uMXAO}`PwU3{p26?سVbǴś'wyDe6Tp0;\ەmp١y#.63 #.|_am.6y:#lf=\?#.-9B,lڏ)3G4oԐ(4BLL{nز靯;ck[!rkRXۇ:L`wAjU4B*Nn'ut oȶ!rʍ(|6sJ#Pkq"Gglbkm;밣m:+&[TnqQ6]1qh5#+k[r+V;B'F)j9*e#+-\L1ftf,1+ #Щf9$l+].aZu `NM I4 ils}ncV5(|>Jʍw'&n1^uY&f+#u`7ȵqтRXkޛk .8jgWfy4]Ϳ-CyRcZT7"BQS3tү mloI!&3m&.Xw}^m̈́4ΛI3_e\ίCwd'25 Т7xڶ)JqK:2`; rY/g牆$ߗ'V/M9llqz uĵ#& mP0^p#+8N)>D#&z>#X8=|=rظ>\>] 2倹iߩSKē,My`ɟ@H\.3sø3Wc9M"cAY)2LDv#&Vf(x;?FVwjrR!S&'DG\'caO^pXs$]O'Vvd)w_a'~Ls¥h-#n-Xҡkйrg>J'CeuQ2A"H9b2I.97s}Ӽ#.\|PdɅR,0ɣ>rnݩnr^݊1|ǑCMM< Ԥk>5ɲt[0\5^Ӹ~V>"M f$GNsc5qL,/mTqr9{kw]}HC\r޳GrdKI‚H&<(((l/=aώjBBP/`Dqϗ׵t磚M,nfʙ`S{  h]QZg9sd#?/y#-/q/C_ kڛC ;pONܴh\%B[iӮO_Wǁxqxay0~)+SQ!Z^ehb!Juiڔ*t+}b^j~8y$*GV7ֲޙфm9[C3k9MNQpNH>D?R1ȱf\l.uȾJl,UؗЦwNIL=Ze[x܆mx[]ж#xq[QxI[}UOawf'DN#+-\҄<3z)aMQ|ѱݖF9#LߊZ66#.esP`'տA\e#$\Ƨ^Q1Enr[| KSkuEϓ k;Z/&FwSq[7N0la fBŚ`Ђ oQ@J(^MY`͊'m{W3y/YT ;?󻜥߅&o9շ1#s.-EDOm(0Π9dd,mtӷ7ͱgۘ+K8쪌G<)H戧)|9Pڌf| gn'jVرm%ݍ؋!b⢢8{̒K<͊;dM,m-!Og)wm0"TAܒp[%[nmozPk#Cc8*DDOyMpC{y (IV/냧ZE4hJ`^cPlR)9Etvwq d־[<3uSrc/+F!}۫`6 4KSX#HĹAjlLޞ?_~N8jIf.y [RVm#+pYVvK,nJ\/]V#.qWݦd9:l 8˜cdqMŹ5K'p"箜ȣs;9mFK"8(ͫ4rKg]PgQI ,:;R/*-ϏLtrM0z@_Q8{چ-. ًoot*DLL󪍼lm/^WHʎT\I^X۔3>t`ڳOFeat $ƾkib.W:#+>xӑD9yR6ZViT#.3Xq~82qnABZde'/"vSvغ1dIa(OQ9~T$#.]`{#.[2f6ĕ.׬qKBSD[NX#fa13K'gG{6]#.xz~M~^$L47e"خJрTXV3yM#.F7>˞a{m=tYg囋/]{(BZ (s'mxȌVf'Dv߽rl7GmM<2ڣJűUA/#/=/:-^>\6x6@N8M0ժ"I,vdcZ%U^7NL#*RaUo"E"!s!$|iPmmZk%[v-\)Et:F*hJW"t6b,M˰d 1;\,:^cȺfP#m#+S~365 L=Ǒ6]>^g-9AۘrlkAMQC=`lرkzgJ7#&ppfKYc`6LNeX|`v#ט;\ljTy̙91&{yqc_ pv)xQau3pN͍t>+yE`*0ONij 直JTI*xzԢjs8RZ\z1VUQ@o;S#+̆6O#.w\?ji6((tvB'샔v!Ƌ5R҂*PZ\OwCrK19y]$hӠVޮٖaUH$L#84aK%tXg %\U{GC-9D:"-pbC-,psx0l5fKeɶy #4iMF#1l_k橸]:-H$Us׀ģ"-]l1<ƺf|>oc{!L"Wa”9m7CK&b@#`N`[™ KGRz~ZGW~qr䚿#+T sY7nF(o-ѸFqkZ9d*tۿ5􃒞[r|o)#XW>z^x Uʃ0nNAwIg]7px7+w.Y/3Y ^3)#+u۹xj.׃#+.|WqO6)*%6iʟd C[\M*=Z WxKWcUb-[ 3=<66M1@{ݼf'kˊ=jA9W (Cȧӄ6@N+k SR%g*8:9b6d2EŁ%ऱn]+xc܁jb;5-/k#-z#+nND E-Ke # $+΄;;ipV=pM#C8034~/ή*ypIs>϶Ķ7{g2MJ?p%BQRB+׼g7d@9F+T 'Fjw/8o1nIɩ>8 M ~Cq_0יV?__N_>Rsr(#&`@)(Esl}|´pv&532@#.'Q_atqٯ#.W:[ZO+lJE6ɱ6Wטx18-#. }c7lp/o^ܚ8Itv>Ӈi̓E2(E`k! }"jxyөg#tWųe'2>I@ē)e /8*#&ޠ>F({ﰑ\!ܜ 0b #.:W#&HD@T)kqY~(+~d@6i&@:'w=rYG_;u_lC%.J1#.#.z9^ 3&3'cb1јU"`lIwt6.֐3\Slad"_==$>8Ɂđ?GTԽM ,OL#+rt,;A);Z+-4k_ԿOgU,#\8EQ/?c;P9=F&^.`ꈇ2P7hNT{F{ Ж;#&"!F#.)C_4:!4S6mP*#& yA J`f e+YĹF{|t:fe n]I0!arMh8%#&c"YҎ7`E@>Q `O-] ]v#&u7t،ğhiaE_0l|em.#&Ǭ] #h8XD\Kؑ ^xҜqDIuQljS+ +*z!H7ݐ3Mn1a/34k#.ɶ;GP46_#.TxR~kg쑝i#&!ޖFLr#&L7ĵB*@!&`(Mn83g9$=`g=Qg¹uC[3$˙@k$[sy!0#&*ﲡnS݆,7"9axhU+w9;x:\X$ eRfRUmcud(g:#+#iuaQ5l\UcRE>Ԩ$y p}Xu/V2<]wdaQ#Uq?r p`u8K<װ('E;Z w`0taǁ#+A*:HyfY6ĨUkcvvv׿s\KI@1 I{ݽv0аoۋ( #.&[n"WT[>mI /Tݑ)OྊY J|+몛$:Tφ|VY㶘-N6x3.TNQSk#+:.K#+&xťJ1߱}s$bnwu҂Vἥ_Fm?2_P|Yvo?蝻/1߼q"c5#+)[8)FL"c%IF;~*4QWlӕt8*lҋItt)pkZ{p8_%#.MS urې$ȍ;;/RRS@dQ#."B]KP%1# +[CB1ןUS?#+Z^{r!.VC1iJݻ&@mSLJ#&^,P'!Uy3$208ˁ׸~a{Vt A?#+[Uyᙀ?_JD׆0 ޶= W׳Bk\Kp#.RєʤAP*ᵞ(B_e H"U&9Fg߿S7!b|kDMzUM0}9sker'PFTӏwzf#e*a}c{u|k2z҈ 8~r݀>h;].8*Z0VAE> J!)t9<=O9'+t**#.MEXwydKX+DOyk0#.;?3#՞MXsB5=,D,p0$\؂awvpD@C|Kae(a@E9 EVv(0sY4-@J _D.`MM>pV SQIc#.H%# D`C@T!նl!FɢQv!dX#ÂD#.Eģ%HBl|tD3#.$O=E,Nj HXRrg*yd&5p?GyՋJ\81!g̀Co^!Bު>>g-GhBWz}wβJ[3MP}{-/2GG"~R&(`;"HwE&hn%}D>n 4N[b;'׽qWE;HC>uK8.jGՈ)Ђ4Vc#$zjʆњU=OqTd 0;6/\߮^`'N룸[)8gеcW5EﱖiaQX1ɡ{֕Ȅ1#&OfVx7;T ŚK"*Y3%1HEFieP^8{ #+huc`vD4̽[m!/|@`HgHE{K"Zi6QSxݚ#+MDIHS&&wc:nf! q6De2vh.g'A. H}ZЃ;A@VMg!`뭤@u*QQQFE#+uz/( T#&Tٽk@f`CnɒgC >Y$y]2XubCeM*y{ Xg#qNGȜP;ءʈ)KnkdcV:ʲZث\mjUڽ/:u*Rh^E#"RREKg:O#.Jj^ :^A#+G4CGXgb'2|p@6:$X}ɼ[" Ҿ3q-OV>7SAARDY0@:3['DS@ɴn,G`Ϡk"bw&r#+Vأj3BI5_2툌мhyɹkA>lPDIS0^k~N׸[֯{6Rb66wZ:och+_2R$*i`M9MVer ਋HUV;0 jJ2Y,Co(" 3*gczu۾ג1J2U2`aN{]5t?_[`k;vnf5C^4,HTa ?N9miϐm#&M;@4{6R<#&`rxҦbHo+4QRS"-@t:d.J@yJD\K#&Ǫ{^ODdZ`.L&o*Hٛ #.3mpu8&Q4Ux܂BOAĂ1FyJp껺RK]#+e+,Na)s+vd5=,C{F{1{F)}jq`P3hOSD!&Ec2. l1LFk#U@Tx29GM m%3g`}〭#+Vٍ=RI0#쟣cOcPcG ԘTdD6d$S[WO6#&ĢZjT E3kۻTu7ZƝvsWN N4QUjal 5߉A&FOijS0#+rf;l#&ݳ]\H܎H;?^4nX}!D.ʩb-b lhÇwovwrA9GËel씇6Qrl(AH a&%/Nyɕ X4Qu#+촖s dq= q#.PP`Ȣ *I t%^0\~m;C֎Vn{+uoON.{5m-o}単/JPhf|冖A"LL|#&>-ITCfo ̢JAP@)HP86ӽxﵟuֺ'4+A?z}9llbs #RM*Zh}ݔ1!%,gRpaw_0{u6LLw=]۞7Umb'*8T#.C!K'cƙqB2} 8$ZoVu%rbf(H9QM Z(EJ tɥ^f=qǑRJb)UF[(8?Uc@7N=@V!y׏kݴCCq'vInD5u4##+С-1g^*58;{#+]GJb<01u9QY< TGYBY%:s,E U-#(-'v42kxjLdK;n}'Bԇ<NB*g@p۰0 L50uMsGxnG'JUU;AJ6{:TECQz7t#+][\yoqle *P!H*2AHn޿=W|pop)--,?gO!Z#.|B7ҏAuts vpK7AW]!a_D _RVKYbY3~3+UVՕI:~XT0b/ل^k@+mؽp$@C*/~:&eB'_#S!c9O# (2i ]:k4oHf#(:q8ew#& J=`$`&q #+|~񿋪?ܵnbM $L3),(KОLAF<=^~SC=%T|q_t$#+$XȔ8rvÝVSu8P@N6؝D̋٧cSc色ڛb3ƥ (O:sto&u שd98:NΡw6ogQ3~}IPOEox>oC?̣UtU`wWL X,Y#&c <_>p|?okc9uY-og8'gW*"!\} r&0$IYcy/?.{kki&5nx@W4wq>6sz+(Շ!GN|ϥ %syQw!sEz#Ը#,-O`j19 ӍVkc#&#.}^vDW#=Fѱ y:ǗJ7i]/0ư:M3:oU+Yӳncby#+z5վ#&BHR=E#&'݉н0Xe5VcCJK(\#+H-x.n:nOL#&5SK 4+[6X?({=Tڨ.Uʌi_;!7FC;-!3gftᅧOXbU a#+&;gS>Ҿ+{ikVVZi%(}^C@SHAtgfM"4kmerf+2_W?wD*}}yFE߻V^~򯒨~~ߖ@gxu9 rE:dz`}|; WqXF#&*渪׸ U傷f؂89==A>@AJXB̰* ۏM2K+ܥtčgjk# qyCgrѤa }#.6XmtCAc^gf.,$9o<-NirJ^=wqA]l~S#.yu,Ϥ睴Vrr,rbw|CY(58qG^zg]nuOPc3N=| d9`g sI#&ّnPBQcKe7}wU㚗kiTxXz塭\0-7#&0MӀu@_vԪ #.2f J#i1~TRHPGCxmOTSjԤtƭS9Q>sa͝8ޝ~飅44)D_i؋]iv֩;;i-b)i|Q:p}b}uʩ~7>%aU4?;q(Rc~ə|sOelQog:S8P#.#.#{=S.xt%sէ#.1_l#+OWU\["l)hxs?ƃü$?Ï18ʮDraS#.9Q3yz[唵t|Qh~EMIڱq8\{S-v|&J @\Z&=QX氊db4opdW^ D]ѱ҆T3!w#. H9i?s$vucY,ssz΁ufܼrw߫ă2RVͩ_*n>ݸ"`b7tq~#&9_kwH?j%BX/Hvxd}ԹbTw(,Օwtrm09( },H3ޢ}9^=p}g95:ּ̀C}QA:E"( #.W- Fi8a#& L#. wxu` Er>"?Ϻ/?g=OCof 󏹶#Dohp KcIky`PsR+s8t%ڗ,m{.|=! S IL fDΩm&#.W^T*>ILŭ<"p"#G7,A'u6W#&U{p`7L\"8xv0P\Q:N?HAf4p,Kc\6Ì19Oպ~ig˭Ny ÒSMJiRTZ(W8X>#.OXBD;^>#5KM.25gu&^o1wijs;Agq~F=Tt.#ާuz36rtdh #&*к/G&d_&{av~Od;7I>,=y#.9!؏: rYȉfhZOb)0 Tt^En(e(%c*#̋ 4Վܤ}SX*akC(- #&l .#+z\Z{1y@#&U* 9P EۻId}i!OgP5}X8Q#. dguX]p4j#+q&yB/ByrY'G5 ^5 1ў6kWOvYPh箽׽CyQ{x#+w0LM^ 4 zFtp9߉HR~ (_gg~h֔`KOG?AlD<~t;)15[PX eȍV3O˞_Qm!ixQ~AťGSyWhszח/ {$~g6+o>4R@cH :G(y9De:S#+qwұh0"{-vımN5<$U6V_?g\tzEs#+`}{t?A:#&34l/"C.% )a}~G;ཡ| ݟWf]Q03[FĊ1DZZK ֧0#&2sDn`: ]j\ M`txN5\~h#$}+v7'gqNU{ pԨ g()dxsq#.Pt1(HHilm-z5]EKLL˖Ĩ(u#&ԤO*#3\F|vs(v$r#&N&$ᢁJm::' :O'(vۄ|^2 > dRkЪkS aYVWN$K ܄nGPiUwn&Y\MvRw=Sq\%OprA`<$qD#.PHT#+#.r*B.SfmA! *b-3c %㊀AbR;z[wGShm(sxuT4SW=$=kg׸YϗAO!|"1|AYJ̐Bi:#]4 ~5E@"Ȣ)QyjA M*O]=*,ˇssT#.^B֩7szHAfoXP]5?c ,)-MWx'&~1ӹWu~\D`Lyf#,o:SW'v[WfNk]]!c+|]3R|ש%a0@~2~sms):6Es*T!LE.lhWN01RHctx],e h&qe#&sHm֠ѝw8Y›=!heйB9A[sOunmldx+zfxfMeڻ[kuZ7s$ aMKPN'zH%N:>3M.7.3 pK-]@jX(vbhO=wՂ-o9W)ںV{qz&o%\er;he85⹽C7SpHSpٞ)gR( 1*0չ!MJ$wiX¢I.{?2ϖC?nЕo>Hu'l>._-z4ﵾb":8ؼ}Ӷ\9*gwKܤW(B-Br`{slc'P91kMEFzO(hgG))3HMbLQ:QA%9H30vx5j^$2}u)-Gx唄0 4-bm`N+bvV;Q/vn[iH\{UR&nF,8KEQHJׇ;% {/x=6b~IA؃}t}h8MpwmOh"Y#V,zc0#.S\##&Y)C/"3-jmk_L3ߞ%}#.G eۆ]zΊh›n;ut,W!zgǵi 8 ʿ0t<,#+Vxwϗڸ:1A^uD}[ 9PE[tH!5zU#.:Z ptL\DLmCFتs7 ~x0x`kEm͗d#.'xչw7#&-a巨!!Ȏ؍kd,5)n9h3V(k/"Ѡίۜfy-"ЇTqu=d+$ks%:w҄MG\$ _mQ:Jhmp:tps#&r[H#.Aw: Oizsc.x*sWi5JI@oT/Lb[)>XlL-uDo3r"r ;bzUKl4 A.ۀQmcQinY"18ؔ+n52xllO]WQ5#./ۮ~a׭p:@&: b%#.A`7`'_Np".@0ăFp#.SY\6#&^D8p~3QT[| h#+ 7???[N^-6d[=eEg)#+^-T#+%5,YppaVA\[_Y>35/$^{:shР$O>XQ+bA$(p#&(tA0Dtݔ(qN;SDԿƾ|}hw p;5#+#&|!n`hvq>)vlxϏ>9vyb2 7񭮖x3PX@?a L#.28~яs;9>#.[CpkU:ʥJT8#+x~χ뙒b?Bkdg#+4QRFG]K v6}a#]`ؔXpE",#&B 0z gx챼vne릥@ G!1֌/qTA2CYؗ :\ٴw3xuB:=zS>Jdd(I@`K]U!!S |=N`ny{Ca?:?j'ZU, .LH.-MF@6X\P5HA:IjH?Ɋ .Srsw[ShkqNxj;έ|_~l=o q~ 惋mD:B5kW^#+mPʀ:p`[/ Y=[9q RbU#.. }F/-$?ͷG2a,3O#&Ce~Pg=sv-YR8~ 57y#&jnV Dqؘ4E؀ah%BդiNxd :cMV6.IP<֝g08.cnM@efkZѵF6Z?oqVȨ7RY$Z7>7=v;֔ $_L0s8#VDu*Ƹ-aXFuyZcXK<j}uzgI?;޲GT%X{wR4U{šjelG]L'e6˯Xy~]4}3)d}k~""1,NRQ䴃$'!U!m#&-G;J*]xu)LSٞET]O~0cif7(om@831n%ҒI UX˳b=xax{#+M][zw<B2 m:`1sF`K6"KjqClO`!_I/#&?oxϑ$P/`0|Hzb>1뺫l"}_!~#+4ȯ>6S`dqC7K.RZ@#.Xb P .z:_}JT󊼋&Bx .t)̂@RG#.hLddhMv$+0#&j!Hs*Y:BNpSxZ3hwI#+g^IF@5HȇWO}}C.[~8 }0*I?Nk#.O{F]=M钓 $61l\K#+_-FvKKF2WYYY2'6C }Y$ #+㬳+CEH$LF&*e֦Yk5 #u u:00(E,nʸ"} h0vG âr%xSaA#&d$|Nݙ]}'=YvِLGR!im 4}E'BYf` RE&&I3B[\$M #.'FRSYۢe|eQ>y.JV9I=meYO~"KMz'Y#m)ٵ71I$I2E~znԦF% *ggi`}m}&:ϸ#+]qJ#.Ҍ' ?[K_h6?joy^[~ҩ*Ձ`sF[j#+U٩,^(YΕ74ނvD`Iw1gbPѸD O2!#+`L8M}#&(h ?Qp߂#@#&kwȷہ !V*Ou}>/A-zRϢ*%K~=}[~i=9>XC4׃"! 0w#[cq?A|ꜢcgޟqCwGS#WGpRC)@ϥv; hI+@;;JݳzB8[ $Rd3&_9;bP K36Z>@sOuAOC_,|G(I>>5{k#+#. KF>n{xy|#.>U_>oBV $:+CNd-=Q95~*4F+d=cs:5R'~bwW܎\k=u%`8& zr m{Jtc$=#Cz9p`829rqr1((`I !*ȅDF)(h&!~2s$qzp`'BS/Rq֡CJOg@1XCu;)NQȝwM@mr`%~wDԽ#&^QY>LV, VI#&`H:I"/#+ztJv4S#PQXJ#.d֍0b?7-7ڜ-kq#+!m^*)p>CThYEL#7m}5WZʄn2iEkvU(s_o|-zT?! Mp*3&jB!kQ,H\`t38v֤(ik#&ăAR:rHŠC@=Tr#Dr/W/8#&׭H*ޚ`$"=`P;=^=#.3huԏ;&\ĥE$!i>|1z{P=|<%Ɣ !WABFNaHbzWE/OMѳCqGf#. _€#+K!?G|3<@ŔQP|JUZ*1c8Pd'0*>Pd_xzӵA!]ݯLzi!qp0>vFEqsx]85G#&ܷ+[1 :oqb`f㊝ճPAސ6qFIxZd5S6X<0s9`1N#&]DQdNfH,{SoSw|>^EYߊ q#&(BӁqf˔\&:1`|U+$^Dyϴ|*Ȝ V,% @lW7i&f#G3i-1׮Kn9kb8eF2cU@*U'&*ҝ'C`-};q*9cvV]/w l0;MđWq'ų;p),MbQRduWǜ8::Ed֗ }- oP[8l#&xzm|m2GMa9*Tgzr77F$#yDa#& q7^ہC:!gvb˸ UUDg p9=γDaaA(Gq0ϳA}(ye]1o;/}`P>iwJNza+8$gq <.e(ޟW_ZrԪPMA1_ŬI<-ɖ} _7tçt|drSSI嵂1kQG}ySLE;:{83>P*Z#.iQʞQ-q")rH#& $ Kд7a`⁸fH#.0#&l8f$Ch1f$, UJoqW9#&X8,[HȏPT^ؼSǵ1 Ph+$l4/ͷc'uQq/C #&UE&Puj($![wf oy!urw5ZJ!؈3Ih}~!OT#yBֆ5k)`uͶl؁#&PXV4Q_?\=rwYz< |[0RZz,hDcAd_Y N>pρ@FR=GypLAπ?:9w*l`RHW? HuT<bHڇmITsɫp @79NPGYx`}B#&L7~#&JĀ#&Lu@ʸ|@LRa!#1/8UfSY*y #&?ߧa8RJӕ\xɰTP|\i0&T,P@X$XUa@{W_C]"XjqB-3πˬm$#b B$e~R#+o{OCyt}J?}+(FcH({NDLhd˦eyJwmayx*aKd>"#.+5t&cNHB:xjai*f)\a+*ymOYFg#+!S[1׈0~Pp@Uk&e(Yg3]]MKz#+d)$t[`;.n@?4b6kH`sx@`T?7~fl8=_!az'#S*0BA_Kԡ(I:*o>sN}N\׳ 2C*#+#.KEZUc ִRsA*-p Q_7r,jr4 vv\7|oַc%i{وb2#.-?DNy!heݢHX8Op>˸a1#&18F*5@')3-@$0ՄWX|#..zԡ-;PHN_(K]j?j 8#.`l҃MDixe\̒ك)|Hg5Obh22myl #_ްc"6nIf-gC?+;a1W#.aDk{"·\`a#+覗&6_uGsDž,2r{YqToe塋ko^'y=<)1V6D=41 ;'s#.&*;!y<9@ />9?ޣ&=]%!4vz0?!7@g}Vz#w_Fi~_#&hGY7ZBCV2hM#jٿ8q{ȠQ6P d=#+R(BlM,ϡæPbw,R?PWkT?1 =!dyE7OxD7򐣣$'r;Z9 `l#+`B#&s`$Jt,mi=Y,uUꛫ{v5n3X' d3X2؂݊6@㖕LoZh>e84j^-ʎ4ALg5kf} :)0L]C/dVE\ݱ#&+#E4.W! khl+xɳ|^*_(0{fR(8(bH,d}>:)7 Cp7swm':B&Y̼t\ݽM)*QhPڂHD'5I^en]j%Qˆ#+=VOmТ{E%t0ߣc3:&LP~O}l9pGAݝ0wCY!hjW?f"?4 hp|d "Gc}nި:Ȼ TmQ>~IW>Mr7spFzMJvKاg;8"WXwy$$ߑ hLq-9mbxۣKTd@/(( %7F/)Sy{Sߎgd} #.[ިȋ.vm|4mso^!Q{#.f{ XLy 8R";6C9*Vw,I횖{h}Ikdpud^1q<n2fC M6E@І6 cyz6vKAfBU@Tp`/(\BYǔLY?uy˸@x:L ==qמHE@*ԈSzj+^JyR#w=Ga#%R,#krauY#˜F z:&*`صI#+<5402FB>"*~||DZ#+(XȀHȧɏ<~?˫?!HW)[۷ 0TNwgߦfg_gN9ő&PD-R~_u??y?4ӆ%ꪬ?zXS#&Lٸ9ۜ H:˘v?M;3#..n(43?[<ǁMQ[qŃ[&unWx>t3~bZ;^CX&q[Л1#. #&Μl#&|Aߊҍ!T7dJh)IA_@d&@\ժQ)Pvd7mkl44m~,b0M2̢=t*<P9`O^l㦄--СxͰФ4ؒ\\MPsnj!UŒ:ίσp p3h5#&a0&b1"J5ih8>G3hһ鱻88 FeqWilj^*$#+j$J6<ݤt2<#K!'wv#.uN^nOCUMlw\e$lDu@"lAApieTA @h9C$@F{WvݛnyB#&sDAHzqpM#&0Zi&p#gN[ia=z+m6~WǬ8^H-ir,f?Y#+N·!0m"d$qCֽb!O"JxdG!bJcl4o3Oe%;1&@d2LKAJIs%0a4D*6=I@1<|u`x~Uu} 9J`6&vv q8BZ΢NbW`#s+9[fl@9#+gdڟ~zXUZ0TuBl2ɉ Qd.^fyΧkȤλ(u]v{<V/9᳭1əxOS! usvɄzI幯Mx4v};gi;vp۹BEu /9)z35C dhB4[-۳`lI@[1#+S8.}F 6G]3Pxp rr60Cw%C5vt2Cs%)!ߧ~{vX-E%,U$]=;7j̰SފQEAyxO#+6cF3H9}B}F#+ #.5Z,A" #+!.N=0!_H@&;]n7 Z)5ƈM=X8#+3cD8:ș퇡$MfǜANX0xV+xca ,A43c#+(=RCwo TM'~Zf:Ż{;jm&EWdsL#.4HquGcG}! iBY:B%J~FehuUvMXayV6T mdnXYgP4NϗpX( TPXTQ/ΚL=uڨ+"-R5(3:IlK#WWN$|na3ҪU45NI1PQ,F IPXITTUVmTT7ikR-Ev[U #"s3#.ps7eZ=8τ/#+sѲzw!~#F͇8CZ9XidBaj[lLms#+! #;}Sg{Z&ߪ,B@"bNlslyeˑe1>LF2ihM#.42Mp&L̜5WH~;CoBpL VgъP?ۈra֚(W&Rq$Hcas9+gL8#.^#+x%h"У #&n~.*&ͩ&wOcZҏь$g\Weӻ{ƚ p4ف %!߬)COq8]=i(" ?ZRfl!FR?j}0Zs0|D 2U)uoݦ,  @AyЀ_L i!hlcMgҗ#9 ߭Wps{!!%-z+Q`~5?HjR#+DQH <)7xoc\rB:j7HtQU&A@feQl@&H3B@!#r`DJA6nf  Cd ##&> >\/ G9'9$eՂ!X$Nݾ6˵zVBFKXsk(0.$nd"-oLhc#:͛_㘬;+ET<1H =&GPK"?U>I)L<&zk7 :WVםw캀mˏa(d88 `@tUB#&A!)#&"v@; ؈ Tkl[[_3mF#.o0C#&OGnVd;e(ijĪ bu XSHh "6,,7PPb`xJbǭ7{75ؔnIyuko7Lsd:u^r|mVV*l@(I~#&=.<R~'`{ Of#Is 22QG״4=1c.ʲ${|p@H)]L@}j1P$MfZ&_L~<ָ;F[!V浍?e4 geCE==r݀ %*c'/KGc80!lyW8&̆MudAd4{iSsM,).6˂AĆ=P5=<1Xz-kfvn)qC8}Fu'~1?0Xmj$]]XzN\@$!j=?8js@Q{ÿq۟ @~ޘpci\O&Nyy.9`UgİTQ¢UMJ>+zBUJ);:Art<(uA/g)@$PW! ,_5NH1bRHKG| ƑrK%IY~K$mg-gfHꊸxul owd!AK#)Qhx)P$$0[lhJ#fi&$bڱ4%%k#*4ٙPE #. #.zM&-ʓ8k#+;d@V(#&@8+}~-ƚh-!&߀#&dAOOG?XyAQYg/b*aڴ@@{1!BUCl9c&Nm(^(k G_՞wQO6Gh1ai'CA x<Lb_#.S U'3y`$(E -1DPwW ;vOa ~"T4I!-A%O'%8Gɫ괲:7U%v7ՁXX69xG3 E"^k @1@ɓ|ڿ3)S[`̛x=d1"w;i YY_A`e+#%KM_]#+)kc72)滛㖅`蘬7VvM^#.#&h#t΍qլGֺ}u˒8u՘Y{HۭT&# Ie;o}Bʺ<_fFW()мǮ2ܹc=p&-t#lAÐ{#.w;60nljm>ص;Qcn6#_{>疇BB?3NBob#٩Gs`KbsaӞ#&](!5oZ''nTBq€4:qVϬEJLU٫۫NVs!Mg̯n}{|\2'קG_tM;HEm -NHkgf8kӎch}\-}'Q~06B2`g5\Nzϗ'-n;ulK w6%9p vk FNƳ. ^@8iR:$];#+n#+˪i>Ә_CȡP79)בKDCgN"g3R)Y1٦eSuB{kv=G(pDA 0LzI=?;ӷN۴LuztG]:a ~ƶȢXZ FUAD^Uzˠ,^0yC9P+CI:욚~k"N(D;%OЎ|LyJVlp&Y?o^ioյyQ !Nn-jڠh@yʱ0K`jHns43d\I]MFښ[]/-P+#0+#.C-%4u۸\;uK(#&BX`m #+Z3 VelDSppSgu=#+oof(|RE"#.WK&m2'#&\PDHA6\ϵNZ@7٘LqE2LYX8>P6xgjӺݮ#"ӑBU&$DhZT"XRIP$$0@'@KMĶB`%QR#&(A`xbP`M,[hF'5o$(u_7C1˛/Ɂ{qCf}#&GWq5nLM,m&mUUO0zI+u/C<[;'c-=8qu#+݂Pnj4|QYd2W?v#&L,8fHZ?}fajgS$.vx|ޟ~PlHTt#+8fy#&..%E#.]NI6b($X=h,yC.,}_3bI ԚJZQ8L}D>(nNz tkn/|+tjن!i$NYK' ۃh#.fxԚJ)jcdOH {ʪvQxհIa:6tCUTS#&)7nAA /.!!hl5V6b_4lXX)sC n@d#+sV r ( HWóLHI\Ȱ$#&#.AЬ hm) `BFW#+#+0dL0PqgyűvaL7,d-%PgڷR4e6Veث(aKK =6[<.s/x(D#~iȻ7a ,_#.^Y6գ6=OofPNή|b3hE"=] }fdHӓ-#+{juD*Hk|.\1,`X#+<'PwCCVud}szĄjC( vq"`P*PCz{OH =NE\A-rd9'|=T#&hS7*UUzK"riqJ\Tb"U`bzeKLsשs*-DxD s/\y6u9כ۸/8B\ q#&2Q.t1'?]& qi(D˙:CJN9 M~[SkHAb#:4_hFDiǸj(vז ώ xUbiUNd022 %qHMI\uioi78p6k(ό`e%٠cɴf1W"JxŘxar@w)=zDRF:,nlC#.ak+1 4e#k FHB*4ٳF+hT(:P{p`utS[k4(Zj#.2Z!FN'1 Mc5!=15즣lme" iwyAєÆT=Ƙ,FJXºu#&ƭ$5ՏOH{%$/D3fKb&T ^P\aaOmf䀽iQ%d:A0h鍳Ů尐;cjl9Ż:""#+IUT!PH+#.X!JھVM˒rZE#cm'>X4_D$жzU4u(kL)jѹMF#.ta#.I&dl;:bcջ3ird'D2D܂l!2!L HR#+ph2[DnãIvt_,nLU# I^LƭΠst:D܍c8C43:W?#.)$8qÐ"%[$6@r .pH,I.gNg@hXCw:x,6#.dbQr2)Q"hD$EJj#.GH#x#&a4VDz \Qffy㮓tn~?,#+D7_V%!]ІoaKeprccH#+#.plvo?Rz)PlQ,D(Q#+"煠#+&3Ғ`â4!TbMD1I# XDHUߥ {[[(#&cH4hbӰk#.$@ hCLAS#+Gb^j#.㐴?c¨Y{ /NR@Iu `gxG?9&r-ժKxSs/⨌^q2Zv5#RLf\VV-k>NxA"vOb $VUsŷX֢Q֣[W+j#.HPкϖ\NCZcZH{$P`@3#y32g\D&Q$ əLҴ2JRiMQi3P~0 TM5(d(,k0ɭ&,LɉfH#.4"MDFY)PT%ңELFhL)l&%!MAALcJho_u`-Z>#asS]Q!TC8g 2D*KJ|`I-~3jb#+ޒyC#&9S]#&P?cː<半F 8h:$|LLO%d]+Jі0{;uIwU߆% MT0рB^rŔcLd&1Z#.26VJŊ#"2 HU>:u305@|&AߓQMOqMaYbE?="#+ v c|v#&7H `M>iֿrCxepdT'J_#1h3Yq<r B̟ZtO#+#.jQJA($I#&֘pIGlUc-Y/sqV}ǎDDf;*Ï12φrb3y Uwp^%'?r AiC3;?W?7;]T e(im4&7ގX8\M|76[Ũ%e 1mG^c.["^7L,1YCt-4'ѯ shcd" "=OD=2𒕇<:gFF#jv#.gifP[]tQ!OZhc%dd^]$@Mh{~Lqդٻ;q5@Bv UW]v>O@5vcRzҗ&YۯY鵗A9iU,FĠ;DyOFz3M+WR{AX#}0uRu7%a*Jk,wQ$UXa,Rd@<#+{;FD(kǚ+Ă"05AdtVkbo<#+{<:$UsJnm'Ƶ#o+2#+hm5E@SKM8%oS)2̗0ғӥsN24c4FвCѣQEMJ5)ֱ,K,y hw1mkyĭ)J jg|O5Y.N0]7KŅSc#&D'u/}aߋ7fKhzIY*4$^tpxyD!yT[ar6{P#Orghɒ5`VmjAٮē}9.F '1#+pcT 2=hbz;;i3Uj 8|#+pj`|$;tـr3.V:W<:0jF&N&_:Xx?vhF98t`Bkց=,Y?, ai(X \o !v;m&EEKb6&SM` I矙=;f "cc9ybLj-Y5ɜ^W7N#:$΀tmU lB7鶱@๭b#:(.$=JL%j5Sx 8$FgWFգi79[vBzv$cc9vn(}b8-])=7A֙Ս&1u*NDMlɠBe|j[nMlm͝]a6qas;}޲#.qs31\2:Xpr\k(pGSb)'BY쎆mnk-ff3}PsDCϏ58Q=N3.f(#.M,$k˙qIenTϟI1W i#\[eaG5UnQ[ZB9H4q:jn21 O)&PmV\[lf5,yULb0vB%93sKY){e݂\UHkέWUy6$zF{[a;;Qp喪p cVR`Q%>PI]Al|&"P&zH9/S@M@SbML`i44C*7bÒR6x[3JgH4H)(Tӕ>."qݢY^[nrm3Ձ2#+F@Dı{$;ڎq5bj#.r AROݝ7#+QcsJ"Z=$#&4û#.bz)|`lTu'CThB&Is>%zkj$Cw@082uCђta+HEL3 ,pty\)&#+7`kU6d4X^k0Zel5djfe24҂[%3j"3Z&p$BsRm$FZCjl ,WGd-05z9.F'6a CV^)њhՇ4W 48PO*Ubx\ (NbZ-1 4&pL*]L63L˔ͨpCd16Q{eTělZV)m!Yjqd&rp#+yƟq:[!͎ @:4cC#C8#+&';R`V#:N_#+VL_uĿ57#&ІӔ&QOIghd㠠+C:8ֈCQPOj|"ǭfac'%P'f2SI#+Q4.⹌&HR^(e)Er׋WTo5&g&Ԧ!#+G]¦BfkL#+)6ędcl$6m./Xm3oA8TX$GaJ9nfB8?7]2@#..׆uQC(Cb[8J)9 ,ZfH(cc34bln6G̽l]a+*P(6b$cвN|C`#&Dl<89#EƎpUC;MMBc &3Sǫ$.&C19ќd͡ufEZn.&ı#+CFh`dωPBI#PWTv[ 6.E9fDp12iDp9VcmV#&.sӬ`),5ә&B@%4 %eT#đb AP?IMPDT؉qґ#&#_G';(#.H#&+D ~r~@ԉ#&8M)?1""T@TX!f#&ʁuI%H;ٖ{L]?<,OzvʪL>%i?# u,ťkFw-Zmieom4/6c`Crӕ#q:lw H•ɬ3.1r#v[y-8!B@GV7נ EC@RCA# sCuXU#&(iT%%D#<#.@PwRʁ"` 4!;)EڠKarpÂZ\aLP_=n_,Wڤ kCkuݙsuvb%l"!H~C֠$(PY#+o?Ux !pPj(0Q{XQ1.s[q~#+>8yFؓŽ b@ң##&l#.pM(.,x -Fh2!M1XR0\-ibqrqHP0z+tPzXOʆ|)l![Z @QhWY&QDy/$Q0LHlX6mm&A$DܦH|^Zr.{p_CikE/lV n.rl9VW"ɽM2eZR,#+;Zmݛ$ .ƥZQWq٠8M$iLi[xR@eo$)FV;c d+.! r.p`p(q[&&IFcghtXJ 2& YKT"2 `LXѱe2B̴-6 +5ǵ\FܶӭT1,,B)U"B*IVnru?9wcBPkj\*ldMi6r@1ǔX%Lu]tyktMͺvM`+뻊Mk&Zvn̫ɱ![c]hTHJ)lԁԂ-[LI I6kcZjE3]K]+K)iZY5Tij-P`S4m*-JMn-2x+& t` 1#.*&khRJ"P#.!" 6|;{,ziRó 35{MNAߨDuYHHz> g/!Ň~zic`jbŸ@bQpQUN9*Gvw1KE8'-JTDBAjRVe@*2 m}kr%da{A#+ r0 lcjؓip& _ U5l-N]*MAw~ ʨD@B~g;G犀jD񝠫Sڭꗮj6=E(DLoYC-Y&5ݫ\m+Ki6QiM2e2R)e?*#.Z͡mmkT=qF5RPn۱" mm(iMjKXSF5*qUuK{I(նȒD-krKF*j[o<#.lMe¦6[-&vmbH']KTI|pzv"/'OD6TzBC 7 ~ms݋f͵11k%(ݤ"+ĺL:4ac(t_bȠ6hJC #+4$yNg2%{p`ۼćJ y#&T*D#^6j#+pNјER4}kDdXc1"$]zD}}^Fof.zyɁ3l(nؑe?B>eb\)VᲁnM#++"Rg#.UR`U әmd0Jީ"@խUՋR7fGHN b_jU%h "@'GLI3PiUE"@#&#&lj=>[#.X"RFD$ĝ\s^Xu\V*X@/q慡$A,7EvT*5I6M#&GP|9&Ƨj#Y#h˖nG5 GU*LC(6[><XnwP i( BXZ >ݛ2^}_WcMAp.E.#&$A@* GvɤCϪm̓*<HblO4%pw#%c#&donNE<)-%"iyHv].Jf./Cj( xvv~;Q"{β괯:$zN8cG>"vP:$!$D+gJ`(ƋSRI02h?c0TCfk0.m#&vC#.- 2СaؗܫU-*HSkr$FdU^9gw"KLm+sv#hYdȂL[\KuicB}"06#LLtcmVo*4d4I{۹KnHc,q5@kZJ92EMjBSI %1Aa! r# clKmryT\5'Q S!d۵Ljcxb0hbF40 0Ԕ1o8p<#+ݛ ( MaTO?0M |c7!"Hگ[s\,Y-]LeW5o嗮+XlTt,WUQ!JŊ&(7a BQf&ړVcDL@eh#&R=Rr4SD?kkaÜUMp*_#*\R#&݀ D ,e rIcQ-U{@=S  и~NJC7e鎌V$K _lPdqY h/,$UT5At66F;*4\T-'^z .A.Xr,sO/H)QP ,5s#&JMD绉rDMfMtμTp~ܱFY~љ'"ܘ8:243QO2t'Ξj}`qT>?#&o@HwmmBDa[(0%&K4kS[KRlkFF2$2ZY-[6EY%lb*Zmfk2,IkESjf&Vhjckl[I$R,CiGL"l65aB&b.8="ZQSmu95ZmZfm*.^Z 7z[#&5j!RZܢR[K|U__ĂB(ed$\JAQlU*ǛA< bL) q= u.)x>bw)Os1P$P)QW;3=i#+aخ'>B "6T#.܈%KtD#+Bxx Q;aϖ,3`$4#;ZpG\H: T#&=0~#+rpd`w.*}XXPȅo>7Ԫo"vCHLY"Wum9ZkZB.Q.haN #&lkg:$kAB#.PPv3V"!А$p-#+%QEn,MEʝ96|bz?!uY{(Ѳ?>ȧSHe 's$I1sLHLB^^syhr[ 9+S:~rt$!B4-yIMˍ˥TUcը|pR(aE!V ,YF"iIrZ8oBL$R4㔥2,-}:|wuL*v#.HLM_Wd3="DZlArSURpa-Pji!(0Mjqo:xlɞ!LBTQmAgJ&)=lr>F"uzCUI#&YḌ[!/ܲ+--#&zh=~WWWblv4Y(}ޗMS,SЩ [U۫ޫҘ%-n"0#+BITm,y(֞mo.Ks`~@6/  `@ l>Ո!1Z#g̕:64kR&ѓ=ۻz+.p1}b*eƤ^;WK}cr֖[3U"U6"i((DlBal҄֩@a#++(s!ˍD6j$B@6dp nՠF#+ cWn%ɲ8PԔ> C&f#4p(j/28)h d #.X@$G1%<9y;g` l}>ZXH (iJX#.lqj,!yDɔĮNh*| Fo+4Tk%lLlVƩHC܁d1#.*#&>l,-R2Aڝ,9Ǖ E͝TTUeՐ{ĥ8t8uǀSϘ:2t;lAyg?vk[MN_~k" /7|,5'3[MePaO)׏Y1wדCePT@L80MRa{k.8n$&Llb|1Fy7ðwd fF3Tbx#+VܩcΆ`eYSPOYR˽n|MtnuN]NqvAmPcg/|)"v{kwxMZ#Unkz~/AP<{!d%]SCKbĦCi4=ɍ3c9ZGMhfßԑdЬƦF0LI=&r~]TtHw@l1g>, 1#`„U*$%Bnu_מf/s5Db;ul{p=*vyD5CN7tC6aXB򜐤XtlX@GA`F#w#Ij"&dy#&CLx8R7ǁl #&B_aHsze4T(fIUY,AvSR諳̜87Ԋ#+PV/]Nh_鶴>9\b5$2FVNC5gS)uEՖv !yć T!n&̊16f&7Ch:qeb o=sw#+b#.ȹKG c+s#&Qw<ΓWv4UYM:gIP>2r_J0Oq%Fu=eC#&'o`!(S|ٗzо GDXwH\Ė.H(#+klL/H~HU30ֿE\!^HɠP؟;$];`RÖ$0>KP`H#+"$hˢ5877w29ۊz dUNI:.̎9\5+߮g-MAHfFn4ӑ5ebHAbjb6z3M&7axAӥgLeXdb;`1D$w~P i=RuD,˃S›1u7LL7&?fJ;Lrpp+f7\#+~oC:lK܃#3ŷZ$lрд%PZO2!b&"ui.NcОkP~2G0ݸFV> FW#&%yBr!LM"*a^ˎ TT>cM\a6 $4VƘ Vf8Oq!vƿ7"4<ِy(]#\*Ȗ꧟L*jFG6U&hr5*r3#&~G q˿M$RaBmf*3T̆>9ȥ5MRiELXBoy(0 u33]#.lrUTA|d}^D#"D:Eba>L"$juB_HU#+"tr$l?֩h(VPPp!?O=V3. :CxbFH!*EVT^}V1x05@a)* *#!5HE OU}/|ەJؘp#.4KL]ŠB?MָXL(*ǃ,lmJx}>~^Ǹ#+ 6oa#.'^CxͫC᩟n.UEfQY!L2UP`CMZYIAO8{cx5XPCpPiiHڙT4Z5 6,hB_{Lj7AeFo lIDF$AQ,ZJ0`28hJCZ2#."DG$Q11#C@ghk~ 'g"116 s}ɹfVt3i2)EwOfJivh<_"&ZLmeC,WyWZlFTLlbԒEldl̓#m]W&ܹ$n4Ĺ7M*ZF{͆M3PSIyqE:錇@PZ`4`h@4Euq"4o-`j[Z`0UkH[yIQMҁp&h\3 Pֆ`jql#.A!ZkdkܬD(G!cٙdXqw]emxi5Q2bCm#@20-6aMlT2VDVm&!#qm,d3-$z:׍^]Wg||c&vf\F o C+vHݍ ̃MN qT7v:V&&9kckR"5`il(AQavmLpY4jy8O),t#abY#Vnmm8lHjƚE`b1U%SgB ȑzG J|#+;, CYx@>GX([6O; 1s{xy{qҺ>4qbƨm#.1Y {Y#+Xy#+!M %(iD@*#+iR*#+ HѰA(!eLJsLI.%7{ΝG:/J>K2)9u)VEb?thdh#}rm5(kҌ?b2@dpE5"7md֌R3=L7\7M^O7ɫ:)eY)w#.O.[nQI!s366o*+x6&gqƎ):jڋ2f'OD@U6dI#.껖CT;ng~Coˠ4QX0v,h#.?rtDɏ.A7)g>\M546jߪAyODқ&ZlHni!vE]" \Ti#vj(e$J陦jθjRN"'yH#xH$=2((.d@DѰ~4vBuJ9"j(6ݛ[Ij*Ư:Wknmݹj)KiRqWwjũ6Rů+i7JmמoQV$`[BJhi~L[BsK9&-Z@4!21E#.BiUrDa p) ac WNk]&hh.Y-By͚c "#&|5T5Hꢛ(LJbةZck2hэ3T%D̘MF̛ fƶ-HH#&Ci邡>oѤܪ4TmI$"%s?|o_s>P(}"tc{-1aܿb@G!( 9L#.Xy J]?o-gݝu%-mTm&mkJW52#&ZhlC#.p#aQ#.#&a14HLA"#.b͋7dT!&d75B[%AsfrH #j` s#.+Qg_=zHn&Fq'#. <-~}!##GK8Kr }GֳߩAG"vQ6:k, mt}AlxW /)CpP#+Zbkf Ma3pW>*0ڬّ4&!QU0i(6tE*R0M,T dpL&`U~WN3wïXGw֩>ʛ&6#mѣ#&3U:sNE0}3=|J sUtUݬES#1 gn!Qjvp6|.;#+r#.Y! S=f;ɭ}Qci^yydeW#+(6%9"i$l&ʖ۴&EՁWIpmHyS&s:?%K9Y^`ҽZpؑ @ԑ,uZ("DڂFaQE(8 %" ?XPSD#.@ѶHΕ cuHJJIVk1[T1\arиKE$ok#&*Kr׊MbYP$Kh*dEaAUq'wjfdl1q PZ@1pux2+4i>8mvƓ75R^"*#+- HȈJRpC HkCnݡ.cGB?6*$#+V8R%_a΍67,)C#.a3MJVBCTBg[X? ta$#+N*[`QYT#&@"ăDUN!O(ҿiW^v[#PZsgS1f`-΋zm 9`#!*Y ssG^j)JŴBҗI~h5JL6"#c׻Rk+S\c.]d1BH#.1xm$"uG+6-hg'~F#+#U#.l+ݦv=Iz:i }A s'fh_ Qd*89nh 刲"#&HR@A'*}r@HwtT{fs:lo#&p)%z/(0 AX!`4k'o-[$#&t> *h/տN=%XXE֥~F/sf<<"-Q$H@P6~z0#&HhTvء[riL昵yI)}'2eyT tj͜;*ɤ͋3dsb#+X,S*[@3E\#+ԃQ#&0,fщ>Y;ӽ6(r~?msԋb۲J ۷`ESI87Sh,ࣙ]\="=Lois EQ$0#U90${"ߊ%G1L},jۄ {YƇh;34 3qh(]aLwTU5yT\@R& OKfZc&F*h;ddvg_VMn{C7F\FsDe&fRy4g:y޴l J#.X1=I7F>Gf;rngmh{:J@Xe_Q5xH#KK0:$7#+}y =CAѼpS46c8CgBub`^r{_]2"8nbF#+زňaf)#+DFG@#.#.K#製&#. Z#&#A̪:l %OY.YW^M/kང|#+i3bWBD`_&d2?=KE ZG=TJ"I YȣwMD&pldLVՓ#.*>JϹfj|P?C5FUUUUb/]bfCJI6HBX$D5'*jե7Y_ЄO}^M7f-}#.곇x *XL:8LycV;i5mv4$U*v/x<}+a"STg!y&`c,bCh(41 .Lΰ2>nzf%OnKwL(@@PmcZʄ;NxUPݞY-۱#'|4U(ZjyBd1>;A=\q ׯ Am#+ P.p'}#&ۃCɘV]OP߈] "$r=A>@?V#+H!"B"ȑYCizO~8#]31oDocAd:rvK6-<"b[EzNEÊ;;afc8vh<\ w[g3#&0ŗw4vęL1gҚ "EMl#+䬁1CHI$#.ˑ gD=|qQyQi-iG윎8_@R!|-`@;`#&bG ie l`'rA&@s#.n3q8^!` cW8?̬O)ՙڤk U#&i@s YCAy0 ]PN#+WIko߅4k3>Vg\6/~KэC)W;dBHF t*l2Tcd8G[v1H@2B33|ђӈɩZ@%sKK!7'ct΍mJA݈n2 ŠÌc*>8J b\Rg#+,ѷvaV #x !#`sV*\̉|+Np.4Єӧm #+w_ʤ{#BIg#EMY.1Zw&@*v㺌@E##.NmigL?]BF1$8xnxĨ/$| !7`r~U&b-[5jmVE,ۮx։$@aKso7ECD=u*)_?G|<3(͒#F`,A4%Q(F6&!&͓aJ 9q~CdٓU7؛om?$6Aah89Mm1cXsȊF*ܛbߦc~cޅ0im@@{jE#R5sQ!ѽLBV̆L_#+i5U9|QIPc&Aq6:ITk&"9M6{}ќA/ο q#+=aAMm`sƩ$_2:p5&a?r H-e*JViƔpMVƁA 7 MYrSrwKt,m!4Дlpc."-S#.Ead0 bD@P"!ۢG{ݶ;I2p*[m}Y&veFZb/#.a"jHl(4TQʌV\1HOYs4i~/Sւ0#.Tr!Au%\mpXoE+#+aV*@ܨtS43h\ fDhMV11!;ނ_ s"mQuDHe=64$҄a^JiS(&M9Q%SML(-V+$H#&"F#(#&vPmYHj=UBsugiPX+E"W^b#+3 @),R+#]]6](tt3֤(T 6kT,(:QL#+jMH~, Pjnk0qDGpu#..|-G=ٛZ\qIź߯P:[׳rHֱ8H Yb>$=Z#SeG:#+?`cٜwju,ktlŃ׮ߎΒ/KAs40Qu) U#.+N1rwP(m`5Xu:X%DSkmiXġw Tڤbh8aɇ1J5/m~6=#d>R-seUE_':Ʋ-\2&|&jC vXOŬ7'#\gM&Ƃ,"BCEu4nTBBZ]qY|~_Y- [-˻Xͮ[tՐ66mk&r\"6xUiXYwa:dj㞫̄қ=ab-"lAA +M[x.$@I;{vPpwU@_/(._b!Ƞq@5!H ѵblL-ormn-wntNN^4#.Z]Rw MM|eUcUki6@REA '=bDp"AowQvĂ$"0 #&,~*X3#&D?VQ*rRӏ+0qz< N$֭yB^՚*07ɫ'ȞzEx*v޾'#+'ӒKe!S#YusSU9Vj!~;/dS=Eh&OigWP!>#&샭^)L~nѤظ#+TYRHTwQlvr㵌`n=Ҭfޥsqv#&ӆuzfUjW(O*灙LHh`$q8ܝu=yw4D d)ULHuzz=ZjM.y~2 #+L>>~ٔ=խ-K(CtTl p,5қ Nn(䛊j%t;;kΣٹ;,KH#.lg3H(ma ˕SaCE8t\E^ZBH/A9j]1H#.`B%pX5`sVBZC/ yo#ߣ$aCV/JEAHGq{>yI|k디2Od>pjC(!ǷĹW*}b٬dH9f#mFrO9Rxd]0c$CSUY'ØE7,$. xmL1:-s6qefٍblC"q81Dlc#&~o#.']Ŵf+2 ڧ+]4Rw[A[i3}.ΰ^I'f7(Z|KW5N3Lu^OF%*1Q9JRZ9궖yOwf+}kSEs6$ lu_֜/"0Xjщ{_z2J"2ͦQ,1WZ%m]9NE,ʪ짮tDkʪ.IWln`nk9Tln.b;4eFW#+т MAɡ\u=~"$Eg8채 dӊ;dcNRiRgkzͅႆazFȎc&Ls)EܶySۑJ[_f7LWB\ 2Nqm7J$S0N+͗G=izp#.<=Qa Bv{vc4Yѳ)qGܓ̇sR&{)Rj3{#.8pQ G4U%5C4qz;@vD5@._ DB#+#.j 6lᶍ7\yu0x'y,P@` V(ScA7hP7 rIhdLC*#&@=*Ll#& "<Έ#+;N=.'qgP`pG-7ʜJ5)#& s^Zani Y;2.&9]|;ɯc}vu֜Q=7P.k1$XR@dYRs,"4=6⩶أ48J6[j$`F%O1z֯%\^.EP$)!"0HQUj-Z0lLYD M`501TEE#.A xyb39#&0s˶/#+'I j(/oxۑrlkKmZhhjUmU#+2nFfpP:X9>f۬x)o*1K+ud/io #+hHif-+W S51%Yx:`@,׌ǓA,Pd$)*2ʠ+ƞw$KȑB#+aDi6K)a.+M1@%rQSh)b)$Y/O[=(M , MBfv\jV p#.1{zjSLxk,f4 #+EZǦֵdƲ:kV=N8[+|2`!P\dCyg"48/6YC.(+mI%|kSrvnѦ²FN!#.A,TAj 8Ƙяv4!BmLNE rWZhE^̱j^:G`|򩨰a!HsCImڷE/&ɺMj)5RN)KIP*BHsP(vn$?#);UN걛ոJc-?Pa"do_k#.zk~w+]:c0ቑWy|Bs_J*5T#+_g?VdO#+F#&G6uaD&rkm. ?//uX(6Z\\gÌ o 0۳cUS#+IcxpC(6#.]/e#tE 3`t MG]zoQmy(jzƶ춒2/.ںoռW܆I#Ȉ~}^#+#e2cƐ-jV)lڱIFؒhŠl1 R4%4TF4FR%$)*SdR I0 6a$լU[7f ́Gs4C}(Ǖv홋m~sxBFn@!'{v8* HZ`mC`^F8.Cm݄Ķ1)!``1xʆ }еI(#ճhm+3i!!Fw`rªr5ZG$AmyTԁқ/Q ~Z5bT #+Q5m1?Um"BQWjUԩT,%w xDHAT}̋fn,[#.  B;#.-CLaѪƈ}N.J82V)#fJF(]ӖJ$ C(H[#&PFlj̵%bĘZn#+m]ۡ'g5kь-!`iLd߶fc4H]0VB zC״q>N&|P-ٖ*@ݮF5#.LF5D#+?߁X s'܌Ra#+ zmsG(4'xbHjF,clPUl!i0X&!8d$Hɀzr&#&31ҕ6▞z{)mû`W#&{HH4)\|1D#>Stղ| K#UCۖ s3*AjJbaYz#&Ċ#+r UrvK<߻G<X#IqGd^いaHFit@+i1Ћ:x֦SqFG(X͏i!"{zv'uIɵu9^ FTU*NGש?3G&E=@y{pq;!LQڱ6]^"- _1#+݃Rj93> чhOxEAdULq_#+Rb_kTCRGႠ#~f8&Fl%`:EgslԲ]4X`C$0[$z3t=pxG"{Cp~g_#&O!7~9r bQWIq睔zJ IrqJuN٬#$l#+=#+lWipϋ6)N!EU89YKd0Pp !K I ̉juV%"xQTNr$|rg&5I`$PIV\0H+y^Py@p,@2g#3c6cI:Lûzb#+l7I:NJֽ,r`n`đ#+Tp(6=2 @JdD˸Y&`ژ0:)IQ%cij &/MC|ȹ !4V(@2ByfkQcb#&FSQ?s/F~yvE2"97@1-$TLNIgl_NVqLɔ|e)1>}~Dr 4vkbxB9aYY0#.H2#& 2)R%`Q-Tik[Ҷ3ujVJT)k "usGlB!`Lɑ;:X#e\$=#.,dob9Έ#+a]V xD^PMLa\2s,'#+2NYѡW=RGScQLěI ݶi`.J@Z1cvL4f\yFD"b8dlaQ{Hi4h2\!A:Ne;mKL#`%lĖ;&v.]=˭`\btש" 5wʼnw'7q$[uL=hd4Z:}#pz8̫ <8%8g2٣ D5Ӛ,g V"T^)Py-؜5vO 9+̛OHvks CV^q5u֍@"e]9R̕*8iȊ!ȷ-mycD)ns]]ʁz#9 XE#.56ɛ ❷1ˁR.TNpFXw0r:^1#+25!>Tp8up&H X&=r("c^<9f~za@Xh( 5#&TTC>ߨ]#&'QX[Ev_.ꕝm+yC,#+D- әe7z-Fpmu͠Gq&`~˒@!|f]WVZ䪠Z 2KJR+ NpVaQPà=k4A6M2p#+*J;dw*D#.D*AYb[ZyZE4ɓ'k>#æ~vaAA k#. .)}l^Tp#+{󳵚Zcci7wt'}aWA*1߽%9q"cY`g,\y ^!Or:BU+'8X-C(69 0;Ũn;IZ0b#i`+q!T1Ȕ[;"e1 #!K$)GpV@@75fAhpiQ;ŊMK(4\UD7(b4j%B.$R,Q GtuuCM[U>t8 X! E25O'I;[b!pU+D2S#. R72hqZ((6' p)w2ӹ)coQ,$_4Ci3+$bE%,0yF9qlՌUjYT0GeS2m2n9PPQ0fIzW$5)3pf`age2#&WߓiU##.Gk8a4&t'rTDdQa~[uj)(kJBVIMj6݊2B B6/c *D$EAp`^p#&ۏ)#.T` 񭝦#+9gsk+ b "Ȭ!|CSEV o ?@b #&"jo<*xpv78k6 E7#&u&tʧ/s#.08)`-$)F6Pm ēaY.UZ((Gj$Lgt*uym^dv^eZniN.9V! hTua ,-kf?vpyy.jϧUGYg0ܚW#+H#uYoj?:PĪf+s_&9 C6(F@^!/MH]({o[u!"B4( M3M$A 鷢`nU6.#&ZifL/Q$Džةtr!;ćADd(ͦRiQP35REuވ%  )v?`l5i"PIA=@ "'" *T >"`\t}avԌV 戎>/$S6RMK-1)AY6EMi+Wt4a7D6O \q2Wnl;Cyn9hirXn[8 " >Dl:i{;&DTS#+{cL$ϾJ#Zp#VF撁%$ԴA#&7MW!jRCδFqR#+iL 57M'w G˹,:"lœqHmo$ʋMS+jXʸ[#&p$p) źt}V2te.jv`h#..PbP2f]hl~qSsިzPbB"Lp=YJQBŘZÃi~Bg:J,`AqȊC!yd Wrh@R#.(%BȐpВLvϞĺcxTNAO#&###&@ U6]{|oq;Hh+;AZ0?EGV @#"7sX#&wQOU׭0#.m%5?9/-T<Ч)#Af^##&(C&3#lDhK #+W0\+(j(ny%s\CxWiZNU6-n5KdOБMbAc_;U||=< ٞ$0O#?aO1^]aӠH2#&BHEbzjQh#.ifJͫx߃UAFblUJR5N%/xʫ#&-2)kY\]O#bCBrQ'Aj!2F)-eXXّV*e'wX BQ:@P"Q ۀi7a=I'zը7<~:aȩXGp ,ìGa#&ށ($^S!EW%`J2F] 'i0&7mA?:!ǻIK8=5(@&4P$P#.64HRkTRiI[NӖ# Ѷd#&AhDX=*Ȱ̲hcq'gv#}=q奥I$l5?/#&lXLa).QFwi.T i~BO&E[h+J;gxxK-{fXҎ7D囶 ɀQD(]C-n Twe7Y5UQo7u3*$EWv46M%L4Bh"%N#.Uut7-M֘E{j4SRezuo:ζ52k-w-XtI\Rn @1TZL}h%M kƪB5Hd>Ϸ)|Z6g$#.|rT6zi2њ)CImY`(^괨|g8\]n\=P$ztOV Ij$B{Lu #.T!džK wk.G" IR&N.αo [30S QrFq/ }z_{I5:kM/]l{߰g-J/F|9+.IcؓHNABR!*Fr8_2$r1+KxPt5x9[ 7$5i:[E!cq;iE#؝bk D uc4;d>ƽ!ȱ|* 4GX0iPhPEe믘W/W#:u`g8ځ6^HòPNlhs-_kQr_#.%dR{103#FOؒ娈gNدZ͵pC'P#+pi+^Dm];ӇG~ - h#+F![J^4:"#t#+S lYE%2D x%\pdlA9qњ4!ωXw$`4/^GC"W $FòB#&rDB,ub;4W[KJ}wQ'ׄBЀD@Nw lA#&koSR$v{b>~ }~݌#Zi{\UɊYU/_x]up^}u?_W~HꀏS(C>at1 2*?")AD\#+%:&+LK2!ZwI Pc6 S#&*êU՞ 4!zހ`#+J!n4ƷfGhlw0c 6D"U;R4p`MB;;tЯk4Bl`sO6e75m8ui+(X Lj Tu|^`ִ&w$$0CoϣV-9R6wsBm6vuaᝲoES|;6ULpGie#.bxE1\^C e#&ȃ2#+LϻLu)zׂ}vo N\-O@`6*ȜgWa#.h2Cyw}XѬLWzK0N6&>1'"a .I<)YpO~nc^ %UEsovs+F< fTPw\S!٨ #&r1j#+nBgibxEJ1r* * PqB@^K&?fd`勴ǍBL8Ckݙw:'8BQiH/5صfʪ6Tfi"ES_vo҄NQ;~cE2#&UTo0X" d{%2H0nH8/-oCuj.hgc}ܪ#F|Dǿ'#xlޯ|-d7#,g=6ϐ#9cq딝MIk#&@qMҝ}4JNiu(sƛTlpFEQW8U|.Z*iIhh^Ӄ͗ iho7exZ@湨}nmczWս-Rh U*N-n:yQ݇&q>0(/#+, H.#&m1t#. u;,\ ,„1)acMpc(!q~;".TdFm+TG7;QqljF#&#.?" ;tF)BLt}剳RkRy$REANgCH"~p<74t`Q>2}#.0<3 )o"WH-&@G#&H*B{l z=6x\#u) ~ʔp:Wo)|\.2`þG:v: ~Ybo1yl%xFDm9Wr9,Qxe_uْ/Y5r׿P`vd%bQMĂ$ voF$']j{\!}JT.p!< #<== diff --git a/wscript b/wscript index 5be7c659c..b1b01295e 100644 --- a/wscript +++ b/wscript @@ -1,52 +1,57 @@ # -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -from waflib import Logs, Utils, Context -import os +from waflib import Context, Logs, Utils +import os, subprocess -VERSION = "0.5.0" -APPNAME = "ndn-cxx" -PACKAGE_BUGREPORT = "https://redmine.named-data.net/projects/ndn-cxx" -PACKAGE_URL = "http://named-data.net/doc/ndn-cxx/" -GIT_TAG_PREFIX = "ndn-cxx-" +VERSION = '0.7.0' +APPNAME = 'ndn-cxx' +PACKAGE_BUGREPORT = 'https://redmine.named-data.net/projects/ndn-cxx' +PACKAGE_URL = 'http://named-data.net/doc/ndn-cxx/' +GIT_TAG_PREFIX = 'ndn-cxx-' def options(opt): opt.load(['compiler_cxx', 'gnu_dirs', 'c_osx']) - opt.load(['default-compiler-flags', 'compiler-features', 'type_traits', - 'coverage', 'pch', 'sanitizers', 'osx-security', - 'boost', 'cryptopp', 'openssl', 'sqlite3', + opt.load(['default-compiler-flags', 'compiler-features', + 'coverage', 'pch', 'sanitizers', 'osx-frameworks', + 'boost', 'openssl', 'sqlite3', 'doxygen', 'sphinx_build'], tooldir=['.waf-tools']) - opt = opt.add_option_group('Library Options') + opt = opt.add_option_group('ndn-cxx Options') - opt.add_option('--with-tests', action='store_true', default=False, dest='with_tests', - help='''Build unit tests''') + opt.add_option('--enable-static', action='store_true', default=False, + dest='enable_static', help='Build static library (disabled by default)') + opt.add_option('--disable-static', action='store_false', default=False, + dest='enable_static', help='Do not build static library (disabled by default)') - opt.add_option('--without-tools', action='store_false', default=True, dest='with_tools', - help='''Do not build tools''') + opt.add_option('--enable-shared', action='store_true', default=True, + dest='enable_shared', help='Build shared library (enabled by default)') + opt.add_option('--disable-shared', action='store_false', default=True, + dest='enable_shared', help='Do not build shared library (enabled by default)') - opt.add_option('--with-examples', action='store_true', default=False, dest='with_examples', - help='''Build examples''') + opt.add_option('--without-osx-keychain', action='store_false', default=True, + dest='with_osx_keychain', help='Do not use macOS Keychain as default TPM (macOS only)') - opt.add_option('--without-sqlite-locking', action='store_false', default=True, - dest='with_sqlite_locking', - help='''Disable filesystem locking in sqlite3 database ''' - '''(use unix-dot locking mechanism instead). ''' - '''This option may be necessary if home directory is hosted on NFS.''') + opt.add_option('--without-sqlite-locking', action='store_false', default=True, dest='with_sqlite_locking', + help='Disable filesystem locking in sqlite3 database ' + '(use unix-dot locking mechanism instead). ' + 'This option may be necessary if the home directory is hosted on NFS.') - opt.add_option('--without-osx-keychain', action='store_false', default=True, - dest='with_osx_keychain', - help='''On Darwin, do not use OSX keychain as a default TPM''') + stacktrace_choices = ['backtrace', 'addr2line', 'basic', 'noop'] + opt.add_option('--with-stacktrace', action='store', default=None, choices=stacktrace_choices, + help='Select the stacktrace backend implementation: ' + '%s [default=auto-detect]' % ', '.join(stacktrace_choices)) + opt.add_option('--without-stacktrace', action='store_const', const='', dest='with_stacktrace', + help='Disable stacktrace support') - opt.add_option('--enable-static', action='store_true', default=False, - dest='enable_static', help='''Build static library (disabled by default)''') - opt.add_option('--disable-static', action='store_false', default=False, - dest='enable_static', help='''Do not build static library (disabled by default)''') + opt.add_option('--with-examples', action='store_true', default=False, + help='Build examples') - opt.add_option('--enable-shared', action='store_true', default=True, - dest='enable_shared', help='''Build shared library (enabled by default)''') - opt.add_option('--disable-shared', action='store_false', default=True, - dest='enable_shared', help='''Do not build shared library (enabled by default)''') + opt.add_option('--with-tests', action='store_true', default=False, + help='Build tests') + + opt.add_option('--without-tools', action='store_false', default=True, dest='with_tools', + help='Do not build tools') def configure(conf): conf.start_msg('Building static library') @@ -64,94 +69,100 @@ def configure(conf): conf.env.enable_shared = conf.options.enable_shared if not conf.options.enable_shared and not conf.options.enable_static: - conf.fatal("Either static library or shared library must be enabled") + conf.fatal('Either static library or shared library must be enabled') conf.load(['compiler_cxx', 'gnu_dirs', 'c_osx', - 'default-compiler-flags', 'compiler-features', 'type_traits', - 'pch', 'osx-security', 'boost', 'cryptopp', 'openssl', 'sqlite3', + 'default-compiler-flags', 'compiler-features', + 'pch', 'osx-frameworks', 'boost', 'openssl', 'sqlite3', 'doxygen', 'sphinx_build']) - conf.env['WITH_TESTS'] = conf.options.with_tests - conf.env['WITH_TOOLS'] = conf.options.with_tools - conf.env['WITH_EXAMPLES'] = conf.options.with_examples + conf.env.WITH_TESTS = conf.options.with_tests + conf.env.WITH_TOOLS = conf.options.with_tools + conf.env.WITH_EXAMPLES = conf.options.with_examples - conf.find_program('sh', var='SH', mandatory=True) + conf.find_program('sh', var='SH') - conf.check_cxx(lib='pthread', uselib_store='PTHREAD', define_name='HAVE_PTHREAD', - mandatory=False) + conf.check_cxx(lib='pthread', uselib_store='PTHREAD', define_name='HAVE_PTHREAD', mandatory=False) conf.check_cxx(lib='rt', uselib_store='RT', define_name='HAVE_RT', mandatory=False) - conf.check_cxx(msg='Checking for function getpass', mandatory=False, - define_name='HAVE_GETPASS', fragment=''' -#include -int -main(int, char**) -{ - char* pass = getpass("test prompt"); - (void)(pass); - return 0; -} -''') - - conf.check_cxx(msg='Checking for rtnetlink', mandatory=False, - define_name='HAVE_RTNETLINK', - header_name=['netinet/in.h', 'linux/netlink.h', 'linux/rtnetlink.h', 'net/if.h']) - - conf.check_osx_security(mandatory=False) - - conf.check_sqlite3(mandatory=True) - conf.check_cryptopp(mandatory=True, use='PTHREAD') - conf.check_openssl(mandatory=True, atleast_version=0x10001000) # 1.0.1 - - USED_BOOST_LIBS = ['system', 'filesystem', 'date_time', 'iostreams', - 'regex', 'program_options', 'chrono', 'thread', - 'log', 'log_setup'] - - if conf.env['WITH_TESTS']: - USED_BOOST_LIBS += ['unit_test_framework'] - conf.define('HAVE_TESTS', 1) - - conf.check_boost(lib=USED_BOOST_LIBS, mandatory=True, mt=True) - if conf.env.BOOST_VERSION_NUMBER < 105400: - Logs.error("Minimum required boost version is 1.54.0") - Logs.error("Please upgrade your distribution or install custom boost libraries" + - " (https://redmine.named-data.net/projects/nfd/wiki/Boost_FAQ)") - return - - if not conf.options.with_sqlite_locking: - conf.define('DISABLE_SQLITE3_FS_LOCKING', 1) - - if conf.env['HAVE_OSX_SECURITY']: - conf.env['WITH_OSX_KEYCHAIN'] = conf.options.with_osx_keychain - if conf.options.with_osx_keychain: - conf.define('WITH_OSX_KEYCHAIN', 1) - else: - conf.env['WITH_OSX_KEYCHAIN'] = False - - # Loading "late" to prevent tests to be compiled with profiling flags + conf.check_cxx(msg='Checking for function getpass', define_name='HAVE_GETPASS', mandatory=False, + fragment='''#include + int main() { getpass("Enter password"); }''') + + if conf.check_cxx(msg='Checking for netlink', define_name='HAVE_NETLINK', mandatory=False, + header_name=['linux/if_addr.h', 'linux/if_link.h', + 'linux/netlink.h', 'linux/rtnetlink.h', 'linux/genetlink.h']): + conf.env.HAVE_NETLINK = True + conf.check_cxx(msg='Checking for NETLINK_EXT_ACK', define_name='HAVE_NETLINK_EXT_ACK', mandatory=False, + fragment='''#include + int main() { return NETLINK_EXT_ACK; }''') + conf.check_cxx(msg='Checking for IFA_FLAGS', define_name='HAVE_IFA_FLAGS', mandatory=False, + fragment='''#include + int main() { return IFA_FLAGS; }''') + + conf.check_osx_frameworks() + conf.check_sqlite3() + conf.check_openssl(lib='crypto', atleast_version=0x1000200f) # 1.0.2 + + boost_libs = ['system', 'program_options', 'chrono', 'date_time', 'filesystem', 'thread', 'log'] + + stacktrace_backend = conf.options.with_stacktrace + if stacktrace_backend is None: + # auto-detect + for candidate in ['backtrace', 'basic']: + try: + conf.check_boost(lib='stacktrace_%s' % candidate, mt=True) + except conf.errors.ConfigurationError: + continue + stacktrace_backend = candidate + break + if stacktrace_backend: + conf.env.HAVE_STACKTRACE = True + conf.env.append_unique('DEFINES_BOOST', ['BOOST_STACKTRACE_DYN_LINK']) + boost_libs.append('stacktrace_%s' % stacktrace_backend) + + if conf.env.WITH_TESTS: + boost_libs.append('unit_test_framework') + + conf.check_boost(lib=boost_libs, mt=True) + if conf.env.BOOST_VERSION_NUMBER < 105800: + conf.fatal('Minimum required Boost version is 1.58.0\n' + 'Please upgrade your distribution or manually install a newer version of Boost' + ' (https://redmine.named-data.net/projects/nfd/wiki/Boost_FAQ)') + + # Workaround for bug 4860 + if conf.env.BOOST_VERSION_NUMBER < 106900 and conf.env.CXX_NAME == 'clang': + conf.env.append_unique('DEFINES_BOOST', ['BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW']) + + conf.check_compiler_flags() + + # Loading "late" to prevent tests from being compiled with profiling flags conf.load('coverage') - conf.load('sanitizers') - conf.define('SYSCONFDIR', conf.env['SYSCONFDIR']) - if not conf.env.enable_static: # If there happens to be a static library, waf will put the corresponding -L flags # before dynamic library flags. This can result in compilation failure when the # system has a different version of the ndn-cxx library installed. - conf.env['STLIBPATH'] = ['.'] + conf.env['STLIBPATH'] - - # config file will contain all defines that were added using conf.define('xxx'...) - # Everything that was added directly to conf.env['DEFINES'] will not appear in the - # config file and will be added using compiler directives in the command line. - conf.write_config_header('src/ndn-cxx-config.hpp', define_prefix='NDN_CXX_') + conf.env.prepend_value('STLIBPATH', ['.']) + + conf.define_cond('HAVE_STACKTRACE', conf.env.HAVE_STACKTRACE) + conf.define_cond('HAVE_TESTS', conf.env.WITH_TESTS) + conf.define_cond('WITH_OSX_KEYCHAIN', conf.env.HAVE_OSX_FRAMEWORKS and conf.options.with_osx_keychain) + conf.define_cond('DISABLE_SQLITE3_FS_LOCKING', not conf.options.with_sqlite_locking) + conf.define('SYSCONFDIR', conf.env.SYSCONFDIR) + # The config header will contain all defines that were added using conf.define() + # or conf.define_cond(). Everything that was added directly to conf.env.DEFINES + # will not appear in the config header, but will instead be passed directly to the + # compiler on the command line. + conf.write_config_header('ndn-cxx/detail/config.hpp', define_prefix='NDN_CXX_') def build(bld): version(bld) - bld(features="subst", - name='version', - source='src/version.hpp.in', - target='src/version.hpp', + bld(features='subst', + name='version.hpp', + source='ndn-cxx/version.hpp.in', + target='ndn-cxx/version.hpp', install_path=None, VERSION_STRING=VERSION_BASE, VERSION_BUILD=VERSION, @@ -162,35 +173,46 @@ def build(bld): VERSION_MINOR=VERSION_SPLIT[1], VERSION_PATCH=VERSION_SPLIT[2]) + if bld.env.HAVE_OSX_FRAMEWORKS: + # Need to disable precompiled headers for Objective-C++ code + bld(features=['cxx'], + target='ndn-cxx-mm-objects', + source=bld.path.ant_glob('ndn-cxx/**/*-osx.mm'), + use='BOOST PTHREAD OSX_COREFOUNDATION OSX_SECURITY OSX_SYSTEMCONFIGURATION OSX_FOUNDATION OSX_COREWLAN', + includes='.') + libndn_cxx = dict( - target="ndn-cxx", - name="ndn-cxx", - source=bld.path.ant_glob('src/**/*.cpp', - excl=['src/security/**/*-osx.cpp', - 'src/**/*-sqlite3.cpp']), - headers='src/common-pch.hpp', - use='version BOOST CRYPTOPP OPENSSL SQLITE3 RT PTHREAD', - includes=". src", - export_includes="src", + target='ndn-cxx', + source=bld.path.ant_glob('ndn-cxx/**/*.cpp', + excl=['ndn-cxx/**/*-osx.cpp', + 'ndn-cxx/**/*netlink*.cpp', + 'ndn-cxx/**/*-sqlite3.cpp']), + features='pch', + headers='ndn-cxx/impl/common-pch.hpp', + use='ndn-cxx-mm-objects version BOOST OPENSSL SQLITE3 RT PTHREAD', + includes='.', + export_includes='.', install_path='${LIBDIR}') - if bld.env['HAVE_OSX_SECURITY']: - libndn_cxx['source'] += bld.path.ant_glob('src/security/**/*-osx.cpp') - libndn_cxx['mac_app'] = True - libndn_cxx['use'] += " OSX_COREFOUNDATION OSX_SECURITY" + if bld.env.HAVE_OSX_FRAMEWORKS: + libndn_cxx['source'] += bld.path.ant_glob('ndn-cxx/**/*-osx.cpp') + libndn_cxx['use'] += ' OSX_COREFOUNDATION OSX_SECURITY OSX_SYSTEMCONFIGURATION OSX_FOUNDATION OSX_COREWLAN' + + if bld.env.HAVE_NETLINK: + libndn_cxx['source'] += bld.path.ant_glob('ndn-cxx/**/*netlink*.cpp') # In case we want to make it optional later - libndn_cxx['source'] += bld.path.ant_glob('src/**/*-sqlite3.cpp') + libndn_cxx['source'] += bld.path.ant_glob('ndn-cxx/**/*-sqlite3.cpp') if bld.env.enable_shared: - bld(features=['pch', 'cxx', 'cxxshlib'], - vnum=VERSION_BASE, - cnum=VERSION_BASE, - **libndn_cxx) + bld.shlib(name='ndn-cxx', + vnum=VERSION_BASE, + cnum=VERSION_BASE, + **libndn_cxx) if bld.env.enable_static: - bld(features=['pch', 'cxx', 'cxxstlib'], - **libndn_cxx) + bld.stlib(name='ndn-cxx-static' if bld.env.enable_shared else 'ndn-cxx', + **libndn_cxx) # Prepare flags that should go to pkgconfig file pkgconfig_libs = [] @@ -198,6 +220,7 @@ def build(bld): pkgconfig_linkflags = [] pkgconfig_includes = [] pkgconfig_cxxflags = [] + pkgconfig_defines = [] for lib in Utils.to_list(libndn_cxx['use']): if bld.env['LIB_%s' % lib]: pkgconfig_libs += Utils.to_list(bld.env['LIB_%s' % lib]) @@ -209,65 +232,75 @@ def build(bld): pkgconfig_linkflags += Utils.to_list(bld.env['LINKFLAGS_%s' % lib]) if bld.env['CXXFLAGS_%s' % lib]: pkgconfig_cxxflags += Utils.to_list(bld.env['CXXFLAGS_%s' % lib]) + if bld.env['DEFINES_%s' % lib]: + pkgconfig_defines += Utils.to_list(bld.env['DEFINES_%s' % lib]) - EXTRA_FRAMEWORKS = "" - if bld.env['HAVE_OSX_SECURITY']: - EXTRA_FRAMEWORKS = "-framework CoreFoundation -framework Security" + EXTRA_FRAMEWORKS = '' + if bld.env.HAVE_OSX_FRAMEWORKS: + EXTRA_FRAMEWORKS = '-framework CoreFoundation -framework Security -framework SystemConfiguration -framework Foundation -framework CoreWLAN' def uniq(alist): seen = set() return [x for x in alist if x not in seen and not seen.add(x)] - pkconfig = bld(features="subst", - source="libndn-cxx.pc.in", - target="libndn-cxx.pc", - install_path="${LIBDIR}/pkgconfig", + pkconfig = bld(features='subst', + source='libndn-cxx.pc.in', + target='libndn-cxx.pc', + install_path='${LIBDIR}/pkgconfig', VERSION=VERSION_BASE, # This probably not the right thing to do, but to simplify life of apps # that use the library - EXTRA_LIBS=" ".join([('-l%s' % i) for i in uniq(pkgconfig_libs)]), - EXTRA_LDFLAGS=" ".join([('-L%s' % i) for i in uniq(pkgconfig_ldflags)]), - EXTRA_LINKFLAGS=" ".join(uniq(pkgconfig_linkflags)), - EXTRA_INCLUDES=" ".join([('-I%s' % i) for i in uniq(pkgconfig_includes)]), - EXTRA_CXXFLAGS=" ".join(uniq(pkgconfig_cxxflags)), + EXTRA_LIBS=' '.join([('-l%s' % i) for i in uniq(pkgconfig_libs)]), + EXTRA_LDFLAGS=' '.join([('-L%s' % i) for i in uniq(pkgconfig_ldflags)]), + EXTRA_LINKFLAGS=' '.join(uniq(pkgconfig_linkflags)), + EXTRA_INCLUDES=' '.join([('-I%s' % i) for i in uniq(pkgconfig_includes)]), + EXTRA_CXXFLAGS=' '.join(uniq(pkgconfig_cxxflags) + [('-D%s' % i) for i in uniq(pkgconfig_defines)]), EXTRA_FRAMEWORKS=EXTRA_FRAMEWORKS) - if bld.env['WITH_TESTS']: + if bld.env.WITH_TESTS: bld.recurse('tests') - if bld.env['WITH_TOOLS']: - bld.recurse("tools") + if bld.env.WITH_TOOLS: + bld.recurse('tools') + + if bld.env.WITH_EXAMPLES: + bld.recurse('examples') - if bld.env['WITH_EXAMPLES']: - bld.recurse("examples") + headers = bld.path.ant_glob('ndn-cxx/**/*.hpp', + excl=['ndn-cxx/**/*-osx.hpp', + 'ndn-cxx/**/*netlink*.hpp', + 'ndn-cxx/**/*-sqlite3.hpp', + 'ndn-cxx/**/impl/**/*']) - headers = bld.path.ant_glob('src/**/*.hpp', - excl=['src/security/**/*-osx.hpp', - 'src/detail/**/*', - 'src/util/detail/**/*']) - if bld.env['HAVE_OSX_SECURITY']: - headers += bld.path.ant_glob('src/security/**/*-osx.hpp') + if bld.env.HAVE_OSX_FRAMEWORKS: + headers += bld.path.ant_glob('ndn-cxx/**/*-osx.hpp', excl='ndn-cxx/**/impl/**/*') - bld.install_files("%s/ndn-cxx" % bld.env['INCLUDEDIR'], headers, - relative_trick=True, cwd=bld.path.find_node('src')) + if bld.env.HAVE_NETLINK: + headers += bld.path.ant_glob('ndn-cxx/**/*netlink*.hpp', excl='ndn-cxx/**/impl/**/*') - bld.install_files("%s/ndn-cxx" % bld.env['INCLUDEDIR'], - bld.path.find_resource('src/ndn-cxx-config.hpp')) + # In case we want to make it optional later + headers += bld.path.ant_glob('ndn-cxx/**/*-sqlite3.hpp', excl='ndn-cxx/**/impl/**/*') + + bld.install_files(bld.env.INCLUDEDIR, headers, relative_trick=True) - bld.install_files("%s/ndn-cxx" % bld.env['INCLUDEDIR'], - bld.path.find_resource('src/version.hpp')) + # Install generated headers + for filename in ['ndn-cxx/detail/config.hpp', 'ndn-cxx/version.hpp']: + bld.install_files('%s/%s' % (bld.env.INCLUDEDIR, os.path.dirname(filename)), + bld.path.find_resource(filename)) - bld.install_files("${SYSCONFDIR}/ndn", "client.conf.sample") + bld.install_files('${SYSCONFDIR}/ndn', 'client.conf.sample') - if bld.env['SPHINX_BUILD']: - bld(features="sphinx", - builder="man", - outdir="docs/manpages", - config="docs/conf.py", - source=bld.path.ant_glob('docs/manpages/**/*.rst'), - install_path="${MANDIR}/", - VERSION=VERSION) + if bld.env.SPHINX_BUILD: + bld(features='sphinx', + name='manpages', + builder='man', + config='docs/conf.py', + outdir='docs/manpages', + source=bld.path.ant_glob('docs/manpages/*.rst'), + install_path='${MANDIR}', + version=VERSION_BASE, + release=VERSION) def docs(bld): from waflib import Options @@ -277,85 +310,83 @@ def doxygen(bld): version(bld) if not bld.env.DOXYGEN: - Logs.error("ERROR: cannot build documentation (`doxygen' not found in $PATH)") - else: - bld(features="subst", - name="doxygen-conf", - source=["docs/doxygen.conf.in", - "docs/named_data_theme/named_data_footer-with-analytics.html.in"], - target=["docs/doxygen.conf", - "docs/named_data_theme/named_data_footer-with-analytics.html"], - VERSION=VERSION, - HTML_FOOTER="../build/docs/named_data_theme/named_data_footer-with-analytics.html" \ - if os.getenv('GOOGLE_ANALYTICS', None) \ - else "../docs/named_data_theme/named_data_footer.html", - GOOGLE_ANALYTICS=os.getenv('GOOGLE_ANALYTICS', "")) - - bld(features="doxygen", - doxyfile='docs/doxygen.conf', - use="doxygen-conf") + bld.fatal('Cannot build documentation ("doxygen" not found in PATH)') + + bld(features='subst', + name='doxygen.conf', + source=['docs/doxygen.conf.in', + 'docs/named_data_theme/named_data_footer-with-analytics.html.in'], + target=['docs/doxygen.conf', + 'docs/named_data_theme/named_data_footer-with-analytics.html'], + VERSION=VERSION, + HTML_FOOTER='../build/docs/named_data_theme/named_data_footer-with-analytics.html' \ + if os.getenv('GOOGLE_ANALYTICS', None) \ + else '../docs/named_data_theme/named_data_footer.html', + GOOGLE_ANALYTICS=os.getenv('GOOGLE_ANALYTICS', '')) + + bld(features='doxygen', + doxyfile='docs/doxygen.conf', + use='doxygen.conf') def sphinx(bld): version(bld) if not bld.env.SPHINX_BUILD: - bld.fatal("ERROR: cannot build documentation (`sphinx-build' not found in $PATH)") - else: - bld(features="sphinx", - outdir="docs", - source=bld.path.ant_glob("docs/**/*.rst"), - config="docs/conf.py", - VERSION=VERSION) + bld.fatal('Cannot build documentation ("sphinx-build" not found in PATH)') + + bld(features='sphinx', + config='docs/conf.py', + outdir='docs', + source=bld.path.ant_glob('docs/**/*.rst'), + version=VERSION_BASE, + release=VERSION) def version(ctx): + # don't execute more than once if getattr(Context.g_module, 'VERSION_BASE', None): return Context.g_module.VERSION_BASE = Context.g_module.VERSION - Context.g_module.VERSION_SPLIT = [v for v in VERSION_BASE.split('.')] + Context.g_module.VERSION_SPLIT = VERSION_BASE.split('.') - didGetVersion = False + # first, try to get a version string from git + gotVersionFromGit = False try: cmd = ['git', 'describe', '--always', '--match', '%s*' % GIT_TAG_PREFIX] - p = Utils.subprocess.Popen(cmd, stdout=Utils.subprocess.PIPE, - stderr=None, stdin=None) - out = str(p.communicate()[0].strip()) - didGetVersion = (p.returncode == 0 and out != "") - if didGetVersion: + out = subprocess.check_output(cmd, universal_newlines=True).strip() + if out: + gotVersionFromGit = True if out.startswith(GIT_TAG_PREFIX): - Context.g_module.VERSION = out[len(GIT_TAG_PREFIX):] + Context.g_module.VERSION = out.lstrip(GIT_TAG_PREFIX) else: - Context.g_module.VERSION = "%s-commit-%s" % (Context.g_module.VERSION_BASE, out) - except OSError: + # no tags matched + Context.g_module.VERSION = '%s-commit-%s' % (VERSION_BASE, out) + except (OSError, subprocess.CalledProcessError): pass versionFile = ctx.path.find_node('VERSION') - - if not didGetVersion and versionFile is not None: + if not gotVersionFromGit and versionFile is not None: try: Context.g_module.VERSION = versionFile.read() return - except (OSError, IOError): + except EnvironmentError: pass # version was obtained from git, update VERSION file if necessary if versionFile is not None: try: - version = versionFile.read() - if version == Context.g_module.VERSION: - return # no need to update - except (OSError, IOError): - Logs.warn("VERSION file exists, but not readable") + if versionFile.read() == Context.g_module.VERSION: + # already up-to-date + return + except EnvironmentError as e: + Logs.warn('%s exists but is not readable (%s)' % (versionFile, e.strerror)) else: versionFile = ctx.path.make_node('VERSION') - if versionFile is None: - return - try: versionFile.write(Context.g_module.VERSION) - except (OSError, IOError): - Logs.warn("VERSION file is not writeable") + except EnvironmentError as e: + Logs.warn('%s is not writable (%s)' % (versionFile, e.strerror)) def dist(ctx): version(ctx)