Compare commits
291 Commits
ndn-tools-0.2
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 36b78ea6ee | |||
| 7e9d7e4f9a | |||
| 816767b4c2 | |||
| 2ab04a2b9f | |||
| b6e10dd86a | |||
| 4a9e0b194b | |||
| 869d73e924 | |||
| dd808b0bae | |||
| 8148cd4a96 | |||
| 0df0e1c5b0 | |||
| 003e45a9f3 | |||
| 3653daedb6 | |||
| ad26607467 | |||
| a22a742de4 | |||
| c2297b11d2 | |||
| db9613e5fd | |||
| 3b4ee2f130 | |||
| be4f1891bd | |||
| d66fb491df | |||
| 6f16856fc2 | |||
| b61e3e2174 | |||
| 3d7b03372b | |||
| 0168d281c6 | |||
| 6b430e963a | |||
| b97a1122e3 | |||
| bd3642f31d | |||
| 423e58a503 | |||
| f597d07ec9 | |||
| 40eae0328b | |||
| 832d2300ee | |||
| f36375232f | |||
| 824c45b503 | |||
| 242d5063f7 | |||
| 96412a18d8 | |||
| b04c52b044 | |||
| b3570c614a | |||
| 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 | |||
| 799390a4e4 | |||
| f8852b3206 | |||
| d4ab87fb12 | |||
| 277ecf085e | |||
| 821a01431b | |||
| ae2c9f73ad | |||
| 672b9a7093 | |||
| 28ae2cbee0 | |||
| 3e79c9cda4 | |||
| e02fb52090 | |||
| c8a0a25a67 |
@@ -0,0 +1,16 @@
|
||||
name: CI
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
Ubuntu:
|
||||
uses: named-data/actions/.github/workflows/jenkins-script-ubuntu.yml@v1
|
||||
macOS:
|
||||
uses: named-data/actions/.github/workflows/jenkins-script-macos.yml@v1
|
||||
PPA:
|
||||
uses: named-data/actions/.github/workflows/ppa.yml@v1
|
||||
with:
|
||||
extra-deps: libboost-program-options-dev libpcap-dev
|
||||
@@ -0,0 +1,10 @@
|
||||
name: Docs
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
man:
|
||||
uses: named-data/actions/.github/workflows/docs-man.yml@v1
|
||||
+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,52 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
set -eo pipefail
|
||||
|
||||
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
case $(uname) in
|
||||
Linux)
|
||||
if [[ -e /etc/os-release ]]; then
|
||||
source /etc/os-release
|
||||
else
|
||||
source /usr/lib/os-release
|
||||
fi
|
||||
export ID VERSION_ID
|
||||
export ID_LIKE="${ID} ${ID_LIKE} linux"
|
||||
export PATH="${HOME}/.local/bin${PATH:+:}${PATH}"
|
||||
;;
|
||||
Darwin)
|
||||
# Emulate a subset of os-release(5)
|
||||
export ID=macos
|
||||
export VERSION_ID=$(sw_vers -productVersion)
|
||||
export PATH="/usr/local/bin${PATH:+:}${PATH}"
|
||||
if [[ -x /opt/homebrew/bin/brew ]]; then
|
||||
eval "$(/opt/homebrew/bin/brew shellenv)"
|
||||
elif [[ -x /usr/local/bin/brew ]]; then
|
||||
eval "$(/usr/local/bin/brew shellenv)"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
for file in "$DIR"/.jenkins.d/*; do
|
||||
export CACHE_DIR=${CACHE_DIR:-/tmp}
|
||||
|
||||
if [[ $JOB_NAME == *"code-coverage" ]]; then
|
||||
export DISABLE_ASAN=yes
|
||||
export DISABLE_HEADERS_CHECK=yes
|
||||
fi
|
||||
|
||||
# https://reproducible-builds.org/docs/source-date-epoch/
|
||||
export SOURCE_DATE_EPOCH=$(git log -1 --format=%ct)
|
||||
|
||||
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
|
||||
|
||||
+33
-19
@@ -1,25 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
set -eo pipefail
|
||||
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
APT_PKGS=(build-essential pkg-config python3-minimal
|
||||
libboost-all-dev libssl-dev libsqlite3-dev
|
||||
libpcap-dev)
|
||||
FORMULAE=(boost openssl pkg-config)
|
||||
PIP_PKGS=()
|
||||
case $JOB_NAME in
|
||||
*code-coverage)
|
||||
APT_PKGS+=(lcov python3-pip)
|
||||
PIP_PKGS+=('gcovr~=5.2')
|
||||
;;
|
||||
*Docs)
|
||||
APT_PKGS+=(python3-pip)
|
||||
PIP_PKGS+=(sphinx)
|
||||
;;
|
||||
esac
|
||||
|
||||
if has OSX $NODE_LABELS; then
|
||||
set -x
|
||||
brew update
|
||||
brew upgrade
|
||||
brew install boost pkg-config cryptopp
|
||||
brew cleanup
|
||||
fi
|
||||
set -x
|
||||
|
||||
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 [[ $ID == macos ]]; then
|
||||
if [[ -n $GITHUB_ACTIONS ]]; then
|
||||
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
|
||||
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
|
||||
brew update
|
||||
brew install --formula "${FORMULAE[@]}"
|
||||
elif [[ $ID_LIKE == *debian* ]]; then
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get -qy install "${APT_PKGS[@]}"
|
||||
elif [[ $ID_LIKE == *fedora* ]]; then
|
||||
sudo dnf -y install gcc-c++ libasan lld pkgconf-pkg-config python3 \
|
||||
boost-devel openssl-devel sqlite-devel \
|
||||
libpcap-devel
|
||||
fi
|
||||
|
||||
if (( ${#PIP_PKGS[@]} )); then
|
||||
pip3 install --user --upgrade --upgrade-strategy=eager "${PIP_PKGS[@]}"
|
||||
fi
|
||||
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
set -exo pipefail
|
||||
|
||||
pushd "$CACHE_DIR" >/dev/null
|
||||
|
||||
INSTALLED_VERSION=
|
||||
if [[ $ID == macos ]]; then
|
||||
BOOST=$(brew list --formula --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
|
||||
|
||||
./waf --color=yes configure --without-osx-keychain
|
||||
./waf --color=yes build
|
||||
sudo ./waf --color=yes install
|
||||
|
||||
popd >/dev/null
|
||||
popd >/dev/null
|
||||
|
||||
if [[ $ID_LIKE == *fedora* ]]; then
|
||||
sudo tee /etc/ld.so.conf.d/ndn.conf >/dev/null <<< /usr/local/lib64
|
||||
fi
|
||||
if [[ $ID_LIKE == *linux* ]]; then
|
||||
sudo ldconfig
|
||||
fi
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
|
||||
if [[ -z $DISABLE_ASAN ]]; then
|
||||
ASAN="--with-sanitizer=address"
|
||||
fi
|
||||
if [[ $JOB_NAME == *"code-coverage" ]]; then
|
||||
COVERAGE="--with-coverage"
|
||||
fi
|
||||
|
||||
set -x
|
||||
|
||||
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
|
||||
|
||||
# Cleanup
|
||||
./waf --color=yes distclean
|
||||
|
||||
# Build in release mode without tests
|
||||
./waf --color=yes configure
|
||||
./waf --color=yes build
|
||||
|
||||
# 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
|
||||
|
||||
# (tests will be run against the debug version)
|
||||
|
||||
# Install
|
||||
sudo ./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
+26
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
|
||||
# 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
|
||||
|
||||
# https://www.boost.org/doc/libs/release/libs/test/doc/html/boost_test/runtime_config/summary.html
|
||||
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
|
||||
|
||||
set -x
|
||||
|
||||
# Prepare environment
|
||||
rm -rf ~/.ndn
|
||||
|
||||
# Run unit tests
|
||||
./build/unit-tests
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
set -exo pipefail
|
||||
|
||||
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 --object-directory build \
|
||||
--filter tools/ \
|
||||
--exclude-throw-branches \
|
||||
--exclude-unreachable-branches \
|
||||
--cobertura build/coverage.xml \
|
||||
--html-details build/gcovr/ \
|
||||
--print-summary
|
||||
|
||||
# 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
|
||||
+26
-20
@@ -1,30 +1,36 @@
|
||||
CONTINUOUS INTEGRATION SCRIPTS
|
||||
==============================
|
||||
# Continuous Integration Scripts
|
||||
|
||||
Environment Variables Used in Build Scripts
|
||||
-------------------------------------------
|
||||
## Environment Variables
|
||||
|
||||
- `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.
|
||||
- `ID`: lower-case string that identifies the operating system, for example: `ID=ubuntu`,
|
||||
`ID=centos`. See [os-release(5)] for more information. On macOS, where `os-release` is
|
||||
not available, we emulate it by setting `ID=macos`.
|
||||
|
||||
The list should include at least `[OS_TYPE]`, `[DISTRO_TYPE]`, and `[DISTRO_VERSION]`.
|
||||
- `ID_LIKE`: space-separated list of operating system identifiers that are closely related
|
||||
to the running OS. See [os-release(5)] for more information. The listed values are used
|
||||
by the CI scripts to select the proper behavior for different platforms and OS flavors.
|
||||
|
||||
Possible values for Linux OS:
|
||||
Examples:
|
||||
|
||||
* `[OS_TYPE]`: `Linux`
|
||||
* `[DISTRO_TYPE]`: `Ubuntu`
|
||||
* `[DISTRO_VERSION]`: `Ubuntu-12.04`, `Ubuntu-14.04`, `Ubuntu-15.04`
|
||||
- On CentOS, `ID_LIKE="centos rhel fedora linux"`
|
||||
- On Ubuntu, `ID_LIKE="ubuntu debian linux"`
|
||||
|
||||
Possible values of OSX OS:
|
||||
- `VERSION_ID`: identifies the operating system version, excluding any release code names.
|
||||
See [os-release(5)] for more information. Examples: `VERSION_ID=42`, `VERSION_ID=22.04`.
|
||||
|
||||
* `[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`: defines the type of the current CI job. Depending on the job type, the CI
|
||||
scripts can perform different tasks.
|
||||
|
||||
- `JOB_NAME`: optional variable to define type of the job. Depending on the defined job type,
|
||||
the build scripts can perform different tasks.
|
||||
Supported values:
|
||||
|
||||
Possible values:
|
||||
- empty: default build task
|
||||
- `code-coverage`: debug build with tests and code coverage analysis
|
||||
- `limited-build`: only a single debug build with tests
|
||||
|
||||
* empty: default build process
|
||||
* `code-coverage` (Linux OS is assumed): build process with code coverage analysis
|
||||
- `CACHE_DIR`: directory containing cached files from previous builds, e.g., a compiled
|
||||
version of ndn-cxx. If not set, `/tmp` is used.
|
||||
|
||||
- `DISABLE_ASAN`: disable building with AddressSanitizer. This is automatically set for
|
||||
the `code-coverage` job type.
|
||||
|
||||
[os-release(5)]: https://www.freedesktop.org/software/systemd/man/os-release.html
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
has() {
|
||||
local p=$1
|
||||
shift
|
||||
local x
|
||||
for x in "$@"; do
|
||||
[[ "${x}" == "${p}" ]] && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
@@ -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/homebrew/lib', '/opt/local/lib', '/sw/lib', '/lib']
|
||||
BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/homebrew/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,54 +1,91 @@
|
||||
# -*- 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 < (7, 4, 0):
|
||||
errmsg = ('The version of gcc you are using is too old.\n'
|
||||
'The minimum supported gcc version is 9.3.')
|
||||
elif ccver < (9, 3, 0):
|
||||
warnmsg = ('Using a version of gcc older than 9.3 is not '
|
||||
'officially supported and may result in build failures.')
|
||||
conf.flags = GccFlags()
|
||||
elif cxx == 'clang':
|
||||
flags = ClangFlags()
|
||||
if Utils.unversioned_sys_platform() == 'darwin':
|
||||
if ccver < (10, 0, 0):
|
||||
errmsg = ('The version of Xcode you are using is too old.\n'
|
||||
'The minimum supported Xcode version is 12.4.')
|
||||
elif ccver < (12, 0, 0):
|
||||
warnmsg = ('Using a version of Xcode older than 12.4 is not '
|
||||
'officially supported and may result in build failures.')
|
||||
elif ccver < (7, 0, 0):
|
||||
errmsg = ('The version of clang you are using is too old.\n'
|
||||
'The minimum supported clang version is 7.0.')
|
||||
conf.flags = ClangFlags()
|
||||
else:
|
||||
flags = CompilerFlags()
|
||||
Logs.warn('The code has not been yet tested with %s compiler' % cxx)
|
||||
warnmsg = f'{cxx} compiler is unsupported'
|
||||
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 will alway be 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']
|
||||
|
||||
# Debug or optimization CXXFLAGS and LINKFLAGS will be applied only if the
|
||||
|
||||
@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 will be always applied
|
||||
# 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_cxxflags(extraFlags['LINKFLAGS'])
|
||||
conf.add_supported_linkflags(extraFlags['LINKFLAGS'])
|
||||
|
||||
conf.env.DEFINES += extraFlags['DEFINES']
|
||||
|
||||
|
||||
@Configure.conf
|
||||
def add_supported_cxxflags(self, cxxflags):
|
||||
"""
|
||||
Check which cxxflags are supported by compiler and add them to env.CXXFLAGS variable
|
||||
Check which cxxflags are supported by the active compiler and add them to env.CXXFLAGS variable.
|
||||
"""
|
||||
if len(cxxflags) == 0:
|
||||
return
|
||||
@@ -56,17 +93,19 @@ 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):
|
||||
"""
|
||||
Check which linkflags are supported by compiler and add them to env.LINKFLAGS variable
|
||||
Check which linkflags are supported by the active compiler and add them to env.LINKFLAGS variable.
|
||||
"""
|
||||
if len(linkflags) == 0:
|
||||
return
|
||||
@@ -74,80 +113,128 @@ 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):
|
||||
class CompilerFlags:
|
||||
def getCompilerVersion(self, conf):
|
||||
return tuple(int(i) for i in conf.env.CC_VERSION)
|
||||
|
||||
def getGeneralFlags(self, conf):
|
||||
"""Get dict {'CXXFLAGS':[...], LINKFLAGS:[...], DEFINES:[...]} that are always needed"""
|
||||
return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': []}
|
||||
"""Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are always needed"""
|
||||
return {
|
||||
'CXXFLAGS': [],
|
||||
'LINKFLAGS': [],
|
||||
'DEFINES': ['BOOST_ASIO_NO_DEPRECATED', 'BOOST_FILESYSTEM_NO_DEPRECATED'],
|
||||
}
|
||||
|
||||
def getDebugFlags(self, conf):
|
||||
"""Get tuple {CXXFLAGS, LINKFLAGS, DEFINES} that are needed in debug mode"""
|
||||
"""Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are needed only in debug mode"""
|
||||
return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': ['_DEBUG']}
|
||||
|
||||
def getOptimizedFlags(self, conf):
|
||||
"""Get tuple {CXXFLAGS, LINKFLAGS, DEFINES} that are needed in optimized mode"""
|
||||
"""Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are needed only in optimized mode"""
|
||||
return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': ['NDEBUG']}
|
||||
|
||||
class GccBasicFlags(CompilerFlags):
|
||||
"""This class defines base flags that work for gcc and clang compiler"""
|
||||
|
||||
class GccClangCommonFlags(CompilerFlags):
|
||||
"""
|
||||
This class defines common flags that work for both gcc and clang compilers.
|
||||
"""
|
||||
|
||||
def getGeneralFlags(self, conf):
|
||||
flags = super().getGeneralFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-std=c++17']
|
||||
if Utils.unversioned_sys_platform() != 'darwin':
|
||||
flags['LINKFLAGS'] += ['-fuse-ld=lld']
|
||||
return flags
|
||||
|
||||
__cxxFlags = [
|
||||
'-fdiagnostics-color',
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-Wpedantic',
|
||||
'-Wenum-conversion',
|
||||
'-Wextra-semi',
|
||||
'-Wno-unused-parameter',
|
||||
]
|
||||
__linkFlags = ['-Wl,-O1']
|
||||
|
||||
def getDebugFlags(self, conf):
|
||||
flags = super(GccBasicFlags, self).getDebugFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-pedantic', '-Wall',
|
||||
'-O0',
|
||||
'-g3',
|
||||
'-Werror',
|
||||
'-Wno-error=maybe-uninitialized', # Bug #1615
|
||||
]
|
||||
flags = super().getDebugFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-Og', '-g'] + self.__cxxFlags + [
|
||||
'-Werror',
|
||||
'-Wno-error=deprecated-declarations', # Bug #3795
|
||||
'-Wno-error=maybe-uninitialized', # Bug #1615
|
||||
]
|
||||
flags['LINKFLAGS'] += self.__linkFlags
|
||||
return flags
|
||||
|
||||
def getOptimizedFlags(self, conf):
|
||||
flags = super(GccBasicFlags, self).getOptimizedFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-pedantic', '-Wall', '-O2', '-g']
|
||||
flags = super().getOptimizedFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-O2', '-g1'] + self.__cxxFlags
|
||||
flags['LINKFLAGS'] += self.__linkFlags
|
||||
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
|
||||
|
||||
class GccFlags(GccClangCommonFlags):
|
||||
__cxxFlags = [
|
||||
'-Wcatch-value=2',
|
||||
'-Wcomma-subscript', # enabled by default in C++20
|
||||
'-Wduplicated-branches',
|
||||
'-Wduplicated-cond',
|
||||
'-Wlogical-op',
|
||||
'-Wredundant-tags',
|
||||
'-Wvolatile', # enabled by default in C++20
|
||||
]
|
||||
|
||||
def getDebugFlags(self, conf):
|
||||
flags = super(GccFlags, self).getDebugFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-Og', # gcc >= 4.8
|
||||
'-fdiagnostics-color', # gcc >= 4.9
|
||||
]
|
||||
flags = super().getDebugFlags(conf)
|
||||
flags['CXXFLAGS'] += self.__cxxFlags
|
||||
if platform.machine() == 'armv7l':
|
||||
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',
|
||||
'-Wno-error=unneeded-internal-declaration', # Bug #1588
|
||||
'-Wno-error=deprecated-register',
|
||||
]
|
||||
if Utils.unversioned_sys_platform() == "darwin":
|
||||
flags['CXXFLAGS'] += ['-stdlib=libc++']
|
||||
flags['LINKFLAGS'] += ['-stdlib=libc++']
|
||||
def getOptimizedFlags(self, conf):
|
||||
flags = super().getOptimizedFlags(conf)
|
||||
flags['CXXFLAGS'] += self.__cxxFlags
|
||||
if platform.machine() == 'armv7l':
|
||||
flags['CXXFLAGS'] += ['-Wno-psabi'] # Bug #5106
|
||||
return flags
|
||||
|
||||
|
||||
class ClangFlags(GccClangCommonFlags):
|
||||
def getGeneralFlags(self, conf):
|
||||
flags = super().getGeneralFlags(conf)
|
||||
if Utils.unversioned_sys_platform() == 'darwin':
|
||||
# Bug #4296
|
||||
brewdir = '/opt/homebrew' if platform.machine() == 'arm64' else '/usr/local'
|
||||
flags['CXXFLAGS'] += [
|
||||
['-isystem', f'{brewdir}/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
|
||||
|
||||
__cxxFlags = [
|
||||
'-Wundefined-func-template',
|
||||
'-Wno-unused-local-typedef', # Bugs #2657 and #3209
|
||||
]
|
||||
|
||||
def getDebugFlags(self, conf):
|
||||
flags = super(ClangFlags, self).getDebugFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-fcolor-diagnostics']
|
||||
flags = super().getDebugFlags(conf)
|
||||
flags['CXXFLAGS'] += self.__cxxFlags
|
||||
return flags
|
||||
|
||||
def getOptimizedFlags(self, conf):
|
||||
flags = super().getOptimizedFlags(conf)
|
||||
flags['CXXFLAGS'] += self.__cxxFlags
|
||||
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
-16
@@ -1,18 +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/main/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/>
|
||||
* 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
+17
-10
@@ -4,19 +4,26 @@ 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://github.com/named-data/ndn-cxx) library and its dependencies.
|
||||
Check out [the documentation](https://docs.named-data.net/ndn-cxx/current/INSTALL.html) for
|
||||
detailed installation instructions. All platforms supported by ndn-cxx are also supported
|
||||
by ndn-tools.
|
||||
|
||||
Any operating system and compiler supported by ndn-cxx are supported by ndn-tools.
|
||||
*Note*: If you have installed ndn-cxx from a binary package, please make sure the development
|
||||
headers are installed (e.g., if using Ubuntu PPA, the `libndn-cxx-dev` package is needed).
|
||||
|
||||
* Install `libpcap` (except on macOS where it is provided by the base system).
|
||||
|
||||
On Debian and Ubuntu:
|
||||
|
||||
sudo apt install libpcap-dev
|
||||
|
||||
On CentOS and Fedora:
|
||||
|
||||
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:
|
||||
|
||||
@@ -24,6 +31,6 @@ in ndn-tools source directory:
|
||||
./waf
|
||||
sudo ./waf install
|
||||
|
||||
To uninstall ndn-tools:
|
||||
To uninstall:
|
||||
|
||||
sudo ./waf uninstall
|
||||
|
||||
+65
-58
@@ -1,13 +1,14 @@
|
||||
# Notes for ndn-tools Developers
|
||||
# Notes for ndn-tools developers
|
||||
|
||||
## Licensing Requirements
|
||||
|
||||
Contributions to ndn-tools MUST be licensed under GPL 3.0 or a compatible license.
|
||||
If you choose GPL 3.0, include the following license boilerplate into all C++ code files:
|
||||
Contributions to ndn-tools must be licensed under the GPL v3 or a compatible license.
|
||||
If you choose the GPL v3, please use the following license boilerplate in all `.hpp`
|
||||
and `.cpp` files:
|
||||
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) [Year(s)], [Copyright Holder(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 +27,97 @@ 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://docs.named-data.net/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.
|
||||
|
||||
namespace ndn {
|
||||
namespace foo {
|
||||
|
||||
class Bar
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Bar(Face& face);
|
||||
|
||||
void
|
||||
run();
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
return ndn::foo::main(argc, argv);
|
||||
}
|
||||
Example:
|
||||
|
||||
```cpp
|
||||
namespace ndn {
|
||||
namespace foo {
|
||||
|
||||
class Bar
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Bar(Face& face);
|
||||
|
||||
void
|
||||
run();
|
||||
};
|
||||
|
||||
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[])
|
||||
{
|
||||
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_71_0/doc/html/program_options.html)
|
||||
is strongly preferred over `getopt(3)` for parsing command line arguments.
|
||||
|
||||
@@ -1,21 +1,40 @@
|
||||
# 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.
|
||||
Tools in this collection include:
|
||||
[](https://github.com/named-data/ndn-tools/actions/workflows/ci.yml)
|
||||
[](https://github.com/named-data/ndn-tools/actions/workflows/docs.yml)
|
||||

|
||||

|
||||
|
||||
* [peek](tools/peek): transmit a single packet between a consumer and a 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
|
||||
This repository contains a collection of basic tools for [Named Data Networking (NDN)](https://named-data.net/).
|
||||
The tools currently included are:
|
||||
|
||||
See [INSTALL.md](INSTALL.md) for build instructions.
|
||||
* [**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
|
||||
|
||||
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.
|
||||
## Installation
|
||||
|
||||
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
|
||||
|
||||
Contributions to ndn-tools are greatly appreciated and can be made through our
|
||||
[Gerrit code review site](https://gerrit.named-data.net/).
|
||||
If you are new to the NDN software community, please read our
|
||||
[Contributor's Guide](https://github.com/named-data/.github/blob/main/CONTRIBUTING.md)
|
||||
and [`README-dev.md`](README-dev.md) to get started.
|
||||
|
||||
## License
|
||||
|
||||
ndn-tools is free software distributed under the GNU General Public License version 3.
|
||||
See [`COPYING.md`](COPYING.md) for details.
|
||||
|
||||
@@ -0,0 +1,302 @@
|
||||
# Release Notes
|
||||
|
||||
## Version 22.12
|
||||
|
||||
The minimum build requirements have been increased as follows:
|
||||
- Either GCC >= 7.4.0 or Clang >= 6.0 is required on Linux
|
||||
- On macOS, Xcode 11.3 or later is recommended; older versions may still work but are
|
||||
not officially supported
|
||||
- Boost >= 1.65.1 is required on all platforms
|
||||
- Sphinx 4.0 or later is required to build the manual pages
|
||||
|
||||
chunks:
|
||||
- Avoid excess window decrease in certain conditions (Issue #5202)
|
||||
- Use ndn-cxx's `Segmenter` class (Issue #4702)
|
||||
|
||||
dissect:
|
||||
- Recognize several TLV elements that appear in `Certificate` and `SafeBag`
|
||||
- Remove support for obsolete TLV types
|
||||
|
||||
dissect-wireshark:
|
||||
- Expose `type`, `len`, and `bin` fields
|
||||
|
||||
build system:
|
||||
- Switch to C++17
|
||||
- macOS 12 (Monterey) and 13 (Ventura) running on arm64 are now supported out-of-the-box
|
||||
(Issue #5135)
|
||||
- CentOS Stream 9 is now supported; CentOS 8 has been dropped (Issue #5181)
|
||||
- Stop using the `gold` linker on Linux; prefer instead linking with `lld` if installed
|
||||
- Upgrade `waf` to version 2.0.24
|
||||
|
||||
## Version 22.02
|
||||
|
||||
Starting with this release, ndn-tools switched to a date-based versioning scheme:
|
||||
`YEAR.MONTH[.PATCH]` (`YY.0M[.MICRO]` in [CalVer](https://calver.org/) notation).
|
||||
|
||||
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.
|
||||
+24
-22
@@ -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-2022, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -38,45 +38,47 @@
|
||||
#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 <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#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,10 @@
|
||||
* 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 {
|
||||
namespace ndn::tools {
|
||||
|
||||
const char VERSION[] = "0.2";
|
||||
const char VERSION[] = "@VERSION_BUILD@";
|
||||
|
||||
} // namespace tools
|
||||
} // namespace ndn
|
||||
} // namespace ndn::tools
|
||||
+7
-8
@@ -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,16 +20,15 @@
|
||||
#ifndef NDN_TOOLS_CORE_VERSION_HPP
|
||||
#define NDN_TOOLS_CORE_VERSION_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "core/common.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace tools {
|
||||
namespace ndn::tools {
|
||||
|
||||
/** \brief version of ndn-tools
|
||||
/**
|
||||
* \brief The version of ndn-tools.
|
||||
*/
|
||||
extern const char VERSION[];
|
||||
|
||||
} // namespace tools
|
||||
} // namespace ndn
|
||||
} // namespace ndn::tools
|
||||
|
||||
#endif // NDN_TOOLS_CORE_VERSION_HPP
|
||||
|
||||
+43
-10
@@ -1,16 +1,49 @@
|
||||
# General information about the project.
|
||||
project = u'NDN Essential Tools'
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# For the full list of built-in configuration values, see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
# -- Project information -----------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||
|
||||
project = 'NDN Essential Tools'
|
||||
copyright = 'Copyright © 2014-2023 Named Data Networking Project.'
|
||||
author = '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 ---------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||
|
||||
needs_sphinx = '4.0'
|
||||
extensions = []
|
||||
|
||||
templates_path = ['_templates']
|
||||
exclude_patterns = ['Thumbs.db', '.DS_Store']
|
||||
|
||||
|
||||
# -- Options for manual page output ------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#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),
|
||||
]
|
||||
|
||||
@@ -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
|
||||
+48
-26
@@ -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 and Data 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 and Data packets from:
|
||||
Currently, :program:`ndndump` is capable of extracting Interest, Data, and Nack packets from:
|
||||
|
||||
* Ethernet, when bare Interest/Data is transmitted without NDNLP header
|
||||
* Ethernet frame
|
||||
* PPP link (e.g., pcap trace from ndnSIM)
|
||||
* IPv4 UDP unicast tunnel
|
||||
* IPv4 UDP multicast group
|
||||
* IPv6 TCP tunnel, when Interest/Data is aligned to the front of a TCP segment
|
||||
* IPv4 TCP tunnel, when Interest/Data/Nack is aligned to the 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.*'
|
||||
|
||||
+55
-28
@@ -1,56 +1,83 @@
|
||||
ndnpeek
|
||||
=======
|
||||
|
||||
Usage
|
||||
-----
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
::
|
||||
|
||||
ndnpeek [-h] [-f] [-r] [-m min] [-M max] [-l lifetime] [-p] [-w timeout] 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
|
||||
-------
|
||||
|
||||
``-h``
|
||||
Print help and exit
|
||||
``-h, --help``
|
||||
Print help and exit.
|
||||
|
||||
``-f``
|
||||
If specified, set ``MustBeFresh`` selector in the Interest packet.
|
||||
``-P, --prefix``
|
||||
If specified, include ``CanBePrefix`` element in the Interest packet.
|
||||
|
||||
``-r``
|
||||
Set ``ChildSelector=1`` (the rightmost child) selector.
|
||||
``-f, --fresh``
|
||||
If specified, include ``MustBeFresh`` element in the Interest packet.
|
||||
|
||||
``-m``
|
||||
Set ``min`` as the ``MinSuffixComponents`` 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``
|
||||
Set ``max`` as the ``MaxSuffixComponents`` selector.
|
||||
|
||||
``-l``
|
||||
``-l, --lifetime <lifetime>``
|
||||
Set ``lifetime`` (in milliseconds) as the ``InterestLifetime``.
|
||||
|
||||
``-p``
|
||||
``-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 after ``timeout`` milliseconds.
|
||||
``-w, --timeout <timeout>``
|
||||
Quit the program after ``timeout`` milliseconds, even if no reply 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: 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-3-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
|
||||
+12
-9
@@ -1,23 +1,26 @@
|
||||
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',
|
||||
```python
|
||||
def build(bld):
|
||||
bld.objects(
|
||||
target='tool-subtool-objects',
|
||||
source=bld.path.ant_glob('subtool/*.cpp', excl='subtool/main.cpp'),
|
||||
use='core-objects')
|
||||
|
||||
bld(features='cxx cxxprogram',
|
||||
bld.program(
|
||||
name='subtool',
|
||||
target='../../bin/subtool',
|
||||
source='subtool/main.cpp',
|
||||
use='tool-subtool-objects')
|
||||
|
||||
bld(name='tool-objects',
|
||||
use='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
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2016-2023, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Andrea Tosatto
|
||||
*/
|
||||
|
||||
#include "tools/chunks/catchunks/consumer.hpp"
|
||||
#include "tools/chunks/catchunks/discover-version.hpp"
|
||||
#include "tools/chunks/catchunks/pipeline-interests.hpp"
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include "tests/io-fixture.hpp"
|
||||
|
||||
#include <ndn-cxx/security/validator-null.hpp>
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
#include <boost/test/tools/output_test_stream.hpp>
|
||||
|
||||
namespace ndn::chunks::tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
using boost::test_tools::output_test_stream;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Chunks)
|
||||
BOOST_AUTO_TEST_SUITE(TestConsumer)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(InOrderData)
|
||||
{
|
||||
// Segment order: 0 1 2 3
|
||||
|
||||
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,"
|
||||
};
|
||||
|
||||
DummyClientFace face;
|
||||
output_test_stream output("");
|
||||
Consumer cons(security::getAcceptAllValidator(), output);
|
||||
|
||||
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(make_span(reinterpret_cast<const uint8_t*>(testStrings[i].data()),
|
||||
testStrings[i].size()));
|
||||
|
||||
cons.m_bufferedData[i] = data;
|
||||
cons.writeInOrderData();
|
||||
|
||||
BOOST_CHECK(output.is_equal(testStrings[i]));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(OutOfOrderData)
|
||||
{
|
||||
// Segment order: 1 0 2
|
||||
|
||||
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,"
|
||||
};
|
||||
|
||||
DummyClientFace face;
|
||||
output_test_stream output("");
|
||||
Consumer cons(security::getAcceptAllValidator(), output);
|
||||
|
||||
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(make_span(reinterpret_cast<const uint8_t*>(testStrings[i].data()),
|
||||
testStrings[i].size()));
|
||||
|
||||
dataStore.push_back(data);
|
||||
}
|
||||
|
||||
output.flush();
|
||||
cons.m_bufferedData[1] = dataStore[1];
|
||||
cons.writeInOrderData();
|
||||
BOOST_CHECK(output.is_equal(""));
|
||||
|
||||
output.flush();
|
||||
cons.m_bufferedData[0] = dataStore[0];
|
||||
cons.writeInOrderData();
|
||||
BOOST_CHECK(output.is_equal(testStrings[0] + testStrings[1]));
|
||||
|
||||
output.flush();
|
||||
cons.m_bufferedData[2] = dataStore[2];
|
||||
cons.writeInOrderData();
|
||||
BOOST_CHECK(output.is_equal(testStrings[2]));
|
||||
}
|
||||
|
||||
class PipelineInterestsDummy final : 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)
|
||||
{
|
||||
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
|
||||
|
||||
} // namespace ndn::chunks::tests
|
||||
@@ -0,0 +1,216 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2016-2023, 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::chunks::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;
|
||||
DummyClientFace face{m_io};
|
||||
Options opt;
|
||||
unique_ptr<DiscoverVersion> discover;
|
||||
std::optional<Name> discoveredName;
|
||||
std::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 ndn::chunks::tests
|
||||
@@ -0,0 +1,643 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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::chunks::tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
class PipelineInterestAimdFixture : public PipelineInterestsFixture
|
||||
{
|
||||
protected:
|
||||
PipelineInterestAimdFixture()
|
||||
{
|
||||
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{makeRttEstimatorOptions()};
|
||||
PipelineInterestsAdaptive* pipeline;
|
||||
static constexpr double MARGIN = 0.001;
|
||||
};
|
||||
|
||||
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(Bug5202)
|
||||
{
|
||||
// If an interest is pending during a window decrease, it should not trigger
|
||||
// another window decrease when it times out.
|
||||
// This test emulates a network where RTT = 20ms and transmission time = 1ms.
|
||||
|
||||
// adding small sample to RTT estimator. This should set rto = 200ms
|
||||
rttEstimator.addMeasurement(time::nanoseconds(1));
|
||||
BOOST_REQUIRE_EQUAL(rttEstimator.getEstimatedRto(), time::milliseconds(200));
|
||||
|
||||
nDataSegments = 300;
|
||||
pipeline->m_ssthresh = 0;
|
||||
pipeline->m_cwnd = 20;
|
||||
|
||||
run(name);
|
||||
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_CHECK_EQUAL(face.sentInterests.size(), 20);
|
||||
advanceClocks(time::milliseconds(20));
|
||||
|
||||
// Segment 1 is lost. Receive segment 0 and 2-99
|
||||
face.receive(*makeDataWithSegment(0));
|
||||
advanceClocks(time::milliseconds(1));
|
||||
for (uint64_t i = 2; i <= 99; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(time::milliseconds(1));
|
||||
}
|
||||
|
||||
// Segment 100 is lost. Receive segment 100 to 181
|
||||
for (uint64_t i = 101; i <= 181; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(time::milliseconds(1));
|
||||
}
|
||||
|
||||
// 200ms passed after sending segment 1, check for timeout
|
||||
BOOST_CHECK_GT(pipeline->m_cwnd, 27./2);
|
||||
BOOST_CHECK_LT(pipeline->m_cwnd, 28./2);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nTimeouts, 1);
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nLossDecr, 1);
|
||||
|
||||
// Receive segment 182 to 300
|
||||
for (uint64_t i = 182; i <= 300; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(time::milliseconds(1));
|
||||
}
|
||||
|
||||
// The second packet should timeout now
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nTimeouts, 2);
|
||||
// This timeout should NOT trigger another window decrease
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nLossDecr, 1);
|
||||
}
|
||||
|
||||
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 ndn::chunks::tests
|
||||
@@ -0,0 +1,560 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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::chunks::tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
class PipelineInterestCubicFixture : public PipelineInterestsFixture
|
||||
{
|
||||
protected:
|
||||
PipelineInterestCubicFixture()
|
||||
{
|
||||
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{makeRttEstimatorOptions()};
|
||||
PipelineInterestsCubic* pipeline;
|
||||
static constexpr double MARGIN = 0.001;
|
||||
};
|
||||
|
||||
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 ndn::chunks::tests
|
||||
@@ -0,0 +1,299 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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 Chavoosh Ghasemi
|
||||
*/
|
||||
|
||||
#include "tools/chunks/catchunks/pipeline-interests-fixed.hpp"
|
||||
#include "tools/chunks/catchunks/data-fetcher.hpp"
|
||||
|
||||
#include "pipeline-interests-fixture.hpp"
|
||||
|
||||
namespace ndn::chunks::tests {
|
||||
|
||||
class PipelineInterestFixedFixture : public PipelineInterestsFixture
|
||||
{
|
||||
public:
|
||||
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:
|
||||
Options opt;
|
||||
PipelineInterestsFixed* pipeline;
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Chunks)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestPipelineInterestsFixed, PipelineInterestFixedFixture)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(FullPipeline)
|
||||
{
|
||||
nDataSegments = 13;
|
||||
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
|
||||
|
||||
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(time::nanoseconds(1));
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, i + 1);
|
||||
|
||||
if (i < nDataSegments - opt.maxPipelineSize) {
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize + i + 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(getSegmentFromPacket(sentInterest), i);
|
||||
}
|
||||
else {
|
||||
// all the interests have been sent for all the segments
|
||||
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_AUTO_TEST_CASE(TimeoutAllSegments)
|
||||
{
|
||||
nDataSegments = 13;
|
||||
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
|
||||
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
|
||||
|
||||
for (int i = 0; i < opt.maxRetriesOnTimeoutOrNack; ++i) {
|
||||
advanceClocks(opt.interestLifetime);
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * (i + 2));
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 0);
|
||||
|
||||
// A single retry for every pipeline element
|
||||
for (size_t j = 0; j < opt.maxPipelineSize; ++j) {
|
||||
const auto& interest = face.sentInterests[(opt.maxPipelineSize * (i + 1)) + j];
|
||||
BOOST_CHECK_EQUAL(static_cast<size_t>(getSegmentFromPacket(interest)), j);
|
||||
}
|
||||
}
|
||||
|
||||
advanceClocks(opt.interestLifetime);
|
||||
BOOST_CHECK_EQUAL(hasFailed, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(TimeoutAfterFinalBlockIdReceived)
|
||||
{
|
||||
// the FinalBlockId is sent with the first segment, after the first segment failure the pipeline
|
||||
// should fail
|
||||
|
||||
nDataSegments = 18;
|
||||
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
|
||||
|
||||
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(opt.interestLifetime);
|
||||
for (uint64_t i = 1; i < opt.maxPipelineSize; ++i) {
|
||||
face.receive(*makeDataWithSegment(i));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
|
||||
// send a single data packet for each pipeline element
|
||||
advanceClocks(opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack - 1);
|
||||
for (uint64_t i = 0; i < opt.maxPipelineSize; ++i) {
|
||||
face.receive(*makeDataWithSegment(opt.maxPipelineSize + i));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
advanceClocks(opt.interestLifetime);
|
||||
|
||||
size_t interestAfterFailure = face.sentInterests.size();
|
||||
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
|
||||
BOOST_CHECK_EQUAL(hasFailed, true);
|
||||
|
||||
// these new segments should not generate new interests
|
||||
advanceClocks(opt.interestLifetime);
|
||||
for (uint64_t i = 0; i < opt.maxPipelineSize; ++i) {
|
||||
face.receive(*makeDataWithSegment(opt.maxPipelineSize * 2 + i - 1));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
|
||||
// no more interests after a failure
|
||||
advanceClocks(opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack);
|
||||
BOOST_CHECK_EQUAL(interestAfterFailure, face.sentInterests.size());
|
||||
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
nDataSegments = 22;
|
||||
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
|
||||
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
|
||||
|
||||
advanceClocks(opt.interestLifetime);
|
||||
for (uint64_t i = 2; i < opt.maxPipelineSize; ++i) {
|
||||
face.receive(*makeDataWithSegment(i, false));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
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);
|
||||
|
||||
// nack for the first pipeline element (segment #0)
|
||||
auto nack = make_shared<lp::Nack>(face.sentInterests[opt.maxPipelineSize]);
|
||||
nack->setReason(lp::NackReason::DUPLICATE);
|
||||
face.receive(*nack);
|
||||
|
||||
// all the pipeline elements are two retries near the timeout error, but not the
|
||||
// second (segment #1) that is only one retry near the timeout
|
||||
advanceClocks(opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack - 1);
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
|
||||
// data for the first pipeline element (segment #0)
|
||||
face.receive(*makeDataWithSegment(0, false));
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
|
||||
// data for all the pipeline element, but not the second (segment #1)
|
||||
for (uint64_t i = opt.maxPipelineSize; i < nDataSegments; ++i) {
|
||||
if (i == nDataSegments - 1) {
|
||||
face.receive(*makeDataWithSegment(i, true));
|
||||
}
|
||||
else {
|
||||
face.receive(*makeDataWithSegment(i, false));
|
||||
}
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
// timeout for the second pipeline element (segment #1), this should trigger an error
|
||||
advanceClocks(opt.interestLifetime);
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, nDataSegments - 1);
|
||||
BOOST_CHECK_EQUAL(hasFailed, true);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
nDataSegments = 22;
|
||||
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
|
||||
|
||||
run(name);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
|
||||
|
||||
advanceClocks(opt.interestLifetime);
|
||||
|
||||
// nack for the first pipeline element (segment #0)
|
||||
auto nack = make_shared<lp::Nack>(face.sentInterests[opt.maxPipelineSize]);
|
||||
nack->setReason(lp::NackReason::DUPLICATE);
|
||||
face.receive(*nack);
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
|
||||
// timeout for all the pipeline elements, but not the first (segment #0)
|
||||
advanceClocks(opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack);
|
||||
BOOST_CHECK_EQUAL(hasFailed, false);
|
||||
|
||||
// data for the first pipeline element (segment #0), this should trigger an error because the
|
||||
// other pipeline elements failed
|
||||
face.receive(*makeDataWithSegment(0, false));
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
|
||||
BOOST_CHECK_EQUAL(pipeline->m_nReceived, 1);
|
||||
BOOST_CHECK_EQUAL(hasFailed, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CongestionAllSegments)
|
||||
{
|
||||
nDataSegments = 13;
|
||||
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
|
||||
|
||||
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 i = 0; i < opt.maxPipelineSize; i++) {
|
||||
auto nack = make_shared<lp::Nack>(face.sentInterests[i]);
|
||||
nack->setReason(lp::NackReason::CONGESTION);
|
||||
face.receive(*nack);
|
||||
advanceClocks(time::nanoseconds(1));
|
||||
}
|
||||
|
||||
// send nack for all the pipeline elements interests after the first
|
||||
for (int i = 1; i <= opt.maxRetriesOnTimeoutOrNack; ++i) {
|
||||
time::milliseconds backoffTime(static_cast<uint64_t>(std::pow(2, i)));
|
||||
if (backoffTime > DataFetcher::MAX_CONGESTION_BACKOFF_TIME)
|
||||
backoffTime = DataFetcher::MAX_CONGESTION_BACKOFF_TIME;
|
||||
|
||||
advanceClocks(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) {
|
||||
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(time::nanoseconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(hasFailed, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestPipelineInterests
|
||||
BOOST_AUTO_TEST_SUITE_END() // Chunks
|
||||
|
||||
} // namespace ndn::chunks::tests
|
||||
@@ -0,0 +1,91 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2016-2023, 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::chunks::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:
|
||||
DummyClientFace face{m_io};
|
||||
Name name{"/ndn/chunks/test"};
|
||||
uint64_t nDataSegments = 0;
|
||||
bool hasFailed = false;
|
||||
|
||||
private:
|
||||
unique_ptr<PipelineInterests> m_pipeline;
|
||||
};
|
||||
|
||||
} // namespace ndn::chunks::tests
|
||||
|
||||
#endif // NDN_TOOLS_TESTS_CHUNKS_PIPELINE_INTERESTS_FIXTURE_HPP
|
||||
@@ -0,0 +1,219 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2016-2023, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Andrea Tosatto
|
||||
*/
|
||||
|
||||
#include "tools/chunks/putchunks/producer.hpp"
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include "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 <cmath>
|
||||
#include <sstream>
|
||||
|
||||
namespace ndn::chunks::tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
class ProducerFixture : public IoFixture, public KeyChainFixture
|
||||
{
|
||||
protected:
|
||||
ProducerFixture()
|
||||
{
|
||||
options.maxSegmentSize = 40;
|
||||
options.isQuiet = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
DummyClientFace face{m_io, {true, true}};
|
||||
Name prefix = "/ndn/chunks/test";
|
||||
Producer::Options options;
|
||||
uint64_t version = 1449227841747;
|
||||
Name keyLocatorName = m_keyChain.createIdentity("/putchunks/producer")
|
||||
.getDefaultKey().getDefaultCertificate().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_FIXTURE_TEST_SUITE(TestProducer, ProducerFixture)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(InputData)
|
||||
{
|
||||
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,"
|
||||
};
|
||||
|
||||
for (const auto& str : testStrings) {
|
||||
std::istringstream input(str);
|
||||
Producer prod(prefix, face, m_keyChain, input, options);
|
||||
size_t expectedSize = str.empty() ? 1 : std::ceil(static_cast<double>(str.size()) / options.maxSegmentSize);
|
||||
BOOST_CHECK_EQUAL(prod.m_store.size(), expectedSize);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(RequestSegmentUnspecifiedVersion)
|
||||
{
|
||||
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, 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_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), 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_CHECK_EQUAL(lastData.getFinalBlock().value().toSegment(), nSegments - 1);
|
||||
BOOST_CHECK_EQUAL(lastData.getKeyLocator().value().getName(), keyLocatorName);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(RequestSegmentSpecifiedVersion)
|
||||
{
|
||||
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, true));
|
||||
face.processEvents();
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
|
||||
auto lastData = face.sentData.back();
|
||||
BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 1);
|
||||
BOOST_CHECK_EQUAL(lastData.getName()[-2].toVersion(), version);
|
||||
BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), 0);
|
||||
BOOST_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), true));
|
||||
face.processEvents();
|
||||
|
||||
BOOST_REQUIRE_EQUAL(face.sentData.size(), 2);
|
||||
lastData = face.sentData.back();
|
||||
BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 1);
|
||||
BOOST_CHECK_EQUAL(lastData.getName()[-2].toVersion(), version);
|
||||
BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), requestSegmentNo);
|
||||
BOOST_CHECK_EQUAL(lastData.getFinalBlock().value().toSegment(), nSegments - 1);
|
||||
BOOST_CHECK_EQUAL(lastData.getKeyLocator().value().getName(), keyLocatorName);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(RequestNotExistingSegment)
|
||||
{
|
||||
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, 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_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), 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
|
||||
|
||||
} // namespace ndn::chunks::tests
|
||||
@@ -0,0 +1,58 @@
|
||||
/* -*- 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 "tests/clock-fixture.hpp"
|
||||
|
||||
namespace ndn::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 ndn::tests
|
||||
@@ -0,0 +1,87 @@
|
||||
/* -*- 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/>.
|
||||
*/
|
||||
|
||||
#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::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 ndn::tests
|
||||
|
||||
#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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,494 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2023, 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.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tools/dump/ndndump.hpp"
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/udp.h>
|
||||
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/test/tools/output_test_stream.hpp>
|
||||
|
||||
#include <ndn-cxx/encoding/encoding-buffer.hpp>
|
||||
#include <ndn-cxx/lp/fields.hpp>
|
||||
#include <ndn-cxx/lp/packet.hpp>
|
||||
#include <ndn-cxx/net/ethernet.hpp>
|
||||
|
||||
namespace ndn::dump::tests {
|
||||
|
||||
namespace endian = boost::endian;
|
||||
using namespace ndn::tests;
|
||||
|
||||
class StdCoutRedirector
|
||||
{
|
||||
public:
|
||||
StdCoutRedirector(std::ostream& os)
|
||||
{
|
||||
// Redirect std::cout to the specified output stream
|
||||
originalBuffer = std::cout.rdbuf(os.rdbuf());
|
||||
}
|
||||
|
||||
~StdCoutRedirector()
|
||||
{
|
||||
// Revert state for std::cout
|
||||
std::cout.rdbuf(originalBuffer);
|
||||
}
|
||||
|
||||
private:
|
||||
std::streambuf* originalBuffer;
|
||||
};
|
||||
|
||||
class NdnDumpFixture
|
||||
{
|
||||
protected:
|
||||
NdnDumpFixture()
|
||||
{
|
||||
dump.m_dataLinkType = DLT_EN10MB;
|
||||
}
|
||||
|
||||
template<typename Packet>
|
||||
void
|
||||
receive(const Packet& packet)
|
||||
{
|
||||
EncodingBuffer buffer(packet.wireEncode());
|
||||
receiveEthernet(buffer);
|
||||
}
|
||||
|
||||
void
|
||||
receiveEthernet(EncodingBuffer& buffer, uint16_t ethertype = s_ethertypeNdn)
|
||||
{
|
||||
ethernet::Address host;
|
||||
|
||||
// Ethernet header
|
||||
buffer.prependBytes({reinterpret_cast<const uint8_t*>(ðertype), ethernet::TYPE_LEN});
|
||||
buffer.prependBytes(host);
|
||||
buffer.prependBytes(host);
|
||||
|
||||
// pcap header
|
||||
pcap_pkthdr pkthdr{};
|
||||
pkthdr.caplen = pkthdr.len = buffer.size();
|
||||
|
||||
{
|
||||
StdCoutRedirector redirect(output);
|
||||
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;
|
||||
boost::test_tools::output_test_stream output;
|
||||
|
||||
static inline const uint16_t s_ethertypeNdn = endian::native_to_big(ethernet::ETHERTYPE_NDN);
|
||||
static inline const uint16_t s_ethertypeIp4 = endian::native_to_big(uint16_t(ETHERTYPE_IP));
|
||||
static inline const uint16_t s_ethertypeIp6 = endian::native_to_big(uint16_t(ETHERTYPE_IPV6));
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Dump)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestNdnDump, NdnDumpFixture)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Interest)
|
||||
{
|
||||
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(Data)
|
||||
{
|
||||
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(Nack)
|
||||
{
|
||||
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);
|
||||
BOOST_CHECK(output.is_equal("0.000000 Ethernet, NDNLPv2, NACK (Duplicate): /test?Nonce=00000001\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(LpFragment)
|
||||
{
|
||||
const uint8_t data[10] = {
|
||||
0x06, 0x08, // Data packet
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
};
|
||||
|
||||
Buffer buffer(data, 4);
|
||||
lp::Packet lpPacket;
|
||||
lpPacket.add<lp::FragmentField>(std::make_pair(buffer.begin(), buffer.end()));
|
||||
lpPacket.add<lp::FragIndexField>(0);
|
||||
lpPacket.add<lp::FragCountField>(2);
|
||||
lpPacket.add<lp::SequenceField>(1000);
|
||||
|
||||
this->receive(lpPacket);
|
||||
BOOST_CHECK(output.is_equal("0.000000 Ethernet, NDNLPv2 fragment\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(LpIdle)
|
||||
{
|
||||
lp::Packet lpPacket;
|
||||
this->receive(lpPacket);
|
||||
BOOST_CHECK(output.is_equal("0.000000 Ethernet, NDNLPv2 idle\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(IncompleteNdnPacket)
|
||||
{
|
||||
const uint8_t interest[] = {
|
||||
0x05, 0x0E, // Interest
|
||||
0x07, 0x06, // Name
|
||||
0x08, 0x04, // NameComponent
|
||||
0x74, 0x65, 0x73, 0x74,
|
||||
0x0a, 0x04, // Nonce
|
||||
0x00, 0x00, 0x00, 0x01
|
||||
};
|
||||
EncodingBuffer buffer;
|
||||
buffer.prependBytes(make_span(interest).first(4));
|
||||
|
||||
this->receiveEthernet(buffer);
|
||||
BOOST_CHECK(output.is_equal("0.000000 Ethernet, NDN truncated packet, length 4\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(UnsupportedNdnPacket)
|
||||
{
|
||||
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(UnsupportedEtherType)
|
||||
{
|
||||
EncodingBuffer pkt;
|
||||
uint16_t type = ETHERTYPE_ARP;
|
||||
endian::native_to_big_inplace(type);
|
||||
|
||||
this->receiveEthernet(pkt, type);
|
||||
BOOST_CHECK(output.is_equal("0.000000 [Unsupported ethertype 0x806]\n"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MalformedIpv4Header)
|
||||
{
|
||||
dump.wantTimestamp = false;
|
||||
|
||||
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 ndn::dump::tests
|
||||
Binary file not shown.
@@ -1,58 +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 "identity-management-time-fixture.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace tests {
|
||||
|
||||
IdentityManagementTimeFixture::IdentityManagementTimeFixture()
|
||||
: m_keyChainTmpPath(boost::filesystem::path(TMP_TESTS_PATH) / "PibIdMgmtTimeTest")
|
||||
, m_keyChain(std::string("pib-sqlite3:").append(m_keyChainTmpPath.string()),
|
||||
std::string("tpm-file:").append(m_keyChainTmpPath.string()))
|
||||
{
|
||||
}
|
||||
|
||||
IdentityManagementTimeFixture::~IdentityManagementTimeFixture()
|
||||
{
|
||||
for (const auto& identity : m_identities) {
|
||||
m_keyChain.deleteIdentity(identity);
|
||||
}
|
||||
|
||||
boost::filesystem::remove_all(m_keyChainTmpPath);
|
||||
}
|
||||
|
||||
bool
|
||||
IdentityManagementTimeFixture::addIdentity(const Name& identity, const KeyParams& params)
|
||||
{
|
||||
try {
|
||||
m_keyChain.createIdentity(identity, params);
|
||||
m_identities.push_back(identity);
|
||||
return true;
|
||||
}
|
||||
catch (std::runtime_error&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace tests
|
||||
} // namespace ndn
|
||||
@@ -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
|
||||
@@ -0,0 +1,53 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2023, 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_IO_FIXTURE_HPP
|
||||
#define NDN_TOOLS_TESTS_IO_FIXTURE_HPP
|
||||
|
||||
#include "tests/clock-fixture.hpp"
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
|
||||
namespace ndn::tests {
|
||||
|
||||
class IoFixture : public ClockFixture
|
||||
{
|
||||
private:
|
||||
void
|
||||
afterTick() final
|
||||
{
|
||||
if (m_io.stopped()) {
|
||||
m_io.restart();
|
||||
}
|
||||
m_io.poll();
|
||||
}
|
||||
|
||||
protected:
|
||||
boost::asio::io_context m_io;
|
||||
};
|
||||
|
||||
} // namespace ndn::tests
|
||||
|
||||
#endif // NDN_TOOLS_TESTS_IO_FIXTURE_HPP
|
||||
@@ -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) 2013-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.
|
||||
@@ -17,25 +17,22 @@
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <ndn-cxx/encoding/block.hpp>
|
||||
#include <fstream>
|
||||
#ifndef NDN_TOOLS_TESTS_KEY_CHAIN_FIXTURE_HPP
|
||||
#define NDN_TOOLS_TESTS_KEY_CHAIN_FIXTURE_HPP
|
||||
|
||||
namespace ndn {
|
||||
namespace dissect {
|
||||
#include <ndn-cxx/security/key-chain.hpp>
|
||||
|
||||
class NdnDissect : noncopyable
|
||||
namespace ndn::tests {
|
||||
|
||||
/**
|
||||
* @brief A fixture providing an in-memory KeyChain.
|
||||
*/
|
||||
class KeyChainFixture
|
||||
{
|
||||
public:
|
||||
void
|
||||
dissect(std::ostream& os, std::istream& is);
|
||||
|
||||
private:
|
||||
void
|
||||
printType(std::ostream& os, uint32_t type);
|
||||
|
||||
void
|
||||
printBlock(std::ostream& os, const Block& block);
|
||||
protected:
|
||||
ndn::KeyChain m_keyChain{"pib-memory:", "tpm-memory:"};
|
||||
};
|
||||
|
||||
} // namespace dissect
|
||||
} // namespace ndn
|
||||
} // namespace ndn::tests
|
||||
|
||||
#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,320 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2023, 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/test/tools/output_test_stream.hpp>
|
||||
|
||||
namespace ndn::peek::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:
|
||||
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.data()), 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.data()), 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 = std::tuple<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() == std::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 = std::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 ndn::peek::tests
|
||||
@@ -0,0 +1,257 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2023, 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::peek::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:
|
||||
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 ndn::peek::tests
|
||||
@@ -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-2023, 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,104 +18,79 @@
|
||||
*/
|
||||
|
||||
#include "tools/ping/client/ping.hpp"
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
#include "tests/io-fixture.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace ping {
|
||||
namespace client {
|
||||
namespace tests {
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
namespace ndn::ping::client::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;
|
||||
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
|
||||
} // namespace ping
|
||||
} // namespace ndn
|
||||
} // namespace ndn::ping::client::tests
|
||||
|
||||
@@ -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-2023, 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,56 +18,44 @@
|
||||
*/
|
||||
|
||||
#include "tools/ping/client/statistics-collector.hpp"
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
#include "tests/test-common.hpp"
|
||||
|
||||
namespace ndn {
|
||||
namespace ping {
|
||||
namespace client {
|
||||
namespace tests {
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
using namespace ndn::tests;
|
||||
namespace ndn::ping::client::tests {
|
||||
|
||||
class StatisticsCollectorFixture
|
||||
{
|
||||
protected:
|
||||
StatisticsCollectorFixture()
|
||||
: face(util::makeDummyClientFace())
|
||||
, pingOptions(makeOptions())
|
||||
, pingProgram(*face, pingOptions)
|
||||
, sc(pingProgram, pingOptions)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
static Options
|
||||
makeOptions()
|
||||
{
|
||||
Options opt;
|
||||
opt.prefix = "ndn:/ping-prefix";
|
||||
opt.prefix = "/ping-prefix";
|
||||
opt.shouldAllowStaleData = false;
|
||||
opt.shouldGenerateRandomSeq = false;
|
||||
opt.shouldPrintTimestamp = false;
|
||||
opt.nPings = 5;
|
||||
opt.interval = time::milliseconds(100);
|
||||
opt.timeout = time::milliseconds(2000);
|
||||
opt.interval = 100_ms;
|
||||
opt.timeout = 2_s;
|
||||
opt.startSeq = 1;
|
||||
return opt;
|
||||
}
|
||||
|
||||
protected:
|
||||
shared_ptr<util::DummyClientFace> face;
|
||||
Options pingOptions;
|
||||
Ping pingProgram;
|
||||
StatisticsCollector sc;
|
||||
DummyClientFace face;
|
||||
Options pingOptions{makeOptions()};
|
||||
Ping pingProgram{face, pingOptions};
|
||||
StatisticsCollector sc{pingProgram, pingOptions};
|
||||
};
|
||||
|
||||
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 +68,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 +84,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 +108,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,9 +135,68 @@ 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();
|
||||
|
||||
} // namespace tests
|
||||
} // namespace client
|
||||
} // namespace ping
|
||||
} // namespace ndn
|
||||
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 ndn::ping::client::tests
|
||||
|
||||
+63
-75
@@ -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-2023, 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,84 +17,78 @@
|
||||
* 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"
|
||||
|
||||
namespace ndn {
|
||||
namespace ping {
|
||||
namespace tests {
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
|
||||
namespace ndn::ping::tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
class PingIntegratedFixture : public IdentityManagementTimeFixture
|
||||
class PingIntegratedFixture : public IoFixture, public KeyChainFixture
|
||||
{
|
||||
public:
|
||||
protected:
|
||||
PingIntegratedFixture()
|
||||
: serverFace(util::makeDummyClientFace(io, {false, true}))
|
||||
, clientFace(util::makeDummyClientFace(io, {false, true}))
|
||||
, numResponses(0)
|
||||
, wantLoss(false)
|
||||
{
|
||||
serverFace->onSendInterest.connect([this] (const Interest& interest) {
|
||||
io.post([=] { if (!wantLoss) { clientFace->receive(interest); } });
|
||||
serverFace.onSendInterest.connect([this] (const auto& interest) {
|
||||
receive(clientFace, interest);
|
||||
});
|
||||
clientFace->onSendInterest.connect([this] (const Interest& interest) {
|
||||
io.post([=] { if (!wantLoss) { serverFace->receive(interest); } });
|
||||
clientFace.onSendInterest.connect([this] (const auto& interest) {
|
||||
receive(serverFace, interest);
|
||||
});
|
||||
serverFace->onSendData.connect([this] (const Data& data) {
|
||||
io.post([=] { if (!wantLoss) { clientFace->receive(data); } });
|
||||
serverFace.onSendData.connect([this] (const auto& data) {
|
||||
receive(clientFace, data);
|
||||
});
|
||||
clientFace->onSendData.connect([this] (const Data& data) {
|
||||
io.post([=] { if (!wantLoss) { serverFace->receive(data); } });
|
||||
clientFace.onSendData.connect([this] (const auto& data) {
|
||||
receive(serverFace, data);
|
||||
});
|
||||
}
|
||||
|
||||
void onTimeout(uint64_t seq)
|
||||
template<typename Packet>
|
||||
void
|
||||
receive(DummyClientFace& face, const Packet& pkt)
|
||||
{
|
||||
numResponses++;
|
||||
if (numResponses == maxResponses) {
|
||||
serverFace->shutdown();
|
||||
clientFace->shutdown();
|
||||
io.stop();
|
||||
}
|
||||
boost::asio::post(m_io, [=, &face] {
|
||||
if (!wantLoss) {
|
||||
face.receive(pkt);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void onData(uint64_t seq)
|
||||
void
|
||||
onFinish()
|
||||
{
|
||||
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;
|
||||
protected:
|
||||
DummyClientFace serverFace{m_io, m_keyChain, {false, true}};
|
||||
DummyClientFace clientFace{m_io, m_keyChain, {false, true}};
|
||||
std::unique_ptr<server::PingServer> server;
|
||||
std::unique_ptr<client::Ping> client;
|
||||
int maxResponses;
|
||||
int numResponses;
|
||||
bool wantLoss;
|
||||
bool wantLoss = false;
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(PingIntegrated)
|
||||
BOOST_AUTO_TEST_SUITE(Ping)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestIntegrated, PingIntegratedFixture)
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(Normal, PingIntegratedFixture)
|
||||
BOOST_AUTO_TEST_CASE(Normal)
|
||||
{
|
||||
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,32 +98,30 @@ 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)
|
||||
BOOST_AUTO_TEST_CASE(Timeout)
|
||||
{
|
||||
wantLoss = true;
|
||||
|
||||
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,24 +131,20 @@ 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
|
||||
} // namespace ndn
|
||||
} // namespace ndn::ping::tests
|
||||
|
||||
@@ -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-2023, 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,40 +18,30 @@
|
||||
*/
|
||||
|
||||
#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"
|
||||
|
||||
namespace ndn {
|
||||
namespace ping {
|
||||
namespace server {
|
||||
namespace tests {
|
||||
#include <ndn-cxx/util/dummy-client-face.hpp>
|
||||
|
||||
namespace ndn::ping::server::tests {
|
||||
|
||||
using namespace ndn::tests;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(PingServerPingServer)
|
||||
|
||||
class CreatePingServerFixture : public IdentityManagementTimeFixture
|
||||
class PingServerFixture : public IoFixture, public KeyChainFixture
|
||||
{
|
||||
protected:
|
||||
CreatePingServerFixture()
|
||||
: face(util::makeDummyClientFace(io, {false, true}))
|
||||
, pingOptions(makeOptions())
|
||||
, pingServer(*face, m_keyChain, pingOptions)
|
||||
{
|
||||
}
|
||||
|
||||
Interest
|
||||
makePingInterest(int seq) const
|
||||
{
|
||||
Name name(pingOptions.prefix);
|
||||
name.append("ping");
|
||||
name.append(std::to_string(seq));
|
||||
Interest interest(name);
|
||||
interest.setMustBeFresh(true);
|
||||
interest.setInterestLifetime(time::milliseconds(2000));
|
||||
return interest;
|
||||
name.append("ping")
|
||||
.append(to_string(seq));
|
||||
|
||||
return Interest(name)
|
||||
.setMustBeFresh(true)
|
||||
.setInterestLifetime(2_s);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -59,39 +49,40 @@ 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;
|
||||
Options pingOptions;
|
||||
PingServer pingServer;
|
||||
DummyClientFace face{m_io, m_keyChain, {false, true}};
|
||||
Options pingOptions{makeOptions()};
|
||||
PingServer pingServer{face, m_keyChain, pingOptions};
|
||||
};
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(CreatePingServer, CreatePingServerFixture)
|
||||
BOOST_AUTO_TEST_SUITE(Ping)
|
||||
BOOST_AUTO_TEST_SUITE(TestServer)
|
||||
|
||||
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
|
||||
} // namespace ping
|
||||
} // namespace ndn
|
||||
} // namespace ndn::ping::server::tests
|
||||
|
||||
@@ -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,22 +17,23 @@
|
||||
* 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.
|
||||
namespace ndn::tool_name::tests {
|
||||
|
||||
// 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,22 +41,19 @@ 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_71_0/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()
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestSkeleton
|
||||
|
||||
} // namespace tests
|
||||
} // namespace tool_name
|
||||
} // namespace ndn
|
||||
} // namespace ndn::tool_name::tests
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2023, 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::tests {
|
||||
|
||||
shared_ptr<Interest>
|
||||
makeInterest(const Name& name, bool canBePrefix, std::optional<time::milliseconds> lifetime,
|
||||
std::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 ndn::tests
|
||||
+47
-104
@@ -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-2023, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,121 +26,64 @@
|
||||
#ifndef NDN_TOOLS_TESTS_TEST_COMMON_HPP
|
||||
#define NDN_TOOLS_TESTS_TEST_COMMON_HPP
|
||||
|
||||
#include "boost-test.hpp"
|
||||
#include "core/common.hpp"
|
||||
#include "tests/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>
|
||||
namespace ndn::tests {
|
||||
|
||||
#include <boost/asio/io_service.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,
|
||||
std::optional<time::milliseconds> lifetime = std::nullopt,
|
||||
std::optional<Interest::Nonce> nonce = std::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)
|
||||
{
|
||||
BOOST_ASSERT(nTicks >= 0);
|
||||
|
||||
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)
|
||||
/**
|
||||
* \brief Create a Nack
|
||||
*/
|
||||
lp::Nack
|
||||
makeNack(Interest interest, lp::NackReason reason);
|
||||
|
||||
/**
|
||||
* \brief Replace a name component in a packet
|
||||
* \param[in,out] 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)
|
||||
{
|
||||
shared_ptr<Data> data = make_shared<Data>(name);
|
||||
return signData(data);
|
||||
Name name = pkt.getName();
|
||||
name.set(index, name::Component(std::forward<Args>(args)...));
|
||||
pkt.setName(name);
|
||||
}
|
||||
|
||||
|
||||
} // namespace tests
|
||||
} // namespace ndn
|
||||
} // namespace ndn::tests
|
||||
|
||||
#endif // NDN_TOOLS_TESTS_TEST_COMMON_HPP
|
||||
|
||||
+6
-10
@@ -2,13 +2,9 @@
|
||||
top = '..'
|
||||
|
||||
def build(bld):
|
||||
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,
|
||||
)
|
||||
bld.program(
|
||||
target=f'{top}/unit-tests',
|
||||
name='unit-tests',
|
||||
source=bld.path.ant_glob(['*.cpp'] + [f'{tool}/**/*.cpp' for tool in bld.env.BUILD_TOOLS]),
|
||||
use=['BOOST_TESTS', 'core-objects'] + [f'{tool}-objects' for tool in bld.env.BUILD_TOOLS],
|
||||
install_path=None)
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
# ndncatchunks and ndnputchunks
|
||||
|
||||
**ndncatchunks** and **ndnputchunks** are a pair of programs to transfer a file as Data segments.
|
||||
|
||||
* **ndnputchunks** is a producer program that reads a file from the standard input, and makes
|
||||
it available as 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-3-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 in ndncatchunks
|
||||
|
||||
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](https://redmine.named-data.net/projects/ndn-tlv/wiki/RDR).
|
||||
|
||||
## Interest pipeline types in ndncatchunks
|
||||
|
||||
* `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
|
||||
|
||||
### Publishing
|
||||
|
||||
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 find the published version you have to start ndnputchunks with the `-p` command line option,
|
||||
for example:
|
||||
|
||||
ndnputchunks -p /localhost/demo/gpl3 < /usr/share/common-licenses/GPL-3
|
||||
|
||||
This command will print the published version to standard output.
|
||||
|
||||
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 -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 /localhost/demo/gpl3
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,88 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Wentao Shang
|
||||
* @author Steve DiBenedetto
|
||||
* @author Andrea Tosatto
|
||||
*/
|
||||
|
||||
#include "consumer.hpp"
|
||||
|
||||
namespace ndn::chunks {
|
||||
|
||||
Consumer::Consumer(security::Validator& validator, std::ostream& os)
|
||||
: m_validator(validator)
|
||||
, m_outputStream(os)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Consumer::run(unique_ptr<DiscoverVersion> discover, unique_ptr<PipelineInterests> pipeline)
|
||||
{
|
||||
m_discover = std::move(discover);
|
||||
m_pipeline = std::move(pipeline);
|
||||
m_nextToPrint = 0;
|
||||
m_bufferedData.clear();
|
||||
|
||||
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::handleData(const Data& data)
|
||||
{
|
||||
auto dataPtr = data.shared_from_this();
|
||||
|
||||
m_validator.validate(data,
|
||||
[this, dataPtr] (const Data& data) {
|
||||
if (data.getContentType() == ndn::tlv::ContentType_Nack) {
|
||||
NDN_THROW(ApplicationNackError(data));
|
||||
}
|
||||
|
||||
// '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
|
||||
Consumer::writeInOrderData()
|
||||
{
|
||||
for (auto it = m_bufferedData.begin();
|
||||
it != m_bufferedData.end() && it->first == m_nextToPrint;
|
||||
it = m_bufferedData.erase(it), ++m_nextToPrint) {
|
||||
const Block& content = it->second->getContent();
|
||||
m_outputStream.write(reinterpret_cast<const char*>(content.value()), content.value_size());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ndn::chunks
|
||||
@@ -0,0 +1,104 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Wentao Shang
|
||||
* @author Steve DiBenedetto
|
||||
* @author Andrea Tosatto
|
||||
*/
|
||||
|
||||
#ifndef NDN_TOOLS_CHUNKS_CATCHUNKS_CONSUMER_HPP
|
||||
#define NDN_TOOLS_CHUNKS_CATCHUNKS_CONSUMER_HPP
|
||||
|
||||
#include "discover-version.hpp"
|
||||
#include "pipeline-interests.hpp"
|
||||
|
||||
#include <ndn-cxx/security/validation-error.hpp>
|
||||
#include <ndn-cxx/security/validator.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace ndn::chunks {
|
||||
|
||||
/**
|
||||
* @brief Segmented version consumer
|
||||
*
|
||||
* Discover the latest version of the data published under a specified prefix, and retrieve all the
|
||||
* segments associated to that version. The segments are fetched in order and written to a
|
||||
* user-specified stream in the same order.
|
||||
*/
|
||||
class Consumer : noncopyable
|
||||
{
|
||||
public:
|
||||
class ApplicationNackError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
ApplicationNackError(const Data& data)
|
||||
: std::runtime_error("Application generated Nack: " + boost::lexical_cast<std::string>(data))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class DataValidationError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
DataValidationError(const security::ValidationError& error)
|
||||
: std::runtime_error(boost::lexical_cast<std::string>(error))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create the consumer
|
||||
*/
|
||||
explicit
|
||||
Consumer(security::Validator& validator, std::ostream& os = std::cout);
|
||||
|
||||
/**
|
||||
* @brief Run the consumer
|
||||
*/
|
||||
void
|
||||
run(unique_ptr<DiscoverVersion> discover, unique_ptr<PipelineInterests> pipeline);
|
||||
|
||||
private:
|
||||
void
|
||||
handleData(const Data& data);
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
void
|
||||
writeInOrderData();
|
||||
|
||||
private:
|
||||
security::Validator& m_validator;
|
||||
std::ostream& m_outputStream;
|
||||
unique_ptr<DiscoverVersion> m_discover;
|
||||
unique_ptr<PipelineInterests> m_pipeline;
|
||||
uint64_t m_nextToPrint = 0;
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
std::map<uint64_t, shared_ptr<const Data>> m_bufferedData;
|
||||
};
|
||||
|
||||
} // namespace ndn::chunks
|
||||
|
||||
#endif // NDN_TOOLS_CHUNKS_CATCHUNKS_CONSUMER_HPP
|
||||
@@ -0,0 +1,171 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2016-2023, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Andrea Tosatto
|
||||
* @author Davide Pesavento
|
||||
*/
|
||||
|
||||
#include "data-fetcher.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace ndn::chunks {
|
||||
|
||||
shared_ptr<DataFetcher>
|
||||
DataFetcher::fetch(Face& face, const Interest& interest, int maxNackRetries, int maxTimeoutRetries,
|
||||
DataCallback onData, FailureCallback onNack, FailureCallback onTimeout,
|
||||
bool isVerbose)
|
||||
{
|
||||
auto dataFetcher = shared_ptr<DataFetcher>(new DataFetcher(face,
|
||||
maxNackRetries,
|
||||
maxTimeoutRetries,
|
||||
std::move(onData),
|
||||
std::move(onNack),
|
||||
std::move(onTimeout),
|
||||
isVerbose));
|
||||
dataFetcher->expressInterest(interest, dataFetcher);
|
||||
return dataFetcher;
|
||||
}
|
||||
|
||||
DataFetcher::DataFetcher(Face& face, int maxNackRetries, int maxTimeoutRetries,
|
||||
DataCallback onData, FailureCallback onNack, FailureCallback onTimeout,
|
||||
bool isVerbose)
|
||||
: m_face(face)
|
||||
, m_scheduler(m_face.getIoContext())
|
||||
, m_onData(std::move(onData))
|
||||
, m_onNack(std::move(onNack))
|
||||
, m_onTimeout(std::move(onTimeout))
|
||||
, m_maxNackRetries(maxNackRetries)
|
||||
, m_maxTimeoutRetries(maxTimeoutRetries)
|
||||
, m_isVerbose(isVerbose)
|
||||
{
|
||||
BOOST_ASSERT(m_onData != nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
DataFetcher::cancel()
|
||||
{
|
||||
if (isRunning()) {
|
||||
m_isStopped = true;
|
||||
m_pendingInterest.cancel();
|
||||
m_scheduler.cancelAllEvents();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DataFetcher::expressInterest(const Interest& interest, const shared_ptr<DataFetcher>& self)
|
||||
{
|
||||
m_nCongestionRetries = 0;
|
||||
m_pendingInterest = m_face.expressInterest(interest,
|
||||
[=] (auto&&... args) { handleData(std::forward<decltype(args)>(args)..., self); },
|
||||
[=] (auto&&... args) { handleNack(std::forward<decltype(args)>(args)..., self); },
|
||||
[=] (auto&&... args) { handleTimeout(std::forward<decltype(args)>(args)..., self); });
|
||||
}
|
||||
|
||||
void
|
||||
DataFetcher::handleData(const Interest& interest, const Data& data,
|
||||
const shared_ptr<DataFetcher>& self)
|
||||
{
|
||||
if (!isRunning())
|
||||
return;
|
||||
|
||||
m_isStopped = true;
|
||||
m_onData(interest, data);
|
||||
}
|
||||
|
||||
void
|
||||
DataFetcher::handleNack(const Interest& interest, const lp::Nack& nack,
|
||||
const shared_ptr<DataFetcher>& self)
|
||||
{
|
||||
if (!isRunning())
|
||||
return;
|
||||
|
||||
if (m_maxNackRetries != MAX_RETRIES_INFINITE)
|
||||
++m_nNacks;
|
||||
|
||||
if (m_isVerbose)
|
||||
std::cerr << "Received Nack with reason " << nack.getReason()
|
||||
<< " for Interest " << interest << "\n";
|
||||
|
||||
if (m_nNacks <= m_maxNackRetries || m_maxNackRetries == MAX_RETRIES_INFINITE) {
|
||||
Interest newInterest(interest);
|
||||
newInterest.refreshNonce();
|
||||
|
||||
switch (nack.getReason()) {
|
||||
case lp::NackReason::DUPLICATE: {
|
||||
expressInterest(newInterest, self);
|
||||
break;
|
||||
}
|
||||
case lp::NackReason::CONGESTION: {
|
||||
time::milliseconds backoffTime(static_cast<uint64_t>(std::pow(2, m_nCongestionRetries)));
|
||||
if (backoffTime > MAX_CONGESTION_BACKOFF_TIME) {
|
||||
backoffTime = MAX_CONGESTION_BACKOFF_TIME;
|
||||
}
|
||||
else {
|
||||
m_nCongestionRetries++;
|
||||
}
|
||||
m_scheduler.schedule(backoffTime, [=] { expressInterest(newInterest, self); });
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
m_hasError = true;
|
||||
if (m_onNack)
|
||||
m_onNack(interest, "Could not retrieve data for " + interest.getName().toUri() +
|
||||
", reason: " + boost::lexical_cast<std::string>(nack.getReason()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_hasError = true;
|
||||
if (m_onNack)
|
||||
m_onNack(interest, "Reached the maximum number of nack retries (" + to_string(m_maxNackRetries) +
|
||||
") while retrieving data for " + interest.getName().toUri());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DataFetcher::handleTimeout(const Interest& interest, const shared_ptr<DataFetcher>& self)
|
||||
{
|
||||
if (!isRunning())
|
||||
return;
|
||||
|
||||
if (m_maxTimeoutRetries != MAX_RETRIES_INFINITE)
|
||||
++m_nTimeouts;
|
||||
|
||||
if (m_isVerbose)
|
||||
std::cerr << "Timeout for Interest " << interest << "\n";
|
||||
|
||||
if (m_nTimeouts <= m_maxTimeoutRetries || m_maxTimeoutRetries == MAX_RETRIES_INFINITE) {
|
||||
Interest newInterest(interest);
|
||||
newInterest.refreshNonce();
|
||||
expressInterest(newInterest, self);
|
||||
}
|
||||
else {
|
||||
m_hasError = true;
|
||||
if (m_onTimeout)
|
||||
m_onTimeout(interest, "Reached the maximum number of timeout retries (" + to_string(m_maxTimeoutRetries) +
|
||||
") while retrieving data for " + interest.getName().toUri());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ndn::chunks
|
||||
@@ -0,0 +1,130 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Andrea Tosatto
|
||||
* @author Davide Pesavento
|
||||
*/
|
||||
|
||||
#ifndef NDN_TOOLS_CHUNKS_CATCHUNKS_DATA_FETCHER_HPP
|
||||
#define NDN_TOOLS_CHUNKS_CATCHUNKS_DATA_FETCHER_HPP
|
||||
|
||||
#include "core/common.hpp"
|
||||
|
||||
namespace ndn::chunks {
|
||||
|
||||
/**
|
||||
* @brief Fetch data for a given interest and handle timeout or nack error with retries.
|
||||
*
|
||||
* To instantiate a DataFetcher you need to use the static method fetch, this will also express the
|
||||
* interest. After a timeout or nack is received, the same interest with a different nonce will be
|
||||
* requested for a maximum number of time specified by the class user. There are separate retry
|
||||
* counters for timeouts and nacks.
|
||||
*
|
||||
* A specified callback is called after the data matching the expressed interest is received. A
|
||||
* different callback is called in case one of the retries counter reach the maximum. This callback
|
||||
* can be different for timeout and nack. The data callback must be defined but the others callback
|
||||
* are optional.
|
||||
*
|
||||
*/
|
||||
class DataFetcher
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief means that there is no maximum number of retries,
|
||||
* i.e. fetching must be retried indefinitely
|
||||
*/
|
||||
static constexpr int MAX_RETRIES_INFINITE = -1;
|
||||
|
||||
/**
|
||||
* @brief ceiling value for backoff time used in congestion handling
|
||||
*/
|
||||
static constexpr time::milliseconds MAX_CONGESTION_BACKOFF_TIME = 10_s;
|
||||
|
||||
using FailureCallback = std::function<void(const Interest& interest, const std::string& reason)>;
|
||||
|
||||
/**
|
||||
* @brief instantiate a DataFetcher object and start fetching data
|
||||
*
|
||||
* @param onData callback for segment correctly received, must not be empty
|
||||
*/
|
||||
static shared_ptr<DataFetcher>
|
||||
fetch(Face& face, const Interest& interest, int maxNackRetries, int maxTimeoutRetries,
|
||||
DataCallback onData, FailureCallback onTimeout, FailureCallback onNack,
|
||||
bool isVerbose);
|
||||
|
||||
/**
|
||||
* @brief stop data fetching without error and calling any callback
|
||||
*/
|
||||
void
|
||||
cancel();
|
||||
|
||||
bool
|
||||
isRunning() const
|
||||
{
|
||||
return !m_isStopped && !m_hasError;
|
||||
}
|
||||
|
||||
bool
|
||||
hasError() const
|
||||
{
|
||||
return m_hasError;
|
||||
}
|
||||
|
||||
private:
|
||||
DataFetcher(Face& face, int maxNackRetries, int maxTimeoutRetries,
|
||||
DataCallback onData, FailureCallback onNack, FailureCallback onTimeout,
|
||||
bool isVerbose);
|
||||
|
||||
void
|
||||
expressInterest(const Interest& interest, const shared_ptr<DataFetcher>& self);
|
||||
|
||||
void
|
||||
handleData(const Interest& interest, const Data& data, const shared_ptr<DataFetcher>& self);
|
||||
|
||||
void
|
||||
handleNack(const Interest& interest, const lp::Nack& nack, const shared_ptr<DataFetcher>& self);
|
||||
|
||||
void
|
||||
handleTimeout(const Interest& interest, const shared_ptr<DataFetcher>& self);
|
||||
|
||||
private:
|
||||
Face& m_face;
|
||||
Scheduler m_scheduler;
|
||||
PendingInterestHandle m_pendingInterest;
|
||||
DataCallback m_onData;
|
||||
FailureCallback m_onNack;
|
||||
FailureCallback m_onTimeout;
|
||||
|
||||
int m_maxNackRetries;
|
||||
int m_maxTimeoutRetries;
|
||||
int m_nNacks = 0;
|
||||
int m_nTimeouts = 0;
|
||||
uint32_t m_nCongestionRetries = 0;
|
||||
|
||||
bool m_isVerbose = false;
|
||||
bool m_isStopped = false;
|
||||
bool m_hasError = false;
|
||||
};
|
||||
|
||||
} // namespace ndn::chunks
|
||||
|
||||
#endif // NDN_TOOLS_CHUNKS_CATCHUNKS_DATA_FETCHER_HPP
|
||||
@@ -0,0 +1,95 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Wentao Shang
|
||||
* @author Steve DiBenedetto
|
||||
* @author Andrea Tosatto
|
||||
* @author Chavoosh Ghasemi
|
||||
*/
|
||||
|
||||
#include "discover-version.hpp"
|
||||
#include "data-fetcher.hpp"
|
||||
|
||||
#include <ndn-cxx/metadata-object.hpp>
|
||||
|
||||
namespace ndn::chunks {
|
||||
|
||||
DiscoverVersion::DiscoverVersion(Face& face, const Name& prefix, const Options& options)
|
||||
: m_face(face)
|
||||
, m_prefix(prefix)
|
||||
, m_options(options)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
DiscoverVersion::run()
|
||||
{
|
||||
if (m_options.disableVersionDiscovery || (!m_prefix.empty() && m_prefix[-1].isVersion())) {
|
||||
onDiscoverySuccess(m_prefix);
|
||||
return;
|
||||
}
|
||||
|
||||
Interest interest = MetadataObject::makeDiscoveryInterest(m_prefix)
|
||||
.setInterestLifetime(m_options.interestLifetime);
|
||||
|
||||
m_fetcher = DataFetcher::fetch(m_face, interest,
|
||||
m_options.maxRetriesOnTimeoutOrNack,
|
||||
m_options.maxRetriesOnTimeoutOrNack,
|
||||
FORWARD_TO_MEM_FN(handleData),
|
||||
[this] (const auto&, const auto& reason) {
|
||||
onDiscoveryFailure(reason);
|
||||
},
|
||||
[this] (const auto&, const auto& reason) {
|
||||
onDiscoveryFailure(reason);
|
||||
},
|
||||
m_options.isVerbose);
|
||||
}
|
||||
|
||||
void
|
||||
DiscoverVersion::handleData(const Interest& interest, const Data& data)
|
||||
{
|
||||
if (m_options.isVerbose)
|
||||
std::cerr << "Data: " << data << "\n";
|
||||
|
||||
// make a metadata object from received metadata packet
|
||||
MetadataObject mobject;
|
||||
try {
|
||||
mobject = MetadataObject(data);
|
||||
}
|
||||
catch (const tlv::Error& e) {
|
||||
onDiscoveryFailure("Invalid metadata packet: "s + e.what());
|
||||
return;
|
||||
}
|
||||
|
||||
if (mobject.getVersionedName().empty() || !mobject.getVersionedName()[-1].isVersion()) {
|
||||
onDiscoveryFailure(mobject.getVersionedName().toUri() + " is not a valid versioned name");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_options.isVerbose) {
|
||||
std::cerr << "Discovered Data version: " << mobject.getVersionedName()[-1] << "\n";
|
||||
}
|
||||
|
||||
onDiscoverySuccess(mobject.getVersionedName());
|
||||
}
|
||||
|
||||
} // namespace ndn::chunks
|
||||
@@ -0,0 +1,77 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2016-2023, Regents of the University of California,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University.
|
||||
*
|
||||
* This file is part of ndn-tools (Named Data Networking Essential Tools).
|
||||
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
|
||||
*
|
||||
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Wentao Shang
|
||||
* @author Steve DiBenedetto
|
||||
* @author Andrea Tosatto
|
||||
* @author Chavoosh Ghasemi
|
||||
*/
|
||||
|
||||
#ifndef NDN_TOOLS_CHUNKS_CATCHUNKS_DISCOVER_VERSION_HPP
|
||||
#define NDN_TOOLS_CHUNKS_CATCHUNKS_DISCOVER_VERSION_HPP
|
||||
|
||||
#include "options.hpp"
|
||||
|
||||
#include <ndn-cxx/util/signal.hpp>
|
||||
|
||||
namespace ndn::chunks {
|
||||
|
||||
class DataFetcher;
|
||||
|
||||
/**
|
||||
* @brief Service for discovering the latest Data version.
|
||||
*
|
||||
* DiscoverVersion's user is notified once after identifying the latest retrievable version or
|
||||
* on failure to find any Data version.
|
||||
*/
|
||||
class DiscoverVersion
|
||||
{
|
||||
public:
|
||||
DiscoverVersion(Face& face, const Name& prefix, const Options& options);
|
||||
|
||||
/**
|
||||
* @brief Signal emitted when the versioned name of Data is found.
|
||||
*/
|
||||
signal::Signal<DiscoverVersion, Name> onDiscoverySuccess;
|
||||
|
||||
/**
|
||||
* @brief Signal emitted when a failure occurs.
|
||||
*/
|
||||
signal::Signal<DiscoverVersion, std::string> onDiscoveryFailure;
|
||||
|
||||
void
|
||||
run();
|
||||
|
||||
private:
|
||||
void
|
||||
handleData(const Interest& interest, const Data& data);
|
||||
|
||||
private:
|
||||
Face& m_face;
|
||||
const Name m_prefix;
|
||||
const Options& m_options;
|
||||
shared_ptr<DataFetcher> m_fetcher;
|
||||
};
|
||||
|
||||
} // namespace ndn::chunks
|
||||
|
||||
#endif // NDN_TOOLS_CHUNKS_CATCHUNKS_DISCOVER_VERSION_HPP
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user