Compare commits
210
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19e2e6d858 | ||
|
|
c31080d470 | ||
|
|
b47247dad9 | ||
|
|
8a84773fdb | ||
|
|
55e21b9e17 | ||
|
|
7d30d8556a | ||
|
|
64d99f21eb | ||
|
|
1b65ca1900 | ||
|
|
3409cd399d | ||
|
|
3206565bac | ||
|
|
32dab97321 | ||
|
|
7003c609b8 | ||
|
|
16320cd28b | ||
|
|
406deb5971 | ||
|
|
38b24c7b94 | ||
|
|
530cf00d68 | ||
|
|
465056e9c6 | ||
|
|
91f6ee0c72 | ||
|
|
b859031855 | ||
|
|
81a9a86305 | ||
|
|
7f566dd0e5 | ||
|
|
65800d22e7 | ||
|
|
4cb74319f9 | ||
|
|
3aba7548f4 | ||
|
|
593887c8d0 | ||
|
|
0e4a1f112d | ||
|
|
18739c4ac1 | ||
|
|
947192570d | ||
|
|
2a00194316 | ||
|
|
9137e9e2ae | ||
|
|
890afe9d85 | ||
|
|
d0e276f66a | ||
|
|
5e8755c774 | ||
|
|
037f4ab4b6 | ||
|
|
f15058ab06 | ||
|
|
c34d167b91 | ||
|
|
b4a5acd890 | ||
|
|
a88911105c | ||
|
|
7ee00fb680 | ||
|
|
c29c0b01a7 | ||
|
|
9db735958c | ||
|
|
57cda13f7b | ||
|
|
2a73f35ce6 | ||
|
|
aaa58a6c10 | ||
|
|
52fa45c6ee | ||
|
|
934f5055ab | ||
|
|
26c82ca131 | ||
|
|
52555b06d4 | ||
|
|
e21b3f3dc4 | ||
|
|
ee400b5235 | ||
|
|
e273333fba | ||
|
|
6d932e83d2 | ||
|
|
ae889380da | ||
|
|
a7f9a29e74 | ||
|
|
a6350d9395 | ||
|
|
6c13562d23 | ||
|
|
00dc91423e | ||
|
|
ac767aad0f | ||
|
|
89567d3b31 | ||
|
|
dcdf6212cc | ||
|
|
c5f651f014 | ||
|
|
a274292b93 | ||
|
|
d3ac777f7b | ||
|
|
ecc45cbc7e | ||
|
|
1b4ba050cc | ||
|
|
5f47aa6140 | ||
|
|
89c4cca866 | ||
|
|
27bdd1a325 | ||
|
|
6db5ce1912 | ||
|
|
91e1d7ce48 | ||
|
|
97210d5b15 | ||
|
|
436f3bd9fe | ||
|
|
7de0444d06 | ||
|
|
7c7951391c | ||
|
|
6e21cdb13f | ||
|
|
67019110d7 | ||
|
|
9a00fabed7 | ||
|
|
c05918c860 | ||
|
|
f40551a061 | ||
|
|
d8205106cc | ||
|
|
cffb4e5bce | ||
|
|
3495b8009c | ||
|
|
c143afea10 | ||
|
|
c69f9210d9 | ||
|
|
043c50147c | ||
|
|
e94804bd48 | ||
|
|
e342e8de70 | ||
|
|
c06746182b | ||
|
|
fc6515d2f7 | ||
|
|
3d1eb091c0 | ||
|
|
bf6acd5cc9 | ||
|
|
737c43cdad | ||
|
|
0fc97486ff | ||
|
|
e0edc4c06d | ||
|
|
0a5e5e2fa5 | ||
|
|
8527f86de4 | ||
|
|
6459e64f36 | ||
|
|
25c6ce41d5 | ||
|
|
cbc8e947bf | ||
|
|
0dba01018c | ||
|
|
b5aa7f58e8 | ||
|
|
64567bb12a | ||
|
|
58320f7156 | ||
|
|
5ad19febad | ||
|
|
88f5f7392b | ||
|
|
4260241659 | ||
|
|
231ddd7508 | ||
|
|
cf0f3ce319 | ||
|
|
aaa5dd3a00 | ||
|
|
a269f47bc7 | ||
|
|
9685cc5682 | ||
|
|
2f741327e6 | ||
|
|
8c39bf0b9f | ||
|
|
e0fa33b2a0 | ||
|
|
fc02186460 | ||
|
|
2af9ca368b | ||
|
|
0cc125c365 | ||
|
|
36b22256c1 | ||
|
|
fbe8efea55 | ||
|
|
2e526d70d2 | ||
|
|
06d6ba666d | ||
|
|
37175489ca | ||
|
|
9ddf1b5c26 | ||
|
|
217384025e | ||
|
|
29b4128397 | ||
|
|
331ade75da | ||
|
|
d243d71bf5 | ||
|
|
5b3feb6008 | ||
|
|
d7631279f7 | ||
|
|
f5409d434a | ||
|
|
1c2c6c45e2 | ||
|
|
b30863e0e2 | ||
|
|
13ad4b7a42 | ||
|
|
9f6ca60f74 | ||
|
|
dbef6dc8e2 | ||
|
|
3248205bb7 | ||
|
|
09cf13cd9f | ||
|
|
8ff0a86e18 | ||
|
|
b9420cf0c1 | ||
|
|
340d5533ea | ||
|
|
e7258ffa88 | ||
|
|
dd8f66140b | ||
|
|
15e98b00f5 | ||
|
|
759993b922 | ||
|
|
7f35843d58 | ||
|
|
f2420fc7a3 | ||
|
|
811c010098 | ||
|
|
67f30273dd | ||
|
|
352fc82185 | ||
|
|
9ede5bd312 | ||
|
|
e3cf285ee7 | ||
|
|
f9f7cf35ae | ||
|
|
b660b4c9c0 | ||
|
|
029401f6cc | ||
|
|
9f5b01dfd8 | ||
|
|
38f4ce9f25 | ||
|
|
9cff779038 | ||
|
|
02b73f5705 | ||
|
|
2570f3ec4f | ||
|
|
dcffdaafb5 | ||
|
|
80f9fcdaa1 | ||
|
|
71d12148c8 | ||
|
|
d23de8b9ef | ||
|
|
4a4ccfe7d6 | ||
|
|
5149320e5b | ||
|
|
cb27ea8185 | ||
|
|
ae04d34c17 | ||
|
|
b84e6743be | ||
|
|
5b43f9a74d | ||
|
|
581cf00ee8 | ||
|
|
a49a1abf12 | ||
|
|
3978c92af1 | ||
|
|
221b6fec69 | ||
|
|
ff10da6575 | ||
|
|
af9aa366fd | ||
|
|
a6de4290c8 | ||
|
|
8d843148d2 | ||
|
|
05cc50ae37 | ||
|
|
b260017fec | ||
|
|
8a4c29e8db | ||
|
|
fde3f54d67 | ||
|
|
cf0db02ced | ||
|
|
25a84074ab | ||
|
|
891f47bcfa | ||
|
|
d41d6077ce | ||
|
|
3d1874af59 | ||
|
|
6ca6cf7474 | ||
|
|
67079664ae | ||
|
|
f5aee94f15 | ||
|
|
2879779804 | ||
|
|
b184e5324d | ||
|
|
ff920303df | ||
|
|
e0d71b0bc0 | ||
|
|
ab49745afe | ||
|
|
ace83ac938 | ||
|
|
75142a10be | ||
|
|
b84bd3a8c4 | ||
|
|
cafae24473 | ||
|
|
cc7bee7d80 | ||
|
|
6602b3b179 | ||
|
|
4f1afaca16 | ||
|
|
d72f092052 | ||
|
|
8744c97a4d | ||
|
|
df846e5904 | ||
|
|
eee53aa5d5 | ||
|
|
f3410d8c59 | ||
|
|
4846f37117 | ||
|
|
39a79be5ae | ||
|
|
fef73e4b86 | ||
|
|
2c5a01a67d |
No files matched your search
+2
-1
@@ -2,7 +2,8 @@
|
||||
.waf-1*
|
||||
.waf3-*
|
||||
.lock*
|
||||
**/*.pyc
|
||||
*.pyc
|
||||
*.pyo
|
||||
build/
|
||||
VERSION
|
||||
unit-tests.conf
|
||||
+7
-15
@@ -4,26 +4,18 @@ set -e
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
|
||||
if has OSX $NODE_LABELS; then
|
||||
if has OSX-10.8 $NODE_LABELS; then
|
||||
EXTRA_FLAGS=--c++11
|
||||
fi
|
||||
set -x
|
||||
|
||||
set -x
|
||||
if has OSX $NODE_LABELS; then
|
||||
brew update
|
||||
brew upgrade
|
||||
brew install boost pkg-config cryptopp $EXTRA_FLAGS
|
||||
brew install boost pkg-config cryptopp openssl
|
||||
brew cleanup
|
||||
fi
|
||||
|
||||
if has Ubuntu $NODE_LABELS; then
|
||||
BOOST_PKG=libboost-all-dev
|
||||
if has Ubuntu-12.04 $NODE_LABELS; then
|
||||
BOOST_PKG=libboost1.48-all-dev
|
||||
fi
|
||||
|
||||
set -x
|
||||
sudo apt-get update -qq -y
|
||||
sudo apt-get -qq -y install build-essential pkg-config $BOOST_PKG \
|
||||
libcrypto++-dev libsqlite3-dev libpcap-dev
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get -qq install build-essential pkg-config libboost-all-dev \
|
||||
libcrypto++-dev libsqlite3-dev libssl-dev \
|
||||
libpcap-dev
|
||||
fi
|
||||
@@ -1,11 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
set -e
|
||||
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
|
||||
pushd ${CACHE_DIR:-/tmp} >/dev/null
|
||||
set -x
|
||||
|
||||
pushd "${CACHE_DIR:-/tmp}" >/dev/null
|
||||
|
||||
INSTALLED_VERSION=$((cd ndn-cxx && git rev-parse HEAD) 2>/dev/null || echo NONE)
|
||||
|
||||
@@ -28,9 +29,9 @@ sudo rm -f /usr/local/lib/pkgconfig/libndn-cxx*
|
||||
|
||||
pushd ndn-cxx >/dev/null
|
||||
|
||||
./waf configure -j1 --color=yes --enable-shared --disable-static --without-osx-keychain
|
||||
./waf -j1 --color=yes
|
||||
sudo ./waf install -j1 --color=yes
|
||||
./waf -j1 --color=yes configure --enable-shared --disable-static --without-osx-keychain
|
||||
./waf -j1 --color=yes build
|
||||
sudo ./waf -j1 --color=yes install
|
||||
|
||||
popd >/dev/null
|
||||
popd >/dev/null
|
||||
|
||||
+24
-16
@@ -1,7 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
set -e
|
||||
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
|
||||
set -x
|
||||
|
||||
git submodule init
|
||||
git submodule sync
|
||||
git submodule update
|
||||
@@ -9,25 +13,29 @@ git submodule update
|
||||
# Cleanup
|
||||
sudo ./waf -j1 --color=yes distclean
|
||||
|
||||
# Configure/build in optimized mode with tests and precompiled headers
|
||||
./waf -j1 --color=yes configure --with-tests
|
||||
./waf -j1 --color=yes build
|
||||
if [[ $JOB_NAME != *"code-coverage" && $JOB_NAME != *"limited-build" ]]; then
|
||||
# Configure/build in optimized mode with tests
|
||||
./waf -j1 --color=yes configure --with-tests
|
||||
./waf -j1 --color=yes build
|
||||
|
||||
# Cleanup
|
||||
sudo ./waf -j1 --color=yes distclean
|
||||
# Cleanup
|
||||
sudo ./waf -j1 --color=yes distclean
|
||||
|
||||
# Configure/build in optimized mode without tests and with precompiled headers
|
||||
./waf -j1 --color=yes configure
|
||||
./waf -j1 --color=yes build
|
||||
# Configure/build in optimized mode without tests
|
||||
./waf -j1 --color=yes configure
|
||||
./waf -j1 --color=yes build
|
||||
|
||||
# Cleanup
|
||||
sudo ./waf -j1 --color=yes distclean
|
||||
|
||||
# Configure/build in debug mode
|
||||
if [[ "$JOB_NAME" == *"code-coverage" ]]; then
|
||||
COVERAGE="--with-coverage"
|
||||
# Cleanup
|
||||
sudo ./waf -j1 --color=yes distclean
|
||||
fi
|
||||
./waf -j1 --color=yes configure --debug --with-tests --without-pch $COVERAGE
|
||||
|
||||
# Configure/build in debug mode with tests and without precompiled headers
|
||||
if [[ $JOB_NAME == *"code-coverage" ]]; then
|
||||
COVERAGE="--with-coverage"
|
||||
elif ! has OSX-10.9 $NODE_LABELS && ! has OSX-10.11 $NODE_LABELS; then
|
||||
ASAN="--with-sanitizer=address"
|
||||
fi
|
||||
./waf -j1 --color=yes configure --debug --with-tests --without-pch $COVERAGE $ASAN
|
||||
./waf -j1 --color=yes build
|
||||
|
||||
# (tests will be run against debug version)
|
||||
|
||||
+37
-24
@@ -1,41 +1,54 @@
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
set -e
|
||||
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
|
||||
set -x
|
||||
|
||||
# Prepare environment
|
||||
rm -Rf ~/.ndnx ~/.ndn
|
||||
rm -Rf ~/.ndn
|
||||
|
||||
if has OSX $NODE_LABELS; then
|
||||
security unlock-keychain -p "named-data"
|
||||
sudo chgrp admin /dev/bpf*
|
||||
sudo chmod g+rw /dev/bpf*
|
||||
fi
|
||||
|
||||
if has Linux $NODE_LABELS; then
|
||||
sudo setcap cap_net_raw,cap_net_admin=eip `pwd`/build/unit-tests-core || true
|
||||
sudo setcap cap_net_raw,cap_net_admin=eip `pwd`/build/unit-tests-daemon || true
|
||||
sudo setcap cap_net_raw,cap_net_admin=eip `pwd`/build/unit-tests-rib || true
|
||||
security unlock-keychain -p named-data
|
||||
fi
|
||||
|
||||
ndnsec-keygen "/tmp/jenkins/$NODE_NAME" | ndnsec-install-cert -
|
||||
|
||||
# Run unit tests
|
||||
# Core
|
||||
if [[ -n $XUNIT ]]; then
|
||||
./build/unit-tests-core -l all -- --log_format2=XML --log_sink2=build/xunit-core-report.xml
|
||||
sudo ./build/unit-tests-core -t TestPrivilegeHelper -l all -- --log_format2=XML --log_sink2=build/xunit-core-sudo-report.xml
|
||||
BOOST_VERSION=$(python -c "import sys; sys.path.append('build/c4che'); import _cache; print(_cache.BOOST_VERSION_NUMBER);")
|
||||
|
||||
./build/unit-tests-daemon -l all -- --log_format2=XML --log_sink2=build/xunit-daemon-report.xml
|
||||
ut_log_args() {
|
||||
if (( BOOST_VERSION >= 106200 )); then
|
||||
echo --logger=HRF,test_suite,stdout:XML,all,build/xunit-${1:-report}.xml
|
||||
else
|
||||
if [[ -n $XUNIT ]]; then
|
||||
echo --log_level=all $( (( BOOST_VERSION >= 106000 )) && echo -- ) \
|
||||
--log_format2=XML --log_sink2=build/xunit-${1:-report}.xml
|
||||
else
|
||||
echo --log_level=test_suite
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
./build/unit-tests-rib -l all -- --log_format2=XML --log_sink2=build/xunit-rib-report.xml
|
||||
else
|
||||
./build/unit-tests-core -l test_suite
|
||||
sudo ./build/unit-tests-core -t TestPrivilegeHelper -l test_suite
|
||||
ASAN_OPTIONS="color=always"
|
||||
ASAN_OPTIONS+=":detect_leaks=false"
|
||||
ASAN_OPTIONS+=":detect_stack_use_after_return=true"
|
||||
ASAN_OPTIONS+=":check_initialization_order=true"
|
||||
ASAN_OPTIONS+=":strict_init_order=true"
|
||||
ASAN_OPTIONS+=":detect_invalid_pointer_pairs=1"
|
||||
ASAN_OPTIONS+=":detect_container_overflow=false"
|
||||
ASAN_OPTIONS+=":strict_string_checks=true"
|
||||
ASAN_OPTIONS+=":strip_path_prefix=${PWD}/"
|
||||
export ASAN_OPTIONS
|
||||
|
||||
./build/unit-tests-daemon -l test_suite
|
||||
# First run all tests as unprivileged user
|
||||
./build/unit-tests-core $(ut_log_args core)
|
||||
./build/unit-tests-daemon $(ut_log_args daemon)
|
||||
./build/unit-tests-rib $(ut_log_args rib)
|
||||
./build/unit-tests-tools $(ut_log_args tools)
|
||||
|
||||
./build/unit-tests-rib -l test_suite
|
||||
fi
|
||||
# Then use sudo to run those tests that need superuser powers
|
||||
sudo -E ./build/unit-tests-core -t TestPrivilegeHelper $(ut_log_args core-privilege)
|
||||
sudo -E ./build/unit-tests-daemon -t Face/TestEthernetTransport $(ut_log_args daemon-ethernet)
|
||||
sudo -E ./build/unit-tests-daemon -t Face/*Factory/ProcessConfig $(ut_log_args daemon-face-config)
|
||||
sudo -E ./build/unit-tests-daemon -t Mgmt/TestGeneralConfigSection/UserAndGroupConfig,NoUserConfig $(ut_log_args daemon-user-config)
|
||||
@@ -1,11 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
set -e
|
||||
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
|
||||
if [[ "$JOB_NAME" == *"code-coverage" ]]; then
|
||||
BASE="`pwd | sed -e 's|/|\\\/|g'`\\"
|
||||
(cd build && gcovr -x -f $BASE/core -f $BASE/daemon -f $BASE/rib -r ../ -o coverage.xml ./)
|
||||
set -x
|
||||
|
||||
if [[ $JOB_NAME == *"code-coverage" ]]; then
|
||||
gcovr --object-directory=build \
|
||||
--output=build/coverage.xml \
|
||||
--exclude="$PWD/(tests|websocketpp)" \
|
||||
--root=. \
|
||||
--xml
|
||||
fi
|
||||
@@ -9,17 +9,17 @@ Environment Variables Used in Build Scripts
|
||||
|
||||
The list should include at least `[OS_TYPE]`, `[DISTRO_TYPE]`, and `[DISTRO_VERSION]`.
|
||||
|
||||
Possible values for Linux OS:
|
||||
Possible values for Linux:
|
||||
|
||||
* `[OS_TYPE]`: `Linux`
|
||||
* `[DISTRO_TYPE]`: `Ubuntu`
|
||||
* `[DISTRO_VERSION]`: `Ubuntu-12.04`, `Ubuntu-14.04`, `Ubuntu-15.04`
|
||||
* `[DISTRO_VERSION]`: `Ubuntu-14.04`, `Ubuntu-16.04`
|
||||
|
||||
Possible values of OSX OS:
|
||||
Possible values for OS X / macOS:
|
||||
|
||||
* `[OS_TYPE]`: `OSX`
|
||||
* `[DISTRO_TYPE]`: `OSX` (can be absent)
|
||||
* `[DISTRO_VERSION]`: `OSX-10.10`, `OSX-10.9`, `OSX-10.8`, `OSX-10.7`
|
||||
* `[DISTRO_VERSION]`: `OSX-10.10`, `OSX-10.11`, `OSX-10.12`
|
||||
|
||||
- `JOB_NAME`: optional variable to define type of the job. Depending on the defined job type,
|
||||
the build scripts can perform different tasks.
|
||||
@@ -27,7 +27,8 @@ Environment Variables Used in Build Scripts
|
||||
Possible values:
|
||||
|
||||
* empty: default build process
|
||||
* `code-coverage` (Linux OS is assumed): build process with code coverage analysis
|
||||
* `code-coverage` (Linux OS is assumed): debug build with tests and code coverage analysis
|
||||
* `limited-build`: only a single debug build with tests
|
||||
|
||||
- `CACHE_DIR`: the variable defines a path to folder containing cached files from previous builds,
|
||||
e.g., a compiled version of ndn-cxx library. If not set, `/tmp` is used.
|
||||
+13
-4
@@ -1,9 +1,18 @@
|
||||
has() {
|
||||
local saved_xtrace
|
||||
[[ $- == *x* ]] && saved_xtrace=-x || saved_xtrace=+x
|
||||
set +x
|
||||
|
||||
local p=$1
|
||||
shift
|
||||
local x
|
||||
for x in "$@"; do
|
||||
[[ "${x}" == "${p}" ]] && return 0
|
||||
local i ret=1
|
||||
for i in "$@"; do
|
||||
if [[ "${i}" == "${p}" ]]; then
|
||||
ret=0
|
||||
break
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
|
||||
set ${saved_xtrace}
|
||||
return ${ret}
|
||||
}
|
||||
+22
-9
@@ -1,15 +1,28 @@
|
||||
sudo: true
|
||||
language: cpp
|
||||
os:
|
||||
- linux
|
||||
compiler:
|
||||
- gcc
|
||||
sudo: required
|
||||
language: generic
|
||||
env:
|
||||
global:
|
||||
- JOB_NAME=limited-build
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
dist: trusty
|
||||
env:
|
||||
- CXX=g++
|
||||
- NODE_LABELS="Linux Ubuntu Ubuntu-14.04"
|
||||
- os: linux
|
||||
dist: trusty
|
||||
env:
|
||||
- CXX=clang++
|
||||
- NODE_LABELS="Linux Ubuntu Ubuntu-14.04"
|
||||
- os: osx
|
||||
osx_image: xcode8.2
|
||||
env:
|
||||
- CXX=clang++
|
||||
- NODE_LABELS="OSX OSX-10.12"
|
||||
notifications:
|
||||
email:
|
||||
on_success: always
|
||||
on_failure: always
|
||||
script:
|
||||
- if [[ $TRAVIS_OS_NAME == linux ]]; then export NODE_LABELS="Linux Ubuntu Ubuntu-12.04"; fi
|
||||
- if [[ $TRAVIS_OS_NAME == osx ]]; then export NODE_LABELS="OSX OSX-10.10"; fi
|
||||
- echo $NODE_LABELS
|
||||
- ./.jenkins
|
||||
@@ -1,63 +1,30 @@
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
"""
|
||||
Copyright (c) 2014-2016, Regents of the University of California,
|
||||
Arizona Board of Regents,
|
||||
Colorado State University,
|
||||
University Pierre & Marie Curie, Sorbonne University,
|
||||
Washington University in St. Louis,
|
||||
Beijing Institute of Technology,
|
||||
The University of Memphis.
|
||||
|
||||
This file is part of 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/>.
|
||||
"""
|
||||
|
||||
from waflib.Configure import conf
|
||||
|
||||
OVERRIDE = '''
|
||||
class Base
|
||||
{
|
||||
virtual void
|
||||
f(int a);
|
||||
};
|
||||
|
||||
class Derived : public Base
|
||||
{
|
||||
virtual void
|
||||
f(int a) override;
|
||||
};
|
||||
'''
|
||||
|
||||
@conf
|
||||
def check_override(self):
|
||||
self.check_cxx(msg='Checking for override specifier',
|
||||
fragment=OVERRIDE,
|
||||
define_name='HAVE_CXX_OVERRIDE',
|
||||
features='cxx', mandatory=False)
|
||||
|
||||
FINAL = '''
|
||||
class Base
|
||||
{
|
||||
virtual void
|
||||
f(int a);
|
||||
};
|
||||
|
||||
class Derived : public Base
|
||||
{
|
||||
virtual void
|
||||
f(int a) final;
|
||||
};
|
||||
'''
|
||||
|
||||
@conf
|
||||
def check_final(self):
|
||||
self.check_cxx(msg='Checking for final specifier on method',
|
||||
fragment=FINAL,
|
||||
define_name='HAVE_CXX_FINAL',
|
||||
features='cxx', mandatory=False)
|
||||
|
||||
CLASS_FINAL = '''
|
||||
class A final
|
||||
{
|
||||
};
|
||||
'''
|
||||
|
||||
@conf
|
||||
def check_class_final(self):
|
||||
self.check_cxx(msg='Checking for final specifier on class',
|
||||
fragment=CLASS_FINAL,
|
||||
define_name='HAVE_CXX_CLASS_FINAL',
|
||||
features='cxx', mandatory=False)
|
||||
|
||||
def configure(conf):
|
||||
conf.check_override()
|
||||
conf.check_final()
|
||||
conf.check_class_final()
|
||||
pass
|
||||
@@ -60,7 +60,7 @@ def add_supported_cxxflags(self, cxxflags):
|
||||
supportedFlags += [flag]
|
||||
|
||||
self.end_msg(' '.join(supportedFlags))
|
||||
self.env.CXXFLAGS = supportedFlags + self.env.CXXFLAGS
|
||||
self.env.prepend_value('CXXFLAGS', supportedFlags)
|
||||
|
||||
@Configure.conf
|
||||
def add_supported_linkflags(self, linkflags):
|
||||
@@ -78,7 +78,7 @@ def add_supported_linkflags(self, linkflags):
|
||||
supportedFlags += [flag]
|
||||
|
||||
self.end_msg(' '.join(supportedFlags))
|
||||
self.env.LINKFLAGS = supportedFlags + self.env.LINKFLAGS
|
||||
self.env.prepend_value('LINKFLAGS', supportedFlags)
|
||||
|
||||
|
||||
class CompilerFlags(object):
|
||||
@@ -108,6 +108,7 @@ class GccBasicFlags(CompilerFlags):
|
||||
'-Werror',
|
||||
'-Wno-unused-parameter',
|
||||
'-Wno-error=maybe-uninitialized', # Bug #1615
|
||||
'-Wno-error=deprecated-declarations', # Bug #3795
|
||||
]
|
||||
return flags
|
||||
|
||||
@@ -126,16 +127,12 @@ class GccFlags(GccBasicFlags):
|
||||
def getGeneralFlags(self, conf):
|
||||
flags = super(GccFlags, self).getGeneralFlags(conf)
|
||||
version = tuple(int(i) for i in conf.env['CC_VERSION'])
|
||||
if version < (4, 6, 0):
|
||||
if version < (4, 8, 2):
|
||||
conf.fatal('The version of gcc you are using (%s) is too old.\n' %
|
||||
'.'.join(conf.env['CC_VERSION']) +
|
||||
'The minimum supported gcc version is 4.6.0.')
|
||||
elif version < (4, 7, 0):
|
||||
flags['CXXFLAGS'] += ['-std=c++0x']
|
||||
'The minimum supported gcc version is 4.8.2.')
|
||||
else:
|
||||
flags['CXXFLAGS'] += ['-std=c++11']
|
||||
if version < (4, 8, 0):
|
||||
flags['DEFINES'] += ['_GLIBCXX_USE_NANOSLEEP'] # Bug #2499
|
||||
return flags
|
||||
|
||||
def getDebugFlags(self, conf):
|
||||
@@ -172,6 +169,7 @@ class ClangFlags(GccBasicFlags):
|
||||
'-Wno-error=unneeded-internal-declaration', # Bug #1588
|
||||
'-Wno-error=deprecated-register',
|
||||
'-Wno-error=keyword-macro', # Bug #3235
|
||||
'-Wno-error=infinite-recursion', # Bug #3358
|
||||
]
|
||||
return flags
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
def options(opt):
|
||||
opt.add_option('--with-sanitizer', action='store', default='', dest='sanitizers',
|
||||
help='Comma-separated list of compiler sanitizers to enable [default=none]')
|
||||
|
||||
def configure(conf):
|
||||
for san in conf.options.sanitizers.split(','):
|
||||
if not san:
|
||||
continue
|
||||
|
||||
sanflag = '-fsanitize=%s' % san
|
||||
conf.start_msg('Checking if compiler supports %s' % sanflag)
|
||||
|
||||
if conf.check_cxx(cxxflags=['-Werror', sanflag, '-fno-omit-frame-pointer'],
|
||||
linkflags=[sanflag], mandatory=False):
|
||||
conf.end_msg('yes')
|
||||
conf.env.append_unique('CXXFLAGS', [sanflag, '-fno-omit-frame-pointer'])
|
||||
conf.env.append_unique('LINKFLAGS', [sanflag])
|
||||
else:
|
||||
conf.end_msg('no', color='RED')
|
||||
conf.fatal('%s sanitizer is not supported by the current compiler' % san)
|
||||
@@ -6,23 +6,12 @@
|
||||
|
||||
from waflib import Configure
|
||||
|
||||
IS_DEFAULT_CONSTRUCTIBLE_CHECK = '''
|
||||
#include <type_traits>
|
||||
static_assert(std::is_default_constructible<int>::value, "");
|
||||
'''
|
||||
|
||||
IS_MOVE_CONSTRUCTIBLE_CHECK = '''
|
||||
#include <type_traits>
|
||||
static_assert(std::is_move_constructible<int>::value, "");
|
||||
'''
|
||||
|
||||
def configure(conf):
|
||||
if conf.check_cxx(msg='Checking for std::is_default_constructible',
|
||||
fragment=IS_DEFAULT_CONSTRUCTIBLE_CHECK,
|
||||
features='cxx', mandatory=False):
|
||||
conf.define('HAVE_IS_DEFAULT_CONSTRUCTIBLE', 1)
|
||||
conf.env['HAVE_IS_DEFAULT_CONSTRUCTIBLE'] = True
|
||||
|
||||
if conf.check_cxx(msg='Checking for std::is_move_constructible',
|
||||
fragment=IS_MOVE_CONSTRUCTIBLE_CHECK,
|
||||
features='cxx', mandatory=False):
|
||||
|
||||
+7
-10
@@ -1,17 +1,14 @@
|
||||
# encoding: utf-8
|
||||
|
||||
from waflib import Options, Logs, Errors
|
||||
from waflib.Configure import conf
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
from waflib import Options, Logs, Errors, Configure
|
||||
import re
|
||||
|
||||
def addWebsocketOptions(self, opt):
|
||||
opt.add_option('--without-websocket', action='store_false', default=True,
|
||||
dest='with_websocket',
|
||||
help='Disable WebSocket face support')
|
||||
dest='with_websocket', help='Disable WebSocket face support')
|
||||
setattr(Options.OptionsContext, "addWebsocketOptions", addWebsocketOptions)
|
||||
|
||||
@conf
|
||||
@Configure.conf
|
||||
def checkWebsocket(self, **kw):
|
||||
if not self.options.with_websocket:
|
||||
return
|
||||
@@ -36,8 +33,8 @@ def checkWebsocket(self, **kw):
|
||||
|
||||
# Looking for the following:
|
||||
# static int const major_version = 0;
|
||||
# static int const minor_version = 5;
|
||||
# static int const patch_version = 1;
|
||||
# static int const minor_version = 7;
|
||||
# static int const patch_version = 0;
|
||||
|
||||
version = [None, None, None]
|
||||
|
||||
@@ -71,7 +68,7 @@ def checkWebsocket(self, **kw):
|
||||
Logs.warn(' git submodule init && git submodule update')
|
||||
Logs.warn('Otherwise, manually download and extract websocketpp library:')
|
||||
Logs.warn(' mkdir websocketpp')
|
||||
Logs.warn(' curl -L https://github.com/zaphoyd/websocketpp/archive/0.5.1.tar.gz > websocket.tar.gz')
|
||||
Logs.warn(' curl -L https://github.com/zaphoyd/websocketpp/archive/0.7.0.tar.gz > websocket.tar.gz')
|
||||
Logs.warn(' tar zxf websocket.tar.gz -C websocketpp/ --strip 1')
|
||||
Logs.warn('Alternatively, WebSocket support can be disabled with --without-websocket')
|
||||
self.fatal("The configuration failed")
|
||||
|
||||
+2
-2
@@ -43,7 +43,7 @@ volunteers.
|
||||
|
||||
* University Pierre & Marie Curie, Sorbonne University
|
||||
|
||||
* Davide Pesavento <http://www.lip6.fr/actualite/personnes-fiche.php?ident=D1469>
|
||||
* Davide Pesavento <https://www.linkedin.com/in/davidepesavento>
|
||||
* Giulio Grassi <http://www.lip6.fr/actualite/personnes-fiche.php?ident=D1461>
|
||||
* Giovanni Pau <http://www.cs.ucla.edu/~gpau/Giovanni_Paus_Home_Page/Home.html>
|
||||
|
||||
@@ -73,7 +73,7 @@ in the library:
|
||||
|
||||
* Tai-Lin Chu <https://www.linkedin.com/pub/tai-lin-chu/55/5b2/669>
|
||||
* Spyridon Mastorakis <http://cs.ucla.edu/~mastorakis/>
|
||||
* Eric Newberry <http://ericnewberry.com>
|
||||
* Eric Newberry <http://cs.arizona.edu/~enewberry/>
|
||||
* Yukai Tu <tuyukai1994@gmail.com>
|
||||
* João Pereira <http://website.jpereira.co.uk>
|
||||
* Mathias Gibbens <gibmat@cs.arizona.edu>
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ NFD relies on third-party software and libraries, licensed under the following l
|
||||
- SQLite is in [public domain](http://www.sqlite.org/copyright.html)
|
||||
|
||||
- WebSocket++ library licensed under conditions of
|
||||
[BSD license](https://github.com/zaphoyd/websocketpp/blob/ac5d7ea5af9734de965688b54a7860259887b537/COPYING)
|
||||
[BSD license](https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/COPYING)
|
||||
|
||||
- Libpcap library licensed under conditions of
|
||||
[a 3-clause BSD license](http://www.tcpdump.org/license.html).
|
||||
|
||||
+4
-4
@@ -30,12 +30,12 @@ Include the following license boilerplate into all `.hpp` and `.cpp` files:
|
||||
*/
|
||||
|
||||
If you are affiliated to an NSF-supported NDN project institution, please use the [NDN Team License
|
||||
Boilerplate](http://redmine.named-data.net/projects/nfd/wiki/NDN_Team_License_Boilerplate_(NFD)).
|
||||
Boilerplate](https://redmine.named-data.net/projects/nfd/wiki/NDN_Team_License_Boilerplate_(NFD)).
|
||||
|
||||
Recommendations
|
||||
---------------
|
||||
|
||||
NFD code is subject to NFD [code style](http://redmine.named-data.net/projects/nfd/wiki/CodeStyle).
|
||||
NFD code is subject to NFD [code style](https://redmine.named-data.net/projects/nfd/wiki/CodeStyle).
|
||||
|
||||
|
||||
Running unit-tests
|
||||
@@ -57,7 +57,7 @@ The simplest way to run tests, is just to run the compiled binary without any pa
|
||||
# Run NFD RIB management tests
|
||||
./build/unit-tests-rib
|
||||
|
||||
However, [Boost.Test framework](http://www.boost.org/doc/libs/1_48_0/libs/test/doc/html/)
|
||||
However, [Boost.Test framework](http://www.boost.org/doc/libs/1_54_0/libs/test/doc/html/index.html)
|
||||
is very flexible and allows a number of run-time customization of what tests should be run.
|
||||
For example, it is possible to choose to run only a specific test suite, only a specific
|
||||
test case within a suite, or specific test cases within specific test suites:
|
||||
@@ -90,5 +90,5 @@ or `-p` to show progress bar:
|
||||
|
||||
There are many more command line options available, information about
|
||||
which can be obtained either from the command line using `--help`
|
||||
switch, or online on [Boost.Test library](http://www.boost.org/doc/libs/1_48_0/libs/test/doc/html/)
|
||||
switch, or online on [Boost.Test library](http://www.boost.org/doc/libs/1_54_0/libs/test/doc/html/index.html)
|
||||
website.
|
||||
@@ -1,15 +1,17 @@
|
||||
NFD - Named Data Networking Forwarding Daemon
|
||||
=============================================
|
||||
|
||||
[](https://travis-ci.org/named-data/NFD)
|
||||
|
||||
For complete documentation, including step-by-step installation instructions and
|
||||
tutorials, please visit the [NFD homepage](http://named-data.net/doc/NFD/).
|
||||
tutorials, please visit the [NFD homepage](https://named-data.net/doc/NFD/).
|
||||
|
||||
## Overview
|
||||
|
||||
NFD is a network forwarder that implements and evolves together with the Named Data
|
||||
Networking (NDN) [protocol](http://named-data.net/doc/ndn-tlv/). After the initial
|
||||
Networking (NDN) [protocol](https://named-data.net/doc/ndn-tlv/). After the initial
|
||||
release, NFD will become a core component of the
|
||||
[NDN Platform](http://named-data.net/codebase/platform/) and will follow the same release
|
||||
[NDN Platform](https://named-data.net/codebase/platform/) and will follow the same release
|
||||
cycle.
|
||||
|
||||
NFD is an open and free software package licensed under GPL 3.0 license and is the
|
||||
@@ -19,14 +21,14 @@ limitation, refer to
|
||||
[`COPYING.md`](https://github.com/named-data/NFD/blob/master/COPYING.md).
|
||||
|
||||
NFD is developed by a community effort. Although the first release was mostly done by the
|
||||
members of [NSF-sponsored NDN project team](http://named-data.net/project/participants/),
|
||||
members of [NSF-sponsored NDN project team](https://named-data.net/project/participants/),
|
||||
it already contains significant contributions from people outside the project team (for
|
||||
more details, refer to
|
||||
[`AUTHORS.md`](https://github.com/named-data/NFD/blob/master/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. Bug reports and feedback are
|
||||
highly appreciated and can be made through
|
||||
[Redmine site](http://redmine.named-data.net/projects/nfd) and the
|
||||
[Redmine site](https://redmine.named-data.net/projects/nfd) and the
|
||||
[ndn-interest mailing list](http://www.lists.cs.ucla.edu/mailman/listinfo/ndn-interest).
|
||||
|
||||
The main design goal of NFD is to support diverse experimentation of NDN technology. The
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of 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_ASSERTS_HPP
|
||||
#define NFD_CORE_ASSERTS_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include <boost/concept/assert.hpp>
|
||||
#include <boost/concept_check.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace nfd {
|
||||
namespace detail {
|
||||
|
||||
// As of Boost 1.54.0, the internal implementation of BOOST_CONCEPT_ASSERT does not allow
|
||||
// multiple assertions on the same line, so we have to combine multiple concepts together.
|
||||
|
||||
template<typename T>
|
||||
class StlForwardIteratorConcept : public boost::ForwardIterator<T>
|
||||
, public boost::DefaultConstructible<T>
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace nfd
|
||||
|
||||
/** \brief assert T is default constructible
|
||||
* \sa http://en.cppreference.com/w/cpp/concept/DefaultConstructible
|
||||
*/
|
||||
#define NFD_ASSERT_DEFAULT_CONSTRUCTIBLE(T) \
|
||||
static_assert(std::is_default_constructible<T>::value, \
|
||||
#T " must be default-constructible"); \
|
||||
BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<T>))
|
||||
|
||||
/** \brief assert T is a forward iterator
|
||||
* \sa http://en.cppreference.com/w/cpp/concept/ForwardIterator
|
||||
* \note A forward iterator should be default constructible, but boost::ForwardIterator follows
|
||||
* SGI standard which doesn't require DefaultConstructible, so a separate check is needed.
|
||||
*/
|
||||
#define NFD_ASSERT_FORWARD_ITERATOR(T) \
|
||||
BOOST_CONCEPT_ASSERT((::nfd::detail::StlForwardIteratorConcept<T>)); \
|
||||
static_assert(std::is_default_constructible<T>::value, \
|
||||
#T " must be default-constructible")
|
||||
|
||||
#endif // NFD_CORE_ASSERTS_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -23,51 +23,23 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_COMMON_HPP
|
||||
#define NFD_COMMON_HPP
|
||||
#ifndef NFD_CORE_COMMON_HPP
|
||||
#define NFD_CORE_COMMON_HPP
|
||||
|
||||
#include "config.hpp"
|
||||
#include "core/config.hpp"
|
||||
|
||||
#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 FINAL_UNLESS_WITH_TESTS
|
||||
#else
|
||||
#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
|
||||
#endif
|
||||
|
||||
/** \def DECL_OVERRIDE
|
||||
* \brief expands to 'override' if compiler supports 'override' specifier,
|
||||
* otherwise expands to nothing
|
||||
*/
|
||||
#ifdef HAVE_CXX_OVERRIDE
|
||||
#define DECL_OVERRIDE override
|
||||
#else
|
||||
#define DECL_OVERRIDE
|
||||
#endif
|
||||
|
||||
/** \def DECL_FINAL
|
||||
* \brief expands to 'final' if compiler supports 'final' specifier on method,
|
||||
* otherwise expands to nothing
|
||||
*/
|
||||
#ifdef HAVE_CXX_FINAL
|
||||
#define DECL_FINAL final
|
||||
#else
|
||||
#define DECL_FINAL
|
||||
#endif
|
||||
|
||||
/** \def DECL_CLASS_FINAL
|
||||
* \brief expands to 'final' if compiler supports 'final' specifier on class,
|
||||
* otherwise expands to nothing
|
||||
*/
|
||||
#ifdef HAVE_CXX_CLASS_FINAL
|
||||
#define DECL_CLASS_FINAL final
|
||||
#else
|
||||
#define DECL_CLASS_FINAL
|
||||
#define FINAL_UNLESS_WITH_TESTS final
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
@@ -93,7 +65,6 @@
|
||||
#include <ndn-cxx/util/face-uri.hpp>
|
||||
#include <ndn-cxx/util/signal.hpp>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
@@ -146,4 +117,4 @@ namespace signal = ndn::util::signal;
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_COMMON_HPP
|
||||
#endif // NFD_CORE_COMMON_HPP
|
||||
+20
-26
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -59,10 +59,10 @@ ConfigFile::ignoreUnknownSection(const std::string& filename,
|
||||
}
|
||||
|
||||
bool
|
||||
ConfigFile::parseYesNo(const ConfigSection::value_type& option,
|
||||
ConfigFile::parseYesNo(const ConfigSection& node, const std::string& key,
|
||||
const std::string& sectionName)
|
||||
{
|
||||
auto value = option.second.get_value<std::string>();
|
||||
auto value = node.get_value<std::string>();
|
||||
|
||||
if (value == "yes") {
|
||||
return true;
|
||||
@@ -72,7 +72,7 @@ ConfigFile::parseYesNo(const ConfigSection::value_type& option,
|
||||
}
|
||||
|
||||
BOOST_THROW_EXCEPTION(Error("Invalid value \"" + value + "\" for option \"" +
|
||||
option.first + "\" in \"" + sectionName + "\" section"));
|
||||
key + "\" in \"" + sectionName + "\" section"));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -85,14 +85,10 @@ ConfigFile::addSectionHandler(const std::string& sectionName,
|
||||
void
|
||||
ConfigFile::parse(const std::string& filename, bool isDryRun)
|
||||
{
|
||||
std::ifstream inputFile;
|
||||
inputFile.open(filename.c_str());
|
||||
if (!inputFile.good() || !inputFile.is_open())
|
||||
{
|
||||
std::string msg = "Failed to read configuration file: ";
|
||||
msg += filename;
|
||||
BOOST_THROW_EXCEPTION(Error(msg));
|
||||
}
|
||||
std::ifstream inputFile(filename);
|
||||
if (!inputFile.good() || !inputFile.is_open()) {
|
||||
BOOST_THROW_EXCEPTION(Error("Failed to read configuration file: " + filename));
|
||||
}
|
||||
parse(inputFile, isDryRun, filename);
|
||||
inputFile.close();
|
||||
}
|
||||
@@ -107,18 +103,16 @@ ConfigFile::parse(const std::string& input, bool isDryRun, const std::string& fi
|
||||
void
|
||||
ConfigFile::parse(std::istream& input, bool isDryRun, const std::string& filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::property_tree::read_info(input, m_global);
|
||||
}
|
||||
catch (const boost::property_tree::info_parser_error& error)
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << "Failed to parse configuration file";
|
||||
msg << " " << filename;
|
||||
msg << " " << error.message() << " line " << error.line();
|
||||
BOOST_THROW_EXCEPTION(Error(msg.str()));
|
||||
}
|
||||
try {
|
||||
boost::property_tree::read_info(input, m_global);
|
||||
}
|
||||
catch (const boost::property_tree::info_parser_error& error) {
|
||||
std::stringstream msg;
|
||||
msg << "Failed to parse configuration file";
|
||||
msg << " " << filename;
|
||||
msg << " " << error.message() << " line " << error.line();
|
||||
BOOST_THROW_EXCEPTION(Error(msg.str()));
|
||||
}
|
||||
|
||||
process(isDryRun, filename);
|
||||
}
|
||||
@@ -144,7 +138,7 @@ ConfigFile::process(bool isDryRun, const std::string& filename) const
|
||||
|
||||
for (const auto& i : m_global) {
|
||||
try {
|
||||
ConfigSectionHandler subscriber = m_subscriptions.at(i.first);
|
||||
const ConfigSectionHandler& subscriber = m_subscriptions.at(i.first);
|
||||
subscriber(i.second, isDryRun, filename);
|
||||
}
|
||||
catch (const std::out_of_range&) {
|
||||
@@ -153,4 +147,4 @@ ConfigFile::process(bool isDryRun, const std::string& filename) const
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace nfd
|
||||
+55
-37
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -32,19 +32,29 @@
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/** \brief a config file section
|
||||
*/
|
||||
typedef boost::property_tree::ptree ConfigSection;
|
||||
|
||||
/// \brief callback for config file sections
|
||||
typedef function<void(const ConfigSection& /*section*/,
|
||||
bool /*isDryRun*/,
|
||||
const std::string& /*filename*/)> ConfigSectionHandler;
|
||||
/** \brief an optional config file section
|
||||
*/
|
||||
typedef boost::optional<const ConfigSection&> OptionalConfigSection;
|
||||
|
||||
/// \brief callback for config file sections without a subscribed handler
|
||||
typedef function<void(const std::string& /*filename*/,
|
||||
const std::string& /*sectionName*/,
|
||||
const ConfigSection& /*section*/,
|
||||
bool /*isDryRun*/)> UnknownConfigSectionHandler;
|
||||
/** \brief callback to process a config file section
|
||||
*/
|
||||
typedef function<void(const ConfigSection& section,
|
||||
bool isDryRun,
|
||||
const std::string& filename)> ConfigSectionHandler;
|
||||
|
||||
/** \brief callback to process a config file section without a \p ConfigSectionHandler
|
||||
*/
|
||||
typedef function<void(const std::string& filename,
|
||||
const std::string& sectionName,
|
||||
const ConfigSection& section,
|
||||
bool isDryRun)> UnknownConfigSectionHandler;
|
||||
|
||||
/** \brief configuration file parsing utility
|
||||
*/
|
||||
class ConfigFile : noncopyable
|
||||
{
|
||||
public:
|
||||
@@ -61,6 +71,7 @@ public:
|
||||
explicit
|
||||
ConfigFile(UnknownConfigSectionHandler unknownSectionCallback = throwErrorOnUnknownSection);
|
||||
|
||||
public: // unknown section handlers
|
||||
static void
|
||||
throwErrorOnUnknownSection(const std::string& filename,
|
||||
const std::string& sectionName,
|
||||
@@ -73,27 +84,50 @@ public:
|
||||
const ConfigSection& section,
|
||||
bool isDryRun);
|
||||
|
||||
/**
|
||||
* \brief parse a config option that can be either "yes" or "no"
|
||||
*
|
||||
* \return true if "yes", false if "no"
|
||||
* \throw Error the value is neither "yes" nor "no"
|
||||
public: // parse helpers
|
||||
/** \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"
|
||||
*/
|
||||
static bool
|
||||
parseYesNo(const ConfigSection::value_type& option,
|
||||
const std::string& sectionName);
|
||||
parseYesNo(const ConfigSection& node, const std::string& key, const std::string& sectionName);
|
||||
|
||||
static bool
|
||||
parseYesNo(const ConfigSection::value_type& option, const std::string& sectionName)
|
||||
{
|
||||
return parseYesNo(option.second, option.first, sectionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief parse a numeric (integral or floating point) config option
|
||||
* \tparam T an arithmetic type
|
||||
*
|
||||
* \return the numeric value of the parsed option
|
||||
* \throw Error the value cannot be converted to the specified type
|
||||
*/
|
||||
template <typename T>
|
||||
static typename std::enable_if<std::is_arithmetic<T>::value, T>::type
|
||||
parseNumber(const ConfigSection::value_type& option,
|
||||
const std::string& sectionName);
|
||||
template<typename T>
|
||||
static T
|
||||
parseNumber(const ConfigSection& node, const std::string& key, const std::string& sectionName)
|
||||
{
|
||||
static_assert(std::is_arithmetic<T>::value, "T must be an arithmetic type");
|
||||
|
||||
boost::optional<T> value = node.get_value_optional<T>();
|
||||
if (value) {
|
||||
return *value;
|
||||
}
|
||||
BOOST_THROW_EXCEPTION(Error("Invalid value \"" + node.get_value<std::string>() +
|
||||
"\" for option \"" + key + "\" in \"" + sectionName + "\" section"));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T
|
||||
parseNumber(const ConfigSection::value_type& option, const std::string& sectionName)
|
||||
{
|
||||
return parseNumber<T>(option.second, option.first, sectionName);
|
||||
}
|
||||
|
||||
public: // setup and parsing
|
||||
/// \brief setup notification of configuration file sections
|
||||
void
|
||||
addSectionHandler(const std::string& sectionName,
|
||||
@@ -146,22 +180,6 @@ private:
|
||||
ConfigSection m_global;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type
|
||||
ConfigFile::parseNumber(const ConfigSection::value_type& option,
|
||||
const std::string& sectionName)
|
||||
{
|
||||
auto value = option.second.get_value<std::string>();
|
||||
|
||||
try {
|
||||
return boost::lexical_cast<T>(value);
|
||||
}
|
||||
catch (const boost::bad_lexical_cast&) {
|
||||
BOOST_THROW_EXCEPTION(Error("Invalid value \"" + value + "\" for option \"" +
|
||||
option.first + "\" in \"" + sectionName + "\" section"));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_CORE_CONFIG_FILE_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -27,6 +27,7 @@
|
||||
#define NFD_CORE_EXTENDED_ERROR_MESSAGE_HPP
|
||||
|
||||
#include <boost/exception/get_error_info.hpp>
|
||||
#include <sstream>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
|
||||
+33
-16
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -25,6 +25,9 @@
|
||||
|
||||
#include "logger-factory.hpp"
|
||||
|
||||
#include <ndn-cxx/util/logging.hpp>
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
|
||||
#ifdef HAVE_CUSTOM_LOGGER
|
||||
@@ -53,6 +56,15 @@ LoggerFactory::LoggerFactory()
|
||||
m_levelNames["DEBUG"] = LOG_DEBUG;
|
||||
m_levelNames["TRACE"] = LOG_TRACE;
|
||||
m_levelNames["ALL"] = LOG_ALL;
|
||||
|
||||
// Let ndn-cxx logging facility initialize Boost.Log backend,
|
||||
// so that only one sink is attached to Boost.Log core.
|
||||
ndn::util::Logging::setDestination(std::clog);
|
||||
}
|
||||
|
||||
LoggerFactory::~LoggerFactory()
|
||||
{
|
||||
ndn::util::Logging::flush();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -64,8 +76,7 @@ LoggerFactory::setConfigFile(ConfigFile& config)
|
||||
LogLevel
|
||||
LoggerFactory::parseLevel(const std::string& level)
|
||||
{
|
||||
std::string upperLevel = level;
|
||||
boost::to_upper(upperLevel);
|
||||
std::string upperLevel = boost::to_upper_copy(level);
|
||||
|
||||
// std::cerr << "parsing level: " << upperLevel << std::endl;;
|
||||
// std::cerr << "# levels: " << m_levelNames.size() << std::endl;
|
||||
@@ -112,19 +123,19 @@ LoggerFactory::onConfig(const ConfigSection& section,
|
||||
bool isDryRun,
|
||||
const std::string& filename)
|
||||
{
|
||||
// log
|
||||
// {
|
||||
// ; default_level specifies the logging level for modules
|
||||
// ; that are not explicitly named. All debugging levels
|
||||
// ; listed above the selected value are enabled.
|
||||
//
|
||||
// default_level INFO
|
||||
//
|
||||
// ; You may also override the default for specific modules:
|
||||
//
|
||||
// FibManager DEBUG
|
||||
// Forwarder WARN
|
||||
// }
|
||||
// log
|
||||
// {
|
||||
// ; default_level specifies the logging level for modules
|
||||
// ; that are not explicitly named. All debugging levels
|
||||
// ; listed above the selected value are enabled.
|
||||
//
|
||||
// default_level INFO
|
||||
//
|
||||
// ; You may also override the default for specific modules:
|
||||
//
|
||||
// FibManager DEBUG
|
||||
// Forwarder WARN
|
||||
// }
|
||||
|
||||
if (!isDryRun) {
|
||||
ConfigSection::const_assoc_iterator item = section.find("default_level");
|
||||
@@ -173,6 +184,12 @@ LoggerFactory::setDefaultLevel(LogLevel level)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LoggerFactory::flushBackend()
|
||||
{
|
||||
ndn::util::Logging::flush();
|
||||
}
|
||||
|
||||
Logger&
|
||||
LoggerFactory::create(const std::string& moduleName)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -35,6 +35,8 @@
|
||||
#include "config-file.hpp"
|
||||
#include "logger.hpp"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
class LoggerFactory : noncopyable
|
||||
@@ -77,10 +79,15 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
void
|
||||
setDefaultLevel(LogLevel level);
|
||||
|
||||
void
|
||||
flushBackend();
|
||||
|
||||
private:
|
||||
|
||||
LoggerFactory();
|
||||
|
||||
~LoggerFactory();
|
||||
|
||||
Logger&
|
||||
createLogger(const std::string& moduleName);
|
||||
|
||||
|
||||
+6
-10
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -36,25 +36,23 @@
|
||||
|
||||
namespace nfd {
|
||||
|
||||
std::mutex g_logMutex;
|
||||
|
||||
Logger::Logger(const std::string& name, LogLevel level)
|
||||
: m_moduleName(name)
|
||||
, m_enabledLogLevel(level)
|
||||
{
|
||||
}
|
||||
|
||||
const char*
|
||||
Logger::now()
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const LoggerTimestamp&)
|
||||
{
|
||||
using namespace ndn::time;
|
||||
|
||||
static const microseconds::rep ONE_SECOND = 1000000;
|
||||
microseconds::rep microsecondsSinceEpoch = duration_cast<microseconds>(
|
||||
system_clock::now().time_since_epoch()).count();
|
||||
system_clock::now().time_since_epoch()).count();
|
||||
|
||||
// 10 (whole seconds) + '.' + 6 (fraction) + '\0'
|
||||
static char buffer[10 + 1 + 6 + 1];
|
||||
char buffer[10 + 1 + 6 + 1];
|
||||
BOOST_ASSERT_MSG(microsecondsSinceEpoch / ONE_SECOND <= 9999999999L,
|
||||
"whole seconds cannot fit in 10 characters");
|
||||
|
||||
@@ -66,9 +64,7 @@ Logger::now()
|
||||
microsecondsSinceEpoch / ONE_SECOND,
|
||||
microsecondsSinceEpoch % ONE_SECOND);
|
||||
|
||||
// It's okay to return a statically allocated buffer, because Logger::now() is invoked
|
||||
// only once per log macro.
|
||||
return buffer;
|
||||
return os << buffer;
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
+40
-24
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -31,8 +31,8 @@
|
||||
#ifdef HAVE_CUSTOM_LOGGER
|
||||
#include "custom-logger.hpp"
|
||||
#else
|
||||
|
||||
#include <mutex>
|
||||
#include <boost/log/common.hpp>
|
||||
#include <boost/log/sources/logger.hpp>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
@@ -84,12 +84,8 @@ public:
|
||||
m_moduleName = name;
|
||||
}
|
||||
|
||||
/** \return string representation of time since epoch: seconds.microseconds
|
||||
* \warning Return value is in a statically allocated buffer,
|
||||
* which subsequent calls will overwrite.
|
||||
*/
|
||||
static const char*
|
||||
now();
|
||||
public:
|
||||
boost::log::sources::logger boostLogger;
|
||||
|
||||
private:
|
||||
std::string m_moduleName;
|
||||
@@ -103,6 +99,20 @@ operator<<(std::ostream& output, const Logger& logger)
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief a tag that writes a timestamp upon stream output
|
||||
*/
|
||||
struct LoggerTimestamp
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief write a timestamp to \p os
|
||||
* \note This function is thread-safe.
|
||||
*/
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const LoggerTimestamp&);
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#include "core/logger-factory.hpp"
|
||||
@@ -110,36 +120,42 @@ operator<<(std::ostream& output, const Logger& logger)
|
||||
namespace nfd {
|
||||
|
||||
#define NFD_LOG_INIT(name) \
|
||||
static nfd::Logger& g_logger = nfd::LoggerFactory::create(name)
|
||||
static ::nfd::Logger& g_logger = ::nfd::LoggerFactory::create(name)
|
||||
|
||||
#define NFD_LOG_INCLASS_DECLARE() \
|
||||
static nfd::Logger& g_logger
|
||||
static ::nfd::Logger& g_logger
|
||||
|
||||
#define NFD_LOG_INCLASS_DEFINE(cls, name) \
|
||||
nfd::Logger& cls::g_logger = nfd::LoggerFactory::create(name)
|
||||
::nfd::Logger& cls::g_logger = ::nfd::LoggerFactory::create(name)
|
||||
|
||||
#define NFD_LOG_INCLASS_TEMPLATE_DEFINE(cls, name) \
|
||||
template<class T> \
|
||||
nfd::Logger& cls<T>::g_logger = nfd::LoggerFactory::create(name)
|
||||
::nfd::Logger& cls<T>::g_logger = ::nfd::LoggerFactory::create(name)
|
||||
|
||||
#define NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(cls, specialization, name) \
|
||||
template<> \
|
||||
nfd::Logger& cls<specialization>::g_logger = nfd::LoggerFactory::create(name)
|
||||
::nfd::Logger& cls<specialization>::g_logger = ::nfd::LoggerFactory::create(name)
|
||||
|
||||
#define NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(cls, s1, s2, name) \
|
||||
template<> \
|
||||
nfd::Logger& cls<s1, s2>::g_logger = nfd::LoggerFactory::create(name)
|
||||
::nfd::Logger& cls<s1, s2>::g_logger = ::nfd::LoggerFactory::create(name)
|
||||
|
||||
extern std::mutex g_logMutex;
|
||||
#if (BOOST_VERSION >= 105900) && (BOOST_VERSION < 106000)
|
||||
// workaround Boost bug 11549
|
||||
#define NFD_BOOST_LOG(x) BOOST_LOG(x) << ""
|
||||
#else
|
||||
#define NFD_BOOST_LOG(x) BOOST_LOG(x)
|
||||
#endif
|
||||
|
||||
#define NFD_LOG(level, msg, expression) \
|
||||
do { \
|
||||
if (g_logger.isEnabled(::nfd::LOG_##level)) { \
|
||||
std::lock_guard<std::mutex> lock(::nfd::g_logMutex); \
|
||||
std::clog << ::nfd::Logger::now() << " "#msg": " \
|
||||
<< "[" << g_logger << "] " << expression << "\n"; \
|
||||
} \
|
||||
} while (false)
|
||||
#define NFD_LOG_LINE(msg, expression) \
|
||||
::nfd::LoggerTimestamp{} << " "#msg": " << "[" << g_logger << "] " << expression
|
||||
|
||||
#define NFD_LOG(level, msg, expression) \
|
||||
do { \
|
||||
if (g_logger.isEnabled(::nfd::LOG_##level)) { \
|
||||
NFD_BOOST_LOG(g_logger.boostLogger) << NFD_LOG_LINE(msg, expression); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define NFD_LOG_TRACE(expression) NFD_LOG(TRACE, TRACE, expression)
|
||||
#define NFD_LOG_DEBUG(expression) NFD_LOG(DEBUG, DEBUG, expression)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -31,13 +31,10 @@ using ndn::mgmt::ValidateParameters;
|
||||
using ndn::mgmt::Authorization;
|
||||
|
||||
ManagerBase::ManagerBase(Dispatcher& dispatcher,
|
||||
CommandValidator& validator,
|
||||
const std::string& module)
|
||||
: m_dispatcher(dispatcher)
|
||||
, m_validator(validator)
|
||||
, m_mgmtModuleName(module)
|
||||
, m_module(module)
|
||||
{
|
||||
m_validator.addSupportedPrivilege(module);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -55,20 +52,6 @@ ManagerBase::registerNotificationStream(const std::string& verb)
|
||||
return m_dispatcher.addNotificationStream(makeRelPrefix(verb));
|
||||
}
|
||||
|
||||
void
|
||||
ManagerBase::authorize(const Name& prefix, const Interest& interest,
|
||||
const ndn::mgmt::ControlParameters* params,
|
||||
ndn::mgmt::AcceptContinuation accept,
|
||||
ndn::mgmt::RejectContinuation reject)
|
||||
{
|
||||
BOOST_ASSERT(params != nullptr);
|
||||
BOOST_ASSERT(typeid(*params) == typeid(ndn::nfd::ControlParameters));
|
||||
|
||||
m_validator.validate(interest,
|
||||
bind(&ManagerBase::extractRequester, this, interest, accept),
|
||||
bind([&] { reject(ndn::mgmt::RejectReply::STATUS403); }));
|
||||
}
|
||||
|
||||
void
|
||||
ManagerBase::extractRequester(const Interest& interest,
|
||||
ndn::mgmt::AcceptContinuation accept)
|
||||
@@ -116,5 +99,4 @@ ManagerBase::handleCommand(shared_ptr<nfd::ControlCommand> command,
|
||||
handler(*command, prefix, interest, parameters, done);
|
||||
}
|
||||
|
||||
|
||||
} // namespace nfd
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -23,16 +23,15 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_MGMT_MANAGER_BASE_HPP
|
||||
#define NFD_DAEMON_MGMT_MANAGER_BASE_HPP
|
||||
#ifndef NFD_CORE_MANAGER_BASE_HPP
|
||||
#define NFD_CORE_MANAGER_BASE_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "mgmt/command-validator.hpp"
|
||||
|
||||
#include <ndn-cxx/mgmt/dispatcher.hpp>
|
||||
#include <ndn-cxx/management/nfd-control-command.hpp>
|
||||
#include <ndn-cxx/management/nfd-control-response.hpp>
|
||||
#include <ndn-cxx/management/nfd-control-parameters.hpp>
|
||||
#include <ndn-cxx/mgmt/nfd/control-command.hpp>
|
||||
#include <ndn-cxx/mgmt/nfd/control-response.hpp>
|
||||
#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
@@ -43,10 +42,10 @@ using ndn::nfd::ControlResponse;
|
||||
using ndn::nfd::ControlParameters;
|
||||
|
||||
/**
|
||||
* @brief a collection of common functions shared by all NFD managers,
|
||||
* @brief a collection of common functions shared by all NFD managers and RIB manager,
|
||||
* such as communicating with the dispatcher and command validator.
|
||||
*/
|
||||
class ManagerBase : public noncopyable
|
||||
class ManagerBase : noncopyable
|
||||
{
|
||||
public:
|
||||
class Error : public std::runtime_error
|
||||
@@ -61,9 +60,14 @@ public:
|
||||
|
||||
public:
|
||||
ManagerBase(Dispatcher& dispatcher,
|
||||
CommandValidator& validator,
|
||||
const std::string& module);
|
||||
|
||||
const std::string&
|
||||
getModule() const
|
||||
{
|
||||
return m_module;
|
||||
}
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PROTECTED: // registrations to the dispatcher
|
||||
|
||||
// difference from mgmt::ControlCommand: accepts nfd::ControlParameters
|
||||
@@ -84,27 +88,7 @@ PUBLIC_WITH_TESTS_ELSE_PROTECTED: // registrations to the dispatcher
|
||||
ndn::mgmt::PostNotification
|
||||
registerNotificationStream(const std::string& verb);
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE: // command validation
|
||||
/**
|
||||
* @brief validate a request for ControlCommand.
|
||||
*
|
||||
* This is called by the dispatcher.
|
||||
*
|
||||
* @pre params != null
|
||||
* @pre typeid(*params) == typeid(ndn::nfd::ControlParameters)
|
||||
*
|
||||
* @param prefix the top prefix
|
||||
* @param interest a request for ControlCommand
|
||||
* @param params the parameters for ControlCommand
|
||||
* @param accept callback of successful validation, take the requester string as a argument
|
||||
* @param reject callback of failure in validation, take the action code as a argument
|
||||
*/
|
||||
void
|
||||
authorize(const Name& prefix, const Interest& interest,
|
||||
const ndn::mgmt::ControlParameters* params,
|
||||
ndn::mgmt::AcceptContinuation accept,
|
||||
ndn::mgmt::RejectContinuation reject);
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PROTECTED:
|
||||
/**
|
||||
* @brief extract a requester from a ControlCommand request
|
||||
*
|
||||
@@ -117,7 +101,13 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE: // command validation
|
||||
extractRequester(const Interest& interest,
|
||||
ndn::mgmt::AcceptContinuation accept);
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE: // helpers
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
/**
|
||||
* @return an authorization function for specified management module and verb
|
||||
*/
|
||||
virtual ndn::mgmt::Authorization
|
||||
makeAuthorization(const std::string& verb) = 0;
|
||||
|
||||
/**
|
||||
* @brief validate the @p parameters for a given @p command
|
||||
*
|
||||
@@ -150,15 +140,14 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE: // helpers
|
||||
makeRelPrefix(const std::string& verb);
|
||||
|
||||
private:
|
||||
Dispatcher& m_dispatcher;
|
||||
CommandValidator& m_validator;
|
||||
std::string m_mgmtModuleName;
|
||||
Dispatcher& m_dispatcher;
|
||||
std::string m_module;
|
||||
};
|
||||
|
||||
inline PartialName
|
||||
ManagerBase::makeRelPrefix(const std::string& verb)
|
||||
{
|
||||
return PartialName(m_mgmtModuleName).append(verb);
|
||||
return PartialName(m_module).append(verb);
|
||||
}
|
||||
|
||||
template<typename Command>
|
||||
@@ -170,11 +159,11 @@ ManagerBase::registerCommandHandler(const std::string& verb,
|
||||
|
||||
m_dispatcher.addControlCommand<ControlParameters>(
|
||||
makeRelPrefix(verb),
|
||||
bind(&ManagerBase::authorize, this, _1, _2, _3, _4, _5),
|
||||
makeAuthorization(verb),
|
||||
bind(&ManagerBase::validateParameters, cref(*command), _1),
|
||||
bind(&ManagerBase::handleCommand, command, handler, _1, _2, _3, _4));
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_MGMT_MANAGER_BASE_HPP
|
||||
#endif // NFD_CORE_MANAGER_BASE_HPP
|
||||
@@ -0,0 +1,129 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2017, 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/>.
|
||||
*/
|
||||
|
||||
#include "network-interface-predicate.hpp"
|
||||
|
||||
#include "config-file.hpp"
|
||||
#include "network-interface.hpp"
|
||||
#include "network.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
NetworkInterfacePredicate::NetworkInterfacePredicate()
|
||||
{
|
||||
this->clear();
|
||||
}
|
||||
|
||||
void
|
||||
NetworkInterfacePredicate::clear()
|
||||
{
|
||||
m_whitelist = std::set<std::string>{"*"};
|
||||
m_blacklist.clear();
|
||||
}
|
||||
|
||||
static void
|
||||
parseList(std::set<std::string>& set, const boost::property_tree::ptree& list, const std::string& section)
|
||||
{
|
||||
set.clear();
|
||||
|
||||
for (const auto& item : list) {
|
||||
if (item.first == "*") {
|
||||
// insert wildcard
|
||||
set.insert(item.first);
|
||||
}
|
||||
else if (item.first == "ifname") {
|
||||
// very basic sanity check for interface names
|
||||
auto name = item.second.get_value<std::string>();
|
||||
if (name.empty()) {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("Empty interface name in \"" + section + "\" section"));
|
||||
}
|
||||
set.insert(name);
|
||||
}
|
||||
else if (item.first == "ether") {
|
||||
// validate ethernet address
|
||||
auto addr = item.second.get_value<std::string>();
|
||||
if (ethernet::Address::fromString(addr).isNull()) {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("Malformed ether address \"" + addr +
|
||||
"\" in \"" + section + "\" section"));
|
||||
}
|
||||
set.insert(addr);
|
||||
}
|
||||
else if (item.first == "subnet") {
|
||||
// example subnet: 10.0.0.0/8
|
||||
auto cidr = item.second.get_value<std::string>();
|
||||
if (!Network::isValidCidr(cidr)) {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("Malformed subnet declaration \"" + cidr +
|
||||
"\" in \"" + section + "\" section"));
|
||||
}
|
||||
set.insert(cidr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NetworkInterfacePredicate::parseWhitelist(const boost::property_tree::ptree& list)
|
||||
{
|
||||
parseList(m_whitelist, list, "whitelist");
|
||||
}
|
||||
|
||||
void
|
||||
NetworkInterfacePredicate::parseBlacklist(const boost::property_tree::ptree& list)
|
||||
{
|
||||
parseList(m_blacklist, list, "blacklist");
|
||||
}
|
||||
|
||||
static bool
|
||||
doesMatchRule(const NetworkInterfaceInfo& netif, const std::string& rule)
|
||||
{
|
||||
// if '/' is in rule, this is a subnet, check if IP in subnet
|
||||
if (rule.find('/') != std::string::npos) {
|
||||
Network n = boost::lexical_cast<Network>(rule);
|
||||
for (const auto& addr : netif.ipv4Addresses) {
|
||||
if (n.doesContain(addr)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rule == "*" ||
|
||||
netif.name == rule ||
|
||||
netif.etherAddress.toString() == rule;
|
||||
}
|
||||
|
||||
bool
|
||||
NetworkInterfacePredicate::operator()(const NetworkInterfaceInfo& netif) const
|
||||
{
|
||||
return std::any_of(m_whitelist.begin(), m_whitelist.end(), bind(&doesMatchRule, netif, _1)) &&
|
||||
std::none_of(m_blacklist.begin(), m_blacklist.end(), bind(&doesMatchRule, netif, _1));
|
||||
}
|
||||
|
||||
bool
|
||||
NetworkInterfacePredicate::operator==(const NetworkInterfacePredicate& other) const
|
||||
{
|
||||
return this->m_whitelist == other.m_whitelist &&
|
||||
this->m_blacklist == other.m_blacklist;
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,80 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2017, 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_NETWORK_INTERFACE_PREDICATE_HPP
|
||||
#define NFD_CORE_NETWORK_INTERFACE_PREDICATE_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
class NetworkInterfaceInfo;
|
||||
|
||||
/**
|
||||
* \brief Represents a predicate to accept or reject a NetworkInterfaceInfo.
|
||||
*
|
||||
* The predicate consists of a whitelist and a blacklist. Whitelist and blacklist can contain,
|
||||
* in no particular order, interface names (e.g., ifname eth0), mac addresses
|
||||
* (e.g., ether 85:3b:4d:d3:5f:c2), subnets (e.g., subnet 192.0.2.0/24) or a wildcard (*) that matches
|
||||
* all interfaces. A NetworkInterfaceInfo is accepted if it matches any entry in the whitelist and none
|
||||
* of the entries in the blacklist.
|
||||
*/
|
||||
class NetworkInterfacePredicate
|
||||
{
|
||||
public:
|
||||
NetworkInterfacePredicate();
|
||||
|
||||
/**
|
||||
* \brief Set the whitelist to "*" and clear the blacklist
|
||||
*/
|
||||
void
|
||||
clear();
|
||||
|
||||
void
|
||||
parseWhitelist(const boost::property_tree::ptree& list);
|
||||
|
||||
void
|
||||
parseBlacklist(const boost::property_tree::ptree& list);
|
||||
|
||||
bool
|
||||
operator()(const NetworkInterfaceInfo& netif) const;
|
||||
|
||||
bool
|
||||
operator==(const NetworkInterfacePredicate& other) const;
|
||||
|
||||
bool
|
||||
operator!=(const NetworkInterfacePredicate& other) const
|
||||
{
|
||||
return !this->operator==(other);
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<std::string> m_whitelist;
|
||||
std::set<std::string> m_blacklist;
|
||||
};
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_CORE_NETWORK_INTERFACE_PREDICATE_HPP
|
||||
+96
-69
@@ -1,12 +1,12 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
@@ -25,19 +25,25 @@
|
||||
|
||||
#include "network.hpp"
|
||||
|
||||
#include <boost/utility/value_init.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
void
|
||||
Network::print(std::ostream& os) const
|
||||
Network::Network() = default;
|
||||
|
||||
Network::Network(const boost::asio::ip::address& minAddress,
|
||||
const boost::asio::ip::address& maxAddress)
|
||||
: m_minAddress(minAddress)
|
||||
, m_maxAddress(maxAddress)
|
||||
{
|
||||
os << m_minAddress << " <-> " << m_maxAddress;
|
||||
}
|
||||
|
||||
const Network&
|
||||
Network::getMaxRangeV4()
|
||||
{
|
||||
using boost::asio::ip::address_v4;
|
||||
static Network range = Network(address_v4(0), address_v4(0xFFFFFFFF));
|
||||
static Network range{address_v4{}, address_v4{0xffffffff}};
|
||||
return range;
|
||||
}
|
||||
|
||||
@@ -47,86 +53,107 @@ Network::getMaxRangeV6()
|
||||
using boost::asio::ip::address_v6;
|
||||
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 = Network(address_v6(), address_v6(maxV6));
|
||||
static Network range{address_v6{}, address_v6{maxV6}};
|
||||
return range;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
bool
|
||||
Network::isValidCidr(const std::string& cidr)
|
||||
{
|
||||
auto pos = cidr.find('/');
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::system::error_code invalidIp;
|
||||
boost::asio::ip::address_v4::from_string(cidr.substr(0, pos), invalidIp);
|
||||
if (invalidIp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto prefixLenStr = cidr.substr(pos + 1);
|
||||
if (!std::all_of(prefixLenStr.begin(), prefixLenStr.end(), ::isdigit)) {
|
||||
return false;
|
||||
}
|
||||
int prefixLen = -1;
|
||||
try {
|
||||
prefixLen = boost::lexical_cast<int>(prefixLenStr);
|
||||
}
|
||||
catch (const boost::bad_lexical_cast&) {
|
||||
return false;
|
||||
}
|
||||
if (prefixLen < 0 || prefixLen > 32) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const Network& network)
|
||||
{
|
||||
network.print(os);
|
||||
return os;
|
||||
return os << network.m_minAddress << " <-> " << network.m_maxAddress;
|
||||
}
|
||||
|
||||
std::istream&
|
||||
operator>>(std::istream& is, Network& network)
|
||||
{
|
||||
using namespace boost::asio;
|
||||
namespace ip = boost::asio::ip;
|
||||
|
||||
std::string networkStr;
|
||||
is >> networkStr;
|
||||
|
||||
size_t position = networkStr.find('/');
|
||||
if (position == std::string::npos)
|
||||
{
|
||||
network.m_minAddress = ip::address::from_string(networkStr);
|
||||
network.m_maxAddress = ip::address::from_string(networkStr);
|
||||
if (position == std::string::npos) {
|
||||
network.m_minAddress = ip::address::from_string(networkStr);
|
||||
network.m_maxAddress = ip::address::from_string(networkStr);
|
||||
}
|
||||
else {
|
||||
ip::address address = ip::address::from_string(networkStr.substr(0, position));
|
||||
size_t mask = boost::lexical_cast<size_t>(networkStr.substr(position+1));
|
||||
|
||||
if (address.is_v4()) {
|
||||
ip::address_v4::bytes_type maskBytes = boost::initialized_value;
|
||||
for (size_t i = 0; i < mask; i++) {
|
||||
size_t byteId = i / 8;
|
||||
size_t bitIndex = 7 - i % 8;
|
||||
maskBytes[byteId] |= (1 << bitIndex);
|
||||
}
|
||||
|
||||
ip::address_v4::bytes_type addressBytes = address.to_v4().to_bytes();
|
||||
ip::address_v4::bytes_type min;
|
||||
ip::address_v4::bytes_type max;
|
||||
|
||||
for (size_t i = 0; i < addressBytes.size(); i++) {
|
||||
min[i] = addressBytes[i] & maskBytes[i];
|
||||
max[i] = addressBytes[i] | ~(maskBytes[i]);
|
||||
}
|
||||
|
||||
network.m_minAddress = ip::address_v4(min);
|
||||
network.m_maxAddress = ip::address_v4(max);
|
||||
}
|
||||
else
|
||||
{
|
||||
ip::address address = ip::address::from_string(networkStr.substr(0, position));
|
||||
size_t mask = boost::lexical_cast<size_t>(networkStr.substr(position+1));
|
||||
else {
|
||||
ip::address_v6::bytes_type maskBytes = boost::initialized_value;
|
||||
for (size_t i = 0; i < mask; i++) {
|
||||
size_t byteId = i / 8;
|
||||
size_t bitIndex = 7 - i % 8;
|
||||
maskBytes[byteId] |= (1 << bitIndex);
|
||||
}
|
||||
|
||||
if (address.is_v4())
|
||||
{
|
||||
ip::address_v4::bytes_type maskBytes = boost::initialized_value;
|
||||
for (size_t i = 0; i < mask; i++)
|
||||
{
|
||||
size_t byteId = i / 8;
|
||||
size_t bitIndex = 7 - i % 8;
|
||||
maskBytes[byteId] |= (1 << bitIndex);
|
||||
}
|
||||
ip::address_v6::bytes_type addressBytes = address.to_v6().to_bytes();
|
||||
ip::address_v6::bytes_type min;
|
||||
ip::address_v6::bytes_type max;
|
||||
|
||||
ip::address_v4::bytes_type addressBytes = address.to_v4().to_bytes();
|
||||
ip::address_v4::bytes_type min;
|
||||
ip::address_v4::bytes_type max;
|
||||
for (size_t i = 0; i < addressBytes.size(); i++) {
|
||||
min[i] = addressBytes[i] & maskBytes[i];
|
||||
max[i] = addressBytes[i] | ~(maskBytes[i]);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < addressBytes.size(); i++)
|
||||
{
|
||||
min[i] = addressBytes[i] & maskBytes[i];
|
||||
max[i] = addressBytes[i] | ~(maskBytes[i]);
|
||||
}
|
||||
|
||||
network.m_minAddress = ip::address_v4(min);
|
||||
network.m_maxAddress = ip::address_v4(max);
|
||||
}
|
||||
else
|
||||
{
|
||||
ip::address_v6::bytes_type maskBytes = boost::initialized_value;
|
||||
for (size_t i = 0; i < mask; i++)
|
||||
{
|
||||
size_t byteId = i / 8;
|
||||
size_t bitIndex = 7 - i % 8;
|
||||
maskBytes[byteId] |= (1 << bitIndex);
|
||||
}
|
||||
|
||||
ip::address_v6::bytes_type addressBytes = address.to_v6().to_bytes();
|
||||
ip::address_v6::bytes_type min;
|
||||
ip::address_v6::bytes_type max;
|
||||
|
||||
for (size_t i = 0; i < addressBytes.size(); i++)
|
||||
{
|
||||
min[i] = addressBytes[i] & maskBytes[i];
|
||||
max[i] = addressBytes[i] | ~(maskBytes[i]);
|
||||
}
|
||||
|
||||
network.m_minAddress = ip::address_v6(min);
|
||||
network.m_maxAddress = ip::address_v6(max);
|
||||
}
|
||||
network.m_minAddress = ip::address_v6(min);
|
||||
network.m_maxAddress = ip::address_v6(max);
|
||||
}
|
||||
}
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
|
||||
+17
-25
@@ -1,12 +1,12 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
@@ -26,33 +26,22 @@
|
||||
#ifndef NFD_CORE_NETWORK_HPP
|
||||
#define NFD_CORE_NETWORK_HPP
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/utility/value_init.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include "common.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
class Network
|
||||
{
|
||||
public:
|
||||
Network()
|
||||
{
|
||||
}
|
||||
Network();
|
||||
|
||||
Network(const boost::asio::ip::address& minAddress,
|
||||
const boost::asio::ip::address& maxAddress)
|
||||
: m_minAddress(minAddress)
|
||||
, m_maxAddress(maxAddress)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
print(std::ostream& os) const;
|
||||
const boost::asio::ip::address& maxAddress);
|
||||
|
||||
bool
|
||||
doesContain(const boost::asio::ip::address& address) const
|
||||
{
|
||||
return (m_minAddress <= address && address <= m_maxAddress);
|
||||
return m_minAddress <= address && address <= m_maxAddress;
|
||||
}
|
||||
|
||||
static const Network&
|
||||
@@ -61,6 +50,9 @@ public:
|
||||
static const Network&
|
||||
getMaxRangeV6();
|
||||
|
||||
static bool
|
||||
isValidCidr(const std::string& cidr);
|
||||
|
||||
bool
|
||||
operator==(const Network& rhs) const
|
||||
{
|
||||
@@ -77,11 +69,11 @@ private:
|
||||
boost::asio::ip::address m_minAddress;
|
||||
boost::asio::ip::address m_maxAddress;
|
||||
|
||||
friend std::istream&
|
||||
operator>>(std::istream& is, Network& network);
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& os, const Network& network);
|
||||
|
||||
friend std::istream&
|
||||
operator>>(std::istream& is, Network& network);
|
||||
};
|
||||
|
||||
std::ostream&
|
||||
|
||||
+7
-13
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -28,21 +28,15 @@
|
||||
|
||||
namespace nfd {
|
||||
|
||||
static boost::thread_specific_ptr<boost::random::mt19937> g_rng;
|
||||
|
||||
boost::random::mt19937&
|
||||
std::mt19937&
|
||||
getGlobalRng()
|
||||
{
|
||||
if (g_rng.get() == nullptr) {
|
||||
g_rng.reset(new boost::random::mt19937());
|
||||
static boost::thread_specific_ptr<std::mt19937> rng;
|
||||
if (rng.get() == nullptr) {
|
||||
std::random_device rd;
|
||||
rng.reset(new std::mt19937(rd()));
|
||||
}
|
||||
return *g_rng;
|
||||
}
|
||||
|
||||
void
|
||||
resetGlobalRng()
|
||||
{
|
||||
g_rng.reset();
|
||||
return *rng;
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
+16
-14
@@ -1,12 +1,12 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
@@ -24,24 +24,26 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file declares the global random number generator
|
||||
* All random numbers in NFD should use this global random number generator,
|
||||
* so that the generator can be properly seeded when necessary.
|
||||
* This file declares the global pseudorandom number generator (PRNG).
|
||||
*
|
||||
* This random number generator is not suitable for security purposes;
|
||||
* security-critical code should use CryptoPP random number generator instead.
|
||||
* All random numbers generated by NFD should use this global generator,
|
||||
* so that it can be properly seeded when necessary.
|
||||
*
|
||||
* This PRNG is not suitable for security purposes; security-critical
|
||||
* code must use a cryptographically secure PRNG, such as those provided
|
||||
* by OpenSSL and Crypto++.
|
||||
*/
|
||||
|
||||
#ifndef NFD_CORE_RANDOM_HPP
|
||||
#define NFD_CORE_RANDOM_HPP
|
||||
|
||||
#include <boost/random/mersenne_twister.hpp>
|
||||
#include <random>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/** \return the global random number generator instance
|
||||
*/
|
||||
boost::random::mt19937&
|
||||
std::mt19937&
|
||||
getGlobalRng();
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
/* -*- 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_SEGMENT_PUBLISHER_HPP
|
||||
#define NFD_CORE_SEGMENT_PUBLISHER_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#include <ndn-cxx/encoding/encoding-buffer.hpp>
|
||||
#include <ndn-cxx/security/key-chain.hpp>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/** \brief provides a publisher of Status Dataset or other segmented octet stream
|
||||
* \sa http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
|
||||
*/
|
||||
template <class FaceBase>
|
||||
class SegmentPublisher : noncopyable
|
||||
{
|
||||
public:
|
||||
SegmentPublisher(FaceBase& face,
|
||||
const Name& prefix,
|
||||
ndn::KeyChain& keyChain,
|
||||
const time::milliseconds& freshnessPeriod = getDefaultFreshness())
|
||||
: m_face(face)
|
||||
, m_prefix(prefix)
|
||||
, m_keyChain(keyChain)
|
||||
, m_freshnessPeriod(freshnessPeriod)
|
||||
{
|
||||
}
|
||||
|
||||
virtual
|
||||
~SegmentPublisher()
|
||||
{
|
||||
}
|
||||
|
||||
static size_t
|
||||
getMaxSegmentSize()
|
||||
{
|
||||
static const size_t MAX_SEGMENT_SIZE = ndn::MAX_NDN_PACKET_SIZE >> 1;
|
||||
return MAX_SEGMENT_SIZE;
|
||||
}
|
||||
|
||||
static constexpr time::milliseconds
|
||||
getDefaultFreshness()
|
||||
{
|
||||
return time::milliseconds(1000);
|
||||
}
|
||||
|
||||
void
|
||||
publish()
|
||||
{
|
||||
ndn::EncodingBuffer buffer;
|
||||
generate(buffer);
|
||||
|
||||
const uint8_t* rawBuffer = buffer.buf();
|
||||
const uint8_t* segmentBegin = rawBuffer;
|
||||
const uint8_t* end = rawBuffer + buffer.size();
|
||||
|
||||
Name segmentPrefix(m_prefix);
|
||||
segmentPrefix.appendVersion();
|
||||
|
||||
uint64_t segmentNo = 0;
|
||||
do {
|
||||
const uint8_t* segmentEnd = segmentBegin + getMaxSegmentSize();
|
||||
if (segmentEnd > end) {
|
||||
segmentEnd = end;
|
||||
}
|
||||
|
||||
Name segmentName(segmentPrefix);
|
||||
segmentName.appendSegment(segmentNo);
|
||||
|
||||
shared_ptr<Data> data = make_shared<Data>(segmentName);
|
||||
data->setContent(segmentBegin, segmentEnd - segmentBegin);
|
||||
data->setFreshnessPeriod(m_freshnessPeriod);
|
||||
|
||||
segmentBegin = segmentEnd;
|
||||
if (segmentBegin >= end) {
|
||||
data->setFinalBlockId(segmentName[-1]);
|
||||
}
|
||||
|
||||
publishSegment(data);
|
||||
++segmentNo;
|
||||
} while (segmentBegin < end);
|
||||
}
|
||||
|
||||
protected:
|
||||
/** \brief In a derived class, write the octets into outBuffer.
|
||||
*/
|
||||
virtual size_t
|
||||
generate(ndn::EncodingBuffer& outBuffer) = 0;
|
||||
|
||||
private:
|
||||
void
|
||||
publishSegment(shared_ptr<Data>& data)
|
||||
{
|
||||
m_keyChain.sign(*data);
|
||||
m_face.put(*data);
|
||||
}
|
||||
|
||||
private:
|
||||
FaceBase& m_face;
|
||||
const Name m_prefix;
|
||||
ndn::KeyChain& m_keyChain;
|
||||
const time::milliseconds m_freshnessPeriod;
|
||||
};
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_CORE_SEGMENT_PUBLISHER_HPP
|
||||
@@ -1,12 +1,12 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
@@ -23,8 +23,8 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_VERSION_HPP
|
||||
#define NFD_VERSION_HPP
|
||||
#ifndef NFD_CORE_VERSION_HPP
|
||||
#define NFD_CORE_VERSION_HPP
|
||||
|
||||
namespace nfd {
|
||||
|
||||
@@ -71,4 +71,4 @@ namespace nfd {
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_VERSION_HPP
|
||||
#endif // NFD_CORE_VERSION_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -41,9 +41,14 @@ typedef function<void(const shared_ptr<Face>& newFace)> FaceCreatedCallback;
|
||||
* \brief Prototype for the callback that is invoked when the face
|
||||
* fails to be created
|
||||
*/
|
||||
typedef function<void(const std::string& reason)> FaceCreationFailedCallback;
|
||||
|
||||
typedef function<void(uint32_t status, const std::string& reason)> FaceCreationFailedCallback;
|
||||
|
||||
/** \brief represent a channel that communicates on a local endpoint
|
||||
* \sa FaceSystem
|
||||
*
|
||||
* A channel can listen on a local endpoint and initiate outgoing connection from a local endpoint.
|
||||
* A channel creates Face objects and retains shared ownership of them.
|
||||
*/
|
||||
class Channel : noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -62,10 +62,10 @@ public:
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
doClose() DECL_OVERRIDE;
|
||||
doClose() override;
|
||||
|
||||
virtual void
|
||||
doSend(Transport::Packet&& packet) DECL_OVERRIDE;
|
||||
doSend(Transport::Packet&& packet) override;
|
||||
|
||||
void
|
||||
handleSend(const boost::system::error_code& error,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,42 +26,112 @@
|
||||
#include "ethernet-factory.hpp"
|
||||
#include "ethernet-transport.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "core/logger.hpp"
|
||||
#include <boost/range/adaptors.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
shared_ptr<Face>
|
||||
EthernetFactory::createMulticastFace(const NetworkInterfaceInfo& interface,
|
||||
const ethernet::Address& address)
|
||||
NFD_LOG_INIT("EthernetFactory");
|
||||
NFD_REGISTER_PROTOCOL_FACTORY(EthernetFactory);
|
||||
|
||||
const std::string&
|
||||
EthernetFactory::getId()
|
||||
{
|
||||
if (!address.isMulticast())
|
||||
BOOST_THROW_EXCEPTION(Error(address.toString() + " is not a multicast address"));
|
||||
static std::string id("ether");
|
||||
return id;
|
||||
}
|
||||
|
||||
auto face = findMulticastFace(interface.name, address);
|
||||
if (face)
|
||||
return face;
|
||||
|
||||
face::GenericLinkService::Options opts;
|
||||
opts.allowFragmentation = true;
|
||||
opts.allowReassembly = true;
|
||||
void
|
||||
EthernetFactory::processConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context)
|
||||
{
|
||||
// ether
|
||||
// {
|
||||
// mcast yes
|
||||
// mcast_group 01:00:5E:00:17:AA
|
||||
// whitelist
|
||||
// {
|
||||
// *
|
||||
// }
|
||||
// blacklist
|
||||
// {
|
||||
// }
|
||||
// }
|
||||
|
||||
auto linkService = make_unique<face::GenericLinkService>(opts);
|
||||
auto transport = make_unique<face::EthernetTransport>(interface, address);
|
||||
face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
MulticastConfig mcastConfig;
|
||||
|
||||
auto key = std::make_pair(interface.name, address);
|
||||
m_multicastFaces[key] = face;
|
||||
connectFaceClosedSignal(*face, [this, key] { m_multicastFaces.erase(key); });
|
||||
if (configSection) {
|
||||
// face_system.ether.mcast defaults to 'yes' but only if face_system.ether section is present
|
||||
mcastConfig.isEnabled = true;
|
||||
|
||||
return face;
|
||||
for (const auto& pair : *configSection) {
|
||||
const std::string& key = pair.first;
|
||||
const ConfigSection& value = pair.second;
|
||||
|
||||
if (key == "mcast") {
|
||||
mcastConfig.isEnabled = ConfigFile::parseYesNo(pair, "ether");
|
||||
}
|
||||
else if (key == "mcast_group") {
|
||||
const std::string& valueStr = value.get_value<std::string>();
|
||||
mcastConfig.group = ethernet::Address::fromString(valueStr);
|
||||
if (mcastConfig.group.isNull()) {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("face_system.ether.mcast_group: '" +
|
||||
valueStr + "' cannot be parsed as an Ethernet address"));
|
||||
}
|
||||
else if (!mcastConfig.group.isMulticast()) {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("face_system.ether.mcast_group: '" +
|
||||
valueStr + "' is not a multicast address"));
|
||||
}
|
||||
}
|
||||
else if (key == "whitelist") {
|
||||
mcastConfig.netifPredicate.parseWhitelist(value);
|
||||
}
|
||||
else if (key == "blacklist") {
|
||||
mcastConfig.netifPredicate.parseBlacklist(value);
|
||||
}
|
||||
else {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system.ether." + key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!context.isDryRun) {
|
||||
if (m_mcastConfig.isEnabled != mcastConfig.isEnabled) {
|
||||
if (mcastConfig.isEnabled) {
|
||||
NFD_LOG_INFO("enabling multicast on " << mcastConfig.group);
|
||||
}
|
||||
else {
|
||||
NFD_LOG_INFO("disabling multicast");
|
||||
}
|
||||
}
|
||||
else if (m_mcastConfig.group != mcastConfig.group) {
|
||||
NFD_LOG_INFO("changing multicast group from " << m_mcastConfig.group <<
|
||||
" to " << mcastConfig.group);
|
||||
}
|
||||
else if (m_mcastConfig.netifPredicate != mcastConfig.netifPredicate) {
|
||||
NFD_LOG_INFO("changing whitelist/blacklist");
|
||||
}
|
||||
else {
|
||||
// There's no configuration change, but we still need to re-apply configuration because
|
||||
// netifs may have changed.
|
||||
}
|
||||
|
||||
m_mcastConfig = mcastConfig;
|
||||
this->applyConfig(context);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFactory::createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed)
|
||||
const FaceCreationFailedCallback& onFailure)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(Error("EthernetFactory does not support 'createFace' operation"));
|
||||
onFailure(406, "Unsupported protocol");
|
||||
}
|
||||
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
@@ -71,14 +141,75 @@ EthernetFactory::getChannels() const
|
||||
}
|
||||
|
||||
shared_ptr<Face>
|
||||
EthernetFactory::findMulticastFace(const std::string& interfaceName,
|
||||
const ethernet::Address& address) const
|
||||
EthernetFactory::createMulticastFace(const NetworkInterfaceInfo& netif,
|
||||
const ethernet::Address& address)
|
||||
{
|
||||
auto i = m_multicastFaces.find({interfaceName, address});
|
||||
if (i != m_multicastFaces.end())
|
||||
return i->second;
|
||||
else
|
||||
return nullptr;
|
||||
BOOST_ASSERT(address.isMulticast());
|
||||
|
||||
auto key = std::make_pair(netif.name, address);
|
||||
auto found = m_mcastFaces.find(key);
|
||||
if (found != m_mcastFaces.end()) {
|
||||
return found->second;
|
||||
}
|
||||
|
||||
face::GenericLinkService::Options opts;
|
||||
opts.allowFragmentation = true;
|
||||
opts.allowReassembly = true;
|
||||
|
||||
auto linkService = make_unique<face::GenericLinkService>(opts);
|
||||
auto transport = make_unique<face::EthernetTransport>(netif, address);
|
||||
auto face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
|
||||
m_mcastFaces[key] = face;
|
||||
connectFaceClosedSignal(*face, [this, key] { m_mcastFaces.erase(key); });
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFactory::applyConfig(const FaceSystem::ConfigContext& context)
|
||||
{
|
||||
// collect old faces
|
||||
std::set<shared_ptr<Face>> oldFaces;
|
||||
boost::copy(m_mcastFaces | boost::adaptors::map_values,
|
||||
std::inserter(oldFaces, oldFaces.end()));
|
||||
|
||||
if (m_mcastConfig.isEnabled) {
|
||||
// determine interfaces on which faces should be created or retained
|
||||
auto capableNetifs = context.listNetifs() |
|
||||
boost::adaptors::filtered([this] (const NetworkInterfaceInfo& netif) {
|
||||
return netif.isUp() && netif.isMulticastCapable() &&
|
||||
m_mcastConfig.netifPredicate(netif);
|
||||
});
|
||||
|
||||
// create faces
|
||||
for (const auto& netif : capableNetifs) {
|
||||
shared_ptr<Face> face;
|
||||
try {
|
||||
face = this->createMulticastFace(netif, m_mcastConfig.group);
|
||||
}
|
||||
catch (const EthernetTransport::Error& e) {
|
||||
NFD_LOG_ERROR("Cannot create Ethernet multicast face on " << netif.name << ": " <<
|
||||
e.what() << ", continuing");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (face->getId() == face::INVALID_FACEID) {
|
||||
// new face: register with forwarding
|
||||
context.addFace(face);
|
||||
}
|
||||
else {
|
||||
// existing face: don't destroy
|
||||
oldFaces.erase(face);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// destroy old faces that are not needed in new configuration
|
||||
for (const auto& face : oldFaces) {
|
||||
face->close();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -27,85 +27,69 @@
|
||||
#define NFD_DAEMON_FACE_ETHERNET_FACTORY_HPP
|
||||
|
||||
#include "protocol-factory.hpp"
|
||||
#include "core/network-interface.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief protocol factory for Ethernet
|
||||
*
|
||||
* Currently, only Ethernet multicast is supported.
|
||||
*/
|
||||
class EthernetFactory : public ProtocolFactory
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Exception of EthernetFactory
|
||||
static const std::string&
|
||||
getId();
|
||||
|
||||
/** \brief process face_system.ether config section
|
||||
*/
|
||||
class Error : public ProtocolFactory::Error
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& what)
|
||||
: ProtocolFactory::Error(what)
|
||||
{
|
||||
}
|
||||
};
|
||||
void
|
||||
processConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context) override;
|
||||
|
||||
typedef std::map<std::pair<std::string, ethernet::Address>,
|
||||
shared_ptr<Face>> MulticastFaceMap;
|
||||
|
||||
/**
|
||||
* \brief Create an EthernetFace to communicate with the given multicast group
|
||||
*
|
||||
* If this method is called twice with the same interface and group, only
|
||||
* one face will be created. Instead, the second call will just retrieve
|
||||
* the existing face.
|
||||
*
|
||||
* \param interface Local network interface
|
||||
* \param address Ethernet broadcast/multicast destination address
|
||||
*
|
||||
* \returns always a valid shared pointer to an EthernetFace object,
|
||||
* an exception will be thrown if the creation fails
|
||||
*
|
||||
* \throws EthernetFactory::Error or EthernetTransport::Error
|
||||
/** \brief unicast face creation is not supported and will always fail
|
||||
*/
|
||||
shared_ptr<Face>
|
||||
createMulticastFace(const NetworkInterfaceInfo& interface,
|
||||
const ethernet::Address& address);
|
||||
|
||||
/**
|
||||
* \brief Get map of configured multicast faces
|
||||
*/
|
||||
const MulticastFaceMap&
|
||||
getMulticastFaces() const;
|
||||
|
||||
public: // from ProtocolFactory
|
||||
virtual void
|
||||
void
|
||||
createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed) DECL_OVERRIDE;
|
||||
const FaceCreationFailedCallback& onFailure) override;
|
||||
|
||||
virtual std::vector<shared_ptr<const Channel>>
|
||||
getChannels() const DECL_OVERRIDE;
|
||||
/** \return empty container, because Ethernet unicast is not supported
|
||||
*/
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
getChannels() const override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* \brief Look up EthernetFace using specified interface and address
|
||||
*
|
||||
* \returns shared pointer to the existing EthernetFace object
|
||||
* or nullptr when such face does not exist
|
||||
/** \brief Create a face to communicate on the given Ethernet multicast group
|
||||
* \param netif local network interface
|
||||
* \param group multicast group address
|
||||
* \note Calling this method again with same arguments returns the existing face on the given
|
||||
* interface and multicast group rather than creating a new one.
|
||||
* \throw EthernetTransport::Error transport creation fails
|
||||
*/
|
||||
shared_ptr<Face>
|
||||
findMulticastFace(const std::string& interfaceName,
|
||||
const ethernet::Address& address) const;
|
||||
createMulticastFace(const NetworkInterfaceInfo& netif, const ethernet::Address& group);
|
||||
|
||||
void
|
||||
applyConfig(const FaceSystem::ConfigContext& context);
|
||||
|
||||
private:
|
||||
MulticastFaceMap m_multicastFaces;
|
||||
struct MulticastConfig
|
||||
{
|
||||
bool isEnabled = false;
|
||||
ethernet::Address group = ethernet::getDefaultMulticastAddress();
|
||||
NetworkInterfacePredicate netifPredicate;
|
||||
};
|
||||
|
||||
MulticastConfig m_mcastConfig;
|
||||
|
||||
/// (ifname, group) => face
|
||||
std::map<std::pair<std::string, ethernet::Address>, shared_ptr<Face>> m_mcastFaces;
|
||||
};
|
||||
|
||||
inline const EthernetFactory::MulticastFaceMap&
|
||||
EthernetFactory::getMulticastFaces() const
|
||||
{
|
||||
return m_multicastFaces;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_ETHERNET_FACTORY_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -120,14 +120,6 @@ EthernetTransport::EthernetTransport(const NetworkInterfaceInfo& interface,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void EthernetTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
|
||||
{
|
||||
if (newPersistency != ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
|
||||
BOOST_THROW_EXCEPTION(
|
||||
std::invalid_argument("EthernetTransport supports only FACE_PERSISTENCY_PERMANENT"));
|
||||
}
|
||||
}
|
||||
|
||||
void EthernetTransport::doSend(Transport::Packet&& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
@@ -374,14 +366,15 @@ EthernetTransport::processIncomingPacket(const pcap_pkthdr* header, const uint8_
|
||||
void
|
||||
EthernetTransport::processErrorCode(const boost::system::error_code& error)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
if (getState() == TransportState::CLOSING ||
|
||||
// boost::asio::error::operation_aborted must be checked first. In that situation, the Transport
|
||||
// may already have been destructed, and it's unsafe to call getState() or do logging.
|
||||
if (error == boost::asio::error::operation_aborted ||
|
||||
getState() == TransportState::CLOSING ||
|
||||
getState() == TransportState::FAILED ||
|
||||
getState() == TransportState::CLOSED ||
|
||||
error == boost::asio::error::operation_aborted)
|
||||
getState() == TransportState::CLOSED) {
|
||||
// transport is shutting down, ignore any errors
|
||||
return;
|
||||
}
|
||||
|
||||
NFD_LOG_FACE_WARN("Receive operation failed: " << error.message());
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,7 +26,7 @@
|
||||
#ifndef NFD_DAEMON_FACE_ETHERNET_TRANSPORT_HPP
|
||||
#define NFD_DAEMON_FACE_ETHERNET_TRANSPORT_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "core/common.hpp"
|
||||
#include "transport.hpp"
|
||||
#include "core/network-interface.hpp"
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace face {
|
||||
/**
|
||||
* \brief A multicast Transport that uses raw Ethernet II frames
|
||||
*/
|
||||
class EthernetTransport DECL_CLASS_FINAL : public Transport
|
||||
class EthernetTransport final : public Transport
|
||||
{
|
||||
public:
|
||||
class Error : public std::runtime_error
|
||||
@@ -65,15 +65,12 @@ public:
|
||||
const ethernet::Address& mcastAddress);
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
|
||||
|
||||
virtual void
|
||||
doClose() DECL_FINAL;
|
||||
void
|
||||
doClose() final;
|
||||
|
||||
private:
|
||||
virtual void
|
||||
doSend(Transport::Packet&& packet) DECL_FINAL;
|
||||
void
|
||||
doSend(Transport::Packet&& packet) final;
|
||||
|
||||
/**
|
||||
* @brief Allocates and initializes a libpcap context for live capture
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2017, 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/>.
|
||||
*/
|
||||
|
||||
#include "face-system.hpp"
|
||||
#include "protocol-factory.hpp"
|
||||
#include "core/logger.hpp"
|
||||
#include "fw/face-table.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INIT("FaceSystem");
|
||||
|
||||
FaceSystem::FaceSystem(FaceTable& faceTable)
|
||||
: m_faceTable(faceTable)
|
||||
{
|
||||
for (const std::string& id : ProtocolFactory::listRegistered()) {
|
||||
NFD_LOG_TRACE("creating factory " << id);
|
||||
m_factories[id] = ProtocolFactory::create(id);
|
||||
}
|
||||
}
|
||||
|
||||
FaceSystem::~FaceSystem() = default;
|
||||
|
||||
std::set<const ProtocolFactory*>
|
||||
FaceSystem::listProtocolFactories() const
|
||||
{
|
||||
std::set<const ProtocolFactory*> factories;
|
||||
for (const auto& p : m_factories) {
|
||||
factories.insert(p.second.get());
|
||||
}
|
||||
return factories;
|
||||
}
|
||||
|
||||
ProtocolFactory*
|
||||
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)
|
||||
{
|
||||
auto found = m_factoryByScheme.find(scheme);
|
||||
return found == m_factoryByScheme.end() ? nullptr : found->second;
|
||||
}
|
||||
|
||||
void
|
||||
FaceSystem::setConfigFile(ConfigFile& configFile)
|
||||
{
|
||||
configFile.addSectionHandler("face_system", bind(&FaceSystem::processConfig, this, _1, _2, _3));
|
||||
}
|
||||
|
||||
void
|
||||
FaceSystem::processConfig(const ConfigSection& configSection, bool isDryRun, const std::string& filename)
|
||||
{
|
||||
ConfigContext context;
|
||||
context.isDryRun = isDryRun;
|
||||
context.addFace = bind(&FaceTable::add, &m_faceTable, _1);
|
||||
context.m_netifs = listNetworkInterfaces();
|
||||
|
||||
// process sections in protocol 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 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 std::string& scheme : oldProvidedSchemes) {
|
||||
m_factoryByScheme.erase(scheme);
|
||||
NFD_LOG_TRACE("factory " << sectionName <<
|
||||
" no longer provides " << scheme << " FaceUri scheme");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// process other sections
|
||||
std::set<std::string> seenSections;
|
||||
for (const auto& pair : configSection) {
|
||||
const std::string& sectionName = pair.first;
|
||||
// const ConfigSection& subSection = pair.second;
|
||||
|
||||
if (!seenSections.insert(sectionName).second) {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("Duplicate section face_system." + sectionName));
|
||||
}
|
||||
|
||||
if (m_factories.count(sectionName) > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
///\todo #3521 nicfaces
|
||||
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system." + sectionName));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,124 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2017, 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_DAEMON_FACE_FACE_SYSTEM_HPP
|
||||
#define NFD_DAEMON_FACE_FACE_SYSTEM_HPP
|
||||
|
||||
#include "channel.hpp"
|
||||
#include "core/config-file.hpp"
|
||||
#include "core/network-interface.hpp"
|
||||
#include "core/network-interface-predicate.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
class FaceTable;
|
||||
|
||||
namespace face {
|
||||
|
||||
class ProtocolFactory;
|
||||
|
||||
/** \brief entry point of the face system
|
||||
*
|
||||
* 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
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
FaceSystem(FaceTable& faceTable);
|
||||
|
||||
~FaceSystem();
|
||||
|
||||
/** \return ProtocolFactory objects owned by the FaceSystem
|
||||
*/
|
||||
std::set<const ProtocolFactory*>
|
||||
listProtocolFactories() const;
|
||||
|
||||
/** \return ProtocolFactory for the specified registered factory id or nullptr if not found
|
||||
*/
|
||||
ProtocolFactory*
|
||||
getFactoryById(const std::string& id);
|
||||
|
||||
/** \return ProtocolFactory for the specified FaceUri scheme or nullptr if not found
|
||||
*/
|
||||
ProtocolFactory*
|
||||
getFactoryByScheme(const std::string& scheme);
|
||||
|
||||
/** \brief register handler for face_system section of NFD configuration file
|
||||
*/
|
||||
void
|
||||
setConfigFile(ConfigFile& configFile);
|
||||
|
||||
/** \brief context for processing a config section in ProtocolFactory
|
||||
*/
|
||||
class ConfigContext : noncopyable
|
||||
{
|
||||
public:
|
||||
const std::vector<NetworkInterfaceInfo>&
|
||||
listNetifs() const
|
||||
{
|
||||
///\todo get netifs from NetworkMonitor
|
||||
return m_netifs;
|
||||
}
|
||||
|
||||
public:
|
||||
bool isDryRun;
|
||||
FaceCreatedCallback addFace;
|
||||
///\todo add NetworkMonitor
|
||||
|
||||
private:
|
||||
std::vector<NetworkInterfaceInfo> m_netifs;
|
||||
|
||||
friend class FaceSystem;
|
||||
};
|
||||
|
||||
private:
|
||||
void
|
||||
processConfig(const ConfigSection& configSection, bool isDryRun,
|
||||
const std::string& filename);
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
/** \brief config section name => protocol factory
|
||||
*/
|
||||
std::map<std::string, unique_ptr<ProtocolFactory>> m_factories;
|
||||
|
||||
private:
|
||||
/** \brief scheme => protocol factory
|
||||
*
|
||||
* The same protocol factory may be available under multiple schemes.
|
||||
*/
|
||||
std::map<std::string, ProtocolFactory*> m_factoryByScheme;
|
||||
|
||||
FaceTable& m_faceTable;
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
|
||||
using face::FaceSystem;
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_FACE_SYSTEM_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -66,7 +66,7 @@ typedef TransportState FaceState;
|
||||
*/
|
||||
class Face
|
||||
#ifndef WITH_TESTS
|
||||
DECL_CLASS_FINAL
|
||||
final
|
||||
#endif
|
||||
: public enable_shared_from_this<Face>, noncopyable
|
||||
{
|
||||
@@ -74,10 +74,10 @@ public:
|
||||
Face(unique_ptr<LinkService> service, unique_ptr<Transport> transport);
|
||||
|
||||
LinkService*
|
||||
getLinkService();
|
||||
getLinkService() const;
|
||||
|
||||
Transport*
|
||||
getTransport();
|
||||
getTransport() const;
|
||||
|
||||
public: // upper interface connected to forwarding
|
||||
/** \brief sends Interest on Face
|
||||
@@ -189,13 +189,13 @@ private:
|
||||
};
|
||||
|
||||
inline LinkService*
|
||||
Face::getLinkService()
|
||||
Face::getLinkService() const
|
||||
{
|
||||
return m_service.get();
|
||||
}
|
||||
|
||||
inline Transport*
|
||||
Face::getTransport()
|
||||
Face::getTransport() const
|
||||
{
|
||||
return m_transport.get();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "generic-link-service.hpp"
|
||||
#include <ndn-cxx/lp/tags.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
@@ -57,9 +58,7 @@ GenericLinkService::doSendInterest(const Interest& interest)
|
||||
{
|
||||
lp::Packet lpPacket(interest.wireEncode());
|
||||
|
||||
if (m_options.allowLocalFields) {
|
||||
encodeLocalFields(interest, lpPacket);
|
||||
}
|
||||
encodeLpFields(interest, lpPacket);
|
||||
|
||||
this->sendNetPacket(std::move(lpPacket));
|
||||
}
|
||||
@@ -69,9 +68,7 @@ GenericLinkService::doSendData(const Data& data)
|
||||
{
|
||||
lp::Packet lpPacket(data.wireEncode());
|
||||
|
||||
if (m_options.allowLocalFields) {
|
||||
encodeLocalFields(data, lpPacket);
|
||||
}
|
||||
encodeLpFields(data, lpPacket);
|
||||
|
||||
this->sendNetPacket(std::move(lpPacket));
|
||||
}
|
||||
@@ -82,19 +79,24 @@ GenericLinkService::doSendNack(const lp::Nack& nack)
|
||||
lp::Packet lpPacket(nack.getInterest().wireEncode());
|
||||
lpPacket.add<lp::NackField>(nack.getHeader());
|
||||
|
||||
if (m_options.allowLocalFields) {
|
||||
encodeLocalFields(nack, lpPacket);
|
||||
}
|
||||
encodeLpFields(nack, lpPacket);
|
||||
|
||||
this->sendNetPacket(std::move(lpPacket));
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::encodeLocalFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket)
|
||||
GenericLinkService::encodeLpFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket)
|
||||
{
|
||||
shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
|
||||
if (incomingFaceIdTag != nullptr) {
|
||||
lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
|
||||
if (m_options.allowLocalFields) {
|
||||
shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
|
||||
if (incomingFaceIdTag != nullptr) {
|
||||
lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<lp::CongestionMarkTag> congestionMarkTag = netPkt.getTag<lp::CongestionMarkTag>();
|
||||
if (congestionMarkTag != nullptr) {
|
||||
lpPacket.add<lp::CongestionMarkField>(*congestionMarkTag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,6 +242,10 @@ GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstP
|
||||
NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::CongestionMarkField>()) {
|
||||
interest->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
|
||||
}
|
||||
|
||||
this->receiveInterest(*interest);
|
||||
}
|
||||
|
||||
@@ -278,6 +284,10 @@ GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::CongestionMarkField>()) {
|
||||
data->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
|
||||
}
|
||||
|
||||
this->receiveData(*data);
|
||||
}
|
||||
|
||||
@@ -306,6 +316,10 @@ GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::CongestionMarkField>()) {
|
||||
nack.setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
|
||||
}
|
||||
|
||||
this->receiveNack(nack);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,7 +26,7 @@
|
||||
#ifndef NFD_DAEMON_FACE_GENERIC_LINK_SERVICE_HPP
|
||||
#define NFD_DAEMON_FACE_GENERIC_LINK_SERVICE_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "core/common.hpp"
|
||||
#include "core/logger.hpp"
|
||||
|
||||
#include "link-service.hpp"
|
||||
@@ -127,29 +127,30 @@ public:
|
||||
setOptions(const Options& options);
|
||||
|
||||
virtual const Counters&
|
||||
getCounters() const DECL_OVERRIDE;
|
||||
getCounters() const override;
|
||||
|
||||
private: // send path
|
||||
/** \brief send Interest
|
||||
*/
|
||||
void
|
||||
doSendInterest(const Interest& interest) DECL_OVERRIDE;
|
||||
doSendInterest(const Interest& interest) override;
|
||||
|
||||
/** \brief send Data
|
||||
*/
|
||||
void
|
||||
doSendData(const Data& data) DECL_OVERRIDE;
|
||||
doSendData(const Data& data) override;
|
||||
|
||||
/** \brief send Nack
|
||||
*/
|
||||
void
|
||||
doSendNack(const ndn::lp::Nack& nack) DECL_OVERRIDE;
|
||||
doSendNack(const ndn::lp::Nack& nack) override;
|
||||
|
||||
/** \brief encode local fields from tags onto outgoing LpPacket
|
||||
* \param pkt LpPacket containing a complete network layer packet
|
||||
/** \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
|
||||
*/
|
||||
static void
|
||||
encodeLocalFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket);
|
||||
void
|
||||
encodeLpFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket);
|
||||
|
||||
/** \brief send a complete network layer packet
|
||||
* \param pkt LpPacket containing a complete network layer packet
|
||||
@@ -171,7 +172,7 @@ private: // receive path
|
||||
/** \brief receive Packet from Transport
|
||||
*/
|
||||
void
|
||||
doReceivePacket(Transport::Packet&& packet) DECL_OVERRIDE;
|
||||
doReceivePacket(Transport::Packet&& packet) override;
|
||||
|
||||
/** \brief decode incoming network-layer packet
|
||||
* \param netPkt reassembled network-layer packet
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -45,15 +45,6 @@ InternalForwarderTransport::InternalForwarderTransport(
|
||||
NFD_LOG_FACE_INFO("Creating transport");
|
||||
}
|
||||
|
||||
void
|
||||
InternalForwarderTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
|
||||
{
|
||||
if (newPersistency != ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
|
||||
BOOST_THROW_EXCEPTION(
|
||||
std::invalid_argument("InternalForwarderTransport supports only FACE_PERSISTENCY_PERMANENT"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InternalForwarderTransport::receiveFromLink(const Block& packet)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -58,19 +58,16 @@ public:
|
||||
ndn::nfd::FaceScope scope = ndn::nfd::FACE_SCOPE_LOCAL,
|
||||
ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_POINT_TO_POINT);
|
||||
|
||||
virtual void
|
||||
receiveFromLink(const Block& packet) DECL_OVERRIDE;
|
||||
void
|
||||
receiveFromLink(const Block& packet) override;
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
doClose() DECL_OVERRIDE;
|
||||
void
|
||||
doClose() override;
|
||||
|
||||
private:
|
||||
virtual void
|
||||
doSend(Packet&& packet) DECL_OVERRIDE;
|
||||
void
|
||||
doSend(Packet&& packet) override;
|
||||
|
||||
private:
|
||||
NFD_LOG_INCLASS_DECLARE();
|
||||
@@ -92,29 +89,29 @@ public:
|
||||
void
|
||||
connectToForwarder(InternalForwarderTransport* forwarderTransport);
|
||||
|
||||
virtual void
|
||||
receiveFromLink(const Block& packet) DECL_OVERRIDE;
|
||||
void
|
||||
receiveFromLink(const Block& packet) override;
|
||||
|
||||
virtual void
|
||||
close() DECL_OVERRIDE
|
||||
void
|
||||
close() override
|
||||
{
|
||||
}
|
||||
|
||||
virtual void
|
||||
pause() DECL_OVERRIDE
|
||||
void
|
||||
pause() override
|
||||
{
|
||||
}
|
||||
|
||||
virtual void
|
||||
resume() DECL_OVERRIDE
|
||||
void
|
||||
resume() override
|
||||
{
|
||||
}
|
||||
|
||||
virtual void
|
||||
send(const Block& wire) DECL_OVERRIDE;
|
||||
void
|
||||
send(const Block& wire) override;
|
||||
|
||||
virtual void
|
||||
send(const Block& header, const Block& payload) DECL_OVERRIDE;
|
||||
void
|
||||
send(const Block& header, const Block& payload) override;
|
||||
|
||||
private:
|
||||
NFD_LOG_INCLASS_DECLARE();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -50,15 +50,6 @@ MulticastUdpTransport::MulticastUdpTransport(const protocol::endpoint& localEndp
|
||||
NFD_LOG_FACE_INFO("Creating transport");
|
||||
}
|
||||
|
||||
void
|
||||
MulticastUdpTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
|
||||
{
|
||||
if (newPersistency != ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
|
||||
BOOST_THROW_EXCEPTION(
|
||||
std::invalid_argument("MulticastUdpTransport supports only FACE_PERSISTENCY_PERMANENT"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MulticastUdpTransport::doSend(Transport::Packet&& packet)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -42,7 +42,7 @@ DatagramTransport<boost::asio::ip::udp, Multicast>::makeEndpointId(const protoco
|
||||
/**
|
||||
* \brief A Transport that communicates on a UDP multicast group
|
||||
*/
|
||||
class MulticastUdpTransport DECL_CLASS_FINAL : public DatagramTransport<boost::asio::ip::udp, Multicast>
|
||||
class MulticastUdpTransport final : public DatagramTransport<boost::asio::ip::udp, Multicast>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -57,16 +57,12 @@ public:
|
||||
protocol::socket&& recvSocket,
|
||||
protocol::socket&& sendSocket);
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
|
||||
|
||||
private:
|
||||
virtual void
|
||||
doSend(Transport::Packet&& packet) DECL_FINAL;
|
||||
void
|
||||
doSend(Transport::Packet&& packet) final;
|
||||
|
||||
virtual void
|
||||
doClose() DECL_FINAL;
|
||||
void
|
||||
doClose() final;
|
||||
|
||||
private:
|
||||
protocol::endpoint m_multicastGroup;
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2017, 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/>.
|
||||
*/
|
||||
|
||||
#include "protocol-factory.hpp"
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
ProtocolFactory::Registry&
|
||||
ProtocolFactory::getRegistry()
|
||||
{
|
||||
static Registry registry;
|
||||
return registry;
|
||||
}
|
||||
|
||||
unique_ptr<ProtocolFactory>
|
||||
ProtocolFactory::create(const std::string& id)
|
||||
{
|
||||
Registry& registry = getRegistry();
|
||||
auto found = registry.find(id);
|
||||
return found == registry.end() ? nullptr : found->second();
|
||||
}
|
||||
|
||||
std::set<std::string>
|
||||
ProtocolFactory::listRegistered()
|
||||
{
|
||||
std::set<std::string> factoryIds;
|
||||
boost::copy(getRegistry() | boost::adaptors::map_keys,
|
||||
std::inserter(factoryIds, factoryIds.end()));
|
||||
return factoryIds;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -27,15 +27,48 @@
|
||||
#define NFD_DAEMON_FACE_PROTOCOL_FACTORY_HPP
|
||||
|
||||
#include "channel.hpp"
|
||||
#include "face-system.hpp"
|
||||
#include <ndn-cxx/encoding/nfd-constants.hpp>
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/**
|
||||
* \brief Abstract base class for all protocol factories
|
||||
/** \brief provide 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 face_system config section and create channels and multicast
|
||||
* faces accordingly.
|
||||
*/
|
||||
class ProtocolFactory
|
||||
class ProtocolFactory : noncopyable
|
||||
{
|
||||
public: // registry
|
||||
/** \brief register a protocol factory type
|
||||
* \tparam S subclass of ProtocolFactory
|
||||
* \param id factory identifier
|
||||
*/
|
||||
template<typename PF>
|
||||
static void
|
||||
registerType(const std::string& id = PF::getId())
|
||||
{
|
||||
Registry& registry = getRegistry();
|
||||
BOOST_ASSERT(registry.count(id) == 0);
|
||||
registry[id] = &make_unique<PF>;
|
||||
}
|
||||
|
||||
/** \return a protocol factory instance
|
||||
* \retval nullptr if factory with \p id is not registered
|
||||
*/
|
||||
static unique_ptr<ProtocolFactory>
|
||||
create(const std::string& id);
|
||||
|
||||
/** \return registered protocol factory ids
|
||||
*/
|
||||
static std::set<std::string>
|
||||
listRegistered();
|
||||
|
||||
public:
|
||||
/**
|
||||
* \brief Base class for all exceptions thrown by protocol factories
|
||||
@@ -50,24 +83,105 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
virtual
|
||||
~ProtocolFactory() = default;
|
||||
|
||||
#ifdef DOXYGEN
|
||||
/** \return protocol factory id
|
||||
*
|
||||
* face_system.factory-id config section is processed by the protocol factory.
|
||||
*/
|
||||
static const std::string&
|
||||
getId();
|
||||
#endif
|
||||
|
||||
/** \brief process face_system subsection that corresponds to this ProtocolFactory type
|
||||
* \param configSection the configuration section or boost::null to indicate it is omitted
|
||||
* \param context provides access to data structures and contextual information
|
||||
* \throw ConfigFile::Error invalid configuration
|
||||
*
|
||||
* This function updates \p providedSchemes
|
||||
*/
|
||||
virtual void
|
||||
processConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context)
|
||||
{
|
||||
///\todo implement in every subclass and make this pure-virtual
|
||||
BOOST_THROW_EXCEPTION(Error("processConfig is not implemented"));
|
||||
}
|
||||
|
||||
/** \return FaceUri schemes accepted by this ProtocolFactory
|
||||
*/
|
||||
const std::set<std::string>&
|
||||
getProvidedSchemes()
|
||||
{
|
||||
return providedSchemes;
|
||||
}
|
||||
|
||||
/** \brief Try to create Face using the supplied FaceUri
|
||||
*
|
||||
* This method should automatically choose channel, based on supplied FaceUri
|
||||
* and create face.
|
||||
*
|
||||
* \throw Error Factory does not support connect operation
|
||||
* \throw Error specified \p persistency is not supported
|
||||
* \param uri remote URI of the new face
|
||||
* \param persistency persistency of the new face
|
||||
* \param wantLocalFieldsEnabled whether local fields should be enabled on the face
|
||||
* \param onCreated callback if face creation succeeds
|
||||
* If a face with the same remote URI already exists, its persistency and
|
||||
* LocalFieldsEnabled setting will not be modified.
|
||||
* \param onFailure callback if face creation fails
|
||||
*/
|
||||
virtual void
|
||||
createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed) = 0;
|
||||
const FaceCreationFailedCallback& onFailure) = 0;
|
||||
|
||||
virtual std::vector<shared_ptr<const Channel>>
|
||||
getChannels() const = 0;
|
||||
|
||||
protected:
|
||||
template<typename ChannelMap>
|
||||
static std::vector<shared_ptr<const Channel>>
|
||||
getChannelsFromMap(const ChannelMap& channelMap)
|
||||
{
|
||||
std::vector<shared_ptr<const Channel>> channels;
|
||||
boost::copy(channelMap | boost::adaptors::map_values, std::back_inserter(channels));
|
||||
return channels;
|
||||
}
|
||||
|
||||
private: // registry
|
||||
typedef std::function<unique_ptr<ProtocolFactory>()> CreateFunc;
|
||||
typedef std::map<std::string, CreateFunc> Registry; // indexed by factory id
|
||||
|
||||
static Registry&
|
||||
getRegistry();
|
||||
|
||||
protected:
|
||||
/** \brief FaceUri schemes provided by this ProtocolFactory
|
||||
*/
|
||||
std::set<std::string> providedSchemes;
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
|
||||
using face::ProtocolFactory;
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
/** \brief registers a protocol factory
|
||||
*
|
||||
* This macro should appear once in .cpp of each protocol factory.
|
||||
*/
|
||||
#define NFD_REGISTER_PROTOCOL_FACTORY(PF) \
|
||||
static class NfdAuto ## PF ## ProtocolFactoryRegistrationClass \
|
||||
{ \
|
||||
public: \
|
||||
NfdAuto ## PF ## ProtocolFactoryRegistrationClass() \
|
||||
{ \
|
||||
::nfd::face::ProtocolFactory::registerType<PF>(); \
|
||||
} \
|
||||
} g_nfdAuto ## PF ## ProtocolFactoryRegistrationVariable
|
||||
|
||||
#endif // NFD_DAEMON_FACE_PROTOCOL_FACTORY_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -53,13 +53,13 @@ public:
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
doClose() DECL_OVERRIDE;
|
||||
doClose() override;
|
||||
|
||||
void
|
||||
deferredClose();
|
||||
|
||||
virtual void
|
||||
doSend(Transport::Packet&& packet) DECL_OVERRIDE;
|
||||
doSend(Transport::Packet&& packet) override;
|
||||
|
||||
void
|
||||
sendFromQueue();
|
||||
@@ -68,6 +68,9 @@ protected:
|
||||
handleSend(const boost::system::error_code& error,
|
||||
size_t nBytesSent);
|
||||
|
||||
void
|
||||
startReceive();
|
||||
|
||||
void
|
||||
handleReceive(const boost::system::error_code& error,
|
||||
size_t nBytesReceived);
|
||||
@@ -75,6 +78,15 @@ protected:
|
||||
void
|
||||
processErrorCode(const boost::system::error_code& error);
|
||||
|
||||
virtual void
|
||||
handleError(const boost::system::error_code& error);
|
||||
|
||||
void
|
||||
resetReceiveBuffer();
|
||||
|
||||
void
|
||||
resetSendQueue();
|
||||
|
||||
protected:
|
||||
typename protocol::socket m_socket;
|
||||
|
||||
@@ -92,10 +104,7 @@ StreamTransport<T>::StreamTransport(typename StreamTransport::protocol::socket&&
|
||||
: m_socket(std::move(socket))
|
||||
, m_receiveBufferSize(0)
|
||||
{
|
||||
m_socket.async_receive(boost::asio::buffer(m_receiveBuffer, ndn::MAX_NDN_PACKET_SIZE),
|
||||
bind(&StreamTransport<T>::handleReceive, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
startReceive();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
@@ -136,9 +145,7 @@ StreamTransport<T>::deferredClose()
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
// clear send queue
|
||||
std::queue<Block> emptyQueue;
|
||||
std::swap(emptyQueue, m_sendQueue);
|
||||
resetSendQueue();
|
||||
|
||||
// use the non-throwing variant and ignore errors, if any
|
||||
boost::system::error_code error;
|
||||
@@ -153,6 +160,9 @@ StreamTransport<T>::doSend(Transport::Packet&& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
if (getState() != TransportState::UP)
|
||||
return;
|
||||
|
||||
bool wasQueueEmpty = m_sendQueue.empty();
|
||||
m_sendQueue.push(packet.packet);
|
||||
|
||||
@@ -187,6 +197,19 @@ StreamTransport<T>::handleSend(const boost::system::error_code& error,
|
||||
sendFromQueue();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
StreamTransport<T>::startReceive()
|
||||
{
|
||||
BOOST_ASSERT(getState() == TransportState::UP);
|
||||
|
||||
m_socket.async_receive(boost::asio::buffer(m_receiveBuffer + m_receiveBufferSize,
|
||||
ndn::MAX_NDN_PACKET_SIZE - m_receiveBufferSize),
|
||||
bind(&StreamTransport<T>::handleReceive, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
StreamTransport<T>::handleReceive(const boost::system::error_code& error,
|
||||
@@ -231,11 +254,7 @@ StreamTransport<T>::handleReceive(const boost::system::error_code& error,
|
||||
}
|
||||
}
|
||||
|
||||
m_socket.async_receive(boost::asio::buffer(m_receiveBuffer + m_receiveBufferSize,
|
||||
ndn::MAX_NDN_PACKET_SIZE - m_receiveBufferSize),
|
||||
bind(&StreamTransport<T>::handleReceive, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
startReceive();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
@@ -252,6 +271,13 @@ StreamTransport<T>::processErrorCode(const boost::system::error_code& error)
|
||||
// transport is shutting down, ignore any errors
|
||||
return;
|
||||
|
||||
handleError(error);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
StreamTransport<T>::handleError(const boost::system::error_code& error)
|
||||
{
|
||||
if (error != boost::asio::error::eof)
|
||||
NFD_LOG_FACE_WARN("Send or receive operation failed: " << error.message());
|
||||
|
||||
@@ -259,6 +285,21 @@ StreamTransport<T>::processErrorCode(const boost::system::error_code& error)
|
||||
doClose();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
StreamTransport<T>::resetReceiveBuffer()
|
||||
{
|
||||
m_receiveBufferSize = 0;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
StreamTransport<T>::resetSendQueue()
|
||||
{
|
||||
std::queue<Block> emptyQueue;
|
||||
std::swap(emptyQueue, m_sendQueue);
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
|
||||
+18
-10
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -66,6 +66,7 @@ TcpChannel::listen(const FaceCreatedCallback& onFaceCreated,
|
||||
|
||||
void
|
||||
TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed,
|
||||
const time::seconds& timeout/* = time::seconds(4)*/)
|
||||
@@ -83,8 +84,8 @@ TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
|
||||
|
||||
clientSocket->async_connect(remoteEndpoint,
|
||||
bind(&TcpChannel::handleConnect, this,
|
||||
boost::asio::placeholders::error,
|
||||
clientSocket, connectTimeoutEvent,
|
||||
boost::asio::placeholders::error, clientSocket,
|
||||
wantLocalFieldsEnabled, connectTimeoutEvent,
|
||||
onFaceCreated, onConnectFailed));
|
||||
}
|
||||
|
||||
@@ -96,8 +97,9 @@ TcpChannel::size() const
|
||||
|
||||
void
|
||||
TcpChannel::createFace(ip::tcp::socket&& socket,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
bool isOnDemand)
|
||||
bool isOnDemand,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const FaceCreatedCallback& onFaceCreated)
|
||||
{
|
||||
shared_ptr<Face> face;
|
||||
tcp::Endpoint remoteEndpoint = socket.remote_endpoint();
|
||||
@@ -107,7 +109,12 @@ TcpChannel::createFace(ip::tcp::socket&& socket,
|
||||
auto persistency = isOnDemand ? ndn::nfd::FACE_PERSISTENCY_ON_DEMAND
|
||||
: ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
|
||||
auto linkService = make_unique<face::GenericLinkService>();
|
||||
auto options = linkService->getOptions();
|
||||
options.allowLocalFields = wantLocalFieldsEnabled;
|
||||
linkService->setOptions(options);
|
||||
|
||||
auto transport = make_unique<face::TcpTransport>(std::move(socket), persistency);
|
||||
|
||||
face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
|
||||
m_channelFaces[remoteEndpoint] = face;
|
||||
@@ -151,13 +158,13 @@ TcpChannel::handleAccept(const boost::system::error_code& error,
|
||||
|
||||
NFD_LOG_DEBUG("[" << m_localEndpoint << "] Accept failed: " << error.message());
|
||||
if (onAcceptFailed)
|
||||
onAcceptFailed(error.message());
|
||||
onAcceptFailed(500, "Accept failed: " + error.message());
|
||||
return;
|
||||
}
|
||||
|
||||
NFD_LOG_DEBUG("[" << m_localEndpoint << "] Connection from " << m_acceptSocket.remote_endpoint());
|
||||
|
||||
createFace(std::move(m_acceptSocket), onFaceCreated, true);
|
||||
createFace(std::move(m_acceptSocket), true, false, onFaceCreated);
|
||||
|
||||
// prepare accepting the next connection
|
||||
accept(onFaceCreated, onAcceptFailed);
|
||||
@@ -166,6 +173,7 @@ TcpChannel::handleAccept(const boost::system::error_code& error,
|
||||
void
|
||||
TcpChannel::handleConnect(const boost::system::error_code& error,
|
||||
const shared_ptr<ip::tcp::socket>& socket,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const scheduler::EventId& connectTimeoutEvent,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed)
|
||||
@@ -189,13 +197,13 @@ TcpChannel::handleConnect(const boost::system::error_code& error,
|
||||
socket->close();
|
||||
|
||||
if (onConnectFailed)
|
||||
onConnectFailed(error.message());
|
||||
onConnectFailed(504, "Connect failed: " + error.message());
|
||||
return;
|
||||
}
|
||||
|
||||
NFD_LOG_DEBUG("[" << m_localEndpoint << "] Connected to " << socket->remote_endpoint());
|
||||
|
||||
createFace(std::move(*socket), onFaceCreated, false);
|
||||
createFace(std::move(*socket), false, wantLocalFieldsEnabled, onFaceCreated);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -209,7 +217,7 @@ TcpChannel::handleConnectTimeout(const shared_ptr<ip::tcp::socket>& socket,
|
||||
socket->close(error);
|
||||
|
||||
if (onConnectFailed)
|
||||
onConnectFailed("Connect to remote endpoint timed out");
|
||||
onConnectFailed(504, "Connect to remote endpoint timed out");
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -73,6 +73,7 @@ public:
|
||||
*/
|
||||
void
|
||||
connect(const tcp::Endpoint& remoteEndpoint,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed,
|
||||
const time::seconds& timeout = time::seconds(4));
|
||||
@@ -89,8 +90,9 @@ public:
|
||||
private:
|
||||
void
|
||||
createFace(boost::asio::ip::tcp::socket&& socket,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
bool isOnDemand);
|
||||
bool isOnDemand,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const FaceCreatedCallback& onFaceCreated);
|
||||
|
||||
void
|
||||
accept(const FaceCreatedCallback& onFaceCreated,
|
||||
@@ -104,6 +106,7 @@ private:
|
||||
void
|
||||
handleConnect(const boost::system::error_code& error,
|
||||
const shared_ptr<boost::asio::ip::tcp::socket>& socket,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const scheduler::EventId& connectTimeoutEvent,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed);
|
||||
|
||||
+143
-42
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -25,13 +25,150 @@
|
||||
|
||||
#include "tcp-factory.hpp"
|
||||
#include "core/logger.hpp"
|
||||
#include "core/network-interface.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
namespace ip = boost::asio::ip;
|
||||
|
||||
NFD_LOG_INIT("TcpFactory");
|
||||
NFD_REGISTER_PROTOCOL_FACTORY(TcpFactory);
|
||||
|
||||
const std::string&
|
||||
TcpFactory::getId()
|
||||
{
|
||||
static std::string id("tcp");
|
||||
return id;
|
||||
}
|
||||
|
||||
void
|
||||
TcpFactory::processConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context)
|
||||
{
|
||||
// tcp
|
||||
// {
|
||||
// listen yes
|
||||
// port 6363
|
||||
// enable_v4 yes
|
||||
// enable_v6 yes
|
||||
// }
|
||||
|
||||
if (!configSection) {
|
||||
if (!context.isDryRun && !m_channels.empty()) {
|
||||
NFD_LOG_WARN("Cannot disable tcp4 and tcp6 channels after initialization");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bool wantListen = true;
|
||||
uint16_t port = 6363;
|
||||
bool enableV4 = true;
|
||||
bool enableV6 = true;
|
||||
|
||||
for (const auto& pair : *configSection) {
|
||||
const std::string& key = pair.first;
|
||||
|
||||
if (key == "listen") {
|
||||
wantListen = ConfigFile::parseYesNo(pair, "face_system.tcp");
|
||||
}
|
||||
else if (key == "port") {
|
||||
port = ConfigFile::parseNumber<uint16_t>(pair, "face_system.tcp");
|
||||
}
|
||||
else if (key == "enable_v4") {
|
||||
enableV4 = ConfigFile::parseYesNo(pair, "face_system.tcp");
|
||||
}
|
||||
else if (key == "enable_v6") {
|
||||
enableV6 = ConfigFile::parseYesNo(pair, "face_system.tcp");
|
||||
}
|
||||
else {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system.tcp." + key));
|
||||
}
|
||||
}
|
||||
|
||||
if (!enableV4 && !enableV6) {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error(
|
||||
"IPv4 and IPv6 TCP channels have been disabled. Remove face_system.tcp section to disable "
|
||||
"TCP channels or enable at least one channel type."));
|
||||
}
|
||||
|
||||
if (!context.isDryRun) {
|
||||
providedSchemes.insert("tcp");
|
||||
|
||||
if (enableV4) {
|
||||
tcp::Endpoint endpoint(ip::tcp::v4(), port);
|
||||
shared_ptr<TcpChannel> v4Channel = this->createChannel(endpoint);
|
||||
if (wantListen && !v4Channel->isListening()) {
|
||||
v4Channel->listen(context.addFace, nullptr);
|
||||
}
|
||||
providedSchemes.insert("tcp4");
|
||||
}
|
||||
else if (providedSchemes.count("tcp4") > 0) {
|
||||
NFD_LOG_WARN("Cannot close tcp4 channel after its creation");
|
||||
}
|
||||
|
||||
if (enableV6) {
|
||||
tcp::Endpoint endpoint(ip::tcp::v6(), port);
|
||||
shared_ptr<TcpChannel> v6Channel = this->createChannel(endpoint);
|
||||
if (wantListen && !v6Channel->isListening()) {
|
||||
v6Channel->listen(context.addFace, nullptr);
|
||||
}
|
||||
providedSchemes.insert("tcp6");
|
||||
}
|
||||
else if (providedSchemes.count("tcp6") > 0) {
|
||||
NFD_LOG_WARN("Cannot close tcp6 channel after its creation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TcpFactory::createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onFailure)
|
||||
{
|
||||
BOOST_ASSERT(uri.isCanonical());
|
||||
|
||||
if (persistency != ndn::nfd::FACE_PERSISTENCY_PERSISTENT) {
|
||||
NFD_LOG_TRACE("createFace only supports FACE_PERSISTENCY_PERSISTENT");
|
||||
onFailure(406, "Outgoing TCP faces only support persistent persistency");
|
||||
return;
|
||||
}
|
||||
|
||||
tcp::Endpoint endpoint(ip::address::from_string(uri.getHost()),
|
||||
boost::lexical_cast<uint16_t>(uri.getPort()));
|
||||
|
||||
if (endpoint.address().is_multicast()) {
|
||||
NFD_LOG_TRACE("createFace cannot create multicast faces");
|
||||
onFailure(406, "Cannot create multicast TCP faces");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end()) {
|
||||
NFD_LOG_TRACE("Requested endpoint is prohibited "
|
||||
"(reserved by NFD or disallowed by face management protocol)");
|
||||
onFailure(406, "Requested endpoint is prohibited");
|
||||
return;
|
||||
}
|
||||
|
||||
if (wantLocalFieldsEnabled && !endpoint.address().is_loopback()) {
|
||||
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;
|
||||
}
|
||||
|
||||
// very simple logic for now
|
||||
for (const auto& i : m_channels) {
|
||||
if ((i.first.address().is_v4() && endpoint.address().is_v4()) ||
|
||||
(i.first.address().is_v6() && endpoint.address().is_v6())) {
|
||||
i.second->connect(endpoint, wantLocalFieldsEnabled, onCreated, onFailure);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NFD_LOG_TRACE("No channels available to connect to " + boost::lexical_cast<std::string>(endpoint));
|
||||
onFailure(504, "No channels available to connect");
|
||||
}
|
||||
|
||||
void
|
||||
TcpFactory::prohibitEndpoint(const tcp::Endpoint& endpoint)
|
||||
@@ -52,6 +189,7 @@ TcpFactory::prohibitEndpoint(const tcp::Endpoint& endpoint)
|
||||
void
|
||||
TcpFactory::prohibitAllIpv4Endpoints(uint16_t port)
|
||||
{
|
||||
///\todo prohibited endpoints need to react to dynamic NIC changes
|
||||
for (const NetworkInterfaceInfo& nic : listNetworkInterfaces()) {
|
||||
for (const auto& addr : nic.ipv4Addresses) {
|
||||
if (addr != ip::address_v4::any()) {
|
||||
@@ -64,6 +202,7 @@ TcpFactory::prohibitAllIpv4Endpoints(uint16_t port)
|
||||
void
|
||||
TcpFactory::prohibitAllIpv6Endpoints(uint16_t port)
|
||||
{
|
||||
///\todo prohibited endpoints need to react to dynamic NIC changes
|
||||
for (const NetworkInterfaceInfo& nic : listNetworkInterfaces()) {
|
||||
for (const auto& addr : nic.ipv6Addresses) {
|
||||
if (addr != ip::address_v6::any()) {
|
||||
@@ -96,49 +235,10 @@ TcpFactory::createChannel(const std::string& localIp, const std::string& localPo
|
||||
return createChannel(endpoint);
|
||||
}
|
||||
|
||||
void
|
||||
TcpFactory::createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed)
|
||||
{
|
||||
BOOST_ASSERT(uri.isCanonical());
|
||||
|
||||
if (persistency != ndn::nfd::FACE_PERSISTENCY_PERSISTENT) {
|
||||
BOOST_THROW_EXCEPTION(Error("TcpFactory::createFace supports only FACE_PERSISTENCY_PERSISTENT"));
|
||||
}
|
||||
|
||||
tcp::Endpoint endpoint(ip::address::from_string(uri.getHost()),
|
||||
boost::lexical_cast<uint16_t>(uri.getPort()));
|
||||
|
||||
if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end()) {
|
||||
onConnectFailed("Requested endpoint is prohibited "
|
||||
"(reserved by this NFD or disallowed by face management protocol)");
|
||||
return;
|
||||
}
|
||||
|
||||
// very simple logic for now
|
||||
for (const auto& i : m_channels) {
|
||||
if ((i.first.address().is_v4() && endpoint.address().is_v4()) ||
|
||||
(i.first.address().is_v6() && endpoint.address().is_v6())) {
|
||||
i.second->connect(endpoint, onCreated, onConnectFailed);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
onConnectFailed("No channels available to connect to " + boost::lexical_cast<std::string>(endpoint));
|
||||
}
|
||||
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
TcpFactory::getChannels() const
|
||||
{
|
||||
std::vector<shared_ptr<const Channel>> channels;
|
||||
channels.reserve(m_channels.size());
|
||||
|
||||
for (const auto& i : m_channels)
|
||||
channels.push_back(i.second);
|
||||
|
||||
return channels;
|
||||
return getChannelsFromMap(m_channels);
|
||||
}
|
||||
|
||||
shared_ptr<TcpChannel>
|
||||
@@ -151,4 +251,5 @@ TcpFactory::findChannel(const tcp::Endpoint& localEndpoint) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
+22
-24
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -30,22 +30,28 @@
|
||||
#include "tcp-channel.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief protocol factory for TCP over IPv4 and IPv6
|
||||
*/
|
||||
class TcpFactory : public ProtocolFactory
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Exception of TcpFactory
|
||||
static const std::string&
|
||||
getId();
|
||||
|
||||
/** \brief process face_system.tcp config section
|
||||
*/
|
||||
class Error : public ProtocolFactory::Error
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& what)
|
||||
: ProtocolFactory::Error(what)
|
||||
{
|
||||
}
|
||||
};
|
||||
void
|
||||
processConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context) override;
|
||||
|
||||
void
|
||||
createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onFailure) override;
|
||||
|
||||
/**
|
||||
* \brief Create TCP-based channel using tcp::Endpoint
|
||||
@@ -59,8 +65,6 @@ public:
|
||||
* \returns always a valid pointer to a TcpChannel object, an exception
|
||||
* is thrown if it cannot be created.
|
||||
*
|
||||
* \throws TcpFactory::Error
|
||||
*
|
||||
* \see http://www.boost.org/doc/libs/1_42_0/doc/html/boost_asio/reference/ip__tcp/endpoint.html
|
||||
* for details on ways to create tcp::Endpoint
|
||||
*/
|
||||
@@ -73,20 +77,13 @@ public:
|
||||
* This method is just a helper that converts a string representation of localIp and port to
|
||||
* tcp::Endpoint and calls the other createChannel overload.
|
||||
*
|
||||
* \throws TcpFactory::Error or std::runtime_error
|
||||
* \throws std::runtime_error
|
||||
*/
|
||||
shared_ptr<TcpChannel>
|
||||
createChannel(const std::string& localIp, const std::string& localPort);
|
||||
|
||||
public: // from ProtocolFactory
|
||||
virtual void
|
||||
createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed) DECL_OVERRIDE;
|
||||
|
||||
virtual std::vector<shared_ptr<const Channel>>
|
||||
getChannels() const DECL_OVERRIDE;
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
getChannels() const override;
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
void
|
||||
@@ -115,6 +112,7 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
std::set<tcp::Endpoint> m_prohibitedEndpoints;
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_TCP_FACTORY_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -28,11 +28,16 @@
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(StreamTransport, TcpTransport::protocol,
|
||||
"TcpTransport");
|
||||
NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(StreamTransport, TcpTransport::protocol, "TcpTransport");
|
||||
|
||||
time::milliseconds TcpTransport::s_initialReconnectWait = time::seconds(1);
|
||||
time::milliseconds TcpTransport::s_maxReconnectWait = time::minutes(5);
|
||||
float TcpTransport::s_reconnectWaitMultiplier = 2.0f;
|
||||
|
||||
TcpTransport::TcpTransport(protocol::socket&& socket, ndn::nfd::FacePersistency persistency)
|
||||
: StreamTransport(std::move(socket))
|
||||
, m_remoteEndpoint(m_socket.remote_endpoint())
|
||||
, m_nextReconnectWait(s_initialReconnectWait)
|
||||
{
|
||||
this->setLocalUri(FaceUri(m_socket.local_endpoint()));
|
||||
this->setRemoteUri(FaceUri(m_socket.remote_endpoint()));
|
||||
@@ -50,14 +55,117 @@ TcpTransport::TcpTransport(protocol::socket&& socket, ndn::nfd::FacePersistency
|
||||
NFD_LOG_FACE_INFO("Creating transport");
|
||||
}
|
||||
|
||||
void
|
||||
TcpTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
|
||||
bool
|
||||
TcpTransport::canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const
|
||||
{
|
||||
if (newPersistency == ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
|
||||
BOOST_THROW_EXCEPTION(
|
||||
std::invalid_argument("TcpTransport does not support FACE_PERSISTENCY_PERMANENT"));
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TcpTransport::afterChangePersistency(ndn::nfd::FacePersistency oldPersistency)
|
||||
{
|
||||
// if persistency was changed from permanent to any other value
|
||||
if (oldPersistency == ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
|
||||
if (this->getState() == TransportState::DOWN) {
|
||||
// non-permanent transport cannot be in DOWN state, so fail hard
|
||||
this->setState(TransportState::FAILED);
|
||||
doClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TcpTransport::handleError(const boost::system::error_code& error)
|
||||
{
|
||||
if (this->getPersistency() == ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
|
||||
NFD_LOG_FACE_TRACE("TCP socket error: " << error.message());
|
||||
this->setState(TransportState::DOWN);
|
||||
|
||||
// cancel all outstanding operations
|
||||
boost::system::error_code error;
|
||||
m_socket.cancel(error);
|
||||
|
||||
// do this asynchronously because there could be some callbacks still pending
|
||||
getGlobalIoService().post([this] { reconnect(); });
|
||||
}
|
||||
else {
|
||||
StreamTransport::handleError(error);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TcpTransport::reconnect()
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
if (getState() == TransportState::CLOSING ||
|
||||
getState() == TransportState::FAILED ||
|
||||
getState() == TransportState::CLOSED) {
|
||||
// transport is shutting down, don't attempt to reconnect
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(getPersistency() == ndn::nfd::FACE_PERSISTENCY_PERMANENT);
|
||||
BOOST_ASSERT(getState() == TransportState::DOWN);
|
||||
|
||||
// recreate the socket
|
||||
m_socket = protocol::socket(m_socket.get_io_service());
|
||||
this->resetReceiveBuffer();
|
||||
this->resetSendQueue();
|
||||
|
||||
m_reconnectEvent = scheduler::schedule(m_nextReconnectWait,
|
||||
[this] { handleReconnectTimeout(); });
|
||||
m_socket.async_connect(m_remoteEndpoint,
|
||||
[this] (const boost::system::error_code& error) { handleReconnect(error); });
|
||||
}
|
||||
|
||||
void
|
||||
TcpTransport::handleReconnect(const boost::system::error_code& error)
|
||||
{
|
||||
if (getState() == TransportState::CLOSING ||
|
||||
getState() == TransportState::FAILED ||
|
||||
getState() == TransportState::CLOSED ||
|
||||
error == boost::asio::error::operation_aborted) {
|
||||
// transport is shutting down, abort the reconnection attempt and ignore any errors
|
||||
return;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
NFD_LOG_FACE_TRACE("Reconnection attempt failed: " << error.message());
|
||||
return;
|
||||
}
|
||||
|
||||
m_reconnectEvent.cancel();
|
||||
m_nextReconnectWait = s_initialReconnectWait;
|
||||
|
||||
this->setLocalUri(FaceUri(m_socket.local_endpoint()));
|
||||
NFD_LOG_FACE_TRACE("TCP connection reestablished");
|
||||
this->setState(TransportState::UP);
|
||||
this->startReceive();
|
||||
}
|
||||
|
||||
void
|
||||
TcpTransport::handleReconnectTimeout()
|
||||
{
|
||||
// abort the reconnection attempt
|
||||
boost::system::error_code error;
|
||||
m_socket.close(error);
|
||||
|
||||
// exponentially back off the reconnection timer
|
||||
m_nextReconnectWait =
|
||||
std::min(time::duration_cast<time::milliseconds>(m_nextReconnectWait * s_reconnectWaitMultiplier),
|
||||
s_maxReconnectWait);
|
||||
|
||||
// do this asynchronously because there could be some callbacks still pending
|
||||
getGlobalIoService().post([this] { reconnect(); });
|
||||
}
|
||||
|
||||
void
|
||||
TcpTransport::doClose()
|
||||
{
|
||||
m_reconnectEvent.cancel();
|
||||
StreamTransport::doClose();
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -1,11 +1,12 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014 Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology
|
||||
* Copyright (c) 2014-2017, 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.
|
||||
@@ -20,28 +21,75 @@
|
||||
*
|
||||
* 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_DAEMON_FACE_TCP_TRANSPORT_HPP
|
||||
#define NFD_DAEMON_FACE_TCP_TRANSPORT_HPP
|
||||
|
||||
#include "stream-transport.hpp"
|
||||
#include "core/scheduler.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/**
|
||||
* \brief A Transport that communicates on a connected TCP socket
|
||||
*
|
||||
* When persistency is set to permanent, whenever the TCP connection is severed, the transport
|
||||
* state is set to DOWN, and the connection is retried periodically with exponential backoff
|
||||
* until it is reestablished
|
||||
*/
|
||||
class TcpTransport DECL_CLASS_FINAL : public StreamTransport<boost::asio::ip::tcp>
|
||||
class TcpTransport FINAL_UNLESS_WITH_TESTS : public StreamTransport<boost::asio::ip::tcp>
|
||||
{
|
||||
public:
|
||||
TcpTransport(protocol::socket&& socket,
|
||||
ndn::nfd::FacePersistency persistency);
|
||||
TcpTransport(protocol::socket&& socket, ndn::nfd::FacePersistency persistency);
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
|
||||
bool
|
||||
canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const final;
|
||||
|
||||
void
|
||||
afterChangePersistency(ndn::nfd::FacePersistency oldPersistency) final;
|
||||
|
||||
void
|
||||
doClose() final;
|
||||
|
||||
void
|
||||
handleError(const boost::system::error_code& error) final;
|
||||
|
||||
PROTECTED_WITH_TESTS_ELSE_PRIVATE:
|
||||
VIRTUAL_WITH_TESTS void
|
||||
reconnect();
|
||||
|
||||
VIRTUAL_WITH_TESTS void
|
||||
handleReconnect(const boost::system::error_code& error);
|
||||
|
||||
VIRTUAL_WITH_TESTS void
|
||||
handleReconnectTimeout();
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
/** \brief how long to wait before the first reconnection attempt after the TCP connection has been severed
|
||||
*/
|
||||
static time::milliseconds s_initialReconnectWait;
|
||||
|
||||
/** \brief maximum amount of time to wait before a reconnection attempt
|
||||
*/
|
||||
static time::milliseconds s_maxReconnectWait;
|
||||
|
||||
/** \brief multiplier for the exponential backoff of the reconnection timer
|
||||
*/
|
||||
static float s_reconnectWaitMultiplier;
|
||||
|
||||
private:
|
||||
typename protocol::endpoint m_remoteEndpoint;
|
||||
|
||||
/** \note valid only when persistency is set to permanent
|
||||
*/
|
||||
scheduler::ScopedEventId m_reconnectEvent;
|
||||
|
||||
/** \note valid only when persistency is set to permanent
|
||||
*/
|
||||
time::milliseconds m_nextReconnectWait;
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
|
||||
+40
-16
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -68,9 +68,7 @@ Transport::Transport()
|
||||
{
|
||||
}
|
||||
|
||||
Transport::~Transport()
|
||||
{
|
||||
}
|
||||
Transport::~Transport() = default;
|
||||
|
||||
void
|
||||
Transport::setFaceAndLinkService(Face& face, LinkService& service)
|
||||
@@ -91,7 +89,7 @@ Transport::close()
|
||||
|
||||
this->setState(TransportState::CLOSING);
|
||||
this->doClose();
|
||||
// warning: don't access any fields after this:
|
||||
// warning: don't access any members after this:
|
||||
// the Transport may be deallocated if doClose changes state to CLOSED
|
||||
}
|
||||
|
||||
@@ -127,23 +125,49 @@ Transport::receive(Packet&& packet)
|
||||
m_service->receivePacket(std::move(packet));
|
||||
}
|
||||
|
||||
bool
|
||||
Transport::canChangePersistencyTo(ndn::nfd::FacePersistency newPersistency) const
|
||||
{
|
||||
// not changing, or setting initial persistency in subclass constructor
|
||||
if (m_persistency == newPersistency || m_persistency == ndn::nfd::FACE_PERSISTENCY_NONE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (newPersistency == ndn::nfd::FACE_PERSISTENCY_NONE) {
|
||||
NFD_LOG_FACE_TRACE("cannot change persistency to NONE");
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->canChangePersistencyToImpl(newPersistency);
|
||||
}
|
||||
|
||||
bool
|
||||
Transport::canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Transport::setPersistency(ndn::nfd::FacePersistency newPersistency)
|
||||
{
|
||||
BOOST_ASSERT(canChangePersistencyTo(newPersistency));
|
||||
|
||||
if (m_persistency == newPersistency) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newPersistency == ndn::nfd::FACE_PERSISTENCY_NONE) {
|
||||
throw std::runtime_error("invalid persistency transition");
|
||||
}
|
||||
|
||||
if (m_persistency != ndn::nfd::FACE_PERSISTENCY_NONE) {
|
||||
this->beforeChangePersistency(newPersistency);
|
||||
NFD_LOG_FACE_DEBUG("setPersistency " << m_persistency << " -> " << newPersistency);
|
||||
}
|
||||
|
||||
auto oldPersistency = m_persistency;
|
||||
m_persistency = newPersistency;
|
||||
|
||||
if (oldPersistency != ndn::nfd::FACE_PERSISTENCY_NONE) {
|
||||
NFD_LOG_FACE_INFO("setPersistency " << oldPersistency << " -> " << newPersistency);
|
||||
this->afterChangePersistency(oldPersistency);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Transport::afterChangePersistency(ndn::nfd::FacePersistency oldPersistency)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
@@ -174,7 +198,7 @@ Transport::setState(TransportState newState)
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
throw std::runtime_error("invalid state transition");
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("invalid state transition"));
|
||||
}
|
||||
|
||||
NFD_LOG_FACE_INFO("setState " << m_state << " -> " << newState);
|
||||
@@ -182,7 +206,7 @@ Transport::setState(TransportState newState)
|
||||
TransportState oldState = m_state;
|
||||
m_state = newState;
|
||||
afterStateChange(oldState, newState);
|
||||
// warning: don't access any fields after this:
|
||||
// warning: don't access any members after this:
|
||||
// the Transport may be deallocated in the signal handler if newState is CLOSED
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -221,10 +221,21 @@ public: // static properties
|
||||
ndn::nfd::FacePersistency
|
||||
getPersistency() const;
|
||||
|
||||
/** \brief check whether the face persistency can be changed to \p newPersistency
|
||||
*
|
||||
* This function serves as the external API, and invokes the protected function
|
||||
* canChangePersistencyToImpl to perform further checks if \p newPersistency differs
|
||||
* from the current persistency.
|
||||
*
|
||||
* \return true if the change can be performed, false otherwise
|
||||
*/
|
||||
bool
|
||||
canChangePersistencyTo(ndn::nfd::FacePersistency newPersistency) const;
|
||||
|
||||
/** \brief changes face persistency setting
|
||||
*/
|
||||
void
|
||||
setPersistency(ndn::nfd::FacePersistency persistency);
|
||||
setPersistency(ndn::nfd::FacePersistency newPersistency);
|
||||
|
||||
/** \return whether face is point-to-point or multi-access
|
||||
*/
|
||||
@@ -289,12 +300,23 @@ protected: // properties to be set by subclass
|
||||
setExpirationTime(const time::steady_clock::TimePoint& expirationTime);
|
||||
|
||||
protected: // to be overridden by subclass
|
||||
/** \brief invoked before persistency is changed
|
||||
* \throw std::invalid_argument new persistency is not supported
|
||||
* \throw std::runtime_error transition is disallowed
|
||||
/** \brief invoked by canChangePersistencyTo to perform the check
|
||||
*
|
||||
* Base class implementation returns false.
|
||||
*
|
||||
* \param newPersistency the new persistency, guaranteed to be different from current persistency
|
||||
*/
|
||||
virtual bool
|
||||
canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const;
|
||||
|
||||
/** \brief invoked after the persistency has been changed
|
||||
*
|
||||
* The base class implementation does nothing.
|
||||
* When overridden in a subclass, the function should update internal states
|
||||
* after persistency setting has been changed.
|
||||
*/
|
||||
virtual void
|
||||
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) = 0;
|
||||
afterChangePersistency(ndn::nfd::FacePersistency oldPersistency);
|
||||
|
||||
/** \brief performs Transport specific operations to close the transport
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -62,7 +62,7 @@ UdpChannel::connect(const udp::Endpoint& remoteEndpoint,
|
||||
catch (const boost::system::system_error& e) {
|
||||
NFD_LOG_WARN("[" << m_localEndpoint << "] Connect failed: " << e.what());
|
||||
if (onConnectFailed)
|
||||
onConnectFailed(e.what());
|
||||
onConnectFailed(504, std::string("Connect failed: ") + e.what());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ UdpChannel::handleNewPeer(const boost::system::error_code& error,
|
||||
|
||||
NFD_LOG_DEBUG("[" << m_localEndpoint << "] Receive failed: " << error.message());
|
||||
if (onReceiveFailed)
|
||||
onReceiveFailed(error.message());
|
||||
onReceiveFailed(500, "Receive failed: " + error.message());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ UdpChannel::handleNewPeer(const boost::system::error_code& error,
|
||||
NFD_LOG_WARN("[" << m_localEndpoint << "] Failed to create face for peer "
|
||||
<< m_remoteEndpoint << ": " << e.what());
|
||||
if (onReceiveFailed)
|
||||
onReceiveFailed(e.what());
|
||||
onReceiveFailed(504, "Failed to create face for peer");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -146,8 +146,10 @@ UdpChannel::createFace(const udp::Endpoint& remoteEndpoint, ndn::nfd::FacePersis
|
||||
{
|
||||
auto it = m_channelFaces.find(remoteEndpoint);
|
||||
if (it != m_channelFaces.end()) {
|
||||
// we already have a face for this endpoint, just reuse it
|
||||
// we already have a face for this endpoint, so reuse it
|
||||
auto face = it->second;
|
||||
|
||||
// TODO #3232: Remove persistency transitions from faces/create
|
||||
// only on-demand -> persistent -> permanent transition is allowed
|
||||
bool isTransitionAllowed = persistency != face->getPersistency() &&
|
||||
(face->getPersistency() == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND ||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -27,13 +27,10 @@
|
||||
#define NFD_DAEMON_FACE_UDP_CHANNEL_HPP
|
||||
|
||||
#include "channel.hpp"
|
||||
#include "udp-protocol.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
namespace udp {
|
||||
typedef boost::asio::ip::udp::endpoint Endpoint;
|
||||
} // namespace udp
|
||||
|
||||
/**
|
||||
* \brief Class implementing UDP-based channel to create faces
|
||||
*/
|
||||
|
||||
+282
-73
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -27,19 +27,222 @@
|
||||
#include "generic-link-service.hpp"
|
||||
#include "multicast-udp-transport.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
#include "core/network-interface.hpp"
|
||||
#include <boost/range/adaptors.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <cerrno> // for errno
|
||||
#include <cstring> // for std::strerror()
|
||||
#include <sys/socket.h> // for setsockopt()
|
||||
#endif
|
||||
#endif // __linux__
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
namespace ip = boost::asio::ip;
|
||||
|
||||
NFD_LOG_INIT("UdpFactory");
|
||||
NFD_REGISTER_PROTOCOL_FACTORY(UdpFactory);
|
||||
|
||||
const std::string&
|
||||
UdpFactory::getId()
|
||||
{
|
||||
static std::string id("udp");
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UdpFactory::processConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context)
|
||||
{
|
||||
// udp
|
||||
// {
|
||||
// port 6363
|
||||
// enable_v4 yes
|
||||
// enable_v6 yes
|
||||
// idle_timeout 600
|
||||
// keep_alive_interval 25 ; acceptable but ignored
|
||||
// mcast yes
|
||||
// mcast_group 224.0.23.170
|
||||
// mcast_port 56363
|
||||
// whitelist
|
||||
// {
|
||||
// *
|
||||
// }
|
||||
// blacklist
|
||||
// {
|
||||
// }
|
||||
// }
|
||||
|
||||
uint16_t port = 6363;
|
||||
bool enableV4 = false;
|
||||
bool enableV6 = false;
|
||||
uint32_t idleTimeout = 600;
|
||||
MulticastConfig mcastConfig;
|
||||
|
||||
if (configSection) {
|
||||
// These default to 'yes' but only if face_system.udp section is present
|
||||
enableV4 = enableV6 = mcastConfig.isEnabled = true;
|
||||
|
||||
for (const auto& pair : *configSection) {
|
||||
const std::string& key = pair.first;
|
||||
const ConfigSection& value = pair.second;
|
||||
|
||||
if (key == "port") {
|
||||
port = ConfigFile::parseNumber<uint16_t>(pair, "face_system.udp");
|
||||
}
|
||||
else if (key == "enable_v4") {
|
||||
enableV4 = ConfigFile::parseYesNo(pair, "face_system.udp");
|
||||
}
|
||||
else if (key == "enable_v6") {
|
||||
enableV6 = ConfigFile::parseYesNo(pair, "face_system.udp");
|
||||
}
|
||||
else if (key == "idle_timeout") {
|
||||
idleTimeout = ConfigFile::parseNumber<uint32_t>(pair, "face_system.udp");
|
||||
}
|
||||
else if (key == "keep_alive_interval") {
|
||||
// ignored
|
||||
}
|
||||
else if (key == "mcast") {
|
||||
mcastConfig.isEnabled = ConfigFile::parseYesNo(pair, "face_system.udp");
|
||||
}
|
||||
else if (key == "mcast_group") {
|
||||
const std::string& valueStr = value.get_value<std::string>();
|
||||
boost::system::error_code ec;
|
||||
mcastConfig.group.address(boost::asio::ip::address_v4::from_string(valueStr, ec));
|
||||
if (ec) {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("face_system.udp.mcast_group: '" +
|
||||
valueStr + "' cannot be parsed as an IPv4 address"));
|
||||
}
|
||||
else if (!mcastConfig.group.address().is_multicast()) {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("face_system.udp.mcast_group: '" +
|
||||
valueStr + "' is not a multicast address"));
|
||||
}
|
||||
}
|
||||
else if (key == "mcast_port") {
|
||||
mcastConfig.group.port(ConfigFile::parseNumber<uint16_t>(pair, "face_system.udp"));
|
||||
}
|
||||
else if (key == "whitelist") {
|
||||
mcastConfig.netifPredicate.parseWhitelist(value);
|
||||
}
|
||||
else if (key == "blacklist") {
|
||||
mcastConfig.netifPredicate.parseBlacklist(value);
|
||||
}
|
||||
else {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system.udp." + key));
|
||||
}
|
||||
}
|
||||
|
||||
if (!enableV4 && !enableV6 && !mcastConfig.isEnabled) {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error(
|
||||
"IPv4 and IPv6 UDP channels and UDP multicast have been disabled. "
|
||||
"Remove face_system.udp section to disable UDP channels or enable at least one of them."));
|
||||
}
|
||||
}
|
||||
|
||||
if (!context.isDryRun) {
|
||||
if (enableV4) {
|
||||
udp::Endpoint endpoint(ip::udp::v4(), port);
|
||||
shared_ptr<UdpChannel> v4Channel = this->createChannel(endpoint, time::seconds(idleTimeout));
|
||||
if (!v4Channel->isListening()) {
|
||||
v4Channel->listen(context.addFace, nullptr);
|
||||
}
|
||||
providedSchemes.insert("udp");
|
||||
providedSchemes.insert("udp4");
|
||||
}
|
||||
else if (providedSchemes.count("udp4") > 0) {
|
||||
NFD_LOG_WARN("Cannot close udp4 channel after its creation");
|
||||
}
|
||||
|
||||
if (enableV6) {
|
||||
udp::Endpoint endpoint(ip::udp::v6(), port);
|
||||
shared_ptr<UdpChannel> v6Channel = this->createChannel(endpoint, time::seconds(idleTimeout));
|
||||
if (!v6Channel->isListening()) {
|
||||
v6Channel->listen(context.addFace, nullptr);
|
||||
}
|
||||
providedSchemes.insert("udp");
|
||||
providedSchemes.insert("udp6");
|
||||
}
|
||||
else if (providedSchemes.count("udp6") > 0) {
|
||||
NFD_LOG_WARN("Cannot close udp6 channel after its creation");
|
||||
}
|
||||
|
||||
if (m_mcastConfig.isEnabled != mcastConfig.isEnabled) {
|
||||
if (mcastConfig.isEnabled) {
|
||||
NFD_LOG_INFO("enabling multicast on " << mcastConfig.group);
|
||||
}
|
||||
else {
|
||||
NFD_LOG_INFO("disabling multicast");
|
||||
}
|
||||
}
|
||||
else if (m_mcastConfig.group != mcastConfig.group) {
|
||||
NFD_LOG_INFO("changing multicast group from " << m_mcastConfig.group <<
|
||||
" to " << mcastConfig.group);
|
||||
}
|
||||
else if (m_mcastConfig.netifPredicate != mcastConfig.netifPredicate) {
|
||||
NFD_LOG_INFO("changing whitelist/blacklist");
|
||||
}
|
||||
else {
|
||||
// There's no configuration change, but we still need to re-apply configuration because
|
||||
// netifs may have changed.
|
||||
}
|
||||
|
||||
m_mcastConfig = mcastConfig;
|
||||
this->applyMulticastConfig(context);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UdpFactory::createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onFailure)
|
||||
{
|
||||
BOOST_ASSERT(uri.isCanonical());
|
||||
|
||||
if (persistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
|
||||
NFD_LOG_TRACE("createFace does not support FACE_PERSISTENCY_ON_DEMAND");
|
||||
onFailure(406, "Outgoing unicast UDP faces do not support on-demand persistency");
|
||||
return;
|
||||
}
|
||||
|
||||
udp::Endpoint endpoint(ip::address::from_string(uri.getHost()),
|
||||
boost::lexical_cast<uint16_t>(uri.getPort()));
|
||||
|
||||
if (endpoint.address().is_multicast()) {
|
||||
NFD_LOG_TRACE("createFace does not support multicast faces");
|
||||
onFailure(406, "Cannot create multicast UDP faces");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end()) {
|
||||
NFD_LOG_TRACE("Requested endpoint is prohibited "
|
||||
"(reserved by this NFD or disallowed by face management protocol)");
|
||||
onFailure(406, "Requested endpoint is prohibited");
|
||||
return;
|
||||
}
|
||||
|
||||
if (wantLocalFieldsEnabled) {
|
||||
// UDP faces are never local
|
||||
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;
|
||||
}
|
||||
|
||||
// very simple logic for now
|
||||
for (const auto& i : m_channels) {
|
||||
if ((i.first.address().is_v4() && endpoint.address().is_v4()) ||
|
||||
(i.first.address().is_v6() && endpoint.address().is_v6())) {
|
||||
i.second->connect(endpoint, persistency, onCreated, onFailure);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NFD_LOG_TRACE("No channels available to connect to " + boost::lexical_cast<std::string>(endpoint));
|
||||
onFailure(504, "No channels available to connect");
|
||||
}
|
||||
|
||||
void
|
||||
UdpFactory::prohibitEndpoint(const udp::Endpoint& endpoint)
|
||||
@@ -110,7 +313,7 @@ UdpFactory::createChannel(const udp::Endpoint& endpoint,
|
||||
"endpoint is already allocated for a UDP multicast face"));
|
||||
}
|
||||
|
||||
channel = make_shared<UdpChannel>(endpoint, timeout);
|
||||
channel = std::make_shared<UdpChannel>(endpoint, timeout);
|
||||
m_channels[endpoint] = channel;
|
||||
prohibitEndpoint(endpoint);
|
||||
|
||||
@@ -126,6 +329,22 @@ UdpFactory::createChannel(const std::string& localIp, const std::string& localPo
|
||||
return createChannel(endpoint, timeout);
|
||||
}
|
||||
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
UdpFactory::getChannels() const
|
||||
{
|
||||
return getChannelsFromMap(m_channels);
|
||||
}
|
||||
|
||||
shared_ptr<UdpChannel>
|
||||
UdpFactory::findChannel(const udp::Endpoint& localEndpoint) const
|
||||
{
|
||||
auto i = m_channels.find(localEndpoint);
|
||||
if (i != m_channels.end())
|
||||
return i->second;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
shared_ptr<Face>
|
||||
UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint,
|
||||
const udp::Endpoint& multicastEndpoint,
|
||||
@@ -203,16 +422,16 @@ UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint,
|
||||
": " + std::strerror(errno)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // __linux__
|
||||
|
||||
auto linkService = make_unique<face::GenericLinkService>();
|
||||
auto transport = make_unique<face::MulticastUdpTransport>(localEndpoint, multicastEndpoint,
|
||||
std::move(receiveSocket),
|
||||
std::move(sendSocket));
|
||||
auto linkService = make_unique<GenericLinkService>();
|
||||
auto transport = make_unique<MulticastUdpTransport>(localEndpoint, multicastEndpoint,
|
||||
std::move(receiveSocket),
|
||||
std::move(sendSocket));
|
||||
face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
|
||||
m_multicastFaces[localEndpoint] = face;
|
||||
connectFaceClosedSignal(*face, [this, localEndpoint] { m_multicastFaces.erase(localEndpoint); });
|
||||
m_mcastFaces[localEndpoint] = face;
|
||||
connectFaceClosedSignal(*face, [this, localEndpoint] { m_mcastFaces.erase(localEndpoint); });
|
||||
|
||||
return face;
|
||||
}
|
||||
@@ -230,74 +449,64 @@ UdpFactory::createMulticastFace(const std::string& localIp,
|
||||
return createMulticastFace(localEndpoint, multicastEndpoint, networkInterfaceName);
|
||||
}
|
||||
|
||||
void
|
||||
UdpFactory::createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed)
|
||||
{
|
||||
BOOST_ASSERT(uri.isCanonical());
|
||||
|
||||
if (persistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
|
||||
BOOST_THROW_EXCEPTION(Error("UdpFactory::createFace does not support FACE_PERSISTENCY_ON_DEMAND"));
|
||||
}
|
||||
|
||||
udp::Endpoint endpoint(ip::address::from_string(uri.getHost()),
|
||||
boost::lexical_cast<uint16_t>(uri.getPort()));
|
||||
|
||||
if (endpoint.address().is_multicast()) {
|
||||
onConnectFailed("The provided address is multicast. Please use createMulticastFace method");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end()) {
|
||||
onConnectFailed("Requested endpoint is prohibited "
|
||||
"(reserved by this NFD or disallowed by face management protocol)");
|
||||
return;
|
||||
}
|
||||
|
||||
// very simple logic for now
|
||||
for (const auto& i : m_channels) {
|
||||
if ((i.first.address().is_v4() && endpoint.address().is_v4()) ||
|
||||
(i.first.address().is_v6() && endpoint.address().is_v6())) {
|
||||
i.second->connect(endpoint, persistency, onCreated, onConnectFailed);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
onConnectFailed("No channels available to connect to " + boost::lexical_cast<std::string>(endpoint));
|
||||
}
|
||||
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
UdpFactory::getChannels() const
|
||||
{
|
||||
std::vector<shared_ptr<const Channel>> channels;
|
||||
channels.reserve(m_channels.size());
|
||||
|
||||
for (const auto& i : m_channels)
|
||||
channels.push_back(i.second);
|
||||
|
||||
return channels;
|
||||
}
|
||||
|
||||
shared_ptr<UdpChannel>
|
||||
UdpFactory::findChannel(const udp::Endpoint& localEndpoint) const
|
||||
{
|
||||
auto i = m_channels.find(localEndpoint);
|
||||
if (i != m_channels.end())
|
||||
return i->second;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
shared_ptr<Face>
|
||||
UdpFactory::findMulticastFace(const udp::Endpoint& localEndpoint) const
|
||||
{
|
||||
auto i = m_multicastFaces.find(localEndpoint);
|
||||
if (i != m_multicastFaces.end())
|
||||
auto i = m_mcastFaces.find(localEndpoint);
|
||||
if (i != m_mcastFaces.end())
|
||||
return i->second;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
UdpFactory::applyMulticastConfig(const FaceSystem::ConfigContext& context)
|
||||
{
|
||||
// collect old faces
|
||||
std::set<shared_ptr<Face>> oldFaces;
|
||||
boost::copy(m_mcastFaces | boost::adaptors::map_values,
|
||||
std::inserter(oldFaces, oldFaces.end()));
|
||||
|
||||
if (m_mcastConfig.isEnabled) {
|
||||
// determine interfaces on which faces should be created or retained
|
||||
auto capableNetifRange = context.listNetifs() |
|
||||
boost::adaptors::filtered([this] (const NetworkInterfaceInfo& netif) {
|
||||
return netif.isUp() && netif.isMulticastCapable() &&
|
||||
!netif.ipv4Addresses.empty() &&
|
||||
m_mcastConfig.netifPredicate(netif);
|
||||
});
|
||||
|
||||
bool needIfname = false;
|
||||
#ifdef __linux__
|
||||
std::vector<NetworkInterfaceInfo> capableNetifs;
|
||||
boost::copy(capableNetifRange, std::back_inserter(capableNetifs));
|
||||
// on Linux, ifname is needed to create more than one UDP multicast face on the same group
|
||||
needIfname = capableNetifs.size() > 1;
|
||||
#else
|
||||
auto& capableNetifs = capableNetifRange;
|
||||
#endif // __linux__
|
||||
|
||||
// create faces
|
||||
for (const auto& netif : capableNetifs) {
|
||||
udp::Endpoint localEndpoint(netif.ipv4Addresses.front(), m_mcastConfig.group.port());
|
||||
shared_ptr<Face> face = this->createMulticastFace(localEndpoint, m_mcastConfig.group,
|
||||
needIfname ? netif.name : "");
|
||||
if (face->getId() == INVALID_FACEID) {
|
||||
// new face: register with forwarding
|
||||
context.addFace(face);
|
||||
}
|
||||
else {
|
||||
// existing face: don't destroy
|
||||
oldFaces.erase(face);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// destroy old faces that are not needed in new configuration
|
||||
for (const auto& face : oldFaces) {
|
||||
face->close();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
+39
-27
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -30,9 +30,13 @@
|
||||
#include "udp-channel.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/// @todo IPv6 multicast support not implemented
|
||||
|
||||
/** \brief protocol factory for UDP over IPv4 and IPv6
|
||||
*
|
||||
* UDP unicast is available over both IPv4 and IPv6.
|
||||
* UDP multicast is available over IPv4 only.
|
||||
*/
|
||||
class UdpFactory : public ProtocolFactory
|
||||
{
|
||||
public:
|
||||
@@ -49,7 +53,21 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<udp::Endpoint, shared_ptr<Face>> MulticastFaceMap;
|
||||
static const std::string&
|
||||
getId();
|
||||
|
||||
/** \brief process face_system.udp config section
|
||||
*/
|
||||
void
|
||||
processConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context) override;
|
||||
|
||||
void
|
||||
createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onFailure) override;
|
||||
|
||||
/**
|
||||
* \brief Create UDP-based channel using udp::Endpoint
|
||||
@@ -97,6 +115,9 @@ public:
|
||||
createChannel(const std::string& localIp, const std::string& localPort,
|
||||
const time::seconds& timeout = time::seconds(600));
|
||||
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
getChannels() const override;
|
||||
|
||||
/**
|
||||
* \brief Create MulticastUdpFace using udp::Endpoint
|
||||
*
|
||||
@@ -139,22 +160,6 @@ public:
|
||||
const std::string& multicastPort,
|
||||
const std::string& networkInterfaceName = "");
|
||||
|
||||
/**
|
||||
* \brief Get map of configured multicast faces
|
||||
*/
|
||||
const MulticastFaceMap&
|
||||
getMulticastFaces() const;
|
||||
|
||||
public: // from ProtocolFactory
|
||||
virtual void
|
||||
createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed) DECL_OVERRIDE;
|
||||
|
||||
virtual std::vector<shared_ptr<const Channel>>
|
||||
getChannels() const DECL_OVERRIDE;
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
void
|
||||
prohibitEndpoint(const udp::Endpoint& endpoint);
|
||||
@@ -184,20 +189,27 @@ private:
|
||||
shared_ptr<Face>
|
||||
findMulticastFace(const udp::Endpoint& localEndpoint) const;
|
||||
|
||||
void
|
||||
applyMulticastConfig(const FaceSystem::ConfigContext& context);
|
||||
|
||||
private:
|
||||
std::map<udp::Endpoint, shared_ptr<UdpChannel>> m_channels;
|
||||
MulticastFaceMap m_multicastFaces;
|
||||
|
||||
struct MulticastConfig
|
||||
{
|
||||
bool isEnabled = false;
|
||||
udp::Endpoint group = udp::getDefaultMulticastGroup();
|
||||
NetworkInterfacePredicate netifPredicate;
|
||||
};
|
||||
|
||||
MulticastConfig m_mcastConfig;
|
||||
std::map<udp::Endpoint, shared_ptr<Face>> m_mcastFaces;
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
std::set<udp::Endpoint> m_prohibitedEndpoints;
|
||||
};
|
||||
|
||||
inline const UdpFactory::MulticastFaceMap&
|
||||
UdpFactory::getMulticastFaces() const
|
||||
{
|
||||
return m_multicastFaces;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_UDP_FACTORY_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -29,7 +29,7 @@ namespace nfd {
|
||||
namespace udp {
|
||||
|
||||
ssize_t
|
||||
computeMtu(const boost::asio::ip::udp::endpoint& localEndpoint)
|
||||
computeMtu(const Endpoint& localEndpoint)
|
||||
{
|
||||
size_t mtu = 0;
|
||||
if (localEndpoint.address().is_v4()) { // IPv4
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,15 +26,26 @@
|
||||
#ifndef NFD_DAEMON_FACE_UDP_PROTOCOL_HPP
|
||||
#define NFD_DAEMON_FACE_UDP_PROTOCOL_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "core/common.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace udp {
|
||||
|
||||
typedef boost::asio::ip::udp::endpoint Endpoint;
|
||||
|
||||
/** \brief computes maximum payload size in a UDP packet
|
||||
*/
|
||||
ssize_t
|
||||
computeMtu(const boost::asio::ip::udp::endpoint& localEndpoint);
|
||||
computeMtu(const Endpoint& localEndpoint);
|
||||
|
||||
/** \return default multicast group: 224.0.23.170:56363
|
||||
*/
|
||||
inline Endpoint
|
||||
getDefaultMulticastGroup()
|
||||
{
|
||||
// 224.0.23.170:56363
|
||||
return {boost::asio::ip::address_v4(0xE00017AA), 56363};
|
||||
}
|
||||
|
||||
} // namespace udp
|
||||
} // namespace nfd
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -80,10 +80,16 @@ UnicastUdpTransport::UnicastUdpTransport(protocol::socket&& socket,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UnicastUdpTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
|
||||
bool
|
||||
UnicastUdpTransport::canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const
|
||||
{
|
||||
if (newPersistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND &&
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
UnicastUdpTransport::afterChangePersistency(ndn::nfd::FacePersistency oldPersistency)
|
||||
{
|
||||
if (getPersistency() == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND &&
|
||||
m_idleTimeout > time::nanoseconds::zero()) {
|
||||
scheduleClosureWhenIdle();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -35,7 +35,7 @@ namespace face {
|
||||
/**
|
||||
* \brief A Transport that communicates on a unicast UDP socket
|
||||
*/
|
||||
class UnicastUdpTransport DECL_CLASS_FINAL : public DatagramTransport<boost::asio::ip::udp, Unicast>
|
||||
class UnicastUdpTransport final : public DatagramTransport<boost::asio::ip::udp, Unicast>
|
||||
{
|
||||
public:
|
||||
UnicastUdpTransport(protocol::socket&& socket,
|
||||
@@ -43,8 +43,11 @@ public:
|
||||
time::nanoseconds idleTimeout);
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
|
||||
bool
|
||||
canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const final;
|
||||
|
||||
void
|
||||
afterChangePersistency(ndn::nfd::FacePersistency oldPersistency) final;
|
||||
|
||||
private:
|
||||
void
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -126,7 +126,7 @@ UnixStreamChannel::handleAccept(const boost::system::error_code& error,
|
||||
|
||||
NFD_LOG_DEBUG("[" << m_endpoint << "] Accept failed: " << error.message());
|
||||
if (onAcceptFailed)
|
||||
onAcceptFailed(error.message());
|
||||
onAcceptFailed(500, "Accept failed: " + error.message());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014 Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
@@ -20,7 +21,7 @@
|
||||
*
|
||||
* 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_DAEMON_FACE_UNIX_STREAM_CHANNEL_HPP
|
||||
#define NFD_DAEMON_FACE_UNIX_STREAM_CHANNEL_HPP
|
||||
@@ -59,7 +60,7 @@ public:
|
||||
explicit
|
||||
UnixStreamChannel(const unix_stream::Endpoint& endpoint);
|
||||
|
||||
~UnixStreamChannel() DECL_OVERRIDE;
|
||||
~UnixStreamChannel() override;
|
||||
|
||||
/**
|
||||
* \brief Enable listening on the local endpoint, accept connections,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -24,10 +24,71 @@
|
||||
*/
|
||||
|
||||
#include "unix-stream-factory.hpp"
|
||||
#include "core/logger.hpp"
|
||||
|
||||
#include <boost/filesystem.hpp> // for canonical()
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INIT("UnixStreamFactory");
|
||||
NFD_REGISTER_PROTOCOL_FACTORY(UnixStreamFactory);
|
||||
|
||||
const std::string&
|
||||
UnixStreamFactory::getId()
|
||||
{
|
||||
static std::string id("unix");
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UnixStreamFactory::processConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context)
|
||||
{
|
||||
// unix
|
||||
// {
|
||||
// path /var/run/nfd.sock
|
||||
// }
|
||||
|
||||
if (!configSection) {
|
||||
if (!context.isDryRun && !m_channels.empty()) {
|
||||
NFD_LOG_WARN("Cannot disable unix channel after initialization");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::string path = "/var/run/nfd.sock";
|
||||
|
||||
for (const auto& pair : *configSection) {
|
||||
const std::string& key = pair.first;
|
||||
const ConfigSection& value = pair.second;
|
||||
|
||||
if (key == "path") {
|
||||
path = value.get_value<std::string>();
|
||||
}
|
||||
else {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system.unix." + key));
|
||||
}
|
||||
}
|
||||
|
||||
if (!context.isDryRun) {
|
||||
auto channel = this->createChannel(path);
|
||||
if (!channel->isListening()) {
|
||||
channel->listen(context.addFace, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UnixStreamFactory::createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onFailure)
|
||||
{
|
||||
onFailure(406, "Unsupported protocol");
|
||||
}
|
||||
|
||||
shared_ptr<UnixStreamChannel>
|
||||
UnixStreamFactory::createChannel(const std::string& unixSocketPath)
|
||||
@@ -45,25 +106,10 @@ UnixStreamFactory::createChannel(const std::string& unixSocketPath)
|
||||
return channel;
|
||||
}
|
||||
|
||||
void
|
||||
UnixStreamFactory::createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(Error("UnixStreamFactory does not support 'createFace' operation"));
|
||||
}
|
||||
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
UnixStreamFactory::getChannels() const
|
||||
{
|
||||
std::vector<shared_ptr<const Channel>> channels;
|
||||
channels.reserve(m_channels.size());
|
||||
|
||||
for (const auto& i : m_channels)
|
||||
channels.push_back(i.second);
|
||||
|
||||
return channels;
|
||||
return getChannelsFromMap(m_channels);
|
||||
}
|
||||
|
||||
shared_ptr<UnixStreamChannel>
|
||||
@@ -76,4 +122,5 @@ UnixStreamFactory::findChannel(const unix_stream::Endpoint& endpoint) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -30,22 +30,28 @@
|
||||
#include "unix-stream-channel.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief protocol factory for stream-oriented Unix sockets
|
||||
*/
|
||||
class UnixStreamFactory : public ProtocolFactory
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Exception of UnixStreamFactory
|
||||
static const std::string&
|
||||
getId();
|
||||
|
||||
/** \brief process face_system.unix config section
|
||||
*/
|
||||
class Error : public ProtocolFactory::Error
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& what)
|
||||
: ProtocolFactory::Error(what)
|
||||
{
|
||||
}
|
||||
};
|
||||
void
|
||||
processConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context) override;
|
||||
|
||||
void
|
||||
createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onFailure) override;
|
||||
|
||||
/**
|
||||
* \brief Create stream-oriented Unix channel using specified socket path
|
||||
@@ -56,21 +62,12 @@ public:
|
||||
*
|
||||
* \returns always a valid pointer to a UnixStreamChannel object,
|
||||
* an exception will be thrown if the channel cannot be created.
|
||||
*
|
||||
* \throws UnixStreamFactory::Error
|
||||
*/
|
||||
shared_ptr<UnixStreamChannel>
|
||||
createChannel(const std::string& unixSocketPath);
|
||||
|
||||
public: // from ProtocolFactory
|
||||
virtual void
|
||||
createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed) DECL_OVERRIDE;
|
||||
|
||||
virtual std::vector<shared_ptr<const Channel>>
|
||||
getChannels() const DECL_OVERRIDE;
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
getChannels() const override;
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -86,6 +83,7 @@ private:
|
||||
std::map<unix_stream::Endpoint, shared_ptr<UnixStreamChannel>> m_channels;
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_UNIX_STREAM_FACTORY_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -49,14 +49,5 @@ UnixStreamTransport::UnixStreamTransport(protocol::socket&& socket)
|
||||
NFD_LOG_FACE_INFO("Creating transport");
|
||||
}
|
||||
|
||||
void
|
||||
UnixStreamTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
|
||||
{
|
||||
if (newPersistency != ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
|
||||
BOOST_THROW_EXCEPTION(
|
||||
std::invalid_argument("UnixStreamTransport supports only FACE_PERSISTENCY_ON_DEMAND"));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -38,15 +38,11 @@ namespace face {
|
||||
/**
|
||||
* \brief A Transport that communicates on a stream-oriented Unix domain socket
|
||||
*/
|
||||
class UnixStreamTransport DECL_CLASS_FINAL : public StreamTransport<boost::asio::local::stream_protocol>
|
||||
class UnixStreamTransport final : public StreamTransport<boost::asio::local::stream_protocol>
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
UnixStreamTransport(protocol::socket&& socket);
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -24,11 +24,106 @@
|
||||
*/
|
||||
|
||||
#include "websocket-factory.hpp"
|
||||
#include "core/logger.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
namespace ip = boost::asio::ip;
|
||||
|
||||
NFD_LOG_INIT("WebSocketFactory");
|
||||
NFD_REGISTER_PROTOCOL_FACTORY(WebSocketFactory);
|
||||
|
||||
const std::string&
|
||||
WebSocketFactory::getId()
|
||||
{
|
||||
static std::string id("websocket");
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WebSocketFactory::processConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context)
|
||||
{
|
||||
// websocket
|
||||
// {
|
||||
// listen yes
|
||||
// port 9696
|
||||
// enable_v4 yes
|
||||
// enable_v6 yes
|
||||
// }
|
||||
|
||||
bool wantListen = false;
|
||||
uint16_t port = 9696;
|
||||
bool enableV4 = true;
|
||||
bool enableV6 = true;
|
||||
|
||||
if (configSection) {
|
||||
wantListen = true;
|
||||
for (const auto& pair : *configSection) {
|
||||
const std::string& key = pair.first;
|
||||
|
||||
if (key == "listen") {
|
||||
wantListen = ConfigFile::parseYesNo(pair, "face_system.websocket");
|
||||
}
|
||||
else if (key == "port") {
|
||||
port = ConfigFile::parseNumber<uint16_t>(pair, "face_system.websocket");
|
||||
}
|
||||
else if (key == "enable_v4") {
|
||||
enableV4 = ConfigFile::parseYesNo(pair, "face_system.websocket");
|
||||
}
|
||||
else if (key == "enable_v6") {
|
||||
enableV6 = ConfigFile::parseYesNo(pair, "face_system.websocket");
|
||||
}
|
||||
else {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system.websocket." + key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!enableV4 && !enableV6) {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error(
|
||||
"IPv4 and IPv6 WebSocket channels have been disabled. Remove face_system.websocket section "
|
||||
"to disable WebSocket channels or enable at least one channel type."));
|
||||
}
|
||||
|
||||
if (!enableV4 && enableV6) {
|
||||
// websocketpp's IPv6 socket always accepts IPv4 connections.
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD does not allow pure IPv6 WebSocket channel."));
|
||||
}
|
||||
|
||||
if (!context.isDryRun) {
|
||||
if (!wantListen) {
|
||||
if (!m_channels.empty()) {
|
||||
NFD_LOG_WARN("Cannot close WebSocket channel after initialization");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(enableV4);
|
||||
websocket::Endpoint endpoint(enableV6 ? ip::tcp::v6() : ip::tcp::v4(), port);
|
||||
|
||||
auto channel = this->createChannel(endpoint);
|
||||
if (!channel->isListening()) {
|
||||
channel->listen(context.addFace);
|
||||
if (m_channels.size() > 1) {
|
||||
NFD_LOG_WARN("Adding WebSocket channel for new endpoint; cannot close existing channels");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketFactory::createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onFailure)
|
||||
{
|
||||
onFailure(406, "Unsupported protocol");
|
||||
}
|
||||
|
||||
shared_ptr<WebSocketChannel>
|
||||
WebSocketFactory::createChannel(const websocket::Endpoint& endpoint)
|
||||
{
|
||||
@@ -50,25 +145,10 @@ WebSocketFactory::createChannel(const std::string& localIp, const std::string& l
|
||||
return createChannel(endpoint);
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketFactory::createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(Error("WebSocketFactory does not support 'createFace' operation"));
|
||||
}
|
||||
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
WebSocketFactory::getChannels() const
|
||||
{
|
||||
std::vector<shared_ptr<const Channel>> channels;
|
||||
channels.reserve(m_channels.size());
|
||||
|
||||
for (const auto& i : m_channels)
|
||||
channels.push_back(i.second);
|
||||
|
||||
return channels;
|
||||
return getChannelsFromMap(m_channels);
|
||||
}
|
||||
|
||||
shared_ptr<WebSocketChannel>
|
||||
@@ -81,4 +161,5 @@ WebSocketFactory::findChannel(const websocket::Endpoint& endpoint) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -30,22 +30,30 @@
|
||||
#include "websocket-channel.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief protocol factory for WebSocket
|
||||
*/
|
||||
class WebSocketFactory : public ProtocolFactory
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Exception of WebSocketFactory
|
||||
static const std::string&
|
||||
getId();
|
||||
|
||||
/** \brief process face_system.websocket config section
|
||||
*/
|
||||
class Error : public ProtocolFactory::Error
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& what)
|
||||
: ProtocolFactory::Error(what)
|
||||
{
|
||||
}
|
||||
};
|
||||
void
|
||||
processConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context) override;
|
||||
|
||||
/** \brief unicast face creation is not supported and will always fail
|
||||
*/
|
||||
void
|
||||
createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
bool wantLocalFieldsEnabled,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onFailure) override;
|
||||
|
||||
/**
|
||||
* \brief Create WebSocket-based channel using websocket::Endpoint
|
||||
@@ -58,8 +66,6 @@ public:
|
||||
*
|
||||
* \returns always a valid pointer to a WebSocketChannel object, an exception
|
||||
* is thrown if it cannot be created.
|
||||
*
|
||||
* \throws WebSocketFactory::Error
|
||||
*/
|
||||
shared_ptr<WebSocketChannel>
|
||||
createChannel(const websocket::Endpoint& localEndpoint);
|
||||
@@ -69,21 +75,12 @@ public:
|
||||
*
|
||||
* This method is just a helper that converts a string representation of localIp and port to
|
||||
* websocket::Endpoint and calls the other createChannel overload.
|
||||
*
|
||||
* \throws WebSocketFactory::Error
|
||||
*/
|
||||
shared_ptr<WebSocketChannel>
|
||||
createChannel(const std::string& localIp, const std::string& localPort);
|
||||
|
||||
public: // from ProtocolFactory
|
||||
virtual void
|
||||
createFace(const FaceUri& uri,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed) DECL_OVERRIDE;
|
||||
|
||||
virtual std::vector<shared_ptr<const Channel>>
|
||||
getChannels() const DECL_OVERRIDE;
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
getChannels() const override;
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -99,6 +96,7 @@ private:
|
||||
std::map<websocket::Endpoint, shared_ptr<WebSocketChannel>> m_channels;
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_WEBSOCKET_FACTORY_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -30,6 +30,24 @@ namespace face {
|
||||
|
||||
NFD_LOG_INIT("WebSocketTransport");
|
||||
|
||||
static bool
|
||||
isLoopback(const boost::asio::ip::address& addr)
|
||||
{
|
||||
if (addr.is_loopback()) {
|
||||
return true;
|
||||
}
|
||||
// Workaround for loopback IPv4-mapped IPv6 addresses
|
||||
// see https://svn.boost.org/trac/boost/ticket/9084
|
||||
else if (addr.is_v6()) {
|
||||
auto addr6 = addr.to_v6();
|
||||
if (addr6.is_v4_mapped()) {
|
||||
return addr6.to_v4().is_loopback();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
WebSocketTransport::WebSocketTransport(websocketpp::connection_hdl hdl,
|
||||
websocket::Server& server,
|
||||
time::milliseconds pingInterval)
|
||||
@@ -41,11 +59,13 @@ WebSocketTransport::WebSocketTransport(websocketpp::connection_hdl hdl,
|
||||
this->setLocalUri(FaceUri(sock.local_endpoint(), "ws"));
|
||||
this->setRemoteUri(FaceUri(sock.remote_endpoint(), "wsclient"));
|
||||
|
||||
if (sock.local_endpoint().address().is_loopback() &&
|
||||
sock.remote_endpoint().address().is_loopback())
|
||||
if (isLoopback(sock.local_endpoint().address()) &&
|
||||
isLoopback(sock.remote_endpoint().address())) {
|
||||
this->setScope(ndn::nfd::FACE_SCOPE_LOCAL);
|
||||
else
|
||||
}
|
||||
else {
|
||||
this->setScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
|
||||
}
|
||||
|
||||
this->setPersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
|
||||
this->setLinkType(ndn::nfd::LINK_TYPE_POINT_TO_POINT);
|
||||
@@ -56,15 +76,6 @@ WebSocketTransport::WebSocketTransport(websocketpp::connection_hdl hdl,
|
||||
NFD_LOG_FACE_INFO("Creating transport");
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
|
||||
{
|
||||
if (newPersistency != ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
|
||||
BOOST_THROW_EXCEPTION(
|
||||
std::invalid_argument("WebSocketTransport supports only FACE_PERSISTENCY_ON_DEMAND"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketTransport::doSend(Transport::Packet&& packet)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -51,8 +51,8 @@ public:
|
||||
|
||||
/** \brief A Transport that communicates on a WebSocket connection
|
||||
*/
|
||||
class WebSocketTransport DECL_CLASS_FINAL : public Transport
|
||||
, protected virtual WebSocketTransportCounters
|
||||
class WebSocketTransport final : public Transport
|
||||
, protected virtual WebSocketTransportCounters
|
||||
{
|
||||
public:
|
||||
/** \brief counters provided by WebSocketTransport
|
||||
@@ -63,8 +63,8 @@ public:
|
||||
websocket::Server& server,
|
||||
time::milliseconds pingInterval);
|
||||
|
||||
virtual const Counters&
|
||||
getCounters() const DECL_OVERRIDE;
|
||||
const Counters&
|
||||
getCounters() const final;
|
||||
|
||||
/** \brief Translates a message into a Block
|
||||
* and delivers it to the link service
|
||||
@@ -79,15 +79,12 @@ public:
|
||||
handlePongTimeout();
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
|
||||
|
||||
virtual void
|
||||
doClose() DECL_FINAL;
|
||||
void
|
||||
doClose() final;
|
||||
|
||||
private:
|
||||
virtual void
|
||||
doSend(Transport::Packet&& packet) DECL_FINAL;
|
||||
void
|
||||
doSend(Transport::Packet&& packet) final;
|
||||
|
||||
void
|
||||
schedulePing();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -24,40 +24,49 @@
|
||||
*/
|
||||
|
||||
#include "access-strategy.hpp"
|
||||
#include "algorithm.hpp"
|
||||
#include "core/logger.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
NFD_LOG_INIT("AccessStrategy");
|
||||
|
||||
const Name AccessStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/access/%FD%01");
|
||||
NFD_REGISTER_STRATEGY(AccessStrategy);
|
||||
|
||||
AccessStrategy::AccessStrategy(Forwarder& forwarder, const Name& name)
|
||||
: Strategy(forwarder, name)
|
||||
: Strategy(forwarder)
|
||||
, m_removeFaceInfoConn(this->beforeRemoveFace.connect(
|
||||
bind(&AccessStrategy::removeFaceInfo, this, _1)))
|
||||
{
|
||||
ParsedInstanceName parsed = parseInstanceName(name);
|
||||
if (!parsed.parameters.empty()) {
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("AccessStrategy does not accept parameters"));
|
||||
}
|
||||
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument(
|
||||
"AccessStrategy does not support version " + std::to_string(*parsed.version)));
|
||||
}
|
||||
this->setInstanceName(makeInstanceName(name, getStrategyName()));
|
||||
}
|
||||
|
||||
AccessStrategy::~AccessStrategy()
|
||||
const Name&
|
||||
AccessStrategy::getStrategyName()
|
||||
{
|
||||
static Name strategyName("/localhost/nfd/strategy/access/%FD%01");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
void
|
||||
AccessStrategy::afterReceiveInterest(const Face& inFace,
|
||||
const Interest& interest,
|
||||
shared_ptr<fib::Entry> fibEntry,
|
||||
shared_ptr<pit::Entry> pitEntry)
|
||||
AccessStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
RetxSuppression::Result suppressResult = m_retxSuppression.decide(inFace, interest, *pitEntry);
|
||||
switch (suppressResult) {
|
||||
case RetxSuppression::NEW:
|
||||
this->afterReceiveNewInterest(inFace, interest, fibEntry, pitEntry);
|
||||
this->afterReceiveNewInterest(inFace, interest, pitEntry);
|
||||
break;
|
||||
case RetxSuppression::FORWARD:
|
||||
this->afterReceiveRetxInterest(inFace, interest, fibEntry, pitEntry);
|
||||
this->afterReceiveRetxInterest(inFace, interest, pitEntry);
|
||||
break;
|
||||
case RetxSuppression::SUPPRESS:
|
||||
NFD_LOG_DEBUG(interest << " interestFrom " << inFace.getId() << " retx-suppress");
|
||||
@@ -69,13 +78,12 @@ AccessStrategy::afterReceiveInterest(const Face& inFace,
|
||||
}
|
||||
|
||||
void
|
||||
AccessStrategy::afterReceiveNewInterest(const Face& inFace,
|
||||
const Interest& interest,
|
||||
shared_ptr<fib::Entry> fibEntry,
|
||||
shared_ptr<pit::Entry> pitEntry)
|
||||
AccessStrategy::afterReceiveNewInterest(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
|
||||
Name miName;
|
||||
shared_ptr<MtInfo> mi;
|
||||
MtInfo* mi = nullptr;
|
||||
std::tie(miName, mi) = this->findPrefixMeasurements(*pitEntry);
|
||||
|
||||
// has measurements for Interest Name?
|
||||
@@ -84,7 +92,7 @@ AccessStrategy::afterReceiveNewInterest(const Face& inFace,
|
||||
" new-interest mi=" << miName);
|
||||
|
||||
// send to last working nexthop
|
||||
bool isSentToLastNexthop = this->sendToLastNexthop(inFace, pitEntry, *mi, fibEntry);
|
||||
bool isSentToLastNexthop = this->sendToLastNexthop(inFace, interest, pitEntry, *mi, fibEntry);
|
||||
|
||||
if (isSentToLastNexthop) {
|
||||
return;
|
||||
@@ -98,22 +106,26 @@ AccessStrategy::afterReceiveNewInterest(const Face& inFace,
|
||||
// no measurements, or last working nexthop unavailable
|
||||
|
||||
// multicast to all nexthops except incoming face
|
||||
this->multicast(pitEntry, fibEntry, {inFace.getId()});
|
||||
int nMulticastSent = this->multicast(inFace, interest, pitEntry, fibEntry);
|
||||
|
||||
if (nMulticastSent < 1) {
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AccessStrategy::afterReceiveRetxInterest(const Face& inFace,
|
||||
const Interest& interest,
|
||||
shared_ptr<fib::Entry> fibEntry,
|
||||
shared_ptr<pit::Entry> pitEntry)
|
||||
AccessStrategy::afterReceiveRetxInterest(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
|
||||
NFD_LOG_DEBUG(interest << " interestFrom " << inFace.getId() << " retx-forward");
|
||||
this->multicast(pitEntry, fibEntry, {inFace.getId()});
|
||||
this->multicast(inFace, interest, pitEntry, fibEntry);
|
||||
}
|
||||
|
||||
bool
|
||||
AccessStrategy::sendToLastNexthop(const Face& inFace, shared_ptr<pit::Entry> pitEntry, MtInfo& mi,
|
||||
shared_ptr<fib::Entry> fibEntry)
|
||||
AccessStrategy::sendToLastNexthop(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry, MtInfo& mi,
|
||||
const fib::Entry& fibEntry)
|
||||
{
|
||||
if (mi.lastNexthop == face::INVALID_FACEID) {
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " no-last-nexthop");
|
||||
@@ -125,13 +137,13 @@ AccessStrategy::sendToLastNexthop(const Face& inFace, shared_ptr<pit::Entry> pit
|
||||
return false;
|
||||
}
|
||||
|
||||
shared_ptr<Face> face = this->getFace(mi.lastNexthop);
|
||||
if (face == nullptr || !fibEntry->hasNextHop(face)) {
|
||||
Face* outFace = this->getFace(mi.lastNexthop);
|
||||
if (outFace == nullptr || !fibEntry.hasNextHop(*outFace)) {
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " last-nexthop-gone");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pitEntry->violatesScope(*face)) {
|
||||
if (wouldViolateScope(inFace, interest, *outFace)) {
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " last-nexthop-violates-scope");
|
||||
return false;
|
||||
}
|
||||
@@ -140,68 +152,83 @@ AccessStrategy::sendToLastNexthop(const Face& inFace, shared_ptr<pit::Entry> pit
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " interestTo " << mi.lastNexthop <<
|
||||
" last-nexthop rto=" << time::duration_cast<time::microseconds>(rto).count());
|
||||
|
||||
this->sendInterest(pitEntry, face);
|
||||
this->sendInterest(pitEntry, *outFace, interest);
|
||||
|
||||
// schedule RTO timeout
|
||||
shared_ptr<PitInfo> pi = pitEntry->getOrCreateStrategyInfo<PitInfo>();
|
||||
PitInfo* pi = pitEntry->insertStrategyInfo<PitInfo>().first;
|
||||
pi->rtoTimer = scheduler::schedule(rto,
|
||||
bind(&AccessStrategy::afterRtoTimeout, this, weak_ptr<pit::Entry>(pitEntry),
|
||||
weak_ptr<fib::Entry>(fibEntry), inFace.getId(), mi.lastNexthop));
|
||||
inFace.getId(), mi.lastNexthop));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
AccessStrategy::afterRtoTimeout(weak_ptr<pit::Entry> pitWeak, weak_ptr<fib::Entry> fibWeak,
|
||||
FaceId inFace, FaceId firstOutFace)
|
||||
AccessStrategy::afterRtoTimeout(weak_ptr<pit::Entry> pitWeak, FaceId inFaceId, FaceId firstOutFaceId)
|
||||
{
|
||||
shared_ptr<pit::Entry> pitEntry = pitWeak.lock();
|
||||
BOOST_ASSERT(pitEntry != nullptr);
|
||||
// pitEntry can't become nullptr, because RTO timer should be cancelled upon pitEntry destruction
|
||||
// if pitEntry is gone, RTO timer should have been cancelled
|
||||
|
||||
shared_ptr<fib::Entry> fibEntry = fibWeak.lock();
|
||||
if (fibEntry == nullptr) {
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " timeoutFrom " << firstOutFace << " fib-gone");
|
||||
Face* inFace = this->getFace(inFaceId);
|
||||
if (inFace == nullptr) {
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " timeoutFrom " << firstOutFaceId <<
|
||||
" inFace-gone " << inFaceId);
|
||||
return;
|
||||
}
|
||||
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " timeoutFrom " << firstOutFace <<
|
||||
" multicast-except " << inFace << ',' << firstOutFace);
|
||||
this->multicast(pitEntry, fibEntry, {inFace, firstOutFace});
|
||||
pit::InRecordCollection::iterator inRecord = pitEntry->getInRecord(*inFace);
|
||||
BOOST_ASSERT(inRecord != pitEntry->in_end());
|
||||
// in-record is erased only if Interest is satisfied, and RTO timer should have been cancelled
|
||||
// note: if this strategy is extended to send Nacks, that would also erase in-record,
|
||||
// and RTO timer should be cancelled in that case as well
|
||||
|
||||
const Interest& interest = inRecord->getInterest();
|
||||
|
||||
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
|
||||
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " timeoutFrom " << firstOutFaceId <<
|
||||
" multicast-except " << firstOutFaceId);
|
||||
this->multicast(*inFace, interest, pitEntry, fibEntry, firstOutFaceId);
|
||||
}
|
||||
|
||||
void
|
||||
AccessStrategy::multicast(shared_ptr<pit::Entry> pitEntry, shared_ptr<fib::Entry> fibEntry,
|
||||
std::unordered_set<FaceId> exceptFaces)
|
||||
int
|
||||
AccessStrategy::multicast(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry, const fib::Entry& fibEntry,
|
||||
FaceId exceptFace)
|
||||
{
|
||||
for (const fib::NextHop& nexthop : fibEntry->getNextHops()) {
|
||||
shared_ptr<Face> face = nexthop.getFace();
|
||||
if (exceptFaces.count(face->getId()) > 0) {
|
||||
int nSent = 0;
|
||||
for (const fib::NextHop& nexthop : fibEntry.getNextHops()) {
|
||||
Face& outFace = nexthop.getFace();
|
||||
if (&outFace == &inFace || outFace.getId() == exceptFace ||
|
||||
wouldViolateScope(inFace, interest, outFace)) {
|
||||
continue;
|
||||
}
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " interestTo " << face->getId() <<
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " interestTo " << outFace.getId() <<
|
||||
" multicast");
|
||||
this->sendInterest(pitEntry, face);
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
++nSent;
|
||||
}
|
||||
return nSent;
|
||||
}
|
||||
|
||||
void
|
||||
AccessStrategy::beforeSatisfyInterest(shared_ptr<pit::Entry> pitEntry,
|
||||
AccessStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const Face& inFace, const Data& data)
|
||||
{
|
||||
shared_ptr<PitInfo> pi = pitEntry->getStrategyInfo<PitInfo>();
|
||||
PitInfo* pi = pitEntry->getStrategyInfo<PitInfo>();
|
||||
if (pi != nullptr) {
|
||||
pi->rtoTimer.cancel();
|
||||
}
|
||||
|
||||
if (pitEntry->getInRecords().empty()) { // already satisfied by another upstream
|
||||
if (!pitEntry->hasInRecords()) { // already satisfied by another upstream
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " dataFrom " << inFace.getId() <<
|
||||
" not-fastest");
|
||||
return;
|
||||
}
|
||||
|
||||
pit::OutRecordCollection::const_iterator outRecord = pitEntry->getOutRecord(inFace);
|
||||
if (outRecord == pitEntry->getOutRecords().end()) { // no OutRecord
|
||||
pit::OutRecordCollection::iterator outRecord = pitEntry->getOutRecord(inFace);
|
||||
if (outRecord == pitEntry->out_end()) { // no out-record
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " dataFrom " << inFace.getId() <<
|
||||
" no-out-record");
|
||||
return;
|
||||
@@ -217,10 +244,11 @@ void
|
||||
AccessStrategy::updateMeasurements(const Face& inFace, const Data& data,
|
||||
const RttEstimator::Duration& rtt)
|
||||
{
|
||||
///\todo move FaceInfoTable out of AccessStrategy instance, to Measurements or somewhere else
|
||||
FaceInfo& fi = m_fit[inFace.getId()];
|
||||
fi.rtt.addMeasurement(rtt);
|
||||
|
||||
shared_ptr<MtInfo> mi = this->addPrefixMeasurements(data);
|
||||
MtInfo* mi = this->addPrefixMeasurements(data);
|
||||
if (mi->lastNexthop != inFace.getId()) {
|
||||
mi->lastNexthop = inFace.getId();
|
||||
mi->rtt = fi.rtt;
|
||||
@@ -236,26 +264,26 @@ AccessStrategy::MtInfo::MtInfo()
|
||||
{
|
||||
}
|
||||
|
||||
std::tuple<Name, shared_ptr<AccessStrategy::MtInfo>>
|
||||
std::tuple<Name, AccessStrategy::MtInfo*>
|
||||
AccessStrategy::findPrefixMeasurements(const pit::Entry& pitEntry)
|
||||
{
|
||||
shared_ptr<measurements::Entry> me = this->getMeasurements().findLongestPrefixMatch(pitEntry);
|
||||
measurements::Entry* me = this->getMeasurements().findLongestPrefixMatch(pitEntry);
|
||||
if (me == nullptr) {
|
||||
return std::forward_as_tuple(Name(), nullptr);
|
||||
return std::make_tuple(Name(), nullptr);
|
||||
}
|
||||
|
||||
shared_ptr<MtInfo> mi = me->getStrategyInfo<MtInfo>();
|
||||
MtInfo* mi = me->getStrategyInfo<MtInfo>();
|
||||
BOOST_ASSERT(mi != nullptr);
|
||||
// XXX after runtime strategy change, it's possible that me exists but mi doesn't exist;
|
||||
// this case needs another longest prefix match until mi is found
|
||||
return std::forward_as_tuple(me->getName(), mi);
|
||||
return std::make_tuple(me->getName(), mi);
|
||||
}
|
||||
|
||||
shared_ptr<AccessStrategy::MtInfo>
|
||||
AccessStrategy::MtInfo*
|
||||
AccessStrategy::addPrefixMeasurements(const Data& data)
|
||||
{
|
||||
shared_ptr<measurements::Entry> me;
|
||||
if (data.getName().size() >= 1) {
|
||||
measurements::Entry* me = nullptr;
|
||||
if (!data.getName().empty()) {
|
||||
me = this->getMeasurements().get(data.getName().getPrefix(-1));
|
||||
}
|
||||
if (me == nullptr) { // parent of Data Name is not in this strategy, or Data Name is empty
|
||||
@@ -267,7 +295,7 @@ AccessStrategy::addPrefixMeasurements(const Data& data)
|
||||
static const time::nanoseconds ME_LIFETIME = time::seconds(8);
|
||||
this->getMeasurements().extendLifetime(*me, ME_LIFETIME);
|
||||
|
||||
return me->getOrCreateStrategyInfo<MtInfo>();
|
||||
return me->insertStrategyInfo<MtInfo>().first;
|
||||
}
|
||||
|
||||
AccessStrategy::FaceInfo::FaceInfo()
|
||||
@@ -276,9 +304,9 @@ AccessStrategy::FaceInfo::FaceInfo()
|
||||
}
|
||||
|
||||
void
|
||||
AccessStrategy::removeFaceInfo(shared_ptr<Face> face)
|
||||
AccessStrategy::removeFaceInfo(const Face& face)
|
||||
{
|
||||
m_fit.erase(face->getId());
|
||||
m_fit.erase(face.getId());
|
||||
}
|
||||
|
||||
} // namespace fw
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -49,21 +49,20 @@ namespace fw {
|
||||
class AccessStrategy : public Strategy
|
||||
{
|
||||
public:
|
||||
AccessStrategy(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
|
||||
explicit
|
||||
AccessStrategy(Forwarder& forwarder, const Name& name = getStrategyName());
|
||||
|
||||
virtual
|
||||
~AccessStrategy();
|
||||
static const Name&
|
||||
getStrategyName();
|
||||
|
||||
public: // triggers
|
||||
virtual void
|
||||
afterReceiveInterest(const Face& inFace,
|
||||
const Interest& interest,
|
||||
shared_ptr<fib::Entry> fibEntry,
|
||||
shared_ptr<pit::Entry> pitEntry) DECL_OVERRIDE;
|
||||
afterReceiveInterest(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
virtual void
|
||||
beforeSatisfyInterest(shared_ptr<pit::Entry> pitEntry,
|
||||
const Face& inFace, const Data& data) DECL_OVERRIDE;
|
||||
beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const Face& inFace, const Data& data) override;
|
||||
|
||||
private: // StrategyInfo
|
||||
/** \brief StrategyInfo on PIT entry
|
||||
@@ -101,13 +100,13 @@ private: // StrategyInfo
|
||||
|
||||
/** \brief find per-prefix measurements for Interest
|
||||
*/
|
||||
std::tuple<Name, shared_ptr<MtInfo>>
|
||||
std::tuple<Name, MtInfo*>
|
||||
findPrefixMeasurements(const pit::Entry& pitEntry);
|
||||
|
||||
/** \brief get or create pre-prefix measurements for incoming Data
|
||||
* \note This function creates MtInfo but doesn't update it.
|
||||
*/
|
||||
shared_ptr<MtInfo>
|
||||
MtInfo*
|
||||
addPrefixMeasurements(const Data& data);
|
||||
|
||||
/** \brief global per-face StrategyInfo
|
||||
@@ -124,47 +123,41 @@ private: // StrategyInfo
|
||||
typedef std::unordered_map<FaceId, FaceInfo> FaceInfoTable;
|
||||
|
||||
void
|
||||
removeFaceInfo(shared_ptr<Face> face);
|
||||
removeFaceInfo(const Face& face);
|
||||
|
||||
private: // forwarding procedures
|
||||
void
|
||||
afterReceiveNewInterest(const Face& inFace,
|
||||
const Interest& interest,
|
||||
shared_ptr<fib::Entry> fibEntry,
|
||||
shared_ptr<pit::Entry> pitEntry);
|
||||
afterReceiveNewInterest(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry);
|
||||
|
||||
void
|
||||
afterReceiveRetxInterest(const Face& inFace,
|
||||
const Interest& interest,
|
||||
shared_ptr<fib::Entry> fibEntry,
|
||||
shared_ptr<pit::Entry> pitEntry);
|
||||
afterReceiveRetxInterest(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry);
|
||||
|
||||
/** \brief send to last working nexthop
|
||||
* \return whether an Interest is sent
|
||||
*/
|
||||
bool
|
||||
sendToLastNexthop(const Face& inFace, shared_ptr<pit::Entry> pitEntry, MtInfo& mi,
|
||||
shared_ptr<fib::Entry> fibEntry);
|
||||
sendToLastNexthop(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry, MtInfo& mi,
|
||||
const fib::Entry& fibEntry);
|
||||
|
||||
void
|
||||
afterRtoTimeout(weak_ptr<pit::Entry> pitWeak, weak_ptr<fib::Entry> fibWeak,
|
||||
FaceId inFace, FaceId firstOutFace);
|
||||
afterRtoTimeout(weak_ptr<pit::Entry> pitWeak, FaceId inFaceId, FaceId firstOutFaceId);
|
||||
|
||||
/** \brief multicast to all nexthops
|
||||
* \param exceptFaces don't forward to those faces
|
||||
* \param exceptFace don't forward to this face; also, inFace is always excluded
|
||||
* \return how many Interests are sent
|
||||
*/
|
||||
void
|
||||
multicast(shared_ptr<pit::Entry> pitEntry,
|
||||
shared_ptr<fib::Entry> fibEntry,
|
||||
std::unordered_set<FaceId> exceptFaces = std::unordered_set<FaceId>());
|
||||
int
|
||||
multicast(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry, const fib::Entry& fibEntry,
|
||||
FaceId exceptFace = face::INVALID_FACEID);
|
||||
|
||||
void
|
||||
updateMeasurements(const Face& inFace, const Data& data,
|
||||
const RttEstimator::Duration& rtt);
|
||||
|
||||
public:
|
||||
static const Name STRATEGY_NAME;
|
||||
|
||||
private:
|
||||
FaceInfoTable m_fit;
|
||||
RetxSuppressionFixed m_retxSuppression;
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of 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/>.
|
||||
*/
|
||||
|
||||
#include "algorithm.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace scope_prefix {
|
||||
const Name LOCALHOST("ndn:/localhost");
|
||||
const Name LOCALHOP("ndn:/localhop");
|
||||
} // namespace scope_prefix
|
||||
|
||||
namespace fw {
|
||||
|
||||
bool
|
||||
wouldViolateScope(const Face& inFace, const Interest& interest, const Face& outFace)
|
||||
{
|
||||
if (outFace.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) {
|
||||
// forwarding to a local face is always allowed
|
||||
return false;
|
||||
}
|
||||
|
||||
if (scope_prefix::LOCALHOST.isPrefixOf(interest.getName())) {
|
||||
// localhost Interests cannot be forwarded to a non-local face
|
||||
return true;
|
||||
}
|
||||
|
||||
if (scope_prefix::LOCALHOP.isPrefixOf(interest.getName())) {
|
||||
// localhop Interests can be forwarded to a non-local face only if it comes from a local face
|
||||
return inFace.getScope() != ndn::nfd::FACE_SCOPE_LOCAL;
|
||||
}
|
||||
|
||||
// Interest name is not subject to scope control
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
canForwardToLegacy(const pit::Entry& pitEntry, const Face& face)
|
||||
{
|
||||
time::steady_clock::TimePoint now = time::steady_clock::now();
|
||||
|
||||
bool hasUnexpiredOutRecord = std::any_of(pitEntry.out_begin(), pitEntry.out_end(),
|
||||
[&face, &now] (const pit::OutRecord& outRecord) {
|
||||
return &outRecord.getFace() == &face && outRecord.getExpiry() >= now;
|
||||
});
|
||||
if (hasUnexpiredOutRecord) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasUnexpiredOtherInRecord = std::any_of(pitEntry.in_begin(), pitEntry.in_end(),
|
||||
[&face, &now] (const pit::InRecord& inRecord) {
|
||||
return &inRecord.getFace() != &face && inRecord.getExpiry() >= now;
|
||||
});
|
||||
if (!hasUnexpiredOtherInRecord) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
findDuplicateNonce(const pit::Entry& pitEntry, uint32_t nonce, const Face& face)
|
||||
{
|
||||
int dnw = DUPLICATE_NONCE_NONE;
|
||||
|
||||
for (const pit::InRecord& inRecord : pitEntry.getInRecords()) {
|
||||
if (inRecord.getLastNonce() == nonce) {
|
||||
if (&inRecord.getFace() == &face) {
|
||||
dnw |= DUPLICATE_NONCE_IN_SAME;
|
||||
}
|
||||
else {
|
||||
dnw |= DUPLICATE_NONCE_IN_OTHER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const pit::OutRecord& outRecord : pitEntry.getOutRecords()) {
|
||||
if (outRecord.getLastNonce() == nonce) {
|
||||
if (&outRecord.getFace() == &face) {
|
||||
dnw |= DUPLICATE_NONCE_OUT_SAME;
|
||||
}
|
||||
else {
|
||||
dnw |= DUPLICATE_NONCE_OUT_OTHER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dnw;
|
||||
}
|
||||
|
||||
bool
|
||||
hasPendingOutRecords(const pit::Entry& pitEntry)
|
||||
{
|
||||
time::steady_clock::TimePoint now = time::steady_clock::now();
|
||||
return std::any_of(pitEntry.out_begin(), pitEntry.out_end(),
|
||||
[&now] (const pit::OutRecord& outRecord) {
|
||||
return outRecord.getExpiry() >= now &&
|
||||
outRecord.getIncomingNack() == nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,114 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of 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_DAEMON_FW_PIT_ALGORITHM_HPP
|
||||
#define NFD_DAEMON_FW_PIT_ALGORITHM_HPP
|
||||
|
||||
#include "table/pit-entry.hpp"
|
||||
|
||||
/** \file
|
||||
* This file contains common algorithms used by forwarding strategies.
|
||||
*/
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/** \brief contain name prefixes that affect namespace-based scope control
|
||||
* \sa https://redmine.named-data.net/projects/nfd/wiki/ScopeControl
|
||||
*/
|
||||
namespace scope_prefix {
|
||||
|
||||
/** \brief ndn:/localhost
|
||||
*
|
||||
* The localhost scope limits propagation to the applications on the originating host.
|
||||
*
|
||||
* Interest and Data packets under prefix ndn:/localhost are restricted by these rules:
|
||||
* \li Interest can come from and go to local faces only.
|
||||
* \li Data can come from and go to local faces only.
|
||||
*/
|
||||
extern const Name LOCALHOST;
|
||||
|
||||
/** \brief ndn:/localhop
|
||||
*
|
||||
* The localhop scope limits propagation to no further than the next node.
|
||||
*
|
||||
* Interest packets under prefix ndn:/localhop are restricted by these rules:
|
||||
* \li If an Interest is received from a local face, it can be forwarded to a non-local face.
|
||||
* \li If an Interest is received from a non-local face, it cannot be forwarded to a non-local face.
|
||||
* \li In either case the Interest can be forwarded to a local face.
|
||||
* \li PIT entry can be satisfied by Data from any source.
|
||||
*
|
||||
* Data packets under prefix ndn:/localhop are unrestricted.
|
||||
*/
|
||||
extern const Name LOCALHOP;
|
||||
|
||||
} // namespace scope_prefix
|
||||
|
||||
namespace fw {
|
||||
|
||||
/** \brief determine whether forwarding the Interest in \p pitEntry to \p outFace would violate scope
|
||||
* \sa https://redmine.named-data.net/projects/nfd/wiki/ScopeControl
|
||||
*/
|
||||
bool
|
||||
wouldViolateScope(const Face& inFace, const Interest& interest, const Face& outFace);
|
||||
|
||||
/** \brief decide whether Interest can be forwarded to face
|
||||
*
|
||||
* \return true if out-record of this face does not exist or has expired,
|
||||
* and there is an in-record not of this face
|
||||
*
|
||||
* \note This algorithm has a weakness that it does not permit consumer retransmissions
|
||||
* before out-record expires. Therefore, it's not recommended to use this function
|
||||
* in new strategies.
|
||||
* \todo find a better name for this function
|
||||
*/
|
||||
bool
|
||||
canForwardToLegacy(const pit::Entry& pitEntry, const Face& face);
|
||||
|
||||
/** \brief indicates where duplicate Nonces are found
|
||||
*/
|
||||
enum DuplicateNonceWhere {
|
||||
DUPLICATE_NONCE_NONE = 0, ///< no duplicate Nonce is found
|
||||
DUPLICATE_NONCE_IN_SAME = (1 << 0), ///< in-record of same face
|
||||
DUPLICATE_NONCE_IN_OTHER = (1 << 1), ///< in-record of other face
|
||||
DUPLICATE_NONCE_OUT_SAME = (1 << 2), ///< out-record of same face
|
||||
DUPLICATE_NONCE_OUT_OTHER = (1 << 3) ///< out-record of other face
|
||||
};
|
||||
|
||||
/** \brief determine whether \p pitEntry has duplicate Nonce \p nonce
|
||||
* \return OR'ed DuplicateNonceWhere
|
||||
*/
|
||||
int
|
||||
findDuplicateNonce(const pit::Entry& pitEntry, uint32_t nonce, const Face& face);
|
||||
|
||||
/** \brief determine whether \p pitEntry has any pending out-records
|
||||
* \return true if there is at least one out-record waiting for Data
|
||||
*/
|
||||
bool
|
||||
hasPendingOutRecords(const pit::Entry& pitEntry);
|
||||
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FW_PIT_ALGORITHM_HPP
|
||||
@@ -0,0 +1,272 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of 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/>.
|
||||
*/
|
||||
|
||||
#include "asf-measurements.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
namespace asf {
|
||||
|
||||
NFD_LOG_INIT("AsfMeasurements");
|
||||
|
||||
const RttStats::Rtt RttStats::RTT_TIMEOUT(-1.0);
|
||||
const RttStats::Rtt RttStats::RTT_NO_MEASUREMENT(0.0);
|
||||
const double RttStats::ALPHA = 0.125;
|
||||
|
||||
RttStats::RttStats()
|
||||
: m_srtt(RTT_NO_MEASUREMENT)
|
||||
, m_rtt(RTT_NO_MEASUREMENT)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
RttStats::addRttMeasurement(RttEstimator::Duration& durationRtt)
|
||||
{
|
||||
m_rtt = static_cast<RttStats::Rtt>(durationRtt.count());
|
||||
|
||||
m_rttEstimator.addMeasurement(durationRtt);
|
||||
|
||||
m_srtt = computeSrtt(m_srtt, m_rtt);
|
||||
}
|
||||
|
||||
RttStats::Rtt
|
||||
RttStats::computeSrtt(Rtt previousSrtt, Rtt currentRtt)
|
||||
{
|
||||
if (previousSrtt == RTT_NO_MEASUREMENT) {
|
||||
return currentRtt;
|
||||
}
|
||||
|
||||
return Rtt(ALPHA * currentRtt + (1 - ALPHA) * previousSrtt);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FaceInfo::FaceInfo()
|
||||
: m_isTimeoutScheduled(false)
|
||||
{
|
||||
}
|
||||
|
||||
FaceInfo::~FaceInfo()
|
||||
{
|
||||
cancelTimeoutEvent();
|
||||
scheduler::cancel(m_measurementExpirationId);
|
||||
}
|
||||
|
||||
void
|
||||
FaceInfo::setTimeoutEvent(const scheduler::EventId& id, const Name& interestName)
|
||||
{
|
||||
if (!m_isTimeoutScheduled) {
|
||||
m_timeoutEventId = id;
|
||||
m_isTimeoutScheduled = true;
|
||||
m_lastInterestName = interestName;
|
||||
}
|
||||
else {
|
||||
BOOST_THROW_EXCEPTION(FaceInfo::Error("Tried to schedule a timeout for a face that already has a timeout scheduled."));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FaceInfo::cancelTimeoutEvent()
|
||||
{
|
||||
scheduler::cancel(m_timeoutEventId);
|
||||
m_isTimeoutScheduled = false;
|
||||
}
|
||||
|
||||
void
|
||||
FaceInfo::cancelTimeoutEvent(const Name& prefix)
|
||||
{
|
||||
if (isTimeoutScheduled() && doesNameMatchLastInterest(prefix)) {
|
||||
cancelTimeoutEvent();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
FaceInfo::doesNameMatchLastInterest(const Name& name)
|
||||
{
|
||||
return m_lastInterestName.isPrefixOf(name);
|
||||
}
|
||||
|
||||
void
|
||||
FaceInfo::recordRtt(const shared_ptr<pit::Entry>& pitEntry, const Face& inFace)
|
||||
{
|
||||
// Calculate RTT
|
||||
pit::OutRecordCollection::const_iterator outRecord = pitEntry->getOutRecord(inFace);
|
||||
|
||||
if (outRecord == pitEntry->out_end()) { // no out-record
|
||||
NFD_LOG_TRACE(pitEntry->getInterest() << " dataFrom inFace=" << inFace.getId() << " no-out-record");
|
||||
return;
|
||||
}
|
||||
|
||||
time::steady_clock::Duration steadyRtt = time::steady_clock::now() - outRecord->getLastRenewed();
|
||||
RttEstimator::Duration durationRtt = time::duration_cast<RttEstimator::Duration>(steadyRtt);
|
||||
|
||||
m_rttStats.addRttMeasurement(durationRtt);
|
||||
|
||||
NFD_LOG_TRACE("Recording RTT for FaceId: " << inFace.getId()
|
||||
<< " RTT: " << m_rttStats.getRtt()
|
||||
<< " SRTT: " << m_rttStats.getSrtt());
|
||||
}
|
||||
|
||||
void
|
||||
FaceInfo::recordTimeout(const Name& interestName)
|
||||
{
|
||||
m_rttStats.recordTimeout();
|
||||
cancelTimeoutEvent(interestName);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NamespaceInfo::NamespaceInfo()
|
||||
: m_isProbingDue(false)
|
||||
, m_hasFirstProbeBeenScheduled(false)
|
||||
{
|
||||
}
|
||||
|
||||
FaceInfo*
|
||||
NamespaceInfo::getFaceInfo(const fib::Entry& fibEntry, const Face& face)
|
||||
{
|
||||
FaceInfoTable::iterator it = m_fit.find(face.getId());
|
||||
|
||||
if (it != m_fit.end()) {
|
||||
return &it->second;
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
FaceInfo&
|
||||
NamespaceInfo::getOrCreateFaceInfo(const fib::Entry& fibEntry, const Face& face)
|
||||
{
|
||||
FaceInfoTable::iterator it = m_fit.find(face.getId());
|
||||
|
||||
FaceInfo* info = nullptr;
|
||||
|
||||
if (it == m_fit.end()) {
|
||||
const auto& pair = m_fit.insert(std::make_pair(face.getId(), FaceInfo()));
|
||||
info = &pair.first->second;
|
||||
|
||||
extendFaceInfoLifetime(*info, face);
|
||||
}
|
||||
else {
|
||||
info = &it->second;
|
||||
}
|
||||
|
||||
return *info;
|
||||
}
|
||||
|
||||
void
|
||||
NamespaceInfo::expireFaceInfo(nfd::face::FaceId faceId)
|
||||
{
|
||||
m_fit.erase(faceId);
|
||||
}
|
||||
|
||||
void
|
||||
NamespaceInfo::extendFaceInfoLifetime(FaceInfo& info, const Face& face)
|
||||
{
|
||||
// Cancel previous expiration
|
||||
scheduler::cancel(info.getMeasurementExpirationEventId());
|
||||
|
||||
// Refresh measurement
|
||||
scheduler::EventId id = scheduler::schedule(AsfMeasurements::MEASUREMENTS_LIFETIME,
|
||||
bind(&NamespaceInfo::expireFaceInfo, this, face.getId()));
|
||||
|
||||
info.setMeasurementExpirationEventId(id);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
constexpr time::microseconds AsfMeasurements::MEASUREMENTS_LIFETIME;
|
||||
|
||||
AsfMeasurements::AsfMeasurements(MeasurementsAccessor& measurements)
|
||||
: m_measurements(measurements)
|
||||
{
|
||||
}
|
||||
|
||||
FaceInfo*
|
||||
AsfMeasurements::getFaceInfo(const fib::Entry& fibEntry, const Interest& interest, const Face& face)
|
||||
{
|
||||
NamespaceInfo& info = getOrCreateNamespaceInfo(fibEntry, interest);
|
||||
return info.getFaceInfo(fibEntry, face);
|
||||
}
|
||||
|
||||
FaceInfo&
|
||||
AsfMeasurements::getOrCreateFaceInfo(const fib::Entry& fibEntry, const Interest& interest, const Face& face)
|
||||
{
|
||||
NamespaceInfo& info = getOrCreateNamespaceInfo(fibEntry, interest);
|
||||
return info.getOrCreateFaceInfo(fibEntry, face);
|
||||
}
|
||||
|
||||
NamespaceInfo*
|
||||
AsfMeasurements::getNamespaceInfo(const Name& prefix)
|
||||
{
|
||||
measurements::Entry* me = m_measurements.findLongestPrefixMatch(prefix);
|
||||
if (me == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Set or update entry lifetime
|
||||
extendLifetime(*me);
|
||||
|
||||
NamespaceInfo* info = me->insertStrategyInfo<NamespaceInfo>().first;
|
||||
BOOST_ASSERT(info != nullptr);
|
||||
return info;
|
||||
}
|
||||
|
||||
NamespaceInfo&
|
||||
AsfMeasurements::getOrCreateNamespaceInfo(const fib::Entry& fibEntry, const Interest& interest)
|
||||
{
|
||||
measurements::Entry* me = m_measurements.get(fibEntry);
|
||||
|
||||
// If the FIB entry is not under the strategy's namespace, find a part of the prefix
|
||||
// that falls under the strategy's namespace
|
||||
for (size_t prefixLen = fibEntry.getPrefix().size() + 1;
|
||||
me == nullptr && prefixLen <= interest.getName().size(); ++prefixLen) {
|
||||
me = m_measurements.get(interest.getName().getPrefix(prefixLen));
|
||||
}
|
||||
|
||||
// Either the FIB entry or the Interest's name must be under this strategy's namespace
|
||||
BOOST_ASSERT(me != nullptr);
|
||||
|
||||
// Set or update entry lifetime
|
||||
extendLifetime(*me);
|
||||
|
||||
NamespaceInfo* info = me->insertStrategyInfo<NamespaceInfo>().first;
|
||||
BOOST_ASSERT(info != nullptr);
|
||||
return *info;
|
||||
}
|
||||
|
||||
void
|
||||
AsfMeasurements::extendLifetime(measurements::Entry& me)
|
||||
{
|
||||
m_measurements.extendLifetime(me, MEASUREMENTS_LIFETIME);
|
||||
}
|
||||
|
||||
} // namespace asf
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,312 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of 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_DAEMON_FW_ASF_MEASUREMENTS_HPP
|
||||
#define NFD_DAEMON_FW_ASF_MEASUREMENTS_HPP
|
||||
|
||||
#include "fw/rtt-estimator.hpp"
|
||||
#include "fw/strategy-info.hpp"
|
||||
#include "table/measurements-accessor.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
namespace asf {
|
||||
|
||||
class RttStats
|
||||
{
|
||||
public:
|
||||
typedef time::duration<double, boost::micro> Rtt;
|
||||
|
||||
RttStats();
|
||||
|
||||
void
|
||||
addRttMeasurement(RttEstimator::Duration& durationRtt);
|
||||
|
||||
void
|
||||
recordTimeout()
|
||||
{
|
||||
m_rtt = RTT_TIMEOUT;
|
||||
}
|
||||
|
||||
Rtt
|
||||
getRtt() const
|
||||
{
|
||||
return m_rtt;
|
||||
}
|
||||
|
||||
Rtt
|
||||
getSrtt() const
|
||||
{
|
||||
return m_srtt;
|
||||
}
|
||||
|
||||
RttEstimator::Duration
|
||||
computeRto() const
|
||||
{
|
||||
return m_rttEstimator.computeRto();
|
||||
}
|
||||
|
||||
private:
|
||||
static Rtt
|
||||
computeSrtt(Rtt previousSrtt, Rtt currentRtt);
|
||||
|
||||
public:
|
||||
static const Rtt RTT_TIMEOUT;
|
||||
static const Rtt RTT_NO_MEASUREMENT;
|
||||
|
||||
private:
|
||||
Rtt m_srtt;
|
||||
Rtt m_rtt;
|
||||
RttEstimator m_rttEstimator;
|
||||
|
||||
static const double ALPHA;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** \brief Strategy information for each face in a namespace
|
||||
*/
|
||||
class FaceInfo
|
||||
{
|
||||
public:
|
||||
class Error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& what)
|
||||
: std::runtime_error(what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
FaceInfo();
|
||||
|
||||
~FaceInfo();
|
||||
|
||||
void
|
||||
setTimeoutEvent(const scheduler::EventId& id, const Name& interestName);
|
||||
|
||||
void
|
||||
setMeasurementExpirationEventId(const scheduler::EventId& id)
|
||||
{
|
||||
m_measurementExpirationId = id;
|
||||
}
|
||||
|
||||
const scheduler::EventId&
|
||||
getMeasurementExpirationEventId()
|
||||
{
|
||||
return m_measurementExpirationId;
|
||||
}
|
||||
|
||||
void
|
||||
cancelTimeoutEvent(const Name& prefix);
|
||||
|
||||
bool
|
||||
isTimeoutScheduled() const
|
||||
{
|
||||
return m_isTimeoutScheduled;
|
||||
}
|
||||
|
||||
void
|
||||
recordRtt(const shared_ptr<pit::Entry>& pitEntry, const Face& inFace);
|
||||
|
||||
void
|
||||
recordTimeout(const Name& interestName);
|
||||
|
||||
bool
|
||||
isTimeout() const
|
||||
{
|
||||
return getRtt() == RttStats::RTT_TIMEOUT;
|
||||
}
|
||||
|
||||
RttEstimator::Duration
|
||||
computeRto() const
|
||||
{
|
||||
return m_rttStats.computeRto();
|
||||
}
|
||||
|
||||
RttStats::Rtt
|
||||
getRtt() const
|
||||
{
|
||||
return m_rttStats.getRtt();
|
||||
}
|
||||
|
||||
RttStats::Rtt
|
||||
getSrtt() const
|
||||
{
|
||||
return m_rttStats.getSrtt();
|
||||
}
|
||||
|
||||
bool
|
||||
hasSrttMeasurement() const
|
||||
{
|
||||
return getSrtt() != RttStats::RTT_NO_MEASUREMENT;
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
cancelTimeoutEvent();
|
||||
|
||||
bool
|
||||
doesNameMatchLastInterest(const Name& name);
|
||||
|
||||
private:
|
||||
RttStats m_rttStats;
|
||||
Name m_lastInterestName;
|
||||
|
||||
// Timeout associated with measurement
|
||||
scheduler::EventId m_measurementExpirationId;
|
||||
|
||||
// RTO associated with Interest
|
||||
scheduler::EventId m_timeoutEventId;
|
||||
bool m_isTimeoutScheduled;
|
||||
};
|
||||
|
||||
typedef std::unordered_map<face::FaceId, FaceInfo> FaceInfoTable;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** \brief stores stategy information about each face in this namespace
|
||||
*/
|
||||
class NamespaceInfo : public StrategyInfo
|
||||
{
|
||||
public:
|
||||
NamespaceInfo();
|
||||
|
||||
static constexpr int
|
||||
getTypeId()
|
||||
{
|
||||
return 1030;
|
||||
}
|
||||
|
||||
FaceInfo&
|
||||
getOrCreateFaceInfo(const fib::Entry& fibEntry, const Face& face);
|
||||
|
||||
FaceInfo*
|
||||
getFaceInfo(const fib::Entry& fibEntry, const Face& face);
|
||||
|
||||
void
|
||||
expireFaceInfo(nfd::face::FaceId faceId);
|
||||
|
||||
void
|
||||
extendFaceInfoLifetime(FaceInfo& info, const Face& face);
|
||||
|
||||
FaceInfo&
|
||||
get(nfd::face::FaceId faceId)
|
||||
{
|
||||
return m_fit.at(faceId);
|
||||
}
|
||||
|
||||
FaceInfoTable::iterator
|
||||
find(nfd::face::FaceId faceId)
|
||||
{
|
||||
return m_fit.find(faceId);
|
||||
}
|
||||
|
||||
FaceInfoTable::iterator
|
||||
end()
|
||||
{
|
||||
return m_fit.end();
|
||||
}
|
||||
|
||||
const FaceInfoTable::iterator
|
||||
insert(nfd::face::FaceId faceId)
|
||||
{
|
||||
const auto& pair = m_fit.insert(std::make_pair(faceId, FaceInfo()));
|
||||
return pair.first;
|
||||
}
|
||||
|
||||
bool
|
||||
isProbingDue() const
|
||||
{
|
||||
return m_isProbingDue;
|
||||
}
|
||||
|
||||
void
|
||||
setIsProbingDue(bool isProbingDue)
|
||||
{
|
||||
m_isProbingDue = isProbingDue;
|
||||
}
|
||||
|
||||
bool
|
||||
isFirstProbeScheduled() const
|
||||
{
|
||||
return m_hasFirstProbeBeenScheduled;
|
||||
}
|
||||
|
||||
void
|
||||
setHasFirstProbeBeenScheduled(bool hasBeenScheduled)
|
||||
{
|
||||
m_hasFirstProbeBeenScheduled = hasBeenScheduled;
|
||||
}
|
||||
|
||||
private:
|
||||
FaceInfoTable m_fit;
|
||||
|
||||
bool m_isProbingDue;
|
||||
bool m_hasFirstProbeBeenScheduled;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** \brief Helper class to retrieve and create strategy measurements
|
||||
*/
|
||||
class AsfMeasurements : noncopyable
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
AsfMeasurements(MeasurementsAccessor& measurements);
|
||||
|
||||
FaceInfo*
|
||||
getFaceInfo(const fib::Entry& fibEntry, const Interest& interest, const Face& face);
|
||||
|
||||
FaceInfo&
|
||||
getOrCreateFaceInfo(const fib::Entry& fibEntry, const Interest& interest, const Face& face);
|
||||
|
||||
NamespaceInfo*
|
||||
getNamespaceInfo(const Name& prefix);
|
||||
|
||||
NamespaceInfo&
|
||||
getOrCreateNamespaceInfo(const fib::Entry& fibEntry, const Interest& interest);
|
||||
|
||||
private:
|
||||
void
|
||||
extendLifetime(measurements::Entry& me);
|
||||
|
||||
public:
|
||||
static constexpr time::microseconds MEASUREMENTS_LIFETIME = time::seconds(300);
|
||||
|
||||
private:
|
||||
MeasurementsAccessor& m_measurements;
|
||||
};
|
||||
|
||||
} // namespace asf
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FW_ASF_MEASUREMENTS_HPP
|
||||
@@ -0,0 +1,194 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of 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/>.
|
||||
*/
|
||||
|
||||
#include "asf-probing-module.hpp"
|
||||
#include "core/random.hpp"
|
||||
#include "algorithm.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
namespace asf {
|
||||
|
||||
constexpr time::seconds ProbingModule::DEFAULT_PROBING_INTERVAL;
|
||||
|
||||
static_assert(ProbingModule::DEFAULT_PROBING_INTERVAL < AsfMeasurements::MEASUREMENTS_LIFETIME,
|
||||
"ProbingModule::DEFAULT_PROBING_INTERVAL must be less than AsfMeasurements::MEASUREMENTS_LIFETIME");
|
||||
|
||||
ProbingModule::ProbingModule(AsfMeasurements& measurements)
|
||||
: m_probingInterval(DEFAULT_PROBING_INTERVAL)
|
||||
, m_measurements(measurements)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ProbingModule::scheduleProbe(const fib::Entry& fibEntry, const time::milliseconds& interval)
|
||||
{
|
||||
Name prefix = fibEntry.getPrefix();
|
||||
|
||||
// Set the probing flag for the namespace to true after passed interval of time
|
||||
scheduler::schedule(interval, [this, prefix] {
|
||||
NamespaceInfo* info = m_measurements.getNamespaceInfo(prefix);
|
||||
|
||||
if (info == nullptr) {
|
||||
// fib::Entry with the passed prefix has been removed or the fib::Entry has
|
||||
// a name that is not controlled by the AsfStrategy
|
||||
return;
|
||||
}
|
||||
else {
|
||||
info->setIsProbingDue(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Face*
|
||||
ProbingModule::getFaceToProbe(const Face& inFace,
|
||||
const Interest& interest,
|
||||
const fib::Entry& fibEntry,
|
||||
const Face& faceUsed)
|
||||
{
|
||||
FaceInfoFacePairSet rankedFaces(
|
||||
[] (FaceInfoFacePair pairLhs, FaceInfoFacePair pairRhs) -> bool {
|
||||
// Sort by RTT
|
||||
// If a face has timed-out, rank it behind non-timed-out faces
|
||||
FaceInfo& lhs = *pairLhs.first;
|
||||
FaceInfo& rhs = *pairRhs.first;
|
||||
|
||||
return (!lhs.isTimeout() && rhs.isTimeout()) ||
|
||||
(lhs.isTimeout() == rhs.isTimeout() && lhs.getSrtt() < rhs.getSrtt());
|
||||
});
|
||||
|
||||
// Put eligible faces into rankedFaces. If a face does not have an RTT measurement,
|
||||
// immediately pick the face for probing
|
||||
for (const fib::NextHop& hop : fibEntry.getNextHops()) {
|
||||
Face& hopFace = hop.getFace();
|
||||
|
||||
// Don't send probe Interest back to the incoming face or use the same face
|
||||
// as the forwarded Interest or use a face that violates scope
|
||||
if (hopFace.getId() == inFace.getId() || hopFace.getId() == faceUsed.getId() ||
|
||||
wouldViolateScope(inFace, interest, hopFace)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace);
|
||||
|
||||
// If no RTT has been recorded, probe this face
|
||||
if (info == nullptr || !info->hasSrttMeasurement()) {
|
||||
return &hopFace;
|
||||
}
|
||||
|
||||
// Add FaceInfo to container sorted by RTT
|
||||
rankedFaces.insert(std::make_pair(info, &hopFace));
|
||||
}
|
||||
|
||||
if (rankedFaces.empty()) {
|
||||
// No Face to probe
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return getFaceBasedOnProbability(rankedFaces);
|
||||
}
|
||||
|
||||
bool
|
||||
ProbingModule::isProbingNeeded(const fib::Entry& fibEntry, const Interest& interest)
|
||||
{
|
||||
// Return the probing status flag for a namespace
|
||||
NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
|
||||
|
||||
// If a first probe has not been scheduled for a namespace
|
||||
if (!info.isFirstProbeScheduled()) {
|
||||
// Schedule first probe between 0 and 5 seconds
|
||||
uint64_t interval = getRandomNumber(0, 5000);
|
||||
scheduleProbe(fibEntry, time::milliseconds(interval));
|
||||
|
||||
info.setHasFirstProbeBeenScheduled(true);
|
||||
}
|
||||
|
||||
return info.isProbingDue();
|
||||
}
|
||||
|
||||
void
|
||||
ProbingModule::afterForwardingProbe(const fib::Entry& fibEntry, const Interest& interest)
|
||||
{
|
||||
// After probing is done, need to set probing flag to false and
|
||||
// schedule another future probe
|
||||
NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
|
||||
info.setIsProbingDue(false);
|
||||
|
||||
scheduleProbe(fibEntry, m_probingInterval);
|
||||
}
|
||||
|
||||
Face*
|
||||
ProbingModule::getFaceBasedOnProbability(const FaceInfoFacePairSet& rankedFaces)
|
||||
{
|
||||
double randomNumber = getRandomNumber(0, 1);
|
||||
uint64_t rankSum = ((rankedFaces.size() + 1) * rankedFaces.size()) / 2;
|
||||
|
||||
uint64_t rank = 1;
|
||||
double offset = 0.0;
|
||||
|
||||
for (const FaceInfoFacePair pair : rankedFaces) {
|
||||
double probability = getProbingProbability(rank++, rankSum, rankedFaces.size());
|
||||
|
||||
// Is the random number within the bounds of this face's probability + the previous faces'
|
||||
// probability?
|
||||
//
|
||||
// e.g. (FaceId: 1, p=0.5), (FaceId: 2, p=0.33), (FaceId: 3, p=0.17)
|
||||
// randomNumber = 0.92
|
||||
//
|
||||
// The face with FaceId: 3 should be picked
|
||||
// (0.68 < 0.5 + 0.33 + 0.17) == true
|
||||
//
|
||||
if (randomNumber <= offset + probability) {
|
||||
// Found face to probe
|
||||
return pair.second;
|
||||
}
|
||||
|
||||
offset += probability;
|
||||
}
|
||||
|
||||
// Given a set of Faces, this method should always select a Face to probe
|
||||
BOOST_ASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
double
|
||||
ProbingModule::getProbingProbability(uint64_t rank, uint64_t rankSum, uint64_t nFaces)
|
||||
{
|
||||
// p = n + 1 - j ; n: # faces
|
||||
// ---------
|
||||
// sum(ranks)
|
||||
return static_cast<double>(nFaces + 1 - rank) / rankSum;
|
||||
}
|
||||
|
||||
double
|
||||
ProbingModule::getRandomNumber(double start, double end)
|
||||
{
|
||||
std::uniform_real_distribution<double> dist(start, end);
|
||||
return dist(getGlobalRng());
|
||||
}
|
||||
|
||||
} // namespace asf
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,85 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of 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_DAEMON_FW_ASF_PROBING_MODULE_HPP
|
||||
#define NFD_DAEMON_FW_ASF_PROBING_MODULE_HPP
|
||||
|
||||
#include "asf-measurements.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
namespace asf {
|
||||
|
||||
/** \brief ASF Probing Module
|
||||
*/
|
||||
class ProbingModule
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
ProbingModule(AsfMeasurements& measurements);
|
||||
|
||||
void
|
||||
scheduleProbe(const fib::Entry& fibEntry, const time::milliseconds& interval);
|
||||
|
||||
Face*
|
||||
getFaceToProbe(const Face& inFace,
|
||||
const Interest& interest,
|
||||
const fib::Entry& fibEntry,
|
||||
const Face& faceUsed);
|
||||
|
||||
bool
|
||||
isProbingNeeded(const fib::Entry& fibEntry, const Interest& interest);
|
||||
|
||||
void
|
||||
afterForwardingProbe(const fib::Entry& fibEntry, const Interest& interest);
|
||||
|
||||
private:
|
||||
// Used to associate FaceInfo with the face in a NextHop
|
||||
typedef std::pair<FaceInfo*, Face*> FaceInfoFacePair;
|
||||
typedef std::function<bool(FaceInfoFacePair, FaceInfoFacePair)> FaceInfoPredicate;
|
||||
typedef std::set<FaceInfoFacePair, FaceInfoPredicate> FaceInfoFacePairSet;
|
||||
|
||||
Face*
|
||||
getFaceBasedOnProbability(const FaceInfoFacePairSet& rankedFaces);
|
||||
|
||||
double
|
||||
getProbingProbability(uint64_t rank, uint64_t rankSum, uint64_t nFaces);
|
||||
|
||||
double
|
||||
getRandomNumber(double start, double end);
|
||||
|
||||
public:
|
||||
static constexpr time::seconds DEFAULT_PROBING_INTERVAL = time::seconds(60);
|
||||
|
||||
private:
|
||||
time::seconds m_probingInterval;
|
||||
AsfMeasurements& m_measurements;
|
||||
};
|
||||
|
||||
} // namespace asf
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FW_ASF_PROBING_MODULE_HPP
|
||||
@@ -0,0 +1,309 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of 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/>.
|
||||
*/
|
||||
|
||||
#include "asf-strategy.hpp"
|
||||
#include "algorithm.hpp"
|
||||
|
||||
#include "core/logger.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
namespace asf {
|
||||
|
||||
NFD_LOG_INIT("AsfStrategy");
|
||||
NFD_REGISTER_STRATEGY(AsfStrategy);
|
||||
|
||||
const time::milliseconds AsfStrategy::RETX_SUPPRESSION_INITIAL(10);
|
||||
const time::milliseconds AsfStrategy::RETX_SUPPRESSION_MAX(250);
|
||||
|
||||
AsfStrategy::AsfStrategy(Forwarder& forwarder, const Name& name)
|
||||
: Strategy(forwarder)
|
||||
, m_measurements(getMeasurements())
|
||||
, m_probing(m_measurements)
|
||||
, m_retxSuppression(RETX_SUPPRESSION_INITIAL,
|
||||
RetxSuppressionExponential::DEFAULT_MULTIPLIER,
|
||||
RETX_SUPPRESSION_MAX)
|
||||
{
|
||||
ParsedInstanceName parsed = parseInstanceName(name);
|
||||
if (!parsed.parameters.empty()) {
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("AsfStrategy does not accept parameters"));
|
||||
}
|
||||
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument(
|
||||
"AsfStrategy does not support version " + std::to_string(*parsed.version)));
|
||||
}
|
||||
this->setInstanceName(makeInstanceName(name, getStrategyName()));
|
||||
}
|
||||
|
||||
const Name&
|
||||
AsfStrategy::getStrategyName()
|
||||
{
|
||||
static Name strategyName("/localhost/nfd/strategy/asf/%FD%01");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
void
|
||||
AsfStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
// Should the Interest be suppressed?
|
||||
RetxSuppression::Result suppressResult = m_retxSuppression.decide(inFace, interest, *pitEntry);
|
||||
|
||||
switch (suppressResult) {
|
||||
case RetxSuppression::NEW:
|
||||
case RetxSuppression::FORWARD:
|
||||
break;
|
||||
case RetxSuppression::SUPPRESS:
|
||||
NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " suppressed");
|
||||
return;
|
||||
}
|
||||
|
||||
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
|
||||
const fib::NextHopList& nexthops = fibEntry.getNextHops();
|
||||
|
||||
if (nexthops.size() == 0) {
|
||||
sendNoRouteNack(inFace, interest, pitEntry);
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
return;
|
||||
}
|
||||
|
||||
Face* faceToUse = getBestFaceForForwarding(fibEntry, interest, inFace);
|
||||
|
||||
if (faceToUse == nullptr) {
|
||||
sendNoRouteNack(inFace, interest, pitEntry);
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
return;
|
||||
}
|
||||
|
||||
forwardInterest(interest, fibEntry, pitEntry, *faceToUse);
|
||||
|
||||
// If necessary, send probe
|
||||
if (m_probing.isProbingNeeded(fibEntry, interest)) {
|
||||
Face* faceToProbe = m_probing.getFaceToProbe(inFace, interest, fibEntry, *faceToUse);
|
||||
|
||||
if (faceToProbe != nullptr) {
|
||||
bool wantNewNonce = true;
|
||||
forwardInterest(interest, fibEntry, pitEntry, *faceToProbe, wantNewNonce);
|
||||
m_probing.afterForwardingProbe(fibEntry, interest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsfStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const Face& inFace, const Data& data)
|
||||
{
|
||||
NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(pitEntry->getName());
|
||||
|
||||
if (namespaceInfo == nullptr) {
|
||||
NFD_LOG_TRACE("Could not find measurements entry for " << pitEntry->getName());
|
||||
return;
|
||||
}
|
||||
|
||||
// Record the RTT between the Interest out to Data in
|
||||
FaceInfo& faceInfo = namespaceInfo->get(inFace.getId());
|
||||
faceInfo.recordRtt(pitEntry, inFace);
|
||||
|
||||
// Extend lifetime for measurements associated with Face
|
||||
namespaceInfo->extendFaceInfoLifetime(faceInfo, inFace);
|
||||
|
||||
if (faceInfo.isTimeoutScheduled()) {
|
||||
faceInfo.cancelTimeoutEvent(data.getName());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsfStrategy::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
NFD_LOG_DEBUG("Nack for " << nack.getInterest() << " from=" << inFace.getId() << ": " << nack.getReason());
|
||||
onTimeout(pitEntry->getName(), inFace.getId());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
AsfStrategy::forwardInterest(const Interest& interest,
|
||||
const fib::Entry& fibEntry,
|
||||
const shared_ptr<pit::Entry>& pitEntry,
|
||||
Face& outFace,
|
||||
bool wantNewNonce)
|
||||
{
|
||||
if (wantNewNonce) {
|
||||
//Send probe: interest with new Nonce
|
||||
Interest probeInterest(interest);
|
||||
probeInterest.refreshNonce();
|
||||
NFD_LOG_TRACE("Sending probe for " << probeInterest << probeInterest.getNonce()
|
||||
<< " to FaceId: " << outFace.getId());
|
||||
this->sendInterest(pitEntry, outFace, probeInterest);
|
||||
}
|
||||
else {
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
}
|
||||
|
||||
FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interest, outFace);
|
||||
|
||||
// Refresh measurements since Face is being used for forwarding
|
||||
NamespaceInfo& namespaceInfo = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
|
||||
namespaceInfo.extendFaceInfoLifetime(faceInfo, outFace);
|
||||
|
||||
if (!faceInfo.isTimeoutScheduled()) {
|
||||
// Estimate and schedule timeout
|
||||
RttEstimator::Duration timeout = faceInfo.computeRto();
|
||||
|
||||
NFD_LOG_TRACE("Scheduling timeout for " << fibEntry.getPrefix()
|
||||
<< " FaceId: " << outFace.getId()
|
||||
<< " in " << time::duration_cast<time::milliseconds>(timeout) << " ms");
|
||||
|
||||
scheduler::EventId id = scheduler::schedule(timeout,
|
||||
bind(&AsfStrategy::onTimeout, this, interest.getName(), outFace.getId()));
|
||||
|
||||
faceInfo.setTimeoutEvent(id, interest.getName());
|
||||
}
|
||||
}
|
||||
|
||||
struct FaceStats
|
||||
{
|
||||
Face* face;
|
||||
RttStats::Rtt rtt;
|
||||
RttStats::Rtt srtt;
|
||||
uint64_t cost;
|
||||
};
|
||||
|
||||
double
|
||||
getValueForSorting(const FaceStats& stats)
|
||||
{
|
||||
// These values allow faces with no measurements to be ranked better than timeouts
|
||||
// srtt < RTT_NO_MEASUREMENT < RTT_TIMEOUT
|
||||
static const RttStats::Rtt SORTING_RTT_TIMEOUT = time::microseconds::max();
|
||||
static const RttStats::Rtt SORTING_RTT_NO_MEASUREMENT = SORTING_RTT_TIMEOUT / 2;
|
||||
|
||||
if (stats.rtt == RttStats::RTT_TIMEOUT) {
|
||||
return SORTING_RTT_TIMEOUT.count();
|
||||
}
|
||||
else if (stats.rtt == RttStats::RTT_NO_MEASUREMENT) {
|
||||
return SORTING_RTT_NO_MEASUREMENT.count();
|
||||
}
|
||||
else {
|
||||
return stats.srtt.count();
|
||||
}
|
||||
}
|
||||
|
||||
Face*
|
||||
AsfStrategy::getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest,
|
||||
const Face& inFace)
|
||||
{
|
||||
NFD_LOG_TRACE("Looking for best face for " << fibEntry.getPrefix());
|
||||
|
||||
typedef std::function<bool(const FaceStats&, const FaceStats&)> FaceStatsPredicate;
|
||||
typedef std::set<FaceStats, FaceStatsPredicate> FaceStatsSet;
|
||||
|
||||
FaceStatsSet rankedFaces(
|
||||
[] (const FaceStats& lhs, const FaceStats& rhs) -> bool {
|
||||
// Sort by RTT and then by cost
|
||||
double lhsValue = getValueForSorting(lhs);
|
||||
double rhsValue = getValueForSorting(rhs);
|
||||
|
||||
if (lhsValue < rhsValue) {
|
||||
return true;
|
||||
}
|
||||
else if (lhsValue == rhsValue) {
|
||||
return lhs.cost < rhs.cost;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
for (const fib::NextHop& hop : fibEntry.getNextHops()) {
|
||||
Face& hopFace = hop.getFace();
|
||||
|
||||
if (hopFace.getId() == inFace.getId() || wouldViolateScope(inFace, interest, hopFace)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace);
|
||||
|
||||
if (info == nullptr) {
|
||||
FaceStats stats = {&hopFace,
|
||||
RttStats::RTT_NO_MEASUREMENT,
|
||||
RttStats::RTT_NO_MEASUREMENT,
|
||||
hop.getCost()};
|
||||
|
||||
rankedFaces.insert(stats);
|
||||
}
|
||||
else {
|
||||
FaceStats stats = {&hopFace, info->getRtt(), info->getSrtt(), hop.getCost()};
|
||||
rankedFaces.insert(stats);
|
||||
}
|
||||
}
|
||||
|
||||
FaceStatsSet::iterator it = rankedFaces.begin();
|
||||
|
||||
if (it != rankedFaces.end()) {
|
||||
return it->face;
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsfStrategy::onTimeout(const Name& interestName, face::FaceId faceId)
|
||||
{
|
||||
NFD_LOG_TRACE("FaceId: " << faceId << " for " << interestName << " has timed-out");
|
||||
|
||||
NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(interestName);
|
||||
|
||||
if (namespaceInfo == nullptr) {
|
||||
NFD_LOG_TRACE("FibEntry for " << interestName << " has been removed since timeout scheduling");
|
||||
return;
|
||||
}
|
||||
|
||||
FaceInfoTable::iterator it = namespaceInfo->find(faceId);
|
||||
|
||||
if (it == namespaceInfo->end()) {
|
||||
it = namespaceInfo->insert(faceId);
|
||||
}
|
||||
|
||||
FaceInfo& faceInfo = it->second;
|
||||
faceInfo.recordTimeout(interestName);
|
||||
}
|
||||
|
||||
void
|
||||
AsfStrategy::sendNoRouteNack(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " noNextHop");
|
||||
|
||||
lp::NackHeader nackHeader;
|
||||
nackHeader.setReason(lp::NackReason::NO_ROUTE);
|
||||
this->sendNack(pitEntry, inFace, nackHeader);
|
||||
}
|
||||
|
||||
} // namespace asf
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,101 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of 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_DAEMON_FW_ASF_STRATEGY_HPP
|
||||
#define NFD_DAEMON_FW_ASF_STRATEGY_HPP
|
||||
|
||||
#include "asf-measurements.hpp"
|
||||
#include "asf-probing-module.hpp"
|
||||
#include "fw/retx-suppression-exponential.hpp"
|
||||
#include "fw/strategy.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
namespace asf {
|
||||
|
||||
/** \brief Adaptive SRTT-based Forwarding Strategy
|
||||
*
|
||||
* \see Vince Lehman, Ashlesh Gawande, Rodrigo Aldecoa, Dmitri Krioukov, Beichuan Zhang, Lixia Zhang, and Lan Wang,
|
||||
* "An Experimental Investigation of Hyperbolic Routing with a Smart Forwarding Plane in NDN,"
|
||||
* NDN Technical Report NDN-0042, 2016. http://named-data.net/techreports.html
|
||||
*/
|
||||
class AsfStrategy : public Strategy
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
AsfStrategy(Forwarder& forwarder, const Name& name = getStrategyName());
|
||||
|
||||
static const Name&
|
||||
getStrategyName();
|
||||
|
||||
public: // triggers
|
||||
virtual void
|
||||
afterReceiveInterest(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
virtual void
|
||||
beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const Face& inFace, const Data& data) override;
|
||||
|
||||
virtual void
|
||||
afterReceiveNack(const Face& inFace, const lp::Nack& nack,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
private:
|
||||
void
|
||||
forwardInterest(const Interest& interest,
|
||||
const fib::Entry& fibEntry,
|
||||
const shared_ptr<pit::Entry>& pitEntry,
|
||||
Face& outFace,
|
||||
bool wantNewNonce = false);
|
||||
|
||||
Face*
|
||||
getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest, const Face& inFace);
|
||||
|
||||
void
|
||||
onTimeout(const Name& interestName, face::FaceId faceId);
|
||||
|
||||
void
|
||||
sendNoRouteNack(const Face& inFace, const Interest& interest, const shared_ptr<pit::Entry>& pitEntry);
|
||||
|
||||
private:
|
||||
AsfMeasurements m_measurements;
|
||||
ProbingModule m_probing;
|
||||
|
||||
private:
|
||||
RetxSuppressionExponential m_retxSuppression;
|
||||
|
||||
static const time::milliseconds RETX_SUPPRESSION_INITIAL;
|
||||
static const time::milliseconds RETX_SUPPRESSION_MAX;
|
||||
};
|
||||
|
||||
} // namespace asf
|
||||
|
||||
using asf::AsfStrategy;
|
||||
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FW_ASF_STRATEGY_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -24,51 +24,61 @@
|
||||
*/
|
||||
|
||||
#include "best-route-strategy.hpp"
|
||||
#include "algorithm.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
const Name BestRouteStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/best-route/%FD%01");
|
||||
NFD_REGISTER_STRATEGY(BestRouteStrategy);
|
||||
|
||||
BestRouteStrategy::BestRouteStrategy(Forwarder& forwarder, const Name& name)
|
||||
: Strategy(forwarder, name)
|
||||
BestRouteStrategyBase::BestRouteStrategyBase(Forwarder& forwarder)
|
||||
: Strategy(forwarder)
|
||||
{
|
||||
}
|
||||
|
||||
BestRouteStrategy::~BestRouteStrategy()
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool
|
||||
predicate_PitEntry_canForwardTo_NextHop(shared_ptr<pit::Entry> pitEntry,
|
||||
const fib::NextHop& nexthop)
|
||||
{
|
||||
return pitEntry->canForwardTo(*nexthop.getFace());
|
||||
}
|
||||
|
||||
void
|
||||
BestRouteStrategy::afterReceiveInterest(const Face& inFace,
|
||||
const Interest& interest,
|
||||
shared_ptr<fib::Entry> fibEntry,
|
||||
shared_ptr<pit::Entry> pitEntry)
|
||||
BestRouteStrategyBase::afterReceiveInterest(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
if (pitEntry->hasUnexpiredOutRecords()) {
|
||||
if (hasPendingOutRecords(*pitEntry)) {
|
||||
// not a new Interest, don't forward
|
||||
return;
|
||||
}
|
||||
|
||||
const fib::NextHopList& nexthops = fibEntry->getNextHops();
|
||||
fib::NextHopList::const_iterator it = std::find_if(nexthops.begin(), nexthops.end(),
|
||||
bind(&predicate_PitEntry_canForwardTo_NextHop, pitEntry, _1));
|
||||
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
|
||||
const fib::NextHopList& nexthops = fibEntry.getNextHops();
|
||||
|
||||
if (it == nexthops.end()) {
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
return;
|
||||
for (fib::NextHopList::const_iterator it = nexthops.begin(); it != nexthops.end(); ++it) {
|
||||
Face& outFace = it->getFace();
|
||||
if (!wouldViolateScope(inFace, interest, outFace) &&
|
||||
canForwardToLegacy(*pitEntry, outFace)) {
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<Face> outFace = it->getFace();
|
||||
this->sendInterest(pitEntry, outFace);
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
}
|
||||
|
||||
NFD_REGISTER_STRATEGY(BestRouteStrategy);
|
||||
|
||||
BestRouteStrategy::BestRouteStrategy(Forwarder& forwarder, const Name& name)
|
||||
: BestRouteStrategyBase(forwarder)
|
||||
{
|
||||
ParsedInstanceName parsed = parseInstanceName(name);
|
||||
if (!parsed.parameters.empty()) {
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("BestRouteStrategy does not accept parameters"));
|
||||
}
|
||||
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument(
|
||||
"BestRouteStrategy does not support version " + std::to_string(*parsed.version)));
|
||||
}
|
||||
this->setInstanceName(makeInstanceName(name, getStrategyName()));
|
||||
}
|
||||
|
||||
const Name&
|
||||
BestRouteStrategy::getStrategyName()
|
||||
{
|
||||
static Name strategyName("/localhost/nfd/strategy/best-route/%FD%01");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
} // namespace fw
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
@@ -31,6 +31,17 @@
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
class BestRouteStrategyBase : public Strategy
|
||||
{
|
||||
public:
|
||||
void
|
||||
afterReceiveInterest(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
protected:
|
||||
BestRouteStrategyBase(Forwarder& forwarder);
|
||||
};
|
||||
|
||||
/** \brief Best Route strategy version 1
|
||||
*
|
||||
* This strategy forwards a new Interest to the lowest-cost nexthop
|
||||
@@ -38,26 +49,18 @@ namespace fw {
|
||||
* Subsequent similar Interests or consumer retransmissions are suppressed
|
||||
* until after InterestLifetime expiry.
|
||||
*
|
||||
* \deprecated This strategy is superceded by Best Route strategy version 2,
|
||||
* which allows consumer retransmissions. This version is kept for
|
||||
* comparison purposes and is not recommended for general usage.
|
||||
* \note This strategy is superceded by Best Route strategy version 2,
|
||||
* which allows consumer retransmissions. This version is kept for
|
||||
* comparison purposes and is not recommended for general usage.
|
||||
*/
|
||||
class BestRouteStrategy : public Strategy
|
||||
class BestRouteStrategy : public BestRouteStrategyBase
|
||||
{
|
||||
public:
|
||||
BestRouteStrategy(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
|
||||
explicit
|
||||
BestRouteStrategy(Forwarder& forwarder, const Name& name = getStrategyName());
|
||||
|
||||
virtual
|
||||
~BestRouteStrategy();
|
||||
|
||||
virtual void
|
||||
afterReceiveInterest(const Face& inFace,
|
||||
const Interest& interest,
|
||||
shared_ptr<fib::Entry> fibEntry,
|
||||
shared_ptr<pit::Entry> pitEntry) DECL_OVERRIDE;
|
||||
|
||||
public:
|
||||
static const Name STRATEGY_NAME;
|
||||
static const Name&
|
||||
getStrategyName();
|
||||
};
|
||||
|
||||
} // namespace fw
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -24,55 +24,71 @@
|
||||
*/
|
||||
|
||||
#include "best-route-strategy2.hpp"
|
||||
#include "algorithm.hpp"
|
||||
#include "core/logger.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
NFD_LOG_INIT("BestRouteStrategy2");
|
||||
|
||||
const Name BestRouteStrategy2::STRATEGY_NAME("ndn:/localhost/nfd/strategy/best-route/%FD%04");
|
||||
NFD_REGISTER_STRATEGY(BestRouteStrategy2);
|
||||
|
||||
const time::milliseconds BestRouteStrategy2::RETX_SUPPRESSION_INITIAL(10);
|
||||
const time::milliseconds BestRouteStrategy2::RETX_SUPPRESSION_MAX(250);
|
||||
|
||||
BestRouteStrategy2::BestRouteStrategy2(Forwarder& forwarder, const Name& name)
|
||||
: Strategy(forwarder, name)
|
||||
: Strategy(forwarder)
|
||||
, m_retxSuppression(RETX_SUPPRESSION_INITIAL,
|
||||
RetxSuppressionExponential::DEFAULT_MULTIPLIER,
|
||||
RETX_SUPPRESSION_MAX)
|
||||
{
|
||||
ParsedInstanceName parsed = parseInstanceName(name);
|
||||
if (!parsed.parameters.empty()) {
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("BestRouteStrategy2 does not accept parameters"));
|
||||
}
|
||||
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument(
|
||||
"BestRouteStrategy2 does not support version " + std::to_string(*parsed.version)));
|
||||
}
|
||||
this->setInstanceName(makeInstanceName(name, getStrategyName()));
|
||||
}
|
||||
|
||||
const Name&
|
||||
BestRouteStrategy2::getStrategyName()
|
||||
{
|
||||
static Name strategyName("/localhost/nfd/strategy/best-route/%FD%04");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
/** \brief determines whether a NextHop is eligible
|
||||
* \param pitEntry PIT entry
|
||||
* \param inFace incoming face of current Interest
|
||||
* \param interest incoming Interest
|
||||
* \param nexthop next hop
|
||||
* \param currentDownstream incoming FaceId of current Interest
|
||||
* \param wantUnused if true, NextHop must not have unexpired OutRecord
|
||||
* \param pitEntry PIT entry
|
||||
* \param wantUnused if true, NextHop must not have unexpired out-record
|
||||
* \param now time::steady_clock::now(), ignored if !wantUnused
|
||||
*/
|
||||
static inline bool
|
||||
predicate_NextHop_eligible(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const fib::NextHop& nexthop, FaceId currentDownstream,
|
||||
bool wantUnused = false,
|
||||
time::steady_clock::TimePoint now = time::steady_clock::TimePoint::min())
|
||||
isNextHopEligible(const Face& inFace, const Interest& interest,
|
||||
const fib::NextHop& nexthop,
|
||||
const shared_ptr<pit::Entry>& pitEntry,
|
||||
bool wantUnused = false,
|
||||
time::steady_clock::TimePoint now = time::steady_clock::TimePoint::min())
|
||||
{
|
||||
shared_ptr<Face> upstream = nexthop.getFace();
|
||||
const Face& outFace = nexthop.getFace();
|
||||
|
||||
// upstream is current downstream
|
||||
if (upstream->getId() == currentDownstream)
|
||||
// do not forward back to the same face
|
||||
if (&outFace == &inFace)
|
||||
return false;
|
||||
|
||||
// forwarding would violate scope
|
||||
if (pitEntry->violatesScope(*upstream))
|
||||
if (wouldViolateScope(inFace, interest, outFace))
|
||||
return false;
|
||||
|
||||
if (wantUnused) {
|
||||
// NextHop must not have unexpired OutRecord
|
||||
pit::OutRecordCollection::const_iterator outRecord = pitEntry->getOutRecord(*upstream);
|
||||
if (outRecord != pitEntry->getOutRecords().end() &&
|
||||
outRecord->getExpiry() > now) {
|
||||
// nexthop must not have unexpired out-record
|
||||
pit::OutRecordCollection::iterator outRecord = pitEntry->getOutRecord(outFace);
|
||||
if (outRecord != pitEntry->out_end() && outRecord->getExpiry() > now) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -80,21 +96,21 @@ predicate_NextHop_eligible(const shared_ptr<pit::Entry>& pitEntry,
|
||||
return true;
|
||||
}
|
||||
|
||||
/** \brief pick an eligible NextHop with earliest OutRecord
|
||||
* \note It is assumed that every nexthop has an OutRecord
|
||||
/** \brief pick an eligible NextHop with earliest out-record
|
||||
* \note It is assumed that every nexthop has an out-record.
|
||||
*/
|
||||
static inline fib::NextHopList::const_iterator
|
||||
findEligibleNextHopWithEarliestOutRecord(const shared_ptr<pit::Entry>& pitEntry,
|
||||
findEligibleNextHopWithEarliestOutRecord(const Face& inFace, const Interest& interest,
|
||||
const fib::NextHopList& nexthops,
|
||||
FaceId currentDownstream)
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
fib::NextHopList::const_iterator found = nexthops.end();
|
||||
time::steady_clock::TimePoint earliestRenewed = time::steady_clock::TimePoint::max();
|
||||
for (fib::NextHopList::const_iterator it = nexthops.begin(); it != nexthops.end(); ++it) {
|
||||
if (!predicate_NextHop_eligible(pitEntry, *it, currentDownstream))
|
||||
if (!isNextHopEligible(inFace, interest, *it, pitEntry))
|
||||
continue;
|
||||
pit::OutRecordCollection::const_iterator outRecord = pitEntry->getOutRecord(*it->getFace());
|
||||
BOOST_ASSERT(outRecord != pitEntry->getOutRecords().end());
|
||||
pit::OutRecordCollection::iterator outRecord = pitEntry->getOutRecord(it->getFace());
|
||||
BOOST_ASSERT(outRecord != pitEntry->out_end());
|
||||
if (outRecord->getLastRenewed() < earliestRenewed) {
|
||||
found = it;
|
||||
earliestRenewed = outRecord->getLastRenewed();
|
||||
@@ -104,19 +120,24 @@ findEligibleNextHopWithEarliestOutRecord(const shared_ptr<pit::Entry>& pitEntry,
|
||||
}
|
||||
|
||||
void
|
||||
BestRouteStrategy2::afterReceiveInterest(const Face& inFace,
|
||||
const Interest& interest,
|
||||
shared_ptr<fib::Entry> fibEntry,
|
||||
shared_ptr<pit::Entry> pitEntry)
|
||||
BestRouteStrategy2::afterReceiveInterest(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
const fib::NextHopList& nexthops = fibEntry->getNextHops();
|
||||
RetxSuppression::Result suppression = m_retxSuppression.decide(inFace, interest, *pitEntry);
|
||||
if (suppression == RetxSuppression::SUPPRESS) {
|
||||
NFD_LOG_DEBUG(interest << " from=" << inFace.getId()
|
||||
<< " suppressed");
|
||||
return;
|
||||
}
|
||||
|
||||
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
|
||||
const fib::NextHopList& nexthops = fibEntry.getNextHops();
|
||||
fib::NextHopList::const_iterator it = nexthops.end();
|
||||
|
||||
RetxSuppression::Result suppression = m_retxSuppression.decide(inFace, interest, *pitEntry);
|
||||
if (suppression == RetxSuppression::NEW) {
|
||||
// forward to nexthop with lowest cost except downstream
|
||||
it = std::find_if(nexthops.begin(), nexthops.end(),
|
||||
bind(&predicate_NextHop_eligible, pitEntry, _1, inFace.getId(),
|
||||
bind(&isNextHopEligible, cref(inFace), interest, _1, pitEntry,
|
||||
false, time::steady_clock::TimePoint::min()));
|
||||
|
||||
if (it == nexthops.end()) {
|
||||
@@ -130,41 +151,35 @@ BestRouteStrategy2::afterReceiveInterest(const Face& inFace,
|
||||
return;
|
||||
}
|
||||
|
||||
shared_ptr<Face> outFace = it->getFace();
|
||||
this->sendInterest(pitEntry, outFace);
|
||||
Face& outFace = it->getFace();
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
NFD_LOG_DEBUG(interest << " from=" << inFace.getId()
|
||||
<< " newPitEntry-to=" << outFace->getId());
|
||||
return;
|
||||
}
|
||||
|
||||
if (suppression == RetxSuppression::SUPPRESS) {
|
||||
NFD_LOG_DEBUG(interest << " from=" << inFace.getId()
|
||||
<< " suppressed");
|
||||
<< " newPitEntry-to=" << outFace.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
// find an unused upstream with lowest cost except downstream
|
||||
it = std::find_if(nexthops.begin(), nexthops.end(),
|
||||
bind(&predicate_NextHop_eligible, pitEntry, _1, inFace.getId(),
|
||||
bind(&isNextHopEligible, cref(inFace), interest, _1, pitEntry,
|
||||
true, time::steady_clock::now()));
|
||||
if (it != nexthops.end()) {
|
||||
shared_ptr<Face> outFace = it->getFace();
|
||||
this->sendInterest(pitEntry, outFace);
|
||||
Face& outFace = it->getFace();
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
NFD_LOG_DEBUG(interest << " from=" << inFace.getId()
|
||||
<< " retransmit-unused-to=" << outFace->getId());
|
||||
<< " retransmit-unused-to=" << outFace.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
// find an eligible upstream that is used earliest
|
||||
it = findEligibleNextHopWithEarliestOutRecord(pitEntry, nexthops, inFace.getId());
|
||||
it = findEligibleNextHopWithEarliestOutRecord(inFace, interest, nexthops, pitEntry);
|
||||
if (it == nexthops.end()) {
|
||||
NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " retransmitNoNextHop");
|
||||
}
|
||||
else {
|
||||
shared_ptr<Face> outFace = it->getFace();
|
||||
this->sendInterest(pitEntry, outFace);
|
||||
Face& outFace = it->getFace();
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
NFD_LOG_DEBUG(interest << " from=" << inFace.getId()
|
||||
<< " retransmit-retry-to=" << outFace->getId());
|
||||
<< " retransmit-retry-to=" << outFace.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,8 +201,7 @@ compareLessSevere(lp::NackReason x, lp::NackReason y)
|
||||
|
||||
void
|
||||
BestRouteStrategy2::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
|
||||
shared_ptr<fib::Entry> fibEntry,
|
||||
shared_ptr<pit::Entry> pitEntry)
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
int nOutRecordsNotNacked = 0;
|
||||
Face* lastFaceNotNacked = nullptr;
|
||||
@@ -196,7 +210,7 @@ BestRouteStrategy2::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
|
||||
const lp::NackHeader* inNack = outR.getIncomingNack();
|
||||
if (inNack == nullptr) {
|
||||
++nOutRecordsNotNacked;
|
||||
lastFaceNotNacked = outR.getFace().get();
|
||||
lastFaceNotNacked = &outR.getFace();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -208,8 +222,8 @@ BestRouteStrategy2::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
|
||||
|
||||
if (nOutRecordsNotNacked == 1) {
|
||||
BOOST_ASSERT(lastFaceNotNacked != nullptr);
|
||||
pit::InRecordCollection::const_iterator inR = pitEntry->getInRecord(*lastFaceNotNacked);
|
||||
if (inR != pitEntry->getInRecords().end()) {
|
||||
pit::InRecordCollection::iterator inR = pitEntry->getInRecord(*lastFaceNotNacked);
|
||||
if (inR != pitEntry->in_end()) {
|
||||
// one out-record not Nacked, which is also a downstream
|
||||
NFD_LOG_DEBUG(nack.getInterest() << " nack-from=" << inFace.getId() <<
|
||||
" nack=" << nack.getReason() <<
|
||||
@@ -228,7 +242,6 @@ BestRouteStrategy2::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
NFD_LOG_DEBUG(nack.getInterest() << " nack-from=" << inFace.getId() <<
|
||||
" nack=" << nack.getReason() <<
|
||||
" nack-to=all out-nack=" << outNack.getReason());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -52,20 +52,19 @@ namespace fw {
|
||||
class BestRouteStrategy2 : public Strategy
|
||||
{
|
||||
public:
|
||||
BestRouteStrategy2(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
|
||||
explicit
|
||||
BestRouteStrategy2(Forwarder& forwarder, const Name& name = getStrategyName());
|
||||
|
||||
static const Name&
|
||||
getStrategyName();
|
||||
|
||||
virtual void
|
||||
afterReceiveInterest(const Face& inFace, const Interest& interest,
|
||||
shared_ptr<fib::Entry> fibEntry,
|
||||
shared_ptr<pit::Entry> pitEntry) DECL_OVERRIDE;
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
virtual void
|
||||
afterReceiveNack(const Face& inFace, const lp::Nack& nack,
|
||||
shared_ptr<fib::Entry> fibEntry,
|
||||
shared_ptr<pit::Entry> pitEntry) DECL_OVERRIDE;
|
||||
|
||||
public:
|
||||
static const Name STRATEGY_NAME;
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
static const time::milliseconds RETX_SUPPRESSION_INITIAL;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -30,44 +30,30 @@ namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
NFD_LOG_INIT("ClientControlStrategy");
|
||||
|
||||
const Name
|
||||
ClientControlStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/client-control/%FD%01");
|
||||
NFD_REGISTER_STRATEGY(ClientControlStrategy);
|
||||
|
||||
ClientControlStrategy::ClientControlStrategy(Forwarder& forwarder, const Name& name)
|
||||
: BestRouteStrategy(forwarder, name)
|
||||
: BestRouteStrategyBase(forwarder)
|
||||
{
|
||||
ParsedInstanceName parsed = parseInstanceName(name);
|
||||
if (!parsed.parameters.empty()) {
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("ClientControlStrategy does not accept parameters"));
|
||||
}
|
||||
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument(
|
||||
"ClientControlStrategy does not support version " + std::to_string(*parsed.version)));
|
||||
}
|
||||
this->setInstanceName(makeInstanceName(name, getStrategyName()));
|
||||
|
||||
NFD_LOG_WARN("NextHopFaceId field is honored universally and "
|
||||
"it's unnecessary to set client-control strategy.");
|
||||
}
|
||||
|
||||
ClientControlStrategy::~ClientControlStrategy()
|
||||
const Name&
|
||||
ClientControlStrategy::getStrategyName()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ClientControlStrategy::afterReceiveInterest(const Face& inFace,
|
||||
const Interest& interest,
|
||||
shared_ptr<fib::Entry> fibEntry,
|
||||
shared_ptr<pit::Entry> pitEntry)
|
||||
{
|
||||
shared_ptr<lp::NextHopFaceIdTag> tag = interest.getTag<lp::NextHopFaceIdTag>();
|
||||
if (tag == nullptr) {
|
||||
this->BestRouteStrategy::afterReceiveInterest(inFace, interest, fibEntry, pitEntry);
|
||||
return;
|
||||
}
|
||||
|
||||
FaceId outFaceId = static_cast<FaceId>(*tag);
|
||||
shared_ptr<Face> outFace = this->getFace(outFaceId);
|
||||
if (outFace == nullptr) {
|
||||
// If outFace doesn't exist, it's better to reject the Interest
|
||||
// than to use BestRouteStrategy.
|
||||
NFD_LOG_WARN("Interest " << interest.getName() <<
|
||||
" NextHopFaceId=" << outFaceId << " non-existent face");
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
return;
|
||||
}
|
||||
|
||||
this->sendInterest(pitEntry, outFace);
|
||||
static Name strategyName("/localhost/nfd/strategy/client-control/%FD%02");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
} // namespace fw
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
@@ -31,28 +31,17 @@
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
/** \brief a forwarding strategy controlled by client application
|
||||
*
|
||||
* The consumer may specify the nexthop for an Interest in NDNLPv2 NextHopFaceId field.
|
||||
* If NextHopFaceId field is omitted, the Interest is forwarded to
|
||||
* the FIB nexthop with lowest routing cost.
|
||||
/** \brief identical to BestRouteStrategy v1, for backwards compatibility
|
||||
* \deprecated NextHopFaceId field is honored universally and it's unnecessary to set this strategy
|
||||
*/
|
||||
class ClientControlStrategy : public BestRouteStrategy
|
||||
class ClientControlStrategy : public BestRouteStrategyBase
|
||||
{
|
||||
public:
|
||||
ClientControlStrategy(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
|
||||
explicit
|
||||
ClientControlStrategy(Forwarder& forwarder, const Name& name = getStrategyName());
|
||||
|
||||
virtual
|
||||
~ClientControlStrategy();
|
||||
|
||||
virtual void
|
||||
afterReceiveInterest(const Face& inFace,
|
||||
const Interest& interest,
|
||||
shared_ptr<fib::Entry> fibEntry,
|
||||
shared_ptr<pit::Entry> pitEntry) DECL_OVERRIDE;
|
||||
|
||||
public:
|
||||
static const Name STRATEGY_NAME;
|
||||
static const Name&
|
||||
getStrategyName();
|
||||
};
|
||||
|
||||
} // namespace fw
|
||||
|
||||
+22
-24
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -25,30 +25,30 @@
|
||||
|
||||
#include "face-table.hpp"
|
||||
#include "forwarder.hpp"
|
||||
#include "core/asserts.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
#include "core/logger.hpp"
|
||||
#include "face/channel.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
NFD_ASSERT_FORWARD_ITERATOR(FaceTable::const_iterator);
|
||||
|
||||
NFD_LOG_INIT("FaceTable");
|
||||
|
||||
FaceTable::FaceTable(Forwarder& forwarder)
|
||||
: m_forwarder(forwarder)
|
||||
, m_lastFaceId(face::FACEID_RESERVED_MAX)
|
||||
FaceTable::FaceTable()
|
||||
: m_lastFaceId(face::FACEID_RESERVED_MAX)
|
||||
{
|
||||
}
|
||||
|
||||
FaceTable::~FaceTable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
shared_ptr<Face>
|
||||
Face*
|
||||
FaceTable::get(FaceId id) const
|
||||
{
|
||||
std::map<FaceId, shared_ptr<Face> >::const_iterator i = m_faces.find(id);
|
||||
return (i == m_faces.end()) ? (shared_ptr<Face>()) : (i->second);
|
||||
auto i = m_faces.find(id);
|
||||
if (i == m_faces.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return i->second.get();
|
||||
}
|
||||
|
||||
size_t
|
||||
@@ -87,29 +87,27 @@ FaceTable::addImpl(shared_ptr<Face> face, FaceId faceId)
|
||||
NFD_LOG_INFO("Added face id=" << faceId << " remote=" << face->getRemoteUri()
|
||||
<< " local=" << face->getLocalUri());
|
||||
|
||||
face->afterReceiveInterest.connect(bind(&Forwarder::startProcessInterest, &m_forwarder, ref(*face), _1));
|
||||
face->afterReceiveData.connect(bind(&Forwarder::startProcessData, &m_forwarder, ref(*face), _1));
|
||||
face->afterReceiveNack.connect(bind(&Forwarder::startProcessNack, &m_forwarder, ref(*face), _1));
|
||||
connectFaceClosedSignal(*face, bind(&FaceTable::remove, this, face));
|
||||
connectFaceClosedSignal(*face, bind(&FaceTable::remove, this, faceId));
|
||||
|
||||
this->afterAdd(face);
|
||||
this->afterAdd(*face);
|
||||
}
|
||||
|
||||
void
|
||||
FaceTable::remove(shared_ptr<Face> face)
|
||||
FaceTable::remove(FaceId faceId)
|
||||
{
|
||||
this->beforeRemove(face);
|
||||
auto i = m_faces.find(faceId);
|
||||
BOOST_ASSERT(i != m_faces.end());
|
||||
shared_ptr<Face> face = i->second;
|
||||
|
||||
FaceId faceId = face->getId();
|
||||
m_faces.erase(faceId);
|
||||
this->beforeRemove(*face);
|
||||
|
||||
m_faces.erase(i);
|
||||
face->setId(face::INVALID_FACEID);
|
||||
|
||||
NFD_LOG_INFO("Removed face id=" << faceId <<
|
||||
" remote=" << face->getRemoteUri() <<
|
||||
" local=" << face->getLocalUri());
|
||||
|
||||
m_forwarder.getFib().removeNextHopFromAllEntries(face);
|
||||
|
||||
// defer Face deallocation, so that Transport isn't deallocated during afterStateChange signal
|
||||
getGlobalIoService().post([face] {});
|
||||
}
|
||||
@@ -117,7 +115,7 @@ FaceTable::remove(shared_ptr<Face> face)
|
||||
FaceTable::ForwardRange
|
||||
FaceTable::getForwardRange() const
|
||||
{
|
||||
return m_faces | boost::adaptors::map_values;
|
||||
return m_faces | boost::adaptors::map_values | boost::adaptors::indirected;
|
||||
}
|
||||
|
||||
FaceTable::const_iterator
|
||||
|
||||
+28
-22
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2015, Regents of the University of California,
|
||||
* Copyright (c) 2014-2016, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -27,42 +27,49 @@
|
||||
#define NFD_DAEMON_FW_FACE_TABLE_HPP
|
||||
|
||||
#include "face/face.hpp"
|
||||
#include <boost/range/adaptor/indirected.hpp>
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
class Forwarder;
|
||||
|
||||
/** \brief container of all Faces
|
||||
/** \brief container of all faces
|
||||
*/
|
||||
class FaceTable : noncopyable
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
FaceTable(Forwarder& forwarder);
|
||||
FaceTable();
|
||||
|
||||
VIRTUAL_WITH_TESTS
|
||||
~FaceTable();
|
||||
|
||||
VIRTUAL_WITH_TESTS void
|
||||
/** \brief add a face
|
||||
*
|
||||
* FaceTable obtains shared ownership of the face.
|
||||
* The channel or protocol factory that creates the face may retain ownership.
|
||||
*/
|
||||
void
|
||||
add(shared_ptr<Face> face);
|
||||
|
||||
/// add a special Face with a reserved FaceId
|
||||
VIRTUAL_WITH_TESTS void
|
||||
/** \brief add a special face with a reserved FaceId
|
||||
*/
|
||||
void
|
||||
addReserved(shared_ptr<Face> face, FaceId faceId);
|
||||
|
||||
VIRTUAL_WITH_TESTS shared_ptr<Face>
|
||||
/** \brief get face by FaceId
|
||||
* \return a face if found, nullptr if not found;
|
||||
* face->shared_from_this() can be used if shared_ptr<Face> is desired
|
||||
*/
|
||||
Face*
|
||||
get(FaceId id) const;
|
||||
|
||||
/** \return count of faces
|
||||
*/
|
||||
size_t
|
||||
size() const;
|
||||
|
||||
public: // enumeration
|
||||
typedef std::map<FaceId, shared_ptr<Face>> FaceMap;
|
||||
|
||||
typedef boost::select_second_const_range<FaceMap> ForwardRange;
|
||||
typedef boost::indirected_range<const boost::select_second_const_range<FaceMap>> ForwardRange;
|
||||
|
||||
/** \brief ForwardIterator for shared_ptr<Face>
|
||||
/** \brief ForwardIterator for Face&
|
||||
*/
|
||||
typedef boost::range_iterator<ForwardRange>::type const_iterator;
|
||||
|
||||
@@ -73,28 +80,27 @@ public: // enumeration
|
||||
end() const;
|
||||
|
||||
public: // signals
|
||||
/** \brief fires after a Face is added
|
||||
/** \brief fires after a face is added
|
||||
*/
|
||||
signal::Signal<FaceTable, shared_ptr<Face>> afterAdd;
|
||||
signal::Signal<FaceTable, Face&> afterAdd;
|
||||
|
||||
/** \brief fires before a Face is removed
|
||||
/** \brief fires before a face is removed
|
||||
*
|
||||
* FaceId is valid when this event is fired
|
||||
* When this signal is emitted, face is still in FaceTable and has valid FaceId.
|
||||
*/
|
||||
signal::Signal<FaceTable, shared_ptr<Face>> beforeRemove;
|
||||
signal::Signal<FaceTable, Face&> beforeRemove;
|
||||
|
||||
private:
|
||||
void
|
||||
addImpl(shared_ptr<Face> face, FaceId faceId);
|
||||
|
||||
void
|
||||
remove(shared_ptr<Face> face);
|
||||
remove(FaceId faceId);
|
||||
|
||||
ForwardRange
|
||||
getForwardRange() const;
|
||||
|
||||
private:
|
||||
Forwarder& m_forwarder;
|
||||
FaceId m_lastFaceId;
|
||||
FaceMap m_faces;
|
||||
};
|
||||
|
||||
+104
-179
@@ -24,32 +24,53 @@
|
||||
*/
|
||||
|
||||
#include "forwarder.hpp"
|
||||
#include "core/logger.hpp"
|
||||
#include "core/random.hpp"
|
||||
#include "algorithm.hpp"
|
||||
#include "best-route-strategy2.hpp"
|
||||
#include "strategy.hpp"
|
||||
#include <boost/random/uniform_int_distribution.hpp>
|
||||
#include "core/logger.hpp"
|
||||
#include "table/cleanup.hpp"
|
||||
#include <ndn-cxx/lp/tags.hpp>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
NFD_LOG_INIT("Forwarder");
|
||||
|
||||
using fw::Strategy;
|
||||
|
||||
const Name Forwarder::LOCALHOST_NAME("ndn:/localhost");
|
||||
static Name
|
||||
getDefaultStrategyName()
|
||||
{
|
||||
return fw::BestRouteStrategy2::getStrategyName();
|
||||
}
|
||||
|
||||
Forwarder::Forwarder()
|
||||
: m_faceTable(*this)
|
||||
: m_unsolicitedDataPolicy(new fw::DefaultUnsolicitedDataPolicy())
|
||||
, m_fib(m_nameTree)
|
||||
, m_pit(m_nameTree)
|
||||
, m_measurements(m_nameTree)
|
||||
, m_strategyChoice(m_nameTree, fw::makeDefaultStrategy(*this))
|
||||
, m_strategyChoice(*this)
|
||||
{
|
||||
fw::installStrategies(*this);
|
||||
m_faceTable.afterAdd.connect([this] (Face& face) {
|
||||
face.afterReceiveInterest.connect(
|
||||
[this, &face] (const Interest& interest) {
|
||||
this->startProcessInterest(face, interest);
|
||||
});
|
||||
face.afterReceiveData.connect(
|
||||
[this, &face] (const Data& data) {
|
||||
this->startProcessData(face, data);
|
||||
});
|
||||
face.afterReceiveNack.connect(
|
||||
[this, &face] (const lp::Nack& nack) {
|
||||
this->startProcessNack(face, nack);
|
||||
});
|
||||
});
|
||||
|
||||
m_faceTable.beforeRemove.connect([this] (Face& face) {
|
||||
cleanupOnFaceRemoval(m_nameTree, m_fib, m_pit, face);
|
||||
});
|
||||
|
||||
m_strategyChoice.setDefaultStrategy(getDefaultStrategyName());
|
||||
}
|
||||
|
||||
Forwarder::~Forwarder()
|
||||
{
|
||||
}
|
||||
Forwarder::~Forwarder() = default;
|
||||
|
||||
void
|
||||
Forwarder::startProcessInterest(Face& face, const Interest& interest)
|
||||
@@ -109,7 +130,7 @@ Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
|
||||
|
||||
// /localhost scope control
|
||||
bool isViolatingLocalhost = inFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
|
||||
LOCALHOST_NAME.isPrefixOf(interest.getName());
|
||||
scope_prefix::LOCALHOST.isPrefixOf(interest.getName());
|
||||
if (isViolatingLocalhost) {
|
||||
NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
|
||||
" interest=" << interest.getName() << " violates /localhost");
|
||||
@@ -129,8 +150,8 @@ Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
|
||||
shared_ptr<pit::Entry> pitEntry = m_pit.insert(interest).first;
|
||||
|
||||
// detect duplicate Nonce in PIT entry
|
||||
bool hasDuplicateNonceInPit = pitEntry->findNonce(interest.getNonce(), inFace) !=
|
||||
pit::DUPLICATE_NONCE_NONE;
|
||||
bool hasDuplicateNonceInPit = fw::findDuplicateNonce(*pitEntry, interest.getNonce(), inFace) !=
|
||||
fw::DUPLICATE_NONCE_NONE;
|
||||
if (hasDuplicateNonceInPit) {
|
||||
// goto Interest loop pipeline
|
||||
this->onInterestLoop(inFace, interest);
|
||||
@@ -138,12 +159,10 @@ Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
|
||||
}
|
||||
|
||||
// cancel unsatisfy & straggler timer
|
||||
this->cancelUnsatisfyAndStragglerTimer(pitEntry);
|
||||
this->cancelUnsatisfyAndStragglerTimer(*pitEntry);
|
||||
|
||||
// is pending?
|
||||
const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
|
||||
bool isPending = inRecords.begin() != inRecords.end();
|
||||
if (!isPending) {
|
||||
if (!pitEntry->hasInRecords()) {
|
||||
m_cs.find(interest,
|
||||
bind(&Forwarder::onContentStoreHit, this, ref(inFace), pitEntry, _1, _2),
|
||||
bind(&Forwarder::onContentStoreMiss, this, ref(inFace), pitEntry, _1));
|
||||
@@ -176,77 +195,39 @@ Forwarder::onInterestLoop(Face& inFace, const Interest& interest)
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onContentStoreMiss(const Face& inFace,
|
||||
shared_ptr<pit::Entry> pitEntry,
|
||||
Forwarder::onContentStoreMiss(const Face& inFace, const shared_ptr<pit::Entry>& pitEntry,
|
||||
const Interest& interest)
|
||||
{
|
||||
NFD_LOG_DEBUG("onContentStoreMiss interest=" << interest.getName());
|
||||
|
||||
shared_ptr<Face> face = const_pointer_cast<Face>(inFace.shared_from_this());
|
||||
// insert InRecord
|
||||
pitEntry->insertOrUpdateInRecord(face, interest);
|
||||
// insert in-record
|
||||
pitEntry->insertOrUpdateInRecord(const_cast<Face&>(inFace), interest);
|
||||
|
||||
// set PIT unsatisfy timer
|
||||
this->setUnsatisfyTimer(pitEntry);
|
||||
|
||||
shared_ptr<fib::Entry> fibEntry;
|
||||
// has Link object?
|
||||
if (!interest.hasLink()) {
|
||||
// FIB lookup with Interest name
|
||||
fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
|
||||
NFD_LOG_TRACE("onContentStoreMiss noLinkObject");
|
||||
}
|
||||
else {
|
||||
const Link& link = interest.getLink();
|
||||
|
||||
// in producer region?
|
||||
if (m_networkRegionTable.isInProducerRegion(link)) {
|
||||
// FIB lookup with Interest name
|
||||
fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
|
||||
NFD_LOG_TRACE("onContentStoreMiss inProducerRegion");
|
||||
}
|
||||
// has SelectedDelegation?
|
||||
else if (interest.hasSelectedDelegation()) {
|
||||
// FIB lookup with SelectedDelegation
|
||||
fibEntry = m_fib.findLongestPrefixMatch(interest.getSelectedDelegation());
|
||||
NFD_LOG_TRACE("onContentStoreMiss hasSelectedDelegation=" << interest.getSelectedDelegation());
|
||||
}
|
||||
else {
|
||||
// FIB lookup with first delegation Name
|
||||
fibEntry = m_fib.findLongestPrefixMatch(link.getDelegations().begin()->second);
|
||||
|
||||
// in default-free zone?
|
||||
bool isDefaultFreeZone = !(fibEntry->getPrefix().size() == 0 && fibEntry->hasNextHops());
|
||||
if (isDefaultFreeZone) {
|
||||
// choose and set SelectedDelegation
|
||||
for (const std::pair<uint32_t, Name>& delegation : link.getDelegations()) {
|
||||
const Name& delegationName = delegation.second;
|
||||
fibEntry = m_fib.findLongestPrefixMatch(delegationName);
|
||||
if (fibEntry->hasNextHops()) {
|
||||
const_cast<Interest&>(interest).setSelectedDelegation(delegationName);
|
||||
NFD_LOG_TRACE("onContentStoreMiss enterDefaultFreeZone"
|
||||
<< " setSelectedDelegation=" << delegationName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
NFD_LOG_TRACE("onContentStoreMiss inConsumerRegion");
|
||||
}
|
||||
// has NextHopFaceId?
|
||||
shared_ptr<lp::NextHopFaceIdTag> nextHopTag = interest.getTag<lp::NextHopFaceIdTag>();
|
||||
if (nextHopTag != nullptr) {
|
||||
// chosen NextHop face exists?
|
||||
Face* nextHopFace = m_faceTable.get(*nextHopTag);
|
||||
if (nextHopFace != nullptr) {
|
||||
NFD_LOG_DEBUG("onContentStoreMiss interest=" << interest.getName() << " nexthop-faceid=" << nextHopFace->getId());
|
||||
// go to outgoing Interest pipeline
|
||||
// scope control is unnecessary, because privileged app explicitly wants to forward
|
||||
this->onOutgoingInterest(pitEntry, *nextHopFace, interest);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// dispatch to strategy
|
||||
BOOST_ASSERT(fibEntry != nullptr);
|
||||
this->dispatchToStrategy(pitEntry, bind(&Strategy::afterReceiveInterest, _1,
|
||||
cref(inFace), cref(interest), fibEntry, pitEntry));
|
||||
// dispatch to strategy: after incoming Interest
|
||||
this->dispatchToStrategy(*pitEntry,
|
||||
[&] (fw::Strategy& strategy) { strategy.afterReceiveInterest(inFace, interest, pitEntry); });
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onContentStoreHit(const Face& inFace,
|
||||
shared_ptr<pit::Entry> pitEntry,
|
||||
const Interest& interest,
|
||||
const Data& data)
|
||||
Forwarder::onContentStoreHit(const Face& inFace, const shared_ptr<pit::Entry>& pitEntry,
|
||||
const Interest& interest, const Data& data)
|
||||
{
|
||||
NFD_LOG_DEBUG("onContentStoreHit interest=" << interest.getName());
|
||||
|
||||
@@ -260,76 +241,24 @@ Forwarder::onContentStoreHit(const Face& inFace,
|
||||
this->onOutgoingData(data, *const_pointer_cast<Face>(inFace.shared_from_this()));
|
||||
}
|
||||
|
||||
/** \brief compare two InRecords for picking outgoing Interest
|
||||
* \return true if b is preferred over a
|
||||
*
|
||||
* This function should be passed to std::max_element over InRecordCollection.
|
||||
* The outgoing Interest picked is the last incoming Interest
|
||||
* that does not come from outFace.
|
||||
* If all InRecords come from outFace, it's fine to pick that. This happens when
|
||||
* there's only one InRecord that comes from outFace. The legit use is for
|
||||
* vehicular network; otherwise, strategy shouldn't send to the sole inFace.
|
||||
*/
|
||||
static inline bool
|
||||
compare_pickInterest(const pit::InRecord& a, const pit::InRecord& b, const Face* outFace)
|
||||
{
|
||||
bool isOutFaceA = a.getFace().get() == outFace;
|
||||
bool isOutFaceB = b.getFace().get() == outFace;
|
||||
|
||||
if (!isOutFaceA && isOutFaceB) {
|
||||
return false;
|
||||
}
|
||||
if (isOutFaceA && !isOutFaceB) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return a.getLastRenewed() > b.getLastRenewed();
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace,
|
||||
bool wantNewNonce)
|
||||
Forwarder::onOutgoingInterest(const shared_ptr<pit::Entry>& pitEntry, Face& outFace, const Interest& interest)
|
||||
{
|
||||
if (outFace.getId() == face::INVALID_FACEID) {
|
||||
NFD_LOG_WARN("onOutgoingInterest face=invalid interest=" << pitEntry->getName());
|
||||
return;
|
||||
}
|
||||
NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
|
||||
" interest=" << pitEntry->getName());
|
||||
|
||||
// scope control
|
||||
if (pitEntry->violatesScope(outFace)) {
|
||||
NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
|
||||
" interest=" << pitEntry->getName() << " violates scope");
|
||||
return;
|
||||
}
|
||||
|
||||
// pick Interest
|
||||
const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
|
||||
pit::InRecordCollection::const_iterator pickedInRecord = std::max_element(
|
||||
inRecords.begin(), inRecords.end(), bind(&compare_pickInterest, _1, _2, &outFace));
|
||||
BOOST_ASSERT(pickedInRecord != inRecords.end());
|
||||
shared_ptr<Interest> interest = const_pointer_cast<Interest>(
|
||||
pickedInRecord->getInterest().shared_from_this());
|
||||
|
||||
if (wantNewNonce) {
|
||||
interest = make_shared<Interest>(*interest);
|
||||
static boost::random::uniform_int_distribution<uint32_t> dist;
|
||||
interest->setNonce(dist(getGlobalRng()));
|
||||
}
|
||||
|
||||
// insert OutRecord
|
||||
pitEntry->insertOrUpdateOutRecord(outFace.shared_from_this(), *interest);
|
||||
// insert out-record
|
||||
pitEntry->insertOrUpdateOutRecord(outFace, interest);
|
||||
|
||||
// send Interest
|
||||
outFace.sendInterest(*interest);
|
||||
outFace.sendInterest(interest);
|
||||
++m_counters.nOutInterests;
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onInterestReject(shared_ptr<pit::Entry> pitEntry)
|
||||
Forwarder::onInterestReject(const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
if (pitEntry->hasUnexpiredOutRecords()) {
|
||||
if (fw::hasPendingOutRecords(*pitEntry)) {
|
||||
NFD_LOG_ERROR("onInterestReject interest=" << pitEntry->getName() <<
|
||||
" cannot reject forwarded Interest");
|
||||
return;
|
||||
@@ -337,28 +266,28 @@ Forwarder::onInterestReject(shared_ptr<pit::Entry> pitEntry)
|
||||
NFD_LOG_DEBUG("onInterestReject interest=" << pitEntry->getName());
|
||||
|
||||
// cancel unsatisfy & straggler timer
|
||||
this->cancelUnsatisfyAndStragglerTimer(pitEntry);
|
||||
this->cancelUnsatisfyAndStragglerTimer(*pitEntry);
|
||||
|
||||
// set PIT straggler timer
|
||||
this->setStragglerTimer(pitEntry, false);
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onInterestUnsatisfied(shared_ptr<pit::Entry> pitEntry)
|
||||
Forwarder::onInterestUnsatisfied(const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
NFD_LOG_DEBUG("onInterestUnsatisfied interest=" << pitEntry->getName());
|
||||
|
||||
// invoke PIT unsatisfied callback
|
||||
this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeExpirePendingInterest, _1,
|
||||
pitEntry));
|
||||
this->dispatchToStrategy(*pitEntry,
|
||||
[&] (fw::Strategy& strategy) { strategy.beforeExpirePendingInterest(pitEntry); });
|
||||
|
||||
// goto Interest Finalize pipeline
|
||||
this->onInterestFinalize(pitEntry, false);
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onInterestFinalize(shared_ptr<pit::Entry> pitEntry, bool isSatisfied,
|
||||
const time::milliseconds& dataFreshnessPeriod)
|
||||
Forwarder::onInterestFinalize(const shared_ptr<pit::Entry>& pitEntry, bool isSatisfied,
|
||||
time::milliseconds dataFreshnessPeriod)
|
||||
{
|
||||
NFD_LOG_DEBUG("onInterestFinalize interest=" << pitEntry->getName() <<
|
||||
(isSatisfied ? " satisfied" : " unsatisfied"));
|
||||
@@ -367,8 +296,8 @@ Forwarder::onInterestFinalize(shared_ptr<pit::Entry> pitEntry, bool isSatisfied,
|
||||
this->insertDeadNonceList(*pitEntry, isSatisfied, dataFreshnessPeriod, 0);
|
||||
|
||||
// PIT delete
|
||||
this->cancelUnsatisfyAndStragglerTimer(pitEntry);
|
||||
m_pit.erase(pitEntry);
|
||||
this->cancelUnsatisfyAndStragglerTimer(*pitEntry);
|
||||
m_pit.erase(pitEntry.get());
|
||||
}
|
||||
|
||||
void
|
||||
@@ -381,7 +310,7 @@ Forwarder::onIncomingData(Face& inFace, const Data& data)
|
||||
|
||||
// /localhost scope control
|
||||
bool isViolatingLocalhost = inFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
|
||||
LOCALHOST_NAME.isPrefixOf(data.getName());
|
||||
scope_prefix::LOCALHOST.isPrefixOf(data.getName());
|
||||
if (isViolatingLocalhost) {
|
||||
NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() <<
|
||||
" data=" << data.getName() << " violates /localhost");
|
||||
@@ -402,29 +331,29 @@ Forwarder::onIncomingData(Face& inFace, const Data& data)
|
||||
|
||||
std::set<Face*> pendingDownstreams;
|
||||
// foreach PitEntry
|
||||
auto now = time::steady_clock::now();
|
||||
for (const shared_ptr<pit::Entry>& pitEntry : pitMatches) {
|
||||
NFD_LOG_DEBUG("onIncomingData matching=" << pitEntry->getName());
|
||||
|
||||
// cancel unsatisfy & straggler timer
|
||||
this->cancelUnsatisfyAndStragglerTimer(pitEntry);
|
||||
this->cancelUnsatisfyAndStragglerTimer(*pitEntry);
|
||||
|
||||
// remember pending downstreams
|
||||
const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
|
||||
for (const pit::InRecord& inRecord : inRecords) {
|
||||
if (inRecord.getExpiry() > time::steady_clock::now()) {
|
||||
pendingDownstreams.insert(inRecord.getFace().get());
|
||||
for (const pit::InRecord& inRecord : pitEntry->getInRecords()) {
|
||||
if (inRecord.getExpiry() > now) {
|
||||
pendingDownstreams.insert(&inRecord.getFace());
|
||||
}
|
||||
}
|
||||
|
||||
// invoke PIT satisfy callback
|
||||
this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeSatisfyInterest, _1,
|
||||
pitEntry, cref(inFace), cref(data)));
|
||||
this->dispatchToStrategy(*pitEntry,
|
||||
[&] (fw::Strategy& strategy) { strategy.beforeSatisfyInterest(pitEntry, inFace, data); });
|
||||
|
||||
// Dead Nonce List insert if necessary (for OutRecord of inFace)
|
||||
// Dead Nonce List insert if necessary (for out-record of inFace)
|
||||
this->insertDeadNonceList(*pitEntry, true, data.getFreshnessPeriod(), &inFace);
|
||||
|
||||
// mark PIT satisfied
|
||||
pitEntry->deleteInRecords();
|
||||
pitEntry->clearInRecords();
|
||||
pitEntry->deleteOutRecord(inFace);
|
||||
|
||||
// set PIT straggler timer
|
||||
@@ -445,15 +374,15 @@ void
|
||||
Forwarder::onDataUnsolicited(Face& inFace, const Data& data)
|
||||
{
|
||||
// accept to cache?
|
||||
bool acceptToCache = inFace.getScope() == ndn::nfd::FACE_SCOPE_LOCAL;
|
||||
if (acceptToCache) {
|
||||
fw::UnsolicitedDataDecision decision = m_unsolicitedDataPolicy->decide(inFace, data);
|
||||
if (decision == fw::UnsolicitedDataDecision::CACHE) {
|
||||
// CS insert
|
||||
m_cs.insert(data, true);
|
||||
}
|
||||
|
||||
NFD_LOG_DEBUG("onDataUnsolicited face=" << inFace.getId() <<
|
||||
" data=" << data.getName() <<
|
||||
(acceptToCache ? " cached" : " not cached"));
|
||||
" decision=" << decision);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -467,7 +396,7 @@ Forwarder::onOutgoingData(const Data& data, Face& outFace)
|
||||
|
||||
// /localhost scope control
|
||||
bool isViolatingLocalhost = outFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
|
||||
LOCALHOST_NAME.isPrefixOf(data.getName());
|
||||
scope_prefix::LOCALHOST.isPrefixOf(data.getName());
|
||||
if (isViolatingLocalhost) {
|
||||
NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() <<
|
||||
" data=" << data.getName() << " violates /localhost");
|
||||
@@ -510,7 +439,7 @@ Forwarder::onIncomingNack(Face& inFace, const lp::Nack& nack)
|
||||
// has out-record?
|
||||
pit::OutRecordCollection::iterator outRecord = pitEntry->getOutRecord(inFace);
|
||||
// if no out-record found, drop
|
||||
if (outRecord == pitEntry->getOutRecords().end()) {
|
||||
if (outRecord == pitEntry->out_end()) {
|
||||
NFD_LOG_DEBUG("onIncomingNack face=" << inFace.getId() <<
|
||||
" nack=" << nack.getInterest().getName() <<
|
||||
"~" << nack.getReason() << " no-out-record");
|
||||
@@ -534,13 +463,12 @@ Forwarder::onIncomingNack(Face& inFace, const lp::Nack& nack)
|
||||
outRecord->setIncomingNack(nack);
|
||||
|
||||
// trigger strategy: after receive NACK
|
||||
shared_ptr<fib::Entry> fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
|
||||
this->dispatchToStrategy(pitEntry, bind(&Strategy::afterReceiveNack, _1,
|
||||
cref(inFace), cref(nack), fibEntry, pitEntry));
|
||||
this->dispatchToStrategy(*pitEntry,
|
||||
[&] (fw::Strategy& strategy) { strategy.afterReceiveNack(inFace, nack, pitEntry); });
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onOutgoingNack(shared_ptr<pit::Entry> pitEntry, const Face& outFace,
|
||||
Forwarder::onOutgoingNack(const shared_ptr<pit::Entry>& pitEntry, const Face& outFace,
|
||||
const lp::NackHeader& nack)
|
||||
{
|
||||
if (outFace.getId() == face::INVALID_FACEID) {
|
||||
@@ -551,10 +479,10 @@ Forwarder::onOutgoingNack(shared_ptr<pit::Entry> pitEntry, const Face& outFace,
|
||||
}
|
||||
|
||||
// has in-record?
|
||||
pit::InRecordCollection::const_iterator inRecord = pitEntry->getInRecord(outFace);
|
||||
pit::InRecordCollection::iterator inRecord = pitEntry->getInRecord(outFace);
|
||||
|
||||
// if no in-record found, drop
|
||||
if (inRecord == pitEntry->getInRecords().end()) {
|
||||
if (inRecord == pitEntry->in_end()) {
|
||||
NFD_LOG_DEBUG("onOutgoingNack face=" << outFace.getId() <<
|
||||
" nack=" << pitEntry->getInterest().getName() <<
|
||||
"~" << nack.getReason() << " no-in-record");
|
||||
@@ -592,17 +520,15 @@ compare_InRecord_expiry(const pit::InRecord& a, const pit::InRecord& b)
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::setUnsatisfyTimer(shared_ptr<pit::Entry> pitEntry)
|
||||
Forwarder::setUnsatisfyTimer(const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
|
||||
pit::InRecordCollection::const_iterator lastExpiring =
|
||||
std::max_element(inRecords.begin(), inRecords.end(),
|
||||
&compare_InRecord_expiry);
|
||||
pit::InRecordCollection::iterator lastExpiring =
|
||||
std::max_element(pitEntry->in_begin(), pitEntry->in_end(), &compare_InRecord_expiry);
|
||||
|
||||
time::steady_clock::TimePoint lastExpiry = lastExpiring->getExpiry();
|
||||
time::nanoseconds lastExpiryFromNow = lastExpiry - time::steady_clock::now();
|
||||
if (lastExpiryFromNow <= time::seconds(0)) {
|
||||
// TODO all InRecords are already expired; will this happen?
|
||||
time::nanoseconds lastExpiryFromNow = lastExpiry - time::steady_clock::now();
|
||||
if (lastExpiryFromNow <= time::seconds::zero()) {
|
||||
// TODO all in-records are already expired; will this happen?
|
||||
}
|
||||
|
||||
scheduler::cancel(pitEntry->m_unsatisfyTimer);
|
||||
@@ -611,8 +537,8 @@ Forwarder::setUnsatisfyTimer(shared_ptr<pit::Entry> pitEntry)
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::setStragglerTimer(shared_ptr<pit::Entry> pitEntry, bool isSatisfied,
|
||||
const time::milliseconds& dataFreshnessPeriod)
|
||||
Forwarder::setStragglerTimer(const shared_ptr<pit::Entry>& pitEntry, bool isSatisfied,
|
||||
time::milliseconds dataFreshnessPeriod)
|
||||
{
|
||||
time::nanoseconds stragglerTime = time::milliseconds(100);
|
||||
|
||||
@@ -622,10 +548,10 @@ Forwarder::setStragglerTimer(shared_ptr<pit::Entry> pitEntry, bool isSatisfied,
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::cancelUnsatisfyAndStragglerTimer(shared_ptr<pit::Entry> pitEntry)
|
||||
Forwarder::cancelUnsatisfyAndStragglerTimer(pit::Entry& pitEntry)
|
||||
{
|
||||
scheduler::cancel(pitEntry->m_unsatisfyTimer);
|
||||
scheduler::cancel(pitEntry->m_stragglerTimer);
|
||||
scheduler::cancel(pitEntry.m_unsatisfyTimer);
|
||||
scheduler::cancel(pitEntry.m_stragglerTimer);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -637,8 +563,7 @@ insertNonceToDnl(DeadNonceList& dnl, const pit::Entry& pitEntry,
|
||||
|
||||
void
|
||||
Forwarder::insertDeadNonceList(pit::Entry& pitEntry, bool isSatisfied,
|
||||
const time::milliseconds& dataFreshnessPeriod,
|
||||
Face* upstream)
|
||||
time::milliseconds dataFreshnessPeriod, Face* upstream)
|
||||
{
|
||||
// need Dead Nonce List insert?
|
||||
bool needDnl = false;
|
||||
@@ -665,7 +590,7 @@ Forwarder::insertDeadNonceList(pit::Entry& pitEntry, bool isSatisfied,
|
||||
}
|
||||
else {
|
||||
// insert outgoing Nonce of a specific face
|
||||
pit::OutRecordCollection::const_iterator outRecord = pitEntry.getOutRecord(*upstream);
|
||||
pit::OutRecordCollection::iterator outRecord = pitEntry.getOutRecord(*upstream);
|
||||
if (outRecord != pitEntry.getOutRecords().end()) {
|
||||
m_deadNonceList.add(pitEntry.getName(), outRecord->getLastNonce());
|
||||
}
|
||||
|
||||
Loaded 100 of 426 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user