Compare commits
244 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ebea9094a3 | |||
| 5998428e9c | |||
| ed0017bd07 | |||
| fd2d1012c7 | |||
| 50882ebf1d | |||
| 84eb4873c8 | |||
| 38dca3952a | |||
| 585e18a5e3 | |||
| 918652862c | |||
| 89b52d4639 | |||
| 200014a739 | |||
| 79482ec462 | |||
| 2c8ec07ae5 | |||
| 8c35390e61 | |||
| c4343232bc | |||
| f8d9a531dd | |||
| e8c82ef8a1 | |||
| a209f6747f | |||
| 7c4246ca67 | |||
| f8a14d88cb | |||
| a420e97fed | |||
| 3f588caea2 | |||
| 7ef5cf7f24 | |||
| 9b1fd4b332 | |||
| 6929b4344a | |||
| 814ad34909 | |||
| a0e6b60e8f | |||
| 3047ba4741 | |||
| 6677762595 | |||
| 374f4e47b5 | |||
| 02ec47c8ac | |||
| 9a1b65d0da | |||
| 352755871f | |||
| d653afaf01 | |||
| 28181ee93a | |||
| 298c4355c3 | |||
| b07d7a96da | |||
| 8a2907ea04 | |||
| d5c2447b3a | |||
| fce3963fc0 | |||
| d8398820f1 | |||
| a1a9d704ba | |||
| 4ab5eed35d | |||
| 9fa6a78e17 | |||
| 3b0fccd9bb | |||
| 9b70f57f8d | |||
| 7d14815aaf | |||
| 6ab7f911e0 | |||
| a8600b0a6a | |||
| 2cd6ae8495 | |||
| 4a2e89d88f | |||
| 296b385c58 | |||
| 97a33b200d | |||
| 32c0df2e9e | |||
| 327fb4b0fd | |||
| cbef7b8393 | |||
| 11c69910f3 | |||
| c214e073d8 | |||
| 9602823383 | |||
| 5e3773dd5a | |||
| 50cf6db473 | |||
| 0d4b182304 | |||
| 7de32c1f2d | |||
| 0da1f44c79 | |||
| 6a1396e2e0 | |||
| 6752d943ef | |||
| c5243b40f4 | |||
| b3ae634086 | |||
| de01c81a92 | |||
| 94dff006fc | |||
| 87434bef4b | |||
| e75861eddb | |||
| c1eb2fcf4b | |||
| ba56066683 | |||
| 0353bae5f6 | |||
| 65d115569e | |||
| 526ff43cdb | |||
| 70576403fe | |||
| 9619295e9e | |||
| 6cc1dfbdfd | |||
| 630b0087b4 | |||
| 786a7f2a38 | |||
| 84d8477ae6 | |||
| 105cd9e3a2 | |||
| e90a3580d6 | |||
| bb2d280580 | |||
| 9e5122bafc | |||
| bf2c51716a | |||
| c16ec575b8 | |||
| da85e25e59 | |||
| e4687a1d57 | |||
| d8197df500 | |||
| aacc7daf62 | |||
| 8ff3abde93 | |||
| 0c6fcb58ba | |||
| d8f9af2689 | |||
| 5cb67014d3 | |||
| 25c37f1557 | |||
| 7b9837bbda | |||
| 80baddfb82 | |||
| ae37cf3eab | |||
| 252b70708d | |||
| d5449e5656 | |||
| 06d008c184 | |||
| 79991a0660 | |||
| 7664b12f2a | |||
| 3347eaad8e | |||
| cb903eac38 | |||
| 4e2a542b3b | |||
| e1b18a6856 | |||
| 1f0cad703b | |||
| f66e40a0ee | |||
| 162bdbbcb2 | |||
| 2c9933c94f | |||
| a8b03df84d | |||
| 4f1d13db23 | |||
| 88beb4d0f5 | |||
| 3f2f48616e | |||
| 20d5a0b9fd | |||
| 2bdda1d185 | |||
| 5923bf814b | |||
| 0ca7e69023 | |||
| f912653a7b | |||
| b6b176c7b9 | |||
| 4fb67ea932 | |||
| 4a1b21d699 | |||
| d1b1bf6666 | |||
| b5b8f95024 | |||
| 24c0861e33 | |||
| c3d65c9a79 | |||
| fb42a3db83 | |||
| ecd44803c7 | |||
| 051db00f35 | |||
| 302941eec2 | |||
| 78de735ab0 | |||
| 468dbdf326 | |||
| 034f30f27a | |||
| 2f041d20af | |||
| 60f8cc12e2 | |||
| 89db73c443 | |||
| 26ea1ac2aa | |||
| c687af62d1 | |||
| 4a43e87b5a | |||
| 79d12c66d8 | |||
| a2d4b1480b | |||
| 969cd5add4 | |||
| ac4b546be8 | |||
| b54aabdb89 | |||
| 5820ed3cc0 | |||
| 75309aeedb | |||
| e7d95a72ba | |||
| 20c85cb868 | |||
| 1aa91434cb | |||
| 48cb0b6f2e | |||
| cc2c717b62 | |||
| 1fda67dc75 | |||
| 9a659d0c3b | |||
| f6991e1a61 | |||
| 3dae1090cf | |||
| 83f9a91944 | |||
| 44b3b23ae6 | |||
| 2c3083dc77 | |||
| dc4cb4bf3a | |||
| 641f593969 | |||
| e9c69855c4 | |||
| b587cfd779 | |||
| 4d36ed5889 | |||
| 1928024363 | |||
| eacd617151 | |||
| 11e74eb20f | |||
| b5e06e6658 | |||
| 6f76afcf06 | |||
| 06807dcdb4 | |||
| 887336ca8d | |||
| 7072e1604a | |||
| 59ec95a15e | |||
| 0ebecab714 | |||
| 6035cd5907 | |||
| 07238e844c | |||
| c07027069f | |||
| 44660cf226 | |||
| 5485ca9ce2 | |||
| bf28cd76ee | |||
| a5b60cc017 | |||
| f860649549 | |||
| c9575a6aa3 | |||
| f085ed10e5 | |||
| 1eecc17e16 | |||
| dd0e1959bb | |||
| 70750cf10d | |||
| 20b2297739 | |||
| bfd66ade98 | |||
| 931dfe8a63 | |||
| 339161aca3 | |||
| 958896e4c0 | |||
| 92998fe2e1 | |||
| 716ab60f05 | |||
| bf1c069b7f | |||
| cd65c2c204 | |||
| dc304c21b7 | |||
| 1b05b0a8fb | |||
| 59869d2d9c | |||
| 82ea0fa9a0 | |||
| 9737aa886b | |||
| f162839c11 | |||
| 022bddf47d | |||
| 1c71bcdcd7 | |||
| 5e384792db | |||
| 3ebb9cb728 | |||
| 574eeb05dd | |||
| e16bc31651 | |||
| 245d791ef7 | |||
| 2547a5288d | |||
| 6a2b3dab98 | |||
| fc4aa0d727 | |||
| b355889743 | |||
| 72c96d23f0 | |||
| 13fda5be9b | |||
| 85de8424e0 | |||
| b5a5745c78 | |||
| 956ac311b8 | |||
| 525c1071b1 | |||
| 013de9bc86 | |||
| f0a301dd60 | |||
| 89d9175e7c | |||
| 244feac1d1 | |||
| e4a2b03245 | |||
| 05d9209741 | |||
| e65c6d7eae | |||
| c75996344f | |||
| c1c2b83766 | |||
| 7809e30b59 | |||
| 523fcb1256 | |||
| b098e9f3c4 | |||
| e476501b49 | |||
| aa1b3c9fc4 | |||
| 6288486984 | |||
| 6fd1695bb2 | |||
| d2300731ed | |||
| 52401cea4d | |||
| 0e8edde5d1 | |||
| 4a1edc661a | |||
| 25625ca1a0 | |||
| 2864b9df7d |
@@ -0,0 +1,68 @@
|
||||
name: CI
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
- '.mailmap'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
name: ${{ matrix.compiler }} on ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
compiler: [g++-8, g++-9, g++-10, g++-11,
|
||||
clang++-7, clang++-8, clang++-9, clang++-10, clang++-11, clang++-12]
|
||||
os: [ubuntu-20.04]
|
||||
include:
|
||||
- compiler: g++-7
|
||||
os: ubuntu-18.04
|
||||
- compiler: clang++-5.0
|
||||
os: ubuntu-18.04
|
||||
- compiler: clang++-6.0
|
||||
os: ubuntu-18.04
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
CXX: ${{ matrix.compiler }}
|
||||
NODE_LABELS: Linux Ubuntu
|
||||
WAF_JOBS: 2
|
||||
steps:
|
||||
- name: Install C++ compiler
|
||||
run: |
|
||||
sudo apt-get -qy install ${CXX/clang++/clang}
|
||||
${CXX} --version
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Build and test
|
||||
run: ./.jenkins
|
||||
|
||||
macos:
|
||||
name: Xcode ${{ matrix.xcode }} on ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
xcode: ['11.3', '11.7', '12.4']
|
||||
os: [macos-10.15]
|
||||
include:
|
||||
- xcode: '12.5'
|
||||
os: macos-11
|
||||
- xcode: '13.2'
|
||||
os: macos-11
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
NODE_LABELS: OSX
|
||||
WAF_JOBS: 3
|
||||
steps:
|
||||
- name: Set up Xcode
|
||||
uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: ${{ matrix.xcode }}
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Build and test
|
||||
run: ./.jenkins
|
||||
@@ -0,0 +1,36 @@
|
||||
name: Docs
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- '*.md'
|
||||
- '.mailmap'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-11, ubuntu-20.04]
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
JOB_NAME: Docs
|
||||
WAF_JOBS: 3
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
case ${RUNNER_OS} in
|
||||
Linux) export NODE_LABELS="Linux Ubuntu" ;;
|
||||
macOS) export NODE_LABELS="OSX" ;;
|
||||
esac
|
||||
find .jenkins.d/ -type f -name '[1-9]*.sh' -exec chmod -x '{}' +
|
||||
./.jenkins
|
||||
- name: Build documentation
|
||||
run: |
|
||||
./waf --color=yes configure
|
||||
./waf --color=yes build --targets=manpages
|
||||
+22
-10
@@ -1,17 +1,29 @@
|
||||
# Emacs temp files
|
||||
# Emacs
|
||||
*~
|
||||
\#*\#
|
||||
/.emacs.desktop
|
||||
/.emacs.desktop.lock
|
||||
*.elc
|
||||
.\#*
|
||||
|
||||
# OS X
|
||||
.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
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
|
||||
# Other
|
||||
VERSION
|
||||
/VERSION.info
|
||||
|
||||
@@ -1,10 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
source .jenkins.d/util.sh
|
||||
|
||||
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
if has Linux $NODE_LABELS; then
|
||||
export PATH="${HOME}/.local/bin${PATH:+:}${PATH}"
|
||||
fi
|
||||
export CACHE_DIR=${CACHE_DIR:-/tmp}
|
||||
export WAF_JOBS=${WAF_JOBS:-1}
|
||||
[[ $JOB_NAME == *"code-coverage" ]] && export DISABLE_ASAN=yes
|
||||
|
||||
for file in "$DIR"/.jenkins.d/*; do
|
||||
for file in .jenkins.d/*; do
|
||||
[[ -f $file && -x $file ]] || continue
|
||||
echo "Run: $file"
|
||||
|
||||
if [[ -n $GITHUB_ACTIONS ]]; then
|
||||
label=$(basename "$file" | sed -E 's/[[:digit:]]+-(.*)\..*/\1/')
|
||||
echo "::group::${label}"
|
||||
fi
|
||||
|
||||
echo "\$ $file"
|
||||
"$file"
|
||||
|
||||
if [[ -n $GITHUB_ACTIONS ]]; then
|
||||
echo "::endgroup::"
|
||||
fi
|
||||
done
|
||||
|
||||
+42
-18
@@ -1,25 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
set -ex
|
||||
|
||||
if has OSX $NODE_LABELS; then
|
||||
set -x
|
||||
brew update
|
||||
brew upgrade
|
||||
brew install boost pkg-config cryptopp
|
||||
brew cleanup
|
||||
fi
|
||||
FORMULAE=(boost openssl pkg-config)
|
||||
|
||||
if has Ubuntu $NODE_LABELS; then
|
||||
BOOST_PKG=libboost-all-dev
|
||||
if has Ubuntu-12.04 $NODE_LABELS; then
|
||||
BOOST_PKG=libboost1.48-all-dev
|
||||
if [[ -n $GITHUB_ACTIONS ]]; then
|
||||
# GitHub Actions runners have a large number of pre-installed
|
||||
# Homebrew packages. Don't waste time upgrading all of them.
|
||||
brew list --versions "${FORMULAE[@]}" || brew update
|
||||
for FORMULA in "${FORMULAE[@]}"; do
|
||||
brew list --versions "$FORMULA" || brew install "$FORMULA"
|
||||
done
|
||||
# Ensure /usr/local/opt/openssl exists
|
||||
brew reinstall openssl
|
||||
else
|
||||
brew update
|
||||
brew upgrade
|
||||
brew install "${FORMULAE[@]}"
|
||||
brew cleanup
|
||||
fi
|
||||
|
||||
set -x
|
||||
sudo apt-get update -qq -y
|
||||
sudo apt-get -qq -y install build-essential pkg-config $BOOST_PKG \
|
||||
libcrypto++-dev libsqlite3-dev libpcap-dev
|
||||
if [[ $JOB_NAME == *"Docs" ]]; then
|
||||
pip3 install --upgrade --upgrade-strategy=eager sphinx
|
||||
fi
|
||||
|
||||
elif has Ubuntu $NODE_LABELS; then
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get -qy install build-essential pkg-config python3-minimal \
|
||||
libboost-all-dev libssl-dev libsqlite3-dev \
|
||||
libpcap-dev
|
||||
|
||||
case $JOB_NAME in
|
||||
*code-coverage)
|
||||
sudo apt-get -qy install lcov python3-pip
|
||||
pip3 install --user --upgrade --upgrade-strategy=eager 'gcovr~=5.0'
|
||||
;;
|
||||
*Docs)
|
||||
sudo apt-get -qy install python3-pip
|
||||
pip3 install --user --upgrade --upgrade-strategy=eager sphinx
|
||||
;;
|
||||
esac
|
||||
|
||||
elif has CentOS-8 $NODE_LABELS; then
|
||||
sudo dnf config-manager --enable powertools
|
||||
sudo dnf -y install gcc-c++ libasan pkgconf-pkg-config python3 \
|
||||
boost-devel openssl-devel sqlite-devel \
|
||||
libpcap-devel
|
||||
fi
|
||||
|
||||
Executable
+55
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
pushd "$CACHE_DIR" >/dev/null
|
||||
|
||||
INSTALLED_VERSION=
|
||||
if has OSX $NODE_LABELS; then
|
||||
BOOST=$(brew ls --versions boost)
|
||||
OLD_BOOST=$(cat boost.txt || :)
|
||||
if [[ $OLD_BOOST != $BOOST ]]; then
|
||||
echo "$BOOST" > boost.txt
|
||||
INSTALLED_VERSION=NONE
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z $INSTALLED_VERSION ]]; then
|
||||
INSTALLED_VERSION=$(git -C ndn-cxx rev-parse HEAD 2>/dev/null || echo NONE)
|
||||
fi
|
||||
|
||||
sudo rm -rf ndn-cxx-latest
|
||||
git clone --depth 1 https://github.com/named-data/ndn-cxx.git ndn-cxx-latest
|
||||
LATEST_VERSION=$(git -C ndn-cxx-latest rev-parse HEAD 2>/dev/null || echo UNKNOWN)
|
||||
|
||||
if [[ $INSTALLED_VERSION != $LATEST_VERSION ]]; then
|
||||
sudo rm -rf ndn-cxx
|
||||
mv ndn-cxx-latest ndn-cxx
|
||||
else
|
||||
sudo rm -rf ndn-cxx-latest
|
||||
fi
|
||||
|
||||
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
|
||||
|
||||
pushd ndn-cxx >/dev/null
|
||||
|
||||
if has CentOS-8 $NODE_LABELS; then
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1721553
|
||||
PCH="--without-pch"
|
||||
fi
|
||||
|
||||
./waf --color=yes configure --disable-static --enable-shared --without-osx-keychain $PCH
|
||||
./waf --color=yes build -j$WAF_JOBS
|
||||
sudo_preserve_env PATH -- ./waf --color=yes install
|
||||
|
||||
popd >/dev/null
|
||||
popd >/dev/null
|
||||
|
||||
if has CentOS-8 $NODE_LABELS; then
|
||||
sudo tee /etc/ld.so.conf.d/ndn.conf >/dev/null <<< /usr/local/lib64
|
||||
fi
|
||||
if has Linux $NODE_LABELS; then
|
||||
sudo ldconfig
|
||||
fi
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
git submodule sync
|
||||
git submodule update --init
|
||||
|
||||
if [[ -z $DISABLE_ASAN ]]; then
|
||||
ASAN="--with-sanitizer=address"
|
||||
fi
|
||||
if [[ $JOB_NAME == *"code-coverage" ]]; then
|
||||
COVERAGE="--with-coverage"
|
||||
fi
|
||||
|
||||
if [[ $JOB_NAME != *"code-coverage" && $JOB_NAME != *"limited-build" ]]; then
|
||||
# Build in release mode with tests
|
||||
./waf --color=yes configure --with-tests
|
||||
./waf --color=yes build -j$WAF_JOBS
|
||||
|
||||
# Cleanup
|
||||
./waf --color=yes distclean
|
||||
|
||||
# Build in release mode without tests
|
||||
./waf --color=yes configure
|
||||
./waf --color=yes build -j$WAF_JOBS
|
||||
|
||||
# Cleanup
|
||||
./waf --color=yes distclean
|
||||
fi
|
||||
|
||||
# Build in debug mode with tests
|
||||
./waf --color=yes configure --debug --with-tests $ASAN $COVERAGE
|
||||
./waf --color=yes build -j$WAF_JOBS
|
||||
|
||||
# (tests will be run against the debug version)
|
||||
|
||||
# Install
|
||||
sudo_preserve_env PATH -- ./waf --color=yes install
|
||||
@@ -1,42 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
set -e
|
||||
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
|
||||
pushd /tmp >/dev/null
|
||||
|
||||
INSTALLED_VERSION=$((cd ndn-cxx && git rev-parse HEAD) 2>/dev/null || echo NONE)
|
||||
|
||||
sudo rm -Rf ndn-cxx-latest
|
||||
|
||||
git clone --depth 1 git://github.com/named-data/ndn-cxx ndn-cxx-latest
|
||||
|
||||
LATEST_VERSION=$((cd ndn-cxx-latest && git rev-parse HEAD) 2>/dev/null || echo UNKNOWN)
|
||||
|
||||
if [[ $INSTALLED_VERSION != $LATEST_VERSION ]]; then
|
||||
sudo rm -Rf ndn-cxx
|
||||
mv ndn-cxx-latest ndn-cxx
|
||||
else
|
||||
sudo rm -Rf ndn-cxx-latest
|
||||
fi
|
||||
|
||||
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*
|
||||
|
||||
pushd ndn-cxx >/dev/null
|
||||
|
||||
./waf configure -j1 --color=yes --enable-shared --disable-static --without-osx-keychain
|
||||
./waf -j1 --color=yes
|
||||
sudo ./waf install -j1 --color=yes
|
||||
|
||||
popd >/dev/null
|
||||
popd >/dev/null
|
||||
|
||||
if has Linux $NODE_LABELS; then
|
||||
sudo ldconfig
|
||||
elif has FreeBSD $NODE_LABELS; then
|
||||
sudo ldconfig -a
|
||||
fi
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
set -e
|
||||
|
||||
# Cleanup
|
||||
sudo ./waf -j1 --color=yes distclean
|
||||
|
||||
# Configure/build in release mode without tests
|
||||
./waf -j1 --color=yes configure
|
||||
./waf -j1 --color=yes build
|
||||
|
||||
# Cleanup
|
||||
sudo ./waf -j1 --color=yes distclean
|
||||
|
||||
# Configure/build in debug mode with tests
|
||||
./waf -j1 --color=yes configure --with-tests --debug
|
||||
./waf -j1 --color=yes build
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
# Prepare environment
|
||||
rm -rf ~/.ndn
|
||||
|
||||
# https://github.com/google/sanitizers/wiki/AddressSanitizerFlags
|
||||
ASAN_OPTIONS="color=always"
|
||||
ASAN_OPTIONS+=":check_initialization_order=1"
|
||||
ASAN_OPTIONS+=":detect_stack_use_after_return=1"
|
||||
ASAN_OPTIONS+=":strict_init_order=1"
|
||||
ASAN_OPTIONS+=":strict_string_checks=1"
|
||||
ASAN_OPTIONS+=":detect_invalid_pointer_pairs=2"
|
||||
ASAN_OPTIONS+=":strip_path_prefix=${PWD}/"
|
||||
export ASAN_OPTIONS
|
||||
|
||||
export BOOST_TEST_BUILD_INFO=1
|
||||
export BOOST_TEST_COLOR_OUTPUT=1
|
||||
export BOOST_TEST_DETECT_MEMORY_LEAK=0
|
||||
export BOOST_TEST_LOGGER=HRF,test_suite,stdout:XML,all,build/xunit-log.xml
|
||||
|
||||
# Run unit tests
|
||||
./build/unit-tests
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
if [[ $JOB_NAME == *"code-coverage" ]]; then
|
||||
# Generate an XML report (Cobertura format) and a detailed HTML report using gcovr
|
||||
# Note: trailing slashes are important in the paths below. Do not remove them!
|
||||
gcovr -j$WAF_JOBS \
|
||||
--object-directory build \
|
||||
--filter tools/ \
|
||||
--exclude-throw-branches \
|
||||
--exclude-unreachable-branches \
|
||||
--print-summary \
|
||||
--html-details build/gcovr/ \
|
||||
--xml build/coverage.xml
|
||||
|
||||
# Generate a detailed HTML report using lcov
|
||||
lcov --quiet \
|
||||
--capture \
|
||||
--directory . \
|
||||
--exclude "$PWD/tests/*" \
|
||||
--no-external \
|
||||
--rc lcov_branch_coverage=1 \
|
||||
--output-file build/coverage.info
|
||||
|
||||
genhtml --branch-coverage \
|
||||
--demangle-cpp \
|
||||
--legend \
|
||||
--output-directory build/lcov \
|
||||
--title "ndn-tools unit tests" \
|
||||
build/coverage.info
|
||||
fi
|
||||
@@ -1,6 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
set -e
|
||||
|
||||
rm -rf $HOME/.ndn
|
||||
./build/unit-tests -l test_suite
|
||||
+18
-20
@@ -1,30 +1,28 @@
|
||||
CONTINUOUS INTEGRATION SCRIPTS
|
||||
==============================
|
||||
# CONTINUOUS INTEGRATION SCRIPTS
|
||||
|
||||
Environment Variables Used in Build Scripts
|
||||
-------------------------------------------
|
||||
## Environment Variables Used in Build Scripts
|
||||
|
||||
- `NODE_LABELS`: the variable defines a list of OS properties. The set values are used by the
|
||||
build scripts to select proper behavior for different OS.
|
||||
- `NODE_LABELS`: space-separated list of platform properties. The included values are used by
|
||||
the build scripts to select the proper behavior for different operating systems and versions.
|
||||
|
||||
The list should include at least `[OS_TYPE]`, `[DISTRO_TYPE]`, and `[DISTRO_VERSION]`.
|
||||
The list should normally contain `[OS_TYPE]`, `[DISTRO_TYPE]`, and `[DISTRO_VERSION]`.
|
||||
|
||||
Possible values for Linux OS:
|
||||
Example values:
|
||||
|
||||
* `[OS_TYPE]`: `Linux`
|
||||
* `[DISTRO_TYPE]`: `Ubuntu`
|
||||
* `[DISTRO_VERSION]`: `Ubuntu-12.04`, `Ubuntu-14.04`, `Ubuntu-15.04`
|
||||
- `[OS_TYPE]`: `Linux`, `OSX`
|
||||
- `[DISTRO_TYPE]`: `Ubuntu`, `CentOS`
|
||||
- `[DISTRO_VERSION]`: `Ubuntu-16.04`, `Ubuntu-18.04`, `CentOS-8`, `OSX-10.14`, `OSX-10.15`
|
||||
|
||||
Possible values of OSX OS:
|
||||
|
||||
* `[OS_TYPE]`: `OSX`
|
||||
* `[DISTRO_TYPE]`: `OSX` (can be absent)
|
||||
* `[DISTRO_VERSION]`: `OSX-10.10`, `OSX-10.9`, `OSX-10.8`, `OSX-10.7`
|
||||
|
||||
- `JOB_NAME`: optional variable to define type of the job. Depending on the defined job type,
|
||||
- `JOB_NAME`: optional variable that defines the type of build job. Depending on the job type,
|
||||
the build scripts can perform different tasks.
|
||||
|
||||
Possible values:
|
||||
|
||||
* empty: default build process
|
||||
* `code-coverage` (Linux OS is assumed): build process with code coverage analysis
|
||||
- empty: default build task
|
||||
- `code-coverage`: debug build with tests and code coverage analysis (Ubuntu Linux is assumed)
|
||||
- `limited-build`: only a single debug build with tests
|
||||
|
||||
- `CACHE_DIR`: directory containing cached files from previous builds, e.g., a compiled version
|
||||
of ndn-cxx. If not set, `/tmp` is used.
|
||||
|
||||
- `WAF_JOBS`: number of parallel build threads used by waf, defaults to 1.
|
||||
|
||||
Executable → Regular
+34
-4
@@ -1,9 +1,39 @@
|
||||
has() {
|
||||
local saved_xtrace
|
||||
[[ $- == *x* ]] && saved_xtrace=-x || saved_xtrace=+x
|
||||
set +x
|
||||
|
||||
local p=$1
|
||||
shift
|
||||
local x
|
||||
for x in "$@"; do
|
||||
[[ "${x}" == "${p}" ]] && return 0
|
||||
local i ret=1
|
||||
for i in "$@"; do
|
||||
if [[ "${i}" == "${p}" ]]; then
|
||||
ret=0
|
||||
break
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
|
||||
set ${saved_xtrace}
|
||||
return ${ret}
|
||||
}
|
||||
export -f has
|
||||
|
||||
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[@]}" "$@"
|
||||
}
|
||||
export -f sudo_preserve_env
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<aa@cs.fiu.edu> <alexander.afanasyev@ucla.edu>
|
||||
<davidepesa@gmail.com> <davide.pesavento@lip6.fr>
|
||||
<enewberry@email.arizona.edu> <enewberry@cs.arizona.edu>
|
||||
Md Ashiqur Rahman <marahman@email.arizona.edu>
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
sudo: true
|
||||
language: cpp
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
matrix:
|
||||
exclude:
|
||||
- os: linux
|
||||
compiler: clang
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
script:
|
||||
- if [[ $TRAVIS_OS_NAME == linux ]]; then export NODE_LABELS="Linux Ubuntu Ubuntu-12.04"; fi
|
||||
- if [[ $TRAVIS_OS_NAME == osx ]]; then export NODE_LABELS="OSX OSX-10.10"; fi
|
||||
- echo $NODE_LABELS
|
||||
- ./.jenkins
|
||||
+430
-275
@@ -13,37 +13,37 @@
|
||||
This is an extra tool, not bundled with the default waf binary.
|
||||
To add the boost tool to the waf file:
|
||||
$ ./waf-light --tools=compat15,boost
|
||||
or, if you have waf >= 1.6.2
|
||||
or, if you have waf >= 1.6.2
|
||||
$ ./waf update --files=boost
|
||||
|
||||
When using this tool, the wscript will look like:
|
||||
|
||||
def options(opt):
|
||||
opt.load('compiler_cxx boost')
|
||||
def options(opt):
|
||||
opt.load('compiler_cxx boost')
|
||||
|
||||
def configure(conf):
|
||||
conf.load('compiler_cxx boost')
|
||||
conf.check_boost(lib='system filesystem')
|
||||
def configure(conf):
|
||||
conf.load('compiler_cxx boost')
|
||||
conf.check_boost(lib='system filesystem')
|
||||
|
||||
def build(bld):
|
||||
bld(source='main.cpp', target='app', use='BOOST')
|
||||
def build(bld):
|
||||
bld(source='main.cpp', target='app', use='BOOST')
|
||||
|
||||
Options are generated, in order to specify the location of boost includes/libraries.
|
||||
The `check_boost` configuration function allows to specify the used boost libraries.
|
||||
It can also provide default arguments to the --boost-static and --boost-mt command-line arguments.
|
||||
It can also provide default arguments to the --boost-mt command-line arguments.
|
||||
Everything will be packaged together in a BOOST component that you can use.
|
||||
|
||||
When using MSVC, a lot of compilation flags need to match your BOOST build configuration:
|
||||
- you may have to add /EHsc to your CXXFLAGS or define boost::throw_exception if BOOST_NO_EXCEPTIONS is defined.
|
||||
Errors: C4530
|
||||
- boost libraries will try to be smart and use the (pretty but often not useful) auto-linking feature of MSVC
|
||||
So before calling `conf.check_boost` you might want to disabling by adding:
|
||||
conf.env.DEFINES_BOOST += ['BOOST_ALL_NO_LIB']
|
||||
So before calling `conf.check_boost` you might want to disabling by adding
|
||||
conf.env.DEFINES_BOOST += ['BOOST_ALL_NO_LIB']
|
||||
Errors:
|
||||
- boost might also be compiled with /MT, which links the runtime statically.
|
||||
If you have problems with redefined symbols,
|
||||
self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB']
|
||||
self.env['CXXFLAGS_%s' % var] += ['/MD', '/EHsc']
|
||||
self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB']
|
||||
self.env['CXXFLAGS_%s' % var] += ['/MD', '/EHsc']
|
||||
Passing `--boost-linkage_autodetect` might help ensuring having a correct linkage in some basic cases.
|
||||
|
||||
'''
|
||||
@@ -52,327 +52,482 @@ import sys
|
||||
import re
|
||||
from waflib import Utils, Logs, Errors
|
||||
from waflib.Configure import conf
|
||||
from waflib.TaskGen import feature, after_method
|
||||
|
||||
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_LIBS = ['/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib', '/usr/lib/x86_64-linux-gnu', '/usr/lib/i386-linux-gnu', '/usr/local/ndn/lib']
|
||||
BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include', '/usr/local/ndn/include']
|
||||
BOOST_VERSION_FILE = 'boost/version.hpp'
|
||||
BOOST_VERSION_CODE = '''
|
||||
#include <iostream>
|
||||
#include <boost/version.hpp>
|
||||
int main() { std::cout << BOOST_LIB_VERSION << ":" << BOOST_VERSION << std::endl; }
|
||||
'''
|
||||
BOOST_SYSTEM_CODE = '''
|
||||
|
||||
BOOST_ERROR_CODE = '''
|
||||
#include <boost/system/error_code.hpp>
|
||||
int main() { boost::system::error_code c; }
|
||||
'''
|
||||
|
||||
PTHREAD_CODE = '''
|
||||
#include <pthread.h>
|
||||
static void* f(void*) { return 0; }
|
||||
int main() {
|
||||
pthread_t th;
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_create(&th, &attr, &f, 0);
|
||||
pthread_join(th, 0);
|
||||
pthread_cleanup_push(0, 0);
|
||||
pthread_cleanup_pop(0);
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
'''
|
||||
|
||||
BOOST_THREAD_CODE = '''
|
||||
#include <boost/thread.hpp>
|
||||
int main() { boost::thread t; }
|
||||
'''
|
||||
|
||||
BOOST_LOG_CODE = '''
|
||||
#include <boost/log/trivial.hpp>
|
||||
int main() { BOOST_LOG_TRIVIAL(info) << "boost_log is working"; }
|
||||
'''
|
||||
|
||||
BOOST_LOG_SETUP_CODE = '''
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/log/utility/setup/console.hpp>
|
||||
#include <boost/log/utility/setup/common_attributes.hpp>
|
||||
int main() {
|
||||
using namespace boost::log;
|
||||
add_common_attributes();
|
||||
add_console_log(std::clog, keywords::format = "%Message%");
|
||||
BOOST_LOG_TRIVIAL(info) << "boost_log_setup is working";
|
||||
}
|
||||
'''
|
||||
|
||||
# toolsets from {boost_dir}/tools/build/v2/tools/common.jam
|
||||
PLATFORM = Utils.unversioned_sys_platform()
|
||||
detect_intel = lambda env: (PLATFORM == 'win32') and 'iw' or 'il'
|
||||
detect_clang = lambda env: (PLATFORM == 'darwin') and 'clang-darwin' or 'clang'
|
||||
detect_mingw = lambda env: (re.search('MinGW', env.CXX[0])) and 'mgw' or 'gcc'
|
||||
BOOST_TOOLSETS = {
|
||||
'borland': 'bcb',
|
||||
'clang': detect_clang,
|
||||
'como': 'como',
|
||||
'cw': 'cw',
|
||||
'darwin': 'xgcc',
|
||||
'edg': 'edg',
|
||||
'g++': detect_mingw,
|
||||
'gcc': detect_mingw,
|
||||
'icpc': detect_intel,
|
||||
'intel': detect_intel,
|
||||
'kcc': 'kcc',
|
||||
'kylix': 'bck',
|
||||
'mipspro': 'mp',
|
||||
'mingw': 'mgw',
|
||||
'msvc': 'vc',
|
||||
'qcc': 'qcc',
|
||||
'sun': 'sw',
|
||||
'sunc++': 'sw',
|
||||
'tru64cxx': 'tru',
|
||||
'vacpp': 'xlc'
|
||||
'borland': 'bcb',
|
||||
'clang': detect_clang,
|
||||
'como': 'como',
|
||||
'cw': 'cw',
|
||||
'darwin': 'xgcc',
|
||||
'edg': 'edg',
|
||||
'g++': detect_mingw,
|
||||
'gcc': detect_mingw,
|
||||
'icpc': detect_intel,
|
||||
'intel': detect_intel,
|
||||
'kcc': 'kcc',
|
||||
'kylix': 'bck',
|
||||
'mipspro': 'mp',
|
||||
'mingw': 'mgw',
|
||||
'msvc': 'vc',
|
||||
'qcc': 'qcc',
|
||||
'sun': 'sw',
|
||||
'sunc++': 'sw',
|
||||
'tru64cxx': 'tru',
|
||||
'vacpp': 'xlc'
|
||||
}
|
||||
|
||||
|
||||
def options(opt):
|
||||
opt = opt.add_option_group('Boost Options')
|
||||
|
||||
opt.add_option('--boost-includes', type='string',
|
||||
default='', dest='boost_includes',
|
||||
help='''path to the directory where the boost includes are, e.g., /path/to/boost_1_55_0/stage/include''')
|
||||
opt.add_option('--boost-libs', type='string',
|
||||
default='', dest='boost_libs',
|
||||
help='''path to the directory where the boost libs are, e.g., /path/to/boost_1_55_0/stage/lib''')
|
||||
opt.add_option('--boost-static', action='store_true',
|
||||
default=False, dest='boost_static',
|
||||
help='link with static boost libraries (.lib/.a)')
|
||||
opt.add_option('--boost-mt', action='store_true',
|
||||
default=False, dest='boost_mt',
|
||||
help='select multi-threaded libraries')
|
||||
opt.add_option('--boost-abi', type='string', default='', dest='boost_abi',
|
||||
help='''select libraries with tags (dgsyp, d for debug), see doc Boost, Getting Started, chapter 6.1''')
|
||||
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',
|
||||
help='force a toolset e.g. msvc, vc90, gcc, mingw, mgw45 (default: auto)')
|
||||
py_version = '%d%d' % (sys.version_info[0], sys.version_info[1])
|
||||
opt.add_option('--boost-python', type='string',
|
||||
default=py_version, dest='boost_python',
|
||||
help='select the lib python with this version (default: %s)' % py_version)
|
||||
opt = opt.add_option_group('Boost Options')
|
||||
opt.add_option('--boost-includes', type='string',
|
||||
default='', dest='boost_includes',
|
||||
help='''path to the directory where the boost includes are,
|
||||
e.g., /path/to/boost_1_55_0/stage/include''')
|
||||
opt.add_option('--boost-libs', type='string',
|
||||
default='', dest='boost_libs',
|
||||
help='''path to the directory where the boost libs are,
|
||||
e.g., path/to/boost_1_55_0/stage/lib''')
|
||||
opt.add_option('--boost-mt', action='store_true',
|
||||
default=False, dest='boost_mt',
|
||||
help='select multi-threaded libraries')
|
||||
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',
|
||||
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',
|
||||
help='force a toolset e.g. msvc, vc90, \
|
||||
gcc, mingw, mgw45 (default: auto)')
|
||||
py_version = '%d%d' % (sys.version_info[0], sys.version_info[1])
|
||||
opt.add_option('--boost-python', type='string',
|
||||
default=py_version, dest='boost_python',
|
||||
help='select the lib python with this version \
|
||||
(default: %s)' % py_version)
|
||||
|
||||
|
||||
@conf
|
||||
def __boost_get_version_file(self, d):
|
||||
dnode = self.root.find_dir(d)
|
||||
if dnode:
|
||||
return dnode.find_node(BOOST_VERSION_FILE)
|
||||
return None
|
||||
if not d:
|
||||
return None
|
||||
dnode = self.root.find_dir(d)
|
||||
if dnode:
|
||||
return dnode.find_node(BOOST_VERSION_FILE)
|
||||
return None
|
||||
|
||||
@conf
|
||||
def boost_get_version(self, d):
|
||||
"""silently retrieve the boost version number"""
|
||||
node = self.__boost_get_version_file(d)
|
||||
if node:
|
||||
try:
|
||||
txt = node.read()
|
||||
except (OSError, IOError):
|
||||
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)
|
||||
|
||||
re_but2 = re.compile('^#define\\s+BOOST_VERSION\\s+(\\d+)', re.M)
|
||||
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(":")
|
||||
"""silently retrieve the boost version number"""
|
||||
node = self.__boost_get_version_file(d)
|
||||
if node:
|
||||
try:
|
||||
txt = node.read()
|
||||
except EnvironmentError:
|
||||
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)
|
||||
re_but2 = re.compile('^#define\\s+BOOST_VERSION\\s+(\\d+)', re.M)
|
||||
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(':')
|
||||
|
||||
@conf
|
||||
def boost_get_includes(self, *k, **kw):
|
||||
includes = k and k[0] or kw.get('includes', None)
|
||||
if includes and self.__boost_get_version_file(includes):
|
||||
return includes
|
||||
for d in Utils.to_list(self.environ.get('INCLUDE', '')) + BOOST_INCLUDES:
|
||||
if self.__boost_get_version_file(d):
|
||||
return d
|
||||
if includes:
|
||||
self.end_msg('headers not found in %s' % includes)
|
||||
self.fatal('The configuration failed')
|
||||
else:
|
||||
self.end_msg('headers not found, please provide a --boost-includes argument (see help)')
|
||||
self.fatal('The configuration failed')
|
||||
includes = k and k[0] or kw.get('includes', None)
|
||||
if includes and self.__boost_get_version_file(includes):
|
||||
return includes
|
||||
for d in self.environ.get('INCLUDE', '').split(';') + BOOST_INCLUDES:
|
||||
if self.__boost_get_version_file(d):
|
||||
return d
|
||||
if 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)', 'YELLOW')
|
||||
self.fatal('The configuration failed')
|
||||
|
||||
|
||||
@conf
|
||||
def boost_get_toolset(self, cc):
|
||||
toolset = cc
|
||||
if not cc:
|
||||
build_platform = Utils.unversioned_sys_platform()
|
||||
if build_platform in BOOST_TOOLSETS:
|
||||
cc = build_platform
|
||||
else:
|
||||
cc = self.env.CXX_NAME
|
||||
if cc in BOOST_TOOLSETS:
|
||||
toolset = BOOST_TOOLSETS[cc]
|
||||
return isinstance(toolset, str) and toolset or toolset(self.env)
|
||||
toolset = cc
|
||||
if not cc:
|
||||
build_platform = Utils.unversioned_sys_platform()
|
||||
if build_platform in BOOST_TOOLSETS:
|
||||
cc = build_platform
|
||||
else:
|
||||
cc = self.env.CXX_NAME
|
||||
if cc in BOOST_TOOLSETS:
|
||||
toolset = BOOST_TOOLSETS[cc]
|
||||
return isinstance(toolset, str) and toolset or toolset(self.env)
|
||||
|
||||
|
||||
@conf
|
||||
def __boost_get_libs_path(self, *k, **kw):
|
||||
''' return the lib path and all the files in it '''
|
||||
if 'files' in kw:
|
||||
return self.root.find_dir('.'), Utils.to_list(kw['files'])
|
||||
libs = k and k[0] or kw.get('libs', None)
|
||||
if libs:
|
||||
path = self.root.find_dir(libs)
|
||||
files = path.ant_glob('*boost_*')
|
||||
if not libs or not files:
|
||||
for d in Utils.to_list(self.environ.get('LIB', [])) + BOOST_LIBS:
|
||||
path = self.root.find_dir(d)
|
||||
if path:
|
||||
files = path.ant_glob('*boost_*')
|
||||
if files:
|
||||
break
|
||||
path = self.root.find_dir(d + '64')
|
||||
if path:
|
||||
files = path.ant_glob('*boost_*')
|
||||
if files:
|
||||
break
|
||||
if not path:
|
||||
if libs:
|
||||
self.end_msg('libs not found in %s' % libs)
|
||||
self.fatal('The configuration failed')
|
||||
else:
|
||||
self.end_msg('libs not found, please provide a --boost-libs argument (see help)')
|
||||
self.fatal('The configuration failed')
|
||||
''' return the lib path and all the files in it '''
|
||||
if 'files' in kw:
|
||||
return self.root.find_dir('.'), Utils.to_list(kw['files'])
|
||||
libs = k and k[0] or kw.get('libs', None)
|
||||
if libs:
|
||||
path = self.root.find_dir(libs)
|
||||
files = path.ant_glob('*boost_*')
|
||||
if not libs or not files:
|
||||
for d in self.environ.get('LIB', '').split(';') + BOOST_LIBS:
|
||||
if not d:
|
||||
continue
|
||||
path = self.root.find_dir(d)
|
||||
if path:
|
||||
files = path.ant_glob('*boost_*')
|
||||
if files:
|
||||
break
|
||||
path = self.root.find_dir(d + '64')
|
||||
if path:
|
||||
files = path.ant_glob('*boost_*')
|
||||
if files:
|
||||
break
|
||||
if not path:
|
||||
if 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)', 'YELLOW')
|
||||
self.fatal('The configuration failed')
|
||||
|
||||
self.to_log('Found the boost path in %r with the libraries:' % path)
|
||||
for x in files:
|
||||
self.to_log(' %r' % x)
|
||||
return path, files
|
||||
self.to_log('Found the boost path in %r with the libraries:' % path)
|
||||
for x in files:
|
||||
self.to_log(' %r' % x)
|
||||
return path, files
|
||||
|
||||
@conf
|
||||
def boost_get_libs(self, *k, **kw):
|
||||
'''
|
||||
return the lib path and the required libs
|
||||
according to the parameters
|
||||
'''
|
||||
path, files = self.__boost_get_libs_path(**kw)
|
||||
files = sorted(files, key=lambda f: (len(f.name), f.name), reverse=True)
|
||||
toolset = self.boost_get_toolset(kw.get('toolset', ''))
|
||||
toolset_pat = '(-%s[0-9]{0,3})' % toolset
|
||||
version = '-%s' % self.env.BOOST_VERSION
|
||||
|
||||
def find_lib(re_lib, files):
|
||||
for file in files:
|
||||
if re_lib.search(file.name):
|
||||
self.to_log('Found boost lib %s' % file)
|
||||
return file
|
||||
return None
|
||||
|
||||
def format_lib_name(name):
|
||||
if name.startswith('lib') and self.env.CC_NAME != 'msvc':
|
||||
name = name[3:]
|
||||
return name[:name.rfind('.')]
|
||||
|
||||
def match_libs(lib_names, is_static):
|
||||
libs = []
|
||||
lib_names = Utils.to_list(lib_names)
|
||||
if not lib_names:
|
||||
return libs
|
||||
t = []
|
||||
if kw.get('mt', False):
|
||||
t.append('-mt')
|
||||
if kw.get('abi', None):
|
||||
t.append('%s%s' % (is_static and '-s' or '-', kw['abi']))
|
||||
elif is_static:
|
||||
t.append('-s')
|
||||
tags_pat = t and ''.join(t) or ''
|
||||
ext = is_static and self.env.cxxstlib_PATTERN or self.env.cxxshlib_PATTERN
|
||||
ext = ext.partition('%s')[2] # remove '%s' or 'lib%s' from PATTERN
|
||||
|
||||
for lib in lib_names:
|
||||
if lib == 'python':
|
||||
# for instance, with python='27',
|
||||
# accepts '-py27', '-py2', '27' and '2'
|
||||
# but will reject '-py3', '-py26', '26' and '3'
|
||||
tags = '({0})?((-py{2})|(-py{1}(?=[^0-9]))|({2})|({1}(?=[^0-9]))|(?=[^0-9])(?!-py))'.format(tags_pat, kw['python'][0], kw['python'])
|
||||
else:
|
||||
tags = tags_pat
|
||||
# Trying libraries, from most strict match to least one
|
||||
for pattern in ['boost_%s%s%s%s%s$' % (lib, toolset_pat, tags, version, ext),
|
||||
'boost_%s%s%s%s$' % (lib, tags, version, ext),
|
||||
# Give up trying to find the right version
|
||||
'boost_%s%s%s%s$' % (lib, toolset_pat, tags, ext),
|
||||
'boost_%s%s%s$' % (lib, tags, ext),
|
||||
'boost_%s%s$' % (lib, ext),
|
||||
'boost_%s' % lib]:
|
||||
self.to_log('Trying pattern %s' % pattern)
|
||||
file = find_lib(re.compile(pattern), files)
|
||||
if file:
|
||||
libs.append(format_lib_name(file.name))
|
||||
break
|
||||
else:
|
||||
self.end_msg('lib %s not found in %s' % (lib, path.abspath()), 'YELLOW')
|
||||
self.fatal('The configuration failed')
|
||||
return libs
|
||||
|
||||
return path.abspath(), match_libs(kw.get('lib', None), False), match_libs(kw.get('stlib', None), True)
|
||||
|
||||
@conf
|
||||
def _check_pthread_flag(self, *k, **kw):
|
||||
'''
|
||||
Computes which flags should be added to CXXFLAGS and LINKFLAGS to compile in multi-threading mode
|
||||
|
||||
Yes, we *need* to put the -pthread thing in CPPFLAGS because with GCC3,
|
||||
boost/thread.hpp will trigger a #error if -pthread isn't used:
|
||||
boost/config/requires_threads.hpp:47:5: #error "Compiler threading support
|
||||
is not turned on. Please set the correct command line options for
|
||||
threading: -pthread (Linux), -pthreads (Solaris) or -mthreads (Mingw32)"
|
||||
|
||||
Based on _BOOST_PTHREAD_FLAG(): https://github.com/tsuna/boost.m4/blob/master/build-aux/boost.m4
|
||||
'''
|
||||
return the lib path and the required libs
|
||||
according to the parameters
|
||||
'''
|
||||
path, files = self.__boost_get_libs_path(**kw)
|
||||
t = []
|
||||
if kw.get('mt', False):
|
||||
t.append('mt')
|
||||
if kw.get('abi', None):
|
||||
t.append(kw['abi'])
|
||||
tags = t and '(-%s)+' % '-'.join(t) or ''
|
||||
toolset = self.boost_get_toolset(kw.get('toolset', ''))
|
||||
toolset_pat = '(-%s[0-9]{0,3})+' % toolset
|
||||
version = '(-%s)+' % self.env.BOOST_VERSION
|
||||
|
||||
def find_lib(re_lib, files):
|
||||
for file in files:
|
||||
if re_lib.search(file.name):
|
||||
self.to_log('Found boost lib %s' % file)
|
||||
return file
|
||||
return None
|
||||
var = kw.get('uselib_store', 'BOOST')
|
||||
|
||||
def format_lib_name(name):
|
||||
if name.startswith('lib') and self.env.CC_NAME != 'msvc':
|
||||
name = name[3:]
|
||||
return name[:name.rfind('.')]
|
||||
self.start_msg('Checking the flags needed to use pthreads')
|
||||
|
||||
libs = []
|
||||
for lib in Utils.to_list(k and k[0] or kw.get('lib', None)):
|
||||
py = (lib == 'python') and '(-py%s)+' % kw['python'] or ''
|
||||
# Trying libraries, from most strict match to least one
|
||||
for pattern in ['boost_%s%s%s%s%s' % (lib, toolset_pat, tags, py, version),
|
||||
'boost_%s%s%s%s' % (lib, tags, py, version),
|
||||
'boost_%s%s%s' % (lib, tags, version),
|
||||
# Give up trying to find the right version
|
||||
'boost_%s%s%s%s' % (lib, toolset_pat, tags, py),
|
||||
'boost_%s%s%s' % (lib, tags, py),
|
||||
'boost_%s%s' % (lib, tags)]:
|
||||
self.to_log('Trying pattern %s' % pattern)
|
||||
file = find_lib(re.compile(pattern), files)
|
||||
if file:
|
||||
libs.append(format_lib_name(file.name))
|
||||
break
|
||||
else:
|
||||
self.end_msg('lib %s not found in %s' % (lib, path.abspath()))
|
||||
self.fatal('The configuration failed')
|
||||
|
||||
return path.abspath(), libs
|
||||
# The ordering *is* (sometimes) important. Some notes on the
|
||||
# individual items follow:
|
||||
# (none): in case threads are in libc; should be tried before -Kthread and
|
||||
# other compiler flags to prevent continual compiler warnings
|
||||
# -lpthreads: AIX (must check this before -lpthread)
|
||||
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# -llthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
# -pthread: GNU Linux/GCC (kernel threads), BSD/GCC (userland threads)
|
||||
# -pthreads: Solaris/GCC
|
||||
# -mthreads: MinGW32/GCC, Lynx/GCC
|
||||
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
||||
# doesn't hurt to check since this sometimes defines pthreads too;
|
||||
# also defines -D_REENTRANT)
|
||||
# ... -mt is also the pthreads flag for HP/aCC
|
||||
# -lpthread: GNU Linux, etc.
|
||||
# --thread-safe: KAI C++
|
||||
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/
|
||||
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
|
||||
# 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']
|
||||
else:
|
||||
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, quiet=True)
|
||||
self.end_msg(boost_pthread_flag)
|
||||
return
|
||||
except self.errors.ConfigurationError:
|
||||
self.env.revert()
|
||||
self.end_msg('none')
|
||||
|
||||
@conf
|
||||
def check_boost(self, *k, **kw):
|
||||
"""
|
||||
Initialize boost libraries to be used.
|
||||
"""
|
||||
Initialize boost libraries to be used.
|
||||
|
||||
Keywords: you can pass the same parameters as with the command line (without "--boost-").
|
||||
Note that the command line has the priority, and should preferably be used.
|
||||
"""
|
||||
if not self.env['CXX']:
|
||||
self.fatal('load a c++ compiler first, conf.load("compiler_cxx")')
|
||||
Keywords: you can pass the same parameters as with the command line (without "--boost-").
|
||||
Note that the command line has the priority, and should preferably be used.
|
||||
"""
|
||||
if not self.env['CXX']:
|
||||
self.fatal('load a c++ compiler first, conf.load("compiler_cxx")')
|
||||
|
||||
params = {'lib': k and k[0] or kw.get('lib', None)}
|
||||
for key, value in self.options.__dict__.items():
|
||||
if not key.startswith('boost_'):
|
||||
continue
|
||||
key = key[len('boost_'):]
|
||||
params[key] = value and value or kw.get(key, '')
|
||||
params = {
|
||||
'lib': k and k[0] or kw.get('lib', None),
|
||||
'stlib': kw.get('stlib', None)
|
||||
}
|
||||
for key, value in self.options.__dict__.items():
|
||||
if not key.startswith('boost_'):
|
||||
continue
|
||||
key = key[len('boost_'):]
|
||||
params[key] = value and value or kw.get(key, '')
|
||||
|
||||
var = kw.get('uselib_store', 'BOOST')
|
||||
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())
|
||||
|
||||
if not params['lib']:
|
||||
return
|
||||
self.start_msg('Checking boost libs')
|
||||
suffix = params.get('static', None) and 'ST' or ''
|
||||
path, libs = self.boost_get_libs(**params)
|
||||
self.env['%sLIBPATH_%s' % (suffix, var)] = [path]
|
||||
self.env['%sLIB_%s' % (suffix, var)] = libs
|
||||
self.end_msg('ok')
|
||||
if Logs.verbose:
|
||||
Logs.pprint('CYAN', ' path : %s' % path)
|
||||
Logs.pprint('CYAN', ' libs : %s' % libs)
|
||||
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
|
||||
if 'static' in kw or 'static' in params:
|
||||
Logs.warn('boost: static parameter is deprecated, use stlib instead.')
|
||||
self.start_msg('Checking boost libs')
|
||||
path, libs, stlibs = self.boost_get_libs(**params)
|
||||
self.env['LIBPATH_%s' % var] = [path]
|
||||
self.env['STLIBPATH_%s' % var] = [path]
|
||||
self.env['LIB_%s' % var] = libs
|
||||
self.env['STLIB_%s' % var] = stlibs
|
||||
self.end_msg(' '.join(libs + stlibs))
|
||||
if Logs.verbose:
|
||||
Logs.pprint('CYAN', ' path : %s' % path)
|
||||
Logs.pprint('CYAN', ' shared libs : %s' % libs)
|
||||
Logs.pprint('CYAN', ' static libs : %s' % stlibs)
|
||||
|
||||
def has_shlib(lib):
|
||||
return params['lib'] and lib in params['lib']
|
||||
def has_stlib(lib):
|
||||
return params['stlib'] and lib in params['stlib']
|
||||
def has_lib(lib):
|
||||
return has_shlib(lib) or has_stlib(lib)
|
||||
if has_lib('thread'):
|
||||
# not inside try_link to make check visible in the output
|
||||
self._check_pthread_flag(k, kw)
|
||||
|
||||
def try_link():
|
||||
if has_lib('system'):
|
||||
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') or has_lib('log_setup'):
|
||||
if not has_lib('thread'):
|
||||
self.env['DEFINES_%s' % var] += ['BOOST_LOG_NO_THREADS']
|
||||
if has_shlib('log') or has_shlib('log_setup'):
|
||||
self.env['DEFINES_%s' % var] += ['BOOST_LOG_DYN_LINK']
|
||||
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')
|
||||
toolset = self.boost_get_toolset(kw.get('toolset', ''))
|
||||
if toolset in ('vc',):
|
||||
# disable auto-linking feature, causing error LNK1181
|
||||
# because the code wants to be linked against
|
||||
self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB']
|
||||
|
||||
# if no dlls are present, we guess the .lib files are not stubs
|
||||
has_dlls = False
|
||||
for x in Utils.listdir(path):
|
||||
if x.endswith(self.env.cxxshlib_PATTERN % ''):
|
||||
has_dlls = True
|
||||
break
|
||||
if not has_dlls:
|
||||
self.env['STLIBPATH_%s' % var] = [path]
|
||||
self.env['STLIB_%s' % var] = libs
|
||||
del self.env['LIB_%s' % var]
|
||||
del self.env['LIBPATH_%s' % var]
|
||||
|
||||
# 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
|
||||
try:
|
||||
try_link()
|
||||
self.end_msg('ok: winning cxxflags combination: %s' % (self.env['CXXFLAGS_%s' % var]))
|
||||
exc = None
|
||||
break
|
||||
except Errors.ConfigurationError as e:
|
||||
self.env.revert()
|
||||
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.fatal('The configuration failed')
|
||||
else:
|
||||
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', 'YELLOW')
|
||||
self.fatal('The configuration failed')
|
||||
self.end_msg('ok')
|
||||
|
||||
|
||||
def try_link():
|
||||
if 'system' in params['lib']:
|
||||
self.check_cxx(
|
||||
fragment=BOOST_SYSTEM_CODE,
|
||||
use=var,
|
||||
execute=False,
|
||||
)
|
||||
if 'thread' in params['lib']:
|
||||
self.check_cxx(
|
||||
fragment=BOOST_THREAD_CODE,
|
||||
use=var,
|
||||
execute=False,
|
||||
)
|
||||
|
||||
if params.get('linkage_autodetect', False):
|
||||
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
|
||||
# because the code wants to be linked against
|
||||
self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB']
|
||||
|
||||
# if no dlls are present, we guess the .lib files are not stubs
|
||||
has_dlls = False
|
||||
for x in Utils.listdir(path):
|
||||
if x.endswith(self.env.cxxshlib_PATTERN % ''):
|
||||
has_dlls = True
|
||||
break
|
||||
if not has_dlls:
|
||||
self.env['STLIBPATH_%s' % var] = [path]
|
||||
self.env['STLIB_%s' % var] = libs
|
||||
del self.env['LIB_%s' % var]
|
||||
del self.env['LIBPATH_%s' % var]
|
||||
|
||||
# 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
|
||||
try:
|
||||
try_link()
|
||||
self.end_msg("ok: winning cxxflags combination: %s" % (self.env["CXXFLAGS_%s" % var]))
|
||||
e = None
|
||||
break
|
||||
except Errors.ConfigurationError as exc:
|
||||
self.env.revert()
|
||||
e = exc
|
||||
|
||||
if e is not None:
|
||||
self.end_msg("Could not auto-detect boost linking flags combination, you may report it to boost.py author", ex=e)
|
||||
self.fatal('The configuration failed')
|
||||
else:
|
||||
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.fatal('The configuration failed')
|
||||
self.end_msg('ok')
|
||||
@feature('cxx')
|
||||
@after_method('apply_link')
|
||||
def install_boost(self):
|
||||
if install_boost.done or not Utils.is_win32 or not self.bld.cmd.startswith('install'):
|
||||
return
|
||||
install_boost.done = True
|
||||
inst_to = getattr(self, 'install_path', '${BINDIR}')
|
||||
for lib in self.env.LIB_BOOST:
|
||||
try:
|
||||
file = self.bld.find_file(self.env.cxxshlib_PATTERN % lib, self.env.LIBPATH_BOOST)
|
||||
self.bld.install_files(inst_to, self.bld.root.find_node(file))
|
||||
except:
|
||||
continue
|
||||
install_boost.done = False
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
from waflib import TaskGen
|
||||
|
||||
def options(opt):
|
||||
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.check_cxx(cxxflags=['-fprofile-arcs', '-ftest-coverage', '-fPIC'],
|
||||
linkflags=['-fprofile-arcs'], uselib_store='GCOV', mandatory=True)
|
||||
|
||||
@TaskGen.feature('cxx','cc')
|
||||
@TaskGen.after('process_source')
|
||||
def add_coverage(self):
|
||||
if getattr(self, 'use', ''):
|
||||
self.use += ' GCOV'
|
||||
else:
|
||||
self.use = 'GCOV'
|
||||
@@ -1,44 +1,74 @@
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
from waflib import Logs, Configure, Utils
|
||||
import platform
|
||||
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 (-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 7.4.0.')
|
||||
elif ccver < (7, 4, 0):
|
||||
warnmsg = ('Using a version of gcc older than 7.4.0 is not '
|
||||
'officially supported and may result in build failures.')
|
||||
conf.flags = GccFlags()
|
||||
elif cxx == 'clang':
|
||||
flags = ClangFlags()
|
||||
if Utils.unversioned_sys_platform() == 'darwin' and ccver < (9, 0, 0):
|
||||
errmsg = ('The version of Xcode you are using is too old.\n'
|
||||
'The minimum supported Xcode version is 9.0.')
|
||||
elif ccver < (4, 0, 0):
|
||||
errmsg = ('The version of clang you are using is too old.\n'
|
||||
'The minimum supported clang version is 4.0.')
|
||||
conf.flags = ClangFlags()
|
||||
else:
|
||||
flags = CompilerFlags()
|
||||
Logs.warn('The code has not yet been tested with %s compiler' % cxx)
|
||||
warnmsg = '%s compiler is unsupported' % cxx
|
||||
conf.flags = CompilerFlags()
|
||||
|
||||
areCustomCxxflagsPresent = (len(conf.env.CXXFLAGS) > 0)
|
||||
if errmsg:
|
||||
conf.end_msg(ccverstr, color='RED')
|
||||
conf.fatal(errmsg)
|
||||
elif warnmsg:
|
||||
conf.end_msg(ccverstr, color='YELLOW')
|
||||
Logs.warn('WARNING: ' + warnmsg)
|
||||
else:
|
||||
conf.end_msg(ccverstr)
|
||||
|
||||
# General flags are always applied (e.g., selecting C++11 mode)
|
||||
generalFlags = flags.getGeneralFlags(conf)
|
||||
conf.areCustomCxxflagsPresent = (len(conf.env.CXXFLAGS) > 0)
|
||||
|
||||
# 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,12 +85,13 @@ 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.CXXFLAGS = supportedFlags + self.env.CXXFLAGS
|
||||
self.env.prepend_value('CXXFLAGS', supportedFlags)
|
||||
|
||||
@Configure.conf
|
||||
def add_supported_linkflags(self, linkflags):
|
||||
@@ -73,15 +104,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.LINKFLAGS = supportedFlags + self.env.LINKFLAGS
|
||||
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,17 +133,31 @@ 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',
|
||||
flags['CXXFLAGS'] += ['-Og',
|
||||
'-g3',
|
||||
'-pedantic',
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-Werror',
|
||||
'-Wno-unused-parameter',
|
||||
'-Wcatch-value=2',
|
||||
'-Wextra-semi',
|
||||
'-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):
|
||||
@@ -118,72 +167,61 @@ class GccBasicFlags(CompilerFlags):
|
||||
'-pedantic',
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-Wcatch-value=2',
|
||||
'-Wextra-semi',
|
||||
'-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, 6, 0):
|
||||
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.6.0.')
|
||||
elif version < (4, 7, 0):
|
||||
flags['CXXFLAGS'] += ['-std=c++0x']
|
||||
else:
|
||||
flags['CXXFLAGS'] += ['-std=c++11']
|
||||
if version < (4, 8, 0):
|
||||
flags['DEFINES'] += ['_GLIBCXX_USE_NANOSLEEP'] # Bug #2499
|
||||
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',
|
||||
'-Wredundant-tags',
|
||||
]
|
||||
if platform.machine() == 'armv7l' and self.getCompilerVersion(conf) >= (7, 1, 0):
|
||||
flags['CXXFLAGS'] += ['-Wno-psabi'] # Bug #5106
|
||||
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',
|
||||
'-Wredundant-tags',
|
||||
]
|
||||
if platform.machine() == 'armv7l' and self.getCompilerVersion(conf) >= (7, 1, 0):
|
||||
flags['CXXFLAGS'] += ['-Wno-psabi'] # Bug #5106
|
||||
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++']
|
||||
# Bug #4296
|
||||
flags['CXXFLAGS'] += [['-isystem', '/usr/local/include'], # for Homebrew
|
||||
['-isystem', '/opt/local/include']] # for MacPorts
|
||||
elif Utils.unversioned_sys_platform() == 'freebsd':
|
||||
# Bug #4790
|
||||
flags['CXXFLAGS'] += [['-isystem', '/usr/local/include']]
|
||||
return flags
|
||||
|
||||
def getDebugFlags(self, conf):
|
||||
flags = super(ClangFlags, self).getDebugFlags(conf)
|
||||
version = tuple(int(i) for i in conf.env['CC_VERSION'])
|
||||
if Utils.unversioned_sys_platform() == 'darwin' and version < (7, 0, 0):
|
||||
flags['CXXFLAGS'] += ['-Wno-missing-field-initializers']
|
||||
flags['CXXFLAGS'] += ['-fcolor-diagnostics',
|
||||
'-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
|
||||
]
|
||||
if self.getCompilerVersion(conf) < (6, 0, 0):
|
||||
flags['CXXFLAGS'] += ['-Wno-missing-braces'] # Bug #4721
|
||||
return flags
|
||||
|
||||
def getOptimizedFlags(self, conf):
|
||||
flags = super(ClangFlags, self).getOptimizedFlags(conf)
|
||||
version = tuple(int(i) for i in conf.env['CC_VERSION'])
|
||||
if Utils.unversioned_sys_platform() == 'darwin' and version < (7, 0, 0):
|
||||
flags['CXXFLAGS'] += ['-Wno-missing-field-initializers']
|
||||
flags['CXXFLAGS'] += ['-fcolor-diagnostics',
|
||||
'-Wundefined-func-template',
|
||||
'-Wno-unused-local-typedef', # Bugs #2657 and #3209
|
||||
]
|
||||
if self.getCompilerVersion(conf) < (6, 0, 0):
|
||||
flags['CXXFLAGS'] += ['-Wno-missing-braces'] # Bug #4721
|
||||
return flags
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
def options(opt):
|
||||
opt.add_option('--with-sanitizer', action='store', default='', dest='sanitizers',
|
||||
help='Comma-separated list of compiler sanitizers to enable [default=none]')
|
||||
|
||||
def configure(conf):
|
||||
for san in conf.options.sanitizers.split(','):
|
||||
if not san:
|
||||
continue
|
||||
|
||||
sanflag = '-fsanitize=%s' % san
|
||||
conf.start_msg('Checking if compiler supports %s' % sanflag)
|
||||
|
||||
if conf.check_cxx(cxxflags=['-Werror', sanflag, '-fno-omit-frame-pointer'],
|
||||
linkflags=[sanflag], mandatory=False):
|
||||
conf.end_msg('yes')
|
||||
conf.env.append_unique('CXXFLAGS', [sanflag, '-fno-omit-frame-pointer'])
|
||||
conf.env.append_unique('LINKFLAGS', [sanflag])
|
||||
else:
|
||||
conf.end_msg('no', color='RED')
|
||||
conf.fatal('%s sanitizer is not supported by the current compiler' % san)
|
||||
@@ -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)
|
||||
|
||||
|
||||
+31
-20
@@ -1,22 +1,33 @@
|
||||
# ndn-tools authors
|
||||
# ndn-tools Authors
|
||||
|
||||
## All project authors and contributors
|
||||
The following lists maintainers, primary developers, and all much-appreciated contributors to ndn-tools in alphabetical order.
|
||||
The specific contributions of individual authors can be obtained from the git history of the [official ndn-tools repository](https://github.com/named-data/ndn-tools).
|
||||
If you would like to become a contributor to the official repository, please follow the recommendations in https://github.com/named-data/.github/blob/master/CONTRIBUTING.md.
|
||||
|
||||
The following is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS,
|
||||
people who have reported bugs, submitted patches, and implemented new features
|
||||
in ndn-tools:
|
||||
|
||||
* Jerald Paul Abraham <http://www.cs.arizona.edu/people/jeraldabraham/>
|
||||
* Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
|
||||
* Davide Pesavento <http://www.lip6.fr/actualite/personnes-fiche.php?ident=D1469>
|
||||
* Junxiao Shi <http://www.cs.arizona.edu/people/shijunxiao/>
|
||||
* Eric Newberry <http://ericnewberry.com/>
|
||||
* Xiaoke Jiang <http://netarchlab.tsinghua.edu.cn/~shock/>
|
||||
* Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
|
||||
* Qi Zhao <https://www.linkedin.com/pub/qi-zhao/73/835/9a3>
|
||||
* Seunghyun Yoo <http://relue2718.com/>
|
||||
* Seungbae Kim <https://sites.google.com/site/sbkimcv/>
|
||||
* Wentao Shang <http://irl.cs.ucla.edu/~wentao/>
|
||||
* Steve DiBenedetto <https://dibenede.github.io>
|
||||
* Andrea Tosatto <https://linkedin.com/in/tosattoandrea>
|
||||
* Vince Lehman <http://vslehman.com>
|
||||
* Jerald Paul Abraham <https://cs.arizona.edu/~jeraldabraham>
|
||||
* ***(Maintainer)*** Alexander Afanasyev <https://users.cs.fiu.edu/~afanasyev>
|
||||
* Stephanie DiBenedetto
|
||||
* Ashlesh Gawande <https://www.linkedin.com/in/agawande>
|
||||
* Chavoosh Ghasemi <https://chavoosh.github.io>
|
||||
* Nick Gordon <https://github.com/gorgonical>
|
||||
* Xiaoke Jiang <http://netarchlab.tsinghua.edu.cn/~shock>
|
||||
* Seungbae Kim <https://sites.google.com/site/sbkimcv>
|
||||
* Vince Lehman <http://vslehman.com>
|
||||
* Zhuo Li <https://github.com/mrzhuoli>
|
||||
* Teng Liang <https://cs.arizona.edu/~philoliang>
|
||||
* Weiwei Liu <https://www.linkedin.com/in/weiweiliu10>
|
||||
* Eric Newberry <https://ericnewberry.com>
|
||||
* João Pereira <http://www.jpereira.co.uk>
|
||||
* ***(Maintainer)*** Davide Pesavento <https://github.com/Pesa>
|
||||
* Klaus Schneider <https://cs.arizona.edu/~klaus>
|
||||
* Wentao Shang <https://irl.cs.ucla.edu/~wentao>
|
||||
* Susmit Shannigrahi <https://susm.it>
|
||||
* Junxiao Shi <https://cs.arizona.edu/~shijunxiao>
|
||||
* Jeff Thompson <https://remap.ucla.edu/jeff-thompson>
|
||||
* Andrea Tosatto <https://linkedin.com/in/tosattoandrea>
|
||||
* Zipeng Wang <https://github.com/zpwang2113>
|
||||
* Ryan Wickman <https://rwickman.github.io>
|
||||
* Seunghyun Yoo <https://relue2718.com>
|
||||
* Qianshan Yu
|
||||
* Yingdi Yu <https://irl.cs.ucla.edu/~yingdi>
|
||||
* Qi Zhao <https://web.cs.ucla.edu/~qi.zhao>
|
||||
|
||||
+354
-356
File diff suppressed because it is too large
Load Diff
+19
-9
@@ -4,19 +4,29 @@ This document describes how to build and install ndn-tools.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Building ndn-tools requires [ndn-cxx](http://named-data.net/doc/ndn-cxx/current/)
|
||||
to be installed.
|
||||
Please see [Getting Started with ndn-cxx](http://named-data.net/doc/ndn-cxx/current/INSTALL.html)
|
||||
on how to install ndn-cxx.
|
||||
Note: if you have installed ndn-cxx from a binary package, please make sure development headers
|
||||
are installed (if using Ubuntu PPA, `ndn-cxx-dev` package is needed).
|
||||
- Install the [ndn-cxx](https://named-data.net/doc/ndn-cxx/current/) library and its prerequisites.
|
||||
Please see [Getting Started with ndn-cxx](https://named-data.net/doc/ndn-cxx/current/INSTALL.html)
|
||||
for how to install ndn-cxx.
|
||||
Note: If you have installed ndn-cxx from a binary package, please make sure development headers
|
||||
are installed (e.g., if using Ubuntu PPA, the `libndn-cxx-dev` package is needed).
|
||||
|
||||
Any operating system and compiler supported by ndn-cxx are supported by ndn-tools.
|
||||
Any operating system and compiler supported by ndn-cxx is supported by ndn-tools.
|
||||
|
||||
- `libpcap`
|
||||
|
||||
Comes with the base system on macOS.
|
||||
|
||||
On Ubuntu:
|
||||
|
||||
sudo apt install libpcap-dev
|
||||
|
||||
On CentOS and Fedora:
|
||||
|
||||
sudo dnf config-manager --enable powertools # CentOS only
|
||||
sudo dnf install libpcap-devel
|
||||
|
||||
## Build Steps
|
||||
|
||||
Waf meta build system is used by ndn-tools.
|
||||
|
||||
To configure, compile, and install ndn-tools, type the following commands
|
||||
in ndn-tools source directory:
|
||||
|
||||
|
||||
+38
-34
@@ -2,12 +2,12 @@
|
||||
|
||||
## Licensing Requirements
|
||||
|
||||
Contributions to ndn-tools MUST be licensed under GPL 3.0 or a compatible license.
|
||||
Contributions to ndn-tools must be licensed under the GPL 3.0 or a compatible license.
|
||||
If you choose GPL 3.0, include the following license boilerplate into all C++ code files:
|
||||
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) [Year(s)], [Copyright Holder(s)].
|
||||
/*
|
||||
* Copyright (c) [Year(s)] [Copyright Holder(s)].
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
@@ -26,91 +26,95 @@ If you choose GPL 3.0, include the following license boilerplate into all C++ co
|
||||
|
||||
## Directory Structure and Build Script
|
||||
|
||||
All tools are placed in subdirectories under `tools/` directory.
|
||||
All tools are placed in subdirectories of the [`tools`](tools) directory.
|
||||
|
||||
A tool can consist of one or more programs.
|
||||
For instance, a pair of consumer and producer programs that are designed to work together
|
||||
should be considered a single tool, not two separate tools.
|
||||
|
||||
Each tool MUST have a `wscript` build script in its subdirectory.
|
||||
It will be invoked if this tool is selected for the build.
|
||||
It SHOULD compile the programs into `build/bin` directory (`target='../../bin/foo'`).
|
||||
Each tool must have a `wscript` build script in its subdirectory. This script will be
|
||||
invoked automatically if the corresponding tool is selected for the build. It should
|
||||
compile the source code and produce one or more binaries in the `build/bin` directory
|
||||
(e.g., use `target='../../bin/foo'`).
|
||||
|
||||
### Shared Modules
|
||||
|
||||
Modules shared among multiple tools SHOULD be placed in `core/` directory.
|
||||
Modules shared among multiple tools should be placed in the [`core`](core) directory.
|
||||
They are available for use in all tools.
|
||||
|
||||
A header in `core/` can be included in a tool like `#include "core/foo.hpp"`.
|
||||
|
||||
`wscript` of a tool can link a program with modules in `core/` with `use='core-objects'`.
|
||||
The `wscript` of a tool can link a program with modules in `core/` with `use='core-objects'`.
|
||||
|
||||
### Documentation
|
||||
|
||||
`README.md` in the subdirectory of a tool SHOULD give a brief description.
|
||||
A file named `README.md` in the subdirectory of each tool should provide a brief
|
||||
description.
|
||||
|
||||
Manual pages for each program SHOULD be written in reStructuredText format
|
||||
and placed in `manpages/` directory.
|
||||
Manual pages for each program should be written in reStructuredText format
|
||||
and placed in the [`manpages`](manpages) directory.
|
||||
|
||||
## Code Guidelines
|
||||
|
||||
C++ code SHOULD conform to
|
||||
[ndn-cxx code style](http://named-data.net/doc/ndn-cxx/current/code-style.html).
|
||||
C++ code should conform to the
|
||||
[ndn-cxx code style](https://named-data.net/doc/ndn-cxx/current/code-style.html).
|
||||
|
||||
### Namespace
|
||||
|
||||
Types in each tool SHOULD be declared in a sub-namespace under `namespace ndn`.
|
||||
For example, a tool in `tools/foo` directory has namespace `ndn::foo`.
|
||||
Types in each tool should be declared in a sub-namespace inside `namespace ndn`.
|
||||
For example, a tool in `tools/foo` directory has namespace `ndn::foo`.
|
||||
This allows the tool to reference ndn-cxx types with unqualified name lookup.
|
||||
This also prevents name conflicts between ndn-cxx and tools.
|
||||
|
||||
Types in `core/` SHOULD be declared directly under `namespace ndn`,
|
||||
Types in `core/` should be declared directly inside `namespace ndn`,
|
||||
or in a sub-namespace if desired.
|
||||
|
||||
`using namespace` SHOULD NOT be used except within block scope.
|
||||
|
||||
### main Function
|
||||
|
||||
The main function of a program SHOULD be declared within its sub-namespace.
|
||||
This allows it to reference types in ndn-cxx and the tool with unqualified name lookup.
|
||||
The `main` function of a program should be declared as a static function in
|
||||
the namespace of the corresponding tool. This allows referencing types in
|
||||
ndn-cxx and the tool via unqualified name lookup.
|
||||
|
||||
Then, another main function in global namespace needs to be defined
|
||||
to call the main function in sub-namespace.
|
||||
Then, another (non-static) `main` function must be defined in the global
|
||||
namespace, and from there call the `main` function in the tool namespace.
|
||||
|
||||
For example:
|
||||
These two functions should appear in a file named `main.cpp` in the tool's
|
||||
subdirectory.
|
||||
|
||||
Example:
|
||||
|
||||
namespace ndn {
|
||||
namespace foo {
|
||||
|
||||
|
||||
class Bar
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Bar(Face& face);
|
||||
|
||||
|
||||
void
|
||||
run();
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
|
||||
static int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
Face face;
|
||||
Bar program(face);
|
||||
program.run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
} // namespace foo
|
||||
} // namespace ndn
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
return ndn::foo::main(argc, argv);
|
||||
}
|
||||
|
||||
### Command Line Arguments
|
||||
|
||||
[Boost.Program\_options](http://www.boost.org/doc/libs/1_48_0/doc/html/program_options.html) is
|
||||
preferred over getopt(3) for parsing command line arguments.
|
||||
[Boost.Program\_options](https://www.boost.org/doc/libs/1_65_1/doc/html/program_options.html)
|
||||
is strongly preferred over `getopt(3)` for parsing command line arguments.
|
||||
|
||||
@@ -1,22 +1,39 @@
|
||||
# NDN Essential Tools
|
||||
|
||||
**ndn-tools** is a collection of essential tools for
|
||||
[Named Data Networking](http://named-data.net/).
|
||||
These tools are recommended to be installed on all NDN nodes.
|
||||
[](https://github.com/named-data/ndn-tools/actions/workflows/ci.yml)
|
||||
[](https://github.com/named-data/ndn-tools/actions/workflows/docs.yml)
|
||||

|
||||

|
||||
|
||||
**ndn-tools** is a collection of basic tools for [Named Data Networking](https://named-data.net/).
|
||||
Tools in this collection include:
|
||||
|
||||
* [peek](tools/peek): transmit a single packet between a consumer and a producer
|
||||
* [chunks](tools/chunks): segmented file transfer between a consumer and producer
|
||||
* [ping](tools/ping): test reachability between two nodes
|
||||
* [dump](tools/dump): analyze traffic on wire
|
||||
* [dissect](tools/dissect): inspect TLV structure of NDN packet format
|
||||
* [dissect-wireshark](tools/dissect-wireshark): Wireshark extension to inspect TLV structure of NDN
|
||||
packets
|
||||
* [pib](tools/pib): a service to manage the public information of keys and publish certificates
|
||||
* [peek](tools/peek): transmit a single Interest/Data packet between a consumer
|
||||
and a producer
|
||||
* [chunks](tools/chunks): segmented file transfer between a consumer and a producer
|
||||
* [ping](tools/ping): test reachability between two NDN nodes
|
||||
* [dump](tools/dump): capture and analyze live traffic on an NDN network
|
||||
* [dissect](tools/dissect): inspect the TLV structure of an NDN packet
|
||||
* [dissect-wireshark](tools/dissect-wireshark): Wireshark extension to inspect
|
||||
the TLV structure of NDN packets
|
||||
|
||||
See [INSTALL.md](INSTALL.md) for build instructions.
|
||||
## Installation
|
||||
|
||||
Please file bug reports and feature requests on
|
||||
[ndn-tools Redmine site](http://redmine.named-data.net/projects/ndn-tools).
|
||||
You may contribute code on [NDN Gerrit](http://gerrit.named-data.net).
|
||||
GitHub pull requests are not accepted.
|
||||
See [`INSTALL.md`](INSTALL.md) for build instructions.
|
||||
|
||||
## Reporting bugs
|
||||
|
||||
Please submit any bug reports or feature requests to the
|
||||
[ndn-tools issue tracker](https://redmine.named-data.net/projects/ndn-tools/issues).
|
||||
|
||||
## Contributing
|
||||
|
||||
We greatly appreciate contributions to ndn-tools. If you are new to the NDN
|
||||
software community, please read [`README-dev.md`](README-dev.md) and the
|
||||
[Contributor's Guide](https://github.com/named-data/.github/blob/master/CONTRIBUTING.md)
|
||||
to get started.
|
||||
|
||||
## License
|
||||
|
||||
ndn-tools is an open source project licensed under the GPL version 3.
|
||||
See [`COPYING.md`](COPYING.md) for more information.
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
# Release Notes
|
||||
|
||||
## Version 22.02
|
||||
|
||||
Starting with this release, ndn-tools switched to a new versioning scheme:
|
||||
`YEAR.MONTH[.REVISION]`.
|
||||
|
||||
chunks:
|
||||
- Add `--naming-convention` command-line option (Issue #5109)
|
||||
- Increase the default segment size to 8000 bytes
|
||||
|
||||
dissect:
|
||||
- Support `InterestSignature` fields and more types of name components
|
||||
- The `Content` field is no longer dissected by default; use the new `--content` option
|
||||
to enable it
|
||||
- Minor cosmetic improvements to the tool output
|
||||
|
||||
dissect-wireshark:
|
||||
- Remove support for obsolete TLV elements
|
||||
- Recognize `ForwardingHint` (Issue #4185)
|
||||
- Recognize `ParametersSha256DigestComponent`
|
||||
- Fix decoding of several TLV elements such as `HopLimit` and `PitToken`
|
||||
- Update the TLV type of `IncomingFaceId` (Issue #5185)
|
||||
|
||||
peek:
|
||||
- Replace `--link-file` option with `--fwhint` and adapt to the new `ForwardingHint`
|
||||
format (Issues #4207, #5187)
|
||||
|
||||
poke:
|
||||
- Remove deprecated `--force` option; use `--unsolicited` instead
|
||||
- Remove deprecated `--identity` and `--digest` options; use `--signing-info` instead
|
||||
- Change the short form of `--freshness` to `-f`
|
||||
|
||||
pingserver:
|
||||
- Remove deprecated `-x` alias for the `--freshness` option
|
||||
|
||||
build system:
|
||||
- Upgrade `waf` to version 2.0.23
|
||||
|
||||
## Version 0.7.1
|
||||
|
||||
The build requirements have been increased to require Clang >= 4.0, Xcode >= 9.0, and Python >= 3.6.
|
||||
Meanwhile, it is *recommended* to use GCC >= 7.4.0 and Boost >= 1.65.1.
|
||||
|
||||
This release contains minor build fixes and code cleanups.
|
||||
|
||||
## Version 0.7
|
||||
|
||||
chunks:
|
||||
- Add `--no-version-discovery` option to ndncatchunks (Issue #5021)
|
||||
- Improve CUBIC performance on lossy networks (Issue #5036)
|
||||
- Switch to ndn-cxx's `RttEstimatorWithStats` class (Issue #4887)
|
||||
- Remove previously deprecated options `-d` and `-t` from ndncatchunks
|
||||
|
||||
ping:
|
||||
- Change the short form of ndnpingserver's `--freshness` option to `-f`,
|
||||
for consistency with ndnputchunks
|
||||
|
||||
peek:
|
||||
- Add `--app-params`, `--app-params-file`, and `--hop-limit` options
|
||||
- The `--link-file` option now expects a raw binary file
|
||||
- Print Data name and Nack reason if `--verbose` is specified
|
||||
- Code cleanup
|
||||
- Manual page improvements
|
||||
|
||||
poke:
|
||||
- Add `--signing-info` option, replacing `--digest` and `--identity` which are
|
||||
now deprecated
|
||||
- Add `--verbose` option
|
||||
- Wait indefinitely if `--timeout` is not specified
|
||||
- The program now exits with status 3 when a timeout occurs and with status 5
|
||||
if prefix registration fails
|
||||
- Rename `--force` option to `--unsolicited`
|
||||
- Code cleanup
|
||||
- Major rewrite of the manual page
|
||||
|
||||
## Version 0.6.4
|
||||
|
||||
chunks:
|
||||
- Add metadata-based version discovery and remove iterative discovery (Issue #4556)
|
||||
- Remove manual selection of version discovery method via `-d` option (Issue #4832)
|
||||
- Implement CUBIC congestion window adaptation in ndncatchunks (Issue #4861)
|
||||
- Increase the default retransmission limit from 3 to 15 (Issue #4861)
|
||||
- Improve stats printed by ndncatchunks after transfer completes (Issue #4603)
|
||||
- Add manual page for ndnputchunks
|
||||
|
||||
dissect & dissect-wireshark:
|
||||
- Follow packet specification changes to renumber the `Parameters` element and
|
||||
rename it to `ApplicationParameters` (Issues #4658, #4780)
|
||||
|
||||
dump:
|
||||
- Fix compilation on CentOS 7 (Issue #4852)
|
||||
|
||||
pib:
|
||||
- Completely remove this obsolete and unmaintained tool (Issue #4205)
|
||||
|
||||
## Version 0.6.3
|
||||
|
||||
chunks:
|
||||
- Fix impossible RTT values (Issue #4604)
|
||||
- Add support for RDR metadata in ndnputchunks (Issue #4556)
|
||||
- Use `PendingInterestHandle` and `RegisteredPrefixHandle` (Issues #4316, #3919)
|
||||
|
||||
ping:
|
||||
- Add systemd unit file for ndnpingserver (Issue #4594)
|
||||
- Use `PendingInterestHandle` and `RegisteredPrefixHandle` (Issues #4316, #3919)
|
||||
|
||||
poke:
|
||||
- Use `PendingInterestHandle` and `RegisteredPrefixHandle` (Issues #4316, #3919)
|
||||
|
||||
build system:
|
||||
- Upgrade `waf` to version 2.0.14 and other improvements
|
||||
|
||||
## Version 0.6.2
|
||||
|
||||
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.
|
||||
|
||||
chunks:
|
||||
- Fix AIMD hanging with files smaller than the chunk size (Issue #4439)
|
||||
|
||||
dissect-wireshark:
|
||||
- Show `Name` and `FinalBlockId` as URIs (Issue #3106)
|
||||
- Improve NDNLPv2 support (Issue #4463)
|
||||
- Add support for dissecting PPP frames
|
||||
|
||||
dump:
|
||||
- Remove dependency on Boost.Regex
|
||||
- Stop using tcpdump headers files
|
||||
- Compile pcap filter with optimizations enabled
|
||||
- Capture in promiscuous mode by default, add an option to disable it
|
||||
- Add `-t` option to suppress printing per-packet timestamp
|
||||
- Properly handle exceptions thrown by `lp::Packet::wireDecode()` (Issue #3943)
|
||||
- Add UDP port 56363 to the default pcap filter
|
||||
- Stricter parsing of IP/TCP/UDP headers
|
||||
- Add IPv6 support
|
||||
- Code cleanup
|
||||
|
||||
poke:
|
||||
- Use `Face::unsetInterestFilter` instead of `shutdown` (Issue #4642)
|
||||
- Improve unit testing (Issue #3740)
|
||||
|
||||
ping:
|
||||
- Add `--quiet` option to ndnpingserver (Issue #4673)
|
||||
- Set `CanBePrefix=false` in Interests sent by ndnping (Issue #4581)
|
||||
- Code cleanup
|
||||
|
||||
## Version 0.6.1
|
||||
|
||||
chunks:
|
||||
- Show correct packet loss stats in final summary (Issue #4437)
|
||||
- Avoid printing meaningless values when no RTT measurements are available (Issue #4551)
|
||||
|
||||
dissect:
|
||||
- Recognize `CanBePrefix`, `HopLimit`, and `Parameters` TLV elements (Issue #4590)
|
||||
|
||||
dissect-wireshark:
|
||||
- Recognize `CanBePrefix`, `HopLimit`, and `Parameters` TLV elements (Issue #4517)
|
||||
|
||||
peek:
|
||||
- Drop `Selectors` support (Issue #4571)
|
||||
- Add `-P/--prefix` option to set `CanBePrefix` in the Interest packet
|
||||
|
||||
build system:
|
||||
- Upgrade `waf` to version 2.0.6 and other improvements
|
||||
|
||||
## Version 0.6
|
||||
|
||||
chunks:
|
||||
- Change the default Interest pipeline to AIMD (Issue #4402)
|
||||
- Include RTT stats in final summary (Issue #4406)
|
||||
- Respect `--retries=-1` in the AIMD pipeline (Issue #4409)
|
||||
- React to congestion marks by default as a timeout event (can be disabled using
|
||||
`--aimd-ignore-cong-marks`) (Issue #4289)
|
||||
- Print a final summary of the transfer regardless of the pipeline type, and even if
|
||||
`--verbose` was not specified (Issue #4421)
|
||||
|
||||
## Version 0.5
|
||||
|
||||
all:
|
||||
- Switch to version 2 of certificates, `KeyChain`, and `Validator` (Issue #4089)
|
||||
- Compilation fixes (Issue #4259)
|
||||
|
||||
chunks:
|
||||
- Make `ndnputchunks` display some output by default; a new `-q` flag makes the tool
|
||||
completely silent, except for errors (Issue #4286)
|
||||
- Refactor `ndnputchunks` options handling
|
||||
- Reduce initial timeout of iterative version discovery in `ndncatchunks` (Issue #4291)
|
||||
- Fix potential `ndncatchunks` crash on exit
|
||||
|
||||
peek:
|
||||
- Convert use of `Link` into `ForwardingHint` (Issue #4055)
|
||||
|
||||
## Version 0.4
|
||||
|
||||
As of this version, NDN Essential Tools require a modern compiler (gcc >= 4.8.2, clang >= 3.4)
|
||||
and a relatively new version of the Boost libraries (>= 1.54). This means that the code no
|
||||
longer compiles with the packaged version of gcc and Boost libraries on Ubuntu 12.04.
|
||||
NDN Essential Tools can still be compiled on such systems, but require a separate
|
||||
installation of a newer version of the compiler (e.g., clang-3.4) and dependencies.
|
||||
|
||||
chunks:
|
||||
- Change default version discovery to iterative
|
||||
- Improve help text of `ndnputchunks`
|
||||
- Fix `DiscoverVersionIterative` build error
|
||||
- Modularize Interest pipeline implementation
|
||||
- Add AIMD congestion control (Issue #3636)
|
||||
- Code cleanup and improvements
|
||||
|
||||
dissect-wireshark:
|
||||
- Add initial support for NDNLPv2 (Issue #3197)
|
||||
- Fix potential memory overflow
|
||||
|
||||
dump:
|
||||
- Add support for Linux cooked-mode capture (SLL) (Issue #3061)
|
||||
- Improve error messages
|
||||
|
||||
pib:
|
||||
- Disable by default (can be compiled with ndn-cxx version 0.5.0)
|
||||
- Fix compilation error with new version of ndn-cxx library
|
||||
- Avoid use of deprecated block helpers
|
||||
- Correct build target path
|
||||
|
||||
ping:
|
||||
- Recognize and trace NACK
|
||||
- Fix potential divide-by-zero bug in `StatisticsCollector` (Issue #3504)
|
||||
|
||||
peek:
|
||||
- Recognize and properly handle NACK
|
||||
- Refactor implementation
|
||||
|
||||
## Version 0.3
|
||||
|
||||
chunks: **New** (pair of) tool(s) for segmented file transfer
|
||||
|
||||
peek:
|
||||
- Allow verbose output
|
||||
- Switch from `getopt` to `boost::program_options`
|
||||
- Add `--link-file` option
|
||||
|
||||
ping:
|
||||
- Document ndnping protocol
|
||||
|
||||
dump:
|
||||
- Capture and print network NACK packets
|
||||
- Update docs to include NACK capture feature
|
||||
|
||||
build system:
|
||||
- Enable `-Wextra` by default
|
||||
- Fix missing tool name in `configure --help` output
|
||||
- Fix compatibility with Python 3
|
||||
|
||||
## Version 0.2
|
||||
|
||||
Code improvements and two new tools:
|
||||
|
||||
- PIB service to manage the public information of keys and publish certificates
|
||||
(Issue 3018)
|
||||
- A Wireshark dissector for NDN packets (Issue 3092)
|
||||
|
||||
## Version 0.1
|
||||
|
||||
Initial release of NDN Essential Tools, featuring:
|
||||
|
||||
- ndnpeek, ndnpoke: a pair of programs to request and make available for
|
||||
retrieval a single Data packet.
|
||||
- ndnping, ndnpingserver: reachability testing tools for Named Data Networking.
|
||||
- ndndump: a traffic analysis tool that captures NDN packets on the wire.
|
||||
- ndn-dissect: an NDN packet format inspector. It reads zero or more NDN
|
||||
packets from either an input file or the standard input, and displays the
|
||||
Type-Length-Value (TLV) structure of those packets on the standard output.
|
||||
+21
-22
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -38,46 +38,45 @@
|
||||
#define PROTECTED_WITH_TESTS_ELSE_PRIVATE private
|
||||
#endif
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/core/noncopyable.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
|
||||
#include <ndn-cxx/data.hpp>
|
||||
#include <ndn-cxx/face.hpp>
|
||||
#include <ndn-cxx/interest.hpp>
|
||||
#include <ndn-cxx/name.hpp>
|
||||
#include <ndn-cxx/security/key-chain.hpp>
|
||||
#include <ndn-cxx/security/signing-helpers.hpp>
|
||||
#include <ndn-cxx/security/signing-info.hpp>
|
||||
#include <ndn-cxx/util/backports.hpp>
|
||||
#include <ndn-cxx/util/exception.hpp>
|
||||
#include <ndn-cxx/util/scheduler.hpp>
|
||||
#include <ndn-cxx/util/scheduler-scoped-event-id.hpp>
|
||||
#include <ndn-cxx/util/signal.hpp>
|
||||
#include <ndn-cxx/util/time.hpp>
|
||||
|
||||
namespace ndn {
|
||||
|
||||
using std::shared_ptr;
|
||||
using std::unique_ptr;
|
||||
using std::make_shared;
|
||||
using std::make_unique;
|
||||
|
||||
using std::size_t;
|
||||
|
||||
using boost::noncopyable;
|
||||
|
||||
namespace signal = util::signal;
|
||||
namespace scheduler = util::scheduler;
|
||||
|
||||
|
||||
} // namespace ndn
|
||||
|
||||
#define FORWARD_TO_MEM_FN(func) \
|
||||
[this] (auto&&... args) { this->func(std::forward<decltype(args)>(args)...); }
|
||||
|
||||
#endif // NDN_TOOLS_CORE_COMMON_HPP
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, 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-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "core/program-options-ext.hpp"
|
||||
|
||||
namespace ndn {
|
||||
|
||||
void
|
||||
validate(boost::any& v, const std::vector<std::string>& values, Name*, int)
|
||||
{
|
||||
using namespace boost::program_options;
|
||||
|
||||
validators::check_first_occurrence(v);
|
||||
const std::string& s = validators::get_single_string(values);
|
||||
|
||||
try {
|
||||
v = Name(s);
|
||||
} catch (const Name::Error&) {
|
||||
throw invalid_option_value(s);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ndn
|
||||
@@ -1,6 +1,12 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California.
|
||||
/*
|
||||
* Copyright (c) 2014-2022, 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-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
@@ -15,52 +21,22 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Yingdi Yu <yingdi@cs.ucla.edu>
|
||||
*/
|
||||
|
||||
#ifndef NDN_TOOLS_PIB_LIST_QUERY_PROCESSOR_HPP
|
||||
#define NDN_TOOLS_PIB_LIST_QUERY_PROCESSOR_HPP
|
||||
#ifndef NDN_TOOLS_CORE_PROGRAM_OPTIONS_EXT_HPP
|
||||
#define NDN_TOOLS_CORE_PROGRAM_OPTIONS_EXT_HPP
|
||||
|
||||
#include "pib-db.hpp"
|
||||
#include "encoding/list-param.hpp"
|
||||
#include <ndn-cxx/interest.hpp>
|
||||
#include <utility>
|
||||
#include <ndn-cxx/name.hpp>
|
||||
#include <boost/program_options/value_semantic.hpp>
|
||||
|
||||
namespace ndn {
|
||||
namespace pib {
|
||||
|
||||
class ListQueryProcessor : noncopyable
|
||||
{
|
||||
public:
|
||||
class Error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& what)
|
||||
: std::runtime_error(what)
|
||||
{
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @brief Provide a Boost.Program_options custom validator for ndn::Name type.
|
||||
*/
|
||||
void
|
||||
validate(boost::any& v, const std::vector<std::string>& values, Name*, int);
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*
|
||||
* @param db The pib database.
|
||||
*/
|
||||
explicit
|
||||
ListQueryProcessor(PibDb& db);
|
||||
|
||||
std::pair<bool, Block>
|
||||
operator()(const Interest& interest);
|
||||
|
||||
private:
|
||||
static const size_t LIST_QUERY_LENGTH;
|
||||
|
||||
const PibDb& m_db;
|
||||
};
|
||||
|
||||
} // namespace pib
|
||||
} // namespace ndn
|
||||
|
||||
#endif // NDN_TOOLS_PIB_LIST_QUERY_PROCESSOR_HPP
|
||||
#endif // NDN_TOOLS_CORE_PROGRAM_OPTIONS_EXT_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Arizona Board of Regents.
|
||||
/*
|
||||
* Copyright (c) 2014-2022, Arizona Board of Regents.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
@@ -17,12 +17,12 @@
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "version.hpp"
|
||||
#include "core/version.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace tools {
|
||||
|
||||
const char VERSION[] = "0.2";
|
||||
const char VERSION[] = "@VERSION_BUILD@";
|
||||
|
||||
} // namespace tools
|
||||
} // namespace ndn
|
||||
+5
-4
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Arizona Board of Regents.
|
||||
/*
|
||||
* Copyright (c) 2014-2022, Arizona Board of Regents.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
@@ -20,12 +20,13 @@
|
||||
#ifndef NDN_TOOLS_CORE_VERSION_HPP
|
||||
#define NDN_TOOLS_CORE_VERSION_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "core/common.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace tools {
|
||||
|
||||
/** \brief version of ndn-tools
|
||||
/**
|
||||
* \brief The version of ndn-tools.
|
||||
*/
|
||||
extern const char VERSION[];
|
||||
|
||||
|
||||
+70
-10
@@ -1,16 +1,76 @@
|
||||
# General information about the project.
|
||||
project = u'NDN Essential Tools'
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
# -- 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.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = u'NDN Essential Tools'
|
||||
copyright = u'Copyright © 2014-2021 Named Data Networking Project.'
|
||||
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 ---------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
needs_sphinx = '1.3'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
]
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# 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 = ['Thumbs.db', '.DS_Store']
|
||||
|
||||
|
||||
# -- Options for manual page output ------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('ndnpeek', 'ndnpeek', 'simple consumer to send one Interest and expect one Data', None, 1),
|
||||
('ndnpoke', 'ndnpoke', 'simple producer to publish one Data', None, 1),
|
||||
('ndnping', 'ndnping', 'reachability testing client', None, 1),
|
||||
('ndnpingserver', 'ndnpingserver', 'reachability testing server', None, 1),
|
||||
('ndndump', 'ndndump', 'traffic analysis tool', None, 8),
|
||||
('ndn-dissect', 'ndn-dissect', 'NDN packet format inspector', None, 1),
|
||||
('ndn-pib', 'ndn-pib', 'NDN PIB service', None, 1),
|
||||
('ndnpeek', 'ndnpeek', 'simple consumer to send one Interest and receive one Data', [], 1),
|
||||
('ndnpoke', 'ndnpoke', 'simple producer to publish one Data', [], 1),
|
||||
('ndnping', 'ndnping', 'reachability testing client', [], 1),
|
||||
('ndnpingserver', 'ndnpingserver', 'reachability testing server', [], 1),
|
||||
('ndnputchunks', 'ndnputchunks', 'producer program with content segmentation', [], 1),
|
||||
('ndndump', 'ndndump', 'traffic analysis tool', [], 8),
|
||||
('ndn-dissect', 'ndn-dissect', 'NDN packet format inspector', [], 1),
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = True
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
.. toctree::
|
||||
ndn-dissect
|
||||
ndndump
|
||||
ndnpeek
|
||||
ndnping
|
||||
ndnpingserver
|
||||
ndnpoke
|
||||
ndnputchunks
|
||||
+24
-19
@@ -1,38 +1,43 @@
|
||||
ndn-dissect
|
||||
===========
|
||||
|
||||
Usage
|
||||
-----
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
::
|
||||
|
||||
ndn-dissect [-hV] [input-file]
|
||||
**ndn-dissect** [**-h**] [**-c**] [**-V**] [*file*]
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
``ndn-dissect`` is an NDN packet format inspector.
|
||||
It reads zero or more NDN packets from either an input file or the standard input,
|
||||
and displays the Type-Length-Value (TLV) structure of those packets on the standard output.
|
||||
:program:`ndn-dissect` is an NDN packet format inspector.
|
||||
It reads zero or more NDN packets from either an input file or the standard
|
||||
input, and displays the Type-Length-Value (TLV) structure of those packets
|
||||
on the standard output.
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
``-h``
|
||||
Print help and exit.
|
||||
.. option:: -h, --help
|
||||
|
||||
``-V``
|
||||
Print version and exit.
|
||||
Print help and exit.
|
||||
|
||||
``input-file``
|
||||
The file to read packets from.
|
||||
If no :option:`input-file` is given, the standard input is used.
|
||||
.. option:: -c, --content
|
||||
|
||||
Dissect the value of Content elements as well. By default, the value of a
|
||||
Content element is treated as an opaque blob and is not dissected further.
|
||||
|
||||
.. option:: -V, --version
|
||||
|
||||
Print program version and exit.
|
||||
|
||||
.. option:: file
|
||||
|
||||
The file to read packets from.
|
||||
If no *file* is given, or if *file* is "-", the standard input is used.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Inspect the response to Interest ``ndn:/app1/video``
|
||||
Inspect the response to Interest ``/app1/video``::
|
||||
|
||||
::
|
||||
|
||||
ndnpeek ndn:/app1/video | ndn-dissect
|
||||
ndnpeek /app1/video | ndn-dissect
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
ndn-pib
|
||||
========
|
||||
|
||||
``ndn-pib`` is a public key and certificate management and publishing service.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
::
|
||||
|
||||
ndn-pib [-h] -o owner -d database_dir -t tpm_locator
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This command will start a PIB service process which serves signing key lookup/management for local
|
||||
applications and also public the public key certificate of signing keys. The lookup/management
|
||||
interface listens on a prefix "/localhost/pib/[OwnerName]" and accept five types of command (get,
|
||||
default, list, update, delete). More details can be found at `Public key Info Base (PIB) Service
|
||||
<http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base>`__
|
||||
|
||||
Since PIB service is queried through Interest/Data exchange, NFD is required to run before this
|
||||
command is executed.
|
||||
|
||||
This command requires three arguments: ``owner`` specify the owner of the pib service, which is also
|
||||
the third name component in the local lookup/management prefix; ``database_dir`` is the path to the
|
||||
database where all the public key, certificate, identity are stored and managed; ``tpm_locator`` is
|
||||
locator of a TPM which stores the corresponding private key of the public keys in PIB.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
::
|
||||
|
||||
$ ndn-pib -o alice -d /var/pib -t tpm-file:/var/ndn/tpm
|
||||
+47
-25
@@ -6,54 +6,76 @@ Usage
|
||||
|
||||
::
|
||||
|
||||
ndndump [-hV] [-i interface] [-r file] [-f filter] [expression]
|
||||
ndndump [-hvV] [-i INTERFACE] [-r FILE] [-f FILTER] [PCAP-FILTER]
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
:program:`ndndump` is a traffic analysis tool that captures Interest, Data, and Nack packets on the
|
||||
wire and displays brief information about captured packets.
|
||||
:program:`ndndump` is a traffic analysis tool that captures NDN packets on the wire and
|
||||
displays brief information about them.
|
||||
|
||||
Currently, :program:`ndndump` is capable of extracting Interest, Data, and Nack packets from:
|
||||
|
||||
* Ethernet
|
||||
* Ethernet frame
|
||||
* PPP link (e.g., pcap trace from ndnSIM)
|
||||
* IPv4 UDP unicast tunnel
|
||||
* IPv4 UDP multicast group
|
||||
* IPv4 TCP tunnel, when Interest/Data/Nack is aligned to the front of a TCP segment
|
||||
* IPv4 TCP tunnel, when Interest/Data/Nack is aligned to the beginning of a TCP segment
|
||||
|
||||
For more complex scenarios, including the case of NDN packets that span multiple IP fragments
|
||||
or multiple TCP segments, it is recommended to use the **NDN Wireshark dissector**, either via
|
||||
:manpage:`wireshark(1)` or :manpage:`tshark(1)`.
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
``-h``
|
||||
Print help and exit.
|
||||
.. option:: -h, --help
|
||||
|
||||
``-V``
|
||||
Print version and exit.
|
||||
Print help and exit.
|
||||
|
||||
``-i``
|
||||
Listen on :option:`interface`.
|
||||
If unspecified, ndndump searches the system interface list for the lowest numbered,
|
||||
configured up interface (excluding loopback).
|
||||
.. option:: -i INTERFACE, --interface=INTERFACE
|
||||
|
||||
``-r``
|
||||
Read packets from :option:`file` (which was created with :manpage:`tcpdump(8)` using its -w option).
|
||||
Listen on *INTERFACE*.
|
||||
If unspecified, ndndump searches the system interface list for the lowest numbered,
|
||||
configured up interface (excluding loopback).
|
||||
On Linux, a value of "any" can be used to capture packets from all interfaces.
|
||||
Note that captures on the "any" pseudo-interface will not be done in promiscuous mode.
|
||||
|
||||
``-v``
|
||||
Produce verbose output.
|
||||
.. option:: -r FILE, --read=FILE
|
||||
|
||||
``-f``
|
||||
Print a packet only if its Name matches the regular expression :option:`filter`.
|
||||
Read packets from *FILE*, which can be created by :manpage:`tcpdump(8)` with its
|
||||
``-w`` option, or by similar programs.
|
||||
|
||||
``expression``
|
||||
Selects which packets will be analyzed, in :manpage:`pcap-filter(7)` format.
|
||||
If no :option:`expression` is given, a default expression is implied which can be seen with ``-h`` option.
|
||||
.. option:: -f FILTER, --filter=FILTER
|
||||
|
||||
Print a packet only if its name matches the regular expression *FILTER*.
|
||||
|
||||
.. option:: -p, --no-promiscuous-mode
|
||||
|
||||
Do not put the interface into promiscuous mode.
|
||||
|
||||
.. option:: -t, --no-timestamp
|
||||
|
||||
Do not print a timestamp for each packet.
|
||||
|
||||
.. option:: -v, --verbose
|
||||
|
||||
Produce verbose output.
|
||||
|
||||
.. option:: -V, --version
|
||||
|
||||
Print ndndump and libpcap version strings and exit.
|
||||
|
||||
.. option:: PCAP-FILTER
|
||||
|
||||
:option:`PCAP-FILTER` is an expression in :manpage:`pcap-filter(7)` format that
|
||||
selects which packets will be analyzed.
|
||||
If no :option:`PCAP-FILTER` is given, a default filter is used. The default filter
|
||||
can be seen with the :option:`--help` option.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Capture on eth1 and print packets containing "ping":
|
||||
|
||||
::
|
||||
Capture on eth1 and print packets containing "ping"::
|
||||
|
||||
ndndump -i eth1 -f '.*ping.*'
|
||||
|
||||
+38
-32
@@ -1,22 +1,20 @@
|
||||
ndnpeek
|
||||
=======
|
||||
|
||||
Usage
|
||||
-----
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
::
|
||||
|
||||
ndnpeek [-h] [-f] [-r] [-m min] [-M max] [-l lifetime] [-p] [-w timeout] [-v] [-V] name
|
||||
**ndnpeek** [-h] [-P] [-f] [-l *lifetime*] [-H *hops*] [-A *parameters*]
|
||||
[-p] [-w *timeout*] [-v] [-V] *name*
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
``ndnpeek`` is a simple consumer program that sends one Interest and expects one Data
|
||||
packet in response. The full Data packet (in TLV format) is written to stdout. The
|
||||
program terminates with return code 0 if Data arrives, and with return code 1 when timeout
|
||||
occurs.
|
||||
:program:`ndnpeek` is a simple consumer program that sends one Interest and
|
||||
expects one Data packet in response. By default, the full Data packet (in TLV
|
||||
format) is written to the standard output.
|
||||
|
||||
``name`` is interpreted as the Interest name.
|
||||
*name* is interpreted as the Interest name.
|
||||
|
||||
Options
|
||||
-------
|
||||
@@ -24,38 +22,42 @@ Options
|
||||
``-h, --help``
|
||||
Print help and exit.
|
||||
|
||||
``-P, --prefix``
|
||||
If specified, include ``CanBePrefix`` element in the Interest packet.
|
||||
|
||||
``-f, --fresh``
|
||||
If specified, set ``MustBeFresh`` selector in the Interest packet.
|
||||
If specified, include ``MustBeFresh`` element in the Interest packet.
|
||||
|
||||
``-r, --rightmost``
|
||||
Set ``ChildSelector=1`` (the rightmost child) selector.
|
||||
``-F, --fwhint <name>``
|
||||
Add a delegation name to the ``ForwardingHint`` of the Interest packet.
|
||||
This option may be repeated to specify multiple delegation names.
|
||||
|
||||
``-m, --minsuffix min``
|
||||
Set ``min`` as the ``MinSuffixComponents`` selector.
|
||||
|
||||
``-M, --maxsuffix max``
|
||||
Set ``max`` as the ``MaxSuffixComponents`` selector.
|
||||
|
||||
``-l, --lifetime lifetime``
|
||||
``-l, --lifetime <lifetime>``
|
||||
Set ``lifetime`` (in milliseconds) as the ``InterestLifetime``.
|
||||
|
||||
``-H, --hop-limit <hops>``
|
||||
Set the Interest's ``HopLimit`` to the specified number of hops.
|
||||
|
||||
``-A, --app-params <parameters>``
|
||||
Set the Interest's ``ApplicationParameters`` from a base64-encoded string.
|
||||
|
||||
``--app-params-file <file>``
|
||||
Set the Interest's ``ApplicationParameters`` from the specified file.
|
||||
|
||||
``-p, --payload``
|
||||
If specified, print the received payload only, not the full packet.
|
||||
|
||||
``-w, --timeout timeout``
|
||||
Timeout after ``timeout`` milliseconds.
|
||||
``-w, --timeout <timeout>``
|
||||
Quit the program after ``timeout`` milliseconds, even if no reply has been received.
|
||||
|
||||
``-v, --verbose``
|
||||
If specified, verbose output.
|
||||
Turn on verbose output.
|
||||
|
||||
``-V, --version``
|
||||
Print version and exit.
|
||||
|
||||
``--link-file [file]``
|
||||
Read Link object from ``file`` and add it to the expressed Interest.
|
||||
|
||||
Exit Codes
|
||||
----------
|
||||
Exit Status
|
||||
-----------
|
||||
|
||||
0: Success
|
||||
|
||||
@@ -63,15 +65,19 @@ Exit Codes
|
||||
|
||||
2: Malformed command line
|
||||
|
||||
3: Network operation timed out
|
||||
3: Operation timed out
|
||||
|
||||
4: Nack received
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Send Interest for ``ndn:/app1/video`` and print the received payload only
|
||||
Send an Interest for ``/app1/video`` and print the received payload only::
|
||||
|
||||
::
|
||||
ndnpeek -p /app1/video
|
||||
|
||||
ndnpeek -p ndn:/app1/video
|
||||
Send an Interest for ``/app2/foo``, requesting fresh content, with an InterestLifetime
|
||||
of 8 seconds, and with the ApplicationParameters containing the ASCII string "hello";
|
||||
print the performed operations verbosely but discard the received Data packet::
|
||||
|
||||
ndnpeek -vf -l 8000 -A "aGVsbG8=" /app2/foo >/dev/null
|
||||
|
||||
+29
-30
@@ -1,25 +1,23 @@
|
||||
ndnping
|
||||
=======
|
||||
ndnpingserver
|
||||
=============
|
||||
|
||||
Usage
|
||||
-----
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
::
|
||||
|
||||
ndnpingserver [-h] [-V] [-x freshness] [-p satisfy] [-t] [-s size] prefix
|
||||
**ndnpingserver** [-h] [-f *freshness*] [-p *count*] [-s *size*] [-t] [-q] [-V] *prefix*
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
``ndnpingserver`` listens for the specified Interest prefix and sends Data packets when an Interest
|
||||
under that prefix is received. Once ``ndnpingserver`` either reaches the specified total number of
|
||||
Interests to be satisfied or receives an interrupt signal, it prints the number of Data packets
|
||||
sent.
|
||||
:program:`ndnpingserver` listens for the specified Interest prefix and sends Data packets when
|
||||
an Interest under that prefix is received. Once :program:`ndnpingserver` either reaches the
|
||||
specified total number of Interests to be satisfied or receives an interrupt signal, it prints
|
||||
the number of Data packets sent.
|
||||
|
||||
``prefix`` is interpreted as the Interest prefix to listen for. The FreshnessPeriod of Data packets
|
||||
is set with the -x option (default 1000ms). The content is by default empty, but if a size is
|
||||
specified with the '-s' option, it contains the specified number of the letter "a". Finally, the
|
||||
Data is signed with an SHA256 digest.
|
||||
*prefix* is interpreted as the Interest prefix to listen for. The FreshnessPeriod of Data packets
|
||||
is set with the **-f** option (default 1 second). The content is by default empty, but if a size
|
||||
is specified with the **-s** option, it contains the specified number of the letter "a". Finally,
|
||||
the Data is signed with a SHA-256 digest.
|
||||
|
||||
Options
|
||||
-------
|
||||
@@ -27,27 +25,28 @@ Options
|
||||
``-h``
|
||||
Print help and exit.
|
||||
|
||||
``-V``
|
||||
Print version and exit.
|
||||
|
||||
``-x``
|
||||
Set freshness period in milliseconds (minimum 1000ms).
|
||||
``-f``
|
||||
Set freshness period in milliseconds.
|
||||
|
||||
``-p``
|
||||
Set maximum number of pings to satisfy.
|
||||
|
||||
``-t``
|
||||
Prints a timestamp with received Data and timeouts.
|
||||
Maximum number of pings to satisfy. A value of 0 means no limit.
|
||||
|
||||
``-s``
|
||||
Specify the size of the response payload.
|
||||
Size of the response payload.
|
||||
|
||||
``-t``
|
||||
Print a timestamp before each log message.
|
||||
|
||||
``-q``
|
||||
Do not print a log message each time a ping is received.
|
||||
|
||||
``-V``
|
||||
Print version and exit.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Listen on ``ndn:/edu/arizona`` and response to at most 4 pings, printing timestamp on each received
|
||||
ping
|
||||
Listen on ``/edu/arizona`` and respond to at most 4 pings, printing the timestamp
|
||||
on each received ping::
|
||||
|
||||
::
|
||||
|
||||
ndnpingserver -p 4 -t ndn:/edu/arizona
|
||||
ndnpingserver -p 4 -t /edu/arizona
|
||||
|
||||
+48
-30
@@ -1,54 +1,72 @@
|
||||
ndnpoke
|
||||
=======
|
||||
|
||||
Usage
|
||||
-----
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
::
|
||||
|
||||
ndnpoke [-h] [-f] [-D] [-i identity] [-F] [-x freshness] [-w timeout] name
|
||||
**ndnpoke** [-h] [-f *freshness*] [-F] [-S *info*] [-u\|\ -w *timeout*] [-v] [-V] *name*
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
``ndnpoke`` is a simple producer program that reads payload from stdin and publishes it
|
||||
as a single NDN Data packet. The Data packet is published either as a response to the
|
||||
incoming Interest for the given ``name``, or forcefully pushed to the local NDN
|
||||
forwarder's cache if ``-f`` flag is specified.
|
||||
|
||||
The program terminates with return code 0 if Data is sent and with return code 1 when
|
||||
timeout occurs.
|
||||
:program:`ndnpoke` is a simple producer program that reads a payload from the standard
|
||||
input and publishes it as a single Data packet. The Data packet is either sent as a
|
||||
response to an incoming Interest matching *name*, or immediately pushed to the local
|
||||
NDN forwarder as "unsolicited Data" if the **-u** flag is specified.
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
``-h``
|
||||
Print usage and exit.
|
||||
``-h, --help``
|
||||
Print help and exit.
|
||||
|
||||
``-f``
|
||||
If specified, send Data without waiting for Interest.
|
||||
``-f, --freshness <freshness>``
|
||||
Set ``freshness`` (in milliseconds) as the ``FreshnessPeriod``.
|
||||
|
||||
``-D``
|
||||
If specified, use ``DigestSha256`` signature instead of default ``SignatureSha256WithRsa``.
|
||||
``-F, --final``
|
||||
Set the ``FinalBlockId`` to the last component of *name*.
|
||||
|
||||
``-i``
|
||||
Use ``identity`` to sign the created Data packet.
|
||||
``-S, --signing-info <info>``
|
||||
Specify the parameters used to sign the Data packet. If omitted, the default key of
|
||||
the default identity is used. The general syntax is ``<scheme>:<name>``. The most
|
||||
common supported combinations are as follows:
|
||||
|
||||
``-F``
|
||||
Set ``FinalBlockId`` to the last component of specified name.
|
||||
* Sign with the default certificate of the default key of an identity: ``id:/<my-identity>``.
|
||||
* Sign with the default certificate of a specific key: ``key:/<my-identity>/ksk-1``.
|
||||
* Sign with a specific certificate: ``cert:/<my-identity>/KEY/ksk-1/ID-CERT/v=1``.
|
||||
* Sign with a SHA-256 digest: ``id:/localhost/identity/digest-sha256``. Note that this
|
||||
is only a hash function, not a real signature, but it can significantly speed up
|
||||
packet signing operations.
|
||||
|
||||
``-x``
|
||||
Set ``FreshnessPeriod`` in milliseconds.
|
||||
``-u, --unsolicited``
|
||||
Send the Data packet without waiting for an incoming Interest.
|
||||
|
||||
``-w``
|
||||
Wait at most ``timeout`` milliseconds for the incoming Interest. If no Interest arrives
|
||||
within the ``timeout``, the Data packet will not be published.
|
||||
``-w, --timeout <timeout>``
|
||||
Quit the program after ``timeout`` milliseconds, even if no Interest has been received.
|
||||
|
||||
``-v, --verbose``
|
||||
Turn on verbose output.
|
||||
|
||||
``-V, --version``
|
||||
Print version and exit.
|
||||
|
||||
Exit Status
|
||||
-----------
|
||||
|
||||
0: Success
|
||||
|
||||
1: An unspecified error occurred
|
||||
|
||||
2: Malformed command line
|
||||
|
||||
3: No Interests received before the timeout
|
||||
|
||||
5: Prefix registration failed
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Create Data packet with content ``hello`` with the name ``ndn:/app/video`` and wait at
|
||||
most 3 seconds for the incoming Interest for it::
|
||||
Create a Data packet with content ``hello`` and name ``/app/video`` and wait at
|
||||
most 3 seconds for a matching Interest to arrive::
|
||||
|
||||
echo "Hello" | build/bin/ndnpoke -w 3000 ndn:/app/video
|
||||
echo "hello" | ndnpoke -w 3000 /app/video
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
ndnputchunks
|
||||
============
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
**ndnputchunks** [*option*]... *name*
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
:program:`ndnputchunks` is a producer program that reads a file from the standard input
|
||||
and makes it available as NDN Data segments.
|
||||
|
||||
Version and segment number components are appended to the specified *name* as needed,
|
||||
according to the `NDN naming conventions`_.
|
||||
|
||||
.. _NDN naming conventions: https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
.. option:: -h, --help
|
||||
|
||||
Print help and exit.
|
||||
|
||||
.. option:: -f, --freshness MILLISECS
|
||||
|
||||
FreshnessPeriod of the published Data packets, in milliseconds.
|
||||
The default is 10000 (10 seconds).
|
||||
|
||||
.. option:: -s, --size BYTES
|
||||
|
||||
Maximum chunk size, in bytes. The default is 8000 bytes.
|
||||
|
||||
.. option:: -N, --naming-convention CONVENTION
|
||||
|
||||
Select the convention used to encode NDN name components. The available choices are:
|
||||
|
||||
* ``marker`` (shorthand: ``m`` or ``1``) for the old marker-based encoding;
|
||||
* ``typed`` (shorthand: ``t`` or ``2``) for the new encoding based on typed name components.
|
||||
|
||||
If this option is not specified, the ndn-cxx library's default is used.
|
||||
|
||||
.. option:: -S, --signing-info STRING
|
||||
|
||||
Specify the parameters used to sign the Data packets. If omitted, the default key
|
||||
of the default identity is used. The general syntax is ``<scheme>:<name>``. The
|
||||
most common supported combinations are as follows:
|
||||
|
||||
* Sign with the default certificate of the default key of an identity: ``id:/<my-identity>``.
|
||||
* Sign with the default certificate of a specific key: ``key:/<my-identity>/ksk-1``.
|
||||
* Sign with a specific certificate: ``cert:/<my-identity>/KEY/ksk-1/ID-CERT/v=1``.
|
||||
* Sign with a SHA-256 digest: ``id:/localhost/identity/digest-sha256``. Note that this
|
||||
is only a hash function, not a real signature, but it can significantly speed up
|
||||
packet signing operations.
|
||||
|
||||
.. option:: -p, --print-data-version
|
||||
|
||||
Print version of the published Data to the standard output.
|
||||
|
||||
.. option:: -q, --quiet
|
||||
|
||||
Turn off all non-error output.
|
||||
|
||||
.. option:: -v, --verbose
|
||||
|
||||
Produce verbose output.
|
||||
|
||||
.. option:: -V, --version
|
||||
|
||||
Print program version and exit.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
The following command will publish the text of the GPL-3 license under the ``/localhost/demo/gpl3``
|
||||
prefix::
|
||||
|
||||
ndnputchunks /localhost/demo/gpl3 < /usr/share/common-licenses/GPL-3
|
||||
|
||||
To see the published version, you can run the program with the **-p** option::
|
||||
|
||||
ndnputchunks -p /localhost/demo/gpl3 < /usr/share/common-licenses/GPL-3
|
||||
|
||||
This command will print the published version to the standard output.
|
||||
|
||||
To publish Data with a specific version, you must append a version component to the end of the
|
||||
prefix. The version component must follow the aforementioned NDN naming conventions.
|
||||
For example, the following command will publish version 1615519151142 of ``/localhost/demo/gpl3``
|
||||
using the "typed" naming convention::
|
||||
|
||||
ndnputchunks -Nt /localhost/demo/gpl3/v=1615519151142 < /usr/share/common-licenses/GPL-3
|
||||
|
||||
See Also
|
||||
--------
|
||||
|
||||
.. target-notes::
|
||||
@@ -1,10 +0,0 @@
|
||||
def build(bld):
|
||||
if not bld.env['SPHINX_BUILD']:
|
||||
return
|
||||
bld(features='sphinx',
|
||||
builder='man',
|
||||
outdir='.',
|
||||
config='./conf.py',
|
||||
source=bld.path.ant_glob('*.rst'),
|
||||
install_path='${MANDIR}/',
|
||||
VERSION=bld.env['VERSION'])
|
||||
@@ -0,0 +1,65 @@
|
||||
# Copyright (c) 2015-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-tools (Named Data Networking Essential Tools).
|
||||
# See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
#
|
||||
# ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
# of the GNU General Public License as published by the Free Software Foundation,
|
||||
# either version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
# PURPOSE. See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
[Unit]
|
||||
Description=NDN Ping Server
|
||||
Documentation=man:ndnpingserver(1)
|
||||
BindsTo=nfd.service
|
||||
After=nfd.service
|
||||
|
||||
[Service]
|
||||
Environment=HOME=%S/ndn/ndnping
|
||||
EnvironmentFile=-@SYSCONFDIR@/default/ndnping
|
||||
ExecStart=@BINDIR@/ndnpingserver ${PREFIX} $FLAGS
|
||||
Restart=on-failure
|
||||
RestartPreventExitStatus=2
|
||||
User=ndn
|
||||
|
||||
CapabilityBoundingSet=
|
||||
LockPersonality=yes
|
||||
MemoryDenyWriteExecute=yes
|
||||
NoNewPrivileges=yes
|
||||
PrivateDevices=yes
|
||||
PrivateNetwork=yes
|
||||
PrivateTmp=yes
|
||||
PrivateUsers=yes
|
||||
ProtectControlGroups=yes
|
||||
ProtectHome=yes
|
||||
ProtectKernelModules=yes
|
||||
ProtectKernelTunables=yes
|
||||
# systemd older than v232 doesn't support a value of "strict" for ProtectSystem,
|
||||
# so it will ignore that line and use ProtectSystem=full; with newer systemd,
|
||||
# the latter assignment is recognized and takes precedence, resulting in an
|
||||
# effective setting of ProtectSystem=strict
|
||||
ProtectSystem=full
|
||||
ProtectSystem=strict
|
||||
RestrictAddressFamilies=AF_UNIX
|
||||
RestrictNamespaces=yes
|
||||
RestrictRealtime=yes
|
||||
StateDirectory=ndn/ndnping
|
||||
SystemCallArchitectures=native
|
||||
SystemCallErrorNumber=EPERM
|
||||
SystemCallFilter=~@aio @chown @clock @cpu-emulation @debug @keyring @module @mount @obsolete @privileged @raw-io @reboot @resources @setuid @swap
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=nfd.service
|
||||
+5
-6
@@ -1,13 +1,12 @@
|
||||
ndn-tool unit tests
|
||||
===================
|
||||
# ndn-tools unit tests
|
||||
|
||||
## Assumptions
|
||||
|
||||
Unit tests for a tool `foo` should be placed in the folder `foo` and build script for the tool
|
||||
should define `foo-objects` that includes all object files for the tool, except object files
|
||||
defining main function.
|
||||
Unit tests for a tool `foo` should be placed in the folder `foo` and the build script
|
||||
for the tool should define `foo-objects` that includes all object files for that tool,
|
||||
except the object that contains the `main()` function.
|
||||
|
||||
For example,
|
||||
For example:
|
||||
|
||||
bld(features='cxx',
|
||||
name='tool-subtool-objects',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -30,8 +30,7 @@
|
||||
#pragma GCC system_header
|
||||
#pragma clang system_header
|
||||
|
||||
#include <boost/concept_check.hpp>
|
||||
#define BOOST_TEST_DYN_LINK
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/test/output_test_stream.hpp>
|
||||
|
||||
#endif // NDN_TOOLS_TESTS_BOOST_TEST_HPP
|
||||
|
||||
+71
-33
@@ -1,8 +1,8 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2016, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
/*
|
||||
* Copyright (c) 2016-2022, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
@@ -24,12 +24,20 @@
|
||||
*/
|
||||
|
||||
#include "tools/chunks/catchunks/consumer.hpp"
|
||||
#include "tools/chunks/catchunks/discover-version.hpp"
|
||||
#include "tools/chunks/catchunks/pipeline-interests.hpp"
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
#include <ndn-cxx/security/validator-null.hpp>
|
||||
#include "tests/io-fixture.hpp"
|
||||
|
||||
#include <ndn-cxx/security/validator-null.hpp>
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
#if BOOST_VERSION >= 105900
|
||||
#include <boost/test/tools/output_test_stream.hpp>
|
||||
#else
|
||||
#include <boost/test/output_test_stream.hpp>
|
||||
#endif
|
||||
|
||||
namespace ndn {
|
||||
namespace chunks {
|
||||
@@ -41,21 +49,16 @@ using boost::test_tools::output_test_stream;
|
||||
BOOST_AUTO_TEST_SUITE(Chunks)
|
||||
BOOST_AUTO_TEST_SUITE(TestConsumer)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(OutputDataSequential)
|
||||
BOOST_AUTO_TEST_CASE(InOrderData)
|
||||
{
|
||||
// Test sequential segments in the right order
|
||||
// Segment order: 0 1 2
|
||||
// Segment order: 0 1 2 3
|
||||
|
||||
std::string name("/ndn/chunks/test");
|
||||
|
||||
std::vector<std::string> testStrings {
|
||||
const std::string name("/ndn/chunks/test");
|
||||
const std::vector<std::string> testStrings {
|
||||
"",
|
||||
|
||||
"a1b2c3%^&(#$&%^$$/><",
|
||||
|
||||
"123456789123456789123456789123456789123456789123456789123456789"
|
||||
"123456789123456789123456789123456789123456789123456789123456789",
|
||||
|
||||
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. "
|
||||
"Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur "
|
||||
"ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla "
|
||||
@@ -63,18 +66,17 @@ BOOST_AUTO_TEST_CASE(OutputDataSequential)
|
||||
};
|
||||
|
||||
util::DummyClientFace face;
|
||||
ValidatorNull validator;
|
||||
output_test_stream output("");
|
||||
Consumer cons(face, validator, false, output);
|
||||
Consumer cons(security::getAcceptAllValidator(), output);
|
||||
|
||||
auto interest = makeInterest(name);
|
||||
auto interest = makeInterest(name, true);
|
||||
|
||||
for (size_t i = 0; i < testStrings.size(); ++i) {
|
||||
output.flush();
|
||||
|
||||
auto data = makeData(Name(name).appendVersion(1).appendSegment(i));
|
||||
data->setContent(reinterpret_cast<const uint8_t*>(testStrings[i].data()),
|
||||
testStrings[i].size());
|
||||
data->setContent(make_span(reinterpret_cast<const uint8_t*>(testStrings[i].data()),
|
||||
testStrings[i].size()));
|
||||
|
||||
cons.m_bufferedData[i] = data;
|
||||
cons.writeInOrderData();
|
||||
@@ -83,37 +85,32 @@ BOOST_AUTO_TEST_CASE(OutputDataSequential)
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(OutputDataUnordered)
|
||||
BOOST_AUTO_TEST_CASE(OutOfOrderData)
|
||||
{
|
||||
// Test unordered segments
|
||||
// Segment order: 1 0 2
|
||||
|
||||
std::string name("/ndn/chunks/test");
|
||||
|
||||
std::vector<std::string> testStrings {
|
||||
const std::string name("/ndn/chunks/test");
|
||||
const std::vector<std::string> testStrings {
|
||||
"a1b2c3%^&(#$&%^$$/><",
|
||||
|
||||
"123456789123456789123456789123456789123456789123456789123456789"
|
||||
"123456789123456789123456789123456789123456789123456789123456789",
|
||||
|
||||
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. "
|
||||
"Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur "
|
||||
"ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla "
|
||||
"consequat massa Donec pede justo,"
|
||||
};;
|
||||
};
|
||||
|
||||
util::DummyClientFace face;
|
||||
ValidatorNull validator;
|
||||
output_test_stream output("");
|
||||
Consumer cons(face, validator, false, output);
|
||||
Consumer cons(security::getAcceptAllValidator(), output);
|
||||
|
||||
auto interest = makeInterest(name);
|
||||
auto interest = makeInterest(name, true);
|
||||
std::vector<shared_ptr<Data>> dataStore;
|
||||
|
||||
for (size_t i = 0; i < testStrings.size(); ++i) {
|
||||
auto data = makeData(Name(name).appendVersion(1).appendSegment(i));
|
||||
data->setContent(reinterpret_cast<const uint8_t*>(testStrings[i].data()),
|
||||
testStrings[i].size());
|
||||
data->setContent(make_span(reinterpret_cast<const uint8_t*>(testStrings[i].data()),
|
||||
testStrings[i].size()));
|
||||
|
||||
dataStore.push_back(data);
|
||||
}
|
||||
@@ -134,6 +131,47 @@ BOOST_AUTO_TEST_CASE(OutputDataUnordered)
|
||||
BOOST_CHECK(output.is_equal(testStrings[2]));
|
||||
}
|
||||
|
||||
class PipelineInterestsDummy : public PipelineInterests
|
||||
{
|
||||
public:
|
||||
using PipelineInterests::PipelineInterests;
|
||||
|
||||
private:
|
||||
void
|
||||
doRun() final
|
||||
{
|
||||
isPipelineRunning = true;
|
||||
}
|
||||
|
||||
void
|
||||
doCancel() final
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
bool isPipelineRunning = false;
|
||||
};
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(RunBasic, IoFixture)
|
||||
{
|
||||
util::DummyClientFace face(m_io);
|
||||
Options options;
|
||||
Consumer consumer(security::getAcceptAllValidator());
|
||||
|
||||
Name prefix = Name("/ndn/chunks/test").appendVersion(1);
|
||||
auto discover = make_unique<DiscoverVersion>(face, prefix, options);
|
||||
auto pipeline = make_unique<PipelineInterestsDummy>(face, options);
|
||||
auto pipelinePtr = pipeline.get();
|
||||
|
||||
BOOST_CHECK_EQUAL(pipelinePtr->isPipelineRunning, false);
|
||||
|
||||
consumer.run(std::move(discover), std::move(pipeline));
|
||||
this->advanceClocks(1_ms);
|
||||
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 0); // no discovery Interests are issued
|
||||
BOOST_CHECK_EQUAL(pipelinePtr->isPipelineRunning, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestConsumer
|
||||
BOOST_AUTO_TEST_SUITE_END() // Chunks
|
||||
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2016, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Andrea Tosatto
|
||||
*/
|
||||
|
||||
#include "tools/chunks/catchunks/discover-version-fixed.hpp"
|
||||
|
||||
#include "discover-version-fixture.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace chunks {
|
||||
namespace tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
class DiscoverVersionFixedFixture : public DiscoverVersionFixture
|
||||
{
|
||||
public:
|
||||
DiscoverVersionFixedFixture()
|
||||
: DiscoverVersionFixture(makeOptions())
|
||||
, version(1449227841747)
|
||||
{
|
||||
setDiscover(make_unique<DiscoverVersionFixed>(Name(name).appendVersion(version),
|
||||
face, makeOptions()));
|
||||
}
|
||||
|
||||
protected:
|
||||
uint64_t version; //Version to find
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Chunks)
|
||||
BOOST_AUTO_TEST_SUITE(TestDiscoverVersionFixed)
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(RequestedVersionAvailable, DiscoverVersionFixedFixture)
|
||||
{
|
||||
discover->run();
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
|
||||
face.receive(*makeDataWithVersion(version));
|
||||
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
|
||||
BOOST_CHECK_EQUAL(discoveredVersion, version);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
auto lastInterest = face.sentInterests.back();
|
||||
BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMaxSuffixComponents(), 2);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMinSuffixComponents(), 2);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(NoVersionsAvailable, DiscoverVersionFixedFixture)
|
||||
{
|
||||
discover->run();
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
|
||||
for (int retries = 0; retries < maxRetriesOnTimeoutOrNack; ++retries) {
|
||||
advanceClocks(io, interestLifetime, 1);
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2 + retries);
|
||||
}
|
||||
|
||||
for (const auto& lastInterest : face.sentInterests) {
|
||||
BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMaxSuffixComponents(), 2);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMinSuffixComponents(), 2);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getName().equals(Name(name).appendVersion(version)), true);
|
||||
}
|
||||
|
||||
advanceClocks(io, interestLifetime, 1);
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
|
||||
// check if discovered version is the default value
|
||||
BOOST_CHECK_EQUAL(discoveredVersion, 0);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), maxRetriesOnTimeoutOrNack + 1);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(DataNotSegment, DiscoverVersionFixedFixture)
|
||||
{
|
||||
discover->run();
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
|
||||
std::vector<std::string> randomStrings {
|
||||
"",
|
||||
"abcdefg",
|
||||
"12345",
|
||||
"qr%67a3%4e"
|
||||
};
|
||||
|
||||
Exclude expectedExclude;
|
||||
for (size_t retries = 0; retries < randomStrings.size(); ++retries) {
|
||||
auto data = make_shared<Data>(Name(name).appendVersion(version).append(randomStrings[retries]));
|
||||
data->setFinalBlockId(name::Component::fromSegment(0));
|
||||
data = signData(data);
|
||||
|
||||
face.receive(*data);
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1 + retries);
|
||||
auto lastInterest = face.sentInterests.back();
|
||||
if (randomStrings[retries] != "")
|
||||
expectedExclude.excludeOne(name::Component::fromEscapedString(randomStrings[retries]));
|
||||
BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMaxSuffixComponents(), 2);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMinSuffixComponents(), 2);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
|
||||
}
|
||||
|
||||
advanceClocks(io, interestLifetime, maxRetriesOnTimeoutOrNack + 1);
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
|
||||
// check if discovered version is the default value
|
||||
BOOST_CHECK_EQUAL(discoveredVersion, 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestDiscoverVersionFixed
|
||||
BOOST_AUTO_TEST_SUITE_END() // Chunks
|
||||
|
||||
} // namespace tests
|
||||
} // namespace chunks
|
||||
} // namespace ndn
|
||||
@@ -1,104 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2016, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Andrea Tosatto
|
||||
*/
|
||||
|
||||
#ifndef NDN_TOOLS_TESTS_CHUNKS_DISCOVER_VERSION_FIXTURE_HPP
|
||||
#define NDN_TOOLS_TESTS_CHUNKS_DISCOVER_VERSION_FIXTURE_HPP
|
||||
|
||||
#include "tools/chunks/catchunks/discover-version.hpp"
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
namespace ndn {
|
||||
namespace chunks {
|
||||
namespace tests {
|
||||
|
||||
class DiscoverVersionFixture : public ndn::tests::UnitTestTimeFixture, virtual protected Options
|
||||
{
|
||||
public:
|
||||
DiscoverVersionFixture(const Options& options)
|
||||
: Options(options)
|
||||
, face(io)
|
||||
, name("/ndn/chunks/test")
|
||||
, isDiscoveryFinished(false)
|
||||
, discoveredVersion(0)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
void setDiscover(unique_ptr<DiscoverVersion> disc)
|
||||
{
|
||||
discover = std::move(disc);
|
||||
discover->onDiscoverySuccess.connect(bind(&DiscoverVersionFixture::onSuccess, this, _1));
|
||||
discover->onDiscoveryFailure.connect(bind(&DiscoverVersionFixture::onFailure, this, _1));
|
||||
}
|
||||
|
||||
shared_ptr<Data>
|
||||
makeDataWithVersion(uint64_t version)
|
||||
{
|
||||
auto data = make_shared<Data>(Name(name).appendVersion(version).appendSegment(0));
|
||||
data->setFinalBlockId(name::Component::fromSegment(0));
|
||||
return ndn::tests::signData(data);
|
||||
}
|
||||
|
||||
static Options
|
||||
makeOptions()
|
||||
{
|
||||
Options options;
|
||||
options.isVerbose = false;
|
||||
options.interestLifetime = time::seconds(1);
|
||||
options.maxRetriesOnTimeoutOrNack = 3;
|
||||
return options;
|
||||
}
|
||||
|
||||
virtual void
|
||||
onSuccess(const Data& data)
|
||||
{
|
||||
isDiscoveryFinished = true;
|
||||
|
||||
if (data.getName()[name.size()].isVersion())
|
||||
discoveredVersion = data.getName()[name.size()].toVersion();
|
||||
}
|
||||
|
||||
virtual void
|
||||
onFailure(const std::string& reason)
|
||||
{
|
||||
isDiscoveryFinished = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
boost::asio::io_service io;
|
||||
util::DummyClientFace face;
|
||||
Name name;
|
||||
unique_ptr<DiscoverVersion> discover;
|
||||
bool isDiscoveryFinished;
|
||||
uint64_t discoveredVersion;
|
||||
};
|
||||
|
||||
} // namespace tests
|
||||
} // namespace chunks
|
||||
} // namespace ndn
|
||||
|
||||
#endif // NDN_TOOLS_TESTS_CHUNKS_DISCOVER_VERSION_FIXTURE_HPP
|
||||
@@ -1,235 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2016, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Andrea Tosatto
|
||||
*/
|
||||
|
||||
#include "tools/chunks/catchunks/discover-version-iterative.hpp"
|
||||
|
||||
#include "discover-version-fixture.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace chunks {
|
||||
namespace tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
class DiscoverVersionIterativeFixture : public DiscoverVersionFixture,
|
||||
protected DiscoverVersionIterativeOptions
|
||||
{
|
||||
public:
|
||||
typedef DiscoverVersionIterativeOptions Options;
|
||||
|
||||
public:
|
||||
explicit
|
||||
DiscoverVersionIterativeFixture(const Options& opt = makeOptionsIterative())
|
||||
: chunks::Options(opt)
|
||||
, DiscoverVersionFixture(opt)
|
||||
, Options(opt)
|
||||
{
|
||||
setDiscover(make_unique<DiscoverVersionIterative>(Name(name), face, opt));
|
||||
}
|
||||
|
||||
protected:
|
||||
static Options
|
||||
makeOptionsIterative()
|
||||
{
|
||||
Options options;
|
||||
options.isVerbose = false;
|
||||
options.maxRetriesOnTimeoutOrNack = 3;
|
||||
options.maxRetriesAfterVersionFound = 1;
|
||||
return options;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Chunks)
|
||||
BOOST_AUTO_TEST_SUITE(TestDiscoverVersionIterative)
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(SingleVersionAvailable, DiscoverVersionIterativeFixture)
|
||||
{
|
||||
discover->run();
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
|
||||
uint64_t version = 1449241767037;
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
auto lastInterest = face.sentInterests.back();
|
||||
BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
|
||||
|
||||
// Send first segment for the right version
|
||||
face.receive(*makeDataWithVersion(version));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2);
|
||||
lastInterest = face.sentInterests.back();
|
||||
Exclude expectedExclude;
|
||||
expectedExclude.excludeBefore(name::Component::fromVersion(version));
|
||||
BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
|
||||
|
||||
// Generate the timeout
|
||||
for (int retries = 0; retries < maxRetriesAfterVersionFound; ++retries) {
|
||||
advanceClocks(io, interestLifetime, 1);
|
||||
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), retries + 3);
|
||||
lastInterest = face.sentInterests.back();
|
||||
Exclude expectedExclude;
|
||||
expectedExclude.excludeBefore(name::Component::fromVersion(version));
|
||||
BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
|
||||
}
|
||||
|
||||
advanceClocks(io, interestLifetime, 1);
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
|
||||
BOOST_CHECK_EQUAL(discoveredVersion, version);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), maxRetriesAfterVersionFound + 2);
|
||||
}
|
||||
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(NoVersionsAvailable, DiscoverVersionIterativeFixture)
|
||||
{
|
||||
discover->run();
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
|
||||
for (int retries = 0; retries < maxRetriesOnTimeoutOrNack; ++retries) {
|
||||
advanceClocks(io, interestLifetime, 1);
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2 + retries);
|
||||
}
|
||||
|
||||
for (auto& lastInterest : face.sentInterests) {
|
||||
BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
|
||||
}
|
||||
|
||||
advanceClocks(io, interestLifetime, 1);
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), maxRetriesOnTimeoutOrNack + 1);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(MultipleVersionsAvailable, DiscoverVersionIterativeFixture)
|
||||
{
|
||||
// nVersions must be positive
|
||||
const uint64_t nVersions = 5;
|
||||
|
||||
discover->run();
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
auto lastInterest = face.sentInterests.back();
|
||||
BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
|
||||
|
||||
for (uint64_t nSentVersions = 0; nSentVersions < nVersions; ++nSentVersions) {
|
||||
face.receive(*makeDataWithVersion(nSentVersions));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2 + nSentVersions);
|
||||
lastInterest = face.sentInterests.back();
|
||||
Exclude expectedExclude;
|
||||
expectedExclude.excludeBefore(name::Component::fromVersion(nSentVersions));
|
||||
BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
|
||||
}
|
||||
|
||||
for (int retries = 0; retries < maxRetriesAfterVersionFound; ++retries) {
|
||||
advanceClocks(io, interestLifetime, 1);
|
||||
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2 + retries + nVersions);
|
||||
lastInterest = face.sentInterests.back();
|
||||
Exclude expectedExclude;
|
||||
expectedExclude.excludeBefore(name::Component::fromVersion(nVersions - 1));
|
||||
BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
|
||||
}
|
||||
|
||||
advanceClocks(io, interestLifetime, 1);
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
|
||||
BOOST_CHECK_EQUAL(discoveredVersion, nVersions - 1);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), nVersions + maxRetriesAfterVersionFound + 1);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(MultipleVersionsAvailableDescendent, DiscoverVersionIterativeFixture)
|
||||
{
|
||||
// nVersions must be positive
|
||||
const uint64_t nVersions = 5;
|
||||
|
||||
discover->run();
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
auto lastInterest = face.sentInterests.back();
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
|
||||
|
||||
for (uint64_t nVersionsToSend = nVersions; nVersionsToSend > 0; --nVersionsToSend) {
|
||||
face.receive(*makeDataWithVersion(nVersionsToSend - 1));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2);
|
||||
lastInterest = face.sentInterests.back();
|
||||
Exclude expectedExclude;
|
||||
expectedExclude.excludeBefore(name::Component::fromVersion(nVersions - 1));
|
||||
BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
|
||||
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
|
||||
}
|
||||
|
||||
advanceClocks(io, interestLifetime, maxRetriesAfterVersionFound + 1);
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
|
||||
BOOST_CHECK_EQUAL(discoveredVersion, nVersions - 1);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), maxRetriesAfterVersionFound + 2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestDiscoverVersionIterative
|
||||
BOOST_AUTO_TEST_SUITE_END() // Chunks
|
||||
|
||||
} // namespace tests
|
||||
} // namespace chunks
|
||||
} // namespace ndn
|
||||
@@ -0,0 +1,220 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2016-2020, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Chavoosh Ghasemi
|
||||
*/
|
||||
|
||||
#include "tools/chunks/catchunks/discover-version.hpp"
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include "tests/io-fixture.hpp"
|
||||
#include "tests/key-chain-fixture.hpp"
|
||||
|
||||
#include <ndn-cxx/metadata-object.hpp>
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
namespace ndn {
|
||||
namespace chunks {
|
||||
namespace tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
class DiscoverVersionFixture : public IoFixture, public KeyChainFixture
|
||||
{
|
||||
public:
|
||||
void
|
||||
run(const Name& prefix)
|
||||
{
|
||||
discover = make_unique<DiscoverVersion>(face, prefix, opt);
|
||||
discover->onDiscoverySuccess.connect([this] (const Name& versionedName) {
|
||||
isDiscoveryFinished = true;
|
||||
discoveredName = versionedName;
|
||||
if (!versionedName.empty() && versionedName[-1].isVersion())
|
||||
discoveredVersion = versionedName[-1].toVersion();
|
||||
});
|
||||
discover->onDiscoveryFailure.connect([this] (const std::string&) {
|
||||
isDiscoveryFinished = true;
|
||||
});
|
||||
|
||||
discover->run();
|
||||
advanceClocks(1_ns);
|
||||
}
|
||||
|
||||
protected:
|
||||
const Name name = "/ndn/chunks/test";
|
||||
const uint64_t version = 1449227841747;
|
||||
util::DummyClientFace face{m_io};
|
||||
Options opt;
|
||||
unique_ptr<DiscoverVersion> discover;
|
||||
optional<Name> discoveredName;
|
||||
optional<uint64_t> discoveredVersion;
|
||||
bool isDiscoveryFinished = false;
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Chunks)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestDiscoverVersion, DiscoverVersionFixture)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Disabled)
|
||||
{
|
||||
opt.disableVersionDiscovery = true;
|
||||
run(name);
|
||||
|
||||
// no version discovery Interest is expressed
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(discoveredName.value(), name);
|
||||
BOOST_CHECK_EQUAL(discoveredVersion.has_value(), false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(NameWithVersion)
|
||||
{
|
||||
// start with a name that already contains a version component
|
||||
Name versionedName = Name(name).appendVersion(version);
|
||||
run(versionedName);
|
||||
|
||||
// no version discovery Interest is expressed
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(discoveredName.value(), versionedName);
|
||||
BOOST_CHECK_EQUAL(discoveredVersion.value(), version);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Success)
|
||||
{
|
||||
run(name);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
|
||||
Interest discoveryInterest = MetadataObject::makeDiscoveryInterest(name);
|
||||
auto lastInterest = face.sentInterests.back();
|
||||
BOOST_CHECK_EQUAL(lastInterest.getName(), discoveryInterest.getName());
|
||||
|
||||
// send back a metadata packet with a valid versioned name
|
||||
MetadataObject mobject;
|
||||
mobject.setVersionedName(Name(name).appendVersion(version));
|
||||
face.receive(mobject.makeData(lastInterest.getName(), m_keyChain));
|
||||
advanceClocks(1_ns);
|
||||
|
||||
BOOST_CHECK_EQUAL(discoveredVersion.value(), version);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(InvalidDiscoveredVersionedName)
|
||||
{
|
||||
run(name);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
|
||||
// send back a metadata packet with an invalid versioned name
|
||||
MetadataObject mobject;
|
||||
mobject.setVersionedName(name);
|
||||
face.receive(mobject.makeData(face.sentInterests.back().getName(), m_keyChain));
|
||||
|
||||
// finish discovery process without a resolved version number
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
|
||||
BOOST_CHECK_EQUAL(discoveredName.has_value(), false);
|
||||
BOOST_CHECK_EQUAL(discoveredVersion.has_value(), false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(InvalidMetadataPacket)
|
||||
{
|
||||
run(name);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
|
||||
// send back an invalid metadata packet
|
||||
Data data(face.sentInterests.back().getName());
|
||||
data.setFreshnessPeriod(1_s);
|
||||
data.setContentType(tlv::ContentType_Key);
|
||||
face.receive(signData(data));
|
||||
|
||||
// finish discovery process without a resolved version number
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
|
||||
BOOST_CHECK_EQUAL(discoveredName.has_value(), false);
|
||||
BOOST_CHECK_EQUAL(discoveredVersion.has_value(), false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MaxRetriesExceeded)
|
||||
{
|
||||
opt.maxRetriesOnTimeoutOrNack = 3;
|
||||
run(name);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
|
||||
// timeout or nack discovery Interests
|
||||
for (int retries = 0; retries < opt.maxRetriesOnTimeoutOrNack * 2; ++retries) {
|
||||
if (retries % 2 == 0) {
|
||||
advanceClocks(opt.interestLifetime);
|
||||
}
|
||||
else {
|
||||
face.receive(makeNack(face.sentInterests.back(), lp::NackReason::DUPLICATE));
|
||||
advanceClocks(1_ns);
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), retries + 2);
|
||||
}
|
||||
|
||||
// timeout the last sent Interest
|
||||
advanceClocks(opt.interestLifetime);
|
||||
|
||||
// finish discovery process without a resolved version number
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
|
||||
BOOST_CHECK_EQUAL(discoveredName.has_value(), false);
|
||||
BOOST_CHECK_EQUAL(discoveredVersion.has_value(), false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(SuccessAfterNackAndTimeout)
|
||||
{
|
||||
opt.maxRetriesOnTimeoutOrNack = 3;
|
||||
run(name);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
|
||||
// timeout or nack discovery Interests
|
||||
for (int retries = 0; retries < opt.maxRetriesOnTimeoutOrNack * 2; ++retries) {
|
||||
if (retries % 2 == 0) {
|
||||
advanceClocks(opt.interestLifetime);
|
||||
}
|
||||
else {
|
||||
face.receive(makeNack(face.sentInterests.back(), lp::NackReason::DUPLICATE));
|
||||
advanceClocks(1_ns);
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), retries + 2);
|
||||
}
|
||||
|
||||
// satisfy the last Interest with a valid metadata packet
|
||||
MetadataObject mobject;
|
||||
mobject.setVersionedName(Name(name).appendVersion(version));
|
||||
face.receive(mobject.makeData(face.sentInterests.back().getName(), m_keyChain));
|
||||
advanceClocks(1_ns);
|
||||
|
||||
BOOST_CHECK_EQUAL(discoveredVersion.value(), version);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestDiscoverVersion
|
||||
BOOST_AUTO_TEST_SUITE_END() // Chunks
|
||||
|
||||
} // namespace tests
|
||||
} // namespace chunks
|
||||
} // namespace ndn
|
||||
@@ -0,0 +1,601 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2016-2020, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Weiwei Liu
|
||||
* @author Chavoosh Ghasemi
|
||||
* @author Klaus Schneider
|
||||
*/
|
||||
|
||||
#include "tools/chunks/catchunks/pipeline-interests-aimd.hpp"
|
||||
|
||||
#include "pipeline-interests-fixture.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace chunks {
|
||||
namespace tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
class PipelineInterestAimdFixture : public PipelineInterestsFixture
|
||||
{
|
||||
public:
|
||||
PipelineInterestAimdFixture()
|
||||
: rttEstimator(makeRttEstimatorOptions())
|
||||
{
|
||||
opt.isQuiet = true;
|
||||
createPipeline();
|
||||
}
|
||||
|
||||
void
|
||||
createPipeline()
|
||||
{
|
||||
auto pline = make_unique<PipelineInterestsAimd>(face, rttEstimator, opt);
|
||||
pipeline = pline.get();
|
||||
setPipeline(std::move(pline));
|
||||
}
|
||||
|
||||
private:
|
||||
static shared_ptr<RttEstimatorWithStats::Options>
|
||||
makeRttEstimatorOptions()
|
||||
{
|
||||
auto rttOptions = make_shared<RttEstimatorWithStats::Options>();
|
||||
rttOptions->alpha = 0.125;
|
||||
rttOptions->beta = 0.25;
|
||||
rttOptions->k = 4;
|
||||
rttOptions->initialRto = 1_s;
|
||||
rttOptions->minRto = 200_ms;
|
||||
rttOptions->maxRto = 4_s;
|
||||
rttOptions->rtoBackoffMultiplier = 2;
|
||||
return rttOptions;
|
||||
}
|
||||
|
||||
protected:
|
||||
Options opt;
|
||||
RttEstimatorWithStats rttEstimator;
|
||||
PipelineInterestsAdaptive* pipeline;
|
||||
static constexpr double MARGIN = 0.001;
|
||||
};
|
||||
|
||||
constexpr double PipelineInterestAimdFixture::MARGIN;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Chunks)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestPipelineInterestsAimd, PipelineInterestAimdFixture)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(SlowStart)
|
||||
{
|
||||
nDataSegments = 4;
|
||||
pipeline->m_ssthresh = 8.0;
|
||||
BOOST_REQUIRE_CLOSE(pipeline->m_cwnd, 2, MARGIN);
|
||||
|
||||
double preCwnd = pipeline->m_cwnd;
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 2);
|
||||
|
||||
for (uint64_t i = 0; i < nDataSegments - 1; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd - preCwnd, 1, MARGIN);
|
||||
preCwnd = pipeline->m_cwnd;
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, nDataSegments - 1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CongestionAvoidance)
|
||||
{
|
||||
nDataSegments = 7;
|
||||
pipeline->m_ssthresh = 4.0;
|
||||
BOOST_REQUIRE_CLOSE(pipeline->m_cwnd, 2, MARGIN);
|
||||
|
||||
double preCwnd = pipeline->m_cwnd;
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 2);
|
||||
|
||||
for (uint64_t i = 0; i < pipeline->m_ssthresh; ++i) { // slow start
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
preCwnd = pipeline->m_cwnd;
|
||||
}
|
||||
|
||||
BOOST_CHECK_CLOSE(preCwnd, 4.5, MARGIN);
|
||||
|
||||
for (uint64_t i = pipeline->m_ssthresh; i < nDataSegments - 1; ++i) { // congestion avoidance
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd - preCwnd, opt.aiStep / floor(preCwnd), MARGIN);
|
||||
preCwnd = pipeline->m_cwnd;
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, nDataSegments -1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Timeout)
|
||||
{
|
||||
nDataSegments = 8;
|
||||
pipeline->m_ssthresh = 4.0;
|
||||
BOOST_REQUIRE_CLOSE(pipeline->m_cwnd, 2, MARGIN);
|
||||
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 2);
|
||||
|
||||
// receive segment 0, 1, and 2
|
||||
for (uint64_t i = 0; i < 3; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 3);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 4.25, MARGIN);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 7); // request for segment 7 has been sent
|
||||
|
||||
advanceClocks(time::milliseconds(100));
|
||||
|
||||
// receive segment 4
|
||||
face.receive(*makeDataWithSegment(4));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// receive segment 5
|
||||
face.receive(*makeDataWithSegment(5));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 5);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 4.75, MARGIN);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), nDataSegments); // all the segment requests have been sent
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nTimeouts, 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nLossDecr, 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nMarkDecr, 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nRetransmitted, 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nSkippedRetx, 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nCongMarks, 0);
|
||||
|
||||
// timeout segment 3 & 6
|
||||
advanceClocks(time::milliseconds(150));
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nTimeouts, 2);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nRetransmitted, 1);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nLossDecr, 1);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nSkippedRetx, 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 5);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 2.375, MARGIN); // window size drop to 1/2 of previous size
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxQueue.size(), 1);
|
||||
|
||||
// receive segment 6, retransmit 3
|
||||
face.receive(*makeDataWithSegment(6));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 6);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 2.875, MARGIN); // congestion avoidance
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxQueue.size(), 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount[3], 1);
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nTimeouts, 2);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nRetransmitted, 2);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nTimeouts,
|
||||
pipeline->m_nRetransmitted + pipeline->m_nSkippedRetx);
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CongestionMarksWithCwa)
|
||||
{
|
||||
nDataSegments = 7;
|
||||
pipeline->m_ssthresh = 4.0;
|
||||
BOOST_REQUIRE_CLOSE(pipeline->m_cwnd, 2, MARGIN);
|
||||
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 2);
|
||||
|
||||
// receive segments 0 to 4
|
||||
for (uint64_t i = 0; i < 5; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 5);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 4.75, MARGIN);
|
||||
|
||||
// receive segment 5 with congestion mark
|
||||
face.receive(*makeDataWithSegmentAndCongMark(5));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 6);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 2.375, MARGIN); // window size drops to 1/2 of previous size
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), nDataSegments); // all interests have been sent
|
||||
|
||||
// receive the last segment with congestion mark
|
||||
face.receive(*makeDataWithSegmentAndCongMark(nDataSegments - 1));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, nDataSegments);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 2.375, MARGIN); // conservative window adaption (window size should not decrease)
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxQueue.size(), 0);
|
||||
|
||||
// make sure no interest is retransmitted for marked data packets
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount[5], 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount[nDataSegments - 1], 0);
|
||||
|
||||
// check number of received marked data packets
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nCongMarks, 2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CongestionMarksWithoutCwa)
|
||||
{
|
||||
opt.disableCwa = true;
|
||||
createPipeline();
|
||||
|
||||
nDataSegments = 7;
|
||||
pipeline->m_ssthresh = 4.0;
|
||||
BOOST_REQUIRE_CLOSE(pipeline->m_cwnd, 2, MARGIN);
|
||||
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 2);
|
||||
|
||||
// receive segments 0 to 4
|
||||
for (uint64_t i = 0; i < 5; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 5);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 4.75, MARGIN);
|
||||
|
||||
// receive segment 5 with congestion mark
|
||||
face.receive(*makeDataWithSegmentAndCongMark(5));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 6);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 2.375, MARGIN); // window size drops to 1/2 of previous size
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), nDataSegments); // all interests have been sent
|
||||
|
||||
// receive the last segment with congestion mark
|
||||
face.receive(*makeDataWithSegmentAndCongMark(nDataSegments - 1));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, nDataSegments);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, PipelineInterestsAdaptive::MIN_SSTHRESH,
|
||||
MARGIN); // window size should decrease, as cwa is disabled
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxQueue.size(), 0);
|
||||
|
||||
// make sure no interest is retransmitted for marked data packets
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount[5], 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount[nDataSegments - 1], 0);
|
||||
|
||||
// check number of received marked data packets
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nCongMarks, 2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(IgnoreCongestionMarks)
|
||||
{
|
||||
opt.ignoreCongMarks = true;
|
||||
createPipeline();
|
||||
|
||||
nDataSegments = 7;
|
||||
pipeline->m_ssthresh = 4.0;
|
||||
BOOST_REQUIRE_CLOSE(pipeline->m_cwnd, 2, MARGIN);
|
||||
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 2);
|
||||
|
||||
// receive segments 0 to 5
|
||||
for (uint64_t i = 0; i < 6; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 6);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 5.0, MARGIN);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), nDataSegments); // all interests have been sent
|
||||
|
||||
// receive the last segment with congestion mark
|
||||
face.receive(*makeDataWithSegmentAndCongMark(nDataSegments - 1));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, nDataSegments);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 5.2, MARGIN); // window size increases
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxQueue.size(), 0);
|
||||
|
||||
// make sure no interest is retransmitted for marked data packet
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount[nDataSegments - 1], 0);
|
||||
|
||||
// check number of received marked data packets
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nCongMarks, 1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Nack)
|
||||
{
|
||||
nDataSegments = 5;
|
||||
pipeline->m_cwnd = 10.0;
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
face.receive(*makeDataWithSegment(0));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
face.receive(*makeDataWithSegment(1));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 2);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 10);
|
||||
|
||||
// receive a nack with NackReason::DUPLICATE for segment 1
|
||||
auto nack1 = makeNack(face.sentInterests[1], lp::NackReason::DUPLICATE);
|
||||
face.receive(nack1);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// nack1 is ignored
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 2);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxQueue.size(), 0);
|
||||
|
||||
// receive a nack with NackReason::CONGESTION for segment 2
|
||||
auto nack2 = makeNack(face.sentInterests[2], lp::NackReason::CONGESTION);
|
||||
face.receive(nack2);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// segment 2 is retransmitted
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount[2], 1);
|
||||
|
||||
// receive a nack with NackReason::NONE for segment 3
|
||||
auto nack3 = makeNack(face.sentInterests[3], lp::NackReason::NONE);
|
||||
face.receive(nack3);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// Other types of Nack will trigger a failure
|
||||
BOOST_CHECK_EQUAL(hasFailed, true);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(FinalBlockIdNotSetAtBeginning)
|
||||
{
|
||||
nDataSegments = 4;
|
||||
pipeline->m_cwnd = 4;
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// receive segment 0 without FinalBlockId
|
||||
face.receive(*makeDataWithSegment(0, false));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// interests for segment 0 - 5 have been sent
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 6);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 1);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_hasFinalBlockId, false);
|
||||
// pending interests: segment 1, 2, 3, 4, 5
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 5);
|
||||
|
||||
// receive segment 1 with FinalBlockId
|
||||
face.receive(*makeDataWithSegment(1));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 2);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_hasFinalBlockId, true);
|
||||
|
||||
// pending interests for segment 1, 4, 5 haven been removed
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(FailureBeforeFinalBlockIdReceived)
|
||||
{
|
||||
// failed to retrieve segNo while the FinalBlockId has not yet been
|
||||
// set, and later received a FinalBlockId >= segNo, i.e. segNo is
|
||||
// part of the content.
|
||||
|
||||
nDataSegments = 4;
|
||||
pipeline->m_cwnd = 4;
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// receive segment 0 without FinalBlockId
|
||||
face.receive(*makeDataWithSegment(0, false));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// receive segment 1 without FinalBlockId
|
||||
face.receive(*makeDataWithSegment(1, false));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// interests for segment 0 - 7 have been sent
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 8);
|
||||
|
||||
// receive nack with NackReason::NONE for segment 3
|
||||
auto nack = makeNack(face.sentInterests[3], lp::NackReason::NONE);
|
||||
face.receive(nack);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// error not triggered
|
||||
// pending interests for segment > 3 haven been removed
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 1);
|
||||
|
||||
// receive segment 2 with FinalBlockId
|
||||
face.receive(*makeDataWithSegment(2));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// error triggered since segment 3 is part of the content
|
||||
BOOST_CHECK_EQUAL(hasFailed, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(SpuriousFailureBeforeFinalBlockIdReceived)
|
||||
{
|
||||
// failed to retrieve segNo while the FinalBlockId has not yet been
|
||||
// set, and later received a FinalBlockId < segNo, i.e. segNo is
|
||||
// not part of the content, and it was actually a spurious failure
|
||||
|
||||
nDataSegments = 4;
|
||||
pipeline->m_cwnd = 4;
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// receive segment 0 without FinalBlockId
|
||||
face.receive(*makeDataWithSegment(0, false));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// receive segment 1 without FinalBlockId
|
||||
face.receive(*makeDataWithSegment(1, false));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// interests for segment 0 - 7 have been sent
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 8);
|
||||
|
||||
// receive nack with NackReason::NONE for segment 4
|
||||
auto nack = makeNack(face.sentInterests[4], lp::NackReason::NONE);
|
||||
face.receive(nack);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// error not triggered
|
||||
// pending interests for segment > 3 have been removed
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 2);
|
||||
|
||||
// receive segment 2 with FinalBlockId
|
||||
face.receive(*makeDataWithSegment(2));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// timeout segment 3
|
||||
advanceClocks(time::seconds(1));
|
||||
|
||||
// segment 3 is retransmitted
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount[3], 1);
|
||||
|
||||
// receive segment 3
|
||||
face.receive(*makeDataWithSegment(3));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(SegmentInfoMaintenance)
|
||||
{
|
||||
// test that m_segmentInfo is properly maintained when
|
||||
// a segment is received after two consecutive timeouts
|
||||
|
||||
nDataSegments = 3;
|
||||
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// receive segment 0
|
||||
face.receive(*makeDataWithSegment(0));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// receive segment 1
|
||||
face.receive(*makeDataWithSegment(1));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 3);
|
||||
|
||||
// check if segment 2's state is FirstTimeSent
|
||||
auto it = pipeline->m_segmentInfo.find(2);
|
||||
BOOST_REQUIRE(it != pipeline->m_segmentInfo.end());
|
||||
BOOST_CHECK(it->second.state == SegmentState::FirstTimeSent);
|
||||
|
||||
// timeout segment 2 twice
|
||||
advanceClocks(time::milliseconds(400), 3);
|
||||
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 5);
|
||||
|
||||
// check if segment 2's state is Retransmitted
|
||||
it = pipeline->m_segmentInfo.find(2);
|
||||
BOOST_REQUIRE(it != pipeline->m_segmentInfo.end());
|
||||
BOOST_CHECK(it->second.state == SegmentState::Retransmitted);
|
||||
|
||||
// check if segment 2 was retransmitted twice
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount.at(2), 2);
|
||||
|
||||
// receive segment 2 the first time
|
||||
face.receive(*makeDataWithSegment(2));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// check if segment 2 was erased from m_segmentInfo
|
||||
it = pipeline->m_segmentInfo.find(2);
|
||||
BOOST_CHECK(it == pipeline->m_segmentInfo.end());
|
||||
|
||||
auto prevRtt = rttEstimator.getAvgRtt();
|
||||
auto prevRto = rttEstimator.getEstimatedRto();
|
||||
|
||||
// receive segment 2 the second time
|
||||
face.receive(*makeDataWithSegment(2));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// nothing changed
|
||||
it = pipeline->m_segmentInfo.find(2);
|
||||
BOOST_CHECK(it == pipeline->m_segmentInfo.end());
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 5);
|
||||
BOOST_CHECK_EQUAL(rttEstimator.getAvgRtt(), prevRtt);
|
||||
BOOST_CHECK_EQUAL(rttEstimator.getEstimatedRto(), prevRto);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(PrintSummaryWithNoRttMeasurements)
|
||||
{
|
||||
// test the console ouptut when no RTT measurement is available,
|
||||
// to make sure a proper message will be printed out
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
// change the underlying buffer and save the old buffer
|
||||
auto oldBuf = std::cerr.rdbuf(ss.rdbuf());
|
||||
|
||||
pipeline->printSummary();
|
||||
std::string line;
|
||||
|
||||
bool found = false;
|
||||
while (std::getline(ss, line)) {
|
||||
if (line == "RTT stats unavailable") {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BOOST_CHECK(found);
|
||||
std::cerr.rdbuf(oldBuf); // reset
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(StopsWhenFileSizeLessThanChunkSize)
|
||||
{
|
||||
// test to see if the program doesn't hang,
|
||||
// when transfer is complete, for files less than the chunk size
|
||||
// (i.e. when only one segment is sent/received)
|
||||
|
||||
createPipeline();
|
||||
nDataSegments = 1;
|
||||
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
face.receive(*makeDataWithSegment(0));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_hasFinalBlockId, true);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_segmentInfo.size(), 0);
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestPipelineInterestsAimd
|
||||
BOOST_AUTO_TEST_SUITE_END() // Chunks
|
||||
|
||||
} // namespace tests
|
||||
} // namespace chunks
|
||||
} // namespace ndn
|
||||
@@ -0,0 +1,567 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2016-2020, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Weiwei Liu
|
||||
* @author Chavoosh Ghasemi
|
||||
* @author Klaus Schneider
|
||||
*/
|
||||
|
||||
#include "tools/chunks/catchunks/pipeline-interests-cubic.hpp"
|
||||
|
||||
#include "pipeline-interests-fixture.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace chunks {
|
||||
namespace tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
class PipelineInterestCubicFixture : public PipelineInterestsFixture
|
||||
{
|
||||
public:
|
||||
PipelineInterestCubicFixture()
|
||||
: rttEstimator(makeRttEstimatorOptions())
|
||||
{
|
||||
opt.isQuiet = true;
|
||||
createPipeline();
|
||||
}
|
||||
|
||||
void
|
||||
createPipeline()
|
||||
{
|
||||
auto pline = make_unique<PipelineInterestsCubic>(face, rttEstimator, opt);
|
||||
pipeline = pline.get();
|
||||
setPipeline(std::move(pline));
|
||||
}
|
||||
|
||||
private:
|
||||
static shared_ptr<RttEstimatorWithStats::Options>
|
||||
makeRttEstimatorOptions()
|
||||
{
|
||||
auto rttOptions = make_shared<RttEstimatorWithStats::Options>();
|
||||
rttOptions->alpha = 0.125;
|
||||
rttOptions->beta = 0.25;
|
||||
rttOptions->k = 8;
|
||||
rttOptions->initialRto = 1_s;
|
||||
rttOptions->minRto = 200_ms;
|
||||
rttOptions->maxRto = 4_s;
|
||||
rttOptions->rtoBackoffMultiplier = 2;
|
||||
return rttOptions;
|
||||
}
|
||||
|
||||
protected:
|
||||
Options opt;
|
||||
RttEstimatorWithStats rttEstimator;
|
||||
PipelineInterestsCubic* pipeline;
|
||||
static constexpr double MARGIN = 0.001;
|
||||
};
|
||||
|
||||
constexpr double PipelineInterestCubicFixture::MARGIN;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Chunks)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestPipelineInterestsCubic, PipelineInterestCubicFixture)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(SlowStart)
|
||||
{
|
||||
nDataSegments = 4;
|
||||
BOOST_REQUIRE_CLOSE(pipeline->m_cwnd, 2, MARGIN);
|
||||
|
||||
double preCwnd = pipeline->m_cwnd;
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 2);
|
||||
|
||||
for (uint64_t i = 0; i < nDataSegments - 1; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd - preCwnd, 1, MARGIN);
|
||||
preCwnd = pipeline->m_cwnd;
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, nDataSegments - 1);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Timeout)
|
||||
{
|
||||
nDataSegments = 8;
|
||||
BOOST_REQUIRE_CLOSE(pipeline->m_cwnd, 2, MARGIN);
|
||||
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 2);
|
||||
|
||||
// receive segment 0, 1, and 2
|
||||
for (uint64_t i = 0; i < 3; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 3);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 5, MARGIN);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 8); // request for segment #7 has been sent
|
||||
|
||||
advanceClocks(time::milliseconds(100));
|
||||
|
||||
// receive segment 4
|
||||
face.receive(*makeDataWithSegment(4));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// receive segment 5
|
||||
face.receive(*makeDataWithSegment(5));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 5);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 7.0, MARGIN);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), nDataSegments); // all the segment requests have been sent
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nTimeouts, 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nLossDecr, 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nMarkDecr, 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nRetransmitted, 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nSkippedRetx, 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nCongMarks, 0);
|
||||
|
||||
// timeout segment 3 & 6
|
||||
advanceClocks(time::milliseconds(150));
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nTimeouts, 3);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nRetransmitted, 3);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nLossDecr, 1);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nSkippedRetx, 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 5);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 4.9, MARGIN); // window size drop to 0.7x of previous size
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxQueue.size(), 0);
|
||||
|
||||
// receive segment 6, retransmit 3
|
||||
face.receive(*makeDataWithSegment(6));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 6);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 4.9, MARGIN); // congestion avoidance
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxQueue.size(), 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount[3], 1);
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nTimeouts, 3);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nRetransmitted, 3);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nTimeouts,
|
||||
pipeline->m_nRetransmitted + pipeline->m_nSkippedRetx);
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CongestionMarksWithCwa)
|
||||
{
|
||||
nDataSegments = 7;
|
||||
BOOST_REQUIRE_CLOSE(pipeline->m_cwnd, 2, MARGIN);
|
||||
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 2);
|
||||
|
||||
// receive segments 0 to 4
|
||||
for (uint64_t i = 0; i < 5; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 5);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 7.0, MARGIN);
|
||||
|
||||
// receive segment 5 with congestion mark
|
||||
face.receive(*makeDataWithSegmentAndCongMark(5));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 6);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 4.9, MARGIN); // window size drops to 0.7x of previous size
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), nDataSegments); // all interests have been sent
|
||||
|
||||
// receive the last segment with congestion mark
|
||||
face.receive(*makeDataWithSegmentAndCongMark(nDataSegments - 1));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, nDataSegments);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 4.9, MARGIN); // conservative window adaption (window size should not decrease)
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxQueue.size(), 0);
|
||||
|
||||
// make sure no interest is retransmitted for marked data packets
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount[5], 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount[nDataSegments - 1], 0);
|
||||
|
||||
// check number of received marked data packets
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nCongMarks, 2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CongestionMarksWithoutCwa)
|
||||
{
|
||||
opt.disableCwa = true;
|
||||
createPipeline();
|
||||
|
||||
nDataSegments = 7;
|
||||
BOOST_REQUIRE_CLOSE(pipeline->m_cwnd, 2, MARGIN);
|
||||
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 2);
|
||||
|
||||
// receive segments 0 to 4
|
||||
for (uint64_t i = 0; i < 5; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 5);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 7.0, MARGIN);
|
||||
|
||||
// receive segment 5 with congestion mark
|
||||
face.receive(*makeDataWithSegmentAndCongMark(5));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 6);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 4.9, MARGIN); // window size drops to 0.7x of previous size
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), nDataSegments); // all interests have been sent
|
||||
|
||||
// receive the last segment with congestion mark
|
||||
face.receive(*makeDataWithSegmentAndCongMark(nDataSegments - 1));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, nDataSegments);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 3.43, MARGIN); // window size should decrease, as cwa is disabled
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxQueue.size(), 0);
|
||||
|
||||
// make sure no interest is retransmitted for marked data packets
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount[5], 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount[nDataSegments - 1], 0);
|
||||
|
||||
// check number of received marked data packets
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nCongMarks, 2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(IgnoreCongestionMarks)
|
||||
{
|
||||
opt.ignoreCongMarks = true;
|
||||
createPipeline();
|
||||
|
||||
nDataSegments = 7;
|
||||
BOOST_REQUIRE_CLOSE(pipeline->m_cwnd, 2, MARGIN);
|
||||
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 2);
|
||||
|
||||
// receive segments 0 to 5
|
||||
for (uint64_t i = 0; i < 6; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 6);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 8.0, MARGIN);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), nDataSegments); // all interests have been sent
|
||||
|
||||
// receive the last segment with congestion mark
|
||||
face.receive(*makeDataWithSegmentAndCongMark(nDataSegments - 1));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, nDataSegments);
|
||||
BOOST_CHECK_CLOSE(pipeline->m_cwnd, 9.0, MARGIN); // window size increases
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxQueue.size(), 0);
|
||||
|
||||
// make sure no interest is retransmitted for marked data packet
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount[nDataSegments - 1], 0);
|
||||
|
||||
// check number of received marked data packets
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nCongMarks, 1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Nack)
|
||||
{
|
||||
nDataSegments = 5;
|
||||
pipeline->m_cwnd = 10.0;
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
face.receive(*makeDataWithSegment(0));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
face.receive(*makeDataWithSegment(1));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 2);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 10);
|
||||
|
||||
// receive a nack with NackReason::DUPLICATE for segment 1
|
||||
auto nack1 = makeNack(face.sentInterests[1], lp::NackReason::DUPLICATE);
|
||||
face.receive(nack1);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// nack1 is ignored
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 2);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxQueue.size(), 0);
|
||||
|
||||
// receive a nack with NackReason::CONGESTION for segment 2
|
||||
auto nack2 = makeNack(face.sentInterests[2], lp::NackReason::CONGESTION);
|
||||
face.receive(nack2);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// segment 2 is retransmitted
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount[2], 1);
|
||||
|
||||
// receive a nack with NackReason::NONE for segment 3
|
||||
auto nack3 = makeNack(face.sentInterests[3], lp::NackReason::NONE);
|
||||
face.receive(nack3);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// Other types of Nack will trigger a failure
|
||||
BOOST_CHECK_EQUAL(hasFailed, true);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(FinalBlockIdNotSetAtBeginning)
|
||||
{
|
||||
nDataSegments = 4;
|
||||
pipeline->m_cwnd = 4;
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// receive segment 0 without FinalBlockId
|
||||
face.receive(*makeDataWithSegment(0, false));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// interests for segment 0 - 5 have been sent
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 6);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 1);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_hasFinalBlockId, false);
|
||||
// pending interests: segment 1, 2, 3, 4, 5
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 5);
|
||||
|
||||
// receive segment 1 with FinalBlockId
|
||||
face.receive(*makeDataWithSegment(1));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 2);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_hasFinalBlockId, true);
|
||||
|
||||
// pending interests for segment 1, 4, 5 haven been removed
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(FailureBeforeFinalBlockIdReceived)
|
||||
{
|
||||
// failed to retrieve segNo while the FinalBlockId has not yet been
|
||||
// set, and later received a FinalBlockId >= segNo, i.e. segNo is
|
||||
// part of the content.
|
||||
|
||||
nDataSegments = 4;
|
||||
pipeline->m_cwnd = 4;
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// receive segment 0 without FinalBlockId
|
||||
face.receive(*makeDataWithSegment(0, false));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// receive segment 1 without FinalBlockId
|
||||
face.receive(*makeDataWithSegment(1, false));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// interests for segment 0 - 7 have been sent
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 8);
|
||||
|
||||
// receive nack with NackReason::NONE for segment 3
|
||||
auto nack = makeNack(face.sentInterests[3], lp::NackReason::NONE);
|
||||
face.receive(nack);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// error not triggered
|
||||
// pending interests for segment > 3 haven been removed
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 1);
|
||||
|
||||
// receive segment 2 with FinalBlockId
|
||||
face.receive(*makeDataWithSegment(2));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// error triggered since segment 3 is part of the content
|
||||
BOOST_CHECK_EQUAL(hasFailed, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(SpuriousFailureBeforeFinalBlockIdReceived)
|
||||
{
|
||||
// failed to retrieve segNo while the FinalBlockId has not yet been
|
||||
// set, and later received a FinalBlockId < segNo, i.e. segNo is
|
||||
// not part of the content, and it was actually a spurious failure
|
||||
|
||||
nDataSegments = 4;
|
||||
pipeline->m_cwnd = 4;
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// receive segment 0 without FinalBlockId
|
||||
face.receive(*makeDataWithSegment(0, false));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// receive segment 1 without FinalBlockId
|
||||
face.receive(*makeDataWithSegment(1, false));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// interests for segment 0 - 7 have been sent
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 8);
|
||||
|
||||
// receive nack with NackReason::NONE for segment 4
|
||||
auto nack = makeNack(face.sentInterests[4], lp::NackReason::NONE);
|
||||
face.receive(nack);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// error not triggered
|
||||
// pending interests for segment > 3 have been removed
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 2);
|
||||
|
||||
// receive segment 2 with FinalBlockId
|
||||
face.receive(*makeDataWithSegment(2));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// timeout segment 3
|
||||
advanceClocks(time::seconds(1));
|
||||
|
||||
// segment 3 is retransmitted
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount[3], 1);
|
||||
|
||||
// receive segment 3
|
||||
face.receive(*makeDataWithSegment(3));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(SegmentInfoMaintenance)
|
||||
{
|
||||
// test that m_segmentInfo is properly maintained when
|
||||
// a segment is received after two consecutive timeouts
|
||||
|
||||
nDataSegments = 3;
|
||||
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// receive segment 0
|
||||
face.receive(*makeDataWithSegment(0));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// receive segment 1
|
||||
face.receive(*makeDataWithSegment(1));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 3);
|
||||
|
||||
// check if segment 2's state is FirstTimeSent
|
||||
auto it = pipeline->m_segmentInfo.find(2);
|
||||
BOOST_REQUIRE(it != pipeline->m_segmentInfo.end());
|
||||
BOOST_CHECK(it->second.state == SegmentState::FirstTimeSent);
|
||||
|
||||
// timeout segment 2 twice
|
||||
advanceClocks(time::milliseconds(400), 3);
|
||||
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 5);
|
||||
|
||||
// check if segment 2's state is Retransmitted
|
||||
it = pipeline->m_segmentInfo.find(2);
|
||||
BOOST_REQUIRE(it != pipeline->m_segmentInfo.end());
|
||||
BOOST_CHECK(it->second.state == SegmentState::Retransmitted);
|
||||
|
||||
// check if segment 2 was retransmitted twice
|
||||
BOOST_CHECK_EQUAL(pipeline->m_retxCount.at(2), 2);
|
||||
|
||||
// receive segment 2 the first time
|
||||
face.receive(*makeDataWithSegment(2));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// check if segment 2 was erased from m_segmentInfo
|
||||
it = pipeline->m_segmentInfo.find(2);
|
||||
BOOST_CHECK(it == pipeline->m_segmentInfo.end());
|
||||
|
||||
auto prevRtt = rttEstimator.getAvgRtt();
|
||||
auto prevRto = rttEstimator.getEstimatedRto();
|
||||
|
||||
// receive segment 2 the second time
|
||||
face.receive(*makeDataWithSegment(2));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
// nothing changed
|
||||
it = pipeline->m_segmentInfo.find(2);
|
||||
BOOST_CHECK(it == pipeline->m_segmentInfo.end());
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 5);
|
||||
BOOST_CHECK_EQUAL(rttEstimator.getAvgRtt(), prevRtt);
|
||||
BOOST_CHECK_EQUAL(rttEstimator.getEstimatedRto(), prevRto);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(PrintSummaryWithNoRttMeasurements)
|
||||
{
|
||||
// test the console ouptut when no RTT measurement is available,
|
||||
// to make sure a proper message will be printed out
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
// change the underlying buffer and save the old buffer
|
||||
auto oldBuf = std::cerr.rdbuf(ss.rdbuf());
|
||||
|
||||
pipeline->printSummary();
|
||||
std::string line;
|
||||
|
||||
bool found = false;
|
||||
while (std::getline(ss, line)) {
|
||||
if (line == "RTT stats unavailable") {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BOOST_CHECK(found);
|
||||
std::cerr.rdbuf(oldBuf); // reset
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(StopsWhenFileSizeLessThanChunkSize)
|
||||
{
|
||||
// test to see if the program doesn't hang,
|
||||
// when transfer is complete, for files less than the chunk size
|
||||
// (i.e. when only one segment is sent/received)
|
||||
|
||||
createPipeline();
|
||||
nDataSegments = 1;
|
||||
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
face.receive(*makeDataWithSegment(0));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_hasFinalBlockId, true);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_segmentInfo.size(), 0);
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestPipelineInterestsCubic
|
||||
BOOST_AUTO_TEST_SUITE_END() // Chunks
|
||||
|
||||
} // namespace tests
|
||||
} // namespace chunks
|
||||
} // namespace ndn
|
||||
+90
-165
@@ -1,8 +1,8 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2016, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
/*
|
||||
* Copyright (c) 2016-2020, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
@@ -21,182 +21,107 @@
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Andrea Tosatto
|
||||
* @author Chavoosh Ghasemi
|
||||
*/
|
||||
|
||||
#include "tools/chunks/catchunks/pipeline-interests.hpp"
|
||||
#include "tools/chunks/catchunks/pipeline-interests-fixed.hpp"
|
||||
#include "tools/chunks/catchunks/data-fetcher.hpp"
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
#include "pipeline-interests-fixture.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace chunks {
|
||||
namespace tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
class PipelineInterestsFixture : public UnitTestTimeFixture
|
||||
class PipelineInterestFixedFixture : public PipelineInterestsFixture
|
||||
{
|
||||
public:
|
||||
typedef PipelineInterestsOptions Options;
|
||||
|
||||
public:
|
||||
PipelineInterestsFixture()
|
||||
: face(io)
|
||||
, opt(makeOptions())
|
||||
, name("/ndn/chunks/test")
|
||||
, pipeline(face, opt)
|
||||
, nDataSegments(0)
|
||||
, nReceivedSegments(0)
|
||||
, hasFailed(false)
|
||||
PipelineInterestFixedFixture()
|
||||
{
|
||||
opt.interestLifetime = 1_s;
|
||||
opt.maxRetriesOnTimeoutOrNack = 3;
|
||||
opt.isQuiet = true;
|
||||
opt.maxPipelineSize = 5;
|
||||
createPipeline();
|
||||
}
|
||||
|
||||
void
|
||||
createPipeline()
|
||||
{
|
||||
auto pline = make_unique<PipelineInterestsFixed>(face, opt);
|
||||
pipeline = pline.get();
|
||||
setPipeline(std::move(pline));
|
||||
}
|
||||
|
||||
protected:
|
||||
shared_ptr<Data>
|
||||
makeDataWithSegment(uint64_t segmentNo, bool setFinalBlockId = true)
|
||||
{
|
||||
auto data = make_shared<Data>(Name(name).appendVersion(0).appendSegment(segmentNo));
|
||||
if (setFinalBlockId)
|
||||
data->setFinalBlockId(name::Component::fromSegment(nDataSegments - 1));
|
||||
return signData(data);
|
||||
}
|
||||
|
||||
void
|
||||
runWithData(const Data& data)
|
||||
{
|
||||
pipeline.runWithExcludedSegment(data,
|
||||
bind(&PipelineInterestsFixture::onData, this, _1, _2),
|
||||
bind(&PipelineInterestsFixture::onFailure, this, _1));
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
onData(const Interest& interest, const Data& data)
|
||||
{
|
||||
nReceivedSegments++;
|
||||
}
|
||||
|
||||
void
|
||||
onFailure(const std::string& reason)
|
||||
{
|
||||
hasFailed = true;
|
||||
}
|
||||
|
||||
static Options
|
||||
makeOptions()
|
||||
{
|
||||
Options options;
|
||||
options.isVerbose = false;
|
||||
options.interestLifetime = time::seconds(1);
|
||||
options.maxRetriesOnTimeoutOrNack = 3;
|
||||
options.maxPipelineSize = 5;
|
||||
return options;
|
||||
}
|
||||
|
||||
protected:
|
||||
boost::asio::io_service io;
|
||||
util::DummyClientFace face;
|
||||
Options opt;
|
||||
Name name;
|
||||
PipelineInterests pipeline;
|
||||
uint64_t nDataSegments;
|
||||
uint64_t nReceivedSegments;
|
||||
bool hasFailed;
|
||||
PipelineInterestsFixed* pipeline;
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Chunks)
|
||||
BOOST_AUTO_TEST_SUITE(TestPipelineInterests)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestPipelineInterestsFixed, PipelineInterestFixedFixture)
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(FewerSegmentsThanPipelineCapacity, PipelineInterestsFixture)
|
||||
{
|
||||
nDataSegments = 3;
|
||||
BOOST_ASSERT(nDataSegments <= opt.maxPipelineSize);
|
||||
|
||||
runWithData(*makeDataWithSegment(0));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), nDataSegments - 1);
|
||||
|
||||
for (uint64_t i = 0; i < nDataSegments - 1; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
|
||||
BOOST_CHECK_EQUAL(nReceivedSegments, i);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), nDataSegments - 1);
|
||||
// check if the interest for the segment i+1 is well formed
|
||||
auto sentInterest = face.sentInterests[i];
|
||||
BOOST_CHECK_EQUAL(sentInterest.getExclude().size(), 0);
|
||||
BOOST_CHECK_EQUAL(sentInterest.getMaxSuffixComponents(), 1);
|
||||
BOOST_CHECK_EQUAL(sentInterest.getMustBeFresh(), opt.mustBeFresh);
|
||||
BOOST_CHECK_EQUAL(Name(name).isPrefixOf(sentInterest.getName()), true);
|
||||
BOOST_CHECK_EQUAL(sentInterest.getName()[-1].toSegment(), i + 1);
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
|
||||
advanceClocks(io, ndn::DEFAULT_INTEREST_LIFETIME, opt.maxRetriesOnTimeoutOrNack + 1);
|
||||
BOOST_CHECK_EQUAL(hasFailed, true);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(FullPipeline, PipelineInterestsFixture)
|
||||
BOOST_AUTO_TEST_CASE(FullPipeline)
|
||||
{
|
||||
nDataSegments = 13;
|
||||
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
|
||||
|
||||
runWithData(*makeDataWithSegment(nDataSegments - 1));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
|
||||
|
||||
for (uint64_t i = 0; i < nDataSegments - 1; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
BOOST_CHECK_EQUAL(nReceivedSegments, i + 1);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, i + 1);
|
||||
|
||||
if (i < nDataSegments - opt.maxPipelineSize - 1) {
|
||||
if (i < nDataSegments - opt.maxPipelineSize) {
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize + i + 1);
|
||||
// check if the interest for the segment i+1 is well formed
|
||||
auto sentInterest = face.sentInterests[i];
|
||||
BOOST_CHECK_EQUAL(sentInterest.getExclude().size(), 0);
|
||||
BOOST_CHECK_EQUAL(sentInterest.getMaxSuffixComponents(), 1);
|
||||
// check if the interest for the segment i is well formed
|
||||
const auto& sentInterest = face.sentInterests[i];
|
||||
BOOST_CHECK_EQUAL(sentInterest.getCanBePrefix(), false);
|
||||
BOOST_CHECK_EQUAL(sentInterest.getMustBeFresh(), opt.mustBeFresh);
|
||||
BOOST_CHECK_EQUAL(Name(name).isPrefixOf(sentInterest.getName()), true);
|
||||
BOOST_CHECK_EQUAL(sentInterest.getName()[-1].toSegment(), i);
|
||||
BOOST_CHECK_EQUAL(getSegmentFromPacket(sentInterest), i);
|
||||
}
|
||||
else {
|
||||
// all the interests have been sent for all the segments
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), nDataSegments - 1);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), nDataSegments);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
|
||||
advanceClocks(ndn::DEFAULT_INTEREST_LIFETIME, opt.maxRetriesOnTimeoutOrNack + 1);
|
||||
BOOST_CHECK_EQUAL(hasFailed, true);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(TimeoutAllSegments, PipelineInterestsFixture)
|
||||
BOOST_AUTO_TEST_CASE(TimeoutAllSegments)
|
||||
{
|
||||
nDataSegments = 13;
|
||||
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
|
||||
|
||||
runWithData(*makeDataWithSegment(nDataSegments - 1));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
|
||||
|
||||
for (int i = 0; i < opt.maxRetriesOnTimeoutOrNack; ++i) {
|
||||
advanceClocks(io, opt.interestLifetime, 1);
|
||||
advanceClocks(opt.interestLifetime);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * (i + 2));
|
||||
BOOST_CHECK_EQUAL(nReceivedSegments, 0);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 0);
|
||||
|
||||
// A single retry for every pipeline element
|
||||
for (size_t j = 0; j < opt.maxPipelineSize; ++j) {
|
||||
auto interest = face.sentInterests[(opt.maxPipelineSize * (i + 1)) + j];
|
||||
BOOST_CHECK_EQUAL(static_cast<size_t>(interest.getName()[-1].toSegment()), j);
|
||||
const auto& interest = face.sentInterests[(opt.maxPipelineSize * (i + 1)) + j];
|
||||
BOOST_CHECK_EQUAL(static_cast<size_t>(getSegmentFromPacket(interest)), j);
|
||||
}
|
||||
}
|
||||
|
||||
advanceClocks(io, opt.interestLifetime, 1);
|
||||
advanceClocks(opt.interestLifetime);
|
||||
BOOST_CHECK_EQUAL(hasFailed, true);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(TimeoutAfterFinalBlockIdReceived, PipelineInterestsFixture)
|
||||
BOOST_AUTO_TEST_CASE(TimeoutAfterFinalBlockIdReceived)
|
||||
{
|
||||
// the FinalBlockId is sent with the first segment, after the first segment failure the pipeline
|
||||
// should fail
|
||||
@@ -204,24 +129,24 @@ BOOST_FIXTURE_TEST_CASE(TimeoutAfterFinalBlockIdReceived, PipelineInterestsFixtu
|
||||
nDataSegments = 18;
|
||||
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
|
||||
|
||||
runWithData(*makeDataWithSegment(nDataSegments - 1));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
|
||||
|
||||
// send a single segment for each pipeline element but not the first element
|
||||
advanceClocks(io, opt.interestLifetime, 1);
|
||||
advanceClocks(opt.interestLifetime);
|
||||
for (uint64_t i = 1; i < opt.maxPipelineSize; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
|
||||
// send a single data packet for each pipeline element
|
||||
advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack - 1);
|
||||
for (uint64_t i = 0; i < opt.maxPipelineSize - 1; ++i) {
|
||||
advanceClocks(opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack - 1);
|
||||
for (uint64_t i = 0; i < opt.maxPipelineSize; ++i) {
|
||||
face.receive(*makeDataWithSegment(opt.maxPipelineSize + i));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
advanceClocks(io, opt.interestLifetime, 1);
|
||||
advanceClocks(opt.interestLifetime);
|
||||
|
||||
size_t interestAfterFailure = face.sentInterests.size();
|
||||
|
||||
@@ -229,19 +154,19 @@ BOOST_FIXTURE_TEST_CASE(TimeoutAfterFinalBlockIdReceived, PipelineInterestsFixtu
|
||||
BOOST_CHECK_EQUAL(hasFailed, true);
|
||||
|
||||
// these new segments should not generate new interests
|
||||
advanceClocks(io, opt.interestLifetime, 1);
|
||||
for (uint64_t i = 0; i < opt.maxPipelineSize - 1; ++i) {
|
||||
advanceClocks(opt.interestLifetime);
|
||||
for (uint64_t i = 0; i < opt.maxPipelineSize; ++i) {
|
||||
face.receive(*makeDataWithSegment(opt.maxPipelineSize * 2 + i - 1));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
|
||||
// no more interests after a failure
|
||||
advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack);
|
||||
advanceClocks(opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack);
|
||||
BOOST_CHECK_EQUAL(interestAfterFailure, face.sentInterests.size());
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(TimeoutBeforeFinalBlockIdReceived, PipelineInterestsFixture)
|
||||
BOOST_AUTO_TEST_CASE(TimeoutBeforeFinalBlockIdReceived)
|
||||
{
|
||||
// the FinalBlockId is sent only with the last segment, all segments are sent except for the
|
||||
// second one (segment #1); all segments are received correctly until the FinalBlockId is received
|
||||
@@ -249,17 +174,17 @@ BOOST_FIXTURE_TEST_CASE(TimeoutBeforeFinalBlockIdReceived, PipelineInterestsFixt
|
||||
nDataSegments = 22;
|
||||
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
|
||||
|
||||
runWithData(*makeDataWithSegment(nDataSegments - 1, false));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
|
||||
|
||||
advanceClocks(io, opt.interestLifetime, 1);
|
||||
advanceClocks(opt.interestLifetime);
|
||||
for (uint64_t i = 2; i < opt.maxPipelineSize; ++i) {
|
||||
face.receive(*makeDataWithSegment(i, false));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
auto lastInterest = face.sentInterests.back();
|
||||
BOOST_CHECK_EQUAL(lastInterest.getName()[-1].toSegment(), opt.maxPipelineSize + i - 2);
|
||||
const auto& lastInterest = face.sentInterests.back();
|
||||
BOOST_CHECK_EQUAL(getSegmentFromPacket(lastInterest), opt.maxPipelineSize + i - 2);
|
||||
}
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * 3 - 2);
|
||||
|
||||
@@ -270,7 +195,7 @@ BOOST_FIXTURE_TEST_CASE(TimeoutBeforeFinalBlockIdReceived, PipelineInterestsFixt
|
||||
|
||||
// all the pipeline elements are two retries near the timeout error, but not the
|
||||
// second (segment #1) that is only one retry near the timeout
|
||||
advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack - 1);
|
||||
advanceClocks(opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack - 1);
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
|
||||
// data for the first pipeline element (segment #0)
|
||||
@@ -278,23 +203,23 @@ BOOST_FIXTURE_TEST_CASE(TimeoutBeforeFinalBlockIdReceived, PipelineInterestsFixt
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
|
||||
// data for all the pipeline element, but not the second (segment #1)
|
||||
for (uint64_t i = opt.maxPipelineSize; i < nDataSegments - 1; ++i) {
|
||||
if (i == nDataSegments - 2) {
|
||||
for (uint64_t i = opt.maxPipelineSize; i < nDataSegments; ++i) {
|
||||
if (i == nDataSegments - 1) {
|
||||
face.receive(*makeDataWithSegment(i, true));
|
||||
}
|
||||
else {
|
||||
face.receive(*makeDataWithSegment(i, false));
|
||||
}
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
// timeout for the second pipeline element (segment #1), this should trigger an error
|
||||
advanceClocks(io, opt.interestLifetime, 1);
|
||||
advanceClocks(opt.interestLifetime);
|
||||
|
||||
BOOST_CHECK_EQUAL(nReceivedSegments, nDataSegments - 2);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, nDataSegments - 1);
|
||||
BOOST_CHECK_EQUAL(hasFailed, true);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(SegmentReceivedAfterTimeout, PipelineInterestsFixture)
|
||||
BOOST_AUTO_TEST_CASE(SegmentReceivedAfterTimeout)
|
||||
{
|
||||
// the FinalBlockId is never sent, all the pipeline elements with a segment number greater than
|
||||
// segment #0 will fail, after this failure also segment #0 fail and this should trigger an error
|
||||
@@ -302,11 +227,11 @@ BOOST_FIXTURE_TEST_CASE(SegmentReceivedAfterTimeout, PipelineInterestsFixture)
|
||||
nDataSegments = 22;
|
||||
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
|
||||
|
||||
runWithData(*makeDataWithSegment(nDataSegments - 1, false));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
|
||||
|
||||
advanceClocks(io, opt.interestLifetime, 1);
|
||||
advanceClocks(opt.interestLifetime);
|
||||
|
||||
// nack for the first pipeline element (segment #0)
|
||||
auto nack = make_shared<lp::Nack>(face.sentInterests[opt.maxPipelineSize]);
|
||||
@@ -315,33 +240,33 @@ BOOST_FIXTURE_TEST_CASE(SegmentReceivedAfterTimeout, PipelineInterestsFixture)
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
|
||||
// timeout for all the pipeline elements, but not the first (segment #0)
|
||||
advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack);
|
||||
advanceClocks(opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack);
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
|
||||
// data for the first pipeline element (segment #0), this should trigger an error because the
|
||||
// others pipeline elements failed
|
||||
// other pipeline elements failed
|
||||
face.receive(*makeDataWithSegment(0, false));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(nReceivedSegments, 1);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 1);
|
||||
BOOST_CHECK_EQUAL(hasFailed, true);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(CongestionAllSegments, PipelineInterestsFixture)
|
||||
BOOST_AUTO_TEST_CASE(CongestionAllSegments)
|
||||
{
|
||||
nDataSegments = 13;
|
||||
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
|
||||
|
||||
runWithData(*makeDataWithSegment(nDataSegments - 1));
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
|
||||
|
||||
// send nack for all the pipeline elements first interest
|
||||
for (size_t j = 0; j < opt.maxPipelineSize; j++) {
|
||||
auto nack = make_shared<lp::Nack>(face.sentInterests[j]);
|
||||
for (size_t i = 0; i < opt.maxPipelineSize; i++) {
|
||||
auto nack = make_shared<lp::Nack>(face.sentInterests[i]);
|
||||
nack->setReason(lp::NackReason::CONGESTION);
|
||||
face.receive(*nack);
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
|
||||
// send nack for all the pipeline elements interests after the first
|
||||
@@ -350,20 +275,20 @@ BOOST_FIXTURE_TEST_CASE(CongestionAllSegments, PipelineInterestsFixture)
|
||||
if (backoffTime > DataFetcher::MAX_CONGESTION_BACKOFF_TIME)
|
||||
backoffTime = DataFetcher::MAX_CONGESTION_BACKOFF_TIME;
|
||||
|
||||
advanceClocks(io, backoffTime, 1);
|
||||
advanceClocks(backoffTime);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * (i +1));
|
||||
|
||||
// A single retry for every pipeline element
|
||||
for (size_t j = 0; j < opt.maxPipelineSize; ++j) {
|
||||
auto interest = face.sentInterests[(opt.maxPipelineSize * i) + j];
|
||||
BOOST_CHECK_LT(static_cast<size_t>(interest.getName()[-1].toSegment()), opt.maxPipelineSize);
|
||||
const auto& interest = face.sentInterests[(opt.maxPipelineSize * i) + j];
|
||||
BOOST_CHECK_LT(static_cast<size_t>(getSegmentFromPacket(interest)), opt.maxPipelineSize);
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < opt.maxPipelineSize; j++) {
|
||||
auto nack = make_shared<lp::Nack>(face.sentInterests[(opt.maxPipelineSize * i) + j]);
|
||||
nack->setReason(lp::NackReason::CONGESTION);
|
||||
face.receive(*nack);
|
||||
advanceClocks(io, time::nanoseconds(1), 1);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2016-2020, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Andrea Tosatto
|
||||
* @author Davide Pesavento
|
||||
* @author Weiwei Liu
|
||||
* @author Chavoosh Ghasemi
|
||||
*/
|
||||
|
||||
#ifndef NDN_TOOLS_TESTS_CHUNKS_PIPELINE_INTERESTS_FIXTURE_HPP
|
||||
#define NDN_TOOLS_TESTS_CHUNKS_PIPELINE_INTERESTS_FIXTURE_HPP
|
||||
|
||||
#include "tools/chunks/catchunks/pipeline-interests.hpp"
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include "tests/io-fixture.hpp"
|
||||
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
namespace ndn {
|
||||
namespace chunks {
|
||||
namespace tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
class PipelineInterestsFixture : public IoFixture
|
||||
{
|
||||
protected:
|
||||
void
|
||||
setPipeline(unique_ptr<PipelineInterests> pline)
|
||||
{
|
||||
m_pipeline = std::move(pline);
|
||||
}
|
||||
|
||||
shared_ptr<Data>
|
||||
makeDataWithSegment(uint64_t segmentNo, bool setFinalBlockId = true) const
|
||||
{
|
||||
auto data = make_shared<Data>(Name(name).appendVersion(0).appendSegment(segmentNo));
|
||||
if (setFinalBlockId)
|
||||
data->setFinalBlock(name::Component::fromSegment(nDataSegments - 1));
|
||||
return signData(data);
|
||||
}
|
||||
|
||||
shared_ptr<Data>
|
||||
makeDataWithSegmentAndCongMark(uint64_t segmentNo,
|
||||
uint64_t congestionMark = 1,
|
||||
bool setFinalBlockId = true) const
|
||||
{
|
||||
auto data = makeDataWithSegment(segmentNo, setFinalBlockId);
|
||||
data->setCongestionMark(congestionMark);
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
run(const Name& name, uint64_t version = 0)
|
||||
{
|
||||
m_pipeline->run(Name(name).appendVersion(version),
|
||||
[] (const Data&) {},
|
||||
[this] (const std::string&) { hasFailed = true; });
|
||||
}
|
||||
|
||||
protected:
|
||||
util::DummyClientFace face{m_io};
|
||||
Name name{"/ndn/chunks/test"};
|
||||
uint64_t nDataSegments = 0;
|
||||
bool hasFailed = false;
|
||||
|
||||
private:
|
||||
unique_ptr<PipelineInterests> m_pipeline;
|
||||
};
|
||||
|
||||
} // namespace tests
|
||||
} // namespace chunks
|
||||
} // namespace ndn
|
||||
|
||||
#endif // NDN_TOOLS_TESTS_CHUNKS_PIPELINE_INTERESTS_FIXTURE_HPP
|
||||
+94
-100
@@ -1,8 +1,8 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2016, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
/*
|
||||
* Copyright (c) 2016-2021, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
@@ -26,10 +26,16 @@
|
||||
#include "tools/chunks/putchunks/producer.hpp"
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include "tests/io-fixture.hpp"
|
||||
#include "tests/key-chain-fixture.hpp"
|
||||
|
||||
#include <ndn-cxx/metadata-object.hpp>
|
||||
#include <ndn-cxx/security/pib/identity.hpp>
|
||||
#include <ndn-cxx/security/pib/key.hpp>
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
#include <ndn-cxx/security/validator-null.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
|
||||
namespace ndn {
|
||||
namespace chunks {
|
||||
@@ -37,17 +43,34 @@ namespace tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
class ProducerFixture : public IoFixture, public KeyChainFixture
|
||||
{
|
||||
protected:
|
||||
ProducerFixture()
|
||||
{
|
||||
options.maxSegmentSize = 40;
|
||||
options.isQuiet = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
util::DummyClientFace face{m_io, {true, true}};
|
||||
Name prefix = "/ndn/chunks/test";
|
||||
Producer::Options options;
|
||||
uint64_t version = 1449227841747;
|
||||
Name keyLocatorName = m_keyChain.createIdentity("/ProducerFixture").getDefaultKey().getName();
|
||||
std::istringstream testString{
|
||||
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget "
|
||||
"dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, "
|
||||
"nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, "
|
||||
"sem. Nulla consequat massa Donec pede justo,"s};
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Chunks)
|
||||
BOOST_AUTO_TEST_SUITE(TestProducer)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestProducer, ProducerFixture)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(InputData)
|
||||
{
|
||||
util::DummyClientFace face;
|
||||
KeyChain keyChain;
|
||||
security::SigningInfo signingInfo;
|
||||
Name prefix("/ndn/chunks/test");
|
||||
int maxSegmentSize = 40;
|
||||
std::vector<std::string> testStrings {
|
||||
std::vector<std::string> testStrings{
|
||||
"",
|
||||
|
||||
"a1b2c3%^&(#$&%^$$/><",
|
||||
@@ -61,14 +84,14 @@ BOOST_AUTO_TEST_CASE(InputData)
|
||||
"consequat massa Donec pede justo,"
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < testStrings.size(); ++i) {
|
||||
std::istringstream str(testStrings[i]);
|
||||
Producer prod(prefix, face, keyChain, signingInfo, time::seconds(4), maxSegmentSize, false,
|
||||
false, str);
|
||||
for (size_t i = 0; i < testStrings.size(); ++i) {
|
||||
std::istringstream input(testStrings[i]);
|
||||
Producer prod(prefix, face, m_keyChain, input, options);
|
||||
|
||||
size_t expectedSize = std::ceil(static_cast<double>(testStrings[i].size()) / maxSegmentSize);
|
||||
if (testStrings[i].size() == 0)
|
||||
size_t expectedSize = std::ceil(static_cast<double>(testStrings[i].size()) / options.maxSegmentSize);
|
||||
if (testStrings[i].empty()) {
|
||||
expectedSize = 1;
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(prod.m_store.size(), expectedSize);
|
||||
}
|
||||
@@ -76,82 +99,45 @@ BOOST_AUTO_TEST_CASE(InputData)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(RequestSegmentUnspecifiedVersion)
|
||||
{
|
||||
boost::asio::io_service io;
|
||||
util::DummyClientFace face(io, {true, true});
|
||||
KeyChain keyChain;
|
||||
security::SigningInfo signingInfo;
|
||||
Name prefix("/ndn/chunks/test");
|
||||
time::milliseconds freshnessPeriod(time::seconds(10));
|
||||
size_t maxSegmentSize(40);
|
||||
std::istringstream testString(std::string(
|
||||
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget "
|
||||
"dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, "
|
||||
"nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, "
|
||||
"sem. Nulla consequat massa Donec pede justo,"));
|
||||
|
||||
Name keyLocatorName = keyChain.getDefaultCertificateName().getPrefix(-1);
|
||||
|
||||
Producer producer(prefix, face, keyChain, signingInfo, freshnessPeriod, maxSegmentSize,
|
||||
false, false, testString);
|
||||
io.poll();
|
||||
|
||||
size_t nSegments = std::ceil(static_cast<double>(testString.str().size()) / maxSegmentSize);
|
||||
Producer producer(prefix, face, m_keyChain, testString, options);
|
||||
m_io.poll();
|
||||
size_t nSegments = std::ceil(static_cast<double>(testString.str().size()) / options.maxSegmentSize);
|
||||
|
||||
// version request
|
||||
face.receive(*makeInterest(prefix));
|
||||
face.receive(*makeInterest(prefix, true));
|
||||
face.processEvents();
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
|
||||
auto lastData = face.sentData.back();
|
||||
BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 2);
|
||||
BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), 0);
|
||||
BOOST_REQUIRE(!lastData.getFinalBlockId().empty());
|
||||
BOOST_CHECK_EQUAL(lastData.getFinalBlockId().toSegment(), nSegments - 1);
|
||||
BOOST_CHECK_EQUAL(lastData.getSignature().getKeyLocator().getName(), keyLocatorName);
|
||||
BOOST_CHECK_EQUAL(lastData.getFinalBlock().value().toSegment(), nSegments - 1);
|
||||
BOOST_CHECK_EQUAL(lastData.getKeyLocator().value().getName(), keyLocatorName);
|
||||
|
||||
// segment request
|
||||
Name nameWithVersion(prefix);
|
||||
nameWithVersion.append(lastData.getName()[-2]);
|
||||
size_t requestSegmentNo = 1;
|
||||
|
||||
face.receive(*makeInterest(nameWithVersion.appendSegment(requestSegmentNo)));
|
||||
face.receive(*makeInterest(nameWithVersion.appendSegment(requestSegmentNo), true));
|
||||
face.processEvents();
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentData.size(), 2);
|
||||
lastData = face.sentData.back();
|
||||
BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 2);
|
||||
BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), requestSegmentNo);
|
||||
BOOST_REQUIRE(!lastData.getFinalBlockId().empty());
|
||||
BOOST_CHECK_EQUAL(lastData.getFinalBlockId().toSegment(), nSegments - 1);
|
||||
BOOST_CHECK_EQUAL(lastData.getSignature().getKeyLocator().getName(), keyLocatorName);
|
||||
BOOST_CHECK_EQUAL(lastData.getFinalBlock().value().toSegment(), nSegments - 1);
|
||||
BOOST_CHECK_EQUAL(lastData.getKeyLocator().value().getName(), keyLocatorName);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(RequestSegmentSpecifiedVersion)
|
||||
{
|
||||
boost::asio::io_service io;
|
||||
util::DummyClientFace face(io, {true, true});
|
||||
KeyChain keyChain;
|
||||
security::SigningInfo signingInfo;
|
||||
Name prefix("/ndn/chunks/test");
|
||||
time::milliseconds freshnessPeriod(time::seconds(10));
|
||||
size_t maxSegmentSize(40);
|
||||
std::istringstream testString(std::string(
|
||||
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget "
|
||||
"dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, "
|
||||
"nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, "
|
||||
"sem. Nulla consequat massa Donec pede justo,"));
|
||||
|
||||
uint64_t version = 1449227841747;
|
||||
Name keyLocatorName = keyChain.getDefaultCertificateName().getPrefix(-1);
|
||||
|
||||
Producer producer(prefix.appendVersion(version), face, keyChain, signingInfo, freshnessPeriod,
|
||||
maxSegmentSize, false, false, testString);
|
||||
io.poll();
|
||||
|
||||
size_t nSegments = std::ceil(static_cast<double>(testString.str().size()) / maxSegmentSize);
|
||||
Producer producer(prefix.appendVersion(version), face, m_keyChain, testString, options);
|
||||
m_io.poll();
|
||||
size_t nSegments = std::ceil(static_cast<double>(testString.str().size()) / options.maxSegmentSize);
|
||||
|
||||
// version request
|
||||
face.receive(*makeInterest(prefix));
|
||||
face.receive(*makeInterest(prefix, true));
|
||||
face.processEvents();
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
|
||||
@@ -159,15 +145,14 @@ BOOST_AUTO_TEST_CASE(RequestSegmentSpecifiedVersion)
|
||||
BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 1);
|
||||
BOOST_CHECK_EQUAL(lastData.getName()[-2].toVersion(), version);
|
||||
BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), 0);
|
||||
BOOST_REQUIRE(!lastData.getFinalBlockId().empty());
|
||||
BOOST_CHECK_EQUAL(lastData.getFinalBlockId().toSegment(), nSegments - 1);
|
||||
BOOST_CHECK_EQUAL(lastData.getSignature().getKeyLocator().getName(), keyLocatorName);
|
||||
BOOST_CHECK_EQUAL(lastData.getFinalBlock().value().toSegment(), nSegments - 1);
|
||||
BOOST_CHECK_EQUAL(lastData.getKeyLocator().value().getName(), keyLocatorName);
|
||||
|
||||
// segment request
|
||||
Name nameWithVersion(prefix);
|
||||
size_t requestSegmentNo = 1;
|
||||
|
||||
face.receive(*makeInterest(nameWithVersion.appendSegment(requestSegmentNo)));
|
||||
face.receive(*makeInterest(nameWithVersion.appendSegment(requestSegmentNo), true));
|
||||
face.processEvents();
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentData.size(), 2);
|
||||
@@ -175,56 +160,65 @@ BOOST_AUTO_TEST_CASE(RequestSegmentSpecifiedVersion)
|
||||
BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 1);
|
||||
BOOST_CHECK_EQUAL(lastData.getName()[-2].toVersion(), version);
|
||||
BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), requestSegmentNo);
|
||||
BOOST_REQUIRE(!lastData.getFinalBlockId().empty());
|
||||
BOOST_CHECK_EQUAL(lastData.getFinalBlockId().toSegment(), nSegments - 1);
|
||||
BOOST_CHECK_EQUAL(lastData.getSignature().getKeyLocator().getName(), keyLocatorName);
|
||||
BOOST_CHECK_EQUAL(lastData.getFinalBlock().value().toSegment(), nSegments - 1);
|
||||
BOOST_CHECK_EQUAL(lastData.getKeyLocator().value().getName(), keyLocatorName);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(RequestNotExistingSegment)
|
||||
{
|
||||
boost::asio::io_service io;
|
||||
util::DummyClientFace face(io, {true, true});
|
||||
KeyChain keyChain;
|
||||
security::SigningInfo signingInfo;
|
||||
Name prefix("/ndn/chunks/test");
|
||||
time::milliseconds freshnessPeriod(time::seconds(10));
|
||||
size_t maxSegmentSize(40);
|
||||
std::istringstream testString(std::string(
|
||||
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget "
|
||||
"dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, "
|
||||
"nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, "
|
||||
"sem. Nulla consequat massa Donec pede justo,"));
|
||||
|
||||
Name keyLocatorName = keyChain.getDefaultCertificateName().getPrefix(-1);
|
||||
|
||||
Producer producer(prefix, face, keyChain, signingInfo, freshnessPeriod, maxSegmentSize,
|
||||
false, false, testString);
|
||||
io.poll();
|
||||
|
||||
size_t nSegments = std::ceil(static_cast<double>(testString.str().size()) / maxSegmentSize);
|
||||
Producer producer(prefix, face, m_keyChain, testString, options);
|
||||
m_io.poll();
|
||||
size_t nSegments = std::ceil(static_cast<double>(testString.str().size()) / options.maxSegmentSize);
|
||||
|
||||
// version request
|
||||
face.receive(*makeInterest(prefix));
|
||||
face.receive(*makeInterest(prefix, true));
|
||||
face.processEvents();
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
|
||||
auto lastData = face.sentData.back();
|
||||
BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 2);
|
||||
BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), 0);
|
||||
BOOST_REQUIRE(!lastData.getFinalBlockId().empty());
|
||||
BOOST_CHECK_EQUAL(lastData.getFinalBlockId().toSegment(), nSegments - 1);
|
||||
BOOST_CHECK_EQUAL(lastData.getSignature().getKeyLocator().getName(), keyLocatorName);
|
||||
BOOST_CHECK_EQUAL(lastData.getFinalBlock().value().toSegment(), nSegments - 1);
|
||||
BOOST_CHECK_EQUAL(lastData.getKeyLocator().value().getName(), keyLocatorName);
|
||||
|
||||
// segment request
|
||||
Name nameWithVersion(prefix);
|
||||
nameWithVersion.append(lastData.getName()[-2]);
|
||||
face.receive(*makeInterest(nameWithVersion.appendSegment(nSegments)));
|
||||
face.receive(*makeInterest(nameWithVersion.appendSegment(nSegments), true));
|
||||
face.processEvents();
|
||||
|
||||
// no new data
|
||||
BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(RequestMetadata)
|
||||
{
|
||||
Producer producer(prefix.appendVersion(version), face, m_keyChain, testString, options);
|
||||
m_io.poll();
|
||||
|
||||
// ask for metadata with a valid discovery interest
|
||||
face.receive(MetadataObject::makeDiscoveryInterest(Name(prefix).getPrefix(-1)));
|
||||
face.processEvents();
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
|
||||
auto lastData = face.sentData.back();
|
||||
|
||||
// check the name of metadata packet
|
||||
BOOST_CHECK(MetadataObject::isValidName(lastData.getName()));
|
||||
|
||||
// make metadata object from metadata packet
|
||||
MetadataObject mobject(lastData);
|
||||
BOOST_CHECK_EQUAL(mobject.getVersionedName(), prefix);
|
||||
|
||||
// ask for metadata with an invalid discovery interest
|
||||
face.receive(MetadataObject::makeDiscoveryInterest(Name(prefix).getPrefix(-1))
|
||||
.setCanBePrefix(false));
|
||||
face.processEvents();
|
||||
|
||||
// we expect Nack in response to a discovery interest without CanBePrefix
|
||||
BOOST_CHECK_EQUAL(face.sentNacks.size(), 1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestProducer
|
||||
BOOST_AUTO_TEST_SUITE_END() // Chunks
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2020, 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-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tests/clock-fixture.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace tests {
|
||||
|
||||
ClockFixture::ClockFixture()
|
||||
: m_steadyClock(make_shared<time::UnitTestSteadyClock>())
|
||||
, m_systemClock(make_shared<time::UnitTestSystemClock>())
|
||||
{
|
||||
time::setCustomClocks(m_steadyClock, m_systemClock);
|
||||
}
|
||||
|
||||
ClockFixture::~ClockFixture()
|
||||
{
|
||||
time::setCustomClocks(nullptr, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
ClockFixture::advanceClocks(time::nanoseconds tick, time::nanoseconds total)
|
||||
{
|
||||
BOOST_ASSERT(tick > time::nanoseconds::zero());
|
||||
BOOST_ASSERT(total >= time::nanoseconds::zero());
|
||||
|
||||
while (total > time::nanoseconds::zero()) {
|
||||
auto t = std::min(tick, total);
|
||||
m_steadyClock->advance(t);
|
||||
m_systemClock->advance(t);
|
||||
total -= t;
|
||||
|
||||
afterTick();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace tests
|
||||
} // namespace ndn
|
||||
@@ -0,0 +1,89 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2020, 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-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NDN_TOOLS_TESTS_CLOCK_FIXTURE_HPP
|
||||
#define NDN_TOOLS_TESTS_CLOCK_FIXTURE_HPP
|
||||
|
||||
#include <ndn-cxx/util/time-unit-test-clock.hpp>
|
||||
|
||||
namespace ndn {
|
||||
namespace tests {
|
||||
|
||||
/** \brief A test fixture that overrides steady clock and system clock.
|
||||
*/
|
||||
class ClockFixture
|
||||
{
|
||||
public:
|
||||
virtual
|
||||
~ClockFixture();
|
||||
|
||||
/** \brief Advance steady and system clocks.
|
||||
*
|
||||
* Clocks are advanced in increments of \p tick for \p nTicks ticks.
|
||||
* afterTick() is called after each tick.
|
||||
*
|
||||
* Exceptions thrown during I/O events are propagated to the caller.
|
||||
* Clock advancement will stop in the event of an exception.
|
||||
*/
|
||||
void
|
||||
advanceClocks(time::nanoseconds tick, size_t nTicks = 1)
|
||||
{
|
||||
advanceClocks(tick, tick * nTicks);
|
||||
}
|
||||
|
||||
/** \brief Advance steady and system clocks.
|
||||
*
|
||||
* Clocks are advanced in increments of \p tick for \p total time.
|
||||
* The last increment might be shorter than \p tick.
|
||||
* afterTick() is called after each tick.
|
||||
*
|
||||
* Exceptions thrown during I/O events are propagated to the caller.
|
||||
* Clock advancement will stop in the event of an exception.
|
||||
*/
|
||||
void
|
||||
advanceClocks(time::nanoseconds tick, time::nanoseconds total);
|
||||
|
||||
protected:
|
||||
ClockFixture();
|
||||
|
||||
private:
|
||||
/** \brief Called by advanceClocks() after each clock advancement (tick).
|
||||
*
|
||||
* The base class implementation is a no-op.
|
||||
*/
|
||||
virtual void
|
||||
afterTick()
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
shared_ptr<time::UnitTestSteadyClock> m_steadyClock;
|
||||
shared_ptr<time::UnitTestSystemClock> m_systemClock;
|
||||
};
|
||||
|
||||
} // namespace tests
|
||||
} // namespace ndn
|
||||
|
||||
#endif // NDN_TOOLS_TESTS_CLOCK_FIXTURE_HPP
|
||||
@@ -25,6 +25,8 @@ Expected result of the dissection:
|
||||
|
||||
- NDN interests are dissected from packets 1, 2, 3, and 8.
|
||||
- NDN data packet is dissected from defragmented packets 4, 5, 6, and 7.
|
||||
- In packet 1, the "Info" column of Wireshark shows: `Interest /ndn/broadcast/ndnrtc-chatrooms/2366d310b15ba97a62c8734d4a760174f78d14446be3d70a54ee80d3ed19c83b`
|
||||
- In packet 7, the "Info" column of Wireshark shows: `Data /example/testApp/1/testApp/%FD%00%00%01O%23E%07%ED`
|
||||
|
||||
### 2. IPv6 UDP
|
||||
|
||||
@@ -105,3 +107,94 @@ Trace summary: Short capture, containing an NDN interest multicasted directly in
|
||||
|
||||
Expected result of the dissection:
|
||||
- interest packet is dissected from packet 6.
|
||||
|
||||
### 8. tvb Overflow
|
||||
|
||||
Trace file: `bug3603.pcap`
|
||||
|
||||
Trace summary: A Data whose payload could be read as incomplete TLV and may cause tvb overflow
|
||||
if parser does not check packet length.
|
||||
|
||||
Expected result of the dissection:
|
||||
- data packet is dissected at packet 12 without Lua error.
|
||||
|
||||
### 9. NDNLPv2
|
||||
|
||||
Trace file: `ndnlpv2.pcap`
|
||||
|
||||
Trace summary: Handcrafted NDNLPv2 packets.
|
||||
(`xxd -p -r < ndnlpv2.hex > ndnlpv2.pcap`).
|
||||
|
||||
Expected result of the dissection: 12 "Ethernet (NDN)" frames.
|
||||
1. LpPacket contains 12 unrecognized fields. The 10th and 12th fields are labelled "ignored".
|
||||
2. No special requirements.
|
||||
3. "Sequence: 12732154106453800448". "FragIndex: 0". "FragCount: 2". Fragment exists.
|
||||
4. "Sequence: 12732154106453800449". "FragIndex: 1". "FragCount: 2". Fragment exists.
|
||||
5. "NackReason: Congestion". The "Info" column shows "Nack /A".
|
||||
6. "NackReason: Duplicate".
|
||||
7. "NackReason: NoRoute".
|
||||
8. "NackReason: 1".
|
||||
9. Nack exists, but NackReason does not exist.
|
||||
10. "PitToken: 15047039637272254167".
|
||||
11. "CongestionMark: 1". "TxSequence: 16204482402681480935".
|
||||
12. There are eight Ack fields. First is "Ack: 16204482402681480704". Eighth is "Ack: 16204482402681480711".
|
||||
|
||||
### 10. NDNLPv2 (random)
|
||||
|
||||
Trace file: `ndnlpv2-more.pcap`
|
||||
|
||||
Trace summary: Short capture of randomly generated NDNLPv2 packets (see
|
||||
https://gist.github.com/cawka/fcdde58cc4dc94d789025ab8300076dc) with multiple fields set to various
|
||||
values. Given the random generation, some fields are semantically meaningless.
|
||||
|
||||
Expected results of the dissection:
|
||||
- 10 NDN (NDNLPv2) packets extracted from the reassembled TCP stream
|
||||
- the dissection results include Fragment (Interest/Data), Sequence (number), FragIndex (number),
|
||||
FragCount (number), Nack (various reasons), NextHopFaceId, IncomingFaceId, CachingPolicy, and
|
||||
unknown fields
|
||||
|
||||
### 11. NDN Packet Format v0.3
|
||||
|
||||
Trace file: `packet03.pcap`
|
||||
|
||||
Trace summary: Handcrafted packets in NDN Packet Format v0.3
|
||||
(`xxd -p -r < packet03.hex > packet03.pcap`).
|
||||
All packets are valid and do not contain unrecognized TLV elements.
|
||||
|
||||
Expected results of the dissection:
|
||||
- Packet 1 is recognized as "Interest" and contains `CanBePrefix: Yes`, `MustBeFresh: Yes`,
|
||||
`HopLimit: 214`, as well as a "ForwardingHint" and an "ApplicationParameters" field.
|
||||
- Packet 2 is recognized as "Interest" and has `Name: /params-sha256=41/7=B/C/252=D/256=E/65535=E/sha256digest=ee357c5791dcaa4494d9b301047b875d8833caa76dada3e95837bbc3eaf7b300`.
|
||||
- Packet 3 is recognized as "Data" and has `Name: /`.
|
||||
|
||||
### 12. URI Scheme
|
||||
|
||||
Trace file: `nameuri.pcap`
|
||||
|
||||
Trace summary: Handcrafted packet for testing URI encoding in Name and FinalBlockId
|
||||
(`xxd -p -r < nameuri.hex > nameuri.pcap`).
|
||||
|
||||
Expected results of the dissection:
|
||||
- Packet 1 is recognized as "Data".
|
||||
- Its name has eight components.
|
||||
- First name component is `NameComponent: ...`.
|
||||
- Second name component is `NameComponent: ....`.
|
||||
- Third name component is `NameComponent: .....`.
|
||||
- Fourth name component is `NameComponent: .A`.
|
||||
- Fifth name component is `NameComponent: %00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F`.
|
||||
Notice that digits, HYPHEN (`-`), and PERIOD (`.`) are not percent-encoded.
|
||||
- Sixth name component is `NameComponent: %40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~%7F`.
|
||||
Notice that upper case letters, lower case letters, UNDERSCORE (`_`), and TILDE (`~`) are not percent-encoded.
|
||||
- Seventh name component is `NameComponent: %80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF`.
|
||||
- Eighth name component is `NameComponent: %C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF`.
|
||||
- FinalBlockId and its nested NameComponent are both `%02`.
|
||||
|
||||
### 13. PPP
|
||||
|
||||
Trace file: `ppp.pcap`
|
||||
|
||||
Trace summary: 8 packets created in a simple ndnSIM scenario
|
||||
|
||||
Expected results of the dissection:
|
||||
- 4 interests (packets 1, 2, 5, 6), each carried in an LpPacket fragment
|
||||
- 4 data packets (packets 3, 4, 7, 8), also each carried in an LpPacket fragment
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,41 @@
|
||||
A1B2C3D4
|
||||
00020004
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
00000001
|
||||
|
||||
# packet 1
|
||||
00000000
|
||||
00000000
|
||||
00000159
|
||||
00000159
|
||||
|
||||
01005E0017AA
|
||||
000000000000
|
||||
8624
|
||||
|
||||
## Data
|
||||
06FD0147
|
||||
|
||||
## Name
|
||||
07FD0115
|
||||
0800
|
||||
08012E
|
||||
08022E2E
|
||||
08022E41
|
||||
0840000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F
|
||||
0840404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F
|
||||
0840808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF
|
||||
0840C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
|
||||
|
||||
## MetaInfo
|
||||
1405
|
||||
1A03080102
|
||||
|
||||
## SignatureInfo
|
||||
1603
|
||||
1B0100
|
||||
|
||||
## SignatureValue
|
||||
1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,218 @@
|
||||
A1B2C3D4
|
||||
00020004
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
00000001
|
||||
|
||||
# packet 1
|
||||
00000000
|
||||
00000000
|
||||
00000030
|
||||
00000030
|
||||
|
||||
01005E0017AA
|
||||
000000000000
|
||||
8624
|
||||
|
||||
## LpPacket with unrecognized headers
|
||||
6420
|
||||
5500
|
||||
5600
|
||||
5700
|
||||
5800
|
||||
5900
|
||||
6000
|
||||
6100
|
||||
6300
|
||||
FD032400
|
||||
FD032500
|
||||
FD032600
|
||||
FD032700
|
||||
|
||||
# packet 2
|
||||
00000000
|
||||
00000000
|
||||
00000029
|
||||
00000029
|
||||
|
||||
01005E0017AA
|
||||
000000000000
|
||||
8624
|
||||
|
||||
## LpPacket with reordered headers
|
||||
6419
|
||||
530102
|
||||
5108B0B1B2B3B4B5B600
|
||||
5007 050B0703080141
|
||||
520100
|
||||
|
||||
# packet 3
|
||||
00000000
|
||||
00000000
|
||||
00000029
|
||||
00000029
|
||||
|
||||
01005E0017AA
|
||||
000000000000
|
||||
8624
|
||||
|
||||
## first half of fragmented Interest
|
||||
6419
|
||||
5108B0B1B2B3B4B5B600
|
||||
520100
|
||||
530102
|
||||
5007
|
||||
050B0703080141
|
||||
|
||||
# packet 4
|
||||
00000000
|
||||
00000000
|
||||
00000028
|
||||
00000028
|
||||
|
||||
01005E0017AA
|
||||
000000000000
|
||||
8624
|
||||
|
||||
## second half of fragmented Interest
|
||||
6418
|
||||
5108B0B1B2B3B4B5B601
|
||||
520101
|
||||
530102
|
||||
5006
|
||||
0A04A0A1A2A3
|
||||
|
||||
# packet 5
|
||||
00000000
|
||||
00000000
|
||||
00000028
|
||||
00000028
|
||||
|
||||
01005E0017AA
|
||||
000000000000
|
||||
8624
|
||||
|
||||
## Nack~Congestion
|
||||
6418
|
||||
FD032005 FD03210132
|
||||
500D
|
||||
050B07030801410A04A0A1A2A3
|
||||
|
||||
# packet 6
|
||||
00000000
|
||||
00000000
|
||||
00000028
|
||||
00000028
|
||||
|
||||
01005E0017AA
|
||||
000000000000
|
||||
8624
|
||||
|
||||
## Nack~Duplicate
|
||||
6418
|
||||
FD032005 FD03210164
|
||||
500D
|
||||
050B07030801410A04A0A1A2A3
|
||||
|
||||
# packet 7
|
||||
00000000
|
||||
00000000
|
||||
00000028
|
||||
00000028
|
||||
|
||||
01005E0017AA
|
||||
000000000000
|
||||
8624
|
||||
|
||||
## Nack~NoRoute
|
||||
6418
|
||||
FD032005 FD03210196
|
||||
500D
|
||||
050B07030801410A04A0A1A2A3
|
||||
|
||||
# packet 8
|
||||
00000000
|
||||
00000000
|
||||
00000028
|
||||
00000028
|
||||
|
||||
01005E0017AA
|
||||
000000000000
|
||||
8624
|
||||
|
||||
## Nack unrecognized reason
|
||||
6418
|
||||
FD032005 FD03210101
|
||||
500D
|
||||
050B07030801410A04A0A1A2A3
|
||||
|
||||
# packet 9
|
||||
00000000
|
||||
00000000
|
||||
00000023
|
||||
00000023
|
||||
|
||||
01005E0017AA
|
||||
000000000000
|
||||
8624
|
||||
|
||||
## Nack no reason
|
||||
6413
|
||||
FD032000
|
||||
500D
|
||||
050B07030801410A04A0A1A2A3
|
||||
|
||||
# packet 10
|
||||
00000000
|
||||
00000000
|
||||
00000029
|
||||
00000029
|
||||
|
||||
01005E0017AA
|
||||
000000000000
|
||||
8624
|
||||
|
||||
## Interest with PIT token
|
||||
6419
|
||||
6208D0D1D2D3D4D5D6D7
|
||||
500D
|
||||
050B07030801410A04A0A1A2A3
|
||||
|
||||
# packet 11
|
||||
00000000
|
||||
00000000
|
||||
0000004E
|
||||
0000004E
|
||||
|
||||
01005E0017AA
|
||||
000000000000
|
||||
8624
|
||||
|
||||
## Data with CongestionMark=1 and TxSequence
|
||||
643E
|
||||
FD03400101
|
||||
FD034808E0E1E2E3E4E5E6E7
|
||||
502B
|
||||
0629 0700 16031B0100 1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76
|
||||
|
||||
# packet 12
|
||||
00000000
|
||||
00000000
|
||||
00000070
|
||||
00000070
|
||||
|
||||
01005E0017AA
|
||||
000000000000
|
||||
8624
|
||||
|
||||
## IDLE packet with Acks
|
||||
6460
|
||||
FD034408E0E1E2E3E4E5E600
|
||||
FD034408E0E1E2E3E4E5E601
|
||||
FD034408E0E1E2E3E4E5E602
|
||||
FD034408E0E1E2E3E4E5E603
|
||||
FD034408E0E1E2E3E4E5E604
|
||||
FD034408E0E1E2E3E4E5E605
|
||||
FD034408E0E1E2E3E4E5E606
|
||||
FD034408E0E1E2E3E4E5E607
|
||||
Binary file not shown.
@@ -0,0 +1,58 @@
|
||||
A1B2C3D4
|
||||
00020004
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
00000001
|
||||
|
||||
# packet 1
|
||||
00000000
|
||||
00000000
|
||||
00000039
|
||||
00000039
|
||||
|
||||
01005E0017AA
|
||||
000000000000
|
||||
8624
|
||||
|
||||
## Interest with CanBePrefix, MustBeFresh, HopLimit, ApplicationParameters
|
||||
0529
|
||||
0703080149
|
||||
2100
|
||||
1200
|
||||
1E0B 1F09 1E023E15 0703080148
|
||||
0A044ACB1E4C
|
||||
0C0276A1
|
||||
2201D6
|
||||
2404C0C1C2C3
|
||||
|
||||
# packet 2
|
||||
00000000
|
||||
00000000
|
||||
00000050
|
||||
00000050
|
||||
|
||||
01005E0017AA
|
||||
000000000000
|
||||
8624
|
||||
|
||||
## Interest Name contains typed name components
|
||||
0540
|
||||
0738 020141 070142 080143 FC0144 FD01000145 FDFFFF0145 0120EE357C5791DCAA4494D9B301047B875D8833CAA76DADA3E95837BBC3EAF7B300
|
||||
0A044ACB1E4C
|
||||
|
||||
# packet 3
|
||||
00000000
|
||||
00000000
|
||||
00000039
|
||||
00000039
|
||||
|
||||
01005E0017AA
|
||||
000000000000
|
||||
8624
|
||||
|
||||
## Data without MetaInfo or Content
|
||||
0629
|
||||
0700
|
||||
16031B0100
|
||||
1720612A79399E60304A9F701C1ECAC7956BF2F1B046E6C6F0D6C29B3FE3A29BAD76
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,29 +0,0 @@
|
||||
Testing Instructions
|
||||
====================
|
||||
|
||||
This folder contains a tcpdump trace that can be used to manually check
|
||||
the correctness of ndndump.
|
||||
|
||||
## Test Cases / Trace File Description
|
||||
|
||||
### 1. NDNLPv2 NACK
|
||||
|
||||
Trace file: `nack.pcap`
|
||||
|
||||
Trace summary: Six IPv4 UDP packets, carrying NDN interests and NACK packets.
|
||||
Twelve IPv4 TCP packets, carrying NDN interests and NACK packets.
|
||||
|
||||
Expected result of the capture:
|
||||
|
||||
- 3 NDN interests are captured with UDP tunnel type.
|
||||
- 3 NACKs are captured with UDP tunnel type and the NACK reasons:
|
||||
- Congestion
|
||||
- Duplicate
|
||||
- None
|
||||
|
||||
- 3 NDN interests are captured with TCP tunnel type.
|
||||
- 4 NACKs are captured with TCP tunnel type and the NACK reasons:
|
||||
- Congestion
|
||||
- Duplicate
|
||||
- None
|
||||
- None
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+370
-112
@@ -1,6 +1,7 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2016, University of Memphis.
|
||||
/*
|
||||
* Copyright (c) 2014-2022, University of Memphis,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
@@ -21,16 +22,28 @@
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
|
||||
#include <boost/test/output_test_stream.hpp>
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/udp.h>
|
||||
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#if BOOST_VERSION >= 105900
|
||||
#include <boost/test/tools/output_test_stream.hpp>
|
||||
#else
|
||||
#include <boost/test/output_test_stream.hpp>
|
||||
#endif
|
||||
|
||||
#include <ndn-cxx/encoding/encoding-buffer.hpp>
|
||||
#include <ndn-cxx/lp/packet.hpp>
|
||||
#include <ndn-cxx/security/key-chain.hpp>
|
||||
#include <ndn-cxx/util/ethernet.hpp>
|
||||
#include <ndn-cxx/net/ethernet.hpp>
|
||||
|
||||
namespace ndn {
|
||||
namespace dump {
|
||||
namespace tests {
|
||||
|
||||
namespace endian = boost::endian;
|
||||
using namespace ndn::tests;
|
||||
|
||||
class StdCoutRedirector
|
||||
@@ -60,97 +73,143 @@ protected:
|
||||
dump.m_dataLinkType = DLT_EN10MB;
|
||||
}
|
||||
|
||||
template <typename Packet>
|
||||
template<typename Packet>
|
||||
void
|
||||
receive(const Packet& packet)
|
||||
{
|
||||
ndn::EncodingBuffer buffer(packet.wireEncode());
|
||||
receive(buffer);
|
||||
EncodingBuffer buffer(packet.wireEncode());
|
||||
receiveEthernet(buffer);
|
||||
}
|
||||
|
||||
void
|
||||
receive(ndn::EncodingBuffer& buffer)
|
||||
receiveEthernet(EncodingBuffer& buffer, uint16_t ethertype = s_ethertypeNdn)
|
||||
{
|
||||
ndn::util::ethernet::Address host;
|
||||
ethernet::Address host;
|
||||
|
||||
// Ethernet header
|
||||
uint16_t frameType = htons(ndn::util::ethernet::ETHERTYPE_NDN);
|
||||
buffer.prependByteArray(reinterpret_cast<const uint8_t*>(&frameType),
|
||||
ndn::util::ethernet::TYPE_LEN);
|
||||
buffer.prependByteArray(host.data(), host.size());
|
||||
buffer.prependByteArray(host.data(), host.size());
|
||||
buffer.prependBytes({reinterpret_cast<const uint8_t*>(ðertype), ethernet::TYPE_LEN});
|
||||
buffer.prependBytes(host);
|
||||
buffer.prependBytes(host);
|
||||
|
||||
pcap_pkthdr header{};
|
||||
header.len = buffer.size();
|
||||
// pcap header
|
||||
pcap_pkthdr pkthdr{};
|
||||
pkthdr.caplen = pkthdr.len = buffer.size();
|
||||
|
||||
{
|
||||
StdCoutRedirector redirect(output);
|
||||
dump.onCapturedPacket(&header, buffer.buf());
|
||||
dump.printPacket(&pkthdr, buffer.data());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
receiveIp4(EncodingBuffer& buffer, const ip* ipHeader)
|
||||
{
|
||||
buffer.prependBytes({reinterpret_cast<const uint8_t*>(ipHeader), sizeof(ip)});
|
||||
receiveEthernet(buffer, s_ethertypeIp4);
|
||||
}
|
||||
|
||||
void
|
||||
receiveIp6(EncodingBuffer& buffer, const ip6_hdr* ip6Header)
|
||||
{
|
||||
buffer.prependBytes({reinterpret_cast<const uint8_t*>(ip6Header), sizeof(ip6_hdr)});
|
||||
receiveEthernet(buffer, s_ethertypeIp6);
|
||||
}
|
||||
|
||||
void
|
||||
receiveTcp4(EncodingBuffer& buffer, const tcphdr* tcpHeader)
|
||||
{
|
||||
buffer.prependBytes({reinterpret_cast<const uint8_t*>(tcpHeader), sizeof(tcphdr)});
|
||||
|
||||
ip ipHeader{};
|
||||
ipHeader.ip_v = 4;
|
||||
ipHeader.ip_hl = 5;
|
||||
ipHeader.ip_len = endian::native_to_big(static_cast<uint16_t>(buffer.size() + sizeof(ipHeader)));
|
||||
ipHeader.ip_ttl = 1;
|
||||
ipHeader.ip_p = IPPROTO_TCP;
|
||||
|
||||
receiveIp4(buffer, &ipHeader);
|
||||
}
|
||||
|
||||
void
|
||||
receiveUdp4(EncodingBuffer& buffer, const udphdr* udpHeader)
|
||||
{
|
||||
buffer.prependBytes({reinterpret_cast<const uint8_t*>(udpHeader), sizeof(udphdr)});
|
||||
|
||||
ip ipHeader{};
|
||||
ipHeader.ip_v = 4;
|
||||
ipHeader.ip_hl = 5;
|
||||
ipHeader.ip_len = endian::native_to_big(static_cast<uint16_t>(buffer.size() + sizeof(ipHeader)));
|
||||
ipHeader.ip_ttl = 1;
|
||||
ipHeader.ip_p = IPPROTO_UDP;
|
||||
|
||||
receiveIp4(buffer, &ipHeader);
|
||||
}
|
||||
|
||||
void
|
||||
readFile(const std::string& filename)
|
||||
{
|
||||
StdCoutRedirector redirect(output);
|
||||
dump.inputFile = filename;
|
||||
dump.run();
|
||||
}
|
||||
|
||||
protected:
|
||||
Ndndump dump;
|
||||
NdnDump dump;
|
||||
boost::test_tools::output_test_stream output;
|
||||
|
||||
static const uint16_t s_ethertypeNdn;
|
||||
static const uint16_t s_ethertypeIp4;
|
||||
static const uint16_t s_ethertypeIp6;
|
||||
};
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(NdnDump, NdnDumpFixture)
|
||||
const uint16_t NdnDumpFixture::s_ethertypeNdn = endian::native_to_big(ethernet::ETHERTYPE_NDN);
|
||||
const uint16_t NdnDumpFixture::s_ethertypeIp4 = endian::native_to_big(uint16_t(ETHERTYPE_IP));
|
||||
const uint16_t NdnDumpFixture::s_ethertypeIp6 = endian::native_to_big(uint16_t(ETHERTYPE_IPV6));
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CaptureInterest)
|
||||
BOOST_AUTO_TEST_SUITE(Dump)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestNdnDump, NdnDumpFixture)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Interest)
|
||||
{
|
||||
ndn::Interest interest("/test");
|
||||
interest.setNonce(0);
|
||||
|
||||
this->receive(interest);
|
||||
|
||||
const std::string expectedOutput =
|
||||
"0.000000 Tunnel Type: EthernetFrame, INTEREST: /test?ndn.Nonce=0\n";
|
||||
|
||||
BOOST_CHECK(output.is_equal(expectedOutput));
|
||||
auto interest = makeInterest("/test", false, DEFAULT_INTEREST_LIFETIME, 1);
|
||||
this->receive(*interest);
|
||||
BOOST_CHECK(output.is_equal("0.000000 Ethernet, INTEREST: /test?Nonce=00000001\n"));
|
||||
this->receive(interest->setCanBePrefix(true));
|
||||
BOOST_CHECK(output.is_equal("0.000000 Ethernet, INTEREST: /test?CanBePrefix&Nonce=00000001\n"));
|
||||
this->receive(interest->setInterestLifetime(50_ms));
|
||||
BOOST_CHECK(output.is_equal("0.000000 Ethernet, INTEREST: /test?CanBePrefix&Nonce=00000001&Lifetime=50\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CaptureData)
|
||||
BOOST_AUTO_TEST_CASE(Data)
|
||||
{
|
||||
ndn::security::KeyChain keyChain;
|
||||
|
||||
ndn::Data data("/test");
|
||||
keyChain.sign(data);
|
||||
|
||||
this->receive(data);
|
||||
|
||||
const std::string expectedOutput = "0.000000 Tunnel Type: EthernetFrame, DATA: /test\n";
|
||||
|
||||
BOOST_CHECK(output.is_equal(expectedOutput));
|
||||
auto data = makeData("/test");
|
||||
this->receive(*data);
|
||||
BOOST_CHECK(output.is_equal("0.000000 Ethernet, DATA: /test\n"));
|
||||
this->receive(data->setContentType(tlv::ContentType_Key));
|
||||
BOOST_CHECK(output.is_equal("0.000000 Ethernet, DATA: /test\n"));
|
||||
this->receive(data->setFreshnessPeriod(42_h));
|
||||
BOOST_CHECK(output.is_equal("0.000000 Ethernet, DATA: /test\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CaptureNack)
|
||||
BOOST_AUTO_TEST_CASE(Nack)
|
||||
{
|
||||
ndn::Interest interest("/test");
|
||||
interest.setNonce(0);
|
||||
|
||||
ndn::lp::Nack nack(interest);
|
||||
nack.setReason(ndn::lp::NackReason::DUPLICATE);
|
||||
|
||||
lp::Packet lpPacket(interest.wireEncode());
|
||||
auto interest = makeInterest("/test", false, DEFAULT_INTEREST_LIFETIME, 1);
|
||||
auto nack = makeNack(*interest, lp::NackReason::DUPLICATE);
|
||||
lp::Packet lpPacket(interest->wireEncode());
|
||||
lpPacket.add<lp::NackField>(nack.getHeader());
|
||||
|
||||
this->receive(lpPacket);
|
||||
|
||||
const std::string expectedOutput =
|
||||
"0.000000 Tunnel Type: EthernetFrame, NACK: Duplicate, /test?ndn.Nonce=0\n";
|
||||
|
||||
BOOST_CHECK(output.is_equal(expectedOutput));
|
||||
BOOST_CHECK(output.is_equal("0.000000 Ethernet, NDNLPv2, NACK (Duplicate): /test?Nonce=00000001\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CaptureLpFragment)
|
||||
BOOST_AUTO_TEST_CASE(LpFragment)
|
||||
{
|
||||
const uint8_t data[10] = {
|
||||
0x06, 0x08, // Data packet
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
};
|
||||
|
||||
ndn::Buffer buffer(data, 4);
|
||||
|
||||
Buffer buffer(data, 4);
|
||||
lp::Packet lpPacket;
|
||||
lpPacket.add<lp::FragmentField>(std::make_pair(buffer.begin(), buffer.end()));
|
||||
lpPacket.add<lp::FragIndexField>(0);
|
||||
@@ -158,26 +217,17 @@ BOOST_AUTO_TEST_CASE(CaptureLpFragment)
|
||||
lpPacket.add<lp::SequenceField>(1000);
|
||||
|
||||
this->receive(lpPacket);
|
||||
|
||||
const std::string expectedOutput =
|
||||
"0.000000 Tunnel Type: EthernetFrame, NDNLPv2-FRAGMENT\n";
|
||||
|
||||
BOOST_CHECK(output.is_equal(expectedOutput));
|
||||
BOOST_CHECK(output.is_equal("0.000000 Ethernet, NDNLPv2 fragment\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CaptureIdlePacket)
|
||||
BOOST_AUTO_TEST_CASE(LpIdle)
|
||||
{
|
||||
lp::Packet lpPacket;
|
||||
|
||||
this->receive(lpPacket);
|
||||
|
||||
const std::string expectedOutput =
|
||||
"0.000000 Tunnel Type: EthernetFrame, NDNLPv2-IDLE\n";
|
||||
|
||||
BOOST_CHECK(output.is_equal(expectedOutput));
|
||||
BOOST_CHECK(output.is_equal("0.000000 Ethernet, NDNLPv2 idle\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CaptureIncompletePacket)
|
||||
BOOST_AUTO_TEST_CASE(IncompleteNdnPacket)
|
||||
{
|
||||
const uint8_t interest[] = {
|
||||
0x05, 0x0E, // Interest
|
||||
@@ -187,60 +237,268 @@ BOOST_AUTO_TEST_CASE(CaptureIncompletePacket)
|
||||
0x0a, 0x04, // Nonce
|
||||
0x00, 0x00, 0x00, 0x01
|
||||
};
|
||||
|
||||
EncodingBuffer buffer;
|
||||
buffer.prependByteArray(interest, 4);
|
||||
buffer.prependBytes(make_span(interest).first(4));
|
||||
|
||||
this->receive(buffer);
|
||||
|
||||
const std::string expectedOutput =
|
||||
"0.000000 Tunnel Type: EthernetFrame, INCOMPLETE-PACKET, size: 4\n";
|
||||
|
||||
BOOST_CHECK(output.is_equal(expectedOutput));
|
||||
this->receiveEthernet(buffer);
|
||||
BOOST_CHECK(output.is_equal("0.000000 Ethernet, NDN truncated packet, length 4\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CaptureUnknownNetworkPacket)
|
||||
BOOST_AUTO_TEST_CASE(UnsupportedNdnPacket)
|
||||
{
|
||||
EncodingBuffer buffer(ndn::encoding::makeEmptyBlock(tlv::Name));
|
||||
|
||||
this->receive(buffer);
|
||||
|
||||
const std::string expectedOutput =
|
||||
"0.000000 Tunnel Type: EthernetFrame, UNKNOWN-NETWORK-PACKET\n";
|
||||
|
||||
BOOST_CHECK(output.is_equal(expectedOutput));
|
||||
EncodingBuffer buffer(encoding::makeEmptyBlock(tlv::Name));
|
||||
this->receiveEthernet(buffer);
|
||||
BOOST_CHECK(output.is_equal("0.000000 Ethernet, [Unsupported NDN packet type 7]\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DumpPcapTrace)
|
||||
BOOST_AUTO_TEST_CASE(UnsupportedEtherType)
|
||||
{
|
||||
dump.inputFile = "tests/dump/nack.pcap";
|
||||
dump.pcapProgram = "";
|
||||
EncodingBuffer pkt;
|
||||
uint16_t type = ETHERTYPE_ARP;
|
||||
endian::native_to_big_inplace(type);
|
||||
|
||||
{
|
||||
StdCoutRedirector redirect(output);
|
||||
dump.run();
|
||||
}
|
||||
|
||||
const std::string expectedOutput =
|
||||
"1456768916.467099 From: 1.0.0.1, To: 1.0.0.2, Tunnel Type: UDP, INTEREST: /producer/nack/congestion?ndn.MustBeFresh=1&ndn.Nonce=2581361680\n"
|
||||
"1456768916.567099 From: 1.0.0.1, To: 1.0.0.2, Tunnel Type: UDP, INTEREST: /producer/nack/duplicate?ndn.MustBeFresh=1&ndn.Nonce=4138343109\n"
|
||||
"1456768916.667099 From: 1.0.0.1, To: 1.0.0.2, Tunnel Type: UDP, INTEREST: /producer/nack/no-reason?ndn.MustBeFresh=1&ndn.Nonce=4034910304\n"
|
||||
"1456768916.767099 From: 1.0.0.2, To: 1.0.0.1, Tunnel Type: UDP, NACK: Congestion, /producer/nack/congestion?ndn.MustBeFresh=1&ndn.Nonce=2581361680\n"
|
||||
"1456768916.867099 From: 1.0.0.2, To: 1.0.0.1, Tunnel Type: UDP, NACK: Duplicate, /producer/nack/duplicate?ndn.MustBeFresh=1&ndn.Nonce=4138343109\n"
|
||||
"1456768916.967099 From: 1.0.0.2, To: 1.0.0.1, Tunnel Type: UDP, NACK: None, /producer/nack/no-reason?ndn.MustBeFresh=1&ndn.Nonce=4034910304\n"
|
||||
"1456768917.067099 From: 1.0.0.1, To: 1.0.0.2, Tunnel Type: TCP, INTEREST: /producer/nack/congestion?ndn.MustBeFresh=1&ndn.Nonce=3192497423\n"
|
||||
"1456768917.267099 From: 1.0.0.2, To: 1.0.0.1, Tunnel Type: TCP, NACK: Congestion, /producer/nack/congestion?ndn.MustBeFresh=1&ndn.Nonce=3192497423\n"
|
||||
"1456768917.367099 From: 1.0.0.1, To: 1.0.0.2, Tunnel Type: TCP, INTEREST: /producer/nack/duplicate?ndn.MustBeFresh=1&ndn.Nonce=522390724\n"
|
||||
"1456768917.567099 From: 1.0.0.2, To: 1.0.0.1, Tunnel Type: TCP, NACK: Duplicate, /producer/nack/duplicate?ndn.MustBeFresh=1&ndn.Nonce=522390724\n"
|
||||
"1456768917.767099 From: 1.0.0.2, To: 1.0.0.1, Tunnel Type: TCP, NACK: None, /producer/nack/no-reason?ndn.MustBeFresh=1&ndn.Nonce=2002441365\n"
|
||||
"1456768917.967099 From: 1.0.0.1, To: 1.0.0.2, Tunnel Type: TCP, INTEREST: /producer/nack/no-reason?ndn.MustBeFresh=1&ndn.Nonce=3776824408\n"
|
||||
"1456768918.067099 From: 1.0.0.2, To: 1.0.0.1, Tunnel Type: TCP, NACK: None, /producer/nack/no-reason?ndn.MustBeFresh=1&ndn.Nonce=3776824408\n";
|
||||
|
||||
BOOST_CHECK(output.is_equal(expectedOutput));
|
||||
this->receiveEthernet(pkt, type);
|
||||
BOOST_CHECK(output.is_equal("0.000000 [Unsupported ethertype 0x806]\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MalformedIpv4Header)
|
||||
{
|
||||
dump.wantTimestamp = false;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
uint8_t theAnswer = 42;
|
||||
|
||||
EncodingBuffer pkt1;
|
||||
pkt1.prependBytes({theAnswer});
|
||||
this->receiveEthernet(pkt1, s_ethertypeIp4);
|
||||
BOOST_CHECK(output.is_equal("IP truncated header, length 1\n"));
|
||||
|
||||
ip ipHdr2{};
|
||||
ipHdr2.ip_v = 7;
|
||||
|
||||
EncodingBuffer pkt2;
|
||||
this->receiveIp4(pkt2, &ipHdr2);
|
||||
BOOST_CHECK(output.is_equal("IP bad version 7\n"));
|
||||
|
||||
ip ipHdr3{};
|
||||
ipHdr3.ip_v = 4;
|
||||
ipHdr3.ip_hl = 2;
|
||||
|
||||
EncodingBuffer pkt3;
|
||||
this->receiveIp4(pkt3, &ipHdr3);
|
||||
BOOST_CHECK(output.is_equal("IP bad header length 8\n"));
|
||||
|
||||
ip ipHdr4{};
|
||||
ipHdr4.ip_v = 4;
|
||||
ipHdr4.ip_hl = 5;
|
||||
ipHdr4.ip_len = 10;
|
||||
endian::native_to_big_inplace(ipHdr4.ip_len);
|
||||
|
||||
EncodingBuffer pkt4;
|
||||
this->receiveIp4(pkt4, &ipHdr4);
|
||||
BOOST_CHECK(output.is_equal("IP bad length 10\n"));
|
||||
|
||||
ip ipHdr5{};
|
||||
ipHdr5.ip_v = 4;
|
||||
ipHdr5.ip_hl = 5;
|
||||
ipHdr5.ip_len = 1000;
|
||||
endian::native_to_big_inplace(ipHdr5.ip_len);
|
||||
|
||||
EncodingBuffer pkt5;
|
||||
this->receiveIp4(pkt5, &ipHdr5);
|
||||
BOOST_CHECK(output.is_equal("IP truncated packet, 980 bytes missing\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MalformedIpv6Header)
|
||||
{
|
||||
dump.wantTimestamp = false;
|
||||
|
||||
uint8_t theAnswer = 42;
|
||||
|
||||
EncodingBuffer pkt1;
|
||||
pkt1.prependBytes({theAnswer});
|
||||
this->receiveEthernet(pkt1, s_ethertypeIp6);
|
||||
BOOST_CHECK(output.is_equal("IP6 truncated header, length 1\n"));
|
||||
|
||||
ip6_hdr ip6Hdr2{};
|
||||
ip6Hdr2.ip6_vfc = 10 << 4;
|
||||
|
||||
EncodingBuffer pkt2;
|
||||
this->receiveIp6(pkt2, &ip6Hdr2);
|
||||
BOOST_CHECK(output.is_equal("IP6 bad version 10\n"));
|
||||
|
||||
ip6_hdr ip6Hdr3{};
|
||||
ip6Hdr3.ip6_vfc = 6 << 4;
|
||||
ip6Hdr3.ip6_plen = 1400;
|
||||
endian::native_to_big_inplace(ip6Hdr3.ip6_plen);
|
||||
|
||||
EncodingBuffer pkt3;
|
||||
this->receiveIp6(pkt3, &ip6Hdr3);
|
||||
BOOST_CHECK(output.is_equal("IP6 truncated payload, 1400 bytes missing\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(UnsupportedIpProto)
|
||||
{
|
||||
dump.wantTimestamp = false;
|
||||
|
||||
ip ipHdr{};
|
||||
ipHdr.ip_v = 4;
|
||||
ipHdr.ip_hl = 5;
|
||||
ipHdr.ip_len = sizeof(ipHdr);
|
||||
endian::native_to_big_inplace(ipHdr.ip_len);
|
||||
ipHdr.ip_p = IPPROTO_SCTP;
|
||||
|
||||
EncodingBuffer pkt1;
|
||||
this->receiveIp4(pkt1, &ipHdr);
|
||||
BOOST_CHECK(output.is_equal("IP 0.0.0.0 > 0.0.0.0, [Unsupported IP proto 132]\n"));
|
||||
|
||||
ip6_hdr ip6Hdr{};
|
||||
ip6Hdr.ip6_vfc = 6 << 4;
|
||||
ip6Hdr.ip6_nxt = IPPROTO_NONE;
|
||||
|
||||
EncodingBuffer pkt2;
|
||||
this->receiveIp6(pkt2, &ip6Hdr);
|
||||
BOOST_CHECK(output.is_equal("IP6 :: > ::, [No next header]\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MalformedTcpHeader)
|
||||
{
|
||||
dump.wantTimestamp = false;
|
||||
|
||||
tcphdr tcpHdr1{};
|
||||
tcpHdr1.TH_OFF = 0x2;
|
||||
|
||||
EncodingBuffer pkt1;
|
||||
this->receiveTcp4(pkt1, &tcpHdr1);
|
||||
BOOST_CHECK(output.is_equal("IP 0.0.0.0 > 0.0.0.0, TCP bad header length 8\n"));
|
||||
|
||||
tcphdr tcpHdr2{};
|
||||
tcpHdr2.TH_OFF = 0xf;
|
||||
|
||||
EncodingBuffer pkt2;
|
||||
this->receiveTcp4(pkt2, &tcpHdr2);
|
||||
BOOST_CHECK(output.is_equal("IP 0.0.0.0 > 0.0.0.0, TCP truncated header, 40 bytes missing\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MalformedUdpHeader)
|
||||
{
|
||||
dump.wantTimestamp = false;
|
||||
|
||||
udphdr udpHdr1{};
|
||||
udpHdr1.UH_LEN = 3;
|
||||
endian::native_to_big_inplace(udpHdr1.UH_LEN);
|
||||
|
||||
EncodingBuffer pkt1;
|
||||
this->receiveUdp4(pkt1, &udpHdr1);
|
||||
BOOST_CHECK(output.is_equal("IP 0.0.0.0 > 0.0.0.0, UDP bad length 3\n"));
|
||||
|
||||
udphdr udpHdr2{};
|
||||
udpHdr2.UH_LEN = 1000;
|
||||
endian::native_to_big_inplace(udpHdr2.UH_LEN);
|
||||
|
||||
EncodingBuffer pkt2;
|
||||
this->receiveUdp4(pkt2, &udpHdr2);
|
||||
BOOST_CHECK(output.is_equal("IP 0.0.0.0 > 0.0.0.0, UDP truncated packet, 992 bytes missing\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(InvalidTlvLength)
|
||||
{
|
||||
dump.wantTimestamp = false;
|
||||
this->readFile("tests/dump/invalid-tlv-length.pcap");
|
||||
|
||||
const std::string expected =
|
||||
"IP 128.196.203.36 > 128.187.81.12, TCP, length 147, NDNLPv2 invalid packet: "
|
||||
"TLV-LENGTH of sub-element of type 5 exceeds TLV-VALUE boundary of parent block\n";
|
||||
BOOST_CHECK(output.is_equal(expected));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(UnrecognizedLpField)
|
||||
{
|
||||
dump.wantTimestamp = false;
|
||||
this->readFile("tests/dump/unrecognized-lp-field.pcap");
|
||||
|
||||
const std::string expected =
|
||||
"IP 128.196.203.36 > 128.187.81.12, TCP, length 800, "
|
||||
"NDNLPv2 invalid packet: unrecognized field 4 cannot be ignored\n";
|
||||
BOOST_CHECK(output.is_equal(expected));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(NoTimestamp)
|
||||
{
|
||||
dump.wantTimestamp = false;
|
||||
|
||||
lp::Packet lpPacket;
|
||||
this->receive(lpPacket);
|
||||
|
||||
BOOST_CHECK(output.is_equal("Ethernet, NDNLPv2 idle\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(FromFile)
|
||||
{
|
||||
dump.pcapFilter = "";
|
||||
this->readFile("tests/dump/nack.pcap");
|
||||
|
||||
const std::string expected =
|
||||
"1571091605.129263 IP 127.0.0.1 > 127.0.0.1, TCP, length 36, "
|
||||
"INTEREST: /producer/nack/no-route?Nonce=827bcac4\n"
|
||||
"1571091605.129702 IP 127.0.0.1 > 127.0.0.1, TCP, length 49, "
|
||||
"NDNLPv2, NACK (NoRoute): /producer/nack/no-route?Nonce=827bcac4\n";
|
||||
BOOST_CHECK(output.is_equal(expected));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(LinuxSllTcp4)
|
||||
{
|
||||
dump.wantTimestamp = false;
|
||||
this->readFile("tests/dump/linux-sll-tcp4.pcap");
|
||||
|
||||
const std::string expected =
|
||||
"IP 162.211.64.84 > 131.179.196.46, TCP, length 41, INTEREST: /ndn/edu/arizona/ping/8202?Nonce=cf062c3f\n"
|
||||
"IP 131.179.196.46 > 162.211.64.84, TCP, length 403, DATA: /ndn/edu/arizona/ping/8202\n";
|
||||
BOOST_CHECK(output.is_equal(expected));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(LinuxSllUdp4)
|
||||
{
|
||||
dump.wantTimestamp = false;
|
||||
this->readFile("tests/dump/linux-sll-udp4.pcap");
|
||||
|
||||
const std::string expected =
|
||||
"IP 162.211.64.84 > 131.179.196.46, UDP, length 42, INTEREST: /ndn/edu/arizona/ping/31044?Nonce=f33c0bbd\n"
|
||||
"IP 131.179.196.46 > 162.211.64.84, UDP, length 404, DATA: /ndn/edu/arizona/ping/31044\n";
|
||||
BOOST_CHECK(output.is_equal(expected));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(LinuxSllTcp6)
|
||||
{
|
||||
dump.wantTimestamp = false;
|
||||
this->readFile("tests/dump/linux-sll-tcp6.pcap");
|
||||
|
||||
const std::string expected =
|
||||
"IP6 2602:fff6:d:b317::39f8 > 2001:660:3302:282c:160::163, TCP, length 42, "
|
||||
"INTEREST: /ndn/edu/arizona/ping/19573?Nonce=7b9e5b2e\n"
|
||||
"IP6 2001:660:3302:282c:160::163 > 2602:fff6:d:b317::39f8, TCP, length 404, "
|
||||
"DATA: /ndn/edu/arizona/ping/19573\n"
|
||||
"IP6 2001:660:3302:282c:160::163 > 2602:fff6:d:b317::39f8, TCP, length 56, "
|
||||
"invalid network packet: Unrecognized element of critical type 9\n";
|
||||
BOOST_CHECK(output.is_equal(expected));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(LinuxSllUdp6)
|
||||
{
|
||||
dump.wantTimestamp = false;
|
||||
this->readFile("tests/dump/linux-sll-udp6.pcap");
|
||||
|
||||
const std::string expected =
|
||||
"IP6 2602:fff6:d:b317::39f8 > 2001:660:3302:282c:160::163, UDP, length 39, "
|
||||
"INTEREST: /ndn/edu/arizona/ping/18?Nonce=7e351222\n"
|
||||
"IP6 2001:660:3302:282c:160::163 > 2602:fff6:d:b317::39f8, UDP, length 401, "
|
||||
"DATA: /ndn/edu/arizona/ping/18\n"
|
||||
"IP6 2001:660:3302:282c:160::163 > 2602:fff6:d:b317::39f8, UDP, length 56, "
|
||||
"invalid network packet: Unrecognized element of critical type 9\n";
|
||||
BOOST_CHECK(output.is_equal(expected));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestNdnDump
|
||||
BOOST_AUTO_TEST_SUITE_END() // Dump
|
||||
|
||||
} // namespace tests
|
||||
} // namespace dump
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,72 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "core/common.hpp"
|
||||
|
||||
#include "tests/boost-test.hpp"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <fstream>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace ndn {
|
||||
namespace tests {
|
||||
|
||||
class GlobalConfiguration
|
||||
{
|
||||
public:
|
||||
GlobalConfiguration()
|
||||
{
|
||||
const char* envHome = ::getenv("HOME");
|
||||
if (envHome)
|
||||
m_home = envHome;
|
||||
|
||||
auto testHome = boost::filesystem::path(UNIT_TESTS_TMPDIR) / "test-home";
|
||||
if (::setenv("HOME", testHome.c_str(), 1) != 0)
|
||||
NDN_THROW(std::runtime_error("setenv() failed"));
|
||||
|
||||
boost::filesystem::create_directories(testHome);
|
||||
|
||||
std::ofstream clientConf((testHome / ".ndn" / "client.conf").c_str());
|
||||
clientConf << "pib=pib-sqlite3" << std::endl
|
||||
<< "tpm=tpm-file" << std::endl;
|
||||
}
|
||||
|
||||
~GlobalConfiguration() noexcept
|
||||
{
|
||||
if (m_home.empty())
|
||||
::unsetenv("HOME");
|
||||
else
|
||||
::setenv("HOME", m_home.data(), 1);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_home;
|
||||
};
|
||||
|
||||
#if BOOST_VERSION >= 106500
|
||||
BOOST_TEST_GLOBAL_CONFIGURATION(GlobalConfiguration);
|
||||
#elif BOOST_VERSION >= 105900
|
||||
BOOST_GLOBAL_FIXTURE(GlobalConfiguration);
|
||||
#else
|
||||
BOOST_GLOBAL_FIXTURE(GlobalConfiguration)
|
||||
#endif
|
||||
|
||||
} // namespace tests
|
||||
} // namespace ndn
|
||||
@@ -1,61 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Yingdi Yu <yingdi@cs.ucla.edu>
|
||||
*/
|
||||
|
||||
#ifndef NDN_TOOLS_TESTS_IDENTITY_MANAGEMENT_TIME_FIXTURE_HPP
|
||||
#define NDN_TOOLS_TESTS_IDENTITY_MANAGEMENT_TIME_FIXTURE_HPP
|
||||
|
||||
#include <ndn-cxx/security/key-chain.hpp>
|
||||
#include <vector>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace tests {
|
||||
|
||||
/**
|
||||
* @brief IdentityManagementTimeFixture is a test suite level fixture.
|
||||
* Test cases in the suite can use this fixture to create identities.
|
||||
* Identities added via addIdentity method are automatically deleted
|
||||
* during test teardown.
|
||||
*/
|
||||
class IdentityManagementTimeFixture : public tests::UnitTestTimeFixture
|
||||
{
|
||||
public:
|
||||
IdentityManagementTimeFixture();
|
||||
|
||||
~IdentityManagementTimeFixture();
|
||||
|
||||
/// @brief add identity, return true if succeed.
|
||||
bool
|
||||
addIdentity(const Name& identity, const KeyParams& params = KeyChain::DEFAULT_KEY_PARAMS);
|
||||
|
||||
protected:
|
||||
boost::filesystem::path m_keyChainTmpPath;
|
||||
|
||||
KeyChain m_keyChain;
|
||||
std::vector<Name> m_identities;
|
||||
};
|
||||
|
||||
} // namespace tests
|
||||
} // namespace ndn
|
||||
|
||||
#endif // NDN_TOOLS_TESTS_IDENTITY_MANAGEMENT_TIME_FIXTURE_HPP
|
||||
@@ -1,6 +1,12 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California.
|
||||
/*
|
||||
* Copyright (c) 2014-2020, 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-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
@@ -15,44 +21,39 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Yingdi Yu <yingdi@cs.ucla.edu>
|
||||
*/
|
||||
|
||||
#include "identity-management-time-fixture.hpp"
|
||||
#ifndef NDN_TOOLS_TESTS_IO_FIXTURE_HPP
|
||||
#define NDN_TOOLS_TESTS_IO_FIXTURE_HPP
|
||||
|
||||
#include "tests/clock-fixture.hpp"
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
|
||||
namespace ndn {
|
||||
namespace tests {
|
||||
|
||||
IdentityManagementTimeFixture::IdentityManagementTimeFixture()
|
||||
: m_keyChainTmpPath(boost::filesystem::path(TMP_TESTS_PATH) / "PibIdMgmtTimeTest")
|
||||
, m_keyChain(std::string("pib-sqlite3:").append(m_keyChainTmpPath.string()),
|
||||
std::string("tpm-file:").append(m_keyChainTmpPath.string()))
|
||||
class IoFixture : public ClockFixture
|
||||
{
|
||||
}
|
||||
|
||||
IdentityManagementTimeFixture::~IdentityManagementTimeFixture()
|
||||
{
|
||||
for (const auto& identity : m_identities) {
|
||||
m_keyChain.deleteIdentity(identity);
|
||||
private:
|
||||
void
|
||||
afterTick() final
|
||||
{
|
||||
if (m_io.stopped()) {
|
||||
#if BOOST_VERSION >= 106600
|
||||
m_io.restart();
|
||||
#else
|
||||
m_io.reset();
|
||||
#endif
|
||||
}
|
||||
m_io.poll();
|
||||
}
|
||||
|
||||
boost::filesystem::remove_all(m_keyChainTmpPath);
|
||||
}
|
||||
|
||||
bool
|
||||
IdentityManagementTimeFixture::addIdentity(const Name& identity, const KeyParams& params)
|
||||
{
|
||||
try {
|
||||
m_keyChain.createIdentity(identity, params);
|
||||
m_identities.push_back(identity);
|
||||
return true;
|
||||
}
|
||||
catch (std::runtime_error&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
boost::asio::io_service m_io;
|
||||
};
|
||||
|
||||
} // namespace tests
|
||||
} // namespace ndn
|
||||
|
||||
#endif // NDN_TOOLS_TESTS_IO_FIXTURE_HPP
|
||||
@@ -0,0 +1,117 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tests/key-chain-fixture.hpp"
|
||||
|
||||
#include <ndn-cxx/util/io.hpp>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace ndn {
|
||||
namespace tests {
|
||||
|
||||
using namespace ndn::security;
|
||||
|
||||
KeyChainFixture::KeyChainFixture()
|
||||
: m_keyChain("pib-memory:", "tpm-memory:")
|
||||
{
|
||||
}
|
||||
|
||||
KeyChainFixture::~KeyChainFixture()
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
for (const auto& certFile : m_certFiles) {
|
||||
boost::filesystem::remove(certFile, ec); // ignore error
|
||||
}
|
||||
}
|
||||
|
||||
Certificate
|
||||
KeyChainFixture::makeCert(const Key& key, const std::string& issuer, const Key& signingKey)
|
||||
{
|
||||
Certificate cert;
|
||||
cert.setName(Name(key.getName())
|
||||
.append(issuer)
|
||||
.appendVersion());
|
||||
|
||||
// set metainfo
|
||||
cert.setContentType(tlv::ContentType_Key);
|
||||
cert.setFreshnessPeriod(1_h);
|
||||
|
||||
// set content
|
||||
cert.setContent(key.getPublicKey());
|
||||
|
||||
// set signature info
|
||||
ndn::SignatureInfo info;
|
||||
auto now = time::system_clock::now();
|
||||
info.setValidityPeriod(ValidityPeriod(now - 30_days, now + 30_days));
|
||||
|
||||
m_keyChain.sign(cert, signingByKey(signingKey ? signingKey : key).setSignatureInfo(info));
|
||||
return cert;
|
||||
}
|
||||
|
||||
bool
|
||||
KeyChainFixture::saveCert(const Data& cert, const std::string& filename)
|
||||
{
|
||||
m_certFiles.push_back(filename);
|
||||
try {
|
||||
ndn::io::save(cert, filename);
|
||||
return true;
|
||||
}
|
||||
catch (const ndn::io::Error&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
KeyChainFixture::saveIdentityCert(const Identity& identity, const std::string& filename)
|
||||
{
|
||||
Certificate cert;
|
||||
try {
|
||||
cert = identity.getDefaultKey().getDefaultCertificate();
|
||||
}
|
||||
catch (const Pib::Error&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return saveCert(cert, filename);
|
||||
}
|
||||
|
||||
bool
|
||||
KeyChainFixture::saveIdentityCert(const Name& identityName, const std::string& filename,
|
||||
bool allowCreate)
|
||||
{
|
||||
Identity id;
|
||||
try {
|
||||
id = m_keyChain.getPib().getIdentity(identityName);
|
||||
}
|
||||
catch (const Pib::Error&) {
|
||||
if (allowCreate) {
|
||||
id = m_keyChain.createIdentity(identityName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return saveIdentityCert(id, filename);
|
||||
}
|
||||
|
||||
} // namespace tests
|
||||
} // namespace ndn
|
||||
@@ -0,0 +1,93 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NDN_TOOLS_TESTS_KEY_CHAIN_FIXTURE_HPP
|
||||
#define NDN_TOOLS_TESTS_KEY_CHAIN_FIXTURE_HPP
|
||||
|
||||
#include <ndn-cxx/security/key-chain.hpp>
|
||||
#include <ndn-cxx/security/signing-helpers.hpp>
|
||||
|
||||
namespace ndn {
|
||||
namespace tests {
|
||||
|
||||
/**
|
||||
* @brief A fixture providing an in-memory KeyChain.
|
||||
*
|
||||
* Test cases can use this fixture to create identities. Identities, certificates, and
|
||||
* saved certificates are automatically removed during test teardown.
|
||||
*/
|
||||
class KeyChainFixture
|
||||
{
|
||||
protected:
|
||||
using Certificate = ndn::security::Certificate;
|
||||
using Identity = ndn::security::Identity;
|
||||
using Key = ndn::security::Key;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Creates and returns a certificate for a given key
|
||||
* @param key The key for which to make a certificate
|
||||
* @param issuer The IssuerId to include in the certificate name
|
||||
* @param signingKey The key with which to sign the certificate; if not provided, the
|
||||
* certificate will be self-signed
|
||||
*/
|
||||
Certificate
|
||||
makeCert(const Key& key, const std::string& issuer, const Key& signingKey = Key());
|
||||
|
||||
/**
|
||||
* @brief Saves an NDN certificate to a file
|
||||
* @return true if successful, false otherwise
|
||||
*/
|
||||
bool
|
||||
saveCert(const Data& cert, const std::string& filename);
|
||||
|
||||
/**
|
||||
* @brief Saves the default certificate of @p identity to a file
|
||||
* @return true if successful, false otherwise
|
||||
*/
|
||||
bool
|
||||
saveIdentityCert(const Identity& identity, const std::string& filename);
|
||||
|
||||
/**
|
||||
* @brief Saves the default certificate of the identity named @p identityName to a file
|
||||
* @param identityName Name of the identity
|
||||
* @param filename File name, must be writable
|
||||
* @param allowCreate If true, create the identity if it does not exist
|
||||
* @return true if successful, false otherwise
|
||||
*/
|
||||
bool
|
||||
saveIdentityCert(const Name& identityName, const std::string& filename,
|
||||
bool allowCreate = false);
|
||||
|
||||
protected:
|
||||
KeyChainFixture();
|
||||
|
||||
~KeyChainFixture();
|
||||
|
||||
protected:
|
||||
ndn::KeyChain m_keyChain;
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_certFiles;
|
||||
};
|
||||
|
||||
} // namespace tests
|
||||
} // namespace ndn
|
||||
|
||||
#endif // NDN_TOOLS_TESTS_KEY_CHAIN_FIXTURE_HPP
|
||||
+4
-6
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -23,7 +23,5 @@
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define BOOST_TEST_MAIN 1
|
||||
#define BOOST_TEST_DYN_LINK 1
|
||||
|
||||
#include "boost-test.hpp"
|
||||
#define BOOST_TEST_MODULE ndn-tools
|
||||
#include "tests/boost-test.hpp"
|
||||
|
||||
@@ -0,0 +1,329 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, Arizona Board of Regents.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tools/peek/ndnpeek/ndnpeek.hpp"
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include "tests/io-fixture.hpp"
|
||||
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
#include <boost/mpl/vector.hpp>
|
||||
#if BOOST_VERSION >= 105900
|
||||
#include <boost/test/tools/output_test_stream.hpp>
|
||||
#else
|
||||
#include <boost/test/output_test_stream.hpp>
|
||||
#endif
|
||||
|
||||
namespace ndn {
|
||||
namespace peek {
|
||||
namespace tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
using boost::test_tools::output_test_stream;
|
||||
|
||||
class CoutRedirector : noncopyable
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
CoutRedirector(std::ostream& destination)
|
||||
{
|
||||
m_originalBuf = std::cout.rdbuf(destination.rdbuf());
|
||||
}
|
||||
|
||||
~CoutRedirector()
|
||||
{
|
||||
std::cout.rdbuf(m_originalBuf);
|
||||
}
|
||||
|
||||
private:
|
||||
std::streambuf* m_originalBuf;
|
||||
};
|
||||
|
||||
static PeekOptions
|
||||
makeDefaultOptions()
|
||||
{
|
||||
PeekOptions opt;
|
||||
opt.name = "/peek/test";
|
||||
return opt;
|
||||
}
|
||||
|
||||
class NdnPeekFixture : public IoFixture
|
||||
{
|
||||
protected:
|
||||
void
|
||||
initialize(const PeekOptions& opts = makeDefaultOptions())
|
||||
{
|
||||
peek = make_unique<NdnPeek>(face, opts);
|
||||
}
|
||||
|
||||
protected:
|
||||
ndn::util::DummyClientFace face{m_io};
|
||||
output_test_stream output;
|
||||
unique_ptr<NdnPeek> peek;
|
||||
};
|
||||
|
||||
class OutputFull
|
||||
{
|
||||
public:
|
||||
static PeekOptions
|
||||
makeOptions()
|
||||
{
|
||||
return makeDefaultOptions();
|
||||
}
|
||||
|
||||
static void
|
||||
checkOutput(output_test_stream& output, const Data& data)
|
||||
{
|
||||
const Block& block = data.wireEncode();
|
||||
std::string expected(reinterpret_cast<const char*>(block.wire()), block.size());
|
||||
BOOST_CHECK(output.is_equal(expected));
|
||||
}
|
||||
|
||||
static void
|
||||
checkOutput(output_test_stream& output, const lp::Nack& nack)
|
||||
{
|
||||
const Block& block = nack.getHeader().wireEncode();
|
||||
std::string expected(reinterpret_cast<const char*>(block.wire()), block.size());
|
||||
BOOST_CHECK(output.is_equal(expected));
|
||||
}
|
||||
};
|
||||
|
||||
class OutputPayloadOnly
|
||||
{
|
||||
public:
|
||||
static PeekOptions
|
||||
makeOptions()
|
||||
{
|
||||
PeekOptions opt = makeDefaultOptions();
|
||||
opt.wantPayloadOnly = true;
|
||||
return opt;
|
||||
}
|
||||
|
||||
static void
|
||||
checkOutput(output_test_stream& output, const Data& data)
|
||||
{
|
||||
const Block& block = data.getContent();
|
||||
std::string expected(reinterpret_cast<const char*>(block.value()), block.value_size());
|
||||
BOOST_CHECK(output.is_equal(expected));
|
||||
}
|
||||
|
||||
static void
|
||||
checkOutput(output_test_stream& output, const lp::Nack& nack)
|
||||
{
|
||||
std::string expected = boost::lexical_cast<std::string>(nack.getReason()) + '\n';
|
||||
BOOST_CHECK(output.is_equal(expected));
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Peek)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestNdnPeek, NdnPeekFixture)
|
||||
|
||||
using OutputChecks = boost::mpl::vector<OutputFull, OutputPayloadOnly>;
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(Default, OutputCheck, OutputChecks)
|
||||
{
|
||||
auto options = OutputCheck::makeOptions();
|
||||
initialize(options);
|
||||
|
||||
auto data = makeData(options.name);
|
||||
data->setContent({'n', 'd', 'n', 'p', 'e', 'e', 'k'});
|
||||
|
||||
{
|
||||
CoutRedirector redir(output);
|
||||
peek->start();
|
||||
this->advanceClocks(25_ms, 4);
|
||||
face.receive(*data);
|
||||
}
|
||||
|
||||
OutputCheck::checkOutput(output, *data);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
const auto& interest = face.sentInterests.back();
|
||||
BOOST_CHECK_EQUAL(interest.getCanBePrefix(), false);
|
||||
BOOST_CHECK_EQUAL(interest.getMustBeFresh(), false);
|
||||
BOOST_CHECK_EQUAL(interest.getForwardingHint().empty(), true);
|
||||
BOOST_CHECK_EQUAL(interest.getInterestLifetime(), DEFAULT_INTEREST_LIFETIME);
|
||||
BOOST_CHECK(interest.getHopLimit() == nullopt);
|
||||
BOOST_CHECK(!interest.hasApplicationParameters());
|
||||
BOOST_CHECK(peek->getResult() == NdnPeek::Result::DATA);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(NonDefault, OutputCheck, OutputChecks)
|
||||
{
|
||||
auto options = OutputCheck::makeOptions();
|
||||
options.canBePrefix = true;
|
||||
options.mustBeFresh = true;
|
||||
options.forwardingHint.emplace_back("/fh");
|
||||
options.interestLifetime = 200_ms;
|
||||
options.hopLimit = 64;
|
||||
initialize(options);
|
||||
|
||||
auto data = makeData(Name(options.name).append("suffix"));
|
||||
data->setFreshnessPeriod(1_s);
|
||||
data->setContent({'n', 'd', 'n', 'p', 'e', 'e', 'k'});
|
||||
|
||||
{
|
||||
CoutRedirector redir(output);
|
||||
peek->start();
|
||||
this->advanceClocks(25_ms, 4);
|
||||
face.receive(*data);
|
||||
}
|
||||
|
||||
OutputCheck::checkOutput(output, *data);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
const auto& interest = face.sentInterests.back();
|
||||
BOOST_CHECK_EQUAL(interest.getCanBePrefix(), true);
|
||||
BOOST_CHECK_EQUAL(interest.getMustBeFresh(), true);
|
||||
BOOST_TEST(interest.getForwardingHint() == std::vector<Name>({"/fh"}),
|
||||
boost::test_tools::per_element());
|
||||
BOOST_CHECK_EQUAL(interest.getInterestLifetime(), 200_ms);
|
||||
BOOST_CHECK(interest.getHopLimit() == 64);
|
||||
BOOST_CHECK(!interest.hasApplicationParameters());
|
||||
BOOST_CHECK(peek->getResult() == NdnPeek::Result::DATA);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(ReceiveNackWithReason, OutputCheck, OutputChecks)
|
||||
{
|
||||
auto options = OutputCheck::makeOptions();
|
||||
initialize(options);
|
||||
lp::Nack nack;
|
||||
|
||||
{
|
||||
CoutRedirector redir(output);
|
||||
peek->start();
|
||||
this->advanceClocks(25_ms, 4);
|
||||
nack = makeNack(face.sentInterests.at(0), lp::NackReason::NO_ROUTE);
|
||||
face.receive(nack);
|
||||
}
|
||||
|
||||
OutputCheck::checkOutput(output, nack);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
|
||||
BOOST_CHECK(peek->getResult() == NdnPeek::Result::NACK);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE_TEMPLATE(ReceiveNackWithoutReason, OutputCheck, OutputChecks)
|
||||
{
|
||||
auto options = OutputCheck::makeOptions();
|
||||
initialize(options);
|
||||
lp::Nack nack;
|
||||
|
||||
{
|
||||
CoutRedirector redir(output);
|
||||
peek->start();
|
||||
this->advanceClocks(25_ms, 4);
|
||||
nack = makeNack(face.sentInterests.at(0), lp::NackReason::NONE);
|
||||
face.receive(nack);
|
||||
}
|
||||
|
||||
OutputCheck::checkOutput(output, nack);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
|
||||
BOOST_CHECK(peek->getResult() == NdnPeek::Result::NACK);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ApplicationParameters)
|
||||
{
|
||||
auto options = makeDefaultOptions();
|
||||
options.applicationParameters = make_shared<Buffer>("hello", 5);
|
||||
initialize(options);
|
||||
|
||||
peek->start();
|
||||
this->advanceClocks(25_ms, 4);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.back().getCanBePrefix(), false);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.back().getMustBeFresh(), false);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.back().getForwardingHint().empty(), true);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.back().getInterestLifetime(), DEFAULT_INTEREST_LIFETIME);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.back().hasApplicationParameters(), true);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.back().getApplicationParameters(), "2405 68656C6C6F"_block);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(NoTimeout)
|
||||
{
|
||||
auto options = makeDefaultOptions();
|
||||
options.interestLifetime = 1_s;
|
||||
options.timeout = nullopt;
|
||||
initialize(options);
|
||||
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 0);
|
||||
|
||||
peek->start();
|
||||
this->advanceClocks(100_ms, 9);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 1);
|
||||
BOOST_CHECK(peek->getResult() == NdnPeek::Result::UNKNOWN);
|
||||
|
||||
this->advanceClocks(100_ms, 2);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
|
||||
BOOST_CHECK(peek->getResult() == NdnPeek::Result::TIMEOUT);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(TimeoutLessThanLifetime)
|
||||
{
|
||||
auto options = makeDefaultOptions();
|
||||
options.interestLifetime = 200_ms;
|
||||
options.timeout = 100_ms;
|
||||
initialize(options);
|
||||
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 0);
|
||||
|
||||
peek->start();
|
||||
this->advanceClocks(25_ms, 6);
|
||||
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
|
||||
BOOST_CHECK(peek->getResult() == NdnPeek::Result::TIMEOUT);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(TimeoutGreaterThanLifetime)
|
||||
{
|
||||
auto options = makeDefaultOptions();
|
||||
options.interestLifetime = 50_ms;
|
||||
options.timeout = 200_ms;
|
||||
initialize(options);
|
||||
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 0);
|
||||
|
||||
peek->start();
|
||||
this->advanceClocks(25_ms, 4);
|
||||
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
|
||||
BOOST_CHECK(peek->getResult() == NdnPeek::Result::TIMEOUT);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(OversizedPacket)
|
||||
{
|
||||
auto options = makeDefaultOptions();
|
||||
options.applicationParameters = make_shared<Buffer>(MAX_NDN_PACKET_SIZE);
|
||||
initialize(options);
|
||||
|
||||
peek->start();
|
||||
BOOST_CHECK_THROW(this->advanceClocks(1_ms, 10), Face::OversizedPacketError);
|
||||
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestNdnPeek
|
||||
BOOST_AUTO_TEST_SUITE_END() // Peek
|
||||
|
||||
} // namespace tests
|
||||
} // namespace peek
|
||||
} // namespace ndn
|
||||
@@ -0,0 +1,261 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2020, 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-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tools/peek/ndnpoke/ndnpoke.hpp"
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include "tests/io-fixture.hpp"
|
||||
#include "tests/key-chain-fixture.hpp"
|
||||
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
namespace ndn {
|
||||
namespace peek {
|
||||
namespace tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
template<bool WANT_PREFIX_REG_REPLY = true>
|
||||
class NdnPokeFixture : public IoFixture, public KeyChainFixture
|
||||
{
|
||||
protected:
|
||||
NdnPokeFixture()
|
||||
{
|
||||
m_keyChain.createIdentity("/test-id");
|
||||
}
|
||||
|
||||
void
|
||||
initialize(const PokeOptions& opts = makeDefaultOptions())
|
||||
{
|
||||
poke = make_unique<NdnPoke>(face, m_keyChain, payload, opts);
|
||||
}
|
||||
|
||||
static PokeOptions
|
||||
makeDefaultOptions()
|
||||
{
|
||||
PokeOptions opt;
|
||||
opt.name = "/poke/test";
|
||||
return opt;
|
||||
}
|
||||
|
||||
protected:
|
||||
ndn::util::DummyClientFace face{m_io, m_keyChain, {true, WANT_PREFIX_REG_REPLY}};
|
||||
std::stringstream payload{"Hello, world!\n"};
|
||||
unique_ptr<NdnPoke> poke;
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Peek)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestNdnPoke, NdnPokeFixture<>)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Basic)
|
||||
{
|
||||
initialize();
|
||||
|
||||
poke->start();
|
||||
this->advanceClocks(1_ms, 10);
|
||||
|
||||
// Check for prefix registration
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.front().getName().getPrefix(4), "/localhost/nfd/rib/register");
|
||||
|
||||
face.receive(*makeInterest("/poke/test"));
|
||||
this->advanceClocks(1_ms, 10);
|
||||
|
||||
BOOST_CHECK(poke->getResult() == NdnPoke::Result::DATA_SENT);
|
||||
BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getName(), "/poke/test");
|
||||
BOOST_CHECK(!face.sentData.back().getFinalBlock());
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getFreshnessPeriod(), 0_ms);
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getContentType(), tlv::ContentType_Blob);
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getContent(), "150E48656C6C6F2C20776F726C64210A"_block);
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getSignatureType(), tlv::SignatureSha256WithEcdsa);
|
||||
|
||||
// Check for prefix unregistration
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2); // One for registration, one for unregistration
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.back().getName().getPrefix(4), "/localhost/nfd/rib/unregister");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(NoMatch)
|
||||
{
|
||||
initialize();
|
||||
|
||||
poke->start();
|
||||
this->advanceClocks(1_ms, 10);
|
||||
|
||||
face.receive(*makeInterest("/poke/test/foo"));
|
||||
this->advanceClocks(1_ms, 10);
|
||||
|
||||
BOOST_CHECK(poke->getResult() == NdnPoke::Result::UNKNOWN);
|
||||
BOOST_CHECK_EQUAL(face.sentData.size(), 0);
|
||||
|
||||
face.receive(*makeInterest("/poke/test"));
|
||||
this->advanceClocks(1_ms, 10);
|
||||
|
||||
BOOST_CHECK(poke->getResult() == NdnPoke::Result::DATA_SENT);
|
||||
BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getName(), "/poke/test");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(FreshnessPeriod)
|
||||
{
|
||||
auto options = makeDefaultOptions();
|
||||
options.freshnessPeriod = 1_s;
|
||||
initialize(options);
|
||||
|
||||
poke->start();
|
||||
this->advanceClocks(1_ms, 10);
|
||||
|
||||
face.receive(*makeInterest("/poke/test"));
|
||||
this->advanceClocks(1_ms, 10);
|
||||
|
||||
BOOST_CHECK(poke->getResult() == NdnPoke::Result::DATA_SENT);
|
||||
BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getName(), "/poke/test");
|
||||
BOOST_CHECK(!face.sentData.back().getFinalBlock());
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getFreshnessPeriod(), 1_s);
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getSignatureType(), tlv::SignatureSha256WithEcdsa);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(FinalBlockId)
|
||||
{
|
||||
auto options = makeDefaultOptions();
|
||||
options.name = "/poke/test/123";
|
||||
options.wantFinalBlockId = true;
|
||||
initialize(options);
|
||||
|
||||
poke->start();
|
||||
this->advanceClocks(1_ms, 10);
|
||||
|
||||
face.receive(*makeInterest(options.name));
|
||||
this->advanceClocks(1_ms, 10);
|
||||
|
||||
BOOST_CHECK(poke->getResult() == NdnPoke::Result::DATA_SENT);
|
||||
BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getName(), options.name);
|
||||
BOOST_REQUIRE(face.sentData.back().getFinalBlock());
|
||||
BOOST_CHECK_EQUAL(*(face.sentData.back().getFinalBlock()), name::Component("123"));
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getFreshnessPeriod(), 0_ms);
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getSignatureType(), tlv::SignatureSha256WithEcdsa);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DigestSha256)
|
||||
{
|
||||
auto options = makeDefaultOptions();
|
||||
options.signingInfo.setSha256Signing();
|
||||
initialize(options);
|
||||
|
||||
poke->start();
|
||||
this->advanceClocks(1_ms, 10);
|
||||
|
||||
face.receive(*makeInterest("/poke/test"));
|
||||
this->advanceClocks(1_ms, 10);
|
||||
|
||||
BOOST_CHECK(poke->getResult() == NdnPoke::Result::DATA_SENT);
|
||||
BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getName(), "/poke/test");
|
||||
BOOST_CHECK(!face.sentData.back().getFinalBlock());
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getFreshnessPeriod(), 0_ms);
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getSignatureType(), tlv::DigestSha256);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Unsolicited)
|
||||
{
|
||||
auto options = makeDefaultOptions();
|
||||
options.wantUnsolicited = true;
|
||||
initialize(options);
|
||||
|
||||
poke->start();
|
||||
this->advanceClocks(1_ms, 10);
|
||||
|
||||
BOOST_CHECK(poke->getResult() == NdnPoke::Result::DATA_SENT);
|
||||
BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getName(), "/poke/test");
|
||||
BOOST_CHECK(!face.sentData.back().getFinalBlock());
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getFreshnessPeriod(), 0_ms);
|
||||
BOOST_CHECK_EQUAL(face.sentData.back().getSignatureType(), tlv::SignatureSha256WithEcdsa);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Timeout)
|
||||
{
|
||||
auto options = makeDefaultOptions();
|
||||
options.timeout = 4_s;
|
||||
initialize(options);
|
||||
|
||||
poke->start();
|
||||
this->advanceClocks(1_ms, 10);
|
||||
|
||||
// Check for prefix registration
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.front().getName().getPrefix(4), "/localhost/nfd/rib/register");
|
||||
|
||||
this->advanceClocks(1_s, 4);
|
||||
|
||||
BOOST_CHECK(poke->getResult() == NdnPoke::Result::TIMEOUT);
|
||||
BOOST_CHECK_EQUAL(face.sentData.size(), 0);
|
||||
|
||||
// Check for prefix unregistration
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2); // One for registration, one for unregistration
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.back().getName().getPrefix(4), "/localhost/nfd/rib/unregister");
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(PrefixRegTimeout, NdnPokeFixture<false>)
|
||||
{
|
||||
initialize();
|
||||
|
||||
poke->start();
|
||||
this->advanceClocks(1_ms, 10);
|
||||
|
||||
// Check for prefix registration
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.front().getName().getPrefix(4), "/localhost/nfd/rib/register");
|
||||
|
||||
this->advanceClocks(1_s, 10);
|
||||
|
||||
BOOST_CHECK(poke->getResult() == NdnPoke::Result::PREFIX_REG_FAIL);
|
||||
BOOST_CHECK_EQUAL(face.sentData.size(), 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(OversizedPacket)
|
||||
{
|
||||
payload << std::string(MAX_NDN_PACKET_SIZE, 'A');
|
||||
initialize();
|
||||
|
||||
poke->start();
|
||||
this->advanceClocks(1_ms, 10);
|
||||
|
||||
face.receive(*makeInterest("/poke/test"));
|
||||
BOOST_CHECK_THROW(face.processEvents(), Face::OversizedPacketError);
|
||||
|
||||
// No point in checking getResult() here. The exception is thrown from processEvents(),
|
||||
// not from put(), so the result is still DATA_SENT even though no packets were sent.
|
||||
BOOST_CHECK_EQUAL(face.sentData.size(), 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestNdnPoke
|
||||
BOOST_AUTO_TEST_SUITE_END() // Peek
|
||||
|
||||
} // namespace tests
|
||||
} // namespace peek
|
||||
} // namespace ndn
|
||||
@@ -1,132 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Yingdi Yu <yingdi@cs.ucla.edu>
|
||||
*/
|
||||
|
||||
#include "tools/pib/cert-publisher.hpp"
|
||||
#include "../identity-management-time-fixture.hpp"
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace pib {
|
||||
namespace tests {
|
||||
|
||||
class CertPublisherFixture : public ndn::tests::IdentityManagementTimeFixture
|
||||
{
|
||||
public:
|
||||
CertPublisherFixture()
|
||||
: tmpPath(boost::filesystem::path(TMP_TESTS_PATH) / "DbTest")
|
||||
, db(tmpPath.c_str())
|
||||
, face(util::makeDummyClientFace(io, {true, true}))
|
||||
{
|
||||
}
|
||||
|
||||
~CertPublisherFixture()
|
||||
{
|
||||
boost::filesystem::remove_all(tmpPath);
|
||||
}
|
||||
|
||||
boost::asio::io_service io;
|
||||
boost::filesystem::path tmpPath;
|
||||
PibDb db;
|
||||
shared_ptr<util::DummyClientFace> face;
|
||||
};
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(PibCertPublisher, CertPublisherFixture)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Basic)
|
||||
{
|
||||
// Initialize id1
|
||||
Name id1("/test/identity");
|
||||
addIdentity(id1);
|
||||
Name certName111 = m_keyChain.getDefaultCertificateNameForIdentity(id1);
|
||||
shared_ptr<IdentityCertificate> cert111 = m_keyChain.getCertificate(certName111);
|
||||
Name keyName11 = cert111->getPublicKeyName();
|
||||
|
||||
advanceClocks(io, time::milliseconds(100));
|
||||
shared_ptr<IdentityCertificate> cert112 = m_keyChain.selfSign(keyName11);
|
||||
Name certName112 = cert112->getName();
|
||||
|
||||
CertPublisher certPublisher(*face, db);
|
||||
|
||||
// Add a certificate
|
||||
db.addCertificate(*cert111);
|
||||
advanceClocks(io, time::milliseconds(2), 50);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0);
|
||||
auto interest111 = make_shared<Interest>(cert111->getName().getPrefix(-1));
|
||||
face->receive(*interest111);
|
||||
advanceClocks(io, time::milliseconds(2), 50);
|
||||
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1);
|
||||
BOOST_CHECK(face->sentDatas[0].wireEncode() == cert111->wireEncode());
|
||||
face->sentDatas.clear();
|
||||
|
||||
// Add another certificate
|
||||
db.addCertificate(*cert112);
|
||||
advanceClocks(io, time::milliseconds(2), 50);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0);
|
||||
auto interest112 = make_shared<Interest>(cert112->getName().getPrefix(-1));
|
||||
face->receive(*interest112);
|
||||
advanceClocks(io, time::milliseconds(2), 50);
|
||||
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1);
|
||||
BOOST_CHECK(face->sentDatas[0].wireEncode() == cert111->wireEncode());
|
||||
face->sentDatas.clear();
|
||||
|
||||
Exclude exclude;
|
||||
exclude.excludeOne(cert111->getName().get(-1));
|
||||
interest112->setExclude(exclude);
|
||||
face->receive(*interest112);
|
||||
advanceClocks(io, time::milliseconds(2), 50);
|
||||
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1);
|
||||
BOOST_CHECK(face->sentDatas[0].wireEncode() == cert112->wireEncode());
|
||||
face->sentDatas.clear();
|
||||
|
||||
// delete a certificate
|
||||
db.deleteCertificate(certName112);
|
||||
face->receive(*interest112);
|
||||
advanceClocks(io, time::milliseconds(2), 50);
|
||||
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0);
|
||||
|
||||
face->receive(*interest111);
|
||||
advanceClocks(io, time::milliseconds(2), 50);
|
||||
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1);
|
||||
BOOST_CHECK(face->sentDatas[0].wireEncode() == cert111->wireEncode());
|
||||
face->sentDatas.clear();
|
||||
|
||||
// delete another certificate
|
||||
db.deleteCertificate(certName111);
|
||||
face->receive(*interest112);
|
||||
advanceClocks(io, time::milliseconds(2), 50);
|
||||
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0);
|
||||
|
||||
face->receive(*interest111);
|
||||
advanceClocks(io, time::milliseconds(2), 50);
|
||||
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
} // namespace tests
|
||||
} // namespace pib
|
||||
} // namespace ndn
|
||||
@@ -1,75 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Yingdi Yu <yingdi@cs.ucla.edu>
|
||||
*/
|
||||
|
||||
#include "tools/pib/key-cache.hpp"
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace pib {
|
||||
namespace tests {
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(PibKeyCache)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Basic)
|
||||
{
|
||||
KeyCache keyCache(3);
|
||||
|
||||
Name name1("/1");
|
||||
Name name2("/2");
|
||||
Name name3("/3");
|
||||
Name name4("/4");
|
||||
|
||||
auto key1 = make_shared<PublicKey>();
|
||||
auto key2 = make_shared<PublicKey>();
|
||||
auto key3 = make_shared<PublicKey>();
|
||||
auto key4 = make_shared<PublicKey>();
|
||||
|
||||
keyCache.insert(name1, key1);
|
||||
keyCache.insert(name2, key2);
|
||||
keyCache.insert(name3, key3);
|
||||
|
||||
BOOST_CHECK_EQUAL(keyCache.size(), 3);
|
||||
BOOST_CHECK(static_cast<bool>(keyCache.find(name1)));
|
||||
BOOST_CHECK(static_cast<bool>(keyCache.find(name2)));
|
||||
BOOST_CHECK(static_cast<bool>(keyCache.find(name3)));
|
||||
BOOST_CHECK(!static_cast<bool>(keyCache.find(name4)));
|
||||
|
||||
keyCache.insert(name1, key1);
|
||||
keyCache.insert(name4, key4);
|
||||
BOOST_CHECK_EQUAL(keyCache.size(), 3);
|
||||
BOOST_CHECK(static_cast<bool>(keyCache.find(name1)));
|
||||
BOOST_CHECK(!static_cast<bool>(keyCache.find(name2)));
|
||||
BOOST_CHECK(static_cast<bool>(keyCache.find(name3)));
|
||||
BOOST_CHECK(static_cast<bool>(keyCache.find(name4)));
|
||||
|
||||
keyCache.erase(name1);
|
||||
BOOST_CHECK_EQUAL(keyCache.size(), 2);
|
||||
BOOST_CHECK(!static_cast<bool>(keyCache.find(name1)));
|
||||
BOOST_CHECK(static_cast<bool>(keyCache.find(name3)));
|
||||
BOOST_CHECK(static_cast<bool>(keyCache.find(name4)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
} // namespace tests
|
||||
} // namespace pib
|
||||
} // namespace ndn
|
||||
@@ -1,474 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Yingdi Yu <yingdi@cs.ucla.edu>
|
||||
*/
|
||||
|
||||
#include "tools/pib/pib-db.hpp"
|
||||
#include "../identity-management-time-fixture.hpp"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace pib {
|
||||
namespace tests {
|
||||
|
||||
class PibDbTestFixture : public ndn::tests::IdentityManagementTimeFixture
|
||||
{
|
||||
public:
|
||||
PibDbTestFixture()
|
||||
: tmpPath(boost::filesystem::path(TMP_TESTS_PATH) / "DbTest")
|
||||
, db(tmpPath.c_str())
|
||||
{
|
||||
}
|
||||
|
||||
~PibDbTestFixture()
|
||||
{
|
||||
boost::filesystem::remove_all(tmpPath);
|
||||
}
|
||||
|
||||
boost::asio::io_service io;
|
||||
boost::filesystem::path tmpPath;
|
||||
PibDb db;
|
||||
std::vector<Name> deletedIds;
|
||||
std::vector<Name> deletedKeys;
|
||||
std::vector<Name> deletedCerts;
|
||||
std::vector<Name> insertedCerts;
|
||||
};
|
||||
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(PibPibDb, PibDbTestFixture)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MgmtTest)
|
||||
{
|
||||
Name testUser("/localhost/pib/test/mgmt");
|
||||
addIdentity(testUser);
|
||||
Name testUserCertName = m_keyChain.getDefaultCertificateNameForIdentity(testUser);
|
||||
shared_ptr<IdentityCertificate> testUserCert = m_keyChain.getCertificate(testUserCertName);
|
||||
|
||||
|
||||
BOOST_CHECK_EQUAL(db.getOwnerName(), "");
|
||||
BOOST_CHECK(db.getMgmtCertificate() == nullptr);
|
||||
|
||||
db.updateMgmtCertificate(*testUserCert);
|
||||
BOOST_CHECK_EQUAL(db.getOwnerName(), "test");
|
||||
BOOST_REQUIRE(db.getMgmtCertificate() != nullptr);
|
||||
BOOST_CHECK_EQUAL(db.getMgmtCertificate()->getName(), testUserCertName);
|
||||
|
||||
db.setTpmLocator("tpmLocator");
|
||||
BOOST_CHECK_EQUAL(db.getTpmLocator(), "tpmLocator");
|
||||
|
||||
Name testUser2("/localhost/pib/test2/mgmt");
|
||||
addIdentity(testUser2);
|
||||
Name testUser2CertName = m_keyChain.getDefaultCertificateNameForIdentity(testUser2);
|
||||
shared_ptr<IdentityCertificate> testUser2Cert = m_keyChain.getCertificate(testUser2CertName);
|
||||
|
||||
BOOST_CHECK_THROW(db.updateMgmtCertificate(*testUser2Cert), PibDb::Error);
|
||||
|
||||
Name testUserKeyName2 = m_keyChain.generateRsaKeyPairAsDefault(testUser);
|
||||
shared_ptr<IdentityCertificate> testUserCert2 = m_keyChain.selfSign(testUserKeyName2);
|
||||
|
||||
BOOST_CHECK_NO_THROW(db.updateMgmtCertificate(*testUserCert2));
|
||||
BOOST_REQUIRE(db.getMgmtCertificate() != nullptr);
|
||||
BOOST_CHECK_EQUAL(db.getMgmtCertificate()->getName(),
|
||||
testUserCert2->getName());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(IdentityTest)
|
||||
{
|
||||
db.identityDeleted.connect([this] (const Name& id) {
|
||||
this->deletedIds.push_back(id);
|
||||
});
|
||||
|
||||
Name identity("/test/identity");
|
||||
Name identity2("/test/identity2");
|
||||
|
||||
// Add an identity: /test/identity
|
||||
// Since there is no default identity,
|
||||
// the new added identity will be set as the default identity.
|
||||
BOOST_CHECK_EQUAL(db.getDefaultIdentity(), PibDb::NON_EXISTING_IDENTITY);
|
||||
db.addIdentity(identity);
|
||||
BOOST_CHECK(db.hasIdentity(identity));
|
||||
BOOST_CHECK_EQUAL(db.getDefaultIdentity(), identity);
|
||||
|
||||
// Add the second identity: /test/identity2
|
||||
// Since the default identity exists,
|
||||
// the new added identity will not be set as the default identity.
|
||||
db.addIdentity(identity2);
|
||||
BOOST_CHECK_EQUAL(db.hasIdentity(identity2), true);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultIdentity(), identity);
|
||||
|
||||
// Set the second identity: /test/identity2 as default explicitly
|
||||
db.setDefaultIdentity(identity2);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultIdentity(), identity2);
|
||||
|
||||
// Delete identity /test/identity2, which is also the default one
|
||||
// This will trigger the identityDeleted signal
|
||||
// and also causes no default identity.
|
||||
db.deleteIdentity(identity2);
|
||||
BOOST_CHECK_EQUAL(db.hasIdentity(identity2), false);
|
||||
BOOST_CHECK_EQUAL(db.hasIdentity(identity), true);
|
||||
BOOST_CHECK_EQUAL(deletedIds.size(), 1);
|
||||
BOOST_CHECK_EQUAL(deletedIds[0], identity2);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultIdentity(), PibDb::NON_EXISTING_IDENTITY);
|
||||
deletedIds.clear();
|
||||
|
||||
// Add the second identity back
|
||||
// Since there is no default identity (though another identity still exists),
|
||||
// the second identity will be set as default.
|
||||
db.addIdentity(identity2);
|
||||
BOOST_CHECK_EQUAL(db.hasIdentity(identity2), true);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultIdentity(), identity2);
|
||||
|
||||
// Delete identity /test/identity
|
||||
db.deleteIdentity(identity);
|
||||
BOOST_CHECK_EQUAL(db.hasIdentity(identity), false);
|
||||
BOOST_CHECK_EQUAL(db.hasIdentity(identity2), true);
|
||||
BOOST_CHECK_EQUAL(deletedIds.size(), 1);
|
||||
BOOST_CHECK_EQUAL(deletedIds[0], identity);
|
||||
deletedIds.clear();
|
||||
|
||||
// Delete identity /test/identity2
|
||||
db.deleteIdentity(identity2);
|
||||
BOOST_CHECK_EQUAL(db.hasIdentity(identity), false);
|
||||
BOOST_CHECK_EQUAL(db.hasIdentity(identity2), false);
|
||||
BOOST_CHECK_EQUAL(deletedIds.size(), 1);
|
||||
BOOST_CHECK_EQUAL(deletedIds[0], identity2);
|
||||
deletedIds.clear();
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(KeyTest)
|
||||
{
|
||||
db.identityDeleted.connect([this] (const Name& id) {
|
||||
this->deletedIds.push_back(id);
|
||||
});
|
||||
|
||||
db.keyDeleted.connect([this] (const Name& key) {
|
||||
this->deletedKeys.push_back(key);
|
||||
});
|
||||
|
||||
// Initialize id1
|
||||
Name id1("/test/identity");
|
||||
addIdentity(id1);
|
||||
Name certName111 = m_keyChain.getDefaultCertificateNameForIdentity(id1);
|
||||
shared_ptr<IdentityCertificate> cert111 = m_keyChain.getCertificate(certName111);
|
||||
Name keyName11 = cert111->getPublicKeyName();
|
||||
PublicKey& key11 = cert111->getPublicKeyInfo();
|
||||
|
||||
advanceClocks(io, time::milliseconds(100));
|
||||
Name keyName12 = m_keyChain.generateRsaKeyPairAsDefault(id1);
|
||||
shared_ptr<IdentityCertificate> cert121 = m_keyChain.selfSign(keyName12);
|
||||
PublicKey& key12 = cert121->getPublicKeyInfo();
|
||||
|
||||
// Initialize id2
|
||||
advanceClocks(io, time::milliseconds(100));
|
||||
Name id2("/test/identity2");
|
||||
addIdentity(id2);
|
||||
Name certName211 = m_keyChain.getDefaultCertificateNameForIdentity(id2);
|
||||
shared_ptr<IdentityCertificate> cert211 = m_keyChain.getCertificate(certName211);
|
||||
Name keyName21 = cert211->getPublicKeyName();
|
||||
PublicKey& key21 = cert211->getPublicKeyInfo();
|
||||
|
||||
advanceClocks(io, time::milliseconds(100));
|
||||
Name keyName22 = m_keyChain.generateRsaKeyPairAsDefault(id2);
|
||||
shared_ptr<IdentityCertificate> cert221 = m_keyChain.selfSign(keyName22);
|
||||
PublicKey& key22 = cert221->getPublicKeyInfo();
|
||||
|
||||
// Add a key, the corresponding identity should be added as well
|
||||
// Since the PIB does not have any default identity set before,
|
||||
// the added identity will be set as default.
|
||||
// Since there is no default key for the identity,
|
||||
// the added key will be set as default.
|
||||
BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), PibDb::NON_EXISTING_KEY);
|
||||
BOOST_CHECK(db.getKey(keyName11) == nullptr);
|
||||
db.addKey(keyName11, key11);
|
||||
BOOST_CHECK(db.hasIdentity(id1));
|
||||
BOOST_CHECK(db.getKey(keyName11) != nullptr);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultIdentity(), id1);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), keyName11);
|
||||
|
||||
// Add the second key of /test/identity.
|
||||
// Since the default key of /test/identity has been set,
|
||||
// The new added key will not be set as default.
|
||||
db.addKey(keyName12, key12);
|
||||
BOOST_CHECK(db.getKey(keyName12) != nullptr);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), keyName11);
|
||||
|
||||
// Explicitly set the second key as the default key of /test/identity
|
||||
db.setDefaultKeyNameOfIdentity(keyName12);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), keyName12);
|
||||
|
||||
// Delete the second key which is also the default key.
|
||||
// This will trigger the keyDeleted signal.
|
||||
// This will also cause no default key for /test/identity
|
||||
db.deleteKey(keyName12);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName12), false);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName11), true);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName22), false);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName21), false);
|
||||
BOOST_CHECK_EQUAL(deletedKeys.size(), 1);
|
||||
BOOST_CHECK_EQUAL(deletedKeys[0], keyName12);
|
||||
deletedKeys.clear();
|
||||
|
||||
// Add the second key back.
|
||||
// Since there is no default key of /test/identity (although another key still exists)
|
||||
// The second key will be set as the default key of /test/identity
|
||||
BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), PibDb::NON_EXISTING_KEY);
|
||||
db.addKey(keyName12, key12);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), keyName12);
|
||||
|
||||
// Prepare test for identity deletion
|
||||
db.addKey(keyName21, key21);
|
||||
db.addKey(keyName22, key22);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName12), true);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName22), true);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName21), true);
|
||||
BOOST_CHECK_EQUAL(db.hasIdentity(id2), true);
|
||||
|
||||
// Delete the identity.
|
||||
// All keys of the identity should also be deleted,
|
||||
// and the keyDeleted signal should be triggered twice.
|
||||
db.deleteIdentity(id1);
|
||||
BOOST_CHECK_EQUAL(db.hasIdentity(id1), false);
|
||||
BOOST_CHECK_EQUAL(db.hasIdentity(id2), true);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName11), false);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName12), false);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName21), true);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName22), true);
|
||||
BOOST_CHECK_EQUAL(deletedKeys.size(), 2);
|
||||
BOOST_CHECK(std::find(deletedKeys.begin(), deletedKeys.end(), keyName11) !=
|
||||
deletedKeys.end());
|
||||
BOOST_CHECK(std::find(deletedKeys.begin(), deletedKeys.end(), keyName12) !=
|
||||
deletedKeys.end());
|
||||
BOOST_CHECK_EQUAL(deletedIds.size(), 1);
|
||||
BOOST_CHECK_EQUAL(deletedIds[0], id1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CertTest)
|
||||
{
|
||||
db.identityDeleted.connect([this] (const Name& id) {
|
||||
this->deletedIds.push_back(id);
|
||||
});
|
||||
|
||||
db.keyDeleted.connect([this] (const Name& key) {
|
||||
this->deletedKeys.push_back(key);
|
||||
});
|
||||
|
||||
db.certificateDeleted.connect([this] (const Name& certificate) {
|
||||
this->deletedCerts.push_back(certificate);
|
||||
});
|
||||
|
||||
db.certificateInserted.connect([this] (const Name& certificate) {
|
||||
this->insertedCerts.push_back(certificate);
|
||||
});
|
||||
|
||||
// Initialize id1
|
||||
Name id1("/test/identity");
|
||||
addIdentity(id1);
|
||||
Name certName111 = m_keyChain.getDefaultCertificateNameForIdentity(id1);
|
||||
shared_ptr<IdentityCertificate> cert111 = m_keyChain.getCertificate(certName111);
|
||||
Name keyName11 = cert111->getPublicKeyName();
|
||||
|
||||
advanceClocks(io, time::milliseconds(100));
|
||||
shared_ptr<IdentityCertificate> cert112 = m_keyChain.selfSign(keyName11);
|
||||
Name certName112 = cert112->getName();
|
||||
|
||||
advanceClocks(io, time::milliseconds(100));
|
||||
Name keyName12 = m_keyChain.generateRsaKeyPairAsDefault(id1);
|
||||
shared_ptr<IdentityCertificate> cert121 = m_keyChain.selfSign(keyName12);
|
||||
Name certName121 = cert121->getName();
|
||||
|
||||
advanceClocks(io, time::milliseconds(100));
|
||||
shared_ptr<IdentityCertificate> cert122 = m_keyChain.selfSign(keyName12);
|
||||
Name certName122 = cert122->getName();
|
||||
|
||||
// Initialize id2
|
||||
advanceClocks(io, time::milliseconds(100));
|
||||
Name id2("/test/identity2");
|
||||
addIdentity(id2);
|
||||
Name certName211 = m_keyChain.getDefaultCertificateNameForIdentity(id2);
|
||||
shared_ptr<IdentityCertificate> cert211 = m_keyChain.getCertificate(certName211);
|
||||
Name keyName21 = cert211->getPublicKeyName();
|
||||
|
||||
advanceClocks(io, time::milliseconds(100));
|
||||
shared_ptr<IdentityCertificate> cert212 = m_keyChain.selfSign(keyName21);
|
||||
Name certName212 = cert212->getName();
|
||||
|
||||
advanceClocks(io, time::milliseconds(100));
|
||||
Name keyName22 = m_keyChain.generateRsaKeyPairAsDefault(id2);
|
||||
shared_ptr<IdentityCertificate> cert221 = m_keyChain.selfSign(keyName22);
|
||||
Name certName221 = cert221->getName();
|
||||
|
||||
advanceClocks(io, time::milliseconds(100));
|
||||
shared_ptr<IdentityCertificate> cert222 = m_keyChain.selfSign(keyName22);
|
||||
Name certName222 = cert222->getName();
|
||||
|
||||
// Add a certificate
|
||||
// This will also add the corresponding key and identity.
|
||||
// Since there is no default setting before,
|
||||
// The certificate will be set as the default one of the key, and so be the key and identity
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName111), false);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName11), false);
|
||||
BOOST_CHECK_EQUAL(db.hasIdentity(id1), false);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), PibDb::NON_EXISTING_CERTIFICATE);
|
||||
db.addCertificate(*cert111);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName111), true);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName11), true);
|
||||
BOOST_CHECK_EQUAL(db.hasIdentity(id1), true);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultIdentity(), id1);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), keyName11);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), certName111);
|
||||
BOOST_CHECK_EQUAL(insertedCerts.size(), 1);
|
||||
BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName111) !=
|
||||
insertedCerts.end());
|
||||
insertedCerts.clear();
|
||||
|
||||
// Add the second certificate of the same key
|
||||
// Since default certificate already exists, no default setting changes.
|
||||
BOOST_CHECK(db.getCertificate(certName112) == nullptr);
|
||||
db.addCertificate(*cert112);
|
||||
BOOST_CHECK(db.getCertificate(certName112) != nullptr);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), certName111);
|
||||
BOOST_CHECK_EQUAL(insertedCerts.size(), 1);
|
||||
BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName112) !=
|
||||
insertedCerts.end());
|
||||
insertedCerts.clear();
|
||||
|
||||
// Explicitly set the second certificate as the default one of the key.
|
||||
db.setDefaultCertNameOfKey(certName112);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), certName112);
|
||||
|
||||
// Delete the default certificate
|
||||
// This will trigger certificateDeleted signal
|
||||
// and also causes no default certificate for the key.
|
||||
db.deleteCertificate(certName112);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName112), false);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName111), true);
|
||||
BOOST_CHECK_EQUAL(deletedCerts.size(), 1);
|
||||
BOOST_CHECK_EQUAL(deletedCerts[0], certName112);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), PibDb::NON_EXISTING_CERTIFICATE);
|
||||
deletedCerts.clear();
|
||||
|
||||
// Add the second certificate back
|
||||
// Since there is no default certificate of the key (though another certificate still exists),
|
||||
// the new added certificate will be set as default
|
||||
db.addCertificate(*cert112);
|
||||
BOOST_CHECK(db.getCertificate(certName112) != nullptr);
|
||||
BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), certName112);
|
||||
insertedCerts.clear();
|
||||
|
||||
// Add entries for delete tests
|
||||
db.addCertificate(*cert111); // already exists no certInserted signal emitted
|
||||
db.addCertificate(*cert112); // already exists no certInserted signal emitted
|
||||
db.addCertificate(*cert121);
|
||||
db.addCertificate(*cert122);
|
||||
db.addCertificate(*cert211);
|
||||
db.addCertificate(*cert212);
|
||||
db.addCertificate(*cert221);
|
||||
db.addCertificate(*cert222);
|
||||
BOOST_CHECK_EQUAL(insertedCerts.size(), 6);
|
||||
BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName121) !=
|
||||
insertedCerts.end());
|
||||
BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName122) !=
|
||||
insertedCerts.end());
|
||||
BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName211) !=
|
||||
insertedCerts.end());
|
||||
BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName212) !=
|
||||
insertedCerts.end());
|
||||
BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName221) !=
|
||||
insertedCerts.end());
|
||||
BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName222) !=
|
||||
insertedCerts.end());
|
||||
insertedCerts.clear();
|
||||
|
||||
// Delete the key.
|
||||
// All the related certificates will be deleted as well.
|
||||
db.deleteKey(keyName11);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName112), false);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName111), false);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName122), true);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName121), true);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName212), true);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName211), true);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName222), true);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName221), true);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName11), false);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName12), true);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName21), true);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName22), true);
|
||||
BOOST_CHECK_EQUAL(deletedCerts.size(), 2);
|
||||
BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName111) !=
|
||||
deletedCerts.end());
|
||||
BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName112) !=
|
||||
deletedCerts.end());
|
||||
BOOST_CHECK_EQUAL(deletedKeys.size(), 1);
|
||||
BOOST_CHECK_EQUAL(deletedKeys[0], keyName11);
|
||||
deletedCerts.clear();
|
||||
deletedKeys.clear();
|
||||
|
||||
// Recover deleted entries
|
||||
db.addCertificate(*cert111);
|
||||
db.addCertificate(*cert112);
|
||||
|
||||
// Delete the identity
|
||||
// All the related certificates and keys will be deleted as well.
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName111), true);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName112), true);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName11), true);
|
||||
BOOST_CHECK_EQUAL(db.hasIdentity(id1), true);
|
||||
db.deleteIdentity(id1);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName112), false);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName111), false);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName122), false);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName121), false);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName212), true);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName211), true);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName222), true);
|
||||
BOOST_CHECK_EQUAL(db.hasCertificate(certName221), true);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName11), false);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName12), false);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName21), true);
|
||||
BOOST_CHECK_EQUAL(db.hasKey(keyName22), true);
|
||||
BOOST_CHECK_EQUAL(db.hasIdentity(id1), false);
|
||||
BOOST_CHECK_EQUAL(db.hasIdentity(id2), true);
|
||||
BOOST_CHECK_EQUAL(deletedCerts.size(), 4);
|
||||
BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName111) !=
|
||||
deletedCerts.end());
|
||||
BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName112) !=
|
||||
deletedCerts.end());
|
||||
BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName121) !=
|
||||
deletedCerts.end());
|
||||
BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName122) !=
|
||||
deletedCerts.end());
|
||||
BOOST_CHECK_EQUAL(deletedKeys.size(), 2);
|
||||
BOOST_CHECK(std::find(deletedKeys.begin(), deletedKeys.end(), keyName11) !=
|
||||
deletedKeys.end());
|
||||
BOOST_CHECK(std::find(deletedKeys.begin(), deletedKeys.end(), keyName12) !=
|
||||
deletedCerts.end());
|
||||
BOOST_CHECK_EQUAL(deletedIds.size(), 1);
|
||||
BOOST_CHECK_EQUAL(deletedIds[0], id1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
} // namespace tests
|
||||
} // namespace pib
|
||||
} // namespace ndn
|
||||
@@ -1,137 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Yingdi Yu <yingdi@cs.ucla.edu>
|
||||
*/
|
||||
|
||||
#include "tools/pib/pib-validator.hpp"
|
||||
#include "tools/pib/encoding/update-param.hpp"
|
||||
#include "tools/pib/encoding/delete-param.hpp"
|
||||
#include <ndn-cxx/security/key-chain.hpp>
|
||||
|
||||
#include "../identity-management-time-fixture.hpp"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "tests/test-common.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace pib {
|
||||
namespace tests {
|
||||
|
||||
class PibValidatorFixture : public ndn::tests::IdentityManagementTimeFixture
|
||||
{
|
||||
public:
|
||||
PibValidatorFixture()
|
||||
: tmpPath(boost::filesystem::path(TMP_TESTS_PATH) / "DbTest")
|
||||
, db(tmpPath.c_str())
|
||||
{
|
||||
}
|
||||
|
||||
~PibValidatorFixture()
|
||||
{
|
||||
boost::filesystem::remove_all(tmpPath);
|
||||
}
|
||||
|
||||
boost::asio::io_service io;
|
||||
boost::filesystem::path tmpPath;
|
||||
PibDb db;
|
||||
bool isProcessed;
|
||||
};
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(PibPibValidator, PibValidatorFixture)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Basic)
|
||||
{
|
||||
PibValidator validator(db);
|
||||
|
||||
Name testUser("/localhost/pib/test/mgmt");
|
||||
BOOST_REQUIRE(addIdentity(testUser, RsaKeyParams()));
|
||||
Name testUserCertName = m_keyChain.getDefaultCertificateNameForIdentity(testUser);
|
||||
shared_ptr<IdentityCertificate> testUserCert = m_keyChain.getCertificate(testUserCertName);
|
||||
|
||||
advanceClocks(io, time::milliseconds(100));
|
||||
Name testUser2("/localhost/pib/test2/mgmt");
|
||||
BOOST_REQUIRE(addIdentity(testUser2, RsaKeyParams()));
|
||||
|
||||
db.updateMgmtCertificate(*testUserCert);
|
||||
|
||||
advanceClocks(io, time::milliseconds(100));
|
||||
Name normalId("/normal/id");
|
||||
BOOST_REQUIRE(addIdentity(normalId, RsaKeyParams()));
|
||||
Name normalIdCertName = m_keyChain.getDefaultCertificateNameForIdentity(normalId);
|
||||
shared_ptr<IdentityCertificate> normalIdCert = m_keyChain.getCertificate(normalIdCertName);
|
||||
|
||||
db.addIdentity(normalId);
|
||||
db.addKey(normalIdCert->getPublicKeyName(), normalIdCert->getPublicKeyInfo());
|
||||
db.addCertificate(*normalIdCert);
|
||||
|
||||
Name command1("/localhost/pib/test/verb/param");
|
||||
shared_ptr<Interest> interest1 = make_shared<Interest>(command1);
|
||||
m_keyChain.signByIdentity(*interest1, testUser);
|
||||
// "test" user is trusted for any command about itself, OK.
|
||||
isProcessed = false;
|
||||
validator.validate(*interest1,
|
||||
[this] (const shared_ptr<const Interest>&) {
|
||||
isProcessed = true;
|
||||
BOOST_CHECK(true);
|
||||
},
|
||||
[this] (const shared_ptr<const Interest>&, const std::string&) {
|
||||
isProcessed = true;
|
||||
BOOST_CHECK(false);
|
||||
});
|
||||
BOOST_CHECK(isProcessed);
|
||||
|
||||
Name command2("/localhost/pib/test/verb/param");
|
||||
shared_ptr<Interest> interest2 = make_shared<Interest>(command2);
|
||||
m_keyChain.signByIdentity(*interest2, testUser2);
|
||||
// "test2" user is NOT trusted for any command about other user, MUST fail
|
||||
isProcessed = false;
|
||||
validator.validate(*interest2,
|
||||
[this] (const shared_ptr<const Interest>&) {
|
||||
isProcessed = true;
|
||||
BOOST_CHECK(false);
|
||||
},
|
||||
[this] (const shared_ptr<const Interest>&, const std::string&) {
|
||||
isProcessed = true;
|
||||
BOOST_CHECK(true);
|
||||
});
|
||||
BOOST_CHECK(isProcessed);
|
||||
|
||||
Name command3("/localhost/pib/test/verb/param");
|
||||
shared_ptr<Interest> interest3 = make_shared<Interest>(command3);
|
||||
m_keyChain.signByIdentity(*interest3, normalId);
|
||||
// "normalId" is in "test" pib, can be trusted for some commands about "test".
|
||||
// Detail checking is needed, but it is not the job of Validator, OK.
|
||||
isProcessed = false;
|
||||
validator.validate(*interest3,
|
||||
[this] (const shared_ptr<const Interest>&) {
|
||||
isProcessed = true;
|
||||
BOOST_CHECK(true);
|
||||
},
|
||||
[this] (const shared_ptr<const Interest>&, const std::string&) {
|
||||
isProcessed = true;
|
||||
BOOST_CHECK(false);
|
||||
});
|
||||
BOOST_CHECK(isProcessed);
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
} // namespace tests
|
||||
} // namespace pib
|
||||
} // namespace ndn
|
||||
-1389
File diff suppressed because it is too large
Load Diff
@@ -1,64 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Yingdi Yu <yingdi@cs.ucla.edu>
|
||||
*/
|
||||
|
||||
#include "tools/pib/response-cache.hpp"
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace pib {
|
||||
namespace tests {
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(PibResponseCache)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Basic)
|
||||
{
|
||||
ResponseCache cache;
|
||||
|
||||
Name dataName("/test/data");
|
||||
dataName.appendVersion();
|
||||
shared_ptr<Data> data = make_shared<Data>(dataName);
|
||||
|
||||
Name dataNameNoVersion("/test/data");
|
||||
Name anotherDataName("/test/another");
|
||||
|
||||
BOOST_CHECK_EQUAL(static_cast<bool>(cache.find(dataNameNoVersion)), false);
|
||||
BOOST_CHECK_EQUAL(static_cast<bool>(cache.find(dataName, true)), false);
|
||||
|
||||
cache.insert(*data);
|
||||
|
||||
BOOST_CHECK(static_cast<bool>(cache.find(dataNameNoVersion)));
|
||||
BOOST_CHECK(static_cast<bool>(cache.find(dataName, true)));
|
||||
BOOST_CHECK_EQUAL(static_cast<bool>(cache.find(anotherDataName)), false);
|
||||
BOOST_CHECK_EQUAL(static_cast<bool>(cache.find(anotherDataName, true)), false);
|
||||
|
||||
cache.erase(dataNameNoVersion);
|
||||
|
||||
BOOST_CHECK_EQUAL(static_cast<bool>(cache.find(dataNameNoVersion)), false);
|
||||
BOOST_CHECK_EQUAL(static_cast<bool>(cache.find(dataName, true)), false);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
} // namespace tests
|
||||
} // namespace pib
|
||||
} // namespace ndn
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Arizona Board of Regents.
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Arizona Board of Regents.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
@@ -18,9 +18,11 @@
|
||||
*/
|
||||
|
||||
#include "tools/ping/client/ping.hpp"
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include "tests/io-fixture.hpp"
|
||||
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
namespace ndn {
|
||||
namespace ping {
|
||||
@@ -29,91 +31,70 @@ namespace tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(PingClientPing)
|
||||
BOOST_AUTO_TEST_SUITE(Ping)
|
||||
BOOST_AUTO_TEST_SUITE(TestClient)
|
||||
|
||||
class SequenceNumberIncrementFixture : public UnitTestTimeFixture
|
||||
using client::Ping;
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(Basic, IoFixture)
|
||||
{
|
||||
protected:
|
||||
SequenceNumberIncrementFixture()
|
||||
: face(util::makeDummyClientFace(io, {false, true}))
|
||||
, pingOptions(makeOptions())
|
||||
, ping(*face, pingOptions)
|
||||
, numPings(0)
|
||||
, lastPingSeq(pingOptions.startSeq)
|
||||
{
|
||||
ping.afterResponse.connect(bind(&SequenceNumberIncrementFixture::onResponse, this, _1));
|
||||
ping.afterTimeout.connect(bind(&SequenceNumberIncrementFixture::onTimeout, this, _1));
|
||||
}
|
||||
|
||||
public:
|
||||
void
|
||||
onResponse(uint64_t seq)
|
||||
{
|
||||
numPings++;
|
||||
lastPingSeq = seq;
|
||||
if (numPings == maxPings) {
|
||||
face->shutdown();
|
||||
io.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
onTimeout(uint64_t seq)
|
||||
{
|
||||
numPings++;
|
||||
lastPingSeq = seq;
|
||||
if (numPings == maxPings) {
|
||||
face->shutdown();
|
||||
io.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static Options
|
||||
makeOptions()
|
||||
{
|
||||
Options opt;
|
||||
opt.prefix = "ndn:/test-prefix";
|
||||
opt.shouldAllowStaleData = false;
|
||||
opt.shouldGenerateRandomSeq = false;
|
||||
opt.shouldPrintTimestamp = false;
|
||||
opt.nPings = 4;
|
||||
opt.interval = time::milliseconds(100);
|
||||
opt.timeout = time::milliseconds(1000);
|
||||
opt.startSeq = 1000;
|
||||
return opt;
|
||||
}
|
||||
|
||||
protected:
|
||||
boost::asio::io_service io;
|
||||
shared_ptr<util::DummyClientFace> face;
|
||||
util::DummyClientFace face(m_io, {true, true});
|
||||
Options pingOptions;
|
||||
Ping ping;
|
||||
uint32_t numPings;
|
||||
uint32_t maxPings;
|
||||
uint64_t lastPingSeq;
|
||||
KeyChain keyChain;
|
||||
};
|
||||
pingOptions.prefix = "/test-prefix";
|
||||
pingOptions.shouldAllowStaleData = false;
|
||||
pingOptions.shouldGenerateRandomSeq = false;
|
||||
pingOptions.shouldPrintTimestamp = false;
|
||||
pingOptions.nPings = 4;
|
||||
pingOptions.interval = 100_ms;
|
||||
pingOptions.timeout = 2_s;
|
||||
pingOptions.startSeq = 1000;
|
||||
Ping ping(face, pingOptions);
|
||||
|
||||
int nFinishSignals = 0;
|
||||
std::vector<uint64_t> dataSeqs;
|
||||
std::vector<uint64_t> nackSeqs;
|
||||
std::vector<uint64_t> timeoutSeqs;
|
||||
|
||||
ping.afterData.connect([&] (uint64_t seq, auto&&...) { dataSeqs.push_back(seq); });
|
||||
ping.afterNack.connect([&] (uint64_t seq, auto&&...) { nackSeqs.push_back(seq); });
|
||||
ping.afterTimeout.connect([&] (uint64_t seq, auto&&...) { timeoutSeqs.push_back(seq); });
|
||||
ping.afterFinish.connect([&] {
|
||||
BOOST_REQUIRE_EQUAL(dataSeqs.size(), 2);
|
||||
BOOST_REQUIRE_EQUAL(nackSeqs.size(), 1);
|
||||
BOOST_REQUIRE_EQUAL(timeoutSeqs.size(), 1);
|
||||
|
||||
BOOST_CHECK_EQUAL(dataSeqs[0], 1000);
|
||||
BOOST_CHECK_EQUAL(nackSeqs[0], 1001);
|
||||
BOOST_CHECK_EQUAL(dataSeqs[1], 1002);
|
||||
BOOST_CHECK_EQUAL(timeoutSeqs[0], 1003);
|
||||
|
||||
nFinishSignals++;
|
||||
});
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(SequenceNumberIncrement, SequenceNumberIncrementFixture)
|
||||
{
|
||||
maxPings = 4;
|
||||
ping.start();
|
||||
|
||||
this->advanceClocks(io, time::milliseconds(1), 400);
|
||||
this->advanceClocks(1_ms, 500);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 4);
|
||||
|
||||
face->receive(*makeData("ndn:/test-prefix/ping/1000"));
|
||||
face->receive(*makeData("ndn:/test-prefix/ping/1001"));
|
||||
face->receive(*makeData("ndn:/test-prefix/ping/1002"));
|
||||
face->receive(*makeData("ndn:/test-prefix/ping/1003"));
|
||||
auto data = makeData("/test-prefix/ping/1000");
|
||||
data->setFreshnessPeriod(1_s);
|
||||
face.receive(*data);
|
||||
|
||||
io.run();
|
||||
face.receive(makeNack(face.sentInterests[1], lp::NackReason::DUPLICATE));
|
||||
|
||||
BOOST_REQUIRE_EQUAL(1003, lastPingSeq);
|
||||
BOOST_REQUIRE_EQUAL(4, numPings);
|
||||
data = makeData("/test-prefix/ping/1002");
|
||||
data->setFreshnessPeriod(1_s);
|
||||
face.receive(*data);
|
||||
|
||||
this->advanceClocks(100_ms, 20);
|
||||
|
||||
// /test-prefix/ping/1003 is unanswered and will timeout
|
||||
|
||||
BOOST_CHECK_EQUAL(nFinishSignals, 1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestClient
|
||||
BOOST_AUTO_TEST_SUITE_END() // Ping
|
||||
|
||||
} // namespace tests
|
||||
} // namespace client
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Arizona Board of Regents.
|
||||
* Copyright (c) 2014-2016, Arizona Board of Regents.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
@@ -18,9 +18,9 @@
|
||||
*/
|
||||
|
||||
#include "tools/ping/client/statistics-collector.hpp"
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
namespace ndn {
|
||||
namespace ping {
|
||||
@@ -33,9 +33,8 @@ class StatisticsCollectorFixture
|
||||
{
|
||||
protected:
|
||||
StatisticsCollectorFixture()
|
||||
: face(util::makeDummyClientFace())
|
||||
, pingOptions(makeOptions())
|
||||
, pingProgram(*face, pingOptions)
|
||||
: pingOptions(makeOptions())
|
||||
, pingProgram(face, pingOptions)
|
||||
, sc(pingProgram, pingOptions)
|
||||
{
|
||||
}
|
||||
@@ -57,17 +56,18 @@ private:
|
||||
}
|
||||
|
||||
protected:
|
||||
shared_ptr<util::DummyClientFace> face;
|
||||
util::DummyClientFace face;
|
||||
Options pingOptions;
|
||||
Ping pingProgram;
|
||||
StatisticsCollector sc;
|
||||
};
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(PingClientStatisticsCollector, StatisticsCollectorFixture)
|
||||
BOOST_AUTO_TEST_SUITE(Ping)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestStatisticsCollector, StatisticsCollectorFixture)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Resp50msResp50ms)
|
||||
{
|
||||
sc.recordResponse(time::milliseconds(50));
|
||||
sc.recordData(time::milliseconds(50));
|
||||
|
||||
Statistics stats1 = sc.computeStatistics();
|
||||
BOOST_CHECK_EQUAL(stats1.prefix, pingOptions.prefix);
|
||||
@@ -80,7 +80,7 @@ BOOST_AUTO_TEST_CASE(Resp50msResp50ms)
|
||||
BOOST_CHECK_CLOSE(stats1.avgRtt, 50.0, 0.001);
|
||||
BOOST_CHECK_CLOSE(stats1.stdDevRtt, 0.0, 0.001);
|
||||
|
||||
sc.recordResponse(time::milliseconds(50));
|
||||
sc.recordData(time::milliseconds(50));
|
||||
|
||||
Statistics stats2 = sc.computeStatistics();
|
||||
BOOST_CHECK_EQUAL(stats2.prefix, pingOptions.prefix);
|
||||
@@ -96,8 +96,8 @@ BOOST_AUTO_TEST_CASE(Resp50msResp50ms)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Resp50msResp100ms)
|
||||
{
|
||||
sc.recordResponse(time::milliseconds(50));
|
||||
sc.recordResponse(time::milliseconds(100));
|
||||
sc.recordData(time::milliseconds(50));
|
||||
sc.recordData(time::milliseconds(100));
|
||||
|
||||
Statistics stats = sc.computeStatistics();
|
||||
BOOST_CHECK_EQUAL(stats.prefix, pingOptions.prefix);
|
||||
@@ -120,12 +120,19 @@ BOOST_AUTO_TEST_CASE(LossLoss)
|
||||
BOOST_CHECK_EQUAL(stats.prefix, pingOptions.prefix);
|
||||
BOOST_CHECK_EQUAL(stats.nSent, 2);
|
||||
BOOST_CHECK_EQUAL(stats.nReceived, 0);
|
||||
BOOST_CHECK_EQUAL(stats.nNacked, 0);
|
||||
BOOST_CHECK_CLOSE(stats.packetLossRate, 1.0, 0.001);
|
||||
BOOST_CHECK_CLOSE(stats.packetNackedRate, 0.0, 0.001);
|
||||
BOOST_CHECK_CLOSE(stats.minRtt, std::numeric_limits<double>::max(), 0.001);
|
||||
BOOST_CHECK_CLOSE(stats.maxRtt, 0.0, 0.001);
|
||||
BOOST_CHECK_CLOSE(stats.sumRtt, 0.0, 0.001);
|
||||
BOOST_CHECK(std::isnan(stats.avgRtt));
|
||||
BOOST_CHECK(std::isnan(stats.stdDevRtt));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Resp50msLoss)
|
||||
{
|
||||
sc.recordResponse(time::milliseconds(50));
|
||||
sc.recordData(time::milliseconds(50));
|
||||
sc.recordTimeout();
|
||||
|
||||
Statistics stats = sc.computeStatistics();
|
||||
@@ -140,7 +147,69 @@ BOOST_AUTO_TEST_CASE(Resp50msLoss)
|
||||
BOOST_CHECK_CLOSE(stats.stdDevRtt, 0.0, 0.001);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
BOOST_AUTO_TEST_CASE(NackNack)
|
||||
{
|
||||
sc.recordNack();
|
||||
sc.recordNack();
|
||||
|
||||
Statistics stats = sc.computeStatistics();
|
||||
BOOST_CHECK_EQUAL(stats.prefix, pingOptions.prefix);
|
||||
BOOST_CHECK_EQUAL(stats.nSent, 2);
|
||||
BOOST_CHECK_EQUAL(stats.nNacked, 2);
|
||||
BOOST_CHECK_EQUAL(stats.nReceived, 0);
|
||||
BOOST_CHECK_CLOSE(stats.packetNackedRate, 1.0, 0.001);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Resp50msNack)
|
||||
{
|
||||
sc.recordData(time::milliseconds(50));
|
||||
sc.recordNack();
|
||||
|
||||
Statistics stats = sc.computeStatistics();
|
||||
BOOST_CHECK_EQUAL(stats.prefix, pingOptions.prefix);
|
||||
BOOST_CHECK_EQUAL(stats.nSent, 2);
|
||||
BOOST_CHECK_EQUAL(stats.nReceived, 1);
|
||||
BOOST_CHECK_CLOSE(stats.minRtt, 50.0, 0.001);
|
||||
BOOST_CHECK_CLOSE(stats.maxRtt, 50.0, 0.001);
|
||||
BOOST_CHECK_CLOSE(stats.sumRtt, 50.0, 0.001);
|
||||
BOOST_CHECK_CLOSE(stats.avgRtt, 50.0, 0.001);
|
||||
BOOST_CHECK_CLOSE(stats.stdDevRtt, 0.0, 0.001);
|
||||
BOOST_CHECK_EQUAL(stats.nNacked, 1);
|
||||
BOOST_CHECK_CLOSE(stats.packetNackedRate, 0.5, 0.001);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(NackLoss)
|
||||
{
|
||||
sc.recordNack();
|
||||
sc.recordTimeout();
|
||||
|
||||
Statistics stats = sc.computeStatistics();
|
||||
BOOST_CHECK_EQUAL(stats.prefix, pingOptions.prefix);
|
||||
BOOST_CHECK_EQUAL(stats.nSent, 2);
|
||||
BOOST_CHECK_EQUAL(stats.nReceived, 0);
|
||||
BOOST_CHECK_EQUAL(stats.nNacked, 1);
|
||||
BOOST_CHECK_CLOSE(stats.packetNackedRate, 0.5, 0.001);
|
||||
BOOST_CHECK_CLOSE(stats.packetLossRate, 0.5, 0.001);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(NoneSent)
|
||||
{
|
||||
Statistics stats = sc.computeStatistics();
|
||||
BOOST_CHECK_EQUAL(stats.prefix, pingOptions.prefix);
|
||||
BOOST_CHECK_EQUAL(stats.nSent, 0);
|
||||
BOOST_CHECK_EQUAL(stats.nReceived, 0);
|
||||
BOOST_CHECK_EQUAL(stats.nNacked, 0);
|
||||
BOOST_CHECK(std::isnan(stats.packetLossRate));
|
||||
BOOST_CHECK(std::isnan(stats.packetNackedRate));
|
||||
BOOST_CHECK_CLOSE(stats.minRtt, std::numeric_limits<double>::max(), 0.001);
|
||||
BOOST_CHECK_CLOSE(stats.maxRtt, 0.0, 0.001);
|
||||
BOOST_CHECK_CLOSE(stats.sumRtt, 0.0, 0.001);
|
||||
BOOST_CHECK(std::isnan(stats.avgRtt));
|
||||
BOOST_CHECK(std::isnan(stats.stdDevRtt));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestStatisticsCollector
|
||||
BOOST_AUTO_TEST_SUITE_END() // Ping
|
||||
|
||||
} // namespace tests
|
||||
} // namespace client
|
||||
|
||||
+48
-66
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Arizona Board of Regents.
|
||||
/*
|
||||
* Copyright (c) 2015-2020, Arizona Board of Regents.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
@@ -17,12 +17,14 @@
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tools/ping/server/ping-server.hpp"
|
||||
#include "tools/ping/client/ping.hpp"
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
#include "tools/ping/server/ping-server.hpp"
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include "../identity-management-time-fixture.hpp"
|
||||
#include "tests/io-fixture.hpp"
|
||||
#include "tests/key-chain-fixture.hpp"
|
||||
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
namespace ndn {
|
||||
namespace ping {
|
||||
@@ -30,71 +32,55 @@ namespace tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
class PingIntegratedFixture : public IdentityManagementTimeFixture
|
||||
class PingIntegratedFixture : public IoFixture, public KeyChainFixture
|
||||
{
|
||||
public:
|
||||
PingIntegratedFixture()
|
||||
: serverFace(util::makeDummyClientFace(io, {false, true}))
|
||||
, clientFace(util::makeDummyClientFace(io, {false, true}))
|
||||
, numResponses(0)
|
||||
: serverFace(m_io, m_keyChain, {false, true})
|
||||
, clientFace(m_io, m_keyChain, {false, true})
|
||||
, wantLoss(false)
|
||||
{
|
||||
serverFace->onSendInterest.connect([this] (const Interest& interest) {
|
||||
io.post([=] { if (!wantLoss) { clientFace->receive(interest); } });
|
||||
serverFace.onSendInterest.connect([this] (const Interest& interest) {
|
||||
m_io.post([=] { if (!wantLoss) { clientFace.receive(interest); } });
|
||||
});
|
||||
clientFace->onSendInterest.connect([this] (const Interest& interest) {
|
||||
io.post([=] { if (!wantLoss) { serverFace->receive(interest); } });
|
||||
clientFace.onSendInterest.connect([this] (const Interest& interest) {
|
||||
m_io.post([=] { if (!wantLoss) { serverFace.receive(interest); } });
|
||||
});
|
||||
serverFace->onSendData.connect([this] (const Data& data) {
|
||||
io.post([=] { if (!wantLoss) { clientFace->receive(data); } });
|
||||
serverFace.onSendData.connect([this] (const Data& data) {
|
||||
m_io.post([=] { if (!wantLoss) { clientFace.receive(data); } });
|
||||
});
|
||||
clientFace->onSendData.connect([this] (const Data& data) {
|
||||
io.post([=] { if (!wantLoss) { serverFace->receive(data); } });
|
||||
clientFace.onSendData.connect([this] (const Data& data) {
|
||||
m_io.post([=] { if (!wantLoss) { serverFace.receive(data); } });
|
||||
});
|
||||
}
|
||||
|
||||
void onTimeout(uint64_t seq)
|
||||
void onFinish()
|
||||
{
|
||||
numResponses++;
|
||||
if (numResponses == maxResponses) {
|
||||
serverFace->shutdown();
|
||||
clientFace->shutdown();
|
||||
io.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void onData(uint64_t seq)
|
||||
{
|
||||
numResponses++;
|
||||
if (numResponses == maxResponses) {
|
||||
serverFace->shutdown();
|
||||
clientFace->shutdown();
|
||||
io.stop();
|
||||
}
|
||||
serverFace.shutdown();
|
||||
clientFace.shutdown();
|
||||
m_io.stop();
|
||||
}
|
||||
|
||||
public:
|
||||
boost::asio::io_service io;
|
||||
shared_ptr<util::DummyClientFace> serverFace;
|
||||
shared_ptr<util::DummyClientFace> clientFace;
|
||||
util::DummyClientFace serverFace;
|
||||
util::DummyClientFace clientFace;
|
||||
std::unique_ptr<server::PingServer> server;
|
||||
std::unique_ptr<client::Ping> client;
|
||||
int maxResponses;
|
||||
int numResponses;
|
||||
bool wantLoss;
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(PingIntegrated)
|
||||
BOOST_AUTO_TEST_SUITE(Ping)
|
||||
BOOST_AUTO_TEST_SUITE(TestIntegrated)
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(Normal, PingIntegratedFixture)
|
||||
{
|
||||
server::Options serverOpts;
|
||||
serverOpts.prefix = "ndn:/test-prefix";
|
||||
serverOpts.freshnessPeriod = time::milliseconds(5000);
|
||||
serverOpts.freshnessPeriod = 5_s;
|
||||
serverOpts.nMaxPings = 4;
|
||||
serverOpts.shouldPrintTimestamp = false;
|
||||
serverOpts.wantTimestamp = false;
|
||||
serverOpts.payloadSize = 0;
|
||||
server.reset(new server::PingServer(*serverFace, m_keyChain, serverOpts));
|
||||
server = make_unique<server::PingServer>(serverFace, m_keyChain, serverOpts);
|
||||
BOOST_REQUIRE_EQUAL(0, server->getNPings());
|
||||
server->start();
|
||||
|
||||
@@ -104,19 +90,17 @@ BOOST_FIXTURE_TEST_CASE(Normal, PingIntegratedFixture)
|
||||
clientOpts.shouldGenerateRandomSeq = false;
|
||||
clientOpts.shouldPrintTimestamp = false;
|
||||
clientOpts.nPings = 4;
|
||||
clientOpts.interval = time::milliseconds(100);
|
||||
clientOpts.timeout = time::milliseconds(2000);
|
||||
clientOpts.interval = 100_ms;
|
||||
clientOpts.timeout = 2_s;
|
||||
clientOpts.startSeq = 1000;
|
||||
client.reset(new client::Ping(*clientFace, clientOpts));
|
||||
client->afterResponse.connect(bind(&PingIntegratedFixture::onData, this, _1));
|
||||
client->afterTimeout.connect(bind(&PingIntegratedFixture::onTimeout, this, _1));
|
||||
maxResponses = 4;
|
||||
client = make_unique<client::Ping>(clientFace, clientOpts);
|
||||
client->afterFinish.connect([this] { onFinish(); });
|
||||
client->start();
|
||||
|
||||
this->advanceClocks(io, time::milliseconds(1), 400);
|
||||
io.run();
|
||||
advanceClocks(1_ms, 400);
|
||||
m_io.run();
|
||||
|
||||
BOOST_REQUIRE_EQUAL(4, server->getNPings());
|
||||
BOOST_CHECK_EQUAL(4, server->getNPings());
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(Timeout, PingIntegratedFixture)
|
||||
@@ -125,11 +109,11 @@ BOOST_FIXTURE_TEST_CASE(Timeout, PingIntegratedFixture)
|
||||
|
||||
server::Options serverOpts;
|
||||
serverOpts.prefix = "ndn:/test-prefix";
|
||||
serverOpts.freshnessPeriod = time::milliseconds(5000);
|
||||
serverOpts.freshnessPeriod = 5_s;
|
||||
serverOpts.nMaxPings = 4;
|
||||
serverOpts.shouldPrintTimestamp = false;
|
||||
serverOpts.wantTimestamp = false;
|
||||
serverOpts.payloadSize = 0;
|
||||
server.reset(new server::PingServer(*serverFace, m_keyChain, serverOpts));
|
||||
server = make_unique<server::PingServer>(serverFace, m_keyChain, serverOpts);
|
||||
BOOST_REQUIRE_EQUAL(0, server->getNPings());
|
||||
server->start();
|
||||
|
||||
@@ -139,23 +123,21 @@ BOOST_FIXTURE_TEST_CASE(Timeout, PingIntegratedFixture)
|
||||
clientOpts.shouldGenerateRandomSeq = false;
|
||||
clientOpts.shouldPrintTimestamp = false;
|
||||
clientOpts.nPings = 4;
|
||||
clientOpts.interval = time::milliseconds(100);
|
||||
clientOpts.timeout = time::milliseconds(500);
|
||||
clientOpts.interval = 100_ms;
|
||||
clientOpts.timeout = 500_ms;
|
||||
clientOpts.startSeq = 1000;
|
||||
client.reset(new client::Ping(*clientFace, clientOpts));
|
||||
numResponses = 0;
|
||||
maxResponses = 4;
|
||||
client->afterResponse.connect(bind(&PingIntegratedFixture::onData, this, _1));
|
||||
client->afterTimeout.connect(bind(&PingIntegratedFixture::onTimeout, this, _1));
|
||||
client = make_unique<client::Ping>(clientFace, clientOpts);
|
||||
client->afterFinish.connect([this] { onFinish(); });
|
||||
client->start();
|
||||
|
||||
this->advanceClocks(io, time::milliseconds(1), 1000);
|
||||
io.run();
|
||||
advanceClocks(1_ms, 1000);
|
||||
m_io.run();
|
||||
|
||||
BOOST_REQUIRE_EQUAL(0, server->getNPings());
|
||||
BOOST_CHECK_EQUAL(0, server->getNPings());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestIntegrated
|
||||
BOOST_AUTO_TEST_SUITE_END() // Ping
|
||||
|
||||
} // namespace tests
|
||||
} // namespace ping
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Arizona Board of Regents.
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Arizona Board of Regents.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
@@ -18,10 +18,12 @@
|
||||
*/
|
||||
|
||||
#include "tools/ping/server/ping-server.hpp"
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include "../../identity-management-time-fixture.hpp"
|
||||
#include "tests/io-fixture.hpp"
|
||||
#include "tests/key-chain-fixture.hpp"
|
||||
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
namespace ndn {
|
||||
namespace ping {
|
||||
@@ -30,15 +32,16 @@ namespace tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(PingServerPingServer)
|
||||
BOOST_AUTO_TEST_SUITE(Ping)
|
||||
BOOST_AUTO_TEST_SUITE(TestServer)
|
||||
|
||||
class CreatePingServerFixture : public IdentityManagementTimeFixture
|
||||
class PingServerFixture : public IoFixture, public KeyChainFixture
|
||||
{
|
||||
protected:
|
||||
CreatePingServerFixture()
|
||||
: face(util::makeDummyClientFace(io, {false, true}))
|
||||
PingServerFixture()
|
||||
: face(m_io, m_keyChain, {false, true})
|
||||
, pingOptions(makeOptions())
|
||||
, pingServer(*face, m_keyChain, pingOptions)
|
||||
, pingServer(face, m_keyChain, pingOptions)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -46,12 +49,13 @@ protected:
|
||||
makePingInterest(int seq) const
|
||||
{
|
||||
Name name(pingOptions.prefix);
|
||||
name.append("ping");
|
||||
name.append(std::to_string(seq));
|
||||
Interest interest(name);
|
||||
interest.setMustBeFresh(true);
|
||||
interest.setInterestLifetime(time::milliseconds(2000));
|
||||
return interest;
|
||||
name.append("ping")
|
||||
.append(to_string(seq));
|
||||
|
||||
return Interest(name)
|
||||
.setCanBePrefix(false)
|
||||
.setMustBeFresh(true)
|
||||
.setInterestLifetime(2_s);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -59,37 +63,38 @@ private:
|
||||
makeOptions()
|
||||
{
|
||||
Options opt;
|
||||
opt.prefix = "ndn:/test-prefix";
|
||||
opt.freshnessPeriod = time::milliseconds(5000);
|
||||
opt.prefix = "/test-prefix";
|
||||
opt.freshnessPeriod = 5_s;
|
||||
opt.nMaxPings = 2;
|
||||
opt.shouldPrintTimestamp = false;
|
||||
opt.payloadSize = 0;
|
||||
opt.wantTimestamp = false;
|
||||
opt.wantQuiet = true;
|
||||
return opt;
|
||||
}
|
||||
|
||||
protected:
|
||||
boost::asio::io_service io;
|
||||
shared_ptr<util::DummyClientFace> face;
|
||||
util::DummyClientFace face;
|
||||
Options pingOptions;
|
||||
PingServer pingServer;
|
||||
};
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(CreatePingServer, CreatePingServerFixture)
|
||||
BOOST_FIXTURE_TEST_CASE(Receive, PingServerFixture)
|
||||
{
|
||||
BOOST_REQUIRE_EQUAL(0, pingServer.getNPings());
|
||||
BOOST_TEST(pingServer.getNPings() == 0);
|
||||
pingServer.start();
|
||||
|
||||
this->advanceClocks(io, time::milliseconds(1), 200);
|
||||
advanceClocks(1_ms, 200);
|
||||
|
||||
face->receive(makePingInterest(1000));
|
||||
face->receive(makePingInterest(1001));
|
||||
face.receive(makePingInterest(1000));
|
||||
face.receive(makePingInterest(1001));
|
||||
|
||||
io.run();
|
||||
m_io.run();
|
||||
|
||||
BOOST_REQUIRE_EQUAL(2, pingServer.getNPings());
|
||||
BOOST_TEST(pingServer.getNPings() == 2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestServer
|
||||
BOOST_AUTO_TEST_SUITE_END() // Ping
|
||||
|
||||
} // namespace tests
|
||||
} // namespace server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Arizona Board of Regents.
|
||||
/*
|
||||
* Copyright (c) 2014-2020 Arizona Board of Regents.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
@@ -17,22 +17,24 @@
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// #include "unit-under-test.hpp"
|
||||
// Unit being tested MUST be included first, to ensure header compiles on its own.
|
||||
// The unit being tested should be included first, to ensure the header compiles on its own.
|
||||
// For further information about test naming conventions, see
|
||||
// http://redmine.named-data.net/projects/nfd/wiki/UnitTesting
|
||||
// https://redmine.named-data.net/projects/nfd/wiki/UnitTesting
|
||||
//#include "unit-under-test.hpp"
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include "tests/io-fixture.hpp" // optional, for IoFixture
|
||||
//#include "tests/key-chain-fixture.hpp" // optional, for KeyChainFixture
|
||||
|
||||
namespace ndn {
|
||||
namespace tool_name {
|
||||
namespace tests {
|
||||
// Unit tests SHOULD go inside ndn::tool_name::tests namespace.
|
||||
// Unit tests should go inside the ndn::tool_name::tests namespace.
|
||||
|
||||
// Common fixtures in ndn::tests can be imported.
|
||||
// Common fixtures in ndn::tests can be imported if needed.
|
||||
using namespace ndn::tests;
|
||||
|
||||
// See http://redmine.named-data.net/projects/nfd/wiki/UnitTesting on how to name a test suite.
|
||||
// See https://redmine.named-data.net/projects/nfd/wiki/UnitTesting for a guide on how to name a test suite.
|
||||
BOOST_AUTO_TEST_SUITE(TestSkeleton)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Test1)
|
||||
@@ -40,18 +42,17 @@ BOOST_AUTO_TEST_CASE(Test1)
|
||||
int i = 0;
|
||||
|
||||
// For reference of available Boost.Test macros, see
|
||||
// http://www.boost.org/doc/libs/1_48_0/libs/test/doc/html/utf/testing-tools/reference.html
|
||||
// https://www.boost.org/doc/libs/1_65_1/libs/test/doc/html/boost_test/testing_tools/summary.html
|
||||
|
||||
BOOST_REQUIRE_NO_THROW(i = 1);
|
||||
BOOST_REQUIRE_EQUAL(i, 1);
|
||||
BOOST_CHECK_EQUAL(i, 1);
|
||||
}
|
||||
|
||||
// Use UnitTestTimeFixture to mock clocks.
|
||||
BOOST_FIXTURE_TEST_CASE(Test2, UnitTestTimeFixture)
|
||||
// Use ClockFixture or IoFixture to mock clocks.
|
||||
BOOST_FIXTURE_TEST_CASE(Test2, IoFixture)
|
||||
{
|
||||
// this->advanceClocks increments mock clocks.
|
||||
boost::asio::io_service io;
|
||||
this->advanceClocks(io, time::milliseconds(500));
|
||||
// advanceClocks() increments mock clocks.
|
||||
advanceClocks(500_ms);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2020, 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-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace tests {
|
||||
|
||||
shared_ptr<Interest>
|
||||
makeInterest(const Name& name, bool canBePrefix, optional<time::milliseconds> lifetime,
|
||||
optional<Interest::Nonce> nonce)
|
||||
{
|
||||
auto interest = std::make_shared<Interest>(name);
|
||||
interest->setCanBePrefix(canBePrefix);
|
||||
if (lifetime) {
|
||||
interest->setInterestLifetime(*lifetime);
|
||||
}
|
||||
interest->setNonce(nonce);
|
||||
return interest;
|
||||
}
|
||||
|
||||
shared_ptr<Data>
|
||||
makeData(const Name& name)
|
||||
{
|
||||
auto data = std::make_shared<Data>(name);
|
||||
return signData(data);
|
||||
}
|
||||
|
||||
Data&
|
||||
signData(Data& data)
|
||||
{
|
||||
data.setSignatureInfo(SignatureInfo(tlv::NullSignature));
|
||||
data.setSignatureValue(std::make_shared<Buffer>());
|
||||
data.wireEncode();
|
||||
return data;
|
||||
}
|
||||
|
||||
lp::Nack
|
||||
makeNack(Interest interest, lp::NackReason reason)
|
||||
{
|
||||
lp::Nack nack(std::move(interest));
|
||||
nack.setReason(reason);
|
||||
return nack;
|
||||
}
|
||||
|
||||
} // namespace tests
|
||||
} // namespace ndn
|
||||
+46
-99
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,117 +26,64 @@
|
||||
#ifndef NDN_TOOLS_TESTS_TEST_COMMON_HPP
|
||||
#define NDN_TOOLS_TESTS_TEST_COMMON_HPP
|
||||
|
||||
#include "boost-test.hpp"
|
||||
|
||||
#include <ndn-cxx/util/time-unit-test-clock.hpp>
|
||||
#include <ndn-cxx/name.hpp>
|
||||
#include <ndn-cxx/interest.hpp>
|
||||
#include <ndn-cxx/data.hpp>
|
||||
#include <ndn-cxx/signature.hpp>
|
||||
#include <ndn-cxx/security/signature-sha256-with-rsa.hpp>
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include "core/common.hpp"
|
||||
#include "tests/boost-test.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace tests {
|
||||
|
||||
/** \brief a test fixture that overrides steady clock and system clock
|
||||
/**
|
||||
* \brief Create an Interest
|
||||
*/
|
||||
class UnitTestTimeFixture
|
||||
{
|
||||
protected:
|
||||
UnitTestTimeFixture()
|
||||
: steadyClock(make_shared<time::UnitTestSteadyClock>())
|
||||
, systemClock(make_shared<time::UnitTestSystemClock>())
|
||||
{
|
||||
time::setCustomClocks(steadyClock, systemClock);
|
||||
}
|
||||
shared_ptr<Interest>
|
||||
makeInterest(const Name& name, bool canBePrefix = false,
|
||||
optional<time::milliseconds> lifetime = nullopt,
|
||||
optional<Interest::Nonce> nonce = nullopt);
|
||||
|
||||
~UnitTestTimeFixture()
|
||||
{
|
||||
time::setCustomClocks(nullptr, nullptr);
|
||||
}
|
||||
/**
|
||||
* \brief Create a Data with a null (i.e., empty) signature
|
||||
*
|
||||
* If a "real" signature is desired, use KeyChainFixture and sign again with `m_keyChain`.
|
||||
*/
|
||||
shared_ptr<Data>
|
||||
makeData(const Name& name);
|
||||
|
||||
/** \brief advance steady and system clocks
|
||||
*
|
||||
* Clocks are advanced in increments of \p tick for \p nTicks ticks.
|
||||
* After each tick, the supplied io_service is polled to process pending I/O events.
|
||||
*
|
||||
* Exceptions thrown during I/O events are propagated to the caller.
|
||||
* Clock advancing would stop in case of an exception.
|
||||
*/
|
||||
void
|
||||
advanceClocks(boost::asio::io_service& io,
|
||||
const time::nanoseconds& tick, size_t nTicks = 1)
|
||||
{
|
||||
this->advanceClocks(io, tick, tick * nTicks);
|
||||
}
|
||||
|
||||
/** \brief advance steady and system clocks
|
||||
*
|
||||
* Clocks are advanced in increments of \p tick for \p total time.
|
||||
* The last increment might be shorter than \p tick.
|
||||
* After each tick, the supplied io_service is polled to process pending I/O events.
|
||||
*
|
||||
* Exceptions thrown during I/O events are propagated to the caller.
|
||||
* Clock advancing would stop in case of an exception.
|
||||
*/
|
||||
void
|
||||
advanceClocks(boost::asio::io_service& io,
|
||||
const time::nanoseconds& tick, const time::nanoseconds& total)
|
||||
{
|
||||
BOOST_ASSERT(tick > time::nanoseconds::zero());
|
||||
BOOST_ASSERT(total >= time::nanoseconds::zero());
|
||||
|
||||
time::nanoseconds remaining = total;
|
||||
while (remaining > time::nanoseconds::zero()) {
|
||||
if (remaining >= tick) {
|
||||
steadyClock->advance(tick);
|
||||
systemClock->advance(tick);
|
||||
remaining -= tick;
|
||||
}
|
||||
else {
|
||||
steadyClock->advance(remaining);
|
||||
systemClock->advance(remaining);
|
||||
remaining = time::nanoseconds::zero();
|
||||
}
|
||||
|
||||
if (io.stopped())
|
||||
io.reset();
|
||||
io.poll();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
shared_ptr<time::UnitTestSteadyClock> steadyClock;
|
||||
shared_ptr<time::UnitTestSystemClock> systemClock;
|
||||
};
|
||||
|
||||
inline shared_ptr<Interest>
|
||||
makeInterest(const Name& name)
|
||||
{
|
||||
return make_shared<Interest>(name);
|
||||
}
|
||||
/**
|
||||
* \brief Add a null signature to \p data
|
||||
*/
|
||||
Data&
|
||||
signData(Data& data);
|
||||
|
||||
/**
|
||||
* \brief Add a null signature to \p data
|
||||
*/
|
||||
inline shared_ptr<Data>
|
||||
signData(const shared_ptr<Data>& data)
|
||||
signData(shared_ptr<Data> data)
|
||||
{
|
||||
ndn::SignatureSha256WithRsa fakeSignature;
|
||||
fakeSignature.setValue(ndn::dataBlock(tlv::SignatureValue,
|
||||
static_cast<const uint8_t*>(nullptr), 0));
|
||||
data->setSignature(fakeSignature);
|
||||
data->wireEncode();
|
||||
|
||||
signData(*data);
|
||||
return data;
|
||||
}
|
||||
|
||||
inline shared_ptr<Data>
|
||||
makeData(const Name& name)
|
||||
{
|
||||
shared_ptr<Data> data = make_shared<Data>(name);
|
||||
return signData(data);
|
||||
}
|
||||
/**
|
||||
* \brief Create a Nack
|
||||
*/
|
||||
lp::Nack
|
||||
makeNack(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<typename Packet, typename ...Args>
|
||||
void
|
||||
setNameComponent(Packet& pkt, ssize_t index, Args&& ...args)
|
||||
{
|
||||
Name name = pkt.getName();
|
||||
name.set(index, name::Component(std::forward<Args>(args)...));
|
||||
pkt.setName(name);
|
||||
}
|
||||
|
||||
} // namespace tests
|
||||
} // namespace ndn
|
||||
|
||||
+9
-8
@@ -2,13 +2,14 @@
|
||||
top = '..'
|
||||
|
||||
def build(bld):
|
||||
if not bld.env['WITH_TESTS']:
|
||||
if not bld.env.WITH_TESTS:
|
||||
return
|
||||
|
||||
bld(target='../unit-tests',
|
||||
features='cxx cxxprogram',
|
||||
source=bld.path.ant_glob(['*.cpp'] + ['%s/**/*.cpp' % tool for tool in bld.env['BUILD_TOOLS']]),
|
||||
use=['core-objects'] + ['%s-objects' % tool for tool in bld.env['BUILD_TOOLS']],
|
||||
headers='../common.hpp boost-test.hpp',
|
||||
defines='TMP_TESTS_PATH=\"%s/tmp-tests\"' % bld.bldnode,
|
||||
)
|
||||
tmpdir = 'UNIT_TESTS_TMPDIR="%s"' % bld.bldnode.make_node('tmp-files')
|
||||
bld.program(
|
||||
target='../unit-tests',
|
||||
name='unit-tests',
|
||||
source=bld.path.ant_glob(['*.cpp'] + ['%s/**/*.cpp' % tool for tool in bld.env.BUILD_TOOLS]),
|
||||
use=['core-objects'] + ['%s-objects' % tool for tool in bld.env.BUILD_TOOLS],
|
||||
defines=[tmpdir],
|
||||
install_path=None)
|
||||
|
||||
+37
-34
@@ -3,29 +3,38 @@
|
||||
**ndncatchunks** and **ndnputchunks** are a pair of programs to transfer a file as Data segments.
|
||||
|
||||
* **ndnputchunks** is a producer program that reads a file from the standard input, and makes
|
||||
it available as NDN Data segments. It appends version and segment number components
|
||||
to the specified name, according to the
|
||||
[NDN naming conventions](http://named-data.net/publications/techreports/ndn-tr-22-ndn-memo-naming-conventions/).
|
||||
it available as a set of NDN Data segments. It appends version and segment number components
|
||||
to the specified name as needed, according to the
|
||||
[NDN naming conventions](https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/).
|
||||
|
||||
* **ndncatchunks** is a consumer program that fetches Data segments of a file, optionally
|
||||
discovering the latest version of the file, and writes the content of the retrieved file to
|
||||
the standard output.
|
||||
|
||||
## Version discovery methods
|
||||
## Version discovery in ndncatchunks
|
||||
|
||||
* `fixed` : ndncatchunks will send an interest attempting to find a data packet with the
|
||||
specified prefix and version number. A version component must be present at the
|
||||
end of the user-specified NDN name.
|
||||
If a version component is present at the end of the user-specified NDN name, the provided version
|
||||
number will be used, without any version discovery process. Otherwise, discovery Interest(s) will
|
||||
be sent out to fetch metadata of the solicited content from which the Data version will be resolved.
|
||||
For more information about the packet format and naming conventions of Interest and Data packets
|
||||
used for version discovery in ndncatchunks, please refer to:
|
||||
[Realtime Data Retrieval (RDR) protocol wiki page](https://redmine.named-data.net/projects/ndn-tlv/wiki/RDR)
|
||||
|
||||
* `iterative`: ndncatchunks will send a series of interests with ChildSelector set to prefer the
|
||||
rightmost child and Exclude selectors, attempting to find a data packet with the
|
||||
specified prefix and the latest (the largest in the NDN canonical ordering)
|
||||
version number. The version is declared "latest" after a predefined number of
|
||||
data retrieval timeouts (default: 1).
|
||||
## Interest pipeline types in ndncatchunks
|
||||
|
||||
The default discovery method is `fixed`. Other methods will be implemented in future versions
|
||||
of the tool.
|
||||
* `fixed`: maintains a fixed-size window of Interests in flight; the window size is configurable
|
||||
via a command line option and defaults to 1.
|
||||
|
||||
* `aimd` : adjusts the window size via additive-increase/multiplicative-decrease (AIMD).
|
||||
By default, it uses a Conservative Window Adaptation, that is, the congestion window
|
||||
will be decreased at most once per round-trip-time.
|
||||
|
||||
* `cubic`: adjusts the window size similar to the TCP CUBIC algorithm.
|
||||
For details about both aimd and cubic please refer to:
|
||||
[A Practical Congestion Control Scheme for Named Data
|
||||
Networking](https://conferences2.sigcomm.org/acm-icn/2016/proceedings/p21-schneider.pdf)
|
||||
|
||||
The default Interest pipeline type is `cubic`.
|
||||
|
||||
## Usage examples
|
||||
|
||||
@@ -34,40 +43,34 @@ of the tool.
|
||||
The following command will publish the text of the GPL-3 license under the `/localhost/demo/gpl3`
|
||||
prefix:
|
||||
|
||||
ndnputchunks ndn:/localhost/demo/gpl3 < /usr/share/common-licenses/GPL-3
|
||||
ndnputchunks /localhost/demo/gpl3 < /usr/share/common-licenses/GPL-3
|
||||
|
||||
To find the published version you have to start ndnputchunks with the `-p` command line option,
|
||||
for example:
|
||||
|
||||
ndnputchunks -p ndn:/localhost/demo/gpl3 < /usr/share/common-licenses/GPL-3
|
||||
ndnputchunks -p /localhost/demo/gpl3 < /usr/share/common-licenses/GPL-3
|
||||
|
||||
This command will print the published version to the standard output.
|
||||
This command will print the published version to standard output.
|
||||
|
||||
To publish data with a specific version, you must append a version component to the end of the
|
||||
prefix. The version component must follow the aforementioned NDN naming conventions.
|
||||
For example, the following command will publish the version `%FD%00%00%01Qc%CF%17v` of the
|
||||
`/localhost/demo/gpl3` prefix:
|
||||
To publish Data with a specific version, you need to append a version component to the end of the
|
||||
prefix. The version component must follow the aforementioned NDN naming conventions. For example,
|
||||
the following command will publish the version 1449078495094 of the `/localhost/demo/gpl3` prefix:
|
||||
|
||||
ndnputchunks ndn:/localhost/demo/gpl3/%FD%00%00%01Qc%CF%17v < /usr/share/common-licenses/GPL-3
|
||||
|
||||
If the version component is not valid, a new well-formed version will be generated and appended
|
||||
to the supplied NDN name.
|
||||
ndnputchunks -Nt /localhost/demo/gpl3/v=1449078495094 < /usr/share/common-licenses/GPL-3
|
||||
|
||||
If the specified version component is not valid, ndnputchunks will exit with an error. If no version
|
||||
component is specified, one will be generated and appended to the name.
|
||||
|
||||
### Retrieval
|
||||
|
||||
To retrieve the latest version of a published file, the following command can be used:
|
||||
|
||||
ndncatchunks -d iterative ndn:/localhost/demo/gpl3
|
||||
ndncatchunks /localhost/demo/gpl3
|
||||
|
||||
This command will use the iterative method to discover the latest version of the file.
|
||||
|
||||
To fetch a specific version of a published file, you can use the `fixed` version discovery method
|
||||
(the default). In this case the version needs to be supplied as part of the name. For example,
|
||||
if the version is known to be `%FD%00%00%01Qc%CF%17v`, the following command will fetch that
|
||||
exact version of the file:
|
||||
|
||||
ndncatchunks ndn:/localhost/demo/gpl3/%FD%00%00%01Qc%CF%17v
|
||||
To fetch a specific version of a published file, you can specify the version number at the end of
|
||||
the name. For example, if the version is known to be 1449078495094, the following command
|
||||
will fetch that exact version of the file (without version discovery):
|
||||
|
||||
ndncatchunks -Nt /localhost/demo/gpl3/v=1449078495094
|
||||
|
||||
For more information, run the programs with `--help` as argument.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2016, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
/*
|
||||
* Copyright (c) 2016-2021, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
@@ -26,72 +26,53 @@
|
||||
*/
|
||||
|
||||
#include "consumer.hpp"
|
||||
#include "discover-version.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace chunks {
|
||||
|
||||
Consumer::Consumer(Face& face, Validator& validator, bool isVerbose, std::ostream& os)
|
||||
: m_face(face)
|
||||
, m_validator(validator)
|
||||
, m_pipeline(nullptr)
|
||||
, m_nextToPrint(0)
|
||||
Consumer::Consumer(security::Validator& validator, std::ostream& os)
|
||||
: m_validator(validator)
|
||||
, m_outputStream(os)
|
||||
, m_isVerbose(isVerbose)
|
||||
{
|
||||
}
|
||||
|
||||
void Consumer::run(DiscoverVersion& discover, PipelineInterests& pipeline)
|
||||
void
|
||||
Consumer::run(unique_ptr<DiscoverVersion> discover, unique_ptr<PipelineInterests> pipeline)
|
||||
{
|
||||
m_pipeline = &pipeline;
|
||||
m_discover = std::move(discover);
|
||||
m_pipeline = std::move(pipeline);
|
||||
m_nextToPrint = 0;
|
||||
m_bufferedData.clear();
|
||||
|
||||
discover.onDiscoverySuccess.connect(bind(&Consumer::runWithData, this, _1));
|
||||
discover.onDiscoveryFailure.connect(bind(&Consumer::onFailure, this, _1));
|
||||
|
||||
discover.run();
|
||||
m_face.processEvents();
|
||||
m_discover->onDiscoverySuccess.connect([this] (const Name& versionedName) {
|
||||
m_pipeline->run(versionedName,
|
||||
FORWARD_TO_MEM_FN(handleData),
|
||||
[] (const std::string& msg) { NDN_THROW(std::runtime_error(msg)); });
|
||||
});
|
||||
m_discover->onDiscoveryFailure.connect([] (const std::string& msg) {
|
||||
NDN_THROW(std::runtime_error(msg));
|
||||
});
|
||||
m_discover->run();
|
||||
}
|
||||
|
||||
void Consumer::runWithData(const Data& data)
|
||||
void
|
||||
Consumer::handleData(const Data& data)
|
||||
{
|
||||
auto dataPtr = data.shared_from_this();
|
||||
|
||||
m_validator.validate(data,
|
||||
bind(&Consumer::onDataValidated, this, _1),
|
||||
bind(&Consumer::onFailure, this, _2));
|
||||
[this, dataPtr] (const Data& data) {
|
||||
if (data.getContentType() == ndn::tlv::ContentType_Nack) {
|
||||
NDN_THROW(ApplicationNackError(data));
|
||||
}
|
||||
|
||||
m_pipeline->runWithExcludedSegment(data,
|
||||
bind(&Consumer::onData, this, _1, _2),
|
||||
bind(&Consumer::onFailure, this, _1));
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
Consumer::onData(const Interest& interest, const Data& data)
|
||||
{
|
||||
m_validator.validate(data,
|
||||
bind(&Consumer::onDataValidated, this, _1),
|
||||
bind(&Consumer::onFailure, this, _2));
|
||||
}
|
||||
|
||||
void
|
||||
Consumer::onDataValidated(shared_ptr<const Data> data)
|
||||
{
|
||||
if (data->getContentType() == ndn::tlv::ContentType_Nack) {
|
||||
if (m_isVerbose)
|
||||
std::cerr << "Application level NACK: " << *data << std::endl;
|
||||
|
||||
m_pipeline->cancel();
|
||||
throw ApplicationNackError(*data);
|
||||
}
|
||||
|
||||
m_bufferedData[data->getName()[-1].toSegment()] = data;
|
||||
writeInOrderData();
|
||||
}
|
||||
|
||||
void
|
||||
Consumer::onFailure(const std::string& reason)
|
||||
{
|
||||
throw std::runtime_error(reason);
|
||||
// 'data' passed to callback comes from DataValidationState and was not created with make_shared
|
||||
m_bufferedData[getSegmentFromPacket(data)] = dataPtr;
|
||||
writeInOrderData();
|
||||
},
|
||||
[] (const Data&, const security::ValidationError& error) {
|
||||
NDN_THROW(DataValidationError(error));
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -100,7 +81,6 @@ Consumer::writeInOrderData()
|
||||
for (auto it = m_bufferedData.begin();
|
||||
it != m_bufferedData.end() && it->first == m_nextToPrint;
|
||||
it = m_bufferedData.erase(it), ++m_nextToPrint) {
|
||||
|
||||
const Block& content = it->second->getContent();
|
||||
m_outputStream.write(reinterpret_cast<const char*>(content.value()), content.value_size());
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user