Compare commits

..
3 Commits
Author SHA1 Message Date
root 1a792daaa3 feat(qsccp): Add QSCCP strategy 2023-12-18 12:49:43 +08:00
SunnyQjm 34e13e9802 fix: Do calculateRate by trigger not by scheduler 2023-12-15 14:55:20 +00:00
SunnyQjm 3813f1c9ee feat: Add qsccp sched 2023-12-03 21:08:06 +08:00
540 changed files with 13380 additions and 11099 deletions

No files matched your search

-8
View File
@@ -1,8 +0,0 @@
Dockerfile
/build/
.waf-*-*/
.waf3-*-*/
.lock-waf*
/VERSION.info
-21
View File
@@ -1,21 +0,0 @@
name: CI
on:
push:
paths-ignore:
- 'docs/**'
- '*.conf.sample*'
- '*.md'
- '.mailmap'
workflow_dispatch:
permissions: {}
jobs:
Ubuntu:
uses: named-data/actions/.github/workflows/jenkins-script-ubuntu.yml@v1
with:
submodules: true
macOS:
uses: named-data/actions/.github/workflows/jenkins-script-macos.yml@v1
with:
submodules: true
-81
View File
@@ -1,81 +0,0 @@
name: Publish Docker image
on:
push:
branches:
- master
paths-ignore:
- '*.md'
- '.mailmap'
workflow_dispatch:
permissions:
contents: read
packages: write
env:
REGISTRY: ghcr.io
jobs:
nfd:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: true
- name: Login to ${{ env.REGISTRY }}
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ github.repository_owner }}/nfd
flavor: latest=true
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
pull: true
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
nfd-status-http-server:
needs: nfd
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Login to ${{ env.REGISTRY }}
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ github.repository_owner }}/nfd-status-http-server
flavor: latest=true
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ./tools
file: ./tools/Dockerfile.nfd-status-http-server
pull: true
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
-24
View File
@@ -1,24 +0,0 @@
name: Docs
on:
push:
workflow_dispatch:
inputs:
skip-deploy:
description: 'Skip deployment?'
required: true
type: boolean
permissions: {}
jobs:
html:
uses: named-data/actions/.github/workflows/docs-html.yml@v1
with:
submodules: true
# Deploy only the master branch and release tags
deploy: ${{ !inputs.skip-deploy && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/NFD-')) }}
secrets: inherit
man:
uses: named-data/actions/.github/workflows/docs-man.yml@v1
with:
submodules: true
+16 -36
View File
@@ -1,52 +1,32 @@
#!/usr/bin/env bash
set -eo pipefail
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
set -e
source .jenkins.d/util.sh
export CACHE_DIR=${CACHE_DIR:-/tmp}
export WAF_JOBS=${WAF_JOBS:-1}
[[ $JOB_NAME == *"code-coverage" ]] && export DISABLE_ASAN=yes
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)
nanos() {
# Cannot use date(1) because macOS does not support %N format specifier
python3 -c 'import time; print(int(time.time() * 1e9))'
}
for file in .jenkins.d/*; do
[[ -f $file && -x $file ]] || continue
if [[ -n $GITHUB_ACTIONS ]]; then
if [[ -n $TRAVIS ]]; then
label=$(basename "$file" | sed -E 's/[[:digit:]]+-(.*)\..*/\1/')
echo "::group::${label}"
echo -ne "travis_fold:start:${label}\r"
echo -ne "travis_time:start:${label}\r"
start=$(nanos)
fi
echo "\$ $file"
"$file"
if [[ -n $GITHUB_ACTIONS ]]; then
echo "::endgroup::"
if [[ -n $TRAVIS ]]; then
finish=$(nanos)
echo -ne "travis_time:end:${label}:start=${start},finish=${finish},duration=$((finish-start)),event=${label}\r"
echo -ne "travis_fold:end:${label}\r"
fi
done
+34 -33
View File
@@ -1,40 +1,41 @@
#!/usr/bin/env bash
set -eo pipefail
set -ex
APT_PKGS=(build-essential pkg-config python3-minimal
libboost-all-dev libssl-dev libsqlite3-dev
libpcap-dev libsystemd-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+=(doxygen graphviz python3-pip)
FORMULAE+=(doxygen graphviz)
PIP_PKGS+=(sphinx sphinxcontrib-doxylink)
;;
esac
set -x
if [[ $ID == macos ]]; then
if [[ -n $GITHUB_ACTIONS ]]; then
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
if has OSX $NODE_LABELS; then
FORMULAE=(boost openssl pkg-config)
if has OSX-10.13 $NODE_LABELS || has OSX-10.14 $NODE_LABELS; then
FORMULAE+=(python)
fi
brew update
brew install --formula "${FORMULAE[@]}"
elif [[ $ID_LIKE == *debian* ]]; then
if [[ -n $TRAVIS ]]; then
# Travis images come with a large number of pre-installed
# brew packages, don't waste time upgrading all of them
brew list --versions "${FORMULAE[@]}" || brew update
for FORMULA in "${FORMULAE[@]}"; do
brew list --versions "$FORMULA" || brew install "$FORMULA"
done
# Ensure /usr/local/opt/openssl exists
brew reinstall openssl
else
brew update
brew upgrade
brew install "${FORMULAE[@]}"
brew cleanup
fi
elif has Ubuntu $NODE_LABELS; 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 \
sudo apt-get -qy install build-essential pkg-config python3-minimal \
libboost-all-dev libssl-dev libsqlite3-dev \
libpcap-dev libsystemd-dev
if [[ $JOB_NAME == *"code-coverage" ]]; then
sudo apt-get -qy install gcovr lcov
fi
elif has CentOS-8 $NODE_LABELS; then
sudo dnf config-manager --enable PowerTools
sudo dnf -y install gcc-c++ libasan pkgconf-pkg-config python3 \
boost-devel openssl-devel sqlite-devel \
libpcap-devel systemd-devel
fi
if (( ${#PIP_PKGS[@]} )); then
pip3 install --user --upgrade --upgrade-strategy=eager "${PIP_PKGS[@]}"
fi
+13 -8
View File
@@ -1,11 +1,11 @@
#!/usr/bin/env bash
set -exo pipefail
set -ex
pushd "$CACHE_DIR" >/dev/null
INSTALLED_VERSION=
if [[ $ID == macos ]]; then
BOOST=$(brew list --formula --versions boost)
if has OSX $NODE_LABELS; then
BOOST=$(brew ls --versions boost)
OLD_BOOST=$(cat boost.txt || :)
if [[ $OLD_BOOST != $BOOST ]]; then
echo "$BOOST" > boost.txt
@@ -35,16 +35,21 @@ 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
if has CentOS-8 $NODE_LABELS; then
# https://bugzilla.redhat.com/show_bug.cgi?id=1721553
PCH="--without-pch"
fi
./waf --color=yes configure --disable-static --enable-shared --without-osx-keychain $PCH
./waf --color=yes build -j$WAF_JOBS
sudo_preserve_env PATH -- ./waf --color=yes install
popd >/dev/null
popd >/dev/null
if [[ $ID_LIKE == *fedora* ]]; then
if has CentOS-8 $NODE_LABELS; then
sudo tee /etc/ld.so.conf.d/ndn.conf >/dev/null <<< /usr/local/lib64
fi
if [[ $ID_LIKE == *linux* ]]; then
if has Linux $NODE_LABELS; then
sudo ldconfig
fi
+10 -8
View File
@@ -1,5 +1,8 @@
#!/usr/bin/env bash
set -eo pipefail
set -ex
git submodule sync
git submodule update --init
if [[ -z $DISABLE_ASAN ]]; then
ASAN="--with-sanitizer=address"
@@ -7,23 +10,22 @@ fi
if [[ $JOB_NAME == *"code-coverage" ]]; then
COVERAGE="--with-coverage"
fi
if [[ -n $DISABLE_PCH ]]; then
if has CentOS-8 $NODE_LABELS; then
# https://bugzilla.redhat.com/show_bug.cgi?id=1721553
PCH="--without-pch"
fi
set -x
if [[ $JOB_NAME != *"code-coverage" && $JOB_NAME != *"limited-build" ]]; then
# Build in release mode with tests and without precompiled headers
./waf --color=yes configure --with-tests --without-pch
./waf --color=yes build
./waf --color=yes build -j$WAF_JOBS
# Cleanup
./waf --color=yes distclean
# Build in release mode without tests, but with "other tests"
./waf --color=yes configure --with-other-tests $PCH
./waf --color=yes build
./waf --color=yes build -j$WAF_JOBS
# Cleanup
./waf --color=yes distclean
@@ -31,9 +33,9 @@ fi
# Build in debug mode with tests
./waf --color=yes configure --debug --with-tests $ASAN $COVERAGE $PCH
./waf --color=yes build
./waf --color=yes build -j$WAF_JOBS
# (tests will be run against the debug version)
# Install
sudo ./waf --color=yes install
sudo_preserve_env PATH -- ./waf --color=yes install
+13 -10
View File
@@ -1,5 +1,14 @@
#!/usr/bin/env bash
set -eo pipefail
set -ex
# Prepare environment
rm -rf ~/.ndn
if has OSX $NODE_LABELS; then
security unlock-keychain -p named-data
fi
ndnsec-keygen "/tmp/jenkins/$NODE_NAME" | ndnsec-install-cert -
# https://github.com/google/sanitizers/wiki/AddressSanitizerFlags
ASAN_OPTIONS="color=always"
@@ -13,7 +22,6 @@ ASAN_OPTIONS+=":detect_leaks=0"
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
@@ -22,11 +30,6 @@ ut_log_args() {
echo --logger=HRF,test_suite,stdout:XML,all,build/xunit-log${1:+-$1}.xml
}
set -x
# Prepare environment
rm -rf ~/.ndn
# First run all tests as unprivileged user
./build/unit-tests-core $(ut_log_args core)
./build/unit-tests-daemon $(ut_log_args daemon)
@@ -34,9 +37,9 @@ rm -rf ~/.ndn
./build/unit-tests-tools $(ut_log_args tools)
# Then use sudo to run those tests that need superuser powers
sudo --preserve-env=ASAN_OPTIONS,BOOST_TEST_COLOR_OUTPUT \
sudo_preserve_env ASAN_OPTIONS BOOST_TEST_COLOR_OUTPUT -- \
./build/unit-tests-daemon -t TestPrivilegeHelper $(ut_log_args daemon-privilege-helper)
sudo --preserve-env=ASAN_OPTIONS,BOOST_TEST_COLOR_OUTPUT \
sudo_preserve_env ASAN_OPTIONS BOOST_TEST_COLOR_OUTPUT -- \
./build/unit-tests-daemon -t Face/*Ethernet* $(ut_log_args daemon-ethernet)
sudo --preserve-env=ASAN_OPTIONS,BOOST_TEST_COLOR_OUTPUT \
sudo_preserve_env ASAN_OPTIONS BOOST_TEST_COLOR_OUTPUT -- \
./build/unit-tests-daemon -t Face/TestUdpFactory $(ut_log_args daemon-udp)
+18 -15
View File
@@ -1,32 +1,35 @@
#!/usr/bin/env bash
set -exo pipefail
set -ex
if [[ $JOB_NAME == *"code-coverage" ]]; then
# Generate an XML report (Cobertura format) and a detailed HTML report using gcovr
# Note: trailing slashes are important in the paths below. Do not remove them!
gcovr --object-directory build \
--exclude tests/ \
--exclude websocketpp/ \
--exclude-throw-branches \
--exclude-unreachable-branches \
--cobertura build/coverage.xml \
--html-details build/gcovr/ \
--print-summary
gcovr --object-directory=build \
--output=build/coverage.xml \
--exclude="$PWD/(tests|websocketpp)" \
--root=. \
--xml
# Generate a detailed HTML report using lcov
# Generate also a detailed HTML output, but using lcov (better results)
lcov --quiet \
--capture \
--directory . \
--exclude "$PWD/tests/*" \
--exclude "$PWD/websocketpp/*" \
--no-external \
--rc lcov_branch_coverage=1 \
--output-file build/coverage-with-tests-and-websocketpp.info
lcov --quiet \
--remove build/coverage-with-tests-and-websocketpp.info "$PWD/websocketpp/*" \
--rc lcov_branch_coverage=1 \
--output-file build/coverage-with-tests.info
lcov --quiet \
--remove build/coverage-with-tests.info "$PWD/tests/*" \
--rc lcov_branch_coverage=1 \
--output-file build/coverage.info
genhtml --branch-coverage \
--demangle-cpp \
--legend \
--output-directory build/lcov \
--output-directory build/coverage \
--title "NFD unit tests" \
build/coverage.info
fi
+16 -24
View File
@@ -1,36 +1,28 @@
# Continuous Integration Scripts
# CONTINUOUS INTEGRATION SCRIPTS
## Environment Variables
## Environment Variables Used in Build Scripts
- `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`.
- `NODE_LABELS`: space-separated list of platform properties. The included values are used by
the build scripts to select the proper behavior for different operating systems and versions.
- `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.
The list should normally contain `[OS_TYPE]`, `[DISTRO_TYPE]`, and `[DISTRO_VERSION]`.
Examples:
Example values:
- On CentOS, `ID_LIKE="centos rhel fedora linux"`
- On Ubuntu, `ID_LIKE="ubuntu debian linux"`
- `[OS_TYPE]`: `Linux`, `OSX`
- `[DISTRO_TYPE]`: `Ubuntu`, `CentOS`
- `[DISTRO_VERSION]`: `Ubuntu-16.04`, `Ubuntu-18.04`, `CentOS-8`, `OSX-10.14`, `OSX-10.15`
- `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`.
- `JOB_NAME`: optional variable that defines the type of build job. Depending on the job type,
the build scripts can perform different tasks.
- `JOB_NAME`: defines the type of the current CI job. Depending on the job type, the CI
scripts can perform different tasks.
Supported values:
Possible values:
- empty: default build task
- `code-coverage`: debug build with tests and code coverage analysis
- `code-coverage`: debug build with tests and code coverage analysis (Ubuntu Linux is assumed)
- `limited-build`: only a single debug build with tests
- `CACHE_DIR`: directory containing cached files from previous builds, e.g., a compiled
version of ndn-cxx. If not set, `/tmp` is used.
- `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
- `WAF_JOBS`: number of parallel build threads used by waf, defaults to 1.
+39
View File
@@ -0,0 +1,39 @@
has() {
local saved_xtrace
[[ $- == *x* ]] && saved_xtrace=-x || saved_xtrace=+x
set +x
local p=$1
shift
local i ret=1
for i in "$@"; do
if [[ "${i}" == "${p}" ]]; then
ret=0
break
fi
done
set ${saved_xtrace}
return ${ret}
}
export -f has
sudo_preserve_env() {
local saved_xtrace
[[ $- == *x* ]] && saved_xtrace=-x || saved_xtrace=+x
set +x
local vars=()
while [[ $# -gt 0 ]]; do
local arg=$1
shift
case ${arg} in
--) break ;;
*) vars+=("${arg}=${!arg}") ;;
esac
done
set ${saved_xtrace}
sudo env "${vars[@]}" "$@"
}
export -f sudo_preserve_env
+7 -9
View File
@@ -1,16 +1,14 @@
<aa@cs.fiu.edu> <alexander.afanasyev@ucla.edu>
Alexander Lane <awlane@memphis.edu>
<chghasemi@cs.arizona.edu> <chavoosh.ghasemi@gmail.com>
<davidepesa@gmail.com> <davide.pesavento@lip6.fr>
<enewberry@email.arizona.edu> <enewberry@cs.arizona.edu>
Haowei Yuan <hyuan@wustl.edu>
Hila Ben Abraham <hilata@gmail.com>
Vince Lehman <vslehman@memphis.edu> <vlehman1@gmail.com>
<lybmath2009@gmail.com> <lybmath@ucla.edu>
Md Ashiqur Rahman <marahman@email.arizona.edu>
Hila Ben Abraham <hilata@gmail.com>
<tuyukai1994@gmail.com> <tyk@bupt.edu.cn>
Haowei Yuan <hyuan@wustl.edu>
Minsheng Zhang <jimmyzms5@gmail.com>
Spyridon Mastorakis <spiros.mastorakis@gmail.com>
Susmit Shannigrahi <susmit@cs.colostate.edu>
Tai-Lin Chu <tailinchu@gmail.com>
<tuyukai1994@gmail.com> <tyk@bupt.edu.cn>
Vince Lehman <vslehman@memphis.edu> <vlehman1@gmail.com>
Md Ashiqur Rahman <marahman@email.arizona.edu>
Yumin Xia <me@yumin-xia.com>
<chghasemi@cs.arizona.edu> <chavoosh.ghasemi@gmail.com>
Tai-Lin Chu <tailinchu@gmail.com>
+115
View File
@@ -0,0 +1,115 @@
version: ~> 1.0
language: cpp
os: linux
dist: bionic
arch:
- amd64
#- arm64 # Too slow, exceeds time limit
#- ppc64le # Fails transport tests
#- s390x # Fails transport tests
env:
- COMPILER=g++-7
- COMPILER=g++-9
- COMPILER=clang++-6.0
- COMPILER=clang++-9
jobs:
include:
# Linux
- env: COMPILER=g++-5
- env: COMPILER=g++-6
- env: COMPILER=g++-8
- env: COMPILER=clang++-4.0
- env: COMPILER=clang++-5.0
- env: COMPILER=clang++-7
- env: COMPILER=clang++-8
- env: COMPILER=clang++-10
- env: COMPILER=clang++-11
- env: COMPILER=clang++-12
# macOS
- os: osx
osx_image: xcode9.4
env: # default compiler
- os: osx
osx_image: xcode10.1
env: # default compiler
- os: osx
osx_image: xcode10.3
env: # default compiler
- os: osx
osx_image: xcode11.3
env: # default compiler
- os: osx
osx_image: xcode11.6
env: # default compiler
- os: osx
osx_image: xcode12
env: # default compiler
allow_failures:
- env: COMPILER=g++-5
- env: COMPILER=g++-6
- env: COMPILER=clang++-4.0
- env: COMPILER=clang++-12
fast_finish: true
before_install:
- |
: Adding apt repositories
case ${COMPILER} in
g++-9)
# https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test/+packages
travis_retry sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
travis_retry sudo apt-get -qq update
;;
clang++-1?)
# https://apt.llvm.org/
LLVM_REPO=${COMPILER/clang++/llvm-toolchain-${TRAVIS_DIST}}
travis_retry wget -nv -O - "https://apt.llvm.org/llvm-snapshot.gpg.key" | sudo apt-key add -
travis_retry sudo add-apt-repository -y "deb http://apt.llvm.org/${TRAVIS_DIST}/ ${LLVM_REPO%-12} main"
travis_retry sudo apt-get -qq update
;;
esac
install:
- |
: Installing C++ compiler
if [[ -n ${COMPILER} ]]; then
travis_retry sudo apt-get -qy install ${COMPILER/clang++/clang}
fi
before_script:
- |
: Setting environment variables
if [[ -n ${COMPILER} ]]; then
export CXX=${COMPILER}
fi
case ${TRAVIS_OS_NAME} in
linux) export NODE_LABELS="Linux Ubuntu Ubuntu-18.04" ;;
osx) export NODE_LABELS="OSX OSX-$(sw_vers -productVersion | cut -d . -f -2)" ;;
esac
export JOB_NAME=limited-build
export WAF_JOBS=2
- |
: Enabling workarounds
case "${TRAVIS_CPU_ARCH},${COMPILER}" in
ppc64le,g++-7)
# AddressSanitizer does not seem to be working
export DISABLE_ASAN=yes
;;
*,clang++-8)
# https://bugs.llvm.org/show_bug.cgi?id=40808
export DISABLE_ASAN=yes
;;
esac
if [[ ${TRAVIS_OS_NAME} == linux ]]; then
sudo sysctl -e -w net.ipv6.conf.all.disable_ipv6=0
fi
- ${CXX:-c++} --version
script:
- ./.jenkins
+2 -2
View File
@@ -54,8 +54,8 @@ 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']
BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include']
BOOST_VERSION_FILE = 'boost/version.hpp'
BOOST_VERSION_CODE = '''
+78 -91
View File
@@ -3,12 +3,10 @@
import platform
from waflib import Configure, Logs, Utils
def options(opt):
opt.add_option('--debug', '--with-debug', action='store_true', default=False,
help='Compile in debugging mode with minimal optimizations (-Og)')
def configure(conf):
conf.start_msg('Checking C++ compiler version')
@@ -18,27 +16,23 @@ def configure(conf):
errmsg = ''
warnmsg = ''
if cxx == 'gcc':
if ccver < (7, 4, 0):
if ccver < (5, 3, 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 '
'The minimum supported gcc version is 7.4.0.')
elif ccver < (7, 4, 0):
warnmsg = ('Using a version of gcc older than 7.4.0 is not '
'officially supported and may result in build failures.')
conf.flags = GccFlags()
elif cxx == 'clang':
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):
if Utils.unversioned_sys_platform() == 'darwin' and ccver < (9, 0, 0):
errmsg = ('The version of Xcode you are using is too old.\n'
'The minimum supported Xcode version is 9.0.')
elif ccver < (4, 0, 0):
errmsg = ('The version of clang you are using is too old.\n'
'The minimum supported clang version is 7.0.')
'The minimum supported clang version is 4.0.')
conf.flags = ClangFlags()
else:
warnmsg = f'{cxx} compiler is unsupported'
warnmsg = '%s compiler is unsupported' % cxx
conf.flags = CompilerFlags()
if errmsg:
@@ -50,7 +44,7 @@ def configure(conf):
else:
conf.end_msg(ccverstr)
conf.areCustomCxxflagsPresent = len(conf.env.CXXFLAGS) > 0
conf.areCustomCxxflagsPresent = (len(conf.env.CXXFLAGS) > 0)
# General flags are always applied (e.g., selecting C++ language standard)
generalFlags = conf.flags.getGeneralFlags(conf)
@@ -58,7 +52,6 @@ def configure(conf):
conf.add_supported_linkflags(generalFlags['LINKFLAGS'])
conf.env.DEFINES += generalFlags['DEFINES']
@Configure.conf
def check_compiler_flags(conf):
# Debug or optimized CXXFLAGS and LINKFLAGS are applied only if the
@@ -81,11 +74,10 @@ def check_compiler_flags(conf):
conf.env.DEFINES += extraFlags['DEFINES']
@Configure.conf
def add_supported_cxxflags(self, cxxflags):
"""
Check which cxxflags are supported by the active compiler and add them to env.CXXFLAGS variable.
Check which cxxflags are supported by compiler and add them to env.CXXFLAGS variable
"""
if len(cxxflags) == 0:
return
@@ -101,11 +93,10 @@ def add_supported_cxxflags(self, cxxflags):
self.end_msg(' '.join(supportedFlags))
self.env.prepend_value('CXXFLAGS', supportedFlags)
@Configure.conf
def add_supported_linkflags(self, linkflags):
"""
Check which linkflags are supported by the active compiler and add them to env.LINKFLAGS variable.
Check which linkflags are supported by compiler and add them to env.LINKFLAGS variable
"""
if len(linkflags) == 0:
return
@@ -122,17 +113,13 @@ def add_supported_linkflags(self, linkflags):
self.env.prepend_value('LINKFLAGS', supportedFlags)
class CompilerFlags:
class CompilerFlags(object):
def getCompilerVersion(self, conf):
return tuple(int(i) for i in conf.env.CC_VERSION)
def getGeneralFlags(self, conf):
"""Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are always needed"""
return {
'CXXFLAGS': [],
'LINKFLAGS': [],
'DEFINES': ['BOOST_FILESYSTEM_NO_DEPRECATED'],
}
return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': []}
def getDebugFlags(self, conf):
"""Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are needed only in debug mode"""
@@ -142,99 +129,99 @@ class CompilerFlags:
"""Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are needed only in optimized mode"""
return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': ['NDEBUG']}
class GccClangCommonFlags(CompilerFlags):
class GccBasicFlags(CompilerFlags):
"""
This class defines common flags that work for both gcc and clang compilers.
This class defines basic 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 = super(GccBasicFlags, self).getGeneralFlags(conf)
flags['CXXFLAGS'] += ['-std=c++14']
if Utils.unversioned_sys_platform() == 'linux':
flags['LINKFLAGS'] += ['-fuse-ld=gold']
elif Utils.unversioned_sys_platform() == 'freebsd':
flags['LINKFLAGS'] += ['-fuse-ld=lld']
return flags
__cxxFlags = [
'-fdiagnostics-color',
'-Wall',
'-Wextra',
'-Wpedantic',
'-Wenum-conversion',
'-Wextra-semi',
'-Wno-unused-parameter',
]
__linkFlags = ['-Wl,-O1']
def getDebugFlags(self, conf):
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
flags = super(GccBasicFlags, self).getDebugFlags(conf)
flags['CXXFLAGS'] += ['-Og',
'-g3',
'-pedantic',
'-Wall',
'-Wextra',
'-Werror',
'-Wcatch-value=2',
'-Wextra-semi',
'-Wnon-virtual-dtor',
'-Wno-error=deprecated-declarations', # Bug #3795
'-Wno-error=maybe-uninitialized', # Bug #1615
'-Wno-unused-parameter',
]
flags['LINKFLAGS'] += ['-Wl,-O1']
return flags
def getOptimizedFlags(self, conf):
flags = super().getOptimizedFlags(conf)
flags['CXXFLAGS'] += ['-O2', '-g1'] + self.__cxxFlags
flags['LINKFLAGS'] += self.__linkFlags
flags = super(GccBasicFlags, self).getOptimizedFlags(conf)
flags['CXXFLAGS'] += ['-O2',
'-g',
'-pedantic',
'-Wall',
'-Wextra',
'-Wcatch-value=2',
'-Wextra-semi',
'-Wnon-virtual-dtor',
'-Wno-unused-parameter',
]
flags['LINKFLAGS'] += ['-Wl,-O1']
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
]
class GccFlags(GccBasicFlags):
def getDebugFlags(self, conf):
flags = super().getDebugFlags(conf)
flags['CXXFLAGS'] += self.__cxxFlags
if platform.machine() == 'armv7l':
flags = super(GccFlags, self).getDebugFlags(conf)
flags['CXXFLAGS'] += ['-fdiagnostics-color',
'-Wredundant-tags',
]
if platform.machine() == 'armv7l' and self.getCompilerVersion(conf) >= (7, 1, 0):
flags['CXXFLAGS'] += ['-Wno-psabi'] # Bug #5106
return flags
def getOptimizedFlags(self, conf):
flags = super().getOptimizedFlags(conf)
flags['CXXFLAGS'] += self.__cxxFlags
if platform.machine() == 'armv7l':
flags = super(GccFlags, self).getOptimizedFlags(conf)
flags['CXXFLAGS'] += ['-fdiagnostics-color',
'-Wredundant-tags',
]
if platform.machine() == 'armv7l' and self.getCompilerVersion(conf) >= (7, 1, 0):
flags['CXXFLAGS'] += ['-Wno-psabi'] # Bug #5106
return flags
class ClangFlags(GccClangCommonFlags):
class ClangFlags(GccBasicFlags):
def getGeneralFlags(self, conf):
flags = super().getGeneralFlags(conf)
flags = super(ClangFlags, self).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
]
flags['CXXFLAGS'] += [['-isystem', '/usr/local/include'], # for Homebrew
['-isystem', '/opt/local/include']] # for MacPorts
elif Utils.unversioned_sys_platform() == 'freebsd':
# Bug #4790
flags['CXXFLAGS'] += [['-isystem', '/usr/local/include']]
return flags
__cxxFlags = [
'-Wundefined-func-template',
'-Wno-unused-local-typedef', # Bugs #2657 and #3209
]
def getDebugFlags(self, conf):
flags = super().getDebugFlags(conf)
flags['CXXFLAGS'] += self.__cxxFlags
flags = super(ClangFlags, self).getDebugFlags(conf)
flags['CXXFLAGS'] += ['-fcolor-diagnostics',
'-Wundefined-func-template',
'-Wno-unused-local-typedef', # Bugs #2657 and #3209
]
if self.getCompilerVersion(conf) < (6, 0, 0):
flags['CXXFLAGS'] += ['-Wno-missing-braces'] # Bug #4721
return flags
def getOptimizedFlags(self, conf):
flags = super().getOptimizedFlags(conf)
flags['CXXFLAGS'] += self.__cxxFlags
flags = super(ClangFlags, self).getOptimizedFlags(conf)
flags['CXXFLAGS'] += ['-fcolor-diagnostics',
'-Wundefined-func-template',
'-Wno-unused-local-typedef', # Bugs #2657 and #3209
]
if self.getCompilerVersion(conf) < (6, 0, 0):
flags['CXXFLAGS'] += ['-Wno-missing-braces'] # Bug #4721
return flags
+1 -1
View File
@@ -53,10 +53,10 @@ def checkWebsocket(self, **kw):
self.end_msg('.'.join(self.env.WEBSOCKET_VERSION))
self.env.append_unique('DEFINES', ['_WEBSOCKETPP_CPP11_STL_'])
self.env.INCLUDES_WEBSOCKET = websocketDir.parent.abspath()
self.env.HAVE_WEBSOCKET = True
self.define('HAVE_WEBSOCKET', 1)
self.define('_WEBSOCKETPP_CPP11_STL_', 1)
except Errors.WafError as error:
if isMandatory:
+5 -6
View File
@@ -1,12 +1,12 @@
# NFD Authors
The following lists maintainers, primary developers, and all much-appreciated contributors to NFD in alphabetical order.
The following lists maintainers, primary developers, and all much-appreciated contributors to NFD in alphabetic order.
The specific contributions of individual authors can be obtained from the git history of the [official NFD repository](https://github.com/named-data/NFD).
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>.
If you would like to become a contributor to the official repository, please follow the recommendations in https://github.com/named-data/.github/blob/master/CONTRIBUTING.md.
* Jerald Paul Abraham <https://cs.arizona.edu/~jeraldabraham>
* ***(Maintainer)*** Alexander Afanasyev <https://users.cs.fiu.edu/~afanasyev>
* Syed Obaid Amin <http://obaidamin.weebly.com>
* Syed Obai Amin <http://obaidamin.weebly.com>
* Hila Ben Abraham <https://sites.wustl.edu/hbabraham>
* Muktadir R Chowdhury <https://github.com/alvyC>
* Tai-Lin Chu <https://www.linkedin.com/pub/tai-lin-chu/55/5b2/669>
@@ -19,7 +19,6 @@ If you would like to become a contributor to the official repository, please fol
* Nick Gordon <https://github.com/gorgonical>
* Giulio Grassi <https://www.lip6.fr/actualite/personnes-fiche.php?ident=D1461>
* Yi Huang <https://www.linkedin.com/in/yihuang1991>
* Alexander Lane <https://github.com/awlane>
* Jongseok Lee <https://github.com/imwhiz>
* Spencer Lee <https://www.linkedin.com/in/spenlee>
* Vince Lehman <http://vslehman.com>
@@ -32,7 +31,7 @@ If you would like to become a contributor to the official repository, please fol
* Eric Newberry <https://ericnewberry.com>
* Ju Pan <https://cs-jupan.com>
* João Pereira <http://website.jpereira.co.uk>
* ***(Maintainer)*** Davide Pesavento <https://github.com/Pesa>
* Davide Pesavento <https://github.com/Pesa>
* Felix Rabe <https://twitter.com/felixrabe>
* Md Ashiqur Rahman <https://ashiqrahman.com>
* Matteo Sammarco <https://www.linkedin.com/in/matteo-sammarco-9b544530>
@@ -56,7 +55,7 @@ If you would like to become a contributor to the official repository, please fol
* Patrick Crowley <https://www.arl.wustl.edu/~pcrowley>
* Christos Papadopoulos <https://www.cs.colostate.edu/~christos>
* Giovanni Pau <https://www.unibo.it/sitoweb/giovanni.pau/en>
* Giovanni Pau <http://www.cs.ucla.edu/~gpau/Giovanni_Paus_Home_Page/Home.html>
* Tian Song <http://www.bit-netlab.org/songtian>
* Lan Wang <http://www.cs.memphis.edu/~lanwang>
* Beichuan Zhang <https://cs.arizona.edu/~bzhang>
-17
View File
@@ -1,17 +0,0 @@
cff-version: 1.2.0
message: If you use NFD in your research, please cite it as below.
license: GPL-3.0-or-later
repository-code: "https://github.com/named-data/NFD"
title: Named Data Networking Forwarding Daemon
url: "https://docs.named-data.net/NFD/"
preferred-citation:
authors:
- name: Named Data Networking Project Team
date-published: "2021-07-30"
journal: NDN Technical Report NDN-0021
month: 7
title: NFD Developer's Guide
type: generic
url: "https://named-data.net/publications/techreports/ndn-0021-11-nfd-guide/"
version: 11
year: 2021
+81
View File
@@ -0,0 +1,81 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our
project and our community a harassment-free experience for everyone,
regardless of age, body size, disability, ethnicity, gender identity
and expression, level of experience, nationality, personal appearance,
race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive
environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual
attention or advances
* Trolling, insulting/derogatory comments, and personal or political
attacks
* Public or private harassment
* Publishing others' private information, such as a physical or
electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in
a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of
acceptable behavior and are expected to take appropriate and fair
corrective action in response to any instances of unacceptable
behavior.
Project maintainers have the right and responsibility to remove, edit,
or reject comments, commits, code, wiki edits, issues, and other
contributions that are not aligned to this Code of Conduct, or to ban
temporarily or permanently any contributor for other behaviors that
they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public
spaces when an individual is representing the project or its
community. Examples of representing a project or community include
using an official project e-mail address, posting via an official
social media account, or acting as an appointed representative at an
online or offline event. Representation of a project may be further
defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior
may be reported by contacting the project leaders Lixia Zhang,
Beichuan Zhang, or Alex Afanasyev
at
[lixia@cs.ucla.edu](mailto:lixia@cs.ucla.edu),
[bzhang@cs.arizona.edu](mailto:bzhang@cs.arizona.edu),
and [aa@cs.ucla.edu](mailto:aa@cs.ucla.edu). All complaints will be
reviewed and investigated and will result in a response that is deemed
necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of
an incident. Further details of specific enforcement policies may be
posted separately.
Project maintainers who do not follow or enforce the Code of Conduct
in good faith may face temporary or permanent repercussions as
determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from
the [Contributor Covenant](http://contributor-covenant.org), version 1.4, available
at [http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4/)
+489
View File
@@ -0,0 +1,489 @@
# Contributing to the NDN Codebase
## Getting Started
The NDN team is very glad you are interested in contributing! The NDN
(Named Data Networking) codebase is composed of many projects, with
multiple universities across the world contributing. This
documentation will help you understand how we work and what we expect
from contributors.
### Code of Conduct
NDN codebase development adheres to the Contributor Covenant, located
in `CODE_OF_CONDUCT.md`. By contributing, you are expected to also
adhere to this code. If you feel someone has breached this code of
conduct,
please
[email us](mailto:lixia@cs.ucla.edu,bzhang@cs.arizona.edu,aa@cs.ucla.edu).
### What can I do?
The NDN codebase continually needs help with, among other
things:
1. Implementing new features
2. Writing fixes for bugs
3. Writing documentation for features that have recently changed or
that change quickly. Sometimes people forget to update
documentation!
4. Code review
## Finding Documentation
The NDN team maintains a community
([Redmine site](https://redmine.named-data.net/projects/nfd)) for
issue tracking and documentation hosting. Redmine is the hub for
design activity. In particular, all design discussion and decisions
will either occur or be copied there.
**Why did they do it *this* way?** When writing code, if you ever have
questions about why some design decision was made, the best approach
is to use `git blame` on a file to inspect the last commit for some
line of code. In this view there will be a commit hash in hex
(e.g. `0ab12e3a`) in the first column. Using our example, `git show
0ab12e3a` would show the commit made for that line. In the commit view
there should be a reference number (e.g. `refs: #1234`). Using this
number, you can find a pertaining issue on the Redmine
(e.g., `https://redmine.named-data.net/issues/1234`).
Additionally, in some cases there are published papers you can read in
order to gain a better understanding of the project. Searching for
these papers is not difficult; in many cases you can find a pertaining
paper or technical report listed on
[the main NDN website](https://named-data.net/publications).
Usually the title of a project will be a good keyword.
If you cannot find an answer to your question, the best place to go is
the
[mailing lists](https://named-data.net/codebase/platform/support/mailing-lists/).
There are multiple different lists for different interests, so be sure you
are mailing the right list for a quick response.
## Tracking work on Redmine ##
As mentioned above, Redmine is the organizational hub of the NDN
projects. As such, extensive use of it is made, and learning how it
works will help you. In particular, there is a workflow associated
with Redmine. Generally it is:
1. An issue is reported by someone. At this point they should
describe the issue, including relationships to other
issues. Unless they know what they're doing, they should leave
particulars blank. Such particulars are priority, target version,
assignees, and categories.
2. Design discussion about the issue occurs, and the issue is either
accepted or rejected.
3. Someone either is assigned to, or assigns themselves to work on the
issue, setting the status to "In progress."
**Note:** You must be a "Developer" of the project before you are
able to toggle the Status field. A user should contact a project
manager to be granted Developer privilege. Project managers can be
found on "Overview" page of the project.
4. After every useful chunk of progress, notes are made on the issue
and the progress percentage is updated to reflect this. Remember
that notes are actually Markdown, so it is advised to use the
'preview' button to ensure your note looks right.
5. The changes are uploaded to Gerrit for review. Once all changes
pertaining to an issue are on Gerrit, an issues status should
change to "Code review."
6. Once all changes are cleared for merging, they either can be
merged, or held for feedback, at which point the issue status
should become "Feedback."
7. After all changes have been merged, the issue should be set to
"Closed."
Redmine provides other facilities for managing your work on NDN
projects, too, such as time logging and time estimation.
## Contributing Guidelines
### Repositories ###
All NDN projects are hosted on GitHub, at various organizations, using git
for version control:
- [Main NDN codebase](https://github.com/named-data)
- [NDN codebase for mobile platforms](https://github.com/named-data-mobile)
- [NDN codebase for IoT](https://github.com/named-data-iot)
- [ndnSIM codebase](https://github.com/named-data-ndnSIM)
- [Other NDN codebase (REMAP)](https://github.com/remap)
If you are unfamiliar with git, some kind
of [tutorial on git](https://git-scm.com/book/en/v1/Getting-Started)
should be your first step.
There is also a [Git game](http://learngitbranching.js.org/index.html)
you can play. Finally, there is a
[wiki page](https://redmine.named-data.net/projects/nfd/wiki#Development-process)
on NFD's Redmine that has more useful links.
There are a lot of different projects, so take some time to look
through them for ones that pertain to your interests. NDN projects
use [Gerrit](https://gerrit.named-data.net/) for code review purposes.
Occasionally there will be other repositories used privately to test
changes, but this is uncommon. In general, you will not need to refer
to these repositories.
### Style ###
Most NDN projects are written in C++, and there is a
[style guide](https://named-data.net/doc/ndn-cxx/current/code-style.html).
In general the NDN style is similar to the GNU style, but there are
some significant changes. This style guide is not exhaustive, and in
all cases not covered by the guide you should emulate the current
style of the project.
There is a
[partial styleguide](https://redmine.named-data.net/projects/nfd/wiki/CodeStyle)
for Python. It applies many of the provisions from the C++ guide, in
addition to some other Python-specific things.
Some NDN projects are written in JavaScript, and there is a [style guide](https://named-data.net/codebase/platform/documentation/ndn-platform-development-guidelines/cpp-code-guidelines/) for that language, too.
#### Commit Messages ####
Commit messages are very important, as they are usually the first
thing (besides the changelog file) a developer looks at when trying to
understand the timeline of a project. Commit messages should:
- Have a short, descriptive first line, starting with the module
they change. A good rule of thumb is a maximum length of 65
characters.
- If including a body, leave a blank line between the first line and
the rest, and ensure that each line is no longer than 72 characters.
- Include Redmine issue numbers. The exact syntax is given below.
- Be written in an imperative mood. E.g. `"Make foo a bar"` and not
`"Foo is now a bar"`
- Use the present tense. E.g. `"Make foo a bar"` and not `"Made foo a
bar"`
To explain, the anatomy of a typical commit message is like this:
docs: write contributing guide and code of conduct
This commit adds a guide that may be useful for new-comers to NDN in
becoming productive contributors. This commit also adds a code of
conduct.
refs: #3898
Change-Id: Ife89360305027dba9020f0b298793c1121ae1fd6c
Explaining this:
- `docs` is the module that the commit affects. We want this because
it lets someone know at a glance what part of the project it
changes. For some projects, there will be only one module or only
very small other modules. This practice should be observed in
those cases, too.
- `#3898` is the Redmine issue number. Gerrit transforms these into
clickable links, and it is useful to reviewers to gain background
understanding of the issue. You can have multiple by separating
them with commas.
- `Change-Id` should be filled automatically. It is used by Gerrit
to track changes.
### Unit Tests ###
With a few exceptions, every patch needs to have unit tests that
accompany them. For C++, we use
the [Boost unit test framework](http://www.boost.org/libs/test) to
help us out. Note that this link points to the newest version of the
Boost Test library documentation, and you may need to refer to older
documentation if you are using an older version of Boost. More
information on this is available in
the
[NFD Dev Guide](https://named-data.net/publications/techreports/ndn-0021-7-nfd-developer-guide/)
When designing and writing tests, a few things need to be kept in mind:
1. Unit tests are **design** tools, *not* debug tools. Just because
your code passes some unit tests does not mean it is
bug-free. Unit tests are tools to convince you that your code does
what you think it does.
2. It can be difficult to know when you should test something. If
you find that you are having a hard time designing a test for
something, ask yourself whether it is because it doesn't make
sense to test what you've just written, or if it's because the way
you designed it makes it difficult to test. Consider a second look
at your design if you think it's the second one.
3. The method that gave the world unit tests says that unit tests
should be written *before* the code they test. This is
a contentious issue, so writing them either before or after is
acceptable. If writing them later, keep the tests in mind when
writing the code, and it will help design good interfaces.
4. At the very least, write the test for a completed module/unit of
code before moving on. Doing this will ensure that the test gets
written, and will help you think about the interface that you need
to examine. If you don't, you may forget exactly what each piece
is responsible for when you're looking at the whole system
afterward.
5. Separate your I/O, as it is very hard to test, so I/O should be
isolated if possible. Consider something like separating a
function that invokes I/O into two functions: one that does the
I/O and calls the other one, which takes that I/O result. This
will make it easier to test that second function than if they were
combined.
Writing unit tests using the Boost framework is quite simple, and you
can refer to existing unit tests for examples.
([This is a good example.](https://github.com/named-data/NFD/blob/master/tests/rib/rib.t.cpp))
#### Building and running unit tests ####
This is mentioned in greater depth in
the [developer's readme](README-dev.md), but the basic procedure is:
1. In the base directory of the project, run `./waf distclean`. This
removes all prior build files.
2. Run `./waf configure --with-tests`. This configures the next build
to also build the tests.
3. Run `./waf`. This will build the tests.
4. Then, the unit tests will be in the `build` directory, and will be
named `unit-tests-<module name`, e.g. `unit-tests-nlsr` or
`unit-tests-rib`. To run just one test suite, run
`./unit-tests-exampleModule -t ExampleTestSuite`. To run a
specific test in a suite, use `./unit-tests-exampleModule -t
ExampleTestSuite/ExampleTestCase`.
## Gerrit: Uploading Patches and Code Review ##
As mentioned above, NDN projects
use [Gerrit](https://gerrit.named-data.net/) for code review. This is
a web-hosted, open code review platform that allows for interactive
code review, rebasing, and cross-linking with the Redmine, and a
developer interacts with it using the familiar git. For issues that
require a tracker reference, a particularly useful feature is that
the `refs: #...` becomes a clickable link to the issue for design
discussion.
### First-time Setup ###
The first-time Gerrit setup goes like this:
1. Log in to Gerrit. You can authenticate using many different
methods, including GitHub OAuth. You need to ensure that you have a Gerrit username:
1. Log in.
2. Click on your name in the top right corner and click "Settings" in the pop-up box.
3. In the `Username` box, check for a name. If there's already one there, great.
4. If not, type one in, and this will be used in later steps.
2. Set up your Gerrit credentials. This will depend on how you
configured your Gerrit remote in step 1. Among other things, you
need to set up identities so that the email on your Gerrit profile
matches whatever email you will be committing with on your git
repo.
**Note:** We only support using
[SSH access to Gerrit](https://gerrit.named-data.net/Documentation/user-upload.html#ssh).
This shows what the identities panel looks like. If you do
not see the email here that you have configured git to use, you
cannot upload to Gerrit.
![Web page showing what the "identities" panel looks like](./docs/images/gerrit-credentials-blurred.png)
In that case, add it under contact information panel.
![Web page showing what the "contact information" panel looks like](./docs/images/gerrit-email.png).
Gerrit itself has
[extensive documentation](https://gerrit.named-data.net/Documentation/error-messages.html)
regarding error messages, and this identity-based one is by far the most
common. This is the
[documentation for an identity error.](https://gerrit.named-data.net/Documentation/error-invalid-author.html)
3. Clone the source for a project from Gerrit.
1. While logged in to Gerrit, there will be a link in the top-left
area, `Projects`.
2. From this project view, click on the `Clone with commit-msg
hook` tab.
3. Click on the `ssh` tab to select cloning over SSH. **Note:**
This will require setting up SSH access to Gerrit first.
4. Copy-and-paste the `git clone ...` command into your terminal
to fetch the project source.
After this, your remotes will be set up correctly, and pushing to
Gerrit will only require `git push origin HEAD:refs/for/master` after
committing work. This section has some
[git tips and tricks to type less][type-less].
### Uploading patches ###
Most patches should have a corresponding Redmine issue that they can
reference. If you search the Redmine and notice there is no relevant
issue for a patch you are writing, please create an issue first. You
will need a Redmine account, which can be created there.
After writing some changes, commit them locally as normal. After
saving and exiting your editor, the commit hook will insert a unique
`Change-Id` to the message.
Once you have a commit message you are happy with, simply run `git
push HEAD:refs/for/master`.
**Note:** Gerrit separates commits into patch sets by the unique
`Change-Id`s. As a result, you must either:
* Squash your various commits into one with `git rebase -i
<initial commit>`, ensuring that the ultimate `Change-Id` in the
commit is the one on the patch set on Gerrit. This workflow is
generally preferred.
* Amend your commit with any new changes using `git commit --amend`.
If you do not do this, what will happen is that each commit will be
interpreted by Gerrit as a separate patch set. This is probably not
what you want.
### Code Review ###
#### Dealing with Code Review ####
It is important to remember that code review is about improving
the quality of code contributed, and nothing else. Further, code
review is highly important, as every line of code that's
committed comes with a burden of maintenance. Code review helps
minimize the burden of that maintenance. Consider that when you
are receiving comments, those comments are influenced by two
things:
- How the reviewer personally feels about the change ("Would I
be happy to see this code in a year?" or "Would I be happy if
I wrote this?") and
- How the reviewer feels the change abides by style and usage
requirements ("I may not personally mind, but we have to do it
this way.")
Remembering these things when reading comments helps to separate
what can feel like needless negativity.
#### Doing Code Review and Writing Comments ####
**Code review is *extremely* important!** We need every bit of code
review you can give. In many cases this is the bottleneck for
new contributors who do not fully understand how certain
language constructs should be used, what best practices are,
etc. In these cases it is important to give constructive
feedback.
Writing comments is somewhat counter-intuitive on Gerrit. If you are
signed in through a modern browser, you can leave a comment in a file
either by clicking on the line number, by selecting some text you want
to comment and pressing 'c', or by clicking on someone else's
comment. After typing, click the `Save` button there. After navigating
through the patch set with the arrows at the top-right of the Gerrit
UI, you then must click the up-arrow to get back to the Change
screen. **At this point your comments have *not* been made yet!** You
must then click the `Reply...` button, and assign a score. If you
correctly saved your comments, they will be shown at the bottom of
that box. Once you click post, the comments will be made public to
others.
Minimally, a review *must* include:
- A score (usually -1, 0, or +1)
- An "itemized" commentary on each objection you have, or a
justification for a whole-change objection.
Optimally, a review should include:
- A useful explanation of *why* you object to some item. This is
more important than it first appears. Consider that although
you may have been writing code since before you could count,
not everyone has. Some things may not be obvious to others,
and sharing your knowledge is key to making an open-source
project work.
- Comments about good design decisions. These help motivate
developers when otherwise a review is entirely negative
comments.
#### Expediting the Code Review Process ####
If you observe that code review takes a long time, there are a
few things that you can do to to expedite the process:
1. **Think about language best practices.**
2. **Ask yourself how you would feel about this code, if you saw it "in the wild."**
3. **When making code decisions, ask yourself "why *shouldn't* I do it this way?"**
#### Responding to Code Review ####
There are a few things to remember when responding to code review, including:
- **Don't** click "Done" on a comment if you agree with a comment and
are updating the code accordingly. These comments are essentially
useless and only clutter the discussion. Gerrit has a convenient
mechanism to check the differences between two patch sets, so
reviewers are expected to check that their comments have been
addressed.
- **Don't** blindly follow what is suggested. Review is just that: a
review. Sometimes what is suggested is functionally equivalent to
what you have implemented. Other times, the reviewer has not
considered something when writing their review, and their
suggestion will not work. Lastly, if you disagree with a suggestion
for some other reason, feel free to object, but you may be asked to
provide an explanation.
- **How** to reply. To reply to a comment, click on the comment in
the Gerrit interface, type your reply, and then press save. After
replying, you **must remember** to go to the main patch set change
screen, and press `Reply...`. Your comments will be shown as
drafts, and you must click `Post` to make them visible to others.
### Jenkins ###
As a supplement to the code review process, every patch set is automatically
compiled and tested on multiple platforms
using [our instance of Jenkins](http://jenkins.named-data.net/), the
continuous integration system. Interacting with Jenkins is not usually
necessary, as Jenkins automatically picks up new patch sets and posts
the results. Typically the only interaction needed with Jenkins is
when some kind of glitch occurs and a build needs to be retriggered.
It is expected that code is checked locally. Reviewers may wait until
Jenkins checks the code before doing a more functional review of the
code. Since Jenkins checks can take a while, you can save some time by
checking yourself first.
### Gerrit Change-Id Commit Hook ###
If you encounter an error like this when trying to push work:
remote: ERROR: [4311462] missing Change-Id in commit message footer
remote:
remote: Hint: To automatically insert Change-Id, install the hook:
remote: gitdir=$(git rev-parse --git-dir); scp -p -P 29418 someuser@gerrit.named-data.net:hooks/commit-msg ${gitdir}/hooks/
remote: And then amend the commit:
remote: git commit --amend
Then your commit hook has not been set up correctly, somehow. Follow
the instructions in the terminal to resolve this.
### Code Style Robot ###
As part of CI, there is a script that checks every patch uploaded to
Gerrit for code style consistency. Checking these kinds of things is
notoriously difficult, and while the robot is very good in general, it
will occasionally report false positives and miss things. So all
issues it raises should be inspected manually to ensure they really
are style problems. Further, since this automated check is not
perfect, you should take steps (e.g., configure your editor or run a
linter before you commit) to ensure you adhere to code style rules.
### <a name="type-less"></a> Typing Less to Upload Patches to Gerrit ###
If typing `HEAD:refs/for/master` feels
repetitive, you have a few options:
* You can configure git to do the work for you, as described
in [this blog post](https://yoursunny.com/t/2017/NFD-devbox/#Uploading-to-Gerrit)
* Git has an alias system that you can use to specify certain
commands. For example, you can use `git config --global alias.pg
"push origin HEAD:refs/for/master"` to make `git pg` push to
Gerrit. [Learn about git aliases here.](https://githowto.com/aliases)
* If using Linux or macOS, it is relatively simple to create a shell
alias: `alias gs="git status"` for example, or `alias gitpush="git
push origin HEAD:refs/for/master`. The alias itself must be one
word, but it can represent multiple words. To persist your
aliases, they need to go in your environment file, which is
generally at `~/.bashrc` or `~/.zshrc` or `~/.profile`. The exact
syntax of aliases and the environment variables file will vary by
shell. You should be careful not to overuse aliases, however.
[type-less]: #type-less
+6 -5
View File
@@ -9,10 +9,10 @@ NFD relies on third-party software, licensed under the following licenses:
- The Boost libraries are licensed under the
[Boost Software License 1.0](https://www.boost.org/users/license.html)
- CityHash is licensed under the
- CityHash is licensed under a
[MIT license](https://github.com/google/cityhash/blob/master/COPYING)
- Libpcap is licensed under the
- Libpcap is licensed under a
[3-clause BSD license](https://github.com/the-tcpdump-group/libpcap/blob/master/LICENSE)
- The WebSocket++ library is licensed under the terms of the
@@ -21,10 +21,11 @@ NFD relies on third-party software, licensed under the following licenses:
- The waf build system is licensed under the terms of the
[BSD license](https://github.com/named-data/NFD/blob/master/waf)
The GPL license is provided below in this file. For more information about
these licenses, see <https://www.gnu.org/licenses/>
--------------------------------------------------------------------------------
The GPL license is provided below in this file. For more information about
these licenses, see https://www.gnu.org/licenses/
----------------------------------------------------------------------------------
### GNU GENERAL PUBLIC LICENSE
-45
View File
@@ -1,45 +0,0 @@
FROM ghcr.io/named-data/ndn-cxx:latest as builder
RUN apt-get update \
&& apt-get install -y --no-install-recommends libpcap-dev \
&& rm -rf /var/lib/apt/lists/*
COPY . /NFD
RUN cd /NFD \
&& ./waf configure --without-pch --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
&& ./waf \
&& ./waf install \
# get list of dependencies
&& mkdir -p /shlibdeps/debian && cd /shlibdeps && touch debian/control \
&& dpkg-shlibdeps --ignore-missing-info /usr/lib/libndn-cxx.so* /usr/bin/nfdc /usr/bin/nfd \
&& sed -n '/^shlibs:Depends=/ s|shlibs:Depends=||p' debian/substvars | sed -e 's|,||g' -e 's| ([^)]*)||g' > /deps.txt
# use same base distro version as named-data/ndn-cxx
FROM debian:bookworm
COPY --from=builder /deps.txt /
RUN apt-get update \
&& apt-get install -y --no-install-recommends $(cat /deps.txt) \
&& rm -rf /var/lib/apt/lists/* /deps.txt
COPY --from=builder /usr/lib/libndn-cxx.so* /usr/lib/
COPY --from=builder /usr/bin/nfd /usr/bin/
COPY --from=builder /usr/bin/nfdc /usr/bin/
COPY --from=builder /usr/bin/nfd-status-http-server /usr/bin/
COPY --from=builder /usr/share/ndn/ /usr/share/ndn/
COPY --from=builder /etc/ndn/nfd.conf.sample /config/nfd.conf
ENV HOME=/config
VOLUME /config
VOLUME /run/nfd
EXPOSE 6363/tcp
EXPOSE 6363/udp
EXPOSE 9696/tcp
ENTRYPOINT ["/usr/bin/nfd"]
CMD ["--config", "/config/nfd.conf"]
+9 -7
View File
@@ -1,7 +1,7 @@
# Notes for NFD developers
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).
If you are new to the NDN software community, please read the
[Contributor's Guide](https://github.com/named-data/.github/blob/master/CONTRIBUTING.md).
## Code style
@@ -9,9 +9,11 @@ NFD code is subject to [NFD code style](https://redmine.named-data.net/projects/
## Licensing
Contributions to NFD 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:
Contributions to NFD must be licensed under the GPL 3.0 or compatible license. If you
are choosing GPL 3.0, please use the following license boilerplate in all `.hpp` and
`.cpp` files:
Include the following license boilerplate into all `.hpp` and `.cpp` files:
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
@@ -59,7 +61,7 @@ The simplest way to run the tests is to launch the compiled binary without any p
# Run NFD RIB management tests
./build/unit-tests-rib
The [Boost.Test framework](https://www.boost.org/doc/libs/1_71_0/libs/test/doc/html/index.html)
The [Boost.Test framework](https://www.boost.org/doc/libs/1_65_1/libs/test/doc/html/index.html)
is very flexible and allows a number of run-time customization of what tests should be run.
For example, it is possible to choose to run only a specific test suite, only a specific
test case within a suite, or specific test cases within specific test suites:
@@ -92,4 +94,4 @@ or `-p` to show a progress bar:
There are many more command line options available, information about which can be obtained
either from the command line using the `--help` switch, or online on the
[Boost.Test website](https://www.boost.org/doc/libs/1_71_0/libs/test/doc/html/boost_test/runtime_config.html).
[Boost.Test website](https://www.boost.org/doc/libs/1_65_1/libs/test/doc/html/index.html).
+17 -23
View File
@@ -1,20 +1,13 @@
<div align="center">
# NFD - Named Data Networking Forwarding Daemon
[<img alt height="65" src="docs/named_data_theme/static/ndn-logo.svg"/>](https://named-data.net/)
# NFD: Named Data Networking Forwarding Daemon
</div>
[![CI](https://github.com/named-data/NFD/actions/workflows/ci.yml/badge.svg)](https://github.com/named-data/NFD/actions/workflows/ci.yml)
[![Docs](https://github.com/named-data/NFD/actions/workflows/docs.yml/badge.svg)](https://github.com/named-data/NFD/actions/workflows/docs.yml)
![Language](https://img.shields.io/badge/C%2B%2B-17-blue)
![Latest version](https://img.shields.io/github/v/tag/named-data/NFD?label=Latest%20version)
![Language](https://img.shields.io/badge/C%2B%2B-14-blue.svg)
[![Build Status](https://travis-ci.org/named-data/NFD.svg?branch=master)](https://travis-ci.org/named-data/NFD)
![Latest Version](https://img.shields.io/github/tag/named-data/NFD.svg?color=darkkhaki&label=latest%20version)
## Overview
NFD is a network forwarder that implements and evolves together with the Named
Data Networking (NDN) [protocol](https://docs.named-data.net/NDN-packet-spec/).
NFD is a network forwarder that implements and evolves together with the Named Data
Networking (NDN) [protocol](https://named-data.net/doc/NDN-packet-spec/current/).
Since the initial public release in 2014, NFD has been a core component of the
[NDN Platform](https://named-data.net/codebase/platform/).
@@ -34,12 +27,13 @@ various features, some of which may eventually work into the protocol spec.
See [`docs/INSTALL.rst`](docs/INSTALL.rst) for compilation and installation instructions.
Extensive documentation is available on NFD's [homepage](https://docs.named-data.net/NFD/).
Extensive documentation is available on NFD's [homepage](https://named-data.net/doc/NFD/).
## Reporting bugs
Please submit any bug reports or feature requests to the
[NFD issue tracker](https://redmine.named-data.net/projects/nfd/issues).
Bug reports and feedback are highly appreciated and can be submitted through the
[NFD issue tracker](https://redmine.named-data.net/projects/nfd/issues) or the
[ndn-interest mailing list](http://www.lists.cs.ucla.edu/mailman/listinfo/ndn-interest).
## Contributing
@@ -49,13 +43,13 @@ it already contains significant contributions from people outside the project te
[`AUTHORS.md`](AUTHORS.md)). We strongly encourage participation from all interested parties,
since broader community support is key for NDN to succeed as a new Internet architecture.
Contributions to NFD 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.
If you are new to the NDN software community, please read [`README-dev.md`](README-dev.md)
and the [Contributor's Guide](https://github.com/named-data/.github/blob/master/CONTRIBUTING.md)
to get started.
## License
NFD is free software distributed under the GNU General Public License version 3.
See [`COPYING.md`](COPYING.md) for details.
NFD is a free and open-source software package licensed under the GPL version 3 and
is the centerpiece of our committement to making NDN's core technology free and open
to all Internet users and developers. For more information about licensing, refer to
[`COPYING.md`](COPYING.md).
+1
View File
@@ -0,0 +1 @@
docs/release-notes-latest.rst
+58
View File
@@ -0,0 +1,58 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NFD_CORE_ALGORITHM_HPP
#define NFD_CORE_ALGORITHM_HPP
#include "common.hpp"
#include <boost/concept/requires.hpp>
namespace nfd {
/** \brief finds the last element satisfying a predicate
* \tparam It BidirectionalIterator
* \tparam Pred UnaryPredicate
*
* \return Iterator to the last element satisfying the condition,
* or \p last if no such element is found.
*
* Complexity: at most \p last-first invocations of \p p
*/
template<typename It, typename Pred>
BOOST_CONCEPT_REQUIRES(
((boost::BidirectionalIterator<It>))
((boost::UnaryPredicate<Pred, typename std::iterator_traits<It>::value_type>)),
(It)
)
find_last_if(It first, It last, Pred p)
{
std::reverse_iterator<It> firstR(first), lastR(last);
auto found = std::find_if(lastR, firstR, p);
return found == firstR ? last : std::prev(found.base());
}
} // namespace nfd
#endif // NFD_CORE_ALGORITHM_HPP
+32 -24
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -28,20 +28,20 @@
#include "core/config.hpp"
#ifdef NFD_WITH_TESTS
#define NFD_VIRTUAL_WITH_TESTS virtual
#define NFD_PUBLIC_WITH_TESTS_ELSE_PROTECTED public
#define NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE public
#define NFD_PROTECTED_WITH_TESTS_ELSE_PRIVATE protected
#define NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL override
#define NFD_FINAL_UNLESS_WITH_TESTS
#ifdef WITH_TESTS
#define VIRTUAL_WITH_TESTS virtual
#define PUBLIC_WITH_TESTS_ELSE_PROTECTED public
#define PUBLIC_WITH_TESTS_ELSE_PRIVATE public
#define PROTECTED_WITH_TESTS_ELSE_PRIVATE protected
#define OVERRIDE_WITH_TESTS_ELSE_FINAL override
#define FINAL_UNLESS_WITH_TESTS
#else
#define NFD_VIRTUAL_WITH_TESTS
#define NFD_PUBLIC_WITH_TESTS_ELSE_PROTECTED protected
#define NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE private
#define NFD_PROTECTED_WITH_TESTS_ELSE_PRIVATE private
#define NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL final
#define NFD_FINAL_UNLESS_WITH_TESTS final
#define VIRTUAL_WITH_TESTS
#define PUBLIC_WITH_TESTS_ELSE_PROTECTED protected
#define PUBLIC_WITH_TESTS_ELSE_PRIVATE private
#define PROTECTED_WITH_TESTS_ELSE_PRIVATE private
#define OVERRIDE_WITH_TESTS_ELSE_FINAL final
#define FINAL_UNLESS_WITH_TESTS final
#endif
#include <cstddef>
@@ -50,15 +50,17 @@
#include <limits>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <stdexcept>
#include <string>
#include <string_view>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include <ndn-cxx/data.hpp>
#include <ndn-cxx/delegation.hpp>
#include <ndn-cxx/delegation-list.hpp>
#include <ndn-cxx/interest.hpp>
#include <ndn-cxx/name.hpp>
#include <ndn-cxx/encoding/block.hpp>
@@ -68,16 +70,20 @@
#include <ndn-cxx/util/exception.hpp>
#include <ndn-cxx/util/scheduler.hpp>
#include <ndn-cxx/util/signal.hpp>
#include <ndn-cxx/util/span.hpp>
#include <ndn-cxx/util/time.hpp>
#include <boost/asio.hpp>
#include <boost/assert.hpp>
#include <boost/core/noncopyable.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/property_tree/ptree.hpp>
namespace nfd {
using std::size_t;
using boost::noncopyable;
using std::shared_ptr;
using std::unique_ptr;
using std::weak_ptr;
@@ -88,15 +94,18 @@ using std::static_pointer_cast;
using std::dynamic_pointer_cast;
using std::const_pointer_cast;
using std::to_string;
using std::bind;
using namespace std::string_literals;
using namespace std::string_view_literals;
using boost::noncopyable;
using ndn::optional;
using ndn::nullopt;
using ndn::to_string;
using ndn::span;
using ndn::Block;
using ndn::Data;
using ndn::Delegation;
using ndn::DelegationList;
using ndn::FaceUri;
using ndn::Interest;
using ndn::Name;
@@ -112,11 +121,10 @@ using namespace ndn::tlv;
namespace lp = ndn::lp;
namespace name = ndn::name;
namespace scheduler = ndn::scheduler;
namespace signal = ndn::signal;
namespace signal = ndn::util::signal;
namespace time = ndn::time;
using namespace ndn::block_literals;
using namespace ndn::time_literals;
using ndn::operator""_block;
} // namespace nfd
+9 -13
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, Regents of the University of California,
* Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -25,13 +25,9 @@
#include "network.hpp"
#include <boost/lexical_cast.hpp>
#include <boost/utility/value_init.hpp>
#include <algorithm>
#include <cctype>
#include <istream>
#include <ostream>
namespace nfd {
@@ -48,7 +44,7 @@ const Network&
Network::getMaxRangeV4()
{
using boost::asio::ip::address_v4;
static const Network range{address_v4{}, address_v4{0xffffffff}};
static Network range{address_v4{}, address_v4{0xffffffff}};
return range;
}
@@ -56,14 +52,14 @@ const Network&
Network::getMaxRangeV6()
{
using boost::asio::ip::address_v6;
static const address_v6::bytes_type maxV6 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
static const Network range{address_v6{}, address_v6{maxV6}};
static address_v6::bytes_type maxV6 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
static Network range{address_v6{}, address_v6{maxV6}};
return range;
}
bool
Network::isValidCidr(std::string_view cidr) noexcept
Network::isValidCidr(const std::string& cidr)
{
auto pos = cidr.find('/');
if (pos == std::string::npos) {
@@ -96,8 +92,8 @@ operator>>(std::istream& is, Network& network)
size_t position = networkStr.find('/');
if (position == std::string::npos) {
try {
network.m_minAddress = ip::make_address(networkStr);
network.m_maxAddress = ip::make_address(networkStr);
network.m_minAddress = ip::address::from_string(networkStr);
network.m_maxAddress = ip::address::from_string(networkStr);
}
catch (const boost::system::system_error&) {
is.setstate(std::ios::failbit);
@@ -106,7 +102,7 @@ operator>>(std::istream& is, Network& network)
}
else {
boost::system::error_code ec;
auto address = ip::make_address(networkStr.substr(0, position), ec);
auto address = ip::address::from_string(networkStr.substr(0, position), ec);
if (ec) {
is.setstate(std::ios::failbit);
return is;
+19 -18
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, Regents of the University of California,
/**
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,14 +26,11 @@
#ifndef NFD_CORE_NETWORK_HPP
#define NFD_CORE_NETWORK_HPP
#include <boost/asio/ip/address.hpp>
#include <boost/operators.hpp>
#include <string_view>
#include "common.hpp"
namespace nfd {
class Network : private boost::equality_comparable<Network>
class Network
{
public:
Network();
@@ -42,7 +39,7 @@ public:
const boost::asio::ip::address& maxAddress);
bool
doesContain(const boost::asio::ip::address& address) const noexcept
doesContain(const boost::asio::ip::address& address) const
{
return m_minAddress <= address && address <= m_maxAddress;
}
@@ -54,25 +51,29 @@ public:
getMaxRangeV6();
static bool
isValidCidr(std::string_view cidr) noexcept;
isValidCidr(const std::string& cidr);
private: // non-member operators
friend bool
operator==(const Network& lhs, const Network& rhs) noexcept
bool
operator==(const Network& rhs) const
{
return lhs.m_minAddress == rhs.m_minAddress &&
lhs.m_maxAddress == rhs.m_maxAddress;
return m_minAddress == rhs.m_minAddress && m_maxAddress == rhs.m_maxAddress;
}
bool
operator!=(const Network& rhs) const
{
return !(*this == rhs);
}
private:
boost::asio::ip::address m_minAddress;
boost::asio::ip::address m_maxAddress;
friend std::ostream&
operator<<(std::ostream& os, const Network& network);
friend std::istream&
operator>>(std::istream& is, Network& network);
private:
boost::asio::ip::address m_minAddress;
boost::asio::ip::address m_maxAddress;
};
std::ostream&
+12 -16
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -26,16 +26,14 @@
#ifndef NFD_CORE_VERSION_HPP
#define NFD_CORE_VERSION_HPP
// The NFD version follows the approach of Calendar Versioning (https://calver.org/)
// based on the year and month of the release, followed by an optional "patch" number,
// i.e., `YY.0M[.MICRO]` using CalVer notation.
// NFD version follows Semantic Versioning 2.0.0
// https://semver.org/spec/v2.0.0.html
//
// To change version number, modify the VERSION variable in the top-level wscript.
// To change version number, modify VERSION variable in top-level wscript.
/**
* \brief NFD version represented as an integer.
/** \brief NFD version represented as an integer.
*
* Equivalent to: #NFD_VERSION_MAJOR*1000000 + #NFD_VERSION_MINOR*1000 + #NFD_VERSION_PATCH
* Equivalent to: `#NFD_VERSION_MAJOR*1000000 + #NFD_VERSION_MINOR*1000 + #NFD_VERSION_PATCH`
*/
#define NFD_VERSION @VERSION@
@@ -46,8 +44,7 @@
/// The patch version of NFD
#define NFD_VERSION_PATCH @VERSION_PATCH@
/**
* \brief NFD version represented as a string.
/** \brief NFD version represented as a string.
*
* Format:
* @code
@@ -56,21 +53,20 @@
*/
extern const char NFD_VERSION_STRING[];
/**
* \brief NFD version string, including git commit information if NFD is build from a
* specific git commit.
/** \brief NFD version string, including git commit information, if NFD is build from
* specific git commit.
*
* #NFD_VERSION_BUILD_STRING is obtained using the following command (`NFD-` prefix is
* afterwards removed): ``git describe --match 'NFD-*'``
* afterwards removed): `git describe --match 'NFD-*'`
*
* When NFD is not built from git, #NFD_VERSION_BUILD_STRING equals #NFD_VERSION_STRING.
*
* Format:
* @code
* MAJOR.MINOR(.PATCH)(-release-candidate-tag)(-(number-of-commits-since-tag)-COMMIT-HASH)
* MAJOR.MINOR.PATCH(-release-candidate-tag)(-(number-of-commits-since-tag)-COMMIT-HASH)
* @endcode
*
* Example: 2022.02-1-g5c86570
* Example: 0.1.0-rc1-1-g5c86570
*/
extern const char NFD_VERSION_BUILD_STRING[];
+4 -4
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -32,8 +32,8 @@
namespace nfd {
ConfigFile::ConfigFile(UnknownConfigSectionHandler callback)
: m_unknownSectionCallback(std::move(callback))
ConfigFile::ConfigFile(UnknownConfigSectionHandler unknownSectionCallback)
: m_unknownSectionCallback(unknownSectionCallback)
{
}
@@ -77,7 +77,7 @@ void
ConfigFile::addSectionHandler(const std::string& sectionName,
ConfigSectionHandler subscriber)
{
m_subscriptions[sectionName] = std::move(subscriber);
m_subscriptions[sectionName] = subscriber;
}
void
+13 -35
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -32,32 +32,27 @@
namespace nfd {
/**
* \brief A configuration file section.
/** \brief a config file section
*/
using ConfigSection = boost::property_tree::ptree;
/**
* \brief An optional configuration file section.
/** \brief an optional config file section
*/
using OptionalConfigSection = boost::optional<const ConfigSection&>;
/**
* \brief Callback to process a configuration file section.
/** \brief callback to process a config file section
*/
using ConfigSectionHandler = std::function<void(const ConfigSection& section, bool isDryRun,
const std::string& filename)>;
/**
* \brief Callback to process a configuration file section without a #ConfigSectionHandler.
/** \brief callback to process a config file section without a \p ConfigSectionHandler
*/
using UnknownConfigSectionHandler = std::function<void(const std::string& filename,
const std::string& sectionName,
const ConfigSection& section,
bool isDryRun)>;
/**
* \brief Configuration file parsing utility.
/** \brief configuration file parsing utility
*/
class ConfigFile : noncopyable
{
@@ -85,7 +80,7 @@ public: // unknown section handlers
bool isDryRun);
public: // parse helpers
/** \brief Parse a config option that can be either "yes" or "no".
/** \brief parse a config option that can be either "yes" or "no"
* \retval true "yes"
* \retval false "no"
* \throw Error the value is neither "yes" nor "no"
@@ -100,7 +95,7 @@ public: // parse helpers
}
/**
* \brief Parse a numeric (integral or floating point) config option.
* \brief parse a numeric (integral or floating point) config option
* \tparam T an arithmetic type
*
* \return the numeric value of the parsed option
@@ -110,44 +105,27 @@ public: // parse helpers
static T
parseNumber(const ConfigSection& node, const std::string& key, const std::string& sectionName)
{
static_assert(std::is_arithmetic_v<T>);
static_assert(std::is_arithmetic<T>::value, "T must be an arithmetic type");
auto value = node.get_value_optional<T>();
boost::optional<T> value = node.get_value_optional<T>();
// Unsigned logic is workaround for https://redmine.named-data.net/issues/4489
if (value &&
(std::is_signed_v<T> || node.get_value<std::string>().find("-") == std::string::npos)) {
(std::is_signed<T>() || node.get_value<std::string>().find("-") == std::string::npos)) {
return *value;
}
NDN_THROW(Error("Invalid value '" + node.get_value<std::string>() +
"' for option '" + key + "' in section '" + sectionName + "'"));
}
template<typename T>
template <typename T>
static T
parseNumber(const ConfigSection::value_type& option, const std::string& sectionName)
{
return parseNumber<T>(option.second, option.first, sectionName);
}
/**
* \brief Check that a value is within the inclusive range [min, max].
* \throw Error the value is out of the acceptable range
*/
template<typename T>
static void
checkRange(T value, T min, T max, const std::string& key, const std::string& sectionName)
{
static_assert(std::is_integral_v<T>);
if (value < min || value > max) {
NDN_THROW(Error("Invalid value '" + to_string(value) + "' for option '" + key +
"' in section '" + sectionName + "': out of acceptable range [" +
to_string(min) + ", " + to_string(max) + "]"));
}
}
public: // setup and parsing
/// \brief Setup notification of configuration file sections.
/// \brief setup notification of configuration file sections
void
addSectionHandler(const std::string& sectionName,
ConfigSectionHandler subscriber);
+21 -29
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,27 +30,24 @@
namespace nfd {
/**
* \brief Represents a counter that encloses an integer value.
/** \brief represents a counter that encloses an integer value
*
* SimpleCounter is noncopyable, because increment should be called on the counter,
* not a copy of it. It's implicitly convertible to an integral type to be observed.
* SimpleCounter is noncopyable, because increment should be called on the counter,
* not a copy of it; it's implicitly convertible to an integral type to be observed
*/
class SimpleCounter : noncopyable
{
public:
using rep = uint64_t;
typedef uint64_t rep;
/**
* \brief Return the counter's value.
/** \brief observe the counter
*/
operator rep() const noexcept
{
return m_value;
}
/**
* \brief Replace the counter's value.
/** \brief replace the counter value
*/
void
set(rep value) noexcept
@@ -62,16 +59,14 @@ protected:
rep m_value = 0;
};
/**
* \brief Represents a counter of number of packets.
/** \brief represents a counter of number of packets
*
* \warning The counter value may wrap after exceeding the range of the underlying integer type.
* \warning The counter value may wrap after exceeding the range of underlying integer type.
*/
class PacketCounter : public SimpleCounter
{
public:
/**
* \brief Increment the counter by one.
/** \brief increment the counter by one
*/
PacketCounter&
operator++() noexcept
@@ -79,18 +74,17 @@ public:
++m_value;
return *this;
}
// postfix ++ operator is not provided because it's not needed
};
/**
* \brief Represents a counter of number of bytes.
/** \brief represents a counter of number of bytes
*
* \warning The counter value may wrap after exceeding the range of the underlying integer type.
* \warning The counter value may wrap after exceeding the range of underlying integer type.
*/
class ByteCounter : public SimpleCounter
{
public:
/**
* \brief Increase the counter.
/** \brief increase the counter
*/
ByteCounter&
operator+=(rep n) noexcept
@@ -100,17 +94,16 @@ public:
}
};
/**
* \brief Provides a counter that observes the size of a table.
* \tparam T a type that provides a `size()` const member function
/** \brief provides a counter that observes the size of a table
* \tparam T a type that provides a size() const member function
*
* If the table is not specified in the constructor, it can be added later by calling observe().
* if table not specified in constructor, it can be added later by invoking observe()
*/
template<typename T>
class SizeCounter : noncopyable
{
public:
using rep = size_t;
typedef size_t Rep;
explicit constexpr
SizeCounter(const T* table = nullptr) noexcept
@@ -124,17 +117,16 @@ public:
m_table = table;
}
/**
* \brief Return the counter's value, i.e., the current size of the table being observed.
/** \brief observe the counter
*/
operator rep() const
operator Rep() const
{
BOOST_ASSERT(m_table != nullptr);
return m_table->size();
}
private:
const T* m_table = nullptr;
const T* m_table;
};
} // namespace nfd
+32 -20
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -27,18 +27,18 @@
namespace nfd {
static thread_local unique_ptr<boost::asio::io_context> g_ioCtx;
static thread_local unique_ptr<boost::asio::io_service> g_ioService;
static thread_local unique_ptr<Scheduler> g_scheduler;
static boost::asio::io_context* g_mainIoCtx = nullptr;
static boost::asio::io_context* g_ribIoCtx = nullptr;
static boost::asio::io_service* g_mainIoService = nullptr;
static boost::asio::io_service* g_ribIoService = nullptr;
boost::asio::io_context&
boost::asio::io_service&
getGlobalIoService()
{
if (g_ioCtx == nullptr) {
g_ioCtx = make_unique<boost::asio::io_context>();
if (g_ioService == nullptr) {
g_ioService = make_unique<boost::asio::io_service>();
}
return *g_ioCtx;
return *g_ioService;
}
Scheduler&
@@ -50,39 +50,51 @@ getScheduler()
return *g_scheduler;
}
#ifdef NFD_WITH_TESTS
#ifdef WITH_TESTS
void
resetGlobalIoService()
{
g_scheduler.reset();
g_ioCtx.reset();
g_ioService.reset();
}
#endif
boost::asio::io_context&
boost::asio::io_service&
getMainIoService()
{
BOOST_ASSERT(g_mainIoCtx != nullptr);
return *g_mainIoCtx;
BOOST_ASSERT(g_mainIoService != nullptr);
return *g_mainIoService;
}
boost::asio::io_context&
boost::asio::io_service&
getRibIoService()
{
BOOST_ASSERT(g_ribIoCtx != nullptr);
return *g_ribIoCtx;
BOOST_ASSERT(g_ribIoService != nullptr);
return *g_ribIoService;
}
void
setMainIoService(boost::asio::io_context* mainIo)
setMainIoService(boost::asio::io_service* mainIo)
{
g_mainIoCtx = mainIo;
g_mainIoService = mainIo;
}
void
setRibIoService(boost::asio::io_context* ribIo)
setRibIoService(boost::asio::io_service* ribIo)
{
g_ribIoCtx = ribIo;
g_ribIoService = ribIo;
}
void
runOnMainIoService(const std::function<void()>& f)
{
getMainIoService().post(f);
}
void
runOnRibIoService(const std::function<void()>& f)
{
getRibIoService().post(f);
}
} // namespace nfd
+21 -16
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023 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,
@@ -27,39 +27,44 @@
#include "core/common.hpp"
#include <boost/asio/io_context.hpp>
namespace nfd {
/**
* \brief Returns the global io_context instance for the calling thread.
/** \brief Returns the global io_service instance for the calling thread.
*/
boost::asio::io_context&
boost::asio::io_service&
getGlobalIoService();
/**
* \brief Returns the global Scheduler instance for the calling thread.
/** \brief Returns the global Scheduler instance for the calling thread.
*/
Scheduler&
getScheduler();
boost::asio::io_context&
boost::asio::io_service&
getMainIoService();
boost::asio::io_context&
boost::asio::io_service&
getRibIoService();
void
setMainIoService(boost::asio::io_context* mainIo);
setMainIoService(boost::asio::io_service* mainIo);
void
setRibIoService(boost::asio::io_context* ribIo);
setRibIoService(boost::asio::io_service* ribIo);
#ifdef NFD_WITH_TESTS
/**
* \brief Destroy the global io_context instance.
/** \brief Run a function on the main io_service instance.
*/
void
runOnMainIoService(const std::function<void()>& f);
/** \brief Run a function on the RIB io_service instance.
*/
void
runOnRibIoService(const std::function<void()>& f);
#ifdef WITH_TESTS
/** \brief Destroy the global io_service instance.
*
* It will be recreated at the next invocation of getGlobalIoService().
* It will be recreated at the next invocation of getGlobalIoService().
*/
void
resetGlobalIoService();
+9 -9
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2021, 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,
@@ -33,18 +33,18 @@ namespace nfd {
NFD_LOG_INIT(PrivilegeHelper);
#ifdef NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
uid_t PrivilegeHelper::s_normalUid = ::geteuid();
gid_t PrivilegeHelper::s_normalGid = ::getegid();
uid_t PrivilegeHelper::s_privilegedUid = ::geteuid();
gid_t PrivilegeHelper::s_privilegedGid = ::getegid();
#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
void
PrivilegeHelper::initialize(const std::string& userName, const std::string& groupName)
{
#ifdef NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
static const size_t MAX_GROUP_BUFFER_SIZE = 16384; // 16 KiB
static const size_t MAX_PASSWD_BUFFER_SIZE = 16384;
@@ -111,13 +111,13 @@ PrivilegeHelper::initialize(const std::string& userName, const std::string& grou
if (!userName.empty() || !groupName.empty()) {
throw Error("Dropping and raising privileges is not supported on this platform");
}
#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
}
void
PrivilegeHelper::drop()
{
#ifdef NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
if (::geteuid() == s_normalUid && ::getegid() == s_normalGid)
return;
@@ -132,13 +132,13 @@ PrivilegeHelper::drop()
NFD_LOG_INFO("dropped to effective uid=" << ::geteuid() << " gid=" << ::getegid());
#else
NFD_LOG_WARN("Dropping privileges is not supported on this platform");
#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
}
void
PrivilegeHelper::raise()
{
#ifdef NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
if (::geteuid() == s_privilegedUid && ::getegid() == s_privilegedGid)
return;
@@ -153,7 +153,7 @@ PrivilegeHelper::raise()
NFD_LOG_INFO("elevated to effective uid=" << ::geteuid() << " gid=" << ::getegid());
#else
NFD_LOG_WARN("Elevating privileges is not supported on this platform");
#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
}
} // namespace nfd
+9 -11
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -35,12 +35,10 @@ namespace nfd {
class PrivilegeHelper
{
public:
/**
* \brief Indicates a serious seteuid/setegid failure.
/** \brief represents a serious seteuid/gid failure
*
* This should only be caught by main as part of a graceful program termination.
*
* \note This is not an std::exception and NDN_THROW should not be used.
* This should only be caught by main as part of a graceful program termination.
* \note This is not an std::exception and NDN_THROW should not be used.
*/
class Error
{
@@ -73,7 +71,7 @@ public:
{
raise();
try {
std::invoke(std::forward<F>(f));
f();
}
catch (...) {
drop();
@@ -82,18 +80,18 @@ public:
drop();
}
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
static void
raise();
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
#ifdef NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
static uid_t s_normalUid;
static gid_t s_normalGid;
static uid_t s_privilegedUid;
static gid_t s_privilegedGid;
#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
};
} // namespace nfd
+21 -1
View File
@@ -1,7 +1,7 @@
#include "TokenBucket.hpp"
#include "common/global.hpp"
#include "common/logger.hpp"
#include <iostream>
#include <functional>
namespace nfd {
namespace face {
@@ -28,6 +28,26 @@ namespace nfd {
}
getScheduler().schedule(time::milliseconds(4), std::bind(&TokenBucket::generateToken, this));
}
void TokenBucket::generateTokenByCurrentTime(long currentTime) {
if (this->lastGenerateTokenTime == -1) {
this->lastGenerateTokenTime = currentTime;
return;
}
if (currentTime - this->lastGenerateTokenTime < 1) {
return;
}
long currentStep = (currentTime - this->lastGenerateTokenTime) * this->rateLimit / 1000.0;
// std::cout << "currentStep: " << currentStep << "currentTime: " << currentTime << "lastGenerateTokenTime: " << this->lastGenerateTokenTime << std::endl;
// NFD_LOG_DEBUG(this->name << "=> do generateToken => " << this->currentTokenSize);
this->lastGenerateTokenTime = currentTime;
if (this->currentTokenSize + currentStep > this->bucketSize) {
this->currentTokenSize = this->bucketSize;
} else {
this->currentTokenSize += currentStep;
}
}
bool TokenBucket::use(uint64_t tokenNum) {
if(this->currentTokenSize > tokenNum) {
this->currentTokenSize -= tokenNum;
+7
View File
@@ -15,6 +15,12 @@ namespace nfd {
* 周期性增加token
**/
void generateToken();
/**
* 根据当前时间生成token
*/
void generateTokenByCurrentTime(long currentTime);
/**
* 尝试消费n个token
* @param tokenNum
@@ -28,6 +34,7 @@ namespace nfd {
uint64_t bucketSize; // 令牌桶容量
std::string name;
bool isStart; // 标识是否启动
long lastGenerateTokenTime = -1;
};
}
}
+6 -10
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -26,22 +26,17 @@
#include "channel.hpp"
#include "face.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
Channel::~Channel() = default;
void
Channel::setUri(const FaceUri& uri) noexcept
Channel::setUri(const FaceUri& uri)
{
m_uri = uri;
}
void
Channel::setDefaultMtu(size_t mtu) noexcept
{
m_defaultMtu = mtu;
}
void
connectFaceClosedSignal(Face& face, std::function<void()> f)
{
@@ -52,4 +47,5 @@ connectFaceClosedSignal(Face& face, std::function<void()> f)
});
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+9 -22
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -29,7 +29,8 @@
#include "channel-log.hpp"
#include "face-common.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
/** \brief Represents a channel that listens on a local endpoint.
* \sa FaceSystem
@@ -44,42 +45,27 @@ public:
~Channel();
const FaceUri&
getUri() const noexcept
getUri() const
{
return m_uri;
}
/**
* \brief Returns the default MTU for all faces created by this channel.
*/
size_t
getDefaultMtu() const noexcept
{
return m_defaultMtu;
}
/**
* \brief Returns whether the channel is listening.
/** \brief Returns whether the channel is listening
*/
virtual bool
isListening() const = 0;
/**
* \brief Returns the number of faces in the channel.
/** \brief Returns the number of faces in the channel
*/
virtual size_t
size() const = 0;
protected:
void
setUri(const FaceUri& uri) noexcept;
void
setDefaultMtu(size_t mtu) noexcept;
setUri(const FaceUri& uri);
private:
FaceUri m_uri;
size_t m_defaultMtu = ndn::MAX_NDN_PACKET_SIZE;
};
/** \brief Prototype for the callback that is invoked when a face is created
@@ -101,6 +87,7 @@ using FaceCreationFailedCallback = std::function<void(uint32_t status, const std
void
connectFaceClosedSignal(Face& face, std::function<void()> f);
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_CHANNEL_HPP
+33 -28
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -32,30 +32,25 @@
#include <array>
#include <boost/asio/defer.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
struct Unicast {};
struct Multicast {};
/**
* \brief Implements a Transport for datagram-based protocols.
/** \brief Implements Transport for datagram-based protocols.
*
* \tparam Protocol A datagram-based protocol in Boost.Asio
* \tparam Addressing The addressing mode, either Unicast or Multicast
* \tparam Protocol a datagram-based protocol in Boost.Asio
*/
template<class Protocol, class Addressing>
template<class Protocol, class Addressing = Unicast>
class DatagramTransport : public Transport
{
public:
using protocol = Protocol;
using addressing = Addressing;
typedef Protocol protocol;
/**
* \brief Construct datagram transport.
/** \brief Construct datagram transport.
*
* \param socket Protocol-specific socket for the created transport
* \param socket Protocol-specific socket for the created transport
*/
explicit
DatagramTransport(typename protocol::socket&& socket);
@@ -63,11 +58,11 @@ public:
ssize_t
getSendQueueLength() override;
/**
* \brief Receive datagram, translate buffer into packet, deliver to parent class.
/** \brief Receive datagram, translate buffer into packet, deliver to parent class.
*/
void
receiveDatagram(span<const uint8_t> buffer, const boost::system::error_code& error);
receiveDatagram(const uint8_t* buffer, size_t nBytesReceived,
const boost::system::error_code& error);
protected:
void
@@ -91,6 +86,9 @@ protected:
void
resetRecentlyReceived();
static EndpointId
makeEndpointId(const typename protocol::endpoint& ep);
protected:
typename protocol::socket m_socket;
typename protocol::endpoint m_sender;
@@ -152,7 +150,7 @@ DatagramTransport<T, U>::doClose()
// Ensure that the Transport stays alive at least until
// all pending handlers are dispatched
boost::asio::defer(getGlobalIoService(), [this] {
getGlobalIoService().post([this] {
this->setState(TransportState::CLOSED);
});
}
@@ -172,38 +170,37 @@ DatagramTransport<T, U>::doSend(const Block& packet)
template<class T, class U>
void
DatagramTransport<T, U>::receiveDatagram(span<const uint8_t> buffer,
DatagramTransport<T, U>::receiveDatagram(const uint8_t* buffer, size_t nBytesReceived,
const boost::system::error_code& error)
{
if (error)
return processErrorCode(error);
NFD_LOG_FACE_TRACE("Received: " << buffer.size() << " bytes from " << m_sender);
NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes from " << m_sender);
auto [isOk, element] = Block::fromBuffer(buffer);
bool isOk = false;
Block element;
std::tie(isOk, element) = Block::fromBuffer(buffer, nBytesReceived);
if (!isOk) {
NFD_LOG_FACE_WARN("Failed to parse incoming packet from " << m_sender);
// This packet won't extend the face lifetime
return;
}
if (element.size() != buffer.size()) {
if (element.size() != nBytesReceived) {
NFD_LOG_FACE_WARN("Received datagram size and decoded element size don't match");
// This packet won't extend the face lifetime
return;
}
m_hasRecentlyReceived = true;
if constexpr (std::is_same_v<addressing, Multicast>)
this->receive(element, m_sender);
else
this->receive(element);
this->receive(element, makeEndpointId(m_sender));
}
template<class T, class U>
void
DatagramTransport<T, U>::handleReceive(const boost::system::error_code& error, size_t nBytesReceived)
{
receiveDatagram(ndn::make_span(m_receiveBuffer).first(nBytesReceived), error);
receiveDatagram(m_receiveBuffer.data(), nBytesReceived, error);
if (m_socket.is_open())
m_socket.async_receive_from(boost::asio::buffer(m_receiveBuffer), m_sender,
@@ -260,6 +257,14 @@ DatagramTransport<T, U>::resetRecentlyReceived()
m_hasRecentlyReceived = false;
}
} // namespace nfd::face
template<class T, class U>
EndpointId
DatagramTransport<T, U>::makeEndpointId(const typename protocol::endpoint&)
{
return 0;
}
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_DATAGRAM_TRANSPORT_HPP
+27 -17
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -33,7 +33,8 @@
#include <boost/range/adaptor/map.hpp>
#include <pcap/pcap.h>
namespace nfd::face {
namespace nfd {
namespace face {
NFD_LOG_INIT(EthernetChannel);
@@ -101,9 +102,8 @@ void
EthernetChannel::asyncRead(const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onReceiveFailed)
{
m_socket.async_wait(boost::asio::posix::stream_descriptor::wait_read, [=] (const auto& e) {
handleRead(e, onFaceCreated, onReceiveFailed);
});
m_socket.async_read_some(boost::asio::null_buffers(),
[=] (const auto& e, auto) { this->handleRead(e, onFaceCreated, onReceiveFailed); });
}
void
@@ -120,20 +120,26 @@ EthernetChannel::handleRead(const boost::system::error_code& error,
return;
}
auto [pkt, readErr] = m_pcap.readNextPacket();
if (pkt.empty()) {
NFD_LOG_CHAN_WARN("Read error: " << readErr);
const uint8_t* pkt;
size_t len;
std::string err;
std::tie(pkt, len, err) = m_pcap.readNextPacket();
if (pkt == nullptr) {
NFD_LOG_CHAN_WARN("Read error: " << err);
}
else {
auto [eh, frameErr] = ethernet::checkFrameHeader(pkt, m_localEndpoint->getEthernetAddress(),
m_localEndpoint->getEthernetAddress());
const ether_header* eh;
std::tie(eh, err) = ethernet::checkFrameHeader(pkt, len, m_localEndpoint->getEthernetAddress(),
m_localEndpoint->getEthernetAddress());
if (eh == nullptr) {
NFD_LOG_CHAN_DEBUG(frameErr);
NFD_LOG_CHAN_DEBUG(err);
}
else {
ethernet::Address sender(eh->ether_shost);
pkt = pkt.subspan(ethernet::HDR_LEN);
processIncomingPacket(pkt, sender, onFaceCreated, onReceiveFailed);
pkt += ethernet::HDR_LEN;
len -= ethernet::HDR_LEN;
processIncomingPacket(pkt, len, sender, onFaceCreated, onReceiveFailed);
}
}
@@ -148,7 +154,7 @@ EthernetChannel::handleRead(const boost::system::error_code& error,
}
void
EthernetChannel::processIncomingPacket(span<const uint8_t> packet,
EthernetChannel::processIncomingPacket(const uint8_t* packet, size_t length,
const ethernet::Address& sender,
const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onReceiveFailed)
@@ -176,7 +182,7 @@ EthernetChannel::processIncomingPacket(span<const uint8_t> packet,
// dispatch the packet to the face for processing
auto* transport = static_cast<UnicastEthernetTransport*>(face->getTransport());
transport->receivePayload(packet, sender);
transport->receivePayload(packet, length, sender);
}
std::pair<bool, shared_ptr<Face>>
@@ -198,12 +204,15 @@ EthernetChannel::createFace(const ethernet::Address& remoteEndpoint,
if (params.mtu) {
options.overrideMtu = *params.mtu;
}
if (params.bandwidth) {
options.C = *params.bandwidth;
}
auto linkService = make_unique<GenericLinkService>(options);
auto transport = make_unique<UnicastEthernetTransport>(*m_localEndpoint, remoteEndpoint,
params.persistency, m_idleFaceTimeout);
auto face = make_shared<Face>(std::move(linkService), std::move(transport));
face->setChannel(weak_from_this());
face->setChannel(shared_from_this()); // use weak_from_this() in C++17
m_channelFaces[remoteEndpoint] = face;
connectFaceClosedSignal(*face, [this, remoteEndpoint] {
@@ -234,4 +243,5 @@ EthernetChannel::updateFilter()
m_pcap.setPacketFilter(filter.data());
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+21 -17
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, Regents of the University of California,
* Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -29,50 +29,53 @@
#include "channel.hpp"
#include "ethernet-protocol.hpp"
#include "pcap-helper.hpp"
#include <boost/asio/posix/stream_descriptor.hpp>
#include <ndn-cxx/net/network-interface.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
/**
* \brief Class implementing an Ethernet-based channel to create faces.
* \brief Class implementing Ethernet-based channel to create faces
*/
class EthernetChannel final : public Channel
class EthernetChannel : public Channel
{
public:
/**
* \brief EthernetChannel-related error.
* \brief EthernetChannel-related error
*/
class Error : public std::runtime_error
{
public:
using std::runtime_error::runtime_error;
explicit
Error(const std::string& what)
: std::runtime_error(what)
{
}
};
/**
* \brief Create an Ethernet channel on the given \p localEndpoint (network interface).
* \brief Create an Ethernet channel on the given \p localEndpoint (network interface)
*
* To enable the creation of faces upon incoming connections, one needs to
* explicitly call listen().
* To enable creation of faces upon incoming connections,
* one needs to explicitly call EthernetChannel::listen method.
*/
EthernetChannel(shared_ptr<const ndn::net::NetworkInterface> localEndpoint,
time::nanoseconds idleTimeout);
bool
isListening() const final
isListening() const override
{
return m_isListening;
}
size_t
size() const final
size() const override
{
return m_channelFaces.size();
}
/**
* \brief Create a unicast Ethernet face toward \p remoteEndpoint.
* \brief Create a unicast Ethernet face toward \p remoteEndpoint
*/
void
connect(const ethernet::Address& remoteEndpoint,
@@ -81,7 +84,7 @@ public:
const FaceCreationFailedCallback& onConnectFailed);
/**
* \brief Start listening.
* \brief Start listening
*
* Enable listening on the local endpoint, waiting for incoming frames,
* and creating a face when a frame is received from a new remote host.
@@ -107,7 +110,7 @@ private:
const FaceCreationFailedCallback& onReceiveFailed);
void
processIncomingPacket(span<const uint8_t> packet,
processIncomingPacket(const uint8_t* packet, size_t length,
const ethernet::Address& sender,
const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onReceiveFailed);
@@ -133,6 +136,7 @@ private:
#endif
};
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_ETHERNET_CHANNEL_HPP
+35 -36
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -30,7 +30,8 @@
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm/copy.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
NFD_LOG_INIT(EthernetFactory);
NFD_REGISTER_PROTOCOL_FACTORY(EthernetFactory);
@@ -46,8 +47,8 @@ EthernetFactory::EthernetFactory(const CtorParams& params)
: ProtocolFactory(params)
{
m_netifAddConn = netmon->onInterfaceAdded.connect([this] (const auto& netif) {
applyUnicastConfigToNetif(netif);
applyMcastConfigToNetif(*netif);
this->applyUnicastConfigToNetif(netif);
this->applyMcastConfigToNetif(*netif);
});
}
@@ -156,11 +157,11 @@ EthernetFactory::doProcessConfig(OptionalConfigSection configSection,
}
}
// Even if there are no configuration changes, we still need to re-apply
// the configuration because netifs may have changed.
m_unicastConfig = std::move(unicastConfig);
m_mcastConfig = std::move(mcastConfig);
applyConfig(context);
// Even if there's no configuration change, we still need to re-apply configuration because
// netifs may have changed.
m_unicastConfig = unicastConfig;
m_mcastConfig = mcastConfig;
this->applyConfig(context);
}
void
@@ -169,13 +170,13 @@ EthernetFactory::doCreateFace(const CreateFaceRequest& req,
const FaceCreationFailedCallback& onFailure)
{
if (!req.localUri || req.localUri->getScheme() != "dev") {
NFD_LOG_TRACE("createFace: dev:// LocalUri required");
NFD_LOG_TRACE("Cannot create unicast Ethernet face without dev:// LocalUri");
onFailure(406, "Creation of unicast Ethernet faces requires a LocalUri with dev:// scheme");
return;
}
if (req.params.persistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
NFD_LOG_TRACE("createFace: unsupported FacePersistency");
NFD_LOG_TRACE("createFace does not support FACE_PERSISTENCY_ON_DEMAND");
onFailure(406, "Outgoing Ethernet faces do not support on-demand persistency");
return;
}
@@ -184,14 +185,14 @@ EthernetFactory::doCreateFace(const CreateFaceRequest& req,
std::string localEndpoint(req.localUri->getHost());
if (remoteEndpoint.isMulticast()) {
NFD_LOG_TRACE("createFace: unsupported multicast endpoint");
NFD_LOG_TRACE("createFace does not support multicast faces");
onFailure(406, "Cannot create multicast Ethernet faces");
return;
}
if (req.params.wantLocalFields) {
// Ethernet faces are never local
NFD_LOG_TRACE("createFace: cannot create non-local face with local fields enabled");
NFD_LOG_TRACE("createFace cannot create non-local face with local fields enabled");
onFailure(406, "Local fields can only be enabled on faces with local scope");
return;
}
@@ -239,7 +240,7 @@ EthernetFactory::createMulticastFace(const ndn::net::NetworkInterface& netif,
{
BOOST_ASSERT(address.isMulticast());
std::pair key(netif.getName(), address);
auto key = std::make_pair(netif.getName(), address);
auto found = m_mcastFaces.find(key);
if (found != m_mcastFaces.end()) {
return found->second;
@@ -257,9 +258,7 @@ EthernetFactory::createMulticastFace(const ndn::net::NetworkInterface& netif,
connectFaceClosedSignal(*face, [this, key] { m_mcastFaces.erase(key); });
auto channelIt = m_channels.find(netif.getName());
if (channelIt != m_channels.end()) {
face->setChannel(channelIt->second);
}
face->setChannel(channelIt != m_channels.end() ? channelIt->second : nullptr);
return face;
}
@@ -271,13 +270,13 @@ EthernetFactory::applyUnicastConfigToNetif(const shared_ptr<const ndn::net::Netw
return nullptr;
}
if (!netif->isUp()) {
NFD_LOG_DEBUG("Not creating channel on " << netif->getName() << ": netif is down");
if (netif->getType() != ndn::net::InterfaceType::ETHERNET) {
NFD_LOG_DEBUG("Not creating channel on " << netif->getName() << ": incompatible netif type");
return nullptr;
}
if (netif->getType() != ndn::net::InterfaceType::ETHERNET) {
NFD_LOG_DEBUG("Not creating channel on " << netif->getName() << ": incompatible netif type");
if (!netif->isUp()) {
NFD_LOG_DEBUG("Not creating channel on " << netif->getName() << ": netif is down");
return nullptr;
}
@@ -305,18 +304,13 @@ EthernetFactory::applyMcastConfigToNetif(const ndn::net::NetworkInterface& netif
return nullptr;
}
if (!netif.isUp()) {
NFD_LOG_DEBUG("Not creating multicast face on " << netif.getName() << ": netif is down");
return nullptr;
}
if (netif.getType() != ndn::net::InterfaceType::ETHERNET) {
NFD_LOG_DEBUG("Not creating multicast face on " << netif.getName() << ": incompatible netif type");
return nullptr;
}
if (netif.getEthernetAddress().isNull()) {
NFD_LOG_DEBUG("Not creating multicast face on " << netif.getName() << ": invalid Ethernet address");
if (!netif.isUp()) {
NFD_LOG_DEBUG("Not creating multicast face on " << netif.getName() << ": netif is down");
return nullptr;
}
@@ -325,6 +319,11 @@ EthernetFactory::applyMcastConfigToNetif(const ndn::net::NetworkInterface& netif
return nullptr;
}
if (netif.getEthernetAddress().isNull()) {
NFD_LOG_DEBUG("Not creating multicast face on " << netif.getName() << ": invalid Ethernet address");
return nullptr;
}
if (!m_mcastConfig.netifPredicate(netif)) {
NFD_LOG_DEBUG("Not creating multicast face on " << netif.getName() << ": rejected by whitelist/blacklist");
return nullptr;
@@ -333,18 +332,17 @@ EthernetFactory::applyMcastConfigToNetif(const ndn::net::NetworkInterface& netif
NFD_LOG_DEBUG("Creating multicast face on " << netif.getName());
shared_ptr<Face> face;
try {
face = createMulticastFace(netif, m_mcastConfig.group);
face = this->createMulticastFace(netif, m_mcastConfig.group);
}
catch (const std::runtime_error& e) {
catch (const EthernetTransport::Error& e) {
NFD_LOG_WARN("Cannot create multicast face on " << netif.getName() << ": " << e.what());
return nullptr; // not a fatal error
return nullptr;
}
if (face->getId() == INVALID_FACEID) {
if (face->getId() == face::INVALID_FACEID) {
// new face: register with forwarding
this->addFace(face);
}
return face;
}
@@ -364,9 +362,9 @@ EthernetFactory::applyConfig(const FaceSystem::ConfigContext&)
// create channels and multicast faces if requested by config
for (const auto& netif : netmon->listNetworkInterfaces()) {
applyUnicastConfigToNetif(netif);
this->applyUnicastConfigToNetif(netif);
auto face = applyMcastConfigToNetif(*netif);
auto face = this->applyMcastConfigToNetif(*netif);
if (face != nullptr) {
// don't destroy face
oldFaces.erase(face);
@@ -379,4 +377,5 @@ EthernetFactory::applyConfig(const FaceSystem::ConfigContext&)
}
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+22 -23
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, Regents of the University of California,
* Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,14 +28,13 @@
#include "protocol-factory.hpp"
#include "ethernet-channel.hpp"
#include "network-predicate.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
/**
* \brief Protocol factory for Ethernet.
/** \brief Protocol factory for Ethernet
*/
class EthernetFactory final : public ProtocolFactory
class EthernetFactory : public ProtocolFactory
{
public:
static const std::string&
@@ -45,12 +44,12 @@ public:
EthernetFactory(const CtorParams& params);
/**
* \brief Create Ethernet-based channel on the specified network interface.
* \brief Create Ethernet-based channel on the specified network interface
*
* If this method is called twice with the same endpoint, only one channel
* will be created. The second call will just return the existing channel.
*
* \return Always a valid pointer to a EthernetChannel object, an exception
* \return always a valid pointer to a EthernetChannel object, an exception
* is thrown if it cannot be created.
* \throw PcapHelper::Error channel creation failed
*/
@@ -59,7 +58,7 @@ public:
time::nanoseconds idleTimeout);
/**
* \brief Create a face to communicate on the given Ethernet multicast group.
* \brief Create a face to communicate on the given Ethernet multicast group
*
* If this method is called twice with the same arguments, only one face
* will be created. The second call will just return the existing face.
@@ -67,35 +66,35 @@ public:
* \param localEndpoint local network interface
* \param group multicast group address
*
* \throw std::runtime_error %Face creation failed
* \throw EthernetTransport::Error transport creation fails
*/
shared_ptr<Face>
createMulticastFace(const ndn::net::NetworkInterface& localEndpoint,
const ethernet::Address& group);
private:
/** \brief process face_system.ether config section
*/
void
doProcessConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context) final;
FaceSystem::ConfigContext& context) override;
void
doCreateFace(const CreateFaceRequest& req,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onFailure) final;
const FaceCreationFailedCallback& onFailure) override;
std::vector<shared_ptr<const Channel>>
doGetChannels() const final;
doGetChannels() const override;
/**
* \brief Create EthernetChannel on \p netif if requested by \p m_unicastConfig.
* \return New or existing channel, or nullptr if no channel should be created.
/** \brief Create EthernetChannel on \p netif if requested by \p m_unicastConfig.
* \return new or existing channel, or nullptr if no channel should be created
*/
shared_ptr<EthernetChannel>
applyUnicastConfigToNetif(const shared_ptr<const ndn::net::NetworkInterface>& netif);
/**
* \brief Create Ethernet multicast face on \p netif if requested by \p m_mcastConfig.
* \return New or existing face, or nullptr if no face should be created.
/** \brief Create Ethernet multicast face on \p netif if requested by \p m_mcastConfig.
* \return new or existing face, or nullptr if no face should be created
*/
shared_ptr<Face>
applyMcastConfigToNetif(const ndn::net::NetworkInterface& netif);
@@ -104,8 +103,7 @@ private:
applyConfig(const FaceSystem::ConfigContext& context);
private:
// ifname => channel
std::map<std::string, shared_ptr<EthernetChannel>> m_channels;
std::map<std::string, shared_ptr<EthernetChannel>> m_channels; ///< ifname => channel
struct UnicastConfig
{
@@ -124,12 +122,13 @@ private:
};
MulticastConfig m_mcastConfig;
// [ifname, group] => face
/// (ifname, group) => face
std::map<std::pair<std::string, ethernet::Address>, shared_ptr<Face>> m_mcastFaces;
signal::ScopedConnection m_netifAddConn;
};
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_ETHERNET_FACTORY_HPP
+11 -8
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, Regents of the University of California,
* Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,15 +27,17 @@
#include <boost/endian/conversion.hpp>
namespace nfd::ethernet {
namespace nfd {
namespace ethernet {
std::tuple<const ether_header*, std::string>
checkFrameHeader(span<const uint8_t> packet, const Address& localAddr, const Address& destAddr)
std::pair<const ether_header*, std::string>
checkFrameHeader(const uint8_t* packet, size_t length,
const Address& localAddr, const Address& destAddr)
{
if (packet.size() < HDR_LEN + MIN_DATA_LEN)
return {nullptr, "Received frame too short: " + to_string(packet.size()) + " bytes"};
if (length < HDR_LEN + MIN_DATA_LEN)
return {nullptr, "Received frame too short: " + to_string(length) + " bytes"};
const ether_header* eh = reinterpret_cast<const ether_header*>(packet.data());
const ether_header* eh = reinterpret_cast<const ether_header*>(packet);
// in some cases VLAN-tagged frames may survive the BPF filter,
// make sure we do not process those frames (see #3348)
@@ -56,4 +58,5 @@ checkFrameHeader(span<const uint8_t> packet, const Address& localAddr, const Add
return {eh, ""};
}
} // namespace nfd::ethernet
} // namespace ethernet
} // namespace nfd
+8 -6
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,17 +27,19 @@
#define NFD_DAEMON_FACE_ETHERNET_PROTOCOL_HPP
#include "core/common.hpp"
#include <ndn-cxx/net/ethernet.hpp>
#include <net/ethernet.h>
namespace nfd::ethernet {
namespace nfd {
namespace ethernet {
using namespace ndn::ethernet;
std::tuple<const ether_header*, std::string>
checkFrameHeader(span<const uint8_t> packet, const Address& localAddr, const Address& destAddr);
std::pair<const ether_header*, std::string>
checkFrameHeader(const uint8_t* packet, size_t length,
const Address& localAddr, const Address& destAddr);
} // namespace nfd::ethernet
} // namespace ethernet
} // namespace nfd
#endif // NFD_DAEMON_FACE_ETHERNET_PROTOCOL_HPP
+42 -24
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -29,10 +29,12 @@
#include <pcap/pcap.h>
#include <boost/asio/defer.hpp>
#include <cstring> // for memcpy()
#include <boost/endian/conversion.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
NFD_LOG_INIT(EthernetTransport);
@@ -88,7 +90,7 @@ EthernetTransport::doClose()
// Ensure that the Transport stays alive at least
// until all pending handlers are dispatched
boost::asio::defer(getGlobalIoService(), [this] {
getGlobalIoService().post([this] {
this->setState(TransportState::CLOSED);
});
}
@@ -123,17 +125,17 @@ EthernetTransport::sendPacket(const ndn::Block& block)
// pad with zeroes if the payload is too short
if (block.size() < ethernet::MIN_DATA_LEN) {
static const uint8_t padding[ethernet::MIN_DATA_LEN] = {};
buffer.appendBytes(ndn::make_span(padding).subspan(block.size()));
buffer.appendByteArray(padding, ethernet::MIN_DATA_LEN - block.size());
}
// construct and prepend the ethernet header
uint16_t ethertype = boost::endian::native_to_big(ethernet::ETHERTYPE_NDN);
buffer.prependBytes({reinterpret_cast<const uint8_t*>(&ethertype), ethernet::TYPE_LEN});
buffer.prependBytes(m_srcAddress);
buffer.prependBytes(m_destAddress);
buffer.prependByteArray(reinterpret_cast<const uint8_t*>(&ethertype), ethernet::TYPE_LEN);
buffer.prependByteArray(m_srcAddress.data(), m_srcAddress.size());
buffer.prependByteArray(m_destAddress.data(), m_destAddress.size());
// send the frame
int sent = pcap_inject(m_pcap, buffer.data(), buffer.size());
int sent = pcap_inject(m_pcap, buffer.buf(), buffer.size());
if (sent < 0)
handleError("Send operation failed: " + m_pcap.getLastError());
else if (static_cast<size_t>(sent) < buffer.size())
@@ -147,8 +149,8 @@ EthernetTransport::sendPacket(const ndn::Block& block)
void
EthernetTransport::asyncRead()
{
m_socket.async_wait(boost::asio::posix::stream_descriptor::wait_read,
[this] (const auto& e) { this->handleRead(e); });
m_socket.async_read_some(boost::asio::null_buffers(),
[this] (const auto& e, auto) { this->handleRead(e); });
}
void
@@ -166,20 +168,26 @@ EthernetTransport::handleRead(const boost::system::error_code& error)
return;
}
auto [pkt, readErr] = m_pcap.readNextPacket();
if (pkt.empty()) {
NFD_LOG_FACE_DEBUG("Read error: " << readErr);
const uint8_t* pkt;
size_t len;
std::string err;
std::tie(pkt, len, err) = m_pcap.readNextPacket();
if (pkt == nullptr) {
NFD_LOG_FACE_WARN("Read error: " << err);
}
else {
auto [eh, frameErr] = ethernet::checkFrameHeader(pkt, m_srcAddress,
m_destAddress.isMulticast() ? m_destAddress : m_srcAddress);
const ether_header* eh;
std::tie(eh, err) = ethernet::checkFrameHeader(pkt, len, m_srcAddress,
m_destAddress.isMulticast() ? m_destAddress : m_srcAddress);
if (eh == nullptr) {
NFD_LOG_FACE_WARN(frameErr);
NFD_LOG_FACE_WARN(err);
}
else {
ethernet::Address sender(eh->ether_shost);
pkt = pkt.subspan(ethernet::HDR_LEN);
receivePayload(pkt, sender);
pkt += ethernet::HDR_LEN;
len -= ethernet::HDR_LEN;
receivePayload(pkt, len, sender);
}
}
@@ -194,11 +202,14 @@ EthernetTransport::handleRead(const boost::system::error_code& error)
}
void
EthernetTransport::receivePayload(span<const uint8_t> payload, const ethernet::Address& sender)
EthernetTransport::receivePayload(const uint8_t* payload, size_t length,
const ethernet::Address& sender)
{
NFD_LOG_FACE_TRACE("Received: " << payload.size() << " bytes from " << sender);
NFD_LOG_FACE_TRACE("Received: " << length << " bytes from " << sender);
auto [isOk, element] = Block::fromBuffer(payload);
bool isOk = false;
Block element;
std::tie(isOk, element) = Block::fromBuffer(payload, length);
if (!isOk) {
NFD_LOG_FACE_WARN("Failed to parse incoming packet from " << sender);
// This packet won't extend the face lifetime
@@ -206,7 +217,13 @@ EthernetTransport::receivePayload(span<const uint8_t> payload, const ethernet::A
}
m_hasRecentlyReceived = true;
this->receive(element, m_destAddress.isMulticast() ? sender : EndpointId{});
static_assert(sizeof(EndpointId) >= ethernet::ADDR_LEN, "EndpointId is too small");
EndpointId endpoint = 0;
if (m_destAddress.isMulticast()) {
std::memcpy(&endpoint, sender.data(), sender.size());
}
this->receive(element, endpoint);
}
void
@@ -222,4 +239,5 @@ EthernetTransport::handleError(const std::string& errorMessage)
doClose();
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+12 -9
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -30,13 +30,13 @@
#include "pcap-helper.hpp"
#include "transport.hpp"
#include <boost/asio/posix/stream_descriptor.hpp>
#include <ndn-cxx/net/network-interface.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
/**
* @brief Base class for Ethernet-based Transports.
* @brief Base class for Ethernet-based Transports
*/
class EthernetTransport : public Transport
{
@@ -48,12 +48,14 @@ public:
};
/**
* @brief Processes the payload of an incoming frame.
* @param payload Payload bytes, starting from the first byte after the Ethernet header
* @brief Processes the payload of an incoming frame
* @param payload Pointer to the first byte of data after the Ethernet header
* @param length Payload length
* @param sender Sender address
*/
void
receivePayload(span<const uint8_t> payload, const ethernet::Address& sender);
receivePayload(const uint8_t* payload, size_t length,
const ethernet::Address& sender);
protected:
EthernetTransport(const ndn::net::NetworkInterface& localEndpoint,
@@ -82,7 +84,7 @@ private:
doSend(const Block& packet) final;
/**
* @brief Sends the specified TLV block on the network wrapped in an Ethernet frame.
* @brief Sends the specified TLV block on the network wrapped in an Ethernet frame
*/
void
sendPacket(const ndn::Block& block);
@@ -113,6 +115,7 @@ private:
#endif
};
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_ETHERNET_TRANSPORT_HPP
+29 -32
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, Regents of the University of California,
* Copyright (c) 2014-2020, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,14 +26,12 @@
#ifndef NFD_DAEMON_FACE_FACE_COMMON_HPP
#define NFD_DAEMON_FACE_FACE_COMMON_HPP
#include "ethernet-protocol.hpp"
#include "udp-protocol.hpp"
#include "core/common.hpp"
#include "common/logger.hpp"
#include <ndn-cxx/encoding/nfd-constants.hpp>
#include <boost/logic/tribool.hpp>
#include <variant>
namespace nfd {
namespace face {
@@ -41,40 +39,36 @@ namespace face {
class Face;
class LinkService;
/**
* \brief Identifies a face.
/** \brief Identifies a face.
*/
using FaceId = uint64_t;
/// Indicates an invalid FaceId
inline constexpr FaceId INVALID_FACEID = ndn::nfd::INVALID_FACE_ID;
/// Identifies the InternalFace used in management
inline constexpr FaceId FACEID_INTERNAL_FACE = 1;
/// Identifies a packet comes from the ContentStore
inline constexpr FaceId FACEID_CONTENT_STORE = 254;
/// Identifies the NullFace that drops every packet
inline constexpr FaceId FACEID_NULL = 255;
/// Upper bound of reserved FaceIds
inline constexpr FaceId FACEID_RESERVED_MAX = 255;
/// indicates an invalid FaceId
const FaceId INVALID_FACEID = ndn::nfd::INVALID_FACE_ID;
/// identifies the InternalFace used in management
const FaceId FACEID_INTERNAL_FACE = 1;
/// identifies a packet comes from the ContentStore
const FaceId FACEID_CONTENT_STORE = 254;
/// identifies the NullFace that drops every packet
const FaceId FACEID_NULL = 255;
/// upper bound of reserved FaceIds
const FaceId FACEID_RESERVED_MAX = 255;
/**
* \brief Minimum MTU that may be set.
/** \brief Minimum MTU that may be set
*
* This is done to ensure the NDNLPv2 fragmentation feature functions properly.
* This is done to ensure the NDNLPv2 fragmentation feature functions properly.
*/
inline constexpr ssize_t MIN_MTU = 64;
const ssize_t MIN_MTU = 64;
/**
* \brief Identifies a remote endpoint on the link.
/** \brief Identifies a remote endpoint on the link.
*
* This ID is only meaningful in the context of the same Transport.
* Incoming packets from the same remote endpoint have the same EndpointId,
* and incoming packets from different remote endpoints have different EndpointIds.
* This ID is only meaningful in the context of the same Transport.
* Incoming packets from the same remote endpoint have the same EndpointId,
* and incoming packets from different remote endpoints have different EndpointIds.
*
* Typically, a point-to-point Transport has only one meaningful EndpointId,
* represented by `std::monostate`.
* Typically, a point-to-point Transport has only one meaningful EndpointId (usually 0).
*/
using EndpointId = std::variant<std::monostate, ethernet::Address, udp::Endpoint>;
using EndpointId = uint64_t;
/** \brief Parameters used to set Transport properties or LinkService options on a newly created face.
*
@@ -84,9 +78,10 @@ using EndpointId = std::variant<std::monostate, ethernet::Address, udp::Endpoint
struct FaceParams
{
ndn::nfd::FacePersistency persistency = ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
std::optional<time::nanoseconds> baseCongestionMarkingInterval;
std::optional<uint64_t> defaultCongestionThreshold;
std::optional<ssize_t> mtu;
optional<time::nanoseconds> baseCongestionMarkingInterval;
optional<uint64_t> defaultCongestionThreshold;
optional<ssize_t> mtu;
optional<uint64_t> bandwidth;
bool wantLocalFields = false;
bool wantLpReliability = false;
boost::logic::tribool wantCongestionMarking = boost::logic::indeterminate;
@@ -134,7 +129,9 @@ using face::FaceId;
// implementation detail
#define NFD_LOG_FACE(level, msg) NFD_LOG_##level( \
::nfd::face::FaceLogHelper< \
std::remove_cv_t<std::remove_reference_t<decltype(*this)>> \
typename std::remove_cv< \
typename std::remove_reference<decltype(*this)>::type \
>::type \
>(*this) \
<< msg)
/** \endcond */
+5 -3
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -25,7 +25,8 @@
#include "face-counters.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
FaceCounters::FaceCounters(const LinkService::Counters& linkServiceCounters,
const Transport::Counters& transportCounters)
@@ -45,4 +46,5 @@ FaceCounters::FaceCounters(const LinkService::Counters& linkServiceCounters,
{
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+10 -8
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -29,9 +29,10 @@
#include "link-service.hpp"
#include "transport.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
/** \brief Gives access to counters provided by Face.
/** \brief gives access to counters provided by Face
*
* This type is a facade that exposes common counters of a Face.
*
@@ -49,7 +50,7 @@ public:
* \throw std::bad_cast counters type mismatch
*/
template<typename T>
std::enable_if_t<std::is_base_of_v<LinkService::Counters, T>, const T&>
typename std::enable_if<std::is_base_of<LinkService::Counters, T>::value, const T&>::type
get() const
{
return dynamic_cast<const T&>(m_linkServiceCounters);
@@ -60,7 +61,7 @@ public:
* \throw std::bad_cast counters type mismatch
*/
template<typename T>
std::enable_if_t<std::is_base_of_v<Transport::Counters, T>, const T&>
typename std::enable_if<std::is_base_of<Transport::Counters, T>::value, const T&>::type
get() const
{
return dynamic_cast<const T&>(m_transportCounters);
@@ -80,11 +81,11 @@ public:
const ByteCounter& nInBytes;
const ByteCounter& nOutBytes;
/** \brief Count of incoming Interests dropped due to HopLimit == 0.
/** \brief count of incoming Interests dropped due to HopLimit == 0
*/
PacketCounter nInHopLimitZero;
/** \brief Count of outgoing Interests dropped due to HopLimit == 0 on non-local faces.
/** \brief count of outgoing Interests dropped due to HopLimit == 0 on non-local faces
*/
PacketCounter nOutHopLimitZero;
@@ -93,6 +94,7 @@ private:
const Transport::Counters& m_transportCounters;
};
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_FACE_COUNTERS_HPP
+12 -15
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,25 +30,16 @@
namespace nfd {
/**
* \brief Represents a face-endpoint pair in the forwarder.
* \sa face::Face, face::EndpointId
/** \brief Represents a face-endpoint pair in the forwarder.
* \sa face::Face, face::EndpointId
*/
class FaceEndpoint
{
public:
explicit
FaceEndpoint(Face& face, const EndpointId& endpoint = {});
private:
void
print(std::ostream& os) const;
friend std::ostream&
operator<<(std::ostream& os, const FaceEndpoint& fe)
FaceEndpoint(const Face& face, EndpointId endpoint)
: face(const_cast<Face&>(face))
, endpoint(endpoint)
{
fe.print(os);
return os;
}
public:
@@ -56,6 +47,12 @@ public:
const EndpointId endpoint;
};
inline std::ostream&
operator<<(std::ostream& os, const FaceEndpoint& fe)
{
return os << '(' << fe.face.getId() << ',' << fe.endpoint << ')';
}
} // namespace nfd
#endif // NFD_DAEMON_FACE_FACE_ENDPOINT_HPP
+17 -13
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -24,11 +24,13 @@
*/
#include "face-system.hpp"
#include "netdev-bound.hpp"
#include "protocol-factory.hpp"
#include "netdev-bound.hpp"
#include "common/global.hpp"
#include "fw/face-table.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
NFD_LOG_INIT(FaceSystem);
@@ -70,14 +72,14 @@ FaceSystem::listProtocolFactories() const
}
ProtocolFactory*
FaceSystem::getFactoryById(const std::string& id) const
FaceSystem::getFactoryById(const std::string& id)
{
auto found = m_factories.find(id);
return found == m_factories.end() ? nullptr : found->second.get();
}
ProtocolFactory*
FaceSystem::getFactoryByScheme(const std::string& scheme) const
FaceSystem::getFactoryByScheme(const std::string& scheme)
{
auto found = m_factoryByScheme.find(scheme);
return found == m_factoryByScheme.end() ? nullptr : found->second;
@@ -92,9 +94,7 @@ FaceSystem::hasFactoryForScheme(const std::string& scheme) const
void
FaceSystem::setConfigFile(ConfigFile& configFile)
{
configFile.addSectionHandler(CFGSEC_FACESYSTEM, [this] (auto&&... args) {
processConfig(std::forward<decltype(args)>(args)...);
});
configFile.addSectionHandler(CFGSEC_FACESYSTEM, bind(&FaceSystem::processConfig, this, _1, _2, _3));
}
void
@@ -118,19 +118,22 @@ FaceSystem::processConfig(const ConfigSection& configSection, bool isDryRun, con
}
// process in protocol factories
for (const auto& [sectionName, factory] : m_factories) {
for (const auto& pair : m_factories) {
const std::string& sectionName = pair.first;
ProtocolFactory* factory = pair.second.get();
std::set<std::string> oldProvidedSchemes = factory->getProvidedSchemes();
factory->processConfig(configSection.get_child_optional(sectionName), context);
if (!isDryRun) {
for (const auto& scheme : factory->getProvidedSchemes()) {
m_factoryByScheme[scheme] = factory.get();
for (const std::string& scheme : factory->getProvidedSchemes()) {
m_factoryByScheme[scheme] = factory;
if (oldProvidedSchemes.erase(scheme) == 0) {
NFD_LOG_TRACE("factory " << sectionName <<
" provides " << scheme << " FaceUri scheme");
}
}
for (const auto& scheme : oldProvidedSchemes) {
for (const std::string& scheme : oldProvidedSchemes) {
m_factoryByScheme.erase(scheme);
NFD_LOG_TRACE("factory " << sectionName <<
" no longer provides " << scheme << " FaceUri scheme");
@@ -161,4 +164,5 @@ FaceSystem::processConfig(const ConfigSection& configSection, bool isDryRun, con
}
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+18 -21
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -26,6 +26,7 @@
#ifndef NFD_DAEMON_FACE_FACE_SYSTEM_HPP
#define NFD_DAEMON_FACE_FACE_SYSTEM_HPP
#include "network-predicate.hpp"
#include "common/config-file.hpp"
#include <ndn-cxx/net/network-address.hpp>
@@ -42,11 +43,10 @@ class NetdevBound;
class ProtocolFactory;
struct ProtocolFactoryCtorParams;
/**
* \brief Entry point of NFD's face system.
/** \brief entry point of the face system
*
* NFD's face system is organized as a FaceSystem-ProtocolFactory-Channel-Face hierarchy.
* The FaceSystem class is the entry point of the face system and owns all ProtocolFactory objects.
* NFD's face system is organized as a FaceSystem-ProtocolFactory-Channel-Face hierarchy.
* FaceSystem class is the entry point of NFD's face system and owns ProtocolFactory objects.
*/
class FaceSystem : noncopyable
{
@@ -55,23 +55,20 @@ public:
~FaceSystem();
/**
* \brief Returns all ProtocolFactory objects owned by the face system.
/** \return ProtocolFactory objects owned by the FaceSystem
*/
[[nodiscard]] std::set<const ProtocolFactory*>
std::set<const ProtocolFactory*>
listProtocolFactories() const;
/**
* \return ProtocolFactory for the specified registered factory id or nullptr if not found.
/** \return ProtocolFactory for the specified registered factory id or nullptr if not found
*/
ProtocolFactory*
getFactoryById(const std::string& id) const;
getFactoryById(const std::string& id);
/**
* \return ProtocolFactory for the specified FaceUri scheme or nullptr if not found.
/** \return ProtocolFactory for the specified FaceUri scheme or nullptr if not found
*/
ProtocolFactory*
getFactoryByScheme(const std::string& scheme) const;
getFactoryByScheme(const std::string& scheme);
bool
hasFactoryForScheme(const std::string& scheme) const;
@@ -82,19 +79,19 @@ public:
return m_faceTable;
}
/** \brief Register handler for the `face_system` section of NFD's configuration file.
/** \brief register handler for face_system section of NFD configuration file
*/
void
setConfigFile(ConfigFile& configFile);
/** \brief Configuration options from `general` section.
/** \brief configuration options from "general" section
*/
struct GeneralConfig
{
bool wantCongestionMarking = true;
};
/** \brief Context for processing a config section in ProtocolFactory.
/** \brief context for processing a config section in ProtocolFactory
*/
class ConfigContext : noncopyable
{
@@ -103,7 +100,7 @@ public:
bool isDryRun;
};
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
ProtocolFactoryCtorParams
makePFCtorParams();
@@ -112,14 +109,14 @@ private:
processConfig(const ConfigSection& configSection, bool isDryRun,
const std::string& filename);
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/** \brief Config section name => protocol factory.
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/** \brief config section name => protocol factory
*/
std::map<std::string, unique_ptr<ProtocolFactory>> m_factories;
unique_ptr<NetdevBound> m_netdevBound;
private:
/** \brief Scheme => protocol factory.
/** \brief scheme => protocol factory
*
* The same protocol factory may be available under multiple schemes.
*/
+6 -3
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -25,7 +25,8 @@
#include "face.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
Face::Face(unique_ptr<LinkService> service, unique_ptr<Transport> transport)
: afterReceiveInterest(service->afterReceiveInterest)
@@ -33,6 +34,7 @@ Face::Face(unique_ptr<LinkService> service, unique_ptr<Transport> transport)
, afterReceiveNack(service->afterReceiveNack)
, onDroppedInterest(service->onDroppedInterest)
, afterStateChange(transport->afterStateChange)
, m_id(INVALID_FACEID)
, m_service(std::move(service))
, m_transport(std::move(transport))
, m_counters(m_service->getCounters(), m_transport->getCounters())
@@ -50,4 +52,5 @@ operator<<(std::ostream& os, const FaceLogHelper<Face>& flh)
return os;
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+68 -72
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -36,12 +36,11 @@ namespace face {
class Channel;
/**
* \brief Indicates the state of a face.
/** \brief indicates the state of a face
*/
using FaceState = TransportState;
typedef TransportState FaceState;
/** \brief Generalization of a network interface.
/** \brief generalization of a network interface
*
* A face generalizes a network interface.
* It provides best-effort network-layer packet delivery services
@@ -52,24 +51,18 @@ using FaceState = TransportState;
* LinkService is the upper part, which translates between network-layer packets
* and TLV blocks, and may provide additional services such as fragmentation and reassembly.
*/
class Face NFD_FINAL_UNLESS_WITH_TESTS : public std::enable_shared_from_this<Face>, noncopyable
class Face FINAL_UNLESS_WITH_TESTS : public std::enable_shared_from_this<Face>, noncopyable
{
public:
Face(unique_ptr<LinkService> service, unique_ptr<Transport> transport);
LinkService*
getLinkService() const noexcept
{
return m_service.get();
}
getLinkService() const;
Transport*
getTransport() const noexcept
{
return m_transport.get();
}
getTransport() const;
/** \brief Request that the face be closed.
/** \brief Request that the face be closed
*
* This operation is effective only if face is in the UP or DOWN state; otherwise, it has no effect.
* The face will change state to CLOSING, and then perform a cleanup procedure.
@@ -82,133 +75,106 @@ public:
close();
public: // upper interface connected to forwarding
/** \brief Send Interest.
/** \brief send Interest
*/
void
sendInterest(const Interest& interest);
/** \brief Send Data.
/** \brief send Data
*/
void
sendData(const Data& data);
/** \brief Send Nack.
/** \brief send Nack
*/
void
sendNack(const lp::Nack& nack);
/** \brief Signals on Interest received.
/** \brief signals on Interest received
*/
signal::Signal<LinkService, Interest, EndpointId>& afterReceiveInterest;
/** \brief Signals on Data received.
/** \brief signals on Data received
*/
signal::Signal<LinkService, Data, EndpointId>& afterReceiveData;
/** \brief Signals on Nack received.
/** \brief signals on Nack received
*/
signal::Signal<LinkService, lp::Nack, EndpointId>& afterReceiveNack;
/** \brief Signals on Interest dropped by reliability system for exceeding allowed number of retx.
/** \brief signals on Interest dropped by reliability system for exceeding allowed number of retx
*/
signal::Signal<LinkService, Interest>& onDroppedInterest;
public: // properties
/**
* \brief Returns the face ID.
/** \return face ID
*/
FaceId
getId() const noexcept
{
return m_id;
}
getId() const;
/**
* \brief Sets the face ID.
* \note Normally, this should only be invoked by FaceTable.
/** \brief sets face ID
* \note Normally, this should only be invoked by FaceTable.
*/
void
setId(FaceId id) noexcept
{
m_id = id;
}
setId(FaceId id);
/**
* \brief Returns a FaceUri representing the local endpoint.
/** \return a FaceUri representing local endpoint
*/
FaceUri
getLocalUri() const;
/**
* \brief Returns a FaceUri representing the remote endpoint.
/** \return a FaceUri representing remote endpoint
*/
FaceUri
getRemoteUri() const;
/**
* \brief Returns whether the face is local or non-local for scope control purposes.
/** \return whether face is local or non-local for scope control purpose
*/
ndn::nfd::FaceScope
getScope() const;
/**
* \brief Returns the current persistency setting of the face.
/** \return face persistency setting
*/
ndn::nfd::FacePersistency
getPersistency() const;
/**
* \brief Changes the face persistency setting.
/** \brief changes face persistency setting
*/
void
setPersistency(ndn::nfd::FacePersistency persistency);
/**
* \brief Returns the link type of the face (point-to-point, multi-access, ...).
/** \return whether face is point-to-point or multi-access
*/
ndn::nfd::LinkType
getLinkType() const;
/**
* \brief Returns the effective MTU of the face.
/** \brief Returns face effective MTU
*
* This function is a wrapper. The effective MTU of a face is determined by the link service.
* This function is a wrapper. The effective MTU of a face is determined by the link service.
*/
ssize_t
getMtu() const;
/**
* \brief Returns the face state.
/** \return face state
*/
FaceState
getState() const;
/**
* \brief Signals after face state changed.
/** \brief signals after face state changed
*/
signal::Signal<Transport, FaceState/*old*/, FaceState/*new*/>& afterStateChange;
/**
* \brief Returns the expiration time of the face.
* \retval time::steady_clock::time_point::max() The face has an indefinite lifetime.
/** \return expiration time of the face
* \retval time::steady_clock::TimePoint::max() the face has an indefinite lifetime
*/
time::steady_clock::time_point
time::steady_clock::TimePoint
getExpirationTime() const;
const FaceCounters&
getCounters() const noexcept
{
return m_counters;
}
FaceCounters&
getCounters() noexcept
{
return m_counters;
}
getCounters() const;
/**
* \brief Get channel on which face was created (unicast) or the associated channel (multicast).
* \brief Get channel on which face was created (unicast) or the associated channel (multicast)
*/
weak_ptr<Channel>
getChannel() const
@@ -217,7 +183,7 @@ public: // properties
}
/**
* \brief Set channel on which face was created (unicast) or the associated channel (multicast).
* \brief Set channel on which face was created (unicast) or the associated channel (multicast)
*/
void
setChannel(weak_ptr<Channel> channel)
@@ -226,13 +192,25 @@ public: // properties
}
private:
FaceId m_id = INVALID_FACEID;
FaceId m_id;
unique_ptr<LinkService> m_service;
unique_ptr<Transport> m_transport;
FaceCounters m_counters;
weak_ptr<Channel> m_channel;
};
inline LinkService*
Face::getLinkService() const
{
return m_service.get();
}
inline Transport*
Face::getTransport() const
{
return m_transport.get();
}
inline void
Face::close()
{
@@ -257,6 +235,18 @@ Face::sendNack(const lp::Nack& nack)
m_service->sendNack(nack);
}
inline FaceId
Face::getId() const
{
return m_id;
}
inline void
Face::setId(FaceId id)
{
m_id = id;
}
inline FaceUri
Face::getLocalUri() const
{
@@ -305,12 +295,18 @@ Face::getState() const
return m_transport->getState();
}
inline time::steady_clock::time_point
inline time::steady_clock::TimePoint
Face::getExpirationTime() const
{
return m_transport->getExpirationTime();
}
inline const FaceCounters&
Face::getCounters() const
{
return m_counters;
}
std::ostream&
operator<<(std::ostream& os, const FaceLogHelper<Face>& flh);
+45 -33
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -25,13 +25,13 @@
#include "generic-link-service.hpp"
#include <iostream>
#include <ndn-cxx/lp/fields.hpp>
#include <ndn-cxx/lp/pit-token.hpp>
#include <ndn-cxx/lp/tags.hpp>
#include <cmath>
namespace nfd::face {
namespace nfd {
namespace face {
NFD_LOG_INIT(GenericLinkService);
@@ -45,15 +45,16 @@ GenericLinkService::GenericLinkService(const GenericLinkService::Options& option
, m_reassembler(m_options.reassemblerOptions, this)
, m_reliability(m_options.reliabilityOptions, this)
, m_lastSeqNo(-2)
, m_nextMarkTime(time::steady_clock::time_point::max())
, m_nextMarkTime(time::steady_clock::TimePoint::max())
, m_nMarkedSinceInMarkingState(0)
, globalSp(options.C * 0.99, options.vqSize)
{
m_reassembler.beforeTimeout.connect([this] (auto&&...) { ++nReassemblyTimeouts; });
m_reliability.onDroppedInterest.connect([this] (const auto& i) { notifyDroppedInterest(i); });
std::cout << "C: " << options.C << std::endl;
m_reassembler.beforeTimeout.connect([this] (auto...) { ++this->nReassemblyTimeouts; });
m_reliability.onDroppedInterest.connect([this] (const auto& i) { this->notifyDroppedInterest(i); });
nReassembling.observe(&m_reassembler);
this->sendPacketCallback = [this](std::shared_ptr<VirtualQueueItem> taskPtr) {
this->globalSp.triggerCalObjectRate();
if (taskPtr != nullptr) {
const Block &block = taskPtr->item->wireEncode();
// std::cout << "interest wireEncode size: " << block.size() << std::endl;
@@ -70,12 +71,14 @@ GenericLinkService::GenericLinkService(const GenericLinkService::Options& option
auto newTaskPtr = this->globalSp.scheduleNext();
if (newTaskPtr == nullptr) {
//NFD_LOG_ERROR("FUCK");
// std::cout << "FUCK" << std::endl;
// 如果没有可调度的包,则 1 ms 之后再调度
this->canScheduler = true;
// getScheduler().schedule(time::milliseconds(1), std::bind(this->sendPacketCallback, nullptr));
} else {
// 等待足够的 token 再发送
this->canScheduler = false;
// std::cout << "Route waitTime: " << newTaskPtr->waitNsTime << std::endl;
// NFD_LOG_DEBUG("Route waitTime: " << newTaskPtr->waitNsTime);
getScheduler().schedule(time::nanoseconds((uint32_t)(newTaskPtr->waitNsTime)),
std::bind(this->sendPacketCallback, newTaskPtr));
@@ -136,7 +139,7 @@ GenericLinkService::sendLpPacket(lp::Packet&& pkt)
auto block = pkt.wireEncode();
if (mtu != MTU_UNLIMITED && block.size() > static_cast<size_t>(mtu)) {
++nOutOverMtu;
++this->nOutOverMtu;
NFD_LOG_FACE_WARN("attempted to send packet over MTU limit");
return;
}
@@ -170,7 +173,6 @@ GenericLinkService::doSendInterest(const Interest& interest)
// this->receiveNack(nack, endpointId);
//}
}
// lp::Packet lpPacket(interest.wireEncode());
// encodeLpFields(interest, lpPacket);
@@ -180,12 +182,9 @@ GenericLinkService::doSendInterest(const Interest& interest)
void
GenericLinkService::doSendData(const Data& data)
{
// const Block& block = data.wireEncode();
// std::cout << "Data wireEncode size: " << block.size() << std::endl;
lp::Packet lpPacket(data.wireEncode());
// std::cout << "Data before encode LpFields size: " << lpPacket.wireEncode().size() << std::endl;
encodeLpFields(data, lpPacket);
// std::cout << "Data After encode LpFields size: " << lpPacket.wireEncode().size() << std::endl;
this->sendNetPacket(std::move(lpPacket), false);
}
@@ -265,7 +264,7 @@ GenericLinkService::sendNetPacket(lp::Packet&& pkt, bool isInterest)
std::tie(isOk, frags) = m_fragmenter.fragmentPacket(pkt, mtu);
if (!isOk) {
// fragmentation failed (warning is logged by LpFragmenter)
++nFragmentationErrors;
++this->nFragmentationErrors;
return;
}
}
@@ -319,7 +318,7 @@ GenericLinkService::checkCongestionLevel(lp::Packet& pkt)
if (static_cast<size_t>(sendQueueLength) > m_options.defaultCongestionThreshold) {
const auto now = time::steady_clock::now();
if (m_nextMarkTime == time::steady_clock::time_point::max()) {
if (m_nextMarkTime == time::steady_clock::TimePoint::max()) {
m_nextMarkTime = now + m_options.baseCongestionMarkingInterval;
}
// Mark packet if sendQueue stays above target for one interval
@@ -337,10 +336,10 @@ GenericLinkService::checkCongestionLevel(lp::Packet& pkt)
m_nextMarkTime += interval;
}
}
else if (m_nextMarkTime != time::steady_clock::time_point::max()) {
else if (m_nextMarkTime != time::steady_clock::TimePoint::max()) {
// Congestion incident has ended, so reset
NFD_LOG_FACE_DEBUG("Send queue length dropped below congestion threshold");
m_nextMarkTime = time::steady_clock::time_point::max();
m_nextMarkTime = time::steady_clock::TimePoint::max();
m_nMarkedSinceInMarkingState = 0;
}
}
@@ -354,7 +353,7 @@ GenericLinkService::doReceivePacket(const Block& packet, const EndpointId& endpo
if (m_options.reliabilityOptions.isEnabled) {
if (!m_reliability.processIncomingPacket(pkt)) {
NFD_LOG_FACE_TRACE("received duplicate fragment: DROP");
++nDuplicateSequence;
++this->nDuplicateSequence;
return;
}
}
@@ -370,13 +369,16 @@ GenericLinkService::doReceivePacket(const Block& packet, const EndpointId& endpo
return;
}
auto [isReassembled, netPkt, firstPkt] = m_reassembler.receiveFragment(endpoint, pkt);
bool isReassembled = false;
Block netPkt;
lp::Packet firstPkt;
std::tie(isReassembled, netPkt, firstPkt) = m_reassembler.receiveFragment(endpoint, pkt);
if (isReassembled) {
this->decodeNetPacket(netPkt, firstPkt, endpoint);
}
}
catch (const tlv::Error& e) {
++nInLpInvalid;
++this->nInLpInvalid;
NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
}
}
@@ -399,14 +401,14 @@ GenericLinkService::decodeNetPacket(const Block& netPkt, const lp::Packet& first
this->decodeData(netPkt, firstPkt, endpointId);
break;
default:
++nInNetInvalid;
++this->nInNetInvalid;
NFD_LOG_FACE_WARN("unrecognized network-layer packet TLV-TYPE " << netPkt.type() << ": DROP");
return;
}
}
catch (const tlv::Error& e) {
++nInNetInvalid;
NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
++this->nInNetInvalid;
NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP" << netPkt.type());
}
}
@@ -431,7 +433,7 @@ GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstP
}
if (firstPkt.has<lp::CachePolicyField>()) {
++nInNetInvalid;
++this->nInNetInvalid;
NFD_LOG_FACE_WARN("received CachePolicy with Interest: DROP");
return;
}
@@ -454,7 +456,7 @@ GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstP
}
if (firstPkt.has<lp::PrefixAnnouncementField>()) {
++nInNetInvalid;
++this->nInNetInvalid;
NFD_LOG_FACE_WARN("received PrefixAnnouncement with Interest: DROP");
return;
}
@@ -463,6 +465,8 @@ GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstP
interest->setTag(make_shared<lp::PitToken>(firstPkt.get<lp::PitTokenField>()));
}
this->globalSp.receiveInterest(*interest);
this->globalSp.triggerCalObjectRate();
this->receiveInterest(*interest, endpointId);
}
@@ -476,13 +480,13 @@ GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt,
auto data = make_shared<Data>(netPkt);
if (firstPkt.has<lp::NackField>()) {
++nInNetInvalid;
++this->nInNetInvalid;
NFD_LOG_FACE_WARN("received Nack with Data: DROP");
return;
}
if (firstPkt.has<lp::NextHopFaceIdField>()) {
++nInNetInvalid;
++this->nInNetInvalid;
NFD_LOG_FACE_WARN("received NextHopFaceId with Data: DROP");
return;
}
@@ -503,7 +507,7 @@ GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt,
}
if (firstPkt.has<lp::NonDiscoveryField>()) {
++nInNetInvalid;
++this->nInNetInvalid;
NFD_LOG_FACE_WARN("received NonDiscovery with Data: DROP");
return;
}
@@ -517,6 +521,13 @@ GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt,
}
}
// 不处理本地命令通信
if (data->getName().getPrefix(1).toUri() != "/localhost") {
// TR = min(TR, OR)
this->globalSp.assignObjectRate(*data);
}
this->globalSp.triggerCalObjectRate();
this->receiveData(*data, endpointId);
}
@@ -531,13 +542,13 @@ GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt,
nack.setHeader(firstPkt.get<lp::NackField>());
if (firstPkt.has<lp::NextHopFaceIdField>()) {
++nInNetInvalid;
++this->nInNetInvalid;
NFD_LOG_FACE_WARN("received NextHopFaceId with Nack: DROP");
return;
}
if (firstPkt.has<lp::CachePolicyField>()) {
++nInNetInvalid;
++this->nInNetInvalid;
NFD_LOG_FACE_WARN("received CachePolicy with Nack: DROP");
return;
}
@@ -551,13 +562,13 @@ GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt,
}
if (firstPkt.has<lp::NonDiscoveryField>()) {
++nInNetInvalid;
++this->nInNetInvalid;
NFD_LOG_FACE_WARN("received NonDiscovery with Nack: DROP");
return;
}
if (firstPkt.has<lp::PrefixAnnouncementField>()) {
++nInNetInvalid;
++this->nInNetInvalid;
NFD_LOG_FACE_WARN("received PrefixAnnouncement with Nack: DROP");
return;
}
@@ -565,4 +576,5 @@ GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt,
this->receiveNack(nack, endpointId);
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+79 -73
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -32,73 +32,73 @@
#include "lp-reliability.hpp"
#include "queues.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
/** \brief Counters provided by GenericLinkService.
* \note The type name GenericLinkServiceCounters is an implementation detail.
* Use GenericLinkService::Counters in public API.
/** \brief counters provided by GenericLinkService
* \note The type name 'GenericLinkServiceCounters' is implementation detail.
* Use 'GenericLinkService::Counters' in public API.
*/
class GenericLinkServiceCounters : public virtual LinkService::Counters
{
public:
/** \brief Count of failed fragmentations.
/** \brief count of failed fragmentations
*/
PacketCounter nFragmentationErrors;
/** \brief Count of outgoing LpPackets dropped due to exceeding MTU limit.
/** \brief count of outgoing LpPackets dropped due to exceeding MTU limit
*
* If this counter is non-zero, the operator should enable fragmentation.
*/
PacketCounter nOutOverMtu;
/** \brief Count of invalid LpPackets dropped before reassembly.
/** \brief count of invalid LpPackets dropped before reassembly
*/
PacketCounter nInLpInvalid;
/** \brief Count of network-layer packets currently being reassembled.
/** \brief count of network-layer packets currently being reassembled
*/
SizeCounter<LpReassembler> nReassembling;
/** \brief Count of dropped partial network-layer packets due to reassembly timeout.
/** \brief count of dropped partial network-layer packets due to reassembly timeout
*/
PacketCounter nReassemblyTimeouts;
/** \brief Count of invalid reassembled network-layer packets dropped.
/** \brief count of invalid reassembled network-layer packets dropped
*/
PacketCounter nInNetInvalid;
/** \brief Count of network-layer packets that did not require retransmission of a fragment.
/** \brief count of network-layer packets that did not require retransmission of a fragment
*/
PacketCounter nAcknowledged;
/** \brief Count of network-layer packets that had at least one fragment retransmitted, but were
* eventually received in full.
/** \brief count of network-layer packets that had at least one fragment retransmitted, but were
* eventually received in full
*/
PacketCounter nRetransmitted;
/** \brief Count of network-layer packets dropped because a fragment reached the maximum number
* of retransmissions.
/** \brief count of network-layer packets dropped because a fragment reached the maximum number
* of retransmissions
*/
PacketCounter nRetxExhausted;
/** \brief Count of LpPackets dropped due to duplicate Sequence numbers.
/** \brief count of LpPackets dropped due to duplicate Sequence numbers
*/
PacketCounter nDuplicateSequence;
/** \brief Count of outgoing LpPackets that were marked with congestion marks.
/** \brief count of outgoing LpPackets that were marked with congestion marks
*/
PacketCounter nCongestionMarked;
};
/**
* \brief GenericLinkService is a LinkService that implements the NDNLPv2 protocol.
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
/** \brief GenericLinkService is a LinkService that implements the NDNLPv2 protocol
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
*/
class GenericLinkService NFD_FINAL_UNLESS_WITH_TESTS : public LinkService
, protected virtual GenericLinkServiceCounters
class GenericLinkService FINAL_UNLESS_WITH_TESTS : public LinkService
, protected virtual GenericLinkServiceCounters
{
public:
/** \brief %Options that control the behavior of GenericLinkService.
/** \brief Options that control the behavior of GenericLinkService
*/
class Options
{
@@ -108,35 +108,35 @@ public:
}
public:
/** \brief Enables encoding of IncomingFaceId, and decoding of NextHopFaceId and CachePolicy.
/** \brief enables encoding of IncomingFaceId, and decoding of NextHopFaceId and CachePolicy
*/
bool allowLocalFields = false;
/** \brief Enables fragmentation.
/** \brief enables fragmentation
*/
bool allowFragmentation = false;
/** \brief Options for fragmentation.
/** \brief options for fragmentation
*/
LpFragmenter::Options fragmenterOptions;
/** \brief Enables reassembly.
/** \brief enables reassembly
*/
bool allowReassembly = false;
/** \brief Options for reassembly.
/** \brief options for reassembly
*/
LpReassembler::Options reassemblerOptions;
/** \brief Options for reliability.
/** \brief options for reliability
*/
LpReliability::Options reliabilityOptions;
/** \brief Enables send queue congestion detection and marking.
/** \brief enables send queue congestion detection and marking
*/
bool allowCongestionMarking = false;
/** \brief Starting value for congestion marking interval.
/** \brief starting value for congestion marking interval
*
* Packets are marked if the queue size stays above THRESHOLD for at least one INTERVAL.
*
@@ -144,7 +144,7 @@ public:
*/
time::nanoseconds baseCongestionMarkingInterval = 100_ms;
/** \brief Default congestion threshold in bytes.
/** \brief default congestion threshold in bytes
*
* Packets are marked if the queue size stays above THRESHOLD for at least one INTERVAL.
*
@@ -152,102 +152,96 @@ public:
*/
size_t defaultCongestionThreshold = 65536;
/** \brief Enables self-learning forwarding support.
/** \brief enables self-learning forwarding support
*/
bool allowSelfLearning = true;
/** \brief Overrides the MTU provided by Transport.
/** \brief overrides MTU provided by Transport
*
* This MTU value will be used instead of the MTU provided by the transport if it is less than
* the transport MTU. However, it will not be utilized when the transport MTU is unlimited.
*
* Acceptable values for this option are values >= #MIN_MTU, which can be validated before
* Acceptable values for the override MTU are values >= MIN_MTU, which can be validated before
* being set with canOverrideMtuTo().
*/
ssize_t overrideMtu = std::numeric_limits<ssize_t>::max();
uint64_t C = 10000000;
uint64_t C = 100000000; // 100Mbps
size_t vqSize = 20;
};
/** \brief %Counters provided by GenericLinkService.
/** \brief counters provided by GenericLinkService
*/
using Counters = GenericLinkServiceCounters;
explicit
GenericLinkService(const Options& options = {});
/** \brief Get the options used by GenericLinkService.
/** \brief get Options used by GenericLinkService
*/
const Options&
getOptions() const
{
return m_options;
}
getOptions() const;
/** \brief Sets the options used by GenericLinkService.
/** \brief sets Options used by GenericLinkService
*/
void
setOptions(const Options& options);
const Counters&
getCounters() const NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL
{
return *this;
}
getCounters() const OVERRIDE_WITH_TESTS_ELSE_FINAL;
ssize_t
getEffectiveMtu() const NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL;
getEffectiveMtu() const OVERRIDE_WITH_TESTS_ELSE_FINAL;
/** \brief Whether MTU can be overridden to the specified value.
/** \brief Whether MTU can be overridden to the specified value
*
* If the transport MTU is unlimited, then this will always return false.
*/
bool
canOverrideMtuTo(ssize_t mtu) const;
NFD_PROTECTED_WITH_TESTS_ELSE_PRIVATE: // send path
/** \brief Request an IDLE packet to transmit pending service fields.
PROTECTED_WITH_TESTS_ELSE_PRIVATE: // send path
/** \brief request an IDLE packet to transmit pending service fields
*/
void
requestIdlePacket();
/** \brief Send an LpPacket.
/** \brief send an LpPacket
*/
void
sendLpPacket(lp::Packet&& pkt);
void
doSendInterest(const Interest& interest) NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL;
doSendInterest(const Interest& interest) OVERRIDE_WITH_TESTS_ELSE_FINAL;
void
doSendData(const Data& data) NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL;
doSendData(const Data& data) OVERRIDE_WITH_TESTS_ELSE_FINAL;
void
doSendNack(const ndn::lp::Nack& nack) NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL;
doSendNack(const ndn::lp::Nack& nack) OVERRIDE_WITH_TESTS_ELSE_FINAL;
/** \brief Assign consecutive sequence numbers to LpPackets.
/** \brief assign consecutive sequence numbers to LpPackets
*/
void
assignSequences(std::vector<lp::Packet>& pkts);
private: // send path
/** \brief Encode link protocol fields from tags onto an outgoing LpPacket.
/** \brief encode link protocol fields from tags onto an outgoing LpPacket
* \param netPkt network-layer packet to extract tags from
* \param lpPacket LpPacket to add link protocol fields to
*/
void
encodeLpFields(const ndn::PacketBase& netPkt, lp::Packet& lpPacket);
/** \brief Send a complete network layer packet.
/** \brief send a complete network layer packet
* \param pkt LpPacket containing a complete network layer packet
* \param isInterest whether the network layer packet is an Interest
*/
void
sendNetPacket(lp::Packet&& pkt, bool isInterest);
/** \brief If the send queue is found to be congested, add a congestion mark to the packet
* according to CoDel.
/** \brief if the send queue is found to be congested, add a congestion mark to the packet
* according to CoDel
* \sa https://tools.ietf.org/html/rfc8289
*/
void
@@ -255,9 +249,9 @@ private: // send path
private: // receive path
void
doReceivePacket(const Block& packet, const EndpointId& endpoint) NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL;
doReceivePacket(const Block& packet, const EndpointId& endpoint) OVERRIDE_WITH_TESTS_ELSE_FINAL;
/** \brief Decode incoming network-layer packet.
/** \brief decode incoming network-layer packet
* \param netPkt reassembled network-layer packet
* \param firstPkt LpPacket of first fragment
* \param endpointId endpoint of peer who sent the packet
@@ -268,7 +262,7 @@ private: // receive path
void
decodeNetPacket(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
/** \brief Decode incoming Interest.
/** \brief decode incoming Interest
* \param netPkt reassembled network-layer packet; TLV-TYPE must be Interest
* \param firstPkt LpPacket of first fragment; must not have Nack field
* \param endpointId endpoint of peer who sent the Interest
@@ -281,7 +275,7 @@ private: // receive path
void
decodeInterest(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
/** \brief Decode incoming Interest.
/** \brief decode incoming Interest
* \param netPkt reassembled network-layer packet; TLV-TYPE must be Data
* \param firstPkt LpPacket of first fragment
* \param endpointId endpoint of peer who sent the Data
@@ -294,7 +288,7 @@ private: // receive path
void
decodeData(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
/** \brief Decode incoming Interest.
/** \brief decode incoming Interest
* \param netPkt reassembled network-layer packet; TLV-TYPE must be Interest
* \param firstPkt LpPacket of first fragment; must have Nack field
* \param endpointId endpoint of peer who sent the Nack
@@ -307,26 +301,38 @@ private: // receive path
void
decodeNack(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
NFD_PROTECTED_WITH_TESTS_ELSE_PRIVATE:
PROTECTED_WITH_TESTS_ELSE_PRIVATE:
Options m_options;
LpFragmenter m_fragmenter;
LpReassembler m_reassembler;
LpReliability m_reliability;
lp::Sequence m_lastSeqNo;
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/// Time to mark next packet due to send queue congestion
time::steady_clock::time_point m_nextMarkTime;
time::steady_clock::TimePoint m_nextMarkTime;
/// number of marked packets in the current incident of congestion
size_t m_nMarkedSinceInMarkingState;
GlobalSP globalSp;
bool canScheduler = true;
std::function<void(std::shared_ptr<VirtualQueueItem>)> sendPacketCallback;
friend LpReliability;
friend class LpReliability;
};
} // namespace nfd::face
inline const GenericLinkService::Options&
GenericLinkService::getOptions() const
{
return m_options;
}
inline const GenericLinkService::Counters&
GenericLinkService::getCounters() const
{
return *this;
}
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_GENERIC_LINK_SERVICE_HPP
+6 -4
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -28,7 +28,8 @@
#include "internal-transport.hpp"
#include "common/global.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
std::tuple<shared_ptr<Face>, shared_ptr<ndn::Face>>
makeInternalFace(ndn::KeyChain& clientKeyChain)
@@ -45,7 +46,8 @@ makeInternalFace(ndn::KeyChain& clientKeyChain)
auto clientFace = make_shared<ndn::Face>(clientTransport, getGlobalIoService(), clientKeyChain);
return {face, clientFace};
return std::make_tuple(face, clientFace);
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+9 -8
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, Regents of the University of California,
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,16 +27,16 @@
#define NFD_DAEMON_FACE_INTERNAL_FACE_HPP
#include "face.hpp"
#include <ndn-cxx/face.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
/** \brief Make a pair of forwarder-side face and client-side face
* that are connected to each other.
/** \brief make a pair of forwarder-side face and client-side face
* that are connected with each other
*
* Network-layer packets sent by one face will be received by the other face
* after `io.poll()`.
* after io.poll().
*
* \param clientKeyChain A KeyChain used by client-side face to sign
* prefix registration commands.
@@ -45,6 +45,7 @@ namespace nfd::face {
std::tuple<shared_ptr<Face>, shared_ptr<ndn::Face>>
makeInternalFace(ndn::KeyChain& clientKeyChain);
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_INTERNAL_FACE_HPP
+17 -7
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, Regents of the University of California,
* Copyright (c) 2014-2020, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,9 +26,8 @@
#include "internal-transport.hpp"
#include "common/global.hpp"
#include <boost/asio/post.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
NFD_LOG_MEMBER_INIT(InternalForwarderTransport, InternalForwarderTransport);
NFD_LOG_MEMBER_INIT(InternalClientTransport, InternalClientTransport);
@@ -49,7 +48,7 @@ InternalForwarderTransport::InternalForwarderTransport(const FaceUri& localUri,
void
InternalForwarderTransport::receivePacket(const Block& packet)
{
boost::asio::post(getGlobalIoService(), [this, packet] {
getGlobalIoService().post([this, packet] {
NFD_LOG_FACE_TRACE("Received: " << packet.size() << " bytes");
receive(packet);
});
@@ -107,7 +106,7 @@ InternalClientTransport::connectToForwarder(InternalForwarderTransport* forwarde
void
InternalClientTransport::receivePacket(const Block& packet)
{
boost::asio::post(getGlobalIoService(), [this, packet] {
getGlobalIoService().post([this, packet] {
NFD_LOG_TRACE("Received: " << packet.size() << " bytes");
if (m_receiveCallback) {
m_receiveCallback(packet);
@@ -124,4 +123,15 @@ InternalClientTransport::send(const Block& wire)
m_forwarder->receivePacket(wire);
}
} // namespace nfd::face
void
InternalClientTransport::send(const Block& header, const Block& payload)
{
ndn::EncodingBuffer encoder(header.size() + payload.size(), header.size() + payload.size());
encoder.appendByteArray(header.wire(), header.size());
encoder.appendByteArray(payload.wire(), payload.size());
send(encoder.block());
}
} // namespace face
} // namespace nfd
+16 -14
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -30,23 +30,22 @@
#include <ndn-cxx/transport/transport.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
/**
* \brief Abstracts a transport that can be paired with another.
/** \brief Abstracts a transport that can be paired with another.
*/
class InternalTransportBase
{
public:
virtual
~InternalTransportBase() = default;
virtual void
receivePacket(const Block& packet) = 0;
protected:
~InternalTransportBase() = default;
};
/**
* \brief Implements a forwarder-side transport that can be paired with another transport.
/** \brief Implements a forwarder-side transport that can be paired with another transport.
*/
class InternalForwarderTransport final : public Transport, public InternalTransportBase
{
@@ -58,7 +57,7 @@ public:
ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_POINT_TO_POINT);
void
setPeer(InternalTransportBase* peer) noexcept
setPeer(InternalTransportBase* peer)
{
m_peer = peer;
}
@@ -80,8 +79,7 @@ private:
InternalTransportBase* m_peer = nullptr;
};
/**
* \brief Implements a client-side transport that can be paired with an InternalForwarderTransport.
/** \brief Implements a client-side transport that can be paired with an InternalForwarderTransport.
*/
class InternalClientTransport final : public ndn::Transport, public InternalTransportBase
{
@@ -103,7 +101,10 @@ public:
receivePacket(const Block& packet) final;
void
send(const Block& block) final;
send(const Block& wire) final;
void
send(const Block& header, const Block& payload) final;
void
close() final
@@ -127,6 +128,7 @@ private:
signal::ScopedConnection m_fwTransportStateConn;
};
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_INTERNAL_TRANSPORT_HPP
+15 -5
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, Regents of the University of California,
* Copyright (c) 2014-2020, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,14 +26,23 @@
#include "link-service.hpp"
#include "face.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
NFD_LOG_INIT(LinkService);
LinkService::~LinkService() = default;
LinkService::LinkService()
: m_face(nullptr)
, m_transport(nullptr)
{
}
LinkService::~LinkService()
{
}
void
LinkService::setFaceAndTransport(Face& face, Transport& transport) noexcept
LinkService::setFaceAndTransport(Face& face, Transport& transport)
{
BOOST_ASSERT(m_face == nullptr);
BOOST_ASSERT(m_transport == nullptr);
@@ -126,4 +135,5 @@ operator<<(std::ostream& os, const FaceLogHelper<LinkService>& flh)
return os;
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+77 -67
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -30,162 +30,147 @@
#include "transport.hpp"
#include "common/counter.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
/** \brief Counters provided by LinkService.
* \note The type name LinkServiceCounters is an implementation detail.
* Use LinkService::Counters in public API.
/** \brief counters provided by LinkService
* \note The type name 'LinkServiceCounters' is implementation detail.
* Use 'LinkService::Counters' in public API.
*/
class LinkServiceCounters
{
public:
/** \brief Count of incoming Interests.
/** \brief count of incoming Interests
*/
PacketCounter nInInterests;
/** \brief Count of outgoing Interests.
/** \brief count of outgoing Interests
*/
PacketCounter nOutInterests;
/** \brief Count of Interests dropped by reliability system for exceeding allowed number of retx.
/** \brief count of Interests dropped by reliability system for exceeding allowed number of retx
*/
PacketCounter nInterestsExceededRetx;
/** \brief Count of incoming Data packets.
/** \brief count of incoming Data packets
*/
PacketCounter nInData;
/** \brief Count of outgoing Data packets.
/** \brief count of outgoing Data packets
*/
PacketCounter nOutData;
/** \brief Count of incoming Nacks.
/** \brief count of incoming Nacks
*/
PacketCounter nInNacks;
/** \brief Count of outgoing Nacks.
/** \brief count of outgoing Nacks
*/
PacketCounter nOutNacks;
};
/**
* \brief The upper half of a Face.
* \sa Face, Transport
/** \brief the upper part of a Face
* \sa Face
*/
class LinkService : protected virtual LinkServiceCounters, noncopyable
{
public:
/**
* \brief %Counters provided by LinkService.
/** \brief counters provided by LinkService
*/
using Counters = LinkServiceCounters;
typedef LinkServiceCounters Counters;
public:
LinkService();
virtual
~LinkService();
/**
* \brief Set Face and Transport for this LinkService.
* \pre setFaceAndTransport() has not been called.
/** \brief set Face and Transport for LinkService
* \pre setFaceAndTransport has not been called
*/
void
setFaceAndTransport(Face& face, Transport& transport) noexcept;
setFaceAndTransport(Face& face, Transport& transport);
/**
* \brief Returns the Face to which this LinkService is attached.
/** \return Face to which this LinkService is attached
*/
const Face*
getFace() const noexcept
{
return m_face;
}
getFace() const;
/**
* \brief Returns the Transport to which this LinkService is attached.
/** \return Transport to which this LinkService is attached
*/
const Transport*
getTransport() const noexcept
{
return m_transport;
}
getTransport() const;
/**
* \brief Returns the Transport to which this LinkService is attached.
/** \return Transport to which this LinkService is attached
*/
Transport*
getTransport() noexcept
{
return m_transport;
}
getTransport();
virtual const Counters&
getCounters() const
{
return *this;
}
getCounters() const;
virtual ssize_t
getEffectiveMtu() const;
public: // upper interface to be used by forwarding
/** \brief Send Interest.
* \pre setFaceAndTransport() has been called.
/** \brief Send Interest
* \pre setTransport has been called
*/
void
sendInterest(const Interest& interest);
/** \brief Send Data.
* \pre setFaceAndTransport() has been called.
/** \brief Send Data
* \pre setTransport has been called
*/
void
sendData(const Data& data);
/** \brief Send Nack.
* \pre setFaceAndTransport() has been called.
/** \brief Send Nack
* \pre setTransport has been called
*/
void
sendNack(const ndn::lp::Nack& nack);
/** \brief Signals on Interest received.
/** \brief signals on Interest received
*/
signal::Signal<LinkService, Interest, EndpointId> afterReceiveInterest;
/** \brief Signals on Data received.
/** \brief signals on Data received
*/
signal::Signal<LinkService, Data, EndpointId> afterReceiveData;
/** \brief Signals on Nack received.
/** \brief signals on Nack received
*/
signal::Signal<LinkService, lp::Nack, EndpointId> afterReceiveNack;
/** \brief Signals on Interest dropped by reliability system for exceeding allowed number of retx.
/** \brief signals on Interest dropped by reliability system for exceeding allowed number of retx
*/
signal::Signal<LinkService, Interest> onDroppedInterest;
public: // lower interface to be invoked by Transport
/** \brief Performs LinkService specific operations to receive a lower-layer packet.
/** \brief performs LinkService specific operations to receive a lower-layer packet
*/
void
receivePacket(const Block& packet, const EndpointId& endpoint);
protected: // upper interface to be invoked in subclass (receive path termination)
/** \brief Delivers received Interest to forwarding.
/** \brief delivers received Interest to forwarding
*/
void
receiveInterest(const Interest& interest, const EndpointId& endpoint);
/** \brief Delivers received Data to forwarding.
/** \brief delivers received Data to forwarding
*/
void
receiveData(const Data& data, const EndpointId& endpoint);
/** \brief Delivers received Nack to forwarding.
/** \brief delivers received Nack to forwarding
*/
void
receiveNack(const lp::Nack& nack, const EndpointId& endpoint);
protected: // lower interface to be invoked in subclass (send path termination)
/** \brief Send a lower-layer packet via Transport.
/** \brief send a lower-layer packet via Transport
*/
void
sendPacket(const Block& packet);
@@ -195,17 +180,17 @@ protected:
notifyDroppedInterest(const Interest& packet);
private: // upper interface to be overridden in subclass (send path entrypoint)
/** \brief Performs LinkService specific operations to send an Interest.
/** \brief performs LinkService specific operations to send an Interest
*/
virtual void
doSendInterest(const Interest& interest) = 0;
/** \brief Performs LinkService specific operations to send a Data.
/** \brief performs LinkService specific operations to send a Data
*/
virtual void
doSendData(const Data& data) = 0;
/** \brief Performs LinkService specific operations to send a Nack.
/** \brief performs LinkService specific operations to send a Nack
*/
virtual void
doSendNack(const lp::Nack& nack) = 0;
@@ -215,10 +200,34 @@ private: // lower interface to be overridden in subclass
doReceivePacket(const Block& packet, const EndpointId& endpoint) = 0;
private:
Face* m_face = nullptr;
Transport* m_transport = nullptr;
Face* m_face;
Transport* m_transport;
};
inline const Face*
LinkService::getFace() const
{
return m_face;
}
inline const Transport*
LinkService::getTransport() const
{
return m_transport;
}
inline Transport*
LinkService::getTransport()
{
return m_transport;
}
inline const LinkService::Counters&
LinkService::getCounters() const
{
return *this;
}
inline ssize_t
LinkService::getEffectiveMtu() const
{
@@ -241,13 +250,14 @@ std::ostream&
operator<<(std::ostream& os, const FaceLogHelper<LinkService>& flh);
template<typename T>
std::enable_if_t<std::is_base_of_v<LinkService, T> && !std::is_same_v<LinkService, T>,
std::ostream&>
typename std::enable_if<std::is_base_of<LinkService, T>::value &&
!std::is_same<LinkService, T>::value, std::ostream&>::type
operator<<(std::ostream& os, const FaceLogHelper<T>& flh)
{
return os << FaceLogHelper<LinkService>(flh.obj);
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_LINK_SERVICE_HPP
+20 -17
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, Regents of the University of California,
* Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,9 +26,10 @@
#include "lp-fragmenter.hpp"
#include "link-service.hpp"
#include <ndn-cxx/lp/fields.hpp>
#include <ndn-cxx/encoding/tlv.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
NFD_LOG_INIT(LpFragmenter);
@@ -38,18 +39,18 @@ static_assert(lp::tlv::FragIndex < 253, "FragIndex TLV-TYPE must fit in 1 octet"
static_assert(lp::tlv::FragCount < 253, "FragCount TLV-TYPE must fit in 1 octet");
static_assert(lp::tlv::Fragment < 253, "Fragment TLV-TYPE must fit in 1 octet");
/**
* \brief Maximum overhead on a single fragment, not counting other NDNLPv2 headers.
/** \brief maximum overhead on a single fragment,
* not counting other NDNLPv2 headers
*/
constexpr size_t MAX_SINGLE_FRAG_OVERHEAD =
static const size_t MAX_SINGLE_FRAG_OVERHEAD =
1 + 9 + // LpPacket TLV-TYPE and TLV-LENGTH
1 + 1 + 8 + // Sequence TLV
1 + 9; // Fragment TLV-TYPE and TLV-LENGTH
/**
* \brief Maximum overhead of adding fragmentation to payload, not counting other NDNLPv2 headers.
/** \brief maximum overhead of adding fragmentation to payload,
* not counting other NDNLPv2 headers
*/
constexpr size_t MAX_FRAG_OVERHEAD =
static const size_t MAX_FRAG_OVERHEAD =
1 + 9 + // LpPacket TLV-TYPE and TLV-LENGTH
1 + 1 + 8 + // Sequence TLV
1 + 1 + 8 + // FragIndex TLV
@@ -85,17 +86,18 @@ LpFragmenter::fragmentPacket(const lp::Packet& packet, size_t mtu)
// fast path: fragmentation not needed
// To qualify for fast path, the packet must have space for adding a sequence number,
// because another NDNLPv2 feature may require the sequence number.
return {true, {packet}};
return std::make_tuple(true, std::vector<lp::Packet>{packet});
}
auto [netPktBegin, netPktEnd] = packet.get<lp::FragmentField>();
ndn::Buffer::const_iterator netPktBegin, netPktEnd;
std::tie(netPktBegin, netPktEnd) = packet.get<lp::FragmentField>();
size_t netPktSize = std::distance(netPktBegin, netPktEnd);
// compute size of other NDNLPv2 headers to be placed on the first fragment
size_t firstHeaderSize = 0;
const auto& packetWire = packet.wireEncode();
const Block& packetWire = packet.wireEncode();
if (packetWire.type() == lp::tlv::LpPacket) {
for (const auto& element : packetWire.elements()) {
for (const Block& element : packetWire.elements()) {
if (element.type() != lp::tlv::Fragment) {
firstHeaderSize += element.size();
}
@@ -105,7 +107,7 @@ LpFragmenter::fragmentPacket(const lp::Packet& packet, size_t mtu)
// compute payload size
if (MAX_FRAG_OVERHEAD + firstHeaderSize + 1 > mtu) { // 1-octet fragment
NFD_LOG_FACE_WARN("fragmentation error, MTU too small for first fragment: DROP");
return {false, {}};
return std::make_tuple(false, std::vector<lp::Packet>{});
}
size_t firstPayloadSize = std::min(netPktSize, mtu - firstHeaderSize - MAX_FRAG_OVERHEAD);
size_t payloadSize = mtu - MAX_FRAG_OVERHEAD;
@@ -115,7 +117,7 @@ LpFragmenter::fragmentPacket(const lp::Packet& packet, size_t mtu)
// compute FragCount
if (fragCount > m_options.nMaxFragments) {
NFD_LOG_FACE_WARN("fragmentation error, FragCount over limit: DROP");
return {false, {}};
return std::make_tuple(false, std::vector<lp::Packet>{});
}
// populate fragments
@@ -137,7 +139,7 @@ LpFragmenter::fragmentPacket(const lp::Packet& packet, size_t mtu)
}
BOOST_ASSERT(fragIndex == fragCount);
return {true, frags};
return std::make_tuple(true, frags);
}
std::ostream&
@@ -152,4 +154,5 @@ operator<<(std::ostream& os, const FaceLogHelper<LpFragmenter>& flh)
return os;
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+10 -8
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,19 +30,20 @@
#include <ndn-cxx/lp/packet.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
/** \brief Fragments network-layer packets into NDNLPv2 link-layer packets.
/** \brief fragments network-layer packets into NDNLPv2 link-layer packets
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
*/
class LpFragmenter
{
public:
/** \brief %Options that control the behavior of LpFragmenter.
/** \brief Options that control the behavior of LpFragmenter
*/
struct Options
{
/** \brief Maximum number of fragments in a packet.
/** \brief maximum number of fragments in a packet
*/
size_t nMaxFragments = 400;
};
@@ -50,7 +51,7 @@ public:
explicit
LpFragmenter(const Options& options, const LinkService* linkService = nullptr);
/** \brief Set options for fragmenter.
/** \brief set options for fragmenter
*/
void
setOptions(const Options& options);
@@ -62,7 +63,7 @@ public:
const LinkService*
getLinkService() const;
/** \brief Fragments a network-layer packet into link-layer packets.
/** \brief fragments a network-layer packet into link-layer packets
* \param packet an LpPacket that contains a network-layer packet;
* must have Fragment field, must not have FragIndex and FragCount fields
* \param mtu maximum allowable LpPacket size after fragmentation and sequence number assignment
@@ -79,6 +80,7 @@ private:
std::ostream&
operator<<(std::ostream& os, const FaceLogHelper<LpFragmenter>& flh);
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_LP_FRAGMENTER_HPP
+28 -22
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -24,14 +24,13 @@
*/
#include "lp-reassembler.hpp"
#include "common/global.hpp"
#include "link-service.hpp"
#include <ndn-cxx/lp/fields.hpp>
#include "common/global.hpp"
#include <numeric>
namespace nfd::face {
namespace nfd {
namespace face {
NFD_LOG_INIT(LpReassembler);
@@ -42,10 +41,12 @@ LpReassembler::LpReassembler(const LpReassembler::Options& options, const LinkSe
}
std::tuple<bool, Block, lp::Packet>
LpReassembler::receiveFragment(const EndpointId& remoteEndpoint, const lp::Packet& packet)
LpReassembler::receiveFragment(EndpointId remoteEndpoint, const lp::Packet& packet)
{
BOOST_ASSERT(packet.has<lp::FragmentField>());
static auto FALSE_RETURN = std::make_tuple(false, Block(), lp::Packet());
// read and check FragIndex and FragCount
uint64_t fragIndex = 0;
uint64_t fragCount = 1;
@@ -58,29 +59,29 @@ LpReassembler::receiveFragment(const EndpointId& remoteEndpoint, const lp::Packe
if (fragIndex >= fragCount) {
NFD_LOG_FACE_WARN("reassembly error, FragIndex>=FragCount: DROP");
return {false, {}, {}};
return FALSE_RETURN;
}
if (fragCount > m_options.nMaxFragments) {
NFD_LOG_FACE_WARN("reassembly error, FragCount over limit: DROP");
return {false, {}, {}};
return FALSE_RETURN;
}
// check for fast path
if (fragIndex == 0 && fragCount == 1) {
auto frag = packet.get<lp::FragmentField>();
Block netPkt({frag.first, frag.second});
return {true, netPkt, packet};
ndn::Buffer::const_iterator fragBegin, fragEnd;
std::tie(fragBegin, fragEnd) = packet.get<lp::FragmentField>();
Block netPkt(&*fragBegin, std::distance(fragBegin, fragEnd));
return std::make_tuple(true, netPkt, packet);
}
// check Sequence and compute message identifier
if (!packet.has<lp::SequenceField>()) {
NFD_LOG_FACE_WARN("reassembly error, Sequence missing: DROP");
return {false, {}, {}};
return FALSE_RETURN;
}
lp::Sequence messageIdentifier = packet.get<lp::SequenceField>() - fragIndex;
Key key(remoteEndpoint, messageIdentifier);
Key key = std::make_tuple(remoteEndpoint, messageIdentifier);
// add to PartialPacket
PartialPacket& pp = m_partialPackets[key];
@@ -92,13 +93,13 @@ LpReassembler::receiveFragment(const EndpointId& remoteEndpoint, const lp::Packe
else {
if (fragCount != pp.fragCount) {
NFD_LOG_FACE_WARN("reassembly error, FragCount changed: DROP");
return {false, {}, {}};
return FALSE_RETURN;
}
}
if (pp.fragments[fragIndex].has<lp::SequenceField>()) {
NFD_LOG_FACE_TRACE("fragment already received: DROP");
return {false, {}, {}};
return FALSE_RETURN;
}
pp.fragments[fragIndex] = packet;
@@ -109,13 +110,13 @@ LpReassembler::receiveFragment(const EndpointId& remoteEndpoint, const lp::Packe
Block reassembled = doReassembly(key);
lp::Packet firstFrag(std::move(pp.fragments[0]));
m_partialPackets.erase(key);
return {true, reassembled, firstFrag};
return std::make_tuple(true, reassembled, firstFrag);
}
// set drop timer
pp.dropTimer = getScheduler().schedule(m_options.reassemblyTimeout, [=] { timeoutPartialPacket(key); });
return {false, {}, {}};
return FALSE_RETURN;
}
Block
@@ -125,17 +126,21 @@ LpReassembler::doReassembly(const Key& key)
size_t payloadSize = std::accumulate(pp.fragments.begin(), pp.fragments.end(), 0U,
[&] (size_t sum, const lp::Packet& pkt) -> size_t {
auto [fragBegin, fragEnd] = pkt.get<lp::FragmentField>();
ndn::Buffer::const_iterator fragBegin, fragEnd;
std::tie(fragBegin, fragEnd) = pkt.get<lp::FragmentField>();
return sum + std::distance(fragBegin, fragEnd);
});
ndn::Buffer fragBuffer(payloadSize);
auto it = fragBuffer.begin();
for (const lp::Packet& frag : pp.fragments) {
auto [fragBegin, fragEnd] = frag.get<lp::FragmentField>();
ndn::Buffer::const_iterator fragBegin, fragEnd;
std::tie(fragBegin, fragEnd) = frag.get<lp::FragmentField>();
it = std::copy(fragBegin, fragEnd, it);
}
return Block(fragBuffer);
return Block(&*(fragBuffer.cbegin()), std::distance(fragBuffer.cbegin(), fragBuffer.cend()));
}
void
@@ -162,4 +167,5 @@ operator<<(std::ostream& os, const FaceLogHelper<LpReassembler>& flh)
return os;
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+25 -28
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -29,28 +29,27 @@
#include "face-common.hpp"
#include <ndn-cxx/lp/packet.hpp>
#include <ndn-cxx/lp/sequence.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
/**
* \brief Reassembles fragmented network-layer packets.
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
/** \brief reassembles fragmented network-layer packets
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
*/
class LpReassembler : noncopyable
{
public:
/** \brief %Options that control the behavior of LpReassembler.
/** \brief Options that control the behavior of LpReassembler
*/
struct Options
{
/** \brief Maximum number of fragments in a packet.
/** \brief maximum number of fragments in a packet
*
* LpPackets with FragCount over this limit are dropped.
*/
size_t nMaxFragments = 400;
/** \brief Timeout before a partially reassembled packet is dropped.
/** \brief timeout before a partially reassembled packet is dropped
*/
time::nanoseconds reassemblyTimeout = 500_ms;
};
@@ -58,7 +57,7 @@ public:
explicit
LpReassembler(const Options& options, const LinkService* linkService = nullptr);
/** \brief Set options for reassembler.
/** \brief set options for reassembler
*/
void
setOptions(const Options& options);
@@ -70,7 +69,7 @@ public:
const LinkService*
getLinkService() const;
/** \brief Adds received fragment to the buffer.
/** \brief adds received fragment to the buffer
* \param remoteEndpoint endpoint that sent the packet
* \param packet received fragment; must have Fragment field
* \return a tuple containing:
@@ -80,26 +79,24 @@ public:
* \throw tlv::Error packet is malformed
*/
std::tuple<bool, Block, lp::Packet>
receiveFragment(const EndpointId& remoteEndpoint, const lp::Packet& packet);
receiveFragment(EndpointId remoteEndpoint, const lp::Packet& packet);
/** \brief Count of partial packets.
/** \brief count of partial packets
*/
size_t
size() const;
/**
* \brief Notifies before a partial packet is dropped due to timeout.
/** \brief signals before a partial packet is dropped due to timeout
*
* If a partial packet is incomplete and no new fragments are received within
* Options::reassemblyTimeout, the partial packet is dropped due to timeout.
* Before dropping the packet, this signal is emitted with the remote endpoint
* and the number of fragments being dropped.
* If a partial packet is incomplete and no new fragment is received
* within Options::reassemblyTimeout, it would be dropped due to timeout.
* Before it's erased, this signal is emitted with the remote endpoint,
* and the number of fragments being dropped.
*/
signal::Signal<LpReassembler, EndpointId, size_t> beforeTimeout;
private:
/**
* \brief Holds all fragments of a packet until reassembled.
/** \brief holds all fragments of packet until reassembled
*/
struct PartialPacket
{
@@ -109,13 +106,12 @@ private:
scheduler::ScopedEventId dropTimer;
};
/**
* \brief Index key for PartialPackets.
/** \brief index key for PartialPackets
*/
using Key = std::tuple<
EndpointId, // remote endpoint
lp::Sequence // message identifier (sequence number of the first fragment)
>;
typedef std::tuple<
EndpointId, // remoteEndpoint
lp::Sequence // message identifier (sequence of the first fragment)
> Key;
Block
doReassembly(const Key& key);
@@ -150,6 +146,7 @@ LpReassembler::size() const
return m_partialPackets.size();
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_LP_REASSEMBLER_HPP
+24 -16
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -24,13 +24,12 @@
*/
#include "lp-reliability.hpp"
#include "common/global.hpp"
#include "generic-link-service.hpp"
#include "transport.hpp"
#include "common/global.hpp"
#include <ndn-cxx/lp/fields.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
NFD_LOG_INIT(LpReliability);
@@ -81,7 +80,10 @@ LpReliability::handleOutgoing(std::vector<lp::Packet>& frags, lp::Packet&& pkt,
lp::Sequence txSeq = assignTxSequence(frag);
// Store LpPacket for future retransmissions
unackedFragsIt = m_unackedFrags.try_emplace(unackedFragsIt, txSeq, frag);
unackedFragsIt = m_unackedFrags.emplace_hint(unackedFragsIt,
std::piecewise_construct,
std::forward_as_tuple(txSeq),
std::forward_as_tuple(frag));
unackedFragsIt->second.sendTime = sendTime;
auto rto = m_rttEst.getEstimatedRto();
lp::Sequence seq = frag.get<lp::SequenceField>();
@@ -172,12 +174,12 @@ LpReliability::processIncomingPacket(const lp::Packet& pkt)
// Check for recent received Sequences to remove
auto now = time::steady_clock::now();
auto rto = m_rttEst.getEstimatedRto();
while (!m_recentRecvSeqsQueue.empty() &&
while (m_recentRecvSeqsQueue.size() > 0 &&
now > m_recentRecvSeqs[m_recentRecvSeqsQueue.front()] + rto) {
m_recentRecvSeqs.erase(m_recentRecvSeqsQueue.front());
m_recentRecvSeqsQueue.pop();
}
m_recentRecvSeqs.try_emplace(pktSequence, now);
m_recentRecvSeqs.emplace(pktSequence, now);
m_recentRecvSeqsQueue.push(pktSequence);
}
@@ -224,7 +226,7 @@ LpReliability::assignTxSequence(lp::Packet& frag)
{
lp::Sequence txSeq = ++m_lastTxSeqNo;
frag.set<lp::TxSequenceField>(txSeq);
if (!m_unackedFrags.empty() && m_lastTxSeqNo == m_firstUnackedFrag->first) {
if (m_unackedFrags.size() > 0 && m_lastTxSeqNo == m_firstUnackedFrag->first) {
NDN_THROW(std::length_error("TxSequence range exceeded"));
}
return m_lastTxSeqNo;
@@ -308,8 +310,10 @@ LpReliability::onLpPacketLost(lp::Sequence txSeq, bool isTimeout)
// Notify strategy of dropped Interest (if any)
if (netPkt->isInterest) {
BOOST_ASSERT(netPkt->pkt.has<lp::FragmentField>());
auto frag = netPkt->pkt.get<lp::FragmentField>();
onDroppedInterest(Interest(Block({frag.first, frag.second})));
ndn::Buffer::const_iterator fragBegin, fragEnd;
std::tie(fragBegin, fragEnd) = netPkt->pkt.get<lp::FragmentField>();
Block frag(&*fragBegin, std::distance(fragBegin, fragEnd));
onDroppedInterest(Interest(frag));
}
// Delete this LpPacket from m_unackedFrags
@@ -322,10 +326,13 @@ LpReliability::onLpPacketLost(lp::Sequence txSeq, bool isTimeout)
netPkt->didRetx = true;
// Move fragment to new TxSequence mapping
auto hint = m_firstUnackedFrag != m_unackedFrags.end() && m_firstUnackedFrag->first > newTxSeq
? m_firstUnackedFrag
: m_unackedFrags.end();
auto newTxFragIt = m_unackedFrags.try_emplace(hint, newTxSeq, txFrag.pkt);
auto newTxFragIt = m_unackedFrags.emplace_hint(
m_firstUnackedFrag != m_unackedFrags.end() && m_firstUnackedFrag->first > newTxSeq
? m_firstUnackedFrag
: m_unackedFrags.end(),
std::piecewise_construct,
std::forward_as_tuple(newTxSeq),
std::forward_as_tuple(txFrag.pkt));
auto& newTxFrag = newTxFragIt->second;
newTxFrag.retxCount = txFrag.retxCount + 1;
newTxFrag.netPkt = netPkt;
@@ -427,4 +434,5 @@ operator<<(std::ostream& os, const FaceLogHelper<LpReliability>& flh)
return os;
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+45 -42
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -34,49 +34,44 @@
#include <queue>
namespace nfd::face {
namespace nfd {
namespace face {
class GenericLinkService;
/**
* \brief Provides for reliable sending and receiving of link-layer packets.
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
/** \brief provides for reliable sending and receiving of link-layer packets
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
*/
class LpReliability : noncopyable
{
public:
/// TxSequence TLV-TYPE (3 octets) + TLV-LENGTH (1 octet) + lp::Sequence (8 octets)
static constexpr size_t RESERVED_HEADER_SPACE = tlv::sizeOfVarNumber(lp::tlv::TxSequence) +
tlv::sizeOfVarNumber(sizeof(lp::Sequence)) +
sizeof(lp::Sequence);
struct Options
{
/** \brief Enables link-layer reliability.
/** \brief enables link-layer reliability
*/
bool isEnabled = false;
/** \brief Maximum number of retransmissions for an LpPacket.
/** \brief maximum number of retransmissions for an LpPacket
*/
size_t maxRetx = 3;
/** \brief Period between sending pending Acks in an IDLE packet.
/** \brief period between sending pending Acks in an IDLE packet
*/
time::nanoseconds idleAckTimerPeriod = 5_ms;
/** \brief A fragment is considered lost if this number of fragments with greater sequence
* numbers are acknowledged.
/** \brief a fragment is considered lost if this number of fragments with greater sequence
* numbers are acknowledged
*/
size_t seqNumLossThreshold = 3;
};
LpReliability(const Options& options, GenericLinkService* linkService);
/** \brief Signals on Interest dropped by reliability system for exceeding allowed number of retx.
/** \brief signals on Interest dropped by reliability system for exceeding allowed number of retx
*/
signal::Signal<LpReliability, Interest> onDroppedInterest;
/** \brief Set options for reliability.
/** \brief set options for reliability
*/
void
setOptions(const Options& options);
@@ -88,7 +83,7 @@ public:
const GenericLinkService*
getLinkService() const;
/** \brief Observe outgoing fragment(s) of a network packet and store for potential retransmission.
/** \brief observe outgoing fragment(s) of a network packet and store for potential retransmission
* \param frags fragments of network packet
* \param pkt encapsulated network packet
* \param isInterest whether the network packet is an Interest
@@ -96,26 +91,27 @@ public:
void
handleOutgoing(std::vector<lp::Packet>& frags, lp::Packet&& pkt, bool isInterest);
/** \brief Extract and parse all Acks and add Ack for contained Fragment (if any) to AckQueue.
/** \brief extract and parse all Acks and add Ack for contained Fragment (if any) to AckQueue
* \param pkt incoming LpPacket
* \return whether incoming LpPacket is new and not a duplicate
*/
bool
processIncomingPacket(const lp::Packet& pkt);
/** \brief Called by GenericLinkService to attach Acks onto an outgoing LpPacket.
/** \brief called by GenericLinkService to attach Acks onto an outgoing LpPacket
* \param pkt outgoing LpPacket to attach Acks to
* \param mtu MTU of the transport
* \param mtu MTU of the Transport
*/
void
piggyback(lp::Packet& pkt, ssize_t mtu);
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
class UnackedFrag;
class NetPkt;
using UnackedFrags = std::map<lp::Sequence, UnackedFrag>;
/** \brief Assign TxSequence number to a fragment.
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/** \brief assign TxSequence number to a fragment
* \param frag fragment to assign TxSequence to
* \return assigned TxSequence number
* \throw std::length_error assigned TxSequence is equal to the start of the existing window
@@ -123,7 +119,7 @@ NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
lp::Sequence
assignTxSequence(lp::Packet& frag);
/** \brief Start the idle Ack timer.
/** \brief start the idle Ack timer
*
* This timer requests an IDLE packet to acknowledge pending fragments not already piggybacked.
* It is called regularly on a period configured in Options::idleAckTimerPeriod. This allows Acks
@@ -132,22 +128,22 @@ NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
startIdleAckTimer();
/** \brief Find and mark as lost fragments where a configurable number of Acks
* (Options::seqNumLossThreshold) have been received for greater TxSequence numbers.
/** \brief find and mark as lost fragments where a configurable number of Acks
* (\p m_options.seqNumLossThreshold) have been received for greater TxSequence numbers
* \param ackIt iterator pointing to acknowledged fragment
* \return vector containing TxSequences of fragments marked lost by this mechanism
*/
std::vector<lp::Sequence>
findLostLpPackets(UnackedFrags::iterator ackIt);
/** \brief Resend (or give up on) a lost fragment.
/** \brief resend (or give up on) a lost fragment
* \return vector of the TxSequences of fragments removed due to a network packet being removed
*/
std::vector<lp::Sequence>
onLpPacketLost(lp::Sequence txSeq, bool isTimeout);
/** \brief Remove the fragment with the given sequence number from the map of unacknowledged
* fragments, as well as its associated network packet (if any).
/** \brief remove the fragment with the given sequence number from the map of unacknowledged
* fragments, as well as its associated network packet (if any)
* \param fragIt iterator to acknowledged fragment
*
* If the given TxSequence marks the beginning of the send window, the window will be incremented.
@@ -156,7 +152,7 @@ NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
onLpPacketAcknowledged(UnackedFrags::iterator fragIt);
/** \brief Delete a fragment from UnackedFrags and advance acknowledge window if necessary.
/** \brief delete a fragment from UnackedFrags and advance acknowledge window if necessary
* \param fragIt iterator to an UnackedFrag, must be dereferencable
* \post fragIt is not in m_unackedFrags
* \post if was equal to m_firstUnackedFrag,
@@ -166,9 +162,8 @@ NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
deleteUnackedFrag(UnackedFrags::iterator fragIt);
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/**
* \brief Contains a sent fragment that has not been acknowledged and associated data.
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/** \brief contains a sent fragment that has not been acknowledged and associated data
*/
class UnackedFrag
{
@@ -179,14 +174,13 @@ NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
public:
lp::Packet pkt;
scheduler::ScopedEventId rtoTimer;
time::steady_clock::time_point sendTime;
time::steady_clock::TimePoint sendTime;
size_t retxCount;
size_t nGreaterSeqAcks; //!< number of Acks received for sequences greater than this fragment
shared_ptr<NetPkt> netPkt;
};
/**
* \brief Contains a network-layer packet with unacknowledged fragments.
/** \brief contains a network-layer packet with unacknowledged fragments
*/
class NetPkt
{
@@ -200,16 +194,24 @@ NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
bool didRetx;
};
public:
/// TxSequence TLV-TYPE (3 octets) + TLV-LENGTH (1 octet) + lp::Sequence (8 octets)
static constexpr size_t RESERVED_HEADER_SPACE = tlv::sizeOfVarNumber(lp::tlv::TxSequence) +
tlv::sizeOfVarNumber(sizeof(lp::Sequence)) +
sizeof(lp::Sequence);
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
Options m_options;
GenericLinkService* m_linkService;
UnackedFrags m_unackedFrags;
// An iterator that points to the first unacknowledged fragment in the current window. The window
// can wrap around so that the beginning of the window is at a TxSequence greater than other
// fragments in the window. When the window is moved past the last item in the iterator, the
// first fragment in the map will become the start of the window.
/** An iterator that points to the first unacknowledged fragment in the current window. The window
* can wrap around so that the beginning of the window is at a TxSequence greater than other
* fragments in the window. When the window is moved past the last item in the iterator, the
* first fragment in the map will become the start of the window.
*/
UnackedFrags::iterator m_firstUnackedFrag;
std::queue<lp::Sequence> m_ackQueue;
std::map<lp::Sequence, time::steady_clock::time_point> m_recentRecvSeqs;
std::map<lp::Sequence, time::steady_clock::TimePoint> m_recentRecvSeqs;
std::queue<lp::Sequence> m_recentRecvSeqsQueue;
lp::Sequence m_lastTxSeqNo;
scheduler::ScopedEventId m_idleAckTimer;
@@ -219,6 +221,7 @@ NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
std::ostream&
operator<<(std::ostream& os, const FaceLogHelper<LpReliability>& flh);
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_LP_RELIABILITY_HPP
+18 -14
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -27,9 +27,9 @@
#include "common/global.hpp"
#include <cerrno> // for errno
#include <cstdio> // for snprintf()
#include <cstring> // for memcpy(), strerror(), strncpy()
#include <net/if.h> // for struct ifreq
#include <stdio.h> // for snprintf()
#include <sys/ioctl.h> // for ioctl()
#if defined(__linux__)
@@ -43,7 +43,8 @@
#endif
#endif
namespace nfd::face {
namespace nfd {
namespace face {
NFD_LOG_INIT(MulticastEthernetTransport);
@@ -65,19 +66,20 @@ MulticastEthernetTransport::MulticastEthernetTransport(const ndn::net::NetworkIn
NFD_LOG_FACE_DEBUG("Creating transport");
char filter[110];
// Note: "not vlan" must appear last in the filter expression, or the
// rest of the filter won't work as intended (see pcap-filter(7))
std::snprintf(filter, sizeof(filter),
"(ether proto 0x%x) && (ether dst %s) && (not ether src %s) && (not vlan)",
ethernet::ETHERTYPE_NDN,
m_destAddress.toString().data(),
m_srcAddress.toString().data());
// note #1: we cannot use std::snprintf because it's not available
// on some platforms (see #2299)
// note #2: "not vlan" must appear last in the filter expression, or the
// rest of the filter won't work as intended (see pcap-filter(7))
snprintf(filter, sizeof(filter),
"(ether proto 0x%x) && (ether dst %s) && (not ether src %s) && (not vlan)",
ethernet::ETHERTYPE_NDN,
m_destAddress.toString().data(),
m_srcAddress.toString().data());
m_pcap.setPacketFilter(filter);
BOOST_ASSERT(m_destAddress.isMulticast());
if (!m_destAddress.isBroadcast()) {
if (!m_destAddress.isBroadcast())
joinMulticastGroup();
}
}
void
@@ -103,7 +105,8 @@ MulticastEthernetTransport::joinMulticastGroup()
#if defined(__APPLE__) || defined(__FreeBSD__)
// see bug #2327
boost::asio::ip::udp::socket sock(getGlobalIoService(), boost::asio::ip::udp::v4());
using boost::asio::ip::udp;
udp::socket sock(getGlobalIoService(), udp::v4());
int fd = sock.native_handle();
// Differences between Linux and the BSDs (including macOS):
@@ -144,4 +147,5 @@ MulticastEthernetTransport::joinMulticastGroup()
NDN_THROW(Error("Failed to join multicast group"));
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+8 -6
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,16 +28,17 @@
#include "ethernet-transport.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
/**
* @brief A multicast Transport that uses raw Ethernet II frames.
* @brief A multicast Transport that uses raw Ethernet II frames
*/
class MulticastEthernetTransport final : public EthernetTransport
{
public:
/**
* @brief Creates an Ethernet-based transport for multicast communication.
* @brief Creates an Ethernet-based transport for multicast communication
*/
MulticastEthernetTransport(const ndn::net::NetworkInterface& localEndpoint,
const ethernet::Address& mcastAddress,
@@ -45,7 +46,7 @@ public:
private:
/**
* @brief Enables receiving frames addressed to our MAC multicast group.
* @brief Enables receiving frames addressed to our MAC multicast group
*/
void
joinMulticastGroup();
@@ -56,6 +57,7 @@ private:
#endif
};
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_MULTICAST_ETHERNET_TRANSPORT_HPP
+54 -30
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -29,8 +29,7 @@
#include "common/privilege-helper.hpp"
#include <boost/asio/ip/multicast.hpp>
#include <boost/asio/ip/v6_only.hpp>
#include <boost/functional/hash.hpp>
#ifdef __linux__
#include <cerrno> // for errno
@@ -38,15 +37,14 @@
#include <sys/socket.h> // for setsockopt()
#endif // __linux__
namespace nfd::face {
namespace nfd {
namespace face {
namespace ip = boost::asio::ip;
NFD_LOG_MEMBER_INIT_SPECIALIZED((DatagramTransport<boost::asio::ip::udp, Multicast>), MulticastUdpTransport);
NFD_LOG_MEMBER_INIT_SPECIALIZED((DatagramTransport<ip::udp, Multicast>), MulticastUdpTransport);
MulticastUdpTransport::MulticastUdpTransport(const ip::udp::endpoint& multicastGroup,
ip::udp::socket&& recvSocket,
ip::udp::socket&& sendSocket,
MulticastUdpTransport::MulticastUdpTransport(const protocol::endpoint& multicastGroup,
protocol::socket&& recvSocket,
protocol::socket&& sendSocket,
ndn::nfd::LinkType linkType)
: DatagramTransport(std::move(recvSocket))
, m_multicastGroup(multicastGroup)
@@ -59,7 +57,7 @@ MulticastUdpTransport::MulticastUdpTransport(const ip::udp::endpoint& multicastG
this->setLinkType(linkType);
this->setMtu(udp::computeMtu(m_sendSocket.local_endpoint()));
boost::asio::socket_base::send_buffer_size sendBufferSizeOption;
protocol::socket::send_buffer_size sendBufferSizeOption;
boost::system::error_code error;
m_sendSocket.get_option(sendBufferSizeOption);
if (error) {
@@ -133,26 +131,34 @@ bindToDevice(int fd, const std::string& ifname)
}
void
MulticastUdpTransport::openRxSocket(ip::udp::socket& sock,
const ip::udp::endpoint& multicastGroup,
const ip::address& localAddress,
const ndn::net::NetworkInterface* netif)
MulticastUdpTransport::openRxSocket(protocol::socket& sock,
const protocol::endpoint& multicastGroup,
const boost::asio::ip::address& localAddress,
const shared_ptr<const ndn::net::NetworkInterface>& netif)
{
BOOST_ASSERT(!sock.is_open());
sock.open(multicastGroup.protocol());
sock.set_option(boost::asio::socket_base::reuse_address(true));
sock.set_option(protocol::socket::reuse_address(true));
if (multicastGroup.address().is_v4()) {
BOOST_ASSERT(localAddress.is_v4());
sock.bind(multicastGroup);
sock.set_option(ip::multicast::join_group(multicastGroup.address().to_v4(), localAddress.to_v4()));
sock.set_option(boost::asio::ip::multicast::join_group(multicastGroup.address().to_v4(),
localAddress.to_v4()));
}
else {
BOOST_ASSERT(multicastGroup.address().to_v6().scope_id() != 0);
sock.set_option(ip::v6_only(true));
sock.bind(multicastGroup);
sock.set_option(ip::multicast::join_group(multicastGroup.address().to_v6()));
BOOST_ASSERT(localAddress.is_v6());
sock.set_option(boost::asio::ip::v6_only(true));
#ifdef WITH_TESTS
// To simplify unit tests, we bind to the "any" IPv6 address if the supplied multicast
// address lacks a scope id. Calling bind() without a scope id would otherwise fail.
if (multicastGroup.address().to_v6().scope_id() == 0)
sock.bind(protocol::endpoint(boost::asio::ip::address_v6::any(), multicastGroup.port()));
else
#endif
sock.bind(multicastGroup);
sock.set_option(boost::asio::ip::multicast::join_group(multicastGroup.address().to_v6()));
}
if (netif)
@@ -160,28 +166,46 @@ MulticastUdpTransport::openRxSocket(ip::udp::socket& sock,
}
void
MulticastUdpTransport::openTxSocket(ip::udp::socket& sock,
const ip::udp::endpoint& localEndpoint,
const ndn::net::NetworkInterface* netif,
MulticastUdpTransport::openTxSocket(protocol::socket& sock,
const protocol::endpoint& localEndpoint,
const shared_ptr<const ndn::net::NetworkInterface>& netif,
bool enableLoopback)
{
BOOST_ASSERT(!sock.is_open());
sock.open(localEndpoint.protocol());
sock.set_option(boost::asio::socket_base::reuse_address(true));
sock.set_option(ip::multicast::enable_loopback(enableLoopback));
sock.set_option(protocol::socket::reuse_address(true));
sock.set_option(boost::asio::ip::multicast::enable_loopback(enableLoopback));
if (localEndpoint.address().is_v4()) {
sock.bind(localEndpoint);
if (!localEndpoint.address().is_unspecified())
sock.set_option(ip::multicast::outbound_interface(localEndpoint.address().to_v4()));
sock.set_option(boost::asio::ip::multicast::outbound_interface(localEndpoint.address().to_v4()));
}
else {
sock.set_option(ip::v6_only(true));
sock.set_option(boost::asio::ip::v6_only(true));
sock.bind(localEndpoint);
if (netif)
sock.set_option(ip::multicast::outbound_interface(netif->getIndex()));
sock.set_option(boost::asio::ip::multicast::outbound_interface(netif->getIndex()));
}
}
} // namespace nfd::face
template<>
EndpointId
DatagramTransport<boost::asio::ip::udp, Multicast>::makeEndpointId(const protocol::endpoint& ep)
{
if (ep.address().is_v4()) {
return (static_cast<uint64_t>(ep.port()) << 32) |
static_cast<uint64_t>(ep.address().to_v4().to_ulong());
}
else {
size_t seed = 0;
const auto& addrBytes = ep.address().to_v6().to_bytes();
boost::hash_range(seed, addrBytes.begin(), addrBytes.end());
boost::hash_combine(seed, ep.port());
return seed;
}
}
} // namespace face
} // namespace nfd
+27 -24
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -28,15 +28,23 @@
#include "datagram-transport.hpp"
#include <boost/asio/ip/udp.hpp>
#include <ndn-cxx/net/network-interface.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
NFD_LOG_MEMBER_DECL_SPECIALIZED((DatagramTransport<boost::asio::ip::udp, Multicast>));
// Explicit specialization of makeEndpointId for the UDP multicast case.
// Note that this "shall be declared before the first use of the specialization
// that would cause an implicit instantiation to take place, in every translation
// unit in which such a use occurs".
template<>
EndpointId
DatagramTransport<boost::asio::ip::udp, Multicast>::makeEndpointId(const protocol::endpoint& ep);
/**
* \brief A Transport that communicates on a UDP multicast group.
* \brief A Transport that communicates on a UDP multicast group
*/
class MulticastUdpTransport final : public DatagramTransport<boost::asio::ip::udp, Multicast>
{
@@ -48,36 +56,30 @@ public:
};
/**
* \brief Creates a UDP-based transport for multicast communication.
* \brief Creates a UDP-based transport for multicast communication
* \param multicastGroup multicast group
* \param recvSocket socket used to receive multicast packets
* \param sendSocket socket used to send to the multicast group
* \param linkType either `ndn::nfd::LINK_TYPE_MULTI_ACCESS` or `ndn::nfd::LINK_TYPE_AD_HOC`
*/
MulticastUdpTransport(const boost::asio::ip::udp::endpoint& multicastGroup,
boost::asio::ip::udp::socket&& recvSocket,
boost::asio::ip::udp::socket&& sendSocket,
MulticastUdpTransport(const protocol::endpoint& multicastGroup,
protocol::socket&& recvSocket,
protocol::socket&& sendSocket,
ndn::nfd::LinkType linkType);
ssize_t
getSendQueueLength() final;
/**
* \brief Opens and configures the receive-side socket.
*/
static void
openRxSocket(boost::asio::ip::udp::socket& sock,
const boost::asio::ip::udp::endpoint& multicastGroup,
const boost::asio::ip::address& localAddress = {},
const ndn::net::NetworkInterface* netif = nullptr);
openRxSocket(protocol::socket& sock,
const protocol::endpoint& multicastGroup,
const boost::asio::ip::address& localAddress,
const shared_ptr<const ndn::net::NetworkInterface>& netif = nullptr);
/**
* \brief Opens and configures the transmit-side socket.
*/
static void
openTxSocket(boost::asio::ip::udp::socket& sock,
const boost::asio::ip::udp::endpoint& localEndpoint,
const ndn::net::NetworkInterface* netif = nullptr,
openTxSocket(protocol::socket& sock,
const protocol::endpoint& localEndpoint,
const shared_ptr<const ndn::net::NetworkInterface>& netif = nullptr,
bool enableLoopback = false);
private:
@@ -88,10 +90,11 @@ private:
doClose() final;
private:
boost::asio::ip::udp::endpoint m_multicastGroup;
boost::asio::ip::udp::socket m_sendSocket;
protocol::endpoint m_multicastGroup;
protocol::socket m_sendSocket;
};
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_MULTICAST_UDP_TRANSPORT_HPP
+11 -5
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -27,7 +27,8 @@
#include "face-system.hpp"
#include "common/logger.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
NFD_LOG_INIT(NetdevBound);
@@ -45,7 +46,9 @@ NetdevBound::processConfig(OptionalConfigSection configSection,
std::vector<Rule> rules;
if (configSection) {
int ruleIndex = 0;
for (const auto& [key, value] : *configSection) {
for (const auto& pair : *configSection) {
const std::string& key = pair.first;
const ConfigSection& value = pair.second;
if (key == "rule") {
rules.push_back(parseRule(ruleIndex++, value));
}
@@ -91,7 +94,9 @@ NetdevBound::parseRule(int index, const ConfigSection& confRule) const
bool hasWhitelist = false;
bool hasBlacklist = false;
for (const auto& [key, value] : confRule) {
for (const auto& pair : confRule) {
const std::string& key = pair.first;
const ConfigSection& value = pair.second;
if (key == "remote") {
try {
rule.remotes.emplace_back(value.get_value<std::string>());
@@ -140,4 +145,5 @@ NetdevBound::parseRule(int index, const ConfigSection& confRule) const
return rule;
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+9 -8
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -26,14 +26,14 @@
#ifndef NFD_DAEMON_FACE_NETDEV_BOUND_HPP
#define NFD_DAEMON_FACE_NETDEV_BOUND_HPP
#include "network-predicate.hpp"
#include "protocol-factory.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
class FaceSystem;
/** \brief Manages netdev-bound faces.
/** \brief manages netdev-bound faces
*/
class NetdevBound : noncopyable
{
@@ -55,13 +55,13 @@ public:
NetdevBound(const ProtocolFactoryCtorParams& params, const FaceSystem& faceSystem);
/** \brief Process `face_system.netdev_bound` config section.
/** \brief process face_system.netdev_bound config section
*/
void
processConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context);
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
struct Rule
{
std::vector<FaceUri> remotes;
@@ -71,7 +71,7 @@ NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
Rule
parseRule(int index, const ConfigSection& confRule) const;
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
const FaceSystem& m_faceSystem;
FaceCreatedCallback m_addFace;
shared_ptr<ndn::net::NetworkMonitor> m_netmon;
@@ -82,6 +82,7 @@ NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
std::map<Key, shared_ptr<Face>> m_faces;
};
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_NETDEV_BOUND_HPP
+18 -13
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -29,15 +29,16 @@
#include <fnmatch.h>
#include <boost/lexical_cast.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
NetworkPredicateBase::NetworkPredicateBase()
{
this->clear();
}
NetworkPredicateBase::~NetworkPredicateBase() = default;
void
NetworkPredicateBase::clear()
{
@@ -161,6 +162,13 @@ IpAddressPredicate::isRuleValid(const std::string& key, const std::string& value
}
}
bool
NetworkPredicateBase::operator==(const NetworkPredicateBase& other) const
{
return this->m_whitelist == other.m_whitelist &&
this->m_blacklist == other.m_blacklist;
}
static bool
doesMatchPattern(const std::string& ifname, const std::string& pattern)
{
@@ -190,10 +198,8 @@ doesNetifMatchRule(const ndn::net::NetworkInterface& netif, const std::string& r
bool
NetworkInterfacePredicate::operator()(const ndn::net::NetworkInterface& netif) const
{
return std::any_of(m_whitelist.begin(), m_whitelist.end(),
[&netif] (const auto& rule) { return doesNetifMatchRule(netif, rule); }) &&
std::none_of(m_blacklist.begin(), m_blacklist.end(),
[&netif] (const auto& rule) { return doesNetifMatchRule(netif, rule); });
return std::any_of(m_whitelist.begin(), m_whitelist.end(), bind(&doesNetifMatchRule, std::cref(netif), _1)) &&
std::none_of(m_blacklist.begin(), m_blacklist.end(), bind(&doesNetifMatchRule, std::cref(netif), _1));
}
static bool
@@ -213,10 +219,9 @@ doesAddressMatchRule(const boost::asio::ip::address& address, const std::string&
bool
IpAddressPredicate::operator()(const boost::asio::ip::address& address) const
{
return std::any_of(m_whitelist.begin(), m_whitelist.end(),
[&address] (const auto& rule) { return doesAddressMatchRule(address, rule); }) &&
std::none_of(m_blacklist.begin(), m_blacklist.end(),
[&address] (const auto& rule) { return doesAddressMatchRule(address, rule); });
return std::any_of(m_whitelist.begin(), m_whitelist.end(), bind(&doesAddressMatchRule, std::cref(address), _1)) &&
std::none_of(m_blacklist.begin(), m_blacklist.end(), bind(&doesAddressMatchRule, std::cref(address), _1));
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+20 -36
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -28,20 +28,21 @@
#include "core/common.hpp"
#include <boost/operators.hpp>
#include <boost/property_tree/ptree_fwd.hpp>
#include <ndn-cxx/net/network-interface.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
class NetworkPredicateBase : private boost::equality_comparable<NetworkPredicateBase>
class NetworkPredicateBase
{
public:
NetworkPredicateBase();
virtual
~NetworkPredicateBase();
/**
* \brief Set the whitelist to "*" and clear the blacklist.
* \brief Set the whitelist to "*" and clear the blacklist
*/
void
clear();
@@ -56,24 +57,14 @@ public:
assign(std::initializer_list<std::pair<std::string, std::string>> whitelist,
std::initializer_list<std::pair<std::string, std::string>> blacklist);
protected:
// Explicitly declare the following four special member functions
// to avoid -Wdeprecated-copy-with-dtor warnings from clang.
bool
operator==(const NetworkPredicateBase& other) const;
NetworkPredicateBase(const NetworkPredicateBase&) = delete;
NetworkPredicateBase(NetworkPredicateBase&&) = default;
NetworkPredicateBase&
operator=(const NetworkPredicateBase&) = delete;
NetworkPredicateBase&
operator=(NetworkPredicateBase&&) = default;
// NetworkPredicateBase is not supposed to be used polymorphically, so we make the destructor
// protected to prevent deletion of derived objects through a pointer to the base class,
// which would be UB when the destructor is non-virtual.
~NetworkPredicateBase() = default;
bool
operator!=(const NetworkPredicateBase& other) const
{
return !this->operator==(other);
}
private:
virtual bool
@@ -88,15 +79,7 @@ private:
void
parseList(std::set<std::string>& set, std::initializer_list<std::pair<std::string, std::string>> list);
private: // non-member operators (hidden friends)
friend bool
operator==(const NetworkPredicateBase& lhs, const NetworkPredicateBase& rhs)
{
return lhs.m_whitelist == rhs.m_whitelist &&
lhs.m_blacklist == rhs.m_blacklist;
}
NFD_PUBLIC_WITH_TESTS_ELSE_PROTECTED:
PUBLIC_WITH_TESTS_ELSE_PROTECTED:
std::set<std::string> m_whitelist;
std::set<std::string> m_blacklist;
};
@@ -111,7 +94,7 @@ NFD_PUBLIC_WITH_TESTS_ELSE_PROTECTED:
* ndn::net::NetworkInterface is accepted if it matches any entry in the whitelist and none of
* the entries in the blacklist.
*/
class NetworkInterfacePredicate final : public NetworkPredicateBase
class NetworkInterfacePredicate : public NetworkPredicateBase
{
public:
bool
@@ -133,7 +116,7 @@ private:
* 2001:db8:2::/64`) or a wildcard (`*`) that matches all IP addresses. An IP address is
* accepted if it matches any entry in the whitelist and none of the entries in the blacklist.
*/
class IpAddressPredicate final : public NetworkPredicateBase
class IpAddressPredicate : public NetworkPredicateBase
{
public:
bool
@@ -147,6 +130,7 @@ private:
isRuleValid(const std::string& key, const std::string& value) final;
};
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_NETWORK_PREDICATE_HPP
+5 -3
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -27,7 +27,8 @@
#include "null-link-service.hpp"
#include "null-transport.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
shared_ptr<Face>
makeNullFace(const FaceUri& uri)
@@ -38,4 +39,5 @@ makeNullFace(const FaceUri& uri)
make_unique<NullTransport>(uri, uri, ndn::nfd::FACE_SCOPE_LOCAL));
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+7 -6
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, Regents of the University of California,
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,14 +28,15 @@
#include "face.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
/**
* \brief Returns a Face that has no underlying transport and drops every packet.
/** \return a Face that has no underlying transport and drops every packet
*/
shared_ptr<Face>
makeNullFace(const FaceUri& uri = FaceUri("null://"));
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_NULL_FACE_HPP
+5 -3
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -28,7 +28,8 @@
#include "link-service.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
/** \brief A LinkService that drops every packet.
*/
@@ -56,6 +57,7 @@ private:
}
};
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_NULL_LINK_SERVICE_HPP
+5 -3
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, Regents of the University of California,
* Copyright (c) 2014-2019, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -25,7 +25,8 @@
#include "null-transport.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
NFD_LOG_INIT(NullTransport);
@@ -42,4 +43,5 @@ NullTransport::NullTransport(const FaceUri& localUri, const FaceUri& remoteUri,
NFD_LOG_FACE_DEBUG("Creating transport");
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+8 -6
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -28,11 +28,12 @@
#include "transport.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
/** \brief A Transport that drops every packet.
*/
class NullTransport NFD_FINAL_UNLESS_WITH_TESTS : public Transport
class NullTransport FINAL_UNLESS_WITH_TESTS : public Transport
{
public:
explicit
@@ -43,18 +44,19 @@ public:
protected:
void
doClose() NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL
doClose() OVERRIDE_WITH_TESTS_ELSE_FINAL
{
setState(TransportState::CLOSED);
}
private:
void
doSend(const Block&) NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL
doSend(const Block&) OVERRIDE_WITH_TESTS_ELSE_FINAL
{
}
};
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_NULL_TRANSPORT_HPP
+17 -22
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -26,8 +26,6 @@
#include "pcap-helper.hpp"
#include "ethernet-protocol.hpp"
#include "common/privilege-helper.hpp"
#include <pcap/pcap.h>
#include <unistd.h>
@@ -35,9 +33,11 @@
#define PCAP_NETMASK_UNKNOWN 0xffffffff
#endif
namespace nfd::face {
namespace nfd {
namespace face {
PcapHelper::PcapHelper(const std::string& interfaceName)
: m_pcap(nullptr)
{
char errbuf[PCAP_ERRBUF_SIZE] = {};
m_pcap = pcap_create(interfaceName.data(), errbuf);
@@ -55,7 +55,7 @@ PcapHelper::PcapHelper(const std::string& interfaceName)
pcap_set_buffer_size(m_pcap, 4 * 1024 * 1024);
}
PcapHelper::~PcapHelper() noexcept
PcapHelper::~PcapHelper()
{
close();
}
@@ -63,15 +63,9 @@ PcapHelper::~PcapHelper() noexcept
void
PcapHelper::activate(int dlt)
{
PrivilegeHelper::runElevated([this] {
int ret = pcap_activate(m_pcap);
if (ret < 0)
NDN_THROW(Error("pcap_activate: " + std::string(pcap_statustostr(ret))));
});
char errbuf[PCAP_ERRBUF_SIZE] = {};
if (pcap_setnonblock(m_pcap, 1, errbuf) < 0)
NDN_THROW(Error("pcap_setnonblock: " + std::string(errbuf)));
int ret = pcap_activate(m_pcap);
if (ret < 0)
NDN_THROW(Error("pcap_activate: " + std::string(pcap_statustostr(ret))));
if (pcap_set_datalink(m_pcap, dlt) < 0)
NDN_THROW(Error("pcap_set_datalink: " + getLastError()));
@@ -81,7 +75,7 @@ PcapHelper::activate(int dlt)
}
void
PcapHelper::close() noexcept
PcapHelper::close()
{
if (m_pcap) {
pcap_close(m_pcap);
@@ -102,7 +96,7 @@ PcapHelper::getFd() const
}
std::string
PcapHelper::getLastError() const noexcept
PcapHelper::getLastError() const
{
return pcap_geterr(m_pcap);
}
@@ -130,19 +124,20 @@ PcapHelper::setPacketFilter(const char* filter) const
NDN_THROW(Error("pcap_setfilter: " + getLastError()));
}
std::tuple<span<const uint8_t>, std::string>
PcapHelper::readNextPacket() const noexcept
std::tuple<const uint8_t*, size_t, std::string>
PcapHelper::readNextPacket() const
{
pcap_pkthdr* header;
const uint8_t* packet;
int ret = pcap_next_ex(m_pcap, &header, &packet);
if (ret < 0)
return {span<uint8_t>{}, getLastError()};
return std::make_tuple(nullptr, 0, getLastError());
else if (ret == 0)
return {span<uint8_t>{}, "Nothing to read"};
return std::make_tuple(nullptr, 0, "timed out");
else
return {{packet, header->caplen}, ""};
return std::make_tuple(packet, header->caplen, "");
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+25 -18
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, Regents of the University of California,
/**
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,7 +28,7 @@
#include "core/common.hpp"
#ifndef NFD_HAVE_LIBPCAP
#ifndef HAVE_LIBPCAP
#error "Cannot include this file when libpcap is not available"
#endif
@@ -36,7 +36,8 @@
struct pcap;
typedef pcap pcap_t;
namespace nfd::face {
namespace nfd {
namespace face {
/**
* @brief Helper class for dealing with libpcap handles.
@@ -47,7 +48,11 @@ public:
class Error : public std::runtime_error
{
public:
using std::runtime_error::runtime_error;
explicit
Error(const std::string& what)
: std::runtime_error(what)
{
}
};
/**
@@ -58,7 +63,7 @@ public:
explicit
PcapHelper(const std::string& interfaceName);
~PcapHelper() noexcept;
~PcapHelper();
/**
* @brief Start capturing packets.
@@ -74,7 +79,7 @@ public:
* @sa pcap_close(3pcap)
*/
void
close() noexcept;
close();
/**
* @brief Obtain a file descriptor that can be used in calls such as select(2) and poll(2).
@@ -93,7 +98,7 @@ public:
* @sa pcap_geterr(3pcap)
*/
std::string
getLastError() const noexcept;
getLastError() const;
/**
* @brief Get the number of packets dropped by the kernel, as reported by libpcap.
@@ -115,25 +120,27 @@ public:
/**
* @brief Read the next packet captured on the interface.
* @return If successful, returns a tuple containing a read-only view of the received
* packet bytes (including the link-layer header) and a second element that
* must be ignored. On failure, returns a tuple containing an empty span and
* the reason for the failure.
* @warning The returned span is valid only until the next call to this function.
* @return If successful, returns a tuple containing a pointer to the received packet
* (including the link-layer header) and the size of the packet; the third
* element must be ignored. On failure, returns a tuple containing nullptr,
* 0, and the reason for the failure.
* @warning The returned pointer must not be freed by the caller, and is valid only
* until the next call to this function.
* @sa pcap_next_ex(3pcap)
*/
std::tuple<span<const uint8_t>, std::string>
readNextPacket() const noexcept;
std::tuple<const uint8_t*, size_t, std::string>
readNextPacket() const;
operator pcap_t*() const noexcept
operator pcap_t*() const
{
return m_pcap;
}
private:
pcap_t* m_pcap = nullptr;
pcap_t* m_pcap;
};
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_PCAP_HELPER_HPP
+5 -3
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -28,7 +28,8 @@
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/copy.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
ProtocolFactory::Registry&
ProtocolFactory::getRegistry()
@@ -128,4 +129,5 @@ ProtocolFactory::doGetChannels() const
return {};
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+31 -41
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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,
@@ -33,16 +33,15 @@
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/copy.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
/**
* \brief Parameters to ProtocolFactory constructor.
/** \brief Parameters to ProtocolFactory constructor
*
* Every ProtocolFactory subclass is expected to have a constructor that accepts
* ProtocolFactory::CtorParams, which in turn passes it to ProtocolFactory base class
* constructor. Parameters are passed as a struct rather than individually, so that
* any future changes in the list of parameters will not require updates to all subclass
* constructors.
* Every ProtocolFactory subclass is expected to have a constructor that accepts CtorParams,
* which in turn passes it to ProtocolFactory base class constructor. Parameters are passed as a
* struct rather than individually, so that a future change in list of parameters does not
* require updates to subclass constructors.
*/
struct ProtocolFactoryCtorParams
{
@@ -50,52 +49,44 @@ struct ProtocolFactoryCtorParams
shared_ptr<ndn::net::NetworkMonitor> netmon;
};
/**
* \brief Provides support for an underlying protocol.
/** \brief Provides support for an underlying protocol
* \sa FaceSystem
*
* A protocol factory provides support for an underlying protocol and owns Channel objects.
* It can process a subsection of the `face_system` configuration section and create channels
* and multicast faces accordingly.
*
* \sa FaceSystem
* A protocol factory provides support for an underlying protocol and owns Channel objects.
* It can process a subsection of face_system config section and create channels and multicast
* faces accordingly.
*/
class ProtocolFactory : noncopyable
{
public: // registry
using CtorParams = ProtocolFactoryCtorParams;
/**
* \brief Register a protocol factory type.
* \tparam PF subclass of ProtocolFactory
* \param id factory identifier
/** \brief Register a protocol factory type
* \tparam PF subclass of ProtocolFactory
* \param id factory identifier
*/
template<typename PF>
static void
registerType(const std::string& id = PF::getId())
{
BOOST_ASSERT(!id.empty());
auto r = getRegistry().insert_or_assign(id, [] (auto&&... p) {
return make_unique<PF>(std::forward<decltype(p)>(p)...);
});
BOOST_VERIFY(r.second);
Registry& registry = getRegistry();
BOOST_ASSERT(registry.count(id) == 0);
registry[id] = [] (const CtorParams& p) { return make_unique<PF>(p); };
}
/**
* \brief Create a protocol factory instance.
* \retval nullptr if a factory with the given \p id is not registered
/** \brief Create a protocol factory instance
* \retval nullptr if a factory with the given \p id is not registered
*/
static unique_ptr<ProtocolFactory>
create(const std::string& id, const CtorParams& params);
/**
* \brief Get all registered protocol factory IDs.
/** \brief Get all registered protocol factory ids
*/
[[nodiscard]] static std::set<std::string>
static std::set<std::string>
listRegistered();
public:
/**
* \brief Base class for all exceptions thrown by ProtocolFactory subclasses.
/** \brief Base class for all exceptions thrown by ProtocolFactory subclasses
*/
class Error : public std::runtime_error
{
@@ -110,20 +101,18 @@ public:
~ProtocolFactory() = 0;
#ifdef DOXYGEN
/**
* \brief Get the ID of this protocol factory.
/** \brief Get id for this protocol factory
*
* `face_system.<factory-id>` config section is processed by the protocol factory.
* face_system.factory-id config section is processed by the protocol factory.
*/
static const std::string&
getId() noexcept;
#endif
/**
* \brief Get FaceUri schemes accepted by this protocol factory.
/** \brief Get FaceUri schemes accepted by this protocol factory
*/
const std::set<std::string>&
getProvidedSchemes() const noexcept
getProvidedSchemes() const
{
return providedSchemes;
}
@@ -144,7 +133,7 @@ public:
struct CreateFaceRequest
{
FaceUri remoteUri;
std::optional<FaceUri> localUri;
optional<FaceUri> localUri;
FaceParams params;
};
@@ -257,7 +246,8 @@ protected:
shared_ptr<ndn::net::NetworkMonitor> netmon;
};
} // namespace nfd::face
} // namespace face
} // namespace nfd
/** \brief Registers a protocol factory
*
+35 -6
View File
@@ -1,7 +1,6 @@
#include "queues.hpp"
#include "common/global.hpp"
#include <ndn-cxx/encoding/estimator.hpp>
namespace nfd
{
namespace face
@@ -44,7 +43,7 @@ namespace nfd
{
this->needRateLimit = true;
this->tokenBucket = std::make_shared<TokenBucket>(rateLimit, 20 * 1000 * 8, name);
this->tokenBucket->start();
// this->tokenBucket->start();
}
else
{
@@ -60,7 +59,6 @@ namespace nfd
std::string key = interest.getName().getPrefix(1).toUri();
if (this->virtualQueues.count(key) == 0)
{
this->virtualQueues[key] = std::make_shared<VirtualQueue>(1, this->vqSize);
this->virtualQueues[key]->tos = this->tos;
this->flows.push_back(key);
@@ -155,13 +153,18 @@ namespace nfd
{
return currentRate;
}
// if (currentRate > 0) {
// std::cout << "currentRate: " << currentRate << ", " << this->recvBits << "," << this->calObjectRateInterval << ", AvaliableBandwidth: " << this->availableBandwidth << std::endl;
// }
bool hasCleanFlow = false;
for (auto it = this->virtualQueues.begin(); it != this->virtualQueues.end();)
{
// std::cout << "key: " << it->first << ", recvBits" << it->second->recvBits << std::endl;
if (it->second->recvBits == 0 && it->second->empty())
{
this->totalWeight -= it->second->weight;
this->virtualQueues.erase(it++); // here is the key
// std::cout << "do clean: " << std::endl;
hasCleanFlow = true;
}
else
@@ -209,6 +212,9 @@ namespace nfd
consumeRate += item.second->currentFlowRate;
}
NFD_LOG_DEBUG(this->name << " => currentRate: " << item.second->currentFlowRate << ", consumerRate: " << consumeRate << ", objectRate: " << item.second->objectRate << ", availableBandwidth" << this->availableBandwidth << ", weight: " << item.second->weight << ", totalWeight: " << this->totalWeight << ", currentSendRate: " << currentSendRate);
// std::cout << this->name << " => currentRate: " << item.second->currentFlowRate << ", consumerRate: " << consumeRate << ", objectRate: " << item.second->objectRate <<
// ", availableBandwidth" << this->availableBandwidth << ", weight: " << item.second->weight << ", totalWeight: " <<
// this->totalWeight << ", currentSendRate: " << currentSendRate << std::endl;
item.second->recvBits = 0;
}
@@ -224,6 +230,8 @@ namespace nfd
item.second->objectRate += (remainRate * item.second->weight / totalHightSpeedFlowWeight);
}
NFD_LOG_DEBUG(this->name << " => objectRate: " << item.second->objectRate << ", remainRate: " << remainRate << ", item.weight: " << item.second->weight << ", totalWeight: " << totalHightSpeedFlowWeight);
// std::cout << this->name << " => objectRate: " << item.second->objectRate << ", remainRate: " <<
// remainRate << ", item.weight: " << item.second->weight << ", totalWeight: " << totalHightSpeedFlowWeight << std::endl;
}
}
@@ -238,6 +246,7 @@ namespace nfd
}
if (item.second->gredyTimes == item.second->gredyThreshold)
{
// std::cout << item.first << ": PenaltyFactor => " << item.second->gredyTimes << ", currentFlowRate: " << item.second->currentFlowRate << ", objectRate: " << item.second->objectRate << std::endl;
item.second->penaltyFactor = 0.5;
item.second->size = 20;
}
@@ -250,6 +259,10 @@ namespace nfd
}
}
}
// if (this->virtualQueues.size() > 0)
// {
// std::cout << "\n\n=====================: " << this->availableBandwidth << std::endl;
// }
for (auto &item : this->virtualQueues)
{
if (item.second->penaltyFactor > 0.99)
@@ -257,7 +270,15 @@ namespace nfd
auto rate = this->calDiscountFactor(item.second->currentSize * 1.0 / item.second->size);
item.second->objectRate *= rate;
}
// std::cout << item.first << ", currentFlowRate: " << item.second->currentFlowRate
// << ", objectRate: " << item.second->objectRate << ", size: " << item.second->currentSize
// << ", weight: " << item.second->weight << ", penaltyFactor: " << item.second->penaltyFactor
// << std::endl;
}
// if (this->virtualQueues.size() > 0)
// {
// std::cout << "\n----------------------" << std::endl;
// }
this->sendBits = 0;
this->recvBits = 0;
return currentRate;
@@ -370,10 +391,13 @@ namespace nfd
int remain = this->availableBandwidth - totalRate;
if (hightSppedFlowNum > 0)
{
// std::cout << "high speed flow num: " << hightSppedFlowNum << ", totalHightSpeedFlowWeight: " << totalHightSpeedFlowWeight << std::endl;
for (auto &queue : this->queues)
{
if (queue->getRemainBandwidthRate(queue->originAvaliableBandwidth) < 0.2)
{
// std::cout << "!!!" << queue->getWeight() * remain * 1.0 / totalHightSpeedFlowWeight +
// queue->originAvaliableBandwidth << std::endl;
queue->updateAvailableBandwidth(
queue->getWeight() * remain * 1.0 / totalHightSpeedFlowWeight +
queue->originAvaliableBandwidth);
@@ -386,6 +410,7 @@ namespace nfd
}
else
{
// std::cout << "has flow queue num: " << hasFlowQueueNum << ", totalHasFlowQueueWeight: " << totalHasFlowQueueWeight << std::endl;
for (auto &queue : this->queues)
{
if (queue->getRemainBandwidthRate(queue->originAvaliableBandwidth) < 0.95)
@@ -465,6 +490,7 @@ namespace nfd
{
serviceClass = (*interest.getServiceClass()) % 8;
}
// std::cout << "appendInterest => serviceClass: " << serviceClass << std::endl;
return this->getQueueByTos(serviceClass)->appendInterest(interest);
}
void GlobalSP::receiveInterest(const Interest &interest)
@@ -472,18 +498,20 @@ namespace nfd
ndn::encoding::EncodingEstimator estimator;
auto size = interest.wireEncode(estimator) + 9;
this->interestBytes += size;
// std::cout << this << "receiveInterest => size: " << size << ", interestBytes: " << this->interestBytes << std::endl;
}
void GlobalSP::calObjectRate(bool getCurrentRateOnly)
{
getScheduler().schedule(time::nanoseconds(1000000 * this->calObjectRateInterval),
[this]
{ this->calObjectRate(false); });
// getScheduler().schedule(time::nanoseconds(1000000 * this->calObjectRateInterval),
// [this] { this->calObjectRate(false); });
uint32_t remain = this->availableBandwidth;
remain -= this->interestBytes * 8000 / this->calObjectRateInterval;
this->interestBytes = 0;
remain -= this->delaySensitiveServiceSp.calObjectRate(false);
// std::cout << "AvaliableBandwidth: " << this->availableBandwidth << ", remain: " << remain << ", interestBytes" << this->interestBytes << std::endl;
this->wfqQueue.calObjectRate(remain);
}
void GlobalSP::assignObjectRate(const Data &data)
@@ -494,6 +522,7 @@ namespace nfd
{
serviceClass = (*data.getServiceClass()) % 8;
}
// std::cout << "assignObjectRate => serviceClass: " << serviceClass << std::endl;
auto objectRate = this->getQueueByTos(serviceClass)->getObjectRateByFlowKey(key);
auto targetRate = data.getTargetRate();
if (!targetRate || *targetRate > objectRate)
+112 -141
View File
@@ -3,109 +3,87 @@
#include <deque>
#include <unordered_map>
#include <memory>
#include <iostream>
#include "common/global.hpp"
#include "link-service.hpp"
#include <ndn-cxx/lp/tags.hpp>
#include "TokenBucket.hpp"
#include <iostream>
namespace nfd
{
namespace face
{
namespace nfd {
namespace face {
class VirtualQueue;
struct VirtualQueueItem
{
struct VirtualQueueItem {
int seq;
std::shared_ptr<const Interest> item;
EndpointId endpointId;
uint32_t dataSize;
uint32_t waitNsTime;
std::shared_ptr<VirtualQueue> queue;
};
class VirtualQueue : public std::enable_shared_from_this<VirtualQueue>
{
class VirtualQueue : public std::enable_shared_from_this<VirtualQueue>{
public:
explicit VirtualQueue(double weight, int size) : std::enable_shared_from_this<VirtualQueue>(),
penaltyFactor(1.0),
weight(weight), size(size), currentSize(0), lastSeq(0),
C(0)
{
explicit VirtualQueue(double weight, int size) :
std::enable_shared_from_this<VirtualQueue>(),
penaltyFactor(1.0),
weight(weight), size(size), currentSize(0), lastSeq(0),
C(0) {
}
void enableTokenBucket(uint32_t limitRate)
{
void enableTokenBucket(uint32_t limitRate) {
this->C = limitRate;
}
bool push(int seq, const std::shared_ptr<const Interest> &interest, const EndpointId &endpointId,
bool push(int seq, const std::shared_ptr<const Interest>& interest,
uint64_t dataSize, bool needInsert);
bool empty()
{
bool empty() {
return this->innerQueue.empty();
}
uint32_t frontSeq()
{
if (this->innerQueue.empty())
{
uint32_t frontSeq() {
if (this->innerQueue.empty()) {
return this->lastSeq;
}
return this->innerQueue.front().seq;
}
VirtualQueueItem front()
{
VirtualQueueItem front() {
return this->innerQueue.front();
}
uint32_t backSeq()
{
uint32_t backSeq() {
return this->lastSeq;
}
VirtualQueueItem back()
{
VirtualQueueItem back() {
return this->innerQueue.back();
}
void pop()
{
if (this->currentSize <= 0)
{
void pop() {
if (this->currentSize <= 0) {
return;
}
this->currentSize--;
this->innerQueue.pop_front();
}
void popBack()
{
if (this->currentSize <= 0)
{
void popBack() {
if (this->currentSize <= 0) {
return;
}
this->currentSize--;
this->innerQueue.pop_back();
}
int len()
{
int len() {
return this->innerQueue.size();
}
void setLastSeq(uint32_t seq)
{
void setLastSeq(uint32_t seq) {
this->lastSeq = seq;
}
uint32_t getLastSeq()
{
uint32_t getLastSeq() {
return lastSeq;
}
void setWeight(double weight)
{
void setWeight(double weight) {
this->weight = weight;
}
double getWeight()
{
double getWeight() {
return this->weight;
}
public:
uint32_t objectRate;
double penaltyFactor = 1.0;
uint32_t gredyTimes = 0;
double gredyRatio = 1.2;
double gredyThreshold = 5;
double gredyThreshold = 10;
double weight = 1.0;
uint32_t tos = 5;
double balance = 0;
@@ -114,89 +92,81 @@ namespace nfd
uint32_t recvBits = 0;
uint32_t currentFlowRate = 0;
double currentRatio = 0.0;
private:
uint32_t lastSeq;
int C;
std::deque<VirtualQueueItem> innerQueue;
};
class WDRRQueue
{
class WDRRQueue {
public:
explicit WDRRQueue(uint32_t rateLimit, uint32_t availableBandwidth, double weight, const std::string &name,
uint32_t tos = 5, size_t vqSize = 20);
explicit WDRRQueue(uint32_t rateLimit, uint32_t availableBandwidth, double weight, const std::string& name,
uint32_t tos = 5, size_t vqSize = 20);
void updateAvailableBandwidth(uint32_t C);
bool appendInterest(const Interest &interest, const EndpointId &endpointId);
bool appendInterest(const Interest &interest);
std::shared_ptr<VirtualQueueItem> scheduleNext();
uint32_t calObjectRate(bool getCurrentRateOnly);
void setCDTLimit(int cdt)
{
void setCDTLimit(int cdt) {
this->cdt = cdt;
}
uint32_t scheduleOnePacketForWFQ(uint32_t totalLastSeq);
std::shared_ptr<VirtualQueueItem> frontForWFQ(uint32_t totalLastSeq)
{
if (this->cachePacketForWFQ == nullptr)
{
std::shared_ptr<VirtualQueueItem> frontForWFQ(uint32_t totalLastSeq) {
if (this->cachePacketForWFQ == nullptr) {
this->scheduleOnePacketForWFQ(totalLastSeq);
}
return this->cachePacketForWFQ;
}
void popForWFQ()
{
void popForWFQ() {
this->cachePacketForWFQ = nullptr;
}
double getRemainBandwidthRate(double curAvailableBandWidth)
{
double getRemainBandwidthRate(double curAvailableBandWidth) {
auto currentRate = this->calObjectRate(true);
if (currentRate > curAvailableBandWidth)
{
if (currentRate > curAvailableBandWidth) {
return 0;
}
return (curAvailableBandWidth - currentRate) * 1.0 / curAvailableBandWidth;
}
uint32_t getRemainBandwidth()
{
uint32_t getRemainBandwidth() {
return this->availableBandwidth - this->calObjectRate(true);
}
double getWeight()
{
double getWeight() {
return this->weight;
}
uint32_t getAvailableBandwidth()
{
uint32_t getAvailableBandwidth() {
return this->availableBandwidth;
}
/**
* @brief
*
* @brief
*
* \sigma=\frac{1}{3}\arccot\funcapply(8\delta-4)
* @param x
* @return double
* @param x
* @return double
*/
double calDiscountFactor(double x)
{
double calDiscountFactor(double x) {
return 1.0 / 3 * (M_PI / 2 - atan(8 * x - 4)) + 0.034;
}
/**
* @brief Get the Object Rate By Flow Key object
*
* @param key
* @return uint32_t
*
* @param key
* @return uint32_t
*/
uint32_t getObjectRateByFlowKey(const std::string &key)
{
if (this->virtualQueues.count(key) == 0)
{
std::cout << "FUCK: " << key << ", count: " << this->virtualQueues.size() << ", flow: " << this->flows.size() << "availbleRate: " << this->availableBandwidth << std::endl;
uint32_t getObjectRateByFlowKey(const std::string& key) {
if (this->virtualQueues.count(key) == 0) {
std::cout << "FUCK: " << key << ", count: " << this->virtualQueues.size() <<
", flow: " << this->flows.size() << "availbleRate: " << this->availableBandwidth << std::endl;
return 0;
}
return this->virtualQueues[key]->objectRate;
}
void triggerByCurrentTime(long currentTime) {
if (this->needRateLimit) {
this->tokenBucket->generateTokenByCurrentTime(currentTime);
}
}
public:
double originAvaliableBandwidth = 0;
private:
std::unordered_map<std::string, std::shared_ptr<VirtualQueue>> virtualQueues;
std::vector<std::string> flows;
@@ -219,81 +189,72 @@ namespace nfd
int64_t lastSeq = -1;
std::shared_ptr<VirtualQueueItem> cachePacketForWFQ = nullptr;
};
class DelaySensitiveServiceSP
{
class DelaySensitiveServiceSP {
public:
explicit DelaySensitiveServiceSP(uint32_t availableBandwidth, size_t vqSize = 20)
{
this->CS7Queue = std::make_shared<WDRRQueue>((uint32_t)(0.2 * availableBandwidth), (uint32_t)(0.2 * availableBandwidth), 2, "CS7", 2, vqSize);
this->CS6Queue = std::make_shared<WDRRQueue>((uint32_t)(0.2 * availableBandwidth), (uint32_t)(0.2 * availableBandwidth), 2, "CS6", 1, vqSize);
this->EFQueue = std::make_shared<WDRRQueue>((uint32_t)(0.3 * availableBandwidth), (uint32_t)(0.3 * availableBandwidth), 3, "EF", 0, vqSize);
explicit DelaySensitiveServiceSP(uint32_t availableBandwidth, size_t vqSize = 20) {
this->CS7Queue = std::make_shared<WDRRQueue>((uint32_t) (0.2 * availableBandwidth), (uint32_t) (0.2 * availableBandwidth), 2, "CS7", 2, vqSize);
this->CS6Queue = std::make_shared<WDRRQueue>((uint32_t) (0.2 * availableBandwidth), (uint32_t) (0.2 * availableBandwidth), 2, "CS6", 1, vqSize);
this->EFQueue = std::make_shared<WDRRQueue>((uint32_t) (0.3 * availableBandwidth), (uint32_t) (0.3 * availableBandwidth), 3, "EF", 0, vqSize);
}
std::shared_ptr<VirtualQueueItem> scheduleNext();
uint32_t calObjectRate(bool getCurrentRateOnly);
std::shared_ptr<WDRRQueue> getCS7Queue()
{
std::shared_ptr<WDRRQueue> getCS7Queue() {
return this->CS7Queue;
}
std::shared_ptr<WDRRQueue> getCS6Queue()
{
std::shared_ptr<WDRRQueue> getCS6Queue() {
return this->CS6Queue;
}
std::shared_ptr<WDRRQueue> getEFQueue()
{
std::shared_ptr<WDRRQueue> getEFQueue() {
return this->EFQueue;
}
void triggerByCurrentTime(long currentTime) {
this->CS7Queue->triggerByCurrentTime(currentTime);
this->CS6Queue->triggerByCurrentTime(currentTime);
this->EFQueue->triggerByCurrentTime(currentTime);
}
private:
std::shared_ptr<WDRRQueue> CS7Queue;
std::shared_ptr<WDRRQueue> CS6Queue;
std::shared_ptr<WDRRQueue> EFQueue;
};
class WFQQueue
{
class WFQQueue {
public:
explicit WFQQueue(uint32_t availableBandwidth, size_t vqSize) : AF4Weight(5),
AF3Weight(4),
AF2Weight(3),
AF1Weight(2),
BEWeight(1),
totalWeight(AF4Weight + AF3Weight + AF2Weight + AF1Weight + BEWeight),
queues(5),
lastSeq(0),
availableBandwidth(availableBandwidth)
{
explicit WFQQueue(uint32_t availableBandwidth, size_t vqSize) :
AF4Weight(5),
AF3Weight(4),
AF2Weight(3),
AF1Weight(2),
BEWeight(1),
totalWeight(AF4Weight + AF3Weight + AF2Weight + AF1Weight + BEWeight),
queues(5),
lastSeq(0),
availableBandwidth(availableBandwidth) {
this->queues[0] = std::make_shared<WDRRQueue>(0, availableBandwidth * AF4Weight / totalWeight, 5, "AF4", 3, vqSize);
this->queues[1] = std::make_shared<WDRRQueue>(0, availableBandwidth * AF3Weight / totalWeight, 4, "AF3", 4, vqSize);
this->queues[2] = std::make_shared<WDRRQueue>(0, availableBandwidth * AF2Weight / totalWeight, 3, "AF2", 5, vqSize);
this->queues[3] = std::make_shared<WDRRQueue>(0, availableBandwidth * AF1Weight / totalWeight, 2, "AF1", 6, vqSize);
this->queues[4] = std::make_shared<WDRRQueue>(0, availableBandwidth * BEWeight / totalWeight, 1, "BE", 7, vqSize);
for (auto &queue : this->queues)
{
for (auto &queue: this->queues) {
queue->setCDTLimit(this->cdt);
}
}
std::shared_ptr<VirtualQueueItem> scheduleNext();
uint32_t calObjectRate(uint32_t availableBandwidth);
std::shared_ptr<WDRRQueue> getAF4Queue()
{
std::shared_ptr<WDRRQueue> getAF4Queue() {
return this->queues[0];
}
std::shared_ptr<WDRRQueue> getAF3Queue()
{
std::shared_ptr<WDRRQueue> getAF3Queue() {
return this->queues[1];
}
std::shared_ptr<WDRRQueue> getAF2Queue()
{
std::shared_ptr<WDRRQueue> getAF2Queue() {
return this->queues[2];
}
std::shared_ptr<WDRRQueue> getAF1Queue()
{
std::shared_ptr<WDRRQueue> getAF1Queue() {
return this->queues[3];
}
std::shared_ptr<WDRRQueue> getBEQueue()
{
std::shared_ptr<WDRRQueue> getBEQueue() {
return this->queues[4];
}
private:
double AF4Weight = 5;
double AF3Weight = 4;
@@ -307,32 +268,42 @@ namespace nfd
int cdt = 200;
int hql;
};
class GlobalSP
{
class GlobalSP {
public:
explicit GlobalSP(uint32_t availableBandwidth, size_t vqSize = 20) : delaySensitiveServiceSp(availableBandwidth, vqSize),
wfqQueue(availableBandwidth, vqSize),
availableBandwidth(availableBandwidth)
{
getScheduler().schedule(time::nanoseconds(1000000 * this->calObjectRateInterval),
[this]
{ this->calObjectRate(false); });
explicit GlobalSP(uint32_t availableBandwidth, size_t vqSize = 20) :
delaySensitiveServiceSp(availableBandwidth, vqSize),
wfqQueue(availableBandwidth, vqSize),
availableBandwidth(availableBandwidth) {
lastTriggerTime = getCurrentTime();
// getScheduler().schedule(time::nanoseconds(1000000 * this->calObjectRateInterval),
// [this] { this->calObjectRate(false); });
}
std::shared_ptr<VirtualQueueItem> scheduleNext();
bool appendInterest(const Interest &interest, const EndpointId &endpointId);
bool appendInterest(const Interest &interest);
void receiveInterest(const Interest &interest);
void calObjectRate(bool getCurrentRateOnly);
std::shared_ptr<WDRRQueue> getQueueByTos(int tosValue);
long getCurrentTime() {
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count();
}
void triggerCalObjectRate() {
auto currentTime = getCurrentTime();
this->delaySensitiveServiceSp.triggerByCurrentTime(currentTime);
if (currentTime - lastTriggerTime > calObjectRateInterval) {
this->calObjectRate(false);
lastTriggerTime = currentTime;
}
}
void assignObjectRate(const Data &data);
private:
DelaySensitiveServiceSP delaySensitiveServiceSp;
WFQQueue wfqQueue;
int calObjectRateInterval = 100;
uint32_t availableBandwidth;
size_t interestBytes = 0;
long lastTriggerTime = 0;
};
}
}
#endif // NS_QUEUES_HPP
#endif //NS_QUEUES_HPP
+5 -3
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, Regents of the University of California,
* Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -33,7 +33,8 @@
#include <sys/socket.h>
#endif
namespace nfd::face {
namespace nfd {
namespace face {
ssize_t
getTxQueueLength(int fd)
@@ -52,4 +53,5 @@ getTxQueueLength(int fd)
return queueLength;
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+6 -4
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, Regents of the University of California,
* Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,9 +28,10 @@
#include "core/common.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
/** \brief Obtain send queue length from a specified system socket.
/** \brief obtain send queue length from a specified system socket
* \param fd file descriptor of the socket
* \retval QUEUE_UNSUPPORTED this operation is unsupported on the current platform
* \retval QUEUE_ERROR there was an error retrieving the send queue length
@@ -41,6 +42,7 @@ namespace nfd::face {
ssize_t
getTxQueueLength(int fd);
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_SOCKET_UTILS_HPP
+15 -19
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -32,26 +32,22 @@
#include <queue>
#include <boost/asio/defer.hpp>
#include <boost/asio/write.hpp>
namespace nfd {
namespace face {
namespace nfd::face {
/**
* \brief Implements a Transport for stream-based protocols.
/** \brief Implements Transport for stream-based protocols.
*
* \tparam Protocol a stream-based protocol in Boost.Asio
* \tparam Protocol a stream-based protocol in Boost.Asio
*/
template<class Protocol>
class StreamTransport : public Transport
{
public:
using protocol = Protocol;
typedef Protocol protocol;
/**
* \brief Construct stream transport.
/** \brief Construct stream transport.
*
* \param socket Protocol-specific socket for the created transport
* \param socket Protocol-specific socket for the created transport
*/
explicit
StreamTransport(typename protocol::socket&& socket);
@@ -147,12 +143,12 @@ StreamTransport<T>::doClose()
// Use the non-throwing variants and ignore errors, if any.
boost::system::error_code error;
m_socket.cancel(error);
m_socket.shutdown(boost::asio::socket_base::shutdown_both, error);
m_socket.shutdown(protocol::socket::shutdown_both, error);
}
// Ensure that the Transport stays alive at least until
// all pending handlers are dispatched
boost::asio::defer(getGlobalIoService(), [this] { deferredClose(); });
getGlobalIoService().post([this] { deferredClose(); });
// Some bug or feature of Boost.Asio (see https://redmine.named-data.net/issues/1856):
//
@@ -248,17 +244,16 @@ StreamTransport<T>::handleReceive(const boost::system::error_code& error,
NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes");
m_receiveBufferSize += nBytesReceived;
auto bufferView = ndn::make_span(m_receiveBuffer, m_receiveBufferSize);
size_t offset = 0;
bool isOk = true;
while (offset < bufferView.size()) {
while (m_receiveBufferSize - offset > 0) {
Block element;
std::tie(isOk, element) = Block::fromBuffer(bufferView.subspan(offset));
std::tie(isOk, element) = Block::fromBuffer(m_receiveBuffer + offset, m_receiveBufferSize - offset);
if (!isOk)
break;
offset += element.size();
BOOST_ASSERT(offset <= bufferView.size());
BOOST_ASSERT(offset <= m_receiveBufferSize);
this->receive(element);
}
@@ -337,6 +332,7 @@ StreamTransport<T>::getSendQueueBytes() const
return m_sendQueueBytes;
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_STREAM_TRANSPORT_HPP
+40 -39
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -29,19 +29,19 @@
#include "tcp-transport.hpp"
#include "common/global.hpp"
#include <boost/asio/ip/v6_only.hpp>
namespace nfd::face {
namespace ip = boost::asio::ip;
namespace nfd {
namespace face {
NFD_LOG_INIT(TcpChannel);
namespace ip = boost::asio::ip;
TcpChannel::TcpChannel(const tcp::Endpoint& localEndpoint, bool wantCongestionMarking,
DetermineFaceScopeFromAddress determineFaceScope)
: m_localEndpoint(localEndpoint)
, m_wantCongestionMarking(wantCongestionMarking)
, m_acceptor(getGlobalIoService())
, m_socket(getGlobalIoService())
, m_wantCongestionMarking(wantCongestionMarking)
, m_determineFaceScope(std::move(determineFaceScope))
{
setUri(FaceUri(m_localEndpoint));
@@ -51,7 +51,7 @@ TcpChannel::TcpChannel(const tcp::Endpoint& localEndpoint, bool wantCongestionMa
void
TcpChannel::listen(const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onAcceptFailed,
int backlog)
int backlog/* = tcp::acceptor::max_connections*/)
{
if (isListening()) {
NFD_LOG_CHAN_WARN("Already listening");
@@ -59,7 +59,7 @@ TcpChannel::listen(const FaceCreatedCallback& onFaceCreated,
}
m_acceptor.open(m_localEndpoint.protocol());
m_acceptor.set_option(boost::asio::socket_base::reuse_address(true));
m_acceptor.set_option(ip::tcp::acceptor::reuse_address(true));
if (m_localEndpoint.address().is_v6()) {
m_acceptor.set_option(ip::v6_only(true));
}
@@ -98,19 +98,10 @@ TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
void
TcpChannel::createFace(ip::tcp::socket&& socket,
const FaceParams& params,
const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onFaceCreationFailed)
const FaceCreatedCallback& onFaceCreated)
{
shared_ptr<Face> face;
boost::system::error_code ec;
tcp::Endpoint remoteEndpoint = socket.remote_endpoint(ec);
if (ec) {
NFD_LOG_CHAN_DEBUG("Retrieve socket remote endpoint failed: " << ec.message());
if (onFaceCreationFailed) {
onFaceCreationFailed(500, "Retrieve socket remote endpoint failed: " + ec.message());
}
return;
}
tcp::Endpoint remoteEndpoint = socket.remote_endpoint();
auto it = m_channelFaces.find(remoteEndpoint);
if (it == m_channelFaces.end()) {
@@ -132,13 +123,16 @@ TcpChannel::createFace(ip::tcp::socket&& socket,
if (params.defaultCongestionThreshold) {
options.defaultCongestionThreshold = *params.defaultCongestionThreshold;
}
if (params.bandwidth) {
options.C = *params.bandwidth;
}
auto linkService = make_unique<GenericLinkService>(options);
auto faceScope = m_determineFaceScope(socket.local_endpoint().address(),
socket.remote_endpoint().address());
auto transport = make_unique<TcpTransport>(std::move(socket), params.persistency, faceScope);
face = make_shared<Face>(std::move(linkService), std::move(transport));
face->setChannel(weak_from_this());
face->setChannel(shared_from_this()); // use weak_from_this() in C++17
m_channelFaces[remoteEndpoint] = face;
connectFaceClosedSignal(*face, [this, remoteEndpoint] { m_channelFaces.erase(remoteEndpoint); });
@@ -149,7 +143,7 @@ TcpChannel::createFace(ip::tcp::socket&& socket,
NFD_LOG_CHAN_TRACE("Reusing existing face for " << remoteEndpoint);
boost::system::error_code error;
socket.shutdown(boost::asio::socket_base::shutdown_both, error);
socket.shutdown(ip::tcp::socket::shutdown_both, error);
socket.close(error);
}
@@ -162,25 +156,31 @@ void
TcpChannel::accept(const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onAcceptFailed)
{
m_acceptor.async_accept([=] (const boost::system::error_code& error, ip::tcp::socket socket) {
if (error) {
if (error != boost::asio::error::operation_aborted) {
NFD_LOG_CHAN_DEBUG("Accept failed: " << error.message());
if (onAcceptFailed)
onAcceptFailed(500, "Accept failed: " + error.message());
}
return;
m_acceptor.async_accept(m_socket, [=] (const auto& e) { this->handleAccept(e, onFaceCreated, onAcceptFailed); });
}
void
TcpChannel::handleAccept(const boost::system::error_code& error,
const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onAcceptFailed)
{
if (error) {
if (error != boost::asio::error::operation_aborted) {
NFD_LOG_CHAN_DEBUG("Accept failed: " << error.message());
if (onAcceptFailed)
onAcceptFailed(500, "Accept failed: " + error.message());
}
return;
}
NFD_LOG_CHAN_TRACE("Incoming connection from " << socket.remote_endpoint());
NFD_LOG_CHAN_TRACE("Incoming connection from " << m_socket.remote_endpoint());
FaceParams params;
params.persistency = ndn::nfd::FACE_PERSISTENCY_ON_DEMAND;
createFace(std::move(socket), params, onFaceCreated, onAcceptFailed);
FaceParams params;
params.persistency = ndn::nfd::FACE_PERSISTENCY_ON_DEMAND;
createFace(std::move(m_socket), params, onFaceCreated);
// prepare accepting the next connection
accept(onFaceCreated, onAcceptFailed);
});
// prepare accepting the next connection
accept(onFaceCreated, onAcceptFailed);
}
void
@@ -204,7 +204,7 @@ TcpChannel::handleConnect(const boost::system::error_code& error,
}
NFD_LOG_CHAN_TRACE("Connected to " << socket->remote_endpoint());
createFace(std::move(*socket), params, onFaceCreated, onConnectFailed);
createFace(std::move(*socket), params, onFaceCreated);
}
void
@@ -222,4 +222,5 @@ TcpChannel::handleConnectTimeout(const tcp::Endpoint& remoteEndpoint,
onConnectFailed(504, "Connection timed out");
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+29 -22
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -28,50 +28,51 @@
#include "channel.hpp"
#include <boost/asio/ip/tcp.hpp>
namespace nfd {
namespace nfd::tcp {
using Endpoint = boost::asio::ip::tcp::endpoint;
} // namespace nfd::tcp
namespace tcp {
typedef boost::asio::ip::tcp::endpoint Endpoint;
} // namespace tcp
namespace nfd::face {
namespace face {
using DetermineFaceScopeFromAddress = std::function<ndn::nfd::FaceScope(const boost::asio::ip::address& local,
const boost::asio::ip::address& remote)>;
/**
* \brief Class implementing a TCP-based channel to create faces.
* \brief Class implementing TCP-based channel to create faces
*
* The channel can create faces as a response to incoming TCP connections (TcpChannel::listen()
* needs to be called for that to work) or explicitly by using TcpChannel::connect().
* Channel can create faces as a response to incoming TCP
* connections (TcpChannel::listen needs to be called for that
* to work) or explicitly after using TcpChannel::connect method.
*/
class TcpChannel final : public Channel
class TcpChannel : public Channel
{
public:
/**
* \brief Create a TCP channel for the specified \p localEndpoint.
* \brief Create TCP channel for the local endpoint
*
* To enable the creation of faces upon incoming connections, one needs to
* explicitly call listen().
* To enable creation faces upon incoming connections,
* one needs to explicitly call TcpChannel::listen method.
*/
TcpChannel(const tcp::Endpoint& localEndpoint, bool wantCongestionMarking,
DetermineFaceScopeFromAddress determineFaceScope);
bool
isListening() const final
isListening() const override
{
return m_acceptor.is_open();
}
size_t
size() const final
size() const override
{
return m_channelFaces.size();
}
/**
* \brief Enable listening on the local endpoint, accept connections,
* and create faces when remote host makes a connection.
* and create faces when remote host makes a connection
* \param onFaceCreated Callback to notify successful creation of the face
* \param onAcceptFailed Callback to notify when channel fails (accept call
* returns an error)
@@ -81,10 +82,10 @@ public:
void
listen(const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onAcceptFailed,
int backlog = boost::asio::socket_base::max_listen_connections);
int backlog = boost::asio::ip::tcp::acceptor::max_connections);
/**
* \brief Create a face by establishing a TCP connection to \p remoteEndpoint.
* \brief Create a face by establishing a TCP connection to \p remoteEndpoint
*/
void
connect(const tcp::Endpoint& remoteEndpoint,
@@ -97,13 +98,17 @@ private:
void
createFace(boost::asio::ip::tcp::socket&& socket,
const FaceParams& params,
const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onFaceCreationFailed);
const FaceCreatedCallback& onFaceCreated);
void
accept(const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onAcceptFailed);
void
handleAccept(const boost::system::error_code& error,
const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onAcceptFailed);
void
handleConnect(const boost::system::error_code& error,
const tcp::Endpoint& remoteEndpoint,
@@ -120,12 +125,14 @@ private:
private:
const tcp::Endpoint m_localEndpoint;
const bool m_wantCongestionMarking;
boost::asio::ip::tcp::acceptor m_acceptor;
boost::asio::ip::tcp::socket m_socket;
std::map<tcp::Endpoint, shared_ptr<Face>> m_channelFaces;
bool m_wantCongestionMarking;
DetermineFaceScopeFromAddress m_determineFaceScope;
};
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_TCP_CHANNEL_HPP
+14 -15
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, Regents of the University of California,
* Copyright (c) 2014-2019, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -25,9 +25,8 @@
#include "tcp-factory.hpp"
#include <boost/lexical_cast.hpp>
namespace nfd::face {
namespace nfd {
namespace face {
namespace ip = boost::asio::ip;
@@ -152,31 +151,31 @@ TcpFactory::doCreateFace(const CreateFaceRequest& req,
const FaceCreationFailedCallback& onFailure)
{
if (req.localUri) {
NFD_LOG_TRACE("createFace: unsupported LocalUri");
NFD_LOG_TRACE("Cannot create unicast TCP face with LocalUri");
onFailure(406, "Unicast TCP faces cannot be created with a LocalUri");
return;
}
if (req.params.persistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
NFD_LOG_TRACE("createFace: unsupported FacePersistency");
NFD_LOG_TRACE("createFace does not support FACE_PERSISTENCY_ON_DEMAND");
onFailure(406, "Outgoing TCP faces do not support on-demand persistency");
return;
}
tcp::Endpoint endpoint(ip::make_address(req.remoteUri.getHost()),
tcp::Endpoint endpoint(ip::address::from_string(req.remoteUri.getHost()),
boost::lexical_cast<uint16_t>(req.remoteUri.getPort()));
// a canonical tcp4/tcp6 FaceUri cannot have a multicast address
BOOST_ASSERT(!endpoint.address().is_multicast());
if (req.params.wantLocalFields && !endpoint.address().is_loopback()) {
NFD_LOG_TRACE("createFace: cannot create non-local face with local fields enabled");
NFD_LOG_TRACE("createFace cannot create non-local face with local fields enabled");
onFailure(406, "Local fields can only be enabled on faces with local scope");
return;
}
if (req.params.mtu) {
NFD_LOG_TRACE("createFace: cannot create TCP face with overridden MTU");
NFD_LOG_TRACE("createFace cannot create a TCP face with an overridden MTU");
onFailure(406, "TCP faces do not support MTU overrides");
return;
}
@@ -201,9 +200,8 @@ TcpFactory::createChannel(const tcp::Endpoint& endpoint)
if (it != m_channels.end())
return it->second;
auto channel = make_shared<TcpChannel>(endpoint, m_wantCongestionMarking, [this] (auto&&... args) {
return determineFaceScopeFromAddresses(std::forward<decltype(args)>(args)...);
});
auto channel = make_shared<TcpChannel>(endpoint, m_wantCongestionMarking,
bind(&TcpFactory::determineFaceScopeFromAddresses, this, _1, _2));
m_channels[endpoint] = channel;
return channel;
}
@@ -215,8 +213,8 @@ TcpFactory::doGetChannels() const
}
ndn::nfd::FaceScope
TcpFactory::determineFaceScopeFromAddresses(const ip::address& localAddress,
const ip::address& remoteAddress) const
TcpFactory::determineFaceScopeFromAddresses(const boost::asio::ip::address& localAddress,
const boost::asio::ip::address& remoteAddress) const
{
if (m_local(localAddress) && m_local(remoteAddress)) {
return ndn::nfd::FACE_SCOPE_LOCAL;
@@ -224,4 +222,5 @@ TcpFactory::determineFaceScopeFromAddresses(const ip::address& localAddress,
return ndn::nfd::FACE_SCOPE_NON_LOCAL;
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
+16 -14
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, Regents of the University of California,
* Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,15 +27,14 @@
#define NFD_DAEMON_FACE_TCP_FACTORY_HPP
#include "protocol-factory.hpp"
#include "network-predicate.hpp"
#include "tcp-channel.hpp"
namespace nfd::face {
namespace nfd {
namespace face {
/**
* \brief Protocol factory for TCP over IPv4 and IPv6.
/** \brief Protocol factory for TCP over IPv4 and IPv6
*/
class TcpFactory final : public ProtocolFactory
class TcpFactory : public ProtocolFactory
{
public:
static const std::string&
@@ -44,31 +43,33 @@ public:
using ProtocolFactory::ProtocolFactory;
/**
* \brief Create TCP-based channel using tcp::Endpoint.
* \brief Create TCP-based channel using tcp::Endpoint
*
* tcp::Endpoint is an alias for boost::asio::ip::tcp::endpoint.
* tcp::Endpoint is really an alias for boost::asio::ip::tcp::endpoint.
*
* If this method is called twice with the same endpoint, only one channel
* will be created. The second call will just return the existing channel.
*
* \return Always a valid pointer to a TcpChannel object, an exception
* \return always a valid pointer to a TcpChannel object, an exception
* is thrown if it cannot be created.
*/
shared_ptr<TcpChannel>
createChannel(const tcp::Endpoint& localEndpoint);
private:
/** \brief process face_system.tcp config section
*/
void
doProcessConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context) final;
FaceSystem::ConfigContext& context) override;
void
doCreateFace(const CreateFaceRequest& req,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onFailure) final;
const FaceCreationFailedCallback& onFailure) override;
std::vector<shared_ptr<const Channel>>
doGetChannels() const final;
doGetChannels() const override;
ndn::nfd::FaceScope
determineFaceScopeFromAddresses(const boost::asio::ip::address& local,
@@ -78,10 +79,11 @@ private:
bool m_wantCongestionMarking = false;
std::map<tcp::Endpoint, shared_ptr<TcpChannel>> m_channels;
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
IpAddressPredicate m_local;
};
} // namespace nfd::face
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_TCP_FACTORY_HPP
+23 -15
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, 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,
@@ -26,25 +26,26 @@
#include "tcp-transport.hpp"
#include "common/global.hpp"
#include <boost/asio/defer.hpp>
#if defined(__linux__)
#include <linux/sockios.h>
#include <sys/ioctl.h>
#endif
namespace nfd::face {
namespace nfd {
namespace face {
namespace ip = boost::asio::ip;
NFD_LOG_MEMBER_INIT_SPECIALIZED(StreamTransport<boost::asio::ip::tcp>, TcpTransport);
NFD_LOG_MEMBER_INIT_SPECIALIZED(StreamTransport<ip::tcp>, TcpTransport);
time::milliseconds TcpTransport::s_initialReconnectWait = 1_s;
time::milliseconds TcpTransport::s_maxReconnectWait = 5_min;
float TcpTransport::s_reconnectWaitMultiplier = 2.0f;
TcpTransport::TcpTransport(ip::tcp::socket&& socket,
TcpTransport::TcpTransport(protocol::socket&& socket,
ndn::nfd::FacePersistency persistency,
ndn::nfd::FaceScope faceScope)
: StreamTransport(std::move(socket))
, m_remoteEndpoint(m_socket.remote_endpoint())
, m_nextReconnectWait(INITIAL_RECONNECT_DELAY)
, m_nextReconnectWait(s_initialReconnectWait)
{
this->setLocalUri(FaceUri(m_socket.local_endpoint()));
this->setRemoteUri(FaceUri(m_socket.remote_endpoint()));
@@ -109,7 +110,7 @@ TcpTransport::handleError(const boost::system::error_code& error)
m_socket.cancel(ec);
// do this asynchronously because there could be some callbacks still pending
boost::asio::defer(getGlobalIoService(), [this] { reconnect(); });
getGlobalIoService().post([this] { reconnect(); });
}
else {
StreamTransport::handleError(error);
@@ -132,7 +133,13 @@ TcpTransport::reconnect()
BOOST_ASSERT(getState() == TransportState::DOWN);
// recreate the socket
m_socket = ip::tcp::socket(m_socket.get_executor());
m_socket = protocol::socket(
#if BOOST_VERSION >= 107000
m_socket.get_executor()
#else
m_socket.get_io_service()
#endif // BOOST_VERSION >= 107000
);
this->resetReceiveBuffer();
this->resetSendQueue();
@@ -158,7 +165,7 @@ TcpTransport::handleReconnect(const boost::system::error_code& error)
}
m_reconnectEvent.cancel();
m_nextReconnectWait = INITIAL_RECONNECT_DELAY;
m_nextReconnectWait = s_initialReconnectWait;
this->setLocalUri(FaceUri(m_socket.local_endpoint()));
NFD_LOG_FACE_TRACE("TCP connection reestablished");
@@ -175,11 +182,11 @@ TcpTransport::handleReconnectTimeout()
// exponentially back off the reconnection timer
m_nextReconnectWait =
std::min(time::duration_cast<time::milliseconds>(m_nextReconnectWait * RECONNECT_DELAY_MULTIPLIER),
MAX_RECONNECT_DELAY);
std::min(time::duration_cast<time::milliseconds>(m_nextReconnectWait * s_reconnectWaitMultiplier),
s_maxReconnectWait);
// do this asynchronously because there could be some callbacks still pending
boost::asio::defer(getGlobalIoService(), [this] { reconnect(); });
getGlobalIoService().post([this] { reconnect(); });
}
void
@@ -189,4 +196,5 @@ TcpTransport::doClose()
StreamTransport::doClose();
}
} // namespace nfd::face
} // namespace face
} // namespace nfd
Loaded 100 of 540 files, more files were not shown because too many files have changed in this diff. Show more