Compare commits
61
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
704430ca07 | ||
|
|
58d479cd4a | ||
|
|
305529410b | ||
|
|
150b80deee | ||
|
|
280d7dde50 | ||
|
|
8509398137 | ||
|
|
42388d6c08 | ||
|
|
ffe8bbb8aa | ||
|
|
330136a89e | ||
|
|
bb9102f7d4 | ||
|
|
4310d505a7 | ||
|
|
d5fe0cf158 | ||
|
|
9360623853 | ||
|
|
e6f0e91590 | ||
|
|
dd7e5da016 | ||
|
|
459cf197b7 | ||
|
|
073da60b19 | ||
|
|
4370fde844 | ||
|
|
965f23dd61 | ||
|
|
72cee94646 | ||
|
|
bc9ed49a55 | ||
|
|
6db75f0bd2 | ||
|
|
4100646192 | ||
|
|
3152abac67 | ||
|
|
9aac873415 | ||
|
|
da3ba96430 | ||
|
|
809462490f | ||
|
|
498373dd01 | ||
|
|
c64d30aeff | ||
|
|
5c47597be9 | ||
|
|
6d8ee7acc9 | ||
|
|
cde37ad608 | ||
|
|
c5401494fe | ||
|
|
65caf20092 | ||
|
|
ca25d72064 | ||
|
|
f22ebaf7f1 | ||
|
|
f35a5a9b08 | ||
|
|
f68f378a23 | ||
|
|
8717e87046 | ||
|
|
0de23a29c5 | ||
|
|
6c4a67af0d | ||
|
|
35120ea2f1 | ||
|
|
eee7b97d7b | ||
|
|
762912d711 | ||
|
|
bd916ad7fc | ||
|
|
4c3e6b89a1 | ||
|
|
8c0500fd97 | ||
|
|
da93f1fd0c | ||
|
|
57df288f5b | ||
|
|
52e8540a86 | ||
|
|
077df8fbb6 | ||
|
|
8728a25f1d | ||
|
|
d5134a7cd4 | ||
|
|
47ab029798 | ||
|
|
ed89ccc521 | ||
|
|
16aabbcc3b | ||
|
|
9c7c79f2eb | ||
|
|
a044be7ed9 | ||
|
|
2d6d5637c0 | ||
|
|
5b8a2b2128 | ||
|
|
abb307c9c5 |
No files matched your search
@@ -5,7 +5,7 @@ set -e
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
|
||||
pushd /tmp >/dev/null
|
||||
pushd ${CACHE_DIR:-/tmp} >/dev/null
|
||||
|
||||
INSTALLED_VERSION=$((cd ndn-cxx && git rev-parse HEAD) 2>/dev/null || echo NONE)
|
||||
|
||||
|
||||
@@ -6,30 +6,31 @@ git submodule init
|
||||
git submodule sync
|
||||
git submodule update
|
||||
|
||||
COVERAGE=$( python -c "print '--with-coverage' if 'code-coverage' in '$JOB_NAME' else ''" )
|
||||
|
||||
# Cleanup
|
||||
sudo ./waf -j1 --color=yes distclean
|
||||
|
||||
# Configure/build in debug mode
|
||||
./waf -j1 --color=yes configure --with-tests --debug
|
||||
# Configure/build in optimized mode with tests and precompiled headers
|
||||
./waf -j1 --color=yes configure --with-tests
|
||||
./waf -j1 --color=yes build
|
||||
|
||||
# Cleanup
|
||||
sudo ./waf -j1 --color=yes distclean
|
||||
|
||||
# Configure/build in optimized mode without tests with precompiled headers
|
||||
# Configure/build in optimized mode without tests and with precompiled headers
|
||||
./waf -j1 --color=yes configure
|
||||
./waf -j1 --color=yes build
|
||||
|
||||
# Cleanup
|
||||
sudo ./waf -j1 --color=yes distclean
|
||||
|
||||
# Configure/build in optimized mode
|
||||
./waf -j1 --color=yes configure --with-tests --without-pch $COVERAGE
|
||||
# Configure/build in debug mode
|
||||
if [[ "$JOB_NAME" == *"code-coverage" ]]; then
|
||||
COVERAGE="--with-coverage"
|
||||
fi
|
||||
./waf -j1 --color=yes configure --debug --with-tests --without-pch $COVERAGE
|
||||
./waf -j1 --color=yes build
|
||||
|
||||
# (tests will be run against optimized version)
|
||||
# (tests will be run against debug version)
|
||||
|
||||
# Install
|
||||
sudo ./waf -j1 --color=yes install
|
||||
+19
-12
@@ -2,19 +2,19 @@
|
||||
set -x
|
||||
set -e
|
||||
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
|
||||
# Prepare environment
|
||||
rm -Rf ~/.ndnx ~/.ndn
|
||||
|
||||
echo $NODE_LABELS
|
||||
IS_OSX=$( python -c "print 'yes' if 'OSX' in '$NODE_LABELS'.strip().split(' ') else 'no'" )
|
||||
IS_LINUX=$( python -c "print 'yes' if 'Linux' in '$NODE_LABELS'.strip().split(' ') else 'no'" )
|
||||
|
||||
if [[ $IS_OSX == "yes" ]]; then
|
||||
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 [[ $IS_LINUX = "yes" ]]; then
|
||||
|
||||
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
|
||||
@@ -24,11 +24,18 @@ ndnsec-keygen "/tmp/jenkins/$NODE_NAME" | ndnsec-install-cert -
|
||||
|
||||
# Run unit tests
|
||||
# Core
|
||||
./build/unit-tests-core -l test_suite
|
||||
sudo ./build/unit-tests-core -t TestPrivilegeHelper -l test_suite
|
||||
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
|
||||
|
||||
# Daemon
|
||||
./build/unit-tests-daemon -l test_suite
|
||||
./build/unit-tests-daemon -l all -- --log_format2=XML --log_sink2=build/xunit-daemon-report.xml
|
||||
|
||||
# RIB
|
||||
./build/unit-tests-rib -l test_suite
|
||||
./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
|
||||
|
||||
./build/unit-tests-daemon -l test_suite
|
||||
|
||||
./build/unit-tests-rib -l test_suite
|
||||
fi
|
||||
@@ -2,9 +2,10 @@
|
||||
set -x
|
||||
set -e
|
||||
|
||||
IS_COVR=$( python -c "print 'yes' if 'code-coverage' in '$JOB_NAME' else 'no'" )
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
|
||||
if [[ $IS_COVR == "yes" ]]; then
|
||||
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 ./)
|
||||
fi
|
||||
@@ -28,3 +28,6 @@ Environment Variables Used in Build Scripts
|
||||
|
||||
* empty: default build process
|
||||
* `code-coverage` (Linux OS is assumed): build process with code coverage analysis
|
||||
|
||||
- `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.
|
||||
+216
-76
@@ -30,15 +30,15 @@ When using this tool, the wscript will look like:
|
||||
|
||||
Options are generated, in order to specify the location of boost includes/libraries.
|
||||
The `check_boost` configuration function allows to specify the used boost libraries.
|
||||
It can also provide default arguments to the --boost-static and --boost-mt command-line arguments.
|
||||
It can also provide default arguments to the --boost-mt command-line arguments.
|
||||
Everything will be packaged together in a BOOST component that you can use.
|
||||
|
||||
When using MSVC, a lot of compilation flags need to match your BOOST build configuration:
|
||||
- you may have to add /EHsc to your CXXFLAGS or define boost::throw_exception if BOOST_NO_EXCEPTIONS is defined.
|
||||
Errors: C4530
|
||||
- boost libraries will try to be smart and use the (pretty but often not useful) auto-linking feature of MSVC
|
||||
So before calling `conf.check_boost` you might want to disabling by adding:
|
||||
conf.env.DEFINES_BOOST += ['BOOST_ALL_NO_LIB']
|
||||
So before calling `conf.check_boost` you might want to disabling by adding
|
||||
conf.env.DEFINES_BOOST += ['BOOST_ALL_NO_LIB']
|
||||
Errors:
|
||||
- boost might also be compiled with /MT, which links the runtime statically.
|
||||
If you have problems with redefined symbols,
|
||||
@@ -52,24 +52,55 @@ import sys
|
||||
import re
|
||||
from waflib import Utils, Logs, Errors
|
||||
from waflib.Configure import conf
|
||||
from waflib.TaskGen import feature, after_method
|
||||
|
||||
BOOST_LIBS = ['/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib', '/usr/lib/x86_64-linux-gnu', '/usr/lib/i386-linux-gnu', '/usr/local/ndn/lib']
|
||||
BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include', '/usr/local/ndn/include']
|
||||
BOOST_LIBS = ['/usr/lib/x86_64-linux-gnu', '/usr/lib/i386-linux-gnu',
|
||||
'/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib']
|
||||
BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include']
|
||||
BOOST_VERSION_FILE = 'boost/version.hpp'
|
||||
BOOST_VERSION_CODE = '''
|
||||
#include <iostream>
|
||||
#include <boost/version.hpp>
|
||||
int main() { std::cout << BOOST_LIB_VERSION << ":" << BOOST_VERSION << std::endl; }
|
||||
'''
|
||||
BOOST_SYSTEM_CODE = '''
|
||||
|
||||
BOOST_ERROR_CODE = '''
|
||||
#include <boost/system/error_code.hpp>
|
||||
int main() { boost::system::error_code c; }
|
||||
'''
|
||||
|
||||
PTHREAD_CODE = '''
|
||||
#include <pthread.h>
|
||||
static void* f(void*) { return 0; }
|
||||
int main() {
|
||||
pthread_t th;
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_create(&th, &attr, &f, 0);
|
||||
pthread_join(th, 0);
|
||||
pthread_cleanup_push(0, 0);
|
||||
pthread_cleanup_pop(0);
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
'''
|
||||
|
||||
BOOST_THREAD_CODE = '''
|
||||
#include <boost/thread.hpp>
|
||||
int main() { boost::thread t; }
|
||||
'''
|
||||
|
||||
BOOST_LOG_CODE = '''
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/log/utility/setup/console.hpp>
|
||||
#include <boost/log/utility/setup/common_attributes.hpp>
|
||||
int main() {
|
||||
using namespace boost::log;
|
||||
add_common_attributes();
|
||||
add_console_log(std::clog, keywords::format = "%Message%");
|
||||
BOOST_LOG_TRIVIAL(debug) << "log is working" << std::endl;
|
||||
}
|
||||
'''
|
||||
|
||||
# toolsets from {boost_dir}/tools/build/v2/tools/common.jam
|
||||
PLATFORM = Utils.unversioned_sys_platform()
|
||||
detect_intel = lambda env: (PLATFORM == 'win32') and 'iw' or 'il'
|
||||
@@ -101,34 +132,37 @@ BOOST_TOOLSETS = {
|
||||
|
||||
def options(opt):
|
||||
opt = opt.add_option_group('Boost Options')
|
||||
|
||||
opt.add_option('--boost-includes', type='string',
|
||||
default='', dest='boost_includes',
|
||||
help='''path to the directory where the boost includes are, e.g., /path/to/boost_1_55_0/stage/include''')
|
||||
help='''path to the directory where the boost includes are,
|
||||
e.g., /path/to/boost_1_55_0/stage/include''')
|
||||
opt.add_option('--boost-libs', type='string',
|
||||
default='', dest='boost_libs',
|
||||
help='''path to the directory where the boost libs are, e.g., /path/to/boost_1_55_0/stage/lib''')
|
||||
opt.add_option('--boost-static', action='store_true',
|
||||
default=False, dest='boost_static',
|
||||
help='link with static boost libraries (.lib/.a)')
|
||||
help='''path to the directory where the boost libs are,
|
||||
e.g., path/to/boost_1_55_0/stage/lib''')
|
||||
opt.add_option('--boost-mt', action='store_true',
|
||||
default=False, dest='boost_mt',
|
||||
help='select multi-threaded libraries')
|
||||
opt.add_option('--boost-abi', type='string', default='', dest='boost_abi',
|
||||
help='''select libraries with tags (dgsyp, d for debug), see doc Boost, Getting Started, chapter 6.1''')
|
||||
help='''select libraries with tags (gd for debug, static is automatically added),
|
||||
see doc Boost, Getting Started, chapter 6.1''')
|
||||
opt.add_option('--boost-linkage_autodetect', action="store_true", dest='boost_linkage_autodetect',
|
||||
help="auto-detect boost linkage options (don't get used to it / might break other stuff)")
|
||||
opt.add_option('--boost-toolset', type='string',
|
||||
default='', dest='boost_toolset',
|
||||
help='force a toolset e.g. msvc, vc90, gcc, mingw, mgw45 (default: auto)')
|
||||
help='force a toolset e.g. msvc, vc90, \
|
||||
gcc, mingw, mgw45 (default: auto)')
|
||||
py_version = '%d%d' % (sys.version_info[0], sys.version_info[1])
|
||||
opt.add_option('--boost-python', type='string',
|
||||
default=py_version, dest='boost_python',
|
||||
help='select the lib python with this version (default: %s)' % py_version)
|
||||
help='select the lib python with this version \
|
||||
(default: %s)' % py_version)
|
||||
|
||||
|
||||
@conf
|
||||
def __boost_get_version_file(self, d):
|
||||
if not d:
|
||||
return None
|
||||
dnode = self.root.find_dir(d)
|
||||
if dnode:
|
||||
return dnode.find_node(BOOST_VERSION_FILE)
|
||||
@@ -141,18 +175,15 @@ def boost_get_version(self, d):
|
||||
if node:
|
||||
try:
|
||||
txt = node.read()
|
||||
except (OSError, IOError):
|
||||
except EnvironmentError:
|
||||
Logs.error("Could not read the file %r" % node.abspath())
|
||||
else:
|
||||
re_but1 = re.compile('^#define\\s+BOOST_LIB_VERSION\\s+"(.+)"', re.M)
|
||||
m1 = re_but1.search(txt)
|
||||
|
||||
re_but2 = re.compile('^#define\\s+BOOST_VERSION\\s+(\\d+)', re.M)
|
||||
m2 = re_but2.search(txt)
|
||||
|
||||
if m1 and m2:
|
||||
return (m1.group(1), m2.group(1))
|
||||
|
||||
return self.check_cxx(fragment=BOOST_VERSION_CODE, includes=[d], execute=True, define_ret=True).split(":")
|
||||
|
||||
@conf
|
||||
@@ -160,7 +191,7 @@ def boost_get_includes(self, *k, **kw):
|
||||
includes = k and k[0] or kw.get('includes', None)
|
||||
if includes and self.__boost_get_version_file(includes):
|
||||
return includes
|
||||
for d in Utils.to_list(self.environ.get('INCLUDE', '')) + BOOST_INCLUDES:
|
||||
for d in self.environ.get('INCLUDE', '').split(';') + BOOST_INCLUDES:
|
||||
if self.__boost_get_version_file(d):
|
||||
return d
|
||||
if includes:
|
||||
@@ -195,7 +226,9 @@ def __boost_get_libs_path(self, *k, **kw):
|
||||
path = self.root.find_dir(libs)
|
||||
files = path.ant_glob('*boost_*')
|
||||
if not libs or not files:
|
||||
for d in Utils.to_list(self.environ.get('LIB', [])) + BOOST_LIBS:
|
||||
for d in self.environ.get('LIB', '').split(';') + BOOST_LIBS:
|
||||
if not d:
|
||||
continue
|
||||
path = self.root.find_dir(d)
|
||||
if path:
|
||||
files = path.ant_glob('*boost_*')
|
||||
@@ -226,15 +259,10 @@ def boost_get_libs(self, *k, **kw):
|
||||
according to the parameters
|
||||
'''
|
||||
path, files = self.__boost_get_libs_path(**kw)
|
||||
t = []
|
||||
if kw.get('mt', False):
|
||||
t.append('mt')
|
||||
if kw.get('abi', None):
|
||||
t.append(kw['abi'])
|
||||
tags = t and '(-%s)+' % '-'.join(t) or ''
|
||||
files = sorted(files, key=lambda f: (len(f.name), f.name), reverse=True)
|
||||
toolset = self.boost_get_toolset(kw.get('toolset', ''))
|
||||
toolset_pat = '(-%s[0-9]{0,3})+' % toolset
|
||||
version = '(-%s)+' % self.env.BOOST_VERSION
|
||||
toolset_pat = '(-%s[0-9]{0,3})' % toolset
|
||||
version = '-%s' % self.env.BOOST_VERSION
|
||||
|
||||
def find_lib(re_lib, files):
|
||||
for file in files:
|
||||
@@ -248,28 +276,110 @@ def boost_get_libs(self, *k, **kw):
|
||||
name = name[3:]
|
||||
return name[:name.rfind('.')]
|
||||
|
||||
libs = []
|
||||
for lib in Utils.to_list(k and k[0] or kw.get('lib', None)):
|
||||
py = (lib == 'python') and '(-py%s)+' % kw['python'] or ''
|
||||
# Trying libraries, from most strict match to least one
|
||||
for pattern in ['boost_%s%s%s%s%s' % (lib, toolset_pat, tags, py, version),
|
||||
'boost_%s%s%s%s' % (lib, tags, py, version),
|
||||
'boost_%s%s%s' % (lib, tags, version),
|
||||
# Give up trying to find the right version
|
||||
'boost_%s%s%s%s' % (lib, toolset_pat, tags, py),
|
||||
'boost_%s%s%s' % (lib, tags, py),
|
||||
'boost_%s%s' % (lib, tags)]:
|
||||
self.to_log('Trying pattern %s' % pattern)
|
||||
file = find_lib(re.compile(pattern), files)
|
||||
if file:
|
||||
libs.append(format_lib_name(file.name))
|
||||
break
|
||||
else:
|
||||
self.end_msg('lib %s not found in %s' % (lib, path.abspath()))
|
||||
self.fatal('The configuration failed')
|
||||
def match_libs(lib_names, is_static):
|
||||
libs = []
|
||||
lib_names = Utils.to_list(lib_names)
|
||||
if not lib_names:
|
||||
return libs
|
||||
t = []
|
||||
if kw.get('mt', False):
|
||||
t.append('-mt')
|
||||
if kw.get('abi', None):
|
||||
t.append('%s%s' % (is_static and '-s' or '-', kw['abi']))
|
||||
elif is_static:
|
||||
t.append('-s')
|
||||
tags_pat = t and ''.join(t) or ''
|
||||
ext = is_static and self.env.cxxstlib_PATTERN or self.env.cxxshlib_PATTERN
|
||||
ext = ext.partition('%s')[2] # remove '%s' or 'lib%s' from PATTERN
|
||||
|
||||
return path.abspath(), libs
|
||||
for lib in lib_names:
|
||||
if lib == 'python':
|
||||
# for instance, with python='27',
|
||||
# accepts '-py27', '-py2', '27' and '2'
|
||||
# but will reject '-py3', '-py26', '26' and '3'
|
||||
tags = '({0})?((-py{2})|(-py{1}(?=[^0-9]))|({2})|({1}(?=[^0-9]))|(?=[^0-9])(?!-py))'.format(tags_pat, kw['python'][0], kw['python'])
|
||||
else:
|
||||
tags = tags_pat
|
||||
# Trying libraries, from most strict match to least one
|
||||
for pattern in ['boost_%s%s%s%s%s$' % (lib, toolset_pat, tags, version, ext),
|
||||
'boost_%s%s%s%s$' % (lib, tags, version, ext),
|
||||
# Give up trying to find the right version
|
||||
'boost_%s%s%s%s$' % (lib, toolset_pat, tags, ext),
|
||||
'boost_%s%s%s$' % (lib, tags, ext),
|
||||
'boost_%s%s$' % (lib, ext),
|
||||
'boost_%s' % lib]:
|
||||
self.to_log('Trying pattern %s' % pattern)
|
||||
file = find_lib(re.compile(pattern), files)
|
||||
if file:
|
||||
libs.append(format_lib_name(file.name))
|
||||
break
|
||||
else:
|
||||
self.end_msg('lib %s not found in %s' % (lib, path.abspath()))
|
||||
self.fatal('The configuration failed')
|
||||
return libs
|
||||
|
||||
return path.abspath(), match_libs(kw.get('lib', None), False), match_libs(kw.get('stlib', None), True)
|
||||
|
||||
@conf
|
||||
def _check_pthread_flag(self, *k, **kw):
|
||||
'''
|
||||
Computes which flags should be added to CXXFLAGS and LINKFLAGS to compile in multi-threading mode
|
||||
|
||||
Yes, we *need* to put the -pthread thing in CPPFLAGS because with GCC3,
|
||||
boost/thread.hpp will trigger a #error if -pthread isn't used:
|
||||
boost/config/requires_threads.hpp:47:5: #error "Compiler threading support
|
||||
is not turned on. Please set the correct command line options for
|
||||
threading: -pthread (Linux), -pthreads (Solaris) or -mthreads (Mingw32)"
|
||||
|
||||
Based on _BOOST_PTHREAD_FLAG(): https://github.com/tsuna/boost.m4/blob/master/build-aux/boost.m4
|
||||
'''
|
||||
|
||||
var = kw.get('uselib_store', 'BOOST')
|
||||
|
||||
self.start_msg('Checking the flags needed to use pthreads')
|
||||
|
||||
# The ordering *is* (sometimes) important. Some notes on the
|
||||
# individual items follow:
|
||||
# (none): in case threads are in libc; should be tried before -Kthread and
|
||||
# other compiler flags to prevent continual compiler warnings
|
||||
# -lpthreads: AIX (must check this before -lpthread)
|
||||
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# -llthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
# -pthread: GNU Linux/GCC (kernel threads), BSD/GCC (userland threads)
|
||||
# -pthreads: Solaris/GCC
|
||||
# -mthreads: MinGW32/GCC, Lynx/GCC
|
||||
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
||||
# doesn't hurt to check since this sometimes defines pthreads too;
|
||||
# also defines -D_REENTRANT)
|
||||
# ... -mt is also the pthreads flag for HP/aCC
|
||||
# -lpthread: GNU Linux, etc.
|
||||
# --thread-safe: KAI C++
|
||||
if Utils.unversioned_sys_platform() == "sunos":
|
||||
# On Solaris (at least, for some versions), libc contains stubbed
|
||||
# (non-functional) versions of the pthreads routines, so link-based
|
||||
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
|
||||
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
|
||||
# a function called by this macro, so we could check for that, but
|
||||
# who knows whether they'll stub that too in a future libc.) So,
|
||||
# we'll just look for -pthreads and -lpthread first:
|
||||
boost_pthread_flags = ["-pthreads", "-lpthread", "-mt", "-pthread"]
|
||||
else:
|
||||
boost_pthread_flags = ["", "-lpthreads", "-Kthread", "-kthread", "-llthread", "-pthread",
|
||||
"-pthreads", "-mthreads", "-lpthread", "--thread-safe", "-mt"]
|
||||
|
||||
for boost_pthread_flag in boost_pthread_flags:
|
||||
try:
|
||||
self.env.stash()
|
||||
self.env['CXXFLAGS_%s' % var] += [boost_pthread_flag]
|
||||
self.env['LINKFLAGS_%s' % var] += [boost_pthread_flag]
|
||||
self.check_cxx(code=PTHREAD_CODE, msg=None, use=var, execute=False)
|
||||
|
||||
self.end_msg(boost_pthread_flag)
|
||||
return
|
||||
except self.errors.ConfigurationError:
|
||||
self.env.revert()
|
||||
self.end_msg('None')
|
||||
|
||||
@conf
|
||||
def check_boost(self, *k, **kw):
|
||||
@@ -282,7 +392,10 @@ def check_boost(self, *k, **kw):
|
||||
if not self.env['CXX']:
|
||||
self.fatal('load a c++ compiler first, conf.load("compiler_cxx")')
|
||||
|
||||
params = {'lib': k and k[0] or kw.get('lib', None)}
|
||||
params = {
|
||||
'lib': k and k[0] or kw.get('lib', None),
|
||||
'stlib': kw.get('stlib', None)
|
||||
}
|
||||
for key, value in self.options.__dict__.items():
|
||||
if not key.startswith('boost_'):
|
||||
continue
|
||||
@@ -297,42 +410,53 @@ def check_boost(self, *k, **kw):
|
||||
self.env.BOOST_VERSION = versions[0]
|
||||
self.env.BOOST_VERSION_NUMBER = int(versions[1])
|
||||
self.end_msg("%d.%d.%d" % (int(versions[1]) / 100000,
|
||||
int(versions[1]) / 100 % 1000,
|
||||
int(versions[1]) % 100))
|
||||
int(versions[1]) / 100 % 1000,
|
||||
int(versions[1]) % 100))
|
||||
if Logs.verbose:
|
||||
Logs.pprint('CYAN', ' path : %s' % self.env['INCLUDES_%s' % var])
|
||||
|
||||
if not params['lib']:
|
||||
if not params['lib'] and not params['stlib']:
|
||||
return
|
||||
if 'static' in kw or 'static' in params:
|
||||
Logs.warn('boost: static parameter is deprecated, use stlib instead.')
|
||||
self.start_msg('Checking boost libs')
|
||||
suffix = params.get('static', None) and 'ST' or ''
|
||||
path, libs = self.boost_get_libs(**params)
|
||||
self.env['%sLIBPATH_%s' % (suffix, var)] = [path]
|
||||
self.env['%sLIB_%s' % (suffix, var)] = libs
|
||||
path, libs, stlibs = self.boost_get_libs(**params)
|
||||
self.env['LIBPATH_%s' % var] = [path]
|
||||
self.env['STLIBPATH_%s' % var] = [path]
|
||||
self.env['LIB_%s' % var] = libs
|
||||
self.env['STLIB_%s' % var] = stlibs
|
||||
self.end_msg('ok')
|
||||
if Logs.verbose:
|
||||
Logs.pprint('CYAN', ' path : %s' % path)
|
||||
Logs.pprint('CYAN', ' libs : %s' % libs)
|
||||
Logs.pprint('CYAN', ' shared libs : %s' % libs)
|
||||
Logs.pprint('CYAN', ' static libs : %s' % stlibs)
|
||||
|
||||
def has_shlib(lib):
|
||||
return params['lib'] and lib in params['lib']
|
||||
def has_stlib(lib):
|
||||
return params['stlib'] and lib in params['stlib']
|
||||
def has_lib(lib):
|
||||
return has_shlib(lib) or has_stlib(lib)
|
||||
if has_lib('thread'):
|
||||
# not inside try_link to make check visible in the output
|
||||
self._check_pthread_flag(k, kw)
|
||||
|
||||
def try_link():
|
||||
if 'system' in params['lib']:
|
||||
self.check_cxx(
|
||||
fragment=BOOST_SYSTEM_CODE,
|
||||
use=var,
|
||||
execute=False,
|
||||
)
|
||||
if 'thread' in params['lib']:
|
||||
self.check_cxx(
|
||||
fragment=BOOST_THREAD_CODE,
|
||||
use=var,
|
||||
execute=False,
|
||||
)
|
||||
if has_lib('system'):
|
||||
self.check_cxx(fragment=BOOST_ERROR_CODE, use=var, execute=False)
|
||||
if has_lib('thread'):
|
||||
self.check_cxx(fragment=BOOST_THREAD_CODE, use=var, execute=False)
|
||||
if has_lib('log'):
|
||||
if not has_lib('thread'):
|
||||
self.env['DEFINES_%s' % var] += ['BOOST_LOG_NO_THREADS']
|
||||
if has_shlib('log'):
|
||||
self.env['DEFINES_%s' % var] += ['BOOST_LOG_DYN_LINK']
|
||||
self.check_cxx(fragment=BOOST_LOG_CODE, use=var, execute=False)
|
||||
|
||||
if params.get('linkage_autodetect', False):
|
||||
self.start_msg("Attempting to detect boost linkage flags")
|
||||
toolset = self.boost_get_toolset(kw.get('toolset', ''))
|
||||
if toolset in ['vc']:
|
||||
if toolset in ('vc',):
|
||||
# disable auto-linking feature, causing error LNK1181
|
||||
# because the code wants to be linked against
|
||||
self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB']
|
||||
@@ -356,14 +480,14 @@ def check_boost(self, *k, **kw):
|
||||
try:
|
||||
try_link()
|
||||
self.end_msg("ok: winning cxxflags combination: %s" % (self.env["CXXFLAGS_%s" % var]))
|
||||
e = None
|
||||
exc = None
|
||||
break
|
||||
except Errors.ConfigurationError as exc:
|
||||
except Errors.ConfigurationError as e:
|
||||
self.env.revert()
|
||||
e = exc
|
||||
exc = e
|
||||
|
||||
if e is not None:
|
||||
self.end_msg("Could not auto-detect boost linking flags combination, you may report it to boost.py author", ex=e)
|
||||
if exc is not None:
|
||||
self.end_msg("Could not auto-detect boost linking flags combination, you may report it to boost.py author", ex=exc)
|
||||
self.fatal('The configuration failed')
|
||||
else:
|
||||
self.end_msg("Boost linkage flags auto-detection not implemented (needed ?) for this toolchain")
|
||||
@@ -376,3 +500,19 @@ def check_boost(self, *k, **kw):
|
||||
self.end_msg("Could not link against boost libraries using supplied options")
|
||||
self.fatal('The configuration failed')
|
||||
self.end_msg('ok')
|
||||
|
||||
|
||||
@feature('cxx')
|
||||
@after_method('apply_link')
|
||||
def install_boost(self):
|
||||
if install_boost.done or not Utils.is_win32 or not self.bld.cmd.startswith('install'):
|
||||
return
|
||||
install_boost.done = True
|
||||
inst_to = getattr(self, 'install_path', '${BINDIR}')
|
||||
for lib in self.env.LIB_BOOST:
|
||||
try:
|
||||
file = self.bld.find_file(self.env.cxxshlib_PATTERN % lib, self.env.LIBPATH_BOOST)
|
||||
self.bld.install_files(inst_to, self.bld.root.find_node(file))
|
||||
except:
|
||||
continue
|
||||
install_boost.done = False
|
||||
@@ -1,10 +1,6 @@
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
#
|
||||
# Copyright (c) 2014, Regents of the University of California
|
||||
#
|
||||
# GPL 3.0 license, see the COPYING.md file for more information
|
||||
|
||||
from waflib import TaskGen
|
||||
from waflib import TaskGen, Logs
|
||||
|
||||
def options(opt):
|
||||
opt.add_option('--with-coverage', action='store_true', default=False, dest='with_coverage',
|
||||
@@ -12,6 +8,8 @@ def options(opt):
|
||||
|
||||
def configure(conf):
|
||||
if conf.options.with_coverage:
|
||||
if not conf.options.debug:
|
||||
conf.fatal("Code coverage flags require debug mode compilation (add --debug)")
|
||||
conf.check_cxx(cxxflags=['-fprofile-arcs', '-ftest-coverage', '-fPIC'],
|
||||
linkflags=['-fprofile-arcs'], uselib_store='GCOV', mandatory=True)
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ def configure(conf):
|
||||
|
||||
if not areCustomCxxflagsPresent:
|
||||
conf.add_supported_cxxflags(extraFlags['CXXFLAGS'])
|
||||
conf.add_supported_cxxflags(extraFlags['LINKFLAGS'])
|
||||
conf.add_supported_linkflags(extraFlags['LINKFLAGS'])
|
||||
|
||||
conf.env.DEFINES += extraFlags['DEFINES']
|
||||
|
||||
@@ -83,15 +83,15 @@ def add_supported_linkflags(self, linkflags):
|
||||
|
||||
class CompilerFlags(object):
|
||||
def getGeneralFlags(self, conf):
|
||||
"""Get dict {'CXXFLAGS':[...], LINKFLAGS:[...], DEFINES:[...]} that are always needed"""
|
||||
"""Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are always needed"""
|
||||
return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': []}
|
||||
|
||||
def getDebugFlags(self, conf):
|
||||
"""Get tuple {CXXFLAGS, LINKFLAGS, DEFINES} that are needed in debug mode"""
|
||||
"""Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are needed only in debug mode"""
|
||||
return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': ['_DEBUG']}
|
||||
|
||||
def getOptimizedFlags(self, conf):
|
||||
"""Get tuple {CXXFLAGS, LINKFLAGS, DEFINES} that are needed in optimized mode"""
|
||||
"""Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are needed only in optimized mode"""
|
||||
return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': ['NDEBUG']}
|
||||
|
||||
class GccBasicFlags(CompilerFlags):
|
||||
@@ -100,21 +100,25 @@ class GccBasicFlags(CompilerFlags):
|
||||
"""
|
||||
def getDebugFlags(self, conf):
|
||||
flags = super(GccBasicFlags, self).getDebugFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-pedantic',
|
||||
'-Wall',
|
||||
'-O0',
|
||||
flags['CXXFLAGS'] += ['-O0',
|
||||
'-g3',
|
||||
'-pedantic',
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-Werror',
|
||||
'-Wno-unused-parameter',
|
||||
'-Wno-error=maybe-uninitialized', # Bug #1615
|
||||
]
|
||||
return flags
|
||||
|
||||
def getOptimizedFlags(self, conf):
|
||||
flags = super(GccBasicFlags, self).getOptimizedFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-pedantic',
|
||||
'-Wall',
|
||||
'-O2',
|
||||
flags['CXXFLAGS'] += ['-O2',
|
||||
'-g',
|
||||
'-pedantic',
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-Wno-unused-parameter',
|
||||
]
|
||||
return flags
|
||||
|
||||
@@ -136,6 +140,9 @@ class GccFlags(GccBasicFlags):
|
||||
|
||||
def getDebugFlags(self, conf):
|
||||
flags = super(GccFlags, self).getDebugFlags(conf)
|
||||
version = tuple(int(i) for i in conf.env['CC_VERSION'])
|
||||
if version < (5, 1, 0):
|
||||
flags['CXXFLAGS'] += ['-Wno-missing-field-initializers']
|
||||
flags['CXXFLAGS'] += ['-Og', # gcc >= 4.8
|
||||
'-fdiagnostics-color', # gcc >= 4.9
|
||||
]
|
||||
@@ -143,6 +150,9 @@ class GccFlags(GccBasicFlags):
|
||||
|
||||
def getOptimizedFlags(self, conf):
|
||||
flags = super(GccFlags, self).getOptimizedFlags(conf)
|
||||
version = tuple(int(i) for i in conf.env['CC_VERSION'])
|
||||
if version < (5, 1, 0):
|
||||
flags['CXXFLAGS'] += ['-Wno-missing-field-initializers']
|
||||
flags['CXXFLAGS'] += ['-fdiagnostics-color'] # gcc >= 4.9
|
||||
return flags
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ class doxygen(Task.Task):
|
||||
|
||||
# Override with any parameters passed to the task generator
|
||||
if getattr(self.generator, 'pars', None):
|
||||
for k, v in self.generator.pars.iteritems():
|
||||
for k, v in self.generator.pars.items():
|
||||
self.pars[k] = v
|
||||
|
||||
self.doxy_inputs = getattr(self, 'doxy_inputs', [])
|
||||
|
||||
@@ -77,3 +77,6 @@ in the library:
|
||||
* Yukai Tu <tuyukai1994@gmail.com>
|
||||
* João Pereira <http://website.jpereira.co.uk>
|
||||
* Mathias Gibbens <gibmat@cs.arizona.edu>
|
||||
* Yanbiao Li <https://www.linkedin.com/pub/yanbiao-li/24/7a1/4ba>
|
||||
* Weiwei Liu <https://www.linkedin.com/in/weiweiliu10>
|
||||
* Spencer Lee <https://www.linkedin.com/in/spenlee>
|
||||
+30
@@ -1,3 +1,33 @@
|
||||
NFD is licensed under conditions of GNU General Public License version 3 or later.
|
||||
|
||||
NFD relies on third-party software and libraries, licensed under the following licenses:
|
||||
|
||||
- ndn-cxx library is licensed under conditions of
|
||||
[GNU Lesser General Public License version 3](https://github.com/named-data/ndn-cxx/blob/master/COPYING.md).
|
||||
|
||||
- Boost libraries licensed under conditions of
|
||||
[Boost Software License 1.0](http://www.boost.org/users/license.html)
|
||||
|
||||
- CryptoPP library is licensed under conditions of
|
||||
[Boost Software License 1.0](http://www.boost.org/users/license.html)
|
||||
|
||||
- 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)
|
||||
|
||||
- Libpcap library licensed under conditions of
|
||||
[a 3-clause BSD license](http://www.tcpdump.org/license.html).
|
||||
|
||||
- waf build system is licensed under conditions of
|
||||
[BSD license](https://github.com/named-data/ndn-cxx/blob/master/waf)
|
||||
|
||||
The GPL license is provided below in this file. For more information about these licenses, see
|
||||
http://www.gnu.org/licenses/
|
||||
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
==========================
|
||||
Version 3, 29 June 2007
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
docs/release-notes/release-notes-0.4.0.rst
|
||||
docs/release-notes-latest.rst
|
||||
@@ -0,0 +1,3 @@
|
||||
# Enable ndn-autoconfig to run in parallel with NFD. Disabled by default
|
||||
# enabled=true
|
||||
enabled=false
|
||||
@@ -0,0 +1,141 @@
|
||||
/* -*- 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_COUNTER_HPP
|
||||
#define NFD_CORE_COUNTER_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/** \brief represents a counter that encloses an integer value
|
||||
*
|
||||
* SimpleCounter is noncopyable, because increment should be called on the counter,
|
||||
* not a copy of it; it's implicitly convertible to an integral type to be observed
|
||||
*/
|
||||
class SimpleCounter
|
||||
{
|
||||
public:
|
||||
typedef uint64_t rep;
|
||||
|
||||
constexpr
|
||||
SimpleCounter()
|
||||
: m_value(0)
|
||||
{
|
||||
}
|
||||
|
||||
SimpleCounter(const SimpleCounter&) = delete;
|
||||
|
||||
SimpleCounter&
|
||||
operator=(const SimpleCounter&) = delete;
|
||||
|
||||
/** \brief observe the counter
|
||||
*/
|
||||
operator rep() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
/** \brief replace the counter value
|
||||
*/
|
||||
void
|
||||
set(rep value)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
protected:
|
||||
rep m_value;
|
||||
};
|
||||
|
||||
/** \brief represents a counter of number of packets
|
||||
*
|
||||
* \warning The counter value may wrap after exceeding the range of underlying integer type.
|
||||
*/
|
||||
class PacketCounter : public SimpleCounter
|
||||
{
|
||||
public:
|
||||
/** \brief increment the counter by one
|
||||
*/
|
||||
PacketCounter&
|
||||
operator++()
|
||||
{
|
||||
++m_value;
|
||||
return *this;
|
||||
}
|
||||
// postfix ++ operator is not provided because it's not needed
|
||||
};
|
||||
|
||||
/** \brief represents a counter of number of bytes
|
||||
*
|
||||
* \warning The counter value may wrap after exceeding the range of underlying integer type.
|
||||
*/
|
||||
class ByteCounter : public SimpleCounter
|
||||
{
|
||||
public:
|
||||
/** \brief increase the counter
|
||||
*/
|
||||
ByteCounter&
|
||||
operator+=(rep n)
|
||||
{
|
||||
m_value += n;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/** \brief provides a counter that observes the size of a table
|
||||
* \tparam T a type that provides a size() const member function
|
||||
*/
|
||||
template<typename T>
|
||||
class SizeCounter
|
||||
{
|
||||
public:
|
||||
typedef size_t rep;
|
||||
|
||||
constexpr
|
||||
SizeCounter(const T& table)
|
||||
: m_table(table)
|
||||
{
|
||||
}
|
||||
|
||||
SizeCounter(const SizeCounter&) = delete;
|
||||
|
||||
SizeCounter&
|
||||
operator=(const SizeCounter&) = delete;
|
||||
|
||||
/** \brief observe the counter
|
||||
*/
|
||||
operator rep() const
|
||||
{
|
||||
return m_table.size();
|
||||
}
|
||||
|
||||
private:
|
||||
const T& m_table;
|
||||
};
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_CORE_COUNTER_HPP
|
||||
+21
-7
@@ -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-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.
|
||||
@@ -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/>.
|
||||
**/
|
||||
*/
|
||||
|
||||
#include "channel.hpp"
|
||||
|
||||
@@ -36,4 +37,17 @@ Channel::setUri(const FaceUri& uri)
|
||||
m_uri = uri;
|
||||
}
|
||||
|
||||
void
|
||||
connectFaceClosedSignal(Face& face, const std::function<void()>& f)
|
||||
{
|
||||
using face::FaceState;
|
||||
|
||||
face.afterStateChange.connect(
|
||||
[f] (FaceState oldState, FaceState newState) {
|
||||
if (newState == FaceState::CLOSED) {
|
||||
f();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
+32
-20
@@ -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-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.
|
||||
@@ -20,31 +21,32 @@
|
||||
*
|
||||
* 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_CHANNEL_HPP
|
||||
#define NFD_DAEMON_FACE_CHANNEL_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "face.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
class Face;
|
||||
/**
|
||||
* \brief Prototype for the callback that is invoked when the face
|
||||
* is created (as a response to incoming connection or after
|
||||
* connection is established)
|
||||
*/
|
||||
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;
|
||||
|
||||
|
||||
class Channel : noncopyable
|
||||
{
|
||||
public:
|
||||
/** \brief Prototype for the callback called when face is created
|
||||
* (as a response to incoming connection or after connection
|
||||
* is established)
|
||||
*/
|
||||
typedef function<void(const shared_ptr<Face>& newFace)> FaceCreatedCallback;
|
||||
|
||||
/** \brief Prototype for the callback that is called when face is failed to
|
||||
* get created
|
||||
*/
|
||||
typedef function<void(const std::string& reason)> ConnectFailedCallback;
|
||||
|
||||
virtual
|
||||
~Channel();
|
||||
|
||||
@@ -65,6 +67,16 @@ Channel::getUri() const
|
||||
return m_uri;
|
||||
}
|
||||
|
||||
/** \brief invokes a callback when the face is closed
|
||||
* \param face the face
|
||||
* \param f the callback to be invoked when the face enters CLOSED state
|
||||
*
|
||||
* This function connects a callback to the afterStateChange signal on the \p face,
|
||||
* and invokes \p f when the state becomes CLOSED.
|
||||
*/
|
||||
void
|
||||
connectFaceClosedSignal(Face& face, const std::function<void()>& f);
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_CHANNEL_HPP
|
||||
@@ -54,12 +54,6 @@ public:
|
||||
explicit
|
||||
DatagramTransport(typename protocol::socket&& socket);
|
||||
|
||||
virtual void
|
||||
doSend(Transport::Packet&& packet) DECL_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
doClose() DECL_OVERRIDE;
|
||||
|
||||
/** \brief Receive datagram, translate buffer into packet, deliver to parent class.
|
||||
*/
|
||||
void
|
||||
@@ -67,14 +61,20 @@ public:
|
||||
const boost::system::error_code& error);
|
||||
|
||||
protected:
|
||||
void
|
||||
handleReceive(const boost::system::error_code& error,
|
||||
size_t nBytesReceived);
|
||||
virtual void
|
||||
doClose() DECL_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
doSend(Transport::Packet&& packet) DECL_OVERRIDE;
|
||||
|
||||
void
|
||||
handleSend(const boost::system::error_code& error,
|
||||
size_t nBytesSent, const Block& payload);
|
||||
|
||||
void
|
||||
handleReceive(const boost::system::error_code& error,
|
||||
size_t nBytesReceived);
|
||||
|
||||
void
|
||||
processErrorCode(const boost::system::error_code& error);
|
||||
|
||||
@@ -84,8 +84,12 @@ protected:
|
||||
void
|
||||
resetRecentUsage();
|
||||
|
||||
static EndpointId
|
||||
makeEndpointId(const typename protocol::endpoint& ep);
|
||||
|
||||
protected:
|
||||
typename protocol::socket m_socket;
|
||||
typename protocol::endpoint m_sender;
|
||||
|
||||
NFD_LOG_INCLASS_DECLARE();
|
||||
|
||||
@@ -96,31 +100,18 @@ private:
|
||||
|
||||
|
||||
template<class T, class U>
|
||||
inline
|
||||
DatagramTransport<T, U>::DatagramTransport(typename DatagramTransport::protocol::socket&& socket)
|
||||
: m_socket(std::move(socket))
|
||||
, m_hasBeenUsedRecently(false)
|
||||
{
|
||||
m_socket.async_receive(boost::asio::buffer(m_receiveBuffer),
|
||||
bind(&DatagramTransport<T, U>::handleReceive, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
m_socket.async_receive_from(boost::asio::buffer(m_receiveBuffer), m_sender,
|
||||
bind(&DatagramTransport<T, U>::handleReceive, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
DatagramTransport<T, U>::doSend(Transport::Packet&& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
m_socket.async_send(boost::asio::buffer(packet.packet),
|
||||
bind(&DatagramTransport<T, U>::handleSend, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred,
|
||||
packet.packet));
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
void
|
||||
DatagramTransport<T, U>::doClose()
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
@@ -141,7 +132,20 @@ DatagramTransport<T, U>::doClose()
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
void
|
||||
DatagramTransport<T, U>::doSend(Transport::Packet&& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
m_socket.async_send(boost::asio::buffer(packet.packet),
|
||||
bind(&DatagramTransport<T, U>::handleSend, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred,
|
||||
packet.packet));
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
void
|
||||
DatagramTransport<T, U>::receiveDatagram(const uint8_t* buffer, size_t nBytesReceived,
|
||||
const boost::system::error_code& error)
|
||||
{
|
||||
@@ -163,27 +167,29 @@ DatagramTransport<T, U>::receiveDatagram(const uint8_t* buffer, size_t nBytesRec
|
||||
// This packet won't extend the face lifetime
|
||||
return;
|
||||
}
|
||||
|
||||
m_hasBeenUsedRecently = true;
|
||||
this->receive(Transport::Packet(std::move(element)));
|
||||
|
||||
Transport::Packet tp(std::move(element));
|
||||
tp.remoteEndpoint = makeEndpointId(m_sender);
|
||||
this->receive(std::move(tp));
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
void
|
||||
DatagramTransport<T, U>::handleReceive(const boost::system::error_code& error,
|
||||
size_t nBytesReceived)
|
||||
{
|
||||
receiveDatagram(m_receiveBuffer.data(), nBytesReceived, error);
|
||||
|
||||
if (m_socket.is_open())
|
||||
m_socket.async_receive(boost::asio::buffer(m_receiveBuffer),
|
||||
bind(&DatagramTransport<T, U>::handleReceive, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
m_socket.async_receive_from(boost::asio::buffer(m_receiveBuffer), m_sender,
|
||||
bind(&DatagramTransport<T, U>::handleReceive, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
void
|
||||
DatagramTransport<T, U>::handleSend(const boost::system::error_code& error,
|
||||
size_t nBytesSent, const Block& payload)
|
||||
// 'payload' is unused; it's needed to retain the underlying Buffer
|
||||
@@ -195,7 +201,7 @@ DatagramTransport<T, U>::handleSend(const boost::system::error_code& error,
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
void
|
||||
DatagramTransport<T, U>::processErrorCode(const boost::system::error_code& error)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
@@ -233,6 +239,13 @@ DatagramTransport<T, U>::resetRecentUsage()
|
||||
m_hasBeenUsedRecently = false;
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline Transport::EndpointId
|
||||
DatagramTransport<T, U>::makeEndpointId(const typename protocol::endpoint& ep)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
|
||||
@@ -24,16 +24,14 @@
|
||||
*/
|
||||
|
||||
#include "ethernet-factory.hpp"
|
||||
#include "face/ethernet-face.hpp"
|
||||
|
||||
#include "core/logger.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
#include "ethernet-transport.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
shared_ptr<EthernetFace>
|
||||
shared_ptr<Face>
|
||||
EthernetFactory::createMulticastFace(const NetworkInterfaceInfo& interface,
|
||||
const ethernet::Address &address)
|
||||
const ethernet::Address& address)
|
||||
{
|
||||
if (!address.isMulticast())
|
||||
BOOST_THROW_EXCEPTION(Error(address.toString() + " is not a multicast address"));
|
||||
@@ -42,14 +40,17 @@ EthernetFactory::createMulticastFace(const NetworkInterfaceInfo& interface,
|
||||
if (face)
|
||||
return face;
|
||||
|
||||
face = make_shared<EthernetFace>(boost::asio::posix::stream_descriptor(getGlobalIoService()),
|
||||
interface, address);
|
||||
face::GenericLinkService::Options opts;
|
||||
opts.allowFragmentation = true;
|
||||
opts.allowReassembly = true;
|
||||
|
||||
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));
|
||||
|
||||
auto key = std::make_pair(interface.name, address);
|
||||
face->onFail.connectSingleShot([this, key] (const std::string& reason) {
|
||||
m_multicastFaces.erase(key);
|
||||
});
|
||||
m_multicastFaces[key] = face;
|
||||
connectFaceClosedSignal(*face, [this, key] { m_multicastFaces.erase(key); });
|
||||
|
||||
return face;
|
||||
}
|
||||
@@ -69,7 +70,7 @@ EthernetFactory::getChannels() const
|
||||
return {};
|
||||
}
|
||||
|
||||
shared_ptr<EthernetFace>
|
||||
shared_ptr<Face>
|
||||
EthernetFactory::findMulticastFace(const std::string& interfaceName,
|
||||
const ethernet::Address& address) const
|
||||
{
|
||||
|
||||
@@ -31,8 +31,6 @@
|
||||
|
||||
namespace nfd {
|
||||
|
||||
class EthernetFace;
|
||||
|
||||
class EthernetFactory : public ProtocolFactory
|
||||
{
|
||||
public:
|
||||
@@ -50,7 +48,7 @@ public:
|
||||
};
|
||||
|
||||
typedef std::map<std::pair<std::string, ethernet::Address>,
|
||||
shared_ptr<EthernetFace>> MulticastFaceMap;
|
||||
shared_ptr<Face>> MulticastFaceMap;
|
||||
|
||||
/**
|
||||
* \brief Create an EthernetFace to communicate with the given multicast group
|
||||
@@ -65,9 +63,9 @@ public:
|
||||
* \returns always a valid shared pointer to an EthernetFace object,
|
||||
* an exception will be thrown if the creation fails
|
||||
*
|
||||
* \throws EthernetFactory::Error or EthernetFace::Error
|
||||
* \throws EthernetFactory::Error or EthernetTransport::Error
|
||||
*/
|
||||
shared_ptr<EthernetFace>
|
||||
shared_ptr<Face>
|
||||
createMulticastFace(const NetworkInterfaceInfo& interface,
|
||||
const ethernet::Address& address);
|
||||
|
||||
@@ -94,7 +92,7 @@ private:
|
||||
* \returns shared pointer to the existing EthernetFace object
|
||||
* or nullptr when such face does not exist
|
||||
*/
|
||||
shared_ptr<EthernetFace>
|
||||
shared_ptr<Face>
|
||||
findMulticastFace(const std::string& interfaceName,
|
||||
const ethernet::Address& address) const;
|
||||
|
||||
|
||||
@@ -23,17 +23,17 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ethernet-face.hpp"
|
||||
#include "ethernet-transport.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
|
||||
#include <pcap/pcap.h>
|
||||
|
||||
#include <cerrno> // for errno
|
||||
#include <cstring> // for std::strerror() and std::strncpy()
|
||||
#include <stdio.h> // for snprintf()
|
||||
#include <cstring> // for memcpy(), strerror(), strncpy()
|
||||
#include <arpa/inet.h> // for htons() and ntohs()
|
||||
#include <net/ethernet.h> // for struct ether_header
|
||||
#include <net/if.h> // for struct ifreq
|
||||
#include <stdio.h> // for snprintf()
|
||||
#include <sys/ioctl.h> // for ioctl()
|
||||
#include <unistd.h> // for dup()
|
||||
|
||||
@@ -57,28 +57,32 @@
|
||||
#endif
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INIT("EthernetFace");
|
||||
NFD_LOG_INIT("EthernetTransport");
|
||||
|
||||
const time::nanoseconds EthernetFace::REASSEMBLER_LIFETIME = time::seconds(60);
|
||||
|
||||
EthernetFace::EthernetFace(boost::asio::posix::stream_descriptor socket,
|
||||
const NetworkInterfaceInfo& interface,
|
||||
const ethernet::Address& address)
|
||||
: Face(FaceUri(address), FaceUri::fromDev(interface.name), false, true)
|
||||
, m_pcap(nullptr, pcap_close)
|
||||
, m_socket(std::move(socket))
|
||||
EthernetTransport::EthernetTransport(const NetworkInterfaceInfo& interface,
|
||||
const ethernet::Address& mcastAddress)
|
||||
: m_pcap(nullptr, pcap_close)
|
||||
, m_socket(getGlobalIoService())
|
||||
, m_srcAddress(interface.etherAddress)
|
||||
, m_destAddress(mcastAddress)
|
||||
, m_interfaceName(interface.name)
|
||||
#if defined(__linux__)
|
||||
, m_interfaceIndex(interface.index)
|
||||
#endif
|
||||
, m_interfaceName(interface.name)
|
||||
, m_srcAddress(interface.etherAddress)
|
||||
, m_destAddress(address)
|
||||
#ifdef _DEBUG
|
||||
, m_nDropped(0)
|
||||
#endif
|
||||
{
|
||||
NFD_LOG_FACE_INFO("Creating face on " << m_interfaceName << "/" << m_srcAddress);
|
||||
this->setLocalUri(FaceUri::fromDev(interface.name));
|
||||
this->setRemoteUri(FaceUri(mcastAddress));
|
||||
this->setScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
|
||||
this->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
|
||||
this->setLinkType(ndn::nfd::LINK_TYPE_MULTI_ACCESS);
|
||||
|
||||
NFD_LOG_FACE_INFO("Creating transport");
|
||||
|
||||
pcapInit();
|
||||
|
||||
int fd = pcap_get_selectable_fd(m_pcap.get());
|
||||
@@ -90,77 +94,69 @@ EthernetFace::EthernetFace(boost::asio::posix::stream_descriptor socket,
|
||||
// same fd and one of them will fail
|
||||
m_socket.assign(::dup(fd));
|
||||
|
||||
m_interfaceMtu = getInterfaceMtu();
|
||||
NFD_LOG_FACE_DEBUG("Interface MTU is: " << m_interfaceMtu);
|
||||
// do this after assigning m_socket because getInterfaceMtu uses it
|
||||
this->setMtu(getInterfaceMtu());
|
||||
|
||||
m_slicer.reset(new ndnlp::Slicer(m_interfaceMtu));
|
||||
|
||||
char filter[100];
|
||||
// std::snprintf not found in some environments
|
||||
// http://redmine.named-data.net/issues/2299 for more information
|
||||
char filter[110];
|
||||
// note #1: we cannot use std::snprintf because it's not available
|
||||
// on some platforms (see #2299)
|
||||
// note #2: "not vlan" must appear last in the filter expression, or the
|
||||
// rest of the filter won't work as intended (see pcap-filter(7))
|
||||
snprintf(filter, sizeof(filter),
|
||||
"(ether proto 0x%x) && (ether dst %s) && (not ether src %s)",
|
||||
"(ether proto 0x%x) && (ether dst %s) && (not ether src %s) && (not vlan)",
|
||||
ethernet::ETHERTYPE_NDN,
|
||||
m_destAddress.toString().c_str(),
|
||||
m_srcAddress.toString().c_str());
|
||||
setPacketFilter(filter);
|
||||
|
||||
if (!m_destAddress.isBroadcast() && !joinMulticastGroup())
|
||||
{
|
||||
NFD_LOG_FACE_WARN("Falling back to promiscuous mode");
|
||||
pcap_set_promisc(m_pcap.get(), 1);
|
||||
}
|
||||
if (!m_destAddress.isBroadcast() && !joinMulticastGroup()) {
|
||||
NFD_LOG_FACE_WARN("Falling back to promiscuous mode");
|
||||
pcap_set_promisc(m_pcap.get(), 1);
|
||||
}
|
||||
|
||||
m_socket.async_read_some(boost::asio::null_buffers(),
|
||||
bind(&EthernetFace::handleRead, this,
|
||||
bind(&EthernetTransport::handleRead, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::sendInterest(const Interest& interest)
|
||||
void EthernetTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
this->emitSignal(onSendInterest, interest);
|
||||
|
||||
ndnlp::PacketArray pa = m_slicer->slice(interest.wireEncode());
|
||||
for (const auto& packet : *pa) {
|
||||
sendPacket(packet);
|
||||
if (newPersistency != ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
|
||||
BOOST_THROW_EXCEPTION(
|
||||
std::invalid_argument("EthernetTransport supports only FACE_PERSISTENCY_PERMANENT"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::sendData(const Data& data)
|
||||
void EthernetTransport::doSend(Transport::Packet&& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
this->emitSignal(onSendData, data);
|
||||
|
||||
ndnlp::PacketArray pa = m_slicer->slice(data.wireEncode());
|
||||
for (const auto& packet : *pa) {
|
||||
sendPacket(packet);
|
||||
}
|
||||
sendPacket(packet.packet);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::close()
|
||||
void EthernetTransport::doClose()
|
||||
{
|
||||
if (!m_pcap)
|
||||
return;
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
NFD_LOG_FACE_INFO("Closing face");
|
||||
|
||||
boost::system::error_code error;
|
||||
m_socket.cancel(error); // ignore errors
|
||||
m_socket.close(error); // ignore errors
|
||||
if (m_socket.is_open()) {
|
||||
// Cancel all outstanding operations and close the socket.
|
||||
// Use the non-throwing variants and ignore errors, if any.
|
||||
boost::system::error_code error;
|
||||
m_socket.cancel(error);
|
||||
m_socket.close(error);
|
||||
}
|
||||
m_pcap.reset();
|
||||
|
||||
fail("Face closed");
|
||||
// Ensure that the Transport stays alive at least
|
||||
// until all pending handlers are dispatched
|
||||
getGlobalIoService().post([this] {
|
||||
this->setState(TransportState::CLOSED);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::pcapInit()
|
||||
EthernetTransport::pcapInit()
|
||||
{
|
||||
char errbuf[PCAP_ERRBUF_SIZE] = {};
|
||||
m_pcap.reset(pcap_create(m_interfaceName.c_str(), errbuf));
|
||||
@@ -187,7 +183,7 @@ EthernetFace::pcapInit()
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::setPacketFilter(const char* filterString)
|
||||
EthernetTransport::setPacketFilter(const char* filterString)
|
||||
{
|
||||
bpf_program filter;
|
||||
if (pcap_compile(m_pcap.get(), &filter, filterString, 1, PCAP_NETMASK_UNKNOWN) < 0)
|
||||
@@ -200,14 +196,14 @@ EthernetFace::setPacketFilter(const char* filterString)
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetFace::joinMulticastGroup()
|
||||
EthernetTransport::joinMulticastGroup()
|
||||
{
|
||||
#if defined(__linux__)
|
||||
packet_mreq mr{};
|
||||
mr.mr_ifindex = m_interfaceIndex;
|
||||
mr.mr_type = PACKET_MR_MULTICAST;
|
||||
mr.mr_alen = m_destAddress.size();
|
||||
std::copy(m_destAddress.begin(), m_destAddress.end(), mr.mr_address);
|
||||
std::memcpy(mr.mr_address, m_destAddress.data(), m_destAddress.size());
|
||||
|
||||
if (::setsockopt(m_socket.native_handle(), SOL_PACKET,
|
||||
PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == 0)
|
||||
@@ -223,7 +219,7 @@ EthernetFace::joinMulticastGroup()
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
// see bug #2327
|
||||
using boost::asio::ip::udp;
|
||||
udp::socket sock(ref(getGlobalIoService()), udp::v4());
|
||||
udp::socket sock(getGlobalIoService(), udp::v4());
|
||||
int fd = sock.native_handle();
|
||||
|
||||
/*
|
||||
@@ -242,7 +238,7 @@ EthernetFace::joinMulticastGroup()
|
||||
sdl->sdl_len = sizeof(ifr.ifr_addr);
|
||||
sdl->sdl_family = AF_LINK;
|
||||
sdl->sdl_alen = m_destAddress.size();
|
||||
std::copy(m_destAddress.begin(), m_destAddress.end(), LLADDR(sdl));
|
||||
std::memcpy(LLADDR(sdl), m_destAddress.data(), m_destAddress.size());
|
||||
|
||||
static_assert(sizeof(ifr.ifr_addr) >= offsetof(sockaddr_dl, sdl_data) + ethernet::ADDR_LEN,
|
||||
"ifr_addr in struct ifreq is too small on this platform");
|
||||
@@ -250,9 +246,9 @@ EthernetFace::joinMulticastGroup()
|
||||
int fd = m_socket.native_handle();
|
||||
|
||||
ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
|
||||
std::copy(m_destAddress.begin(), m_destAddress.end(), ifr.ifr_hwaddr.sa_data);
|
||||
std::memcpy(ifr.ifr_hwaddr.sa_data, m_destAddress.data(), m_destAddress.size());
|
||||
|
||||
static_assert(sizeof(ifr.ifr_hwaddr) >= offsetof(sockaddr, sa_data) + ethernet::ADDR_LEN,
|
||||
static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= ethernet::ADDR_LEN,
|
||||
"ifr_hwaddr in struct ifreq is too small on this platform");
|
||||
#endif
|
||||
|
||||
@@ -266,26 +262,17 @@ EthernetFace::joinMulticastGroup()
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::sendPacket(const ndn::Block& block)
|
||||
EthernetTransport::sendPacket(const ndn::Block& block)
|
||||
{
|
||||
if (!m_pcap)
|
||||
{
|
||||
NFD_LOG_FACE_WARN("Trying to send on closed face");
|
||||
return fail("Face closed");
|
||||
}
|
||||
|
||||
BOOST_ASSERT(block.size() <= m_interfaceMtu);
|
||||
|
||||
/// \todo Right now there is no reserve when packet is received, but
|
||||
/// we should reserve some space at the beginning and at the end
|
||||
ndn::EncodingBuffer buffer(block);
|
||||
|
||||
// pad with zeroes if the payload is too short
|
||||
if (block.size() < ethernet::MIN_DATA_LEN)
|
||||
{
|
||||
static const uint8_t padding[ethernet::MIN_DATA_LEN] = {};
|
||||
buffer.appendByteArray(padding, ethernet::MIN_DATA_LEN - block.size());
|
||||
}
|
||||
if (block.size() < ethernet::MIN_DATA_LEN) {
|
||||
static const uint8_t padding[ethernet::MIN_DATA_LEN] = {};
|
||||
buffer.appendByteArray(padding, ethernet::MIN_DATA_LEN - block.size());
|
||||
}
|
||||
|
||||
// construct and prepend the ethernet header
|
||||
static uint16_t ethertype = htons(ethernet::ETHERTYPE_NDN);
|
||||
@@ -296,66 +283,53 @@ EthernetFace::sendPacket(const ndn::Block& block)
|
||||
// send the packet
|
||||
int sent = pcap_inject(m_pcap.get(), buffer.buf(), buffer.size());
|
||||
if (sent < 0)
|
||||
{
|
||||
return fail("pcap_inject: " + std::string(pcap_geterr(m_pcap.get())));
|
||||
}
|
||||
NFD_LOG_FACE_ERROR("pcap_inject failed: " << pcap_geterr(m_pcap.get()));
|
||||
else if (static_cast<size_t>(sent) < buffer.size())
|
||||
{
|
||||
return fail("Failed to inject frame");
|
||||
}
|
||||
|
||||
NFD_LOG_FACE_TRACE("Successfully sent: " << block.size() << " bytes");
|
||||
this->getMutableCounters().getNOutBytes() += block.size();
|
||||
NFD_LOG_FACE_ERROR("Failed to send the full frame: bufsize=" << buffer.size() << " sent=" << sent);
|
||||
else
|
||||
// print block size because we don't want to count the padding in buffer
|
||||
NFD_LOG_FACE_TRACE("Successfully sent: " << block.size() << " bytes");
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::handleRead(const boost::system::error_code& error, size_t)
|
||||
EthernetTransport::handleRead(const boost::system::error_code& error, size_t)
|
||||
{
|
||||
if (!m_pcap)
|
||||
return fail("Face closed");
|
||||
|
||||
if (error)
|
||||
return processErrorCode(error);
|
||||
|
||||
pcap_pkthdr* header;
|
||||
const uint8_t* packet;
|
||||
|
||||
// read the pcap header and packet data
|
||||
int ret = pcap_next_ex(m_pcap.get(), &header, &packet);
|
||||
if (ret < 0)
|
||||
{
|
||||
return fail("pcap_next_ex: " + std::string(pcap_geterr(m_pcap.get())));
|
||||
}
|
||||
NFD_LOG_FACE_ERROR("pcap_next_ex failed: " << pcap_geterr(m_pcap.get()));
|
||||
else if (ret == 0)
|
||||
{
|
||||
NFD_LOG_FACE_WARN("Read timeout");
|
||||
}
|
||||
NFD_LOG_FACE_WARN("Read timeout");
|
||||
else
|
||||
{
|
||||
processIncomingPacket(header, packet);
|
||||
}
|
||||
processIncomingPacket(header, packet);
|
||||
|
||||
#ifdef _DEBUG
|
||||
pcap_stat ps{};
|
||||
ret = pcap_stats(m_pcap.get(), &ps);
|
||||
if (ret < 0)
|
||||
{
|
||||
NFD_LOG_FACE_DEBUG("pcap_stats failed: " << pcap_geterr(m_pcap.get()));
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
if (ps.ps_drop - m_nDropped > 0)
|
||||
NFD_LOG_FACE_DEBUG("Detected " << ps.ps_drop - m_nDropped << " dropped packet(s)");
|
||||
m_nDropped = ps.ps_drop;
|
||||
}
|
||||
if (ret < 0) {
|
||||
NFD_LOG_FACE_DEBUG("pcap_stats failed: " << pcap_geterr(m_pcap.get()));
|
||||
}
|
||||
else if (ret == 0) {
|
||||
if (ps.ps_drop - m_nDropped > 0)
|
||||
NFD_LOG_FACE_DEBUG("Detected " << ps.ps_drop - m_nDropped << " dropped packet(s)");
|
||||
m_nDropped = ps.ps_drop;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_socket.async_read_some(boost::asio::null_buffers(),
|
||||
bind(&EthernetFace::handleRead, this,
|
||||
bind(&EthernetTransport::handleRead, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::processIncomingPacket(const pcap_pkthdr* header, const uint8_t* packet)
|
||||
EthernetTransport::processIncomingPacket(const pcap_pkthdr* header, const uint8_t* packet)
|
||||
{
|
||||
size_t length = header->caplen;
|
||||
if (length < ethernet::HDR_LEN + ethernet::MIN_DATA_LEN) {
|
||||
@@ -366,88 +340,60 @@ EthernetFace::processIncomingPacket(const pcap_pkthdr* header, const uint8_t* pa
|
||||
const ether_header* eh = reinterpret_cast<const ether_header*>(packet);
|
||||
const ethernet::Address sourceAddress(eh->ether_shost);
|
||||
|
||||
// assert in case BPF fails to filter unwanted frames
|
||||
// in some cases VLAN-tagged frames may survive the BPF filter,
|
||||
// make sure we do not process those frames (see #3348)
|
||||
if (ntohs(eh->ether_type) != ethernet::ETHERTYPE_NDN)
|
||||
return;
|
||||
|
||||
// check that our BPF filter is working correctly
|
||||
BOOST_ASSERT_MSG(ethernet::Address(eh->ether_dhost) == m_destAddress,
|
||||
"Received frame addressed to a different multicast group");
|
||||
BOOST_ASSERT_MSG(sourceAddress != m_srcAddress,
|
||||
"Received frame sent by this host");
|
||||
BOOST_ASSERT_MSG(ntohs(eh->ether_type) == ethernet::ETHERTYPE_NDN,
|
||||
"Received frame with unrecognized ethertype");
|
||||
|
||||
packet += ethernet::HDR_LEN;
|
||||
length -= ethernet::HDR_LEN;
|
||||
|
||||
/// \todo Reserve space in front and at the back of the underlying buffer
|
||||
bool isOk = false;
|
||||
Block fragmentBlock;
|
||||
std::tie(isOk, fragmentBlock) = Block::fromBuffer(packet, length);
|
||||
Block element;
|
||||
std::tie(isOk, element) = Block::fromBuffer(packet, length);
|
||||
if (!isOk) {
|
||||
NFD_LOG_FACE_WARN("Block received from " << sourceAddress.toString()
|
||||
<< " is invalid or too large to process");
|
||||
NFD_LOG_FACE_WARN("Received invalid packet from " << sourceAddress.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
NFD_LOG_FACE_TRACE("Received: " << fragmentBlock.size() << " bytes from "
|
||||
<< sourceAddress.toString());
|
||||
this->getMutableCounters().getNInBytes() += fragmentBlock.size();
|
||||
NFD_LOG_FACE_TRACE("Received: " << element.size() << " bytes from " << sourceAddress.toString());
|
||||
|
||||
Reassembler& reassembler = m_reassemblers[sourceAddress];
|
||||
if (!reassembler.pms) {
|
||||
// new sender, setup a PartialMessageStore for it
|
||||
reassembler.pms.reset(new ndnlp::PartialMessageStore);
|
||||
reassembler.pms->onReceive.connect(
|
||||
[this, sourceAddress] (const Block& block) {
|
||||
NFD_LOG_FACE_TRACE("All fragments received from " << sourceAddress.toString());
|
||||
if (!decodeAndDispatchInput(block))
|
||||
NFD_LOG_FACE_WARN("Received unrecognized TLV block of type " << block.type()
|
||||
<< " from " << sourceAddress.toString());
|
||||
});
|
||||
}
|
||||
|
||||
scheduler::cancel(reassembler.expireEvent);
|
||||
reassembler.expireEvent = scheduler::schedule(REASSEMBLER_LIFETIME,
|
||||
[this, sourceAddress] {
|
||||
BOOST_VERIFY(m_reassemblers.erase(sourceAddress) == 1);
|
||||
});
|
||||
|
||||
ndnlp::NdnlpData fragment;
|
||||
std::tie(isOk, fragment) = ndnlp::NdnlpData::fromBlock(fragmentBlock);
|
||||
if (!isOk) {
|
||||
NFD_LOG_FACE_WARN("Received invalid NDNLP fragment from " << sourceAddress.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
reassembler.pms->receive(fragment);
|
||||
Transport::Packet tp(std::move(element));
|
||||
static_assert(sizeof(tp.remoteEndpoint) >= ethernet::ADDR_LEN,
|
||||
"Transport::Packet::remoteEndpoint is too small");
|
||||
std::memcpy(&tp.remoteEndpoint, sourceAddress.data(), sourceAddress.size());
|
||||
this->receive(std::move(tp));
|
||||
}
|
||||
|
||||
void
|
||||
EthernetFace::processErrorCode(const boost::system::error_code& error)
|
||||
EthernetTransport::processErrorCode(const boost::system::error_code& error)
|
||||
{
|
||||
if (error == boost::asio::error::operation_aborted)
|
||||
// cancel() has been called on the socket
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
if (getState() == TransportState::CLOSING ||
|
||||
getState() == TransportState::FAILED ||
|
||||
getState() == TransportState::CLOSED ||
|
||||
error == boost::asio::error::operation_aborted)
|
||||
// transport is shutting down, ignore any errors
|
||||
return;
|
||||
|
||||
std::string msg;
|
||||
if (error == boost::asio::error::eof)
|
||||
{
|
||||
msg = "Face closed";
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = "Receive operation failed: " + error.message();
|
||||
NFD_LOG_FACE_WARN(msg);
|
||||
}
|
||||
fail(msg);
|
||||
NFD_LOG_FACE_WARN("Receive operation failed: " << error.message());
|
||||
}
|
||||
|
||||
size_t
|
||||
EthernetFace::getInterfaceMtu()
|
||||
EthernetTransport::getInterfaceMtu()
|
||||
{
|
||||
#ifdef SIOCGIFMTU
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
// see bug #2328
|
||||
using boost::asio::ip::udp;
|
||||
udp::socket sock(ref(getGlobalIoService()), udp::v4());
|
||||
udp::socket sock(getGlobalIoService(), udp::v4());
|
||||
int fd = sock.native_handle();
|
||||
#else
|
||||
int fd = m_socket.native_handle();
|
||||
@@ -456,13 +402,17 @@ EthernetFace::getInterfaceMtu()
|
||||
ifreq ifr{};
|
||||
std::strncpy(ifr.ifr_name, m_interfaceName.c_str(), sizeof(ifr.ifr_name) - 1);
|
||||
|
||||
if (::ioctl(fd, SIOCGIFMTU, &ifr) == 0)
|
||||
if (::ioctl(fd, SIOCGIFMTU, &ifr) == 0) {
|
||||
NFD_LOG_FACE_DEBUG("Interface MTU is " << ifr.ifr_mtu);
|
||||
return static_cast<size_t>(ifr.ifr_mtu);
|
||||
}
|
||||
|
||||
NFD_LOG_FACE_WARN("Failed to get interface MTU: " << std::strerror(errno));
|
||||
#endif
|
||||
|
||||
NFD_LOG_FACE_DEBUG("Assuming default MTU of " << ethernet::MAX_DATA_LEN);
|
||||
return ethernet::MAX_DATA_LEN;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -23,17 +23,13 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_ETHERNET_FACE_HPP
|
||||
#define NFD_DAEMON_FACE_ETHERNET_FACE_HPP
|
||||
#ifndef NFD_DAEMON_FACE_ETHERNET_TRANSPORT_HPP
|
||||
#define NFD_DAEMON_FACE_ETHERNET_TRANSPORT_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "face.hpp"
|
||||
#include "ndnlp-partial-message-store.hpp"
|
||||
#include "ndnlp-slicer.hpp"
|
||||
#include "transport.hpp"
|
||||
#include "core/network-interface.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#ifndef HAVE_LIBPCAP
|
||||
#error "Cannot include this file when libpcap is not available"
|
||||
#endif
|
||||
@@ -44,43 +40,41 @@ typedef pcap pcap_t;
|
||||
struct pcap_pkthdr;
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/**
|
||||
* @brief Implementation of Face abstraction that uses raw
|
||||
* Ethernet frames as underlying transport mechanism
|
||||
* \brief A multicast Transport that uses raw Ethernet II frames
|
||||
*/
|
||||
class EthernetFace : public Face
|
||||
class EthernetTransport DECL_CLASS_FINAL : public Transport
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief EthernetFace-related error
|
||||
*/
|
||||
struct Error : public Face::Error
|
||||
class Error : public std::runtime_error
|
||||
{
|
||||
Error(const std::string& what) : Face::Error(what) {}
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& what)
|
||||
: std::runtime_error(what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
EthernetFace(boost::asio::posix::stream_descriptor socket,
|
||||
const NetworkInterfaceInfo& interface,
|
||||
const ethernet::Address& address);
|
||||
|
||||
/// send an Interest
|
||||
void
|
||||
sendInterest(const Interest& interest) DECL_OVERRIDE;
|
||||
|
||||
/// send a Data
|
||||
void
|
||||
sendData(const Data& data) DECL_OVERRIDE;
|
||||
|
||||
/**
|
||||
* @brief Closes the face
|
||||
*
|
||||
* This terminates all communication on the face and triggers the onFail() event.
|
||||
* @brief Creates an Ethernet-based transport for multicast communication
|
||||
*/
|
||||
void
|
||||
close() DECL_OVERRIDE;
|
||||
EthernetTransport(const NetworkInterfaceInfo& interface,
|
||||
const ethernet::Address& mcastAddress);
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
|
||||
|
||||
virtual void
|
||||
doClose() DECL_FINAL;
|
||||
|
||||
private:
|
||||
virtual void
|
||||
doSend(Transport::Packet&& packet) DECL_FINAL;
|
||||
|
||||
/**
|
||||
* @brief Allocates and initializes a libpcap context for live capture
|
||||
*/
|
||||
@@ -139,26 +133,15 @@ private:
|
||||
getInterfaceMtu();
|
||||
|
||||
private:
|
||||
struct Reassembler
|
||||
{
|
||||
unique_ptr<ndnlp::PartialMessageStore> pms;
|
||||
scheduler::EventId expireEvent;
|
||||
};
|
||||
|
||||
unique_ptr<pcap_t, void(*)(pcap_t*)> m_pcap;
|
||||
boost::asio::posix::stream_descriptor m_socket;
|
||||
|
||||
ethernet::Address m_srcAddress;
|
||||
ethernet::Address m_destAddress;
|
||||
std::string m_interfaceName;
|
||||
#if defined(__linux__)
|
||||
int m_interfaceIndex;
|
||||
#endif
|
||||
std::string m_interfaceName;
|
||||
ethernet::Address m_srcAddress;
|
||||
ethernet::Address m_destAddress;
|
||||
|
||||
size_t m_interfaceMtu;
|
||||
unique_ptr<ndnlp::Slicer> m_slicer;
|
||||
std::unordered_map<ethernet::Address, Reassembler> m_reassemblers;
|
||||
static const time::nanoseconds REASSEMBLER_LIFETIME;
|
||||
|
||||
#ifdef _DEBUG
|
||||
/// number of packets dropped by the kernel, as reported by libpcap
|
||||
@@ -166,6 +149,7 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_ETHERNET_FACE_HPP
|
||||
#endif // NFD_DAEMON_FACE_ETHERNET_TRANSPORT_HPP
|
||||
@@ -23,40 +23,27 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_NDNLP_PARSE_HPP
|
||||
#define NFD_DAEMON_FACE_NDNLP_PARSE_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "ndnlp-tlv.hpp"
|
||||
#include "face-counters.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace ndnlp {
|
||||
namespace face {
|
||||
|
||||
/** \brief represents a NdnlpData packet
|
||||
*
|
||||
* NdnlpData ::= NDNLP-DATA-TYPE TLV-LENGTH
|
||||
* NdnlpSequence
|
||||
* NdnlpFragIndex?
|
||||
* NdnlpFragCount?
|
||||
* NdnlpPayload
|
||||
*/
|
||||
class NdnlpData
|
||||
FaceCounters::FaceCounters(const LinkService::Counters& linkServiceCounters,
|
||||
const Transport::Counters& transportCounters)
|
||||
: nInInterests(linkServiceCounters.nInInterests)
|
||||
, nOutInterests(linkServiceCounters.nOutInterests)
|
||||
, nInData(linkServiceCounters.nInData)
|
||||
, nOutData(linkServiceCounters.nOutData)
|
||||
, nInNacks(linkServiceCounters.nInNacks)
|
||||
, nOutNacks(linkServiceCounters.nOutNacks)
|
||||
, nInPackets(transportCounters.nInPackets)
|
||||
, nOutPackets(transportCounters.nOutPackets)
|
||||
, nInBytes(transportCounters.nInBytes)
|
||||
, nOutBytes(transportCounters.nOutBytes)
|
||||
, m_linkServiceCounters(linkServiceCounters)
|
||||
, m_transportCounters(transportCounters)
|
||||
{
|
||||
public:
|
||||
/** \brief parse a NdnlpData packet
|
||||
* \return whether \p wire has a valid NdnlpData packet, and the parsed packet
|
||||
*/
|
||||
static std::tuple<bool, NdnlpData>
|
||||
fromBlock(const Block& wire);
|
||||
}
|
||||
|
||||
public:
|
||||
uint64_t seq;
|
||||
uint16_t fragIndex;
|
||||
uint16_t fragCount;
|
||||
Block payload;
|
||||
};
|
||||
|
||||
} // namespace ndnlp
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_NDNLP_PARSE_HPP
|
||||
+53
-213
@@ -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-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.
|
||||
@@ -26,226 +26,66 @@
|
||||
#ifndef NFD_DAEMON_FACE_FACE_COUNTERS_HPP
|
||||
#define NFD_DAEMON_FACE_FACE_COUNTERS_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "link-service.hpp"
|
||||
#include "transport.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief represents a counter of number of packets
|
||||
/** \brief gives access to counters provided by Face
|
||||
*
|
||||
* This type is a facade that exposes common counters of a Face.
|
||||
*
|
||||
* get<T>() can be used to access extended counters provided by
|
||||
* LinkService or Transport of the Face.
|
||||
*/
|
||||
// PacketCounter is noncopyable, because increment should be called on the counter,
|
||||
// not a copy of it; it's implicitly convertible to uint64_t to be observed
|
||||
class PacketCounter : noncopyable
|
||||
class FaceCounters
|
||||
{
|
||||
public:
|
||||
typedef uint64_t rep;
|
||||
FaceCounters(const LinkService::Counters& linkServiceCounters,
|
||||
const Transport::Counters& transportCounters);
|
||||
|
||||
PacketCounter()
|
||||
: m_value(0)
|
||||
{
|
||||
}
|
||||
|
||||
operator rep() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
PacketCounter&
|
||||
operator++()
|
||||
{
|
||||
++m_value;
|
||||
return *this;
|
||||
}
|
||||
// postfix ++ operator is not provided because it's not needed
|
||||
|
||||
void
|
||||
set(rep value)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
private:
|
||||
rep m_value;
|
||||
};
|
||||
|
||||
/** \brief represents a counter of number of bytes
|
||||
*/
|
||||
// ByteCounter is noncopyable, because increment should be called on the counter,
|
||||
// not a copy of it; it's implicitly convertible to uint64_t to be observed
|
||||
class ByteCounter : noncopyable
|
||||
{
|
||||
public:
|
||||
typedef uint64_t rep;
|
||||
|
||||
ByteCounter()
|
||||
: m_value(0)
|
||||
{
|
||||
}
|
||||
|
||||
operator rep() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
ByteCounter&
|
||||
operator+=(rep n)
|
||||
{
|
||||
m_value += n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
set(rep value)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
private:
|
||||
rep m_value;
|
||||
};
|
||||
|
||||
/** \brief contains network layer packet counters
|
||||
*/
|
||||
class NetworkLayerCounters : noncopyable
|
||||
{
|
||||
public:
|
||||
/// incoming Interest
|
||||
const PacketCounter&
|
||||
getNInInterests() const
|
||||
{
|
||||
return m_nInInterests;
|
||||
}
|
||||
|
||||
PacketCounter&
|
||||
getNInInterests()
|
||||
{
|
||||
return m_nInInterests;
|
||||
}
|
||||
|
||||
/// incoming Data
|
||||
const PacketCounter&
|
||||
getNInDatas() const
|
||||
{
|
||||
return m_nInDatas;
|
||||
}
|
||||
|
||||
PacketCounter&
|
||||
getNInDatas()
|
||||
{
|
||||
return m_nInDatas;
|
||||
}
|
||||
|
||||
/// outgoing Interest
|
||||
const PacketCounter&
|
||||
getNOutInterests() const
|
||||
{
|
||||
return m_nOutInterests;
|
||||
}
|
||||
|
||||
PacketCounter&
|
||||
getNOutInterests()
|
||||
{
|
||||
return m_nOutInterests;
|
||||
}
|
||||
|
||||
/// outgoing Data
|
||||
const PacketCounter&
|
||||
getNOutDatas() const
|
||||
{
|
||||
return m_nOutDatas;
|
||||
}
|
||||
|
||||
PacketCounter&
|
||||
getNOutDatas()
|
||||
{
|
||||
return m_nOutDatas;
|
||||
}
|
||||
|
||||
protected:
|
||||
/** \brief copy current obseverations to a struct
|
||||
* \param recipient an object with set methods for counters
|
||||
/** \return counters provided by LinkService
|
||||
* \tparam T LinkService counters type
|
||||
* \throw std::bad_cast counters type mismatch
|
||||
*/
|
||||
template<typename R>
|
||||
void
|
||||
copyTo(R& recipient) const
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_base_of<LinkService::Counters, T>::value, const T&>::type
|
||||
get() const
|
||||
{
|
||||
recipient.setNInInterests(this->getNInInterests());
|
||||
recipient.setNInDatas(this->getNInDatas());
|
||||
recipient.setNOutInterests(this->getNOutInterests());
|
||||
recipient.setNOutDatas(this->getNOutDatas());
|
||||
return dynamic_cast<const T&>(m_linkServiceCounters);
|
||||
}
|
||||
|
||||
/** \return counters provided by Transport
|
||||
* \tparam T Transport counters type
|
||||
* \throw std::bad_cast counters type mismatch
|
||||
*/
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_base_of<Transport::Counters, T>::value, const T&>::type
|
||||
get() const
|
||||
{
|
||||
return dynamic_cast<const T&>(m_transportCounters);
|
||||
}
|
||||
|
||||
public:
|
||||
const PacketCounter& nInInterests;
|
||||
const PacketCounter& nOutInterests;
|
||||
const PacketCounter& nInData;
|
||||
const PacketCounter& nOutData;
|
||||
const PacketCounter& nInNacks;
|
||||
const PacketCounter& nOutNacks;
|
||||
|
||||
const PacketCounter& nInPackets;
|
||||
const PacketCounter& nOutPackets;
|
||||
const ByteCounter& nInBytes;
|
||||
const ByteCounter& nOutBytes;
|
||||
|
||||
private:
|
||||
PacketCounter m_nInInterests;
|
||||
PacketCounter m_nInDatas;
|
||||
PacketCounter m_nOutInterests;
|
||||
PacketCounter m_nOutDatas;
|
||||
};
|
||||
|
||||
/** \brief contains link layer byte counters
|
||||
*/
|
||||
class LinkLayerCounters : noncopyable
|
||||
{
|
||||
public:
|
||||
/// received bytes
|
||||
const ByteCounter&
|
||||
getNInBytes() const
|
||||
{
|
||||
return m_nInBytes;
|
||||
}
|
||||
|
||||
ByteCounter&
|
||||
getNInBytes()
|
||||
{
|
||||
return m_nInBytes;
|
||||
}
|
||||
|
||||
/// sent bytes
|
||||
const ByteCounter&
|
||||
getNOutBytes() const
|
||||
{
|
||||
return m_nOutBytes;
|
||||
}
|
||||
|
||||
ByteCounter&
|
||||
getNOutBytes()
|
||||
{
|
||||
return m_nOutBytes;
|
||||
}
|
||||
|
||||
protected:
|
||||
/** \brief copy current obseverations to a struct
|
||||
* \param recipient an object with set methods for counters
|
||||
*/
|
||||
template<typename R>
|
||||
void
|
||||
copyTo(R& recipient) const
|
||||
{
|
||||
recipient.setNInBytes(this->getNInBytes());
|
||||
recipient.setNOutBytes(this->getNOutBytes());
|
||||
}
|
||||
|
||||
private:
|
||||
ByteCounter m_nInBytes;
|
||||
ByteCounter m_nOutBytes;
|
||||
};
|
||||
|
||||
/** \brief contains counters on face
|
||||
*/
|
||||
class FaceCounters : public NetworkLayerCounters, public LinkLayerCounters
|
||||
{
|
||||
public:
|
||||
/** \brief copy current obseverations to a struct
|
||||
* \param recipient an object with set methods for counters
|
||||
*/
|
||||
template<typename R>
|
||||
void
|
||||
copyTo(R& recipient) const
|
||||
{
|
||||
this->NetworkLayerCounters::copyTo(recipient);
|
||||
this->LinkLayerCounters::copyTo(recipient);
|
||||
}
|
||||
const LinkService::Counters& m_linkServiceCounters;
|
||||
const Transport::Counters& m_transportCounters;
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_FACE_COUNTERS_HPP
|
||||
+19
-91
@@ -25,103 +25,31 @@
|
||||
|
||||
#include "face.hpp"
|
||||
|
||||
#include <ndn-cxx/management/nfd-face-event-notification.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
Face::Face(const FaceUri& remoteUri, const FaceUri& localUri, bool isLocal, bool isMultiAccess)
|
||||
: m_id(INVALID_FACEID)
|
||||
, m_remoteUri(remoteUri)
|
||||
, m_localUri(localUri)
|
||||
, m_isLocal(isLocal)
|
||||
, m_persistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT)
|
||||
, m_isMultiAccess(isMultiAccess)
|
||||
, m_isFailed(false)
|
||||
Face::Face(unique_ptr<LinkService> service, unique_ptr<Transport> transport)
|
||||
: afterReceiveInterest(service->afterReceiveInterest)
|
||||
, afterReceiveData(service->afterReceiveData)
|
||||
, afterReceiveNack(service->afterReceiveNack)
|
||||
, afterStateChange(transport->afterStateChange)
|
||||
, m_id(INVALID_FACEID)
|
||||
, m_service(std::move(service))
|
||||
, m_transport(std::move(transport))
|
||||
, m_counters(m_service->getCounters(), m_transport->getCounters())
|
||||
{
|
||||
onReceiveInterest.connect([this] (const ndn::Interest&) { ++m_counters.getNInInterests(); });
|
||||
onReceiveData .connect([this] (const ndn::Data&) { ++m_counters.getNInDatas(); });
|
||||
onSendInterest .connect([this] (const ndn::Interest&) { ++m_counters.getNOutInterests(); });
|
||||
onSendData .connect([this] (const ndn::Data&) { ++m_counters.getNOutDatas(); });
|
||||
m_service->setFaceAndTransport(*this, *m_transport);
|
||||
m_transport->setFaceAndLinkService(*this, *m_service);
|
||||
}
|
||||
|
||||
Face::~Face()
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const FaceLogHelper<Face>& flh)
|
||||
{
|
||||
const Face& face = flh.obj;
|
||||
os << "[id=" << face.getId() << ",local=" << face.getLocalUri() <<
|
||||
",remote=" << face.getRemoteUri() << "] ";
|
||||
return os;
|
||||
}
|
||||
|
||||
bool
|
||||
Face::isUp() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Face::decodeAndDispatchInput(const Block& element)
|
||||
{
|
||||
try {
|
||||
/// \todo Ensure lazy field decoding process
|
||||
|
||||
if (element.type() == tlv::Interest)
|
||||
{
|
||||
shared_ptr<Interest> i = make_shared<Interest>();
|
||||
i->wireDecode(element);
|
||||
this->onReceiveInterest(*i);
|
||||
}
|
||||
else if (element.type() == tlv::Data)
|
||||
{
|
||||
shared_ptr<Data> d = make_shared<Data>();
|
||||
d->wireDecode(element);
|
||||
this->onReceiveData(*d);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (const tlv::Error&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Face::fail(const std::string& reason)
|
||||
{
|
||||
if (m_isFailed) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_isFailed = true;
|
||||
this->onFail(reason);
|
||||
}
|
||||
|
||||
template<typename FaceTraits>
|
||||
void
|
||||
Face::copyStatusTo(FaceTraits& traits) const
|
||||
{
|
||||
traits.setFaceId(getId())
|
||||
.setRemoteUri(getRemoteUri().toString())
|
||||
.setLocalUri(getLocalUri().toString())
|
||||
.setFaceScope(isLocal() ? ndn::nfd::FACE_SCOPE_LOCAL
|
||||
: ndn::nfd::FACE_SCOPE_NON_LOCAL)
|
||||
.setFacePersistency(getPersistency())
|
||||
.setLinkType(isMultiAccess() ? ndn::nfd::LINK_TYPE_MULTI_ACCESS
|
||||
: ndn::nfd::LINK_TYPE_POINT_TO_POINT);
|
||||
}
|
||||
|
||||
template void
|
||||
Face::copyStatusTo<ndn::nfd::FaceStatus>(ndn::nfd::FaceStatus&) const;
|
||||
|
||||
template void
|
||||
Face::copyStatusTo<ndn::nfd::FaceEventNotification>(ndn::nfd::FaceEventNotification&) const;
|
||||
|
||||
ndn::nfd::FaceStatus
|
||||
Face::getFaceStatus() const
|
||||
{
|
||||
ndn::nfd::FaceStatus status;
|
||||
|
||||
copyStatusTo(status);
|
||||
this->getCounters().copyTo(status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
+189
-192
@@ -23,209 +23,201 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_FACE_HPP
|
||||
#define NFD_DAEMON_FACE_FACE_HPP
|
||||
#ifndef NFD_DAEMON_FACE_HPP
|
||||
#define NFD_DAEMON_FACE_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "core/logger.hpp"
|
||||
#include "transport.hpp"
|
||||
#include "link-service.hpp"
|
||||
#include "face-counters.hpp"
|
||||
#include "face-log.hpp"
|
||||
|
||||
#include <ndn-cxx/management/nfd-face-status.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \class FaceId
|
||||
* \brief identifies a face
|
||||
/** \brief identifies a face
|
||||
*/
|
||||
typedef int FaceId;
|
||||
typedef uint64_t FaceId;
|
||||
|
||||
/// indicates an invalid FaceId
|
||||
const FaceId INVALID_FACEID = -1;
|
||||
|
||||
const FaceId INVALID_FACEID = 0;
|
||||
/// identifies the InternalFace used in management
|
||||
const FaceId FACEID_INTERNAL_FACE = 1;
|
||||
/// identifies a packet comes from the ContentStore, in LocalControlHeader incomingFaceId
|
||||
/// identifies a packet comes from the ContentStore
|
||||
const FaceId FACEID_CONTENT_STORE = 254;
|
||||
/// identifies the NullFace that drops every packet
|
||||
const FaceId FACEID_NULL = 255;
|
||||
/// upper bound of reserved FaceIds
|
||||
const FaceId FACEID_RESERVED_MAX = 255;
|
||||
|
||||
|
||||
/** \brief represents a face
|
||||
/** \brief indicates the state of a face
|
||||
*/
|
||||
class Face : noncopyable, public enable_shared_from_this<Face>
|
||||
typedef TransportState FaceState;
|
||||
|
||||
/** \brief generalization of a network interface
|
||||
*
|
||||
* A face generalizes a network interface.
|
||||
* It provides best-effort network-layer packet delivery services
|
||||
* on a physical interface, an overlay tunnel, or a link to a local application.
|
||||
*
|
||||
* A face combines two parts: LinkService and Transport.
|
||||
* Transport is the lower part, which provides best-effort TLV block deliveries.
|
||||
* LinkService is the upper part, which translates between network-layer packets
|
||||
* and TLV blocks, and may provide additional services such as fragmentation and reassembly.
|
||||
*/
|
||||
class Face
|
||||
#ifndef WITH_TESTS
|
||||
DECL_CLASS_FINAL
|
||||
#endif
|
||||
: public enable_shared_from_this<Face>, noncopyable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Face-related error
|
||||
Face(unique_ptr<LinkService> service, unique_ptr<Transport> transport);
|
||||
|
||||
LinkService*
|
||||
getLinkService();
|
||||
|
||||
Transport*
|
||||
getTransport();
|
||||
|
||||
public: // upper interface connected to forwarding
|
||||
/** \brief sends Interest on Face
|
||||
*/
|
||||
class Error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& what)
|
||||
: std::runtime_error(what)
|
||||
{
|
||||
}
|
||||
};
|
||||
void
|
||||
sendInterest(const Interest& interest);
|
||||
|
||||
Face(const FaceUri& remoteUri, const FaceUri& localUri,
|
||||
bool isLocal = false, bool isMultiAccess = false);
|
||||
|
||||
virtual
|
||||
~Face();
|
||||
|
||||
/// fires when an Interest is received
|
||||
signal::Signal<Face, Interest> onReceiveInterest;
|
||||
|
||||
/// fires when a Data is received
|
||||
signal::Signal<Face, Data> onReceiveData;
|
||||
|
||||
/// fires when a Nack is received
|
||||
signal::Signal<Face, lp::Nack> onReceiveNack;
|
||||
|
||||
/// fires when an Interest is sent out
|
||||
signal::Signal<Face, Interest> onSendInterest;
|
||||
|
||||
/// fires when a Data is sent out
|
||||
signal::Signal<Face, Data> onSendData;
|
||||
|
||||
/// fires when a Nack is sent out
|
||||
signal::Signal<Face, lp::Nack> onSendNack;
|
||||
|
||||
/// fires when face disconnects or fails to perform properly
|
||||
signal::Signal<Face, std::string/*reason*/> onFail;
|
||||
|
||||
/// send an Interest
|
||||
virtual void
|
||||
sendInterest(const Interest& interest) = 0;
|
||||
|
||||
/// send a Data
|
||||
virtual void
|
||||
sendData(const Data& data) = 0;
|
||||
|
||||
/// send a Nack
|
||||
virtual void
|
||||
sendNack(const ndn::lp::Nack& nack)
|
||||
{
|
||||
}
|
||||
|
||||
/** \brief Close the face
|
||||
*
|
||||
* This terminates all communication on the face and cause
|
||||
* onFail() method event to be invoked
|
||||
/** \brief sends Data on Face
|
||||
*/
|
||||
virtual void
|
||||
close() = 0;
|
||||
void
|
||||
sendData(const Data& data);
|
||||
|
||||
public: // attributes
|
||||
/** \brief sends Nack on Face
|
||||
*/
|
||||
void
|
||||
sendNack(const lp::Nack& nack);
|
||||
|
||||
/** \brief signals on Interest received
|
||||
*/
|
||||
signal::Signal<LinkService, Interest>& afterReceiveInterest;
|
||||
|
||||
/** \brief signals on Data received
|
||||
*/
|
||||
signal::Signal<LinkService, Data>& afterReceiveData;
|
||||
|
||||
/** \brief signals on Nack received
|
||||
*/
|
||||
signal::Signal<LinkService, lp::Nack>& afterReceiveNack;
|
||||
|
||||
public: // static properties
|
||||
/** \return face ID
|
||||
*/
|
||||
FaceId
|
||||
getId() const;
|
||||
|
||||
/** \brief Get the description
|
||||
*/
|
||||
const std::string&
|
||||
getDescription() const;
|
||||
|
||||
/** \brief Set the face description
|
||||
*
|
||||
* This is typically invoked by management on set description command
|
||||
/** \brief sets face ID
|
||||
* \note Normally, this should only be invoked by FaceTable.
|
||||
*/
|
||||
void
|
||||
setDescription(const std::string& description);
|
||||
setId(FaceId id);
|
||||
|
||||
/** \brief Get whether face is connected to a local app
|
||||
/** \return a FaceUri representing local endpoint
|
||||
*/
|
||||
bool
|
||||
isLocal() const;
|
||||
FaceUri
|
||||
getLocalUri() const;
|
||||
|
||||
/** \brief Get the persistency setting
|
||||
/** \return a FaceUri representing remote endpoint
|
||||
*/
|
||||
FaceUri
|
||||
getRemoteUri() const;
|
||||
|
||||
/** \return whether face is local or non-local for scope control purpose
|
||||
*/
|
||||
ndn::nfd::FaceScope
|
||||
getScope() const;
|
||||
|
||||
/** \return face persistency setting
|
||||
*/
|
||||
ndn::nfd::FacePersistency
|
||||
getPersistency() const;
|
||||
|
||||
// 'virtual' to allow override in LpFaceWrapper
|
||||
virtual void
|
||||
/** \brief changes face persistency setting
|
||||
*/
|
||||
void
|
||||
setPersistency(ndn::nfd::FacePersistency persistency);
|
||||
|
||||
/** \brief Get whether packets sent by this face may reach multiple peers
|
||||
/** \return whether face is point-to-point or multi-access
|
||||
*/
|
||||
bool
|
||||
isMultiAccess() const;
|
||||
ndn::nfd::LinkType
|
||||
getLinkType() const;
|
||||
|
||||
/** \brief Get whether underlying communication is up
|
||||
public: // dynamic properties
|
||||
/** \return face state
|
||||
*/
|
||||
FaceState
|
||||
getState() const;
|
||||
|
||||
/** \brief signals after face state changed
|
||||
*/
|
||||
signal::Signal<Transport, FaceState/*old*/, FaceState/*new*/>& afterStateChange;
|
||||
|
||||
/** \return expiration time of the face
|
||||
* \retval time::steady_clock::TimePoint::max() the face has an indefinite lifetime
|
||||
*/
|
||||
time::steady_clock::TimePoint
|
||||
getExpirationTime() const;
|
||||
|
||||
/** \brief request the face to be closed
|
||||
*
|
||||
* In this base class this property is always true.
|
||||
* This operation is effective only if face is in UP or DOWN state,
|
||||
* otherwise it has no effect.
|
||||
* The face changes state to CLOSING, and performs cleanup procedure.
|
||||
* The state will be changed to CLOSED when cleanup is complete, which may
|
||||
* happen synchronously or asynchronously.
|
||||
*
|
||||
* \warning the face must not be deallocated until its state changes to CLOSED
|
||||
*/
|
||||
virtual bool
|
||||
isUp() const;
|
||||
void
|
||||
close();
|
||||
|
||||
// 'virtual' to allow override in LpFaceWrapper
|
||||
virtual const FaceCounters&
|
||||
const FaceCounters&
|
||||
getCounters() const;
|
||||
|
||||
/** \return a FaceUri that represents the remote endpoint
|
||||
*/
|
||||
const FaceUri&
|
||||
getRemoteUri() const;
|
||||
|
||||
/** \return a FaceUri that represents the local endpoint (NFD side)
|
||||
*/
|
||||
const FaceUri&
|
||||
getLocalUri() const;
|
||||
|
||||
/** \return FaceTraits data structure filled with the current FaceTraits status
|
||||
*/
|
||||
template<typename FaceTraits>
|
||||
void
|
||||
copyStatusTo(FaceTraits& traits) const;
|
||||
|
||||
/** \return FaceStatus data structure filled with the current Face status
|
||||
*/
|
||||
virtual ndn::nfd::FaceStatus
|
||||
getFaceStatus() const;
|
||||
|
||||
protected:
|
||||
bool
|
||||
decodeAndDispatchInput(const Block& element);
|
||||
|
||||
/** \brief fail the face and raise onFail event if it's UP; otherwise do nothing
|
||||
*/
|
||||
void
|
||||
fail(const std::string& reason);
|
||||
|
||||
FaceCounters&
|
||||
getMutableCounters();
|
||||
|
||||
DECLARE_SIGNAL_EMIT(onReceiveInterest)
|
||||
DECLARE_SIGNAL_EMIT(onReceiveData)
|
||||
DECLARE_SIGNAL_EMIT(onReceiveNack)
|
||||
DECLARE_SIGNAL_EMIT(onSendInterest)
|
||||
DECLARE_SIGNAL_EMIT(onSendData)
|
||||
DECLARE_SIGNAL_EMIT(onSendNack)
|
||||
|
||||
// this method should be used only by the FaceTable
|
||||
// 'virtual' to allow override in LpFaceWrapper
|
||||
virtual void
|
||||
setId(FaceId faceId);
|
||||
|
||||
private:
|
||||
FaceId m_id;
|
||||
std::string m_description;
|
||||
unique_ptr<LinkService> m_service;
|
||||
unique_ptr<Transport> m_transport;
|
||||
FaceCounters m_counters;
|
||||
const FaceUri m_remoteUri;
|
||||
const FaceUri m_localUri;
|
||||
const bool m_isLocal;
|
||||
ndn::nfd::FacePersistency m_persistency;
|
||||
const bool m_isMultiAccess;
|
||||
bool m_isFailed;
|
||||
|
||||
// allow setting FaceId
|
||||
friend class FaceTable;
|
||||
};
|
||||
|
||||
inline LinkService*
|
||||
Face::getLinkService()
|
||||
{
|
||||
return m_service.get();
|
||||
}
|
||||
|
||||
inline Transport*
|
||||
Face::getTransport()
|
||||
{
|
||||
return m_transport.get();
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::sendInterest(const Interest& interest)
|
||||
{
|
||||
m_service->sendInterest(interest);
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::sendData(const Data& data)
|
||||
{
|
||||
m_service->sendData(data);
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::sendNack(const lp::Nack& nack)
|
||||
{
|
||||
m_service->sendNack(nack);
|
||||
}
|
||||
|
||||
inline FaceId
|
||||
Face::getId() const
|
||||
{
|
||||
@@ -233,45 +225,63 @@ Face::getId() const
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::setId(FaceId faceId)
|
||||
Face::setId(FaceId id)
|
||||
{
|
||||
m_id = faceId;
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
inline const std::string&
|
||||
Face::getDescription() const
|
||||
inline FaceUri
|
||||
Face::getLocalUri() const
|
||||
{
|
||||
return m_description;
|
||||
return m_transport->getLocalUri();
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::setDescription(const std::string& description)
|
||||
inline FaceUri
|
||||
Face::getRemoteUri() const
|
||||
{
|
||||
m_description = description;
|
||||
return m_transport->getRemoteUri();
|
||||
}
|
||||
|
||||
inline bool
|
||||
Face::isLocal() const
|
||||
inline ndn::nfd::FaceScope
|
||||
Face::getScope() const
|
||||
{
|
||||
return m_isLocal;
|
||||
return m_transport->getScope();
|
||||
}
|
||||
|
||||
inline ndn::nfd::FacePersistency
|
||||
Face::getPersistency() const
|
||||
{
|
||||
return m_persistency;
|
||||
return m_transport->getPersistency();
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::setPersistency(ndn::nfd::FacePersistency persistency)
|
||||
{
|
||||
m_persistency = persistency;
|
||||
return m_transport->setPersistency(persistency);
|
||||
}
|
||||
|
||||
inline bool
|
||||
Face::isMultiAccess() const
|
||||
inline ndn::nfd::LinkType
|
||||
Face::getLinkType() const
|
||||
{
|
||||
return m_isMultiAccess;
|
||||
return m_transport->getLinkType();
|
||||
}
|
||||
|
||||
inline FaceState
|
||||
Face::getState() const
|
||||
{
|
||||
return m_transport->getState();
|
||||
}
|
||||
|
||||
inline time::steady_clock::TimePoint
|
||||
Face::getExpirationTime() const
|
||||
{
|
||||
return m_transport->getExpirationTime();
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::close()
|
||||
{
|
||||
m_transport->close();
|
||||
}
|
||||
|
||||
inline const FaceCounters&
|
||||
@@ -280,34 +290,21 @@ Face::getCounters() const
|
||||
return m_counters;
|
||||
}
|
||||
|
||||
inline FaceCounters&
|
||||
Face::getMutableCounters()
|
||||
{
|
||||
return m_counters;
|
||||
}
|
||||
|
||||
inline const FaceUri&
|
||||
Face::getRemoteUri() const
|
||||
{
|
||||
return m_remoteUri;
|
||||
}
|
||||
|
||||
inline const FaceUri&
|
||||
Face::getLocalUri() const
|
||||
{
|
||||
return m_localUri;
|
||||
}
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const FaceLogHelper<Face>& flh);
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_base_of<Face, T>::value, std::ostream&>::type
|
||||
operator<<(std::ostream& os, const face::FaceLogHelper<T>& flh)
|
||||
operator<<(std::ostream& os, const FaceLogHelper<T>& flh)
|
||||
{
|
||||
const Face& face = flh.obj;
|
||||
os << "[id=" << face.getId() << ",local=" << face.getLocalUri() <<
|
||||
",remote=" << face.getRemoteUri() << "] ";
|
||||
return os;
|
||||
return os << FaceLogHelper<Face>(flh.obj);
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
|
||||
using face::FaceId;
|
||||
using face::Face;
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_FACE_HPP
|
||||
#endif // NFD_DAEMON_FACE_HPP
|
||||
@@ -30,38 +30,50 @@ namespace face {
|
||||
|
||||
NFD_LOG_INIT("GenericLinkService");
|
||||
|
||||
GenericLinkServiceCounters::GenericLinkServiceCounters(const LpReassembler& reassembler)
|
||||
: nReassembling(reassembler)
|
||||
{
|
||||
}
|
||||
|
||||
GenericLinkService::Options::Options()
|
||||
: allowLocalFields(false)
|
||||
, allowFragmentation(false)
|
||||
, allowReassembly(false)
|
||||
{
|
||||
}
|
||||
|
||||
GenericLinkService::GenericLinkService(const GenericLinkService::Options& options)
|
||||
: m_options(options)
|
||||
: GenericLinkServiceCounters(m_reassembler)
|
||||
, m_options(options)
|
||||
, m_fragmenter(m_options.fragmenterOptions, this)
|
||||
, m_reassembler(m_options.reassemblerOptions, this)
|
||||
, m_lastSeqNo(-2)
|
||||
{
|
||||
m_reassembler.beforeTimeout.connect(bind([this] { ++this->nReassemblyTimeouts; }));
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::doSendInterest(const Interest& interest)
|
||||
{
|
||||
lp::Packet lpPacket(interest.wireEncode());
|
||||
|
||||
if (m_options.allowLocalFields) {
|
||||
encodeLocalFields(interest, lpPacket);
|
||||
}
|
||||
Transport::Packet packet;
|
||||
packet.packet = lpPacket.wireEncode();
|
||||
sendPacket(std::move(packet));
|
||||
|
||||
this->sendNetPacket(std::move(lpPacket));
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::doSendData(const Data& data)
|
||||
{
|
||||
lp::Packet lpPacket(data.wireEncode());
|
||||
|
||||
if (m_options.allowLocalFields) {
|
||||
encodeLocalFields(data, lpPacket);
|
||||
}
|
||||
Transport::Packet packet;
|
||||
packet.packet = lpPacket.wireEncode();
|
||||
sendPacket(std::move(packet));
|
||||
|
||||
this->sendNetPacket(std::move(lpPacket));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -69,51 +81,74 @@ GenericLinkService::doSendNack(const lp::Nack& nack)
|
||||
{
|
||||
lp::Packet lpPacket(nack.getInterest().wireEncode());
|
||||
lpPacket.add<lp::NackField>(nack.getHeader());
|
||||
|
||||
if (m_options.allowLocalFields) {
|
||||
encodeLocalFields(nack.getInterest(), lpPacket);
|
||||
encodeLocalFields(nack, lpPacket);
|
||||
}
|
||||
Transport::Packet packet;
|
||||
packet.packet = lpPacket.wireEncode();
|
||||
sendPacket(std::move(packet));
|
||||
|
||||
this->sendNetPacket(std::move(lpPacket));
|
||||
}
|
||||
|
||||
bool
|
||||
GenericLinkService::encodeLocalFields(const Interest& interest, lp::Packet& lpPacket)
|
||||
void
|
||||
GenericLinkService::encodeLocalFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket)
|
||||
{
|
||||
if (interest.getLocalControlHeader().hasIncomingFaceId()) {
|
||||
lpPacket.add<lp::IncomingFaceIdField>(interest.getIncomingFaceId());
|
||||
shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
|
||||
if (incomingFaceIdTag != nullptr) {
|
||||
lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
|
||||
}
|
||||
|
||||
if (interest.getLocalControlHeader().hasCachingPolicy()) {
|
||||
// Packet must be dropped
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GenericLinkService::encodeLocalFields(const Data& data, lp::Packet& lpPacket)
|
||||
void
|
||||
GenericLinkService::sendNetPacket(lp::Packet&& pkt)
|
||||
{
|
||||
if (data.getLocalControlHeader().hasIncomingFaceId()) {
|
||||
lpPacket.add<lp::IncomingFaceIdField>(data.getIncomingFaceId());
|
||||
}
|
||||
|
||||
if (data.getLocalControlHeader().hasCachingPolicy()) {
|
||||
switch (data.getCachingPolicy()) {
|
||||
case ndn::nfd::LocalControlHeader::CachingPolicy::NO_CACHE: {
|
||||
lp::CachePolicy cachePolicy;
|
||||
cachePolicy.setPolicy(lp::CachePolicyType::NO_CACHE);
|
||||
lpPacket.add<lp::CachePolicyField>(cachePolicy);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
std::vector<lp::Packet> frags;
|
||||
const ssize_t mtu = this->getTransport()->getMtu();
|
||||
if (m_options.allowFragmentation && mtu != MTU_UNLIMITED) {
|
||||
bool isOk = false;
|
||||
std::tie(isOk, frags) = m_fragmenter.fragmentPacket(pkt, mtu);
|
||||
if (!isOk) {
|
||||
// fragmentation failed (warning is logged by LpFragmenter)
|
||||
++this->nFragmentationErrors;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
frags.push_back(pkt);
|
||||
}
|
||||
|
||||
return true;
|
||||
if (frags.size() > 1) {
|
||||
// sequence is needed only if packet is fragmented
|
||||
this->assignSequences(frags);
|
||||
}
|
||||
else {
|
||||
// even if indexed fragmentation is enabled, the fragmenter should not
|
||||
// fragment the packet if it can fit in MTU
|
||||
BOOST_ASSERT(frags.size() > 0);
|
||||
BOOST_ASSERT(!frags.front().has<lp::FragIndexField>());
|
||||
BOOST_ASSERT(!frags.front().has<lp::FragCountField>());
|
||||
}
|
||||
|
||||
for (const lp::Packet& frag : frags) {
|
||||
Transport::Packet tp(frag.wireEncode());
|
||||
if (mtu != MTU_UNLIMITED && tp.packet.size() > static_cast<size_t>(mtu)) {
|
||||
++this->nOutOverMtu;
|
||||
NFD_LOG_FACE_WARN("attempt to send packet over MTU limit");
|
||||
continue;
|
||||
}
|
||||
this->sendPacket(std::move(tp));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::assignSequence(lp::Packet& pkt)
|
||||
{
|
||||
pkt.set<lp::SequenceField>(++m_lastSeqNo);
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::assignSequences(std::vector<lp::Packet>& pkts)
|
||||
{
|
||||
std::for_each(pkts.begin(), pkts.end(), bind(&GenericLinkService::assignSequence, this, _1));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -127,38 +162,55 @@ GenericLinkService::doReceivePacket(Transport::Packet&& packet)
|
||||
return;
|
||||
}
|
||||
|
||||
if (pkt.has<lp::FragIndexField>() || pkt.has<lp::FragCountField>()) {
|
||||
NFD_LOG_FACE_WARN("received fragment, but reassembly not implemented: DROP");
|
||||
if ((pkt.has<lp::FragIndexField>() || pkt.has<lp::FragCountField>()) &&
|
||||
!m_options.allowReassembly) {
|
||||
NFD_LOG_FACE_WARN("received fragment, but reassembly disabled: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
ndn::Buffer::const_iterator fragBegin, fragEnd;
|
||||
std::tie(fragBegin, fragEnd) = pkt.get<lp::FragmentField>();
|
||||
Block netPkt(&*fragBegin, std::distance(fragBegin, fragEnd));
|
||||
bool isReassembled = false;
|
||||
Block netPkt;
|
||||
lp::Packet firstPkt;
|
||||
std::tie(isReassembled, netPkt, firstPkt) = m_reassembler.receiveFragment(packet.remoteEndpoint,
|
||||
pkt);
|
||||
if (isReassembled) {
|
||||
this->decodeNetPacket(netPkt, firstPkt);
|
||||
}
|
||||
}
|
||||
catch (const tlv::Error& e) {
|
||||
++this->nInLpInvalid;
|
||||
NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::decodeNetPacket(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
{
|
||||
try {
|
||||
switch (netPkt.type()) {
|
||||
case tlv::Interest:
|
||||
if (pkt.has<lp::NackField>()) {
|
||||
this->decodeNack(netPkt, pkt);
|
||||
if (firstPkt.has<lp::NackField>()) {
|
||||
this->decodeNack(netPkt, firstPkt);
|
||||
}
|
||||
else {
|
||||
this->decodeInterest(netPkt, pkt);
|
||||
this->decodeInterest(netPkt, firstPkt);
|
||||
}
|
||||
break;
|
||||
case tlv::Data:
|
||||
this->decodeData(netPkt, pkt);
|
||||
this->decodeData(netPkt, firstPkt);
|
||||
break;
|
||||
default:
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("unrecognized network-layer packet TLV-TYPE " << netPkt.type() << ": DROP");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (const tlv::Error& e) {
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
{
|
||||
@@ -170,7 +222,7 @@ GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstP
|
||||
|
||||
if (firstPkt.has<lp::NextHopFaceIdField>()) {
|
||||
if (m_options.allowLocalFields) {
|
||||
interest->setNextHopFaceId(firstPkt.get<lp::NextHopFaceIdField>());
|
||||
interest->setTag(make_shared<lp::NextHopFaceIdTag>(firstPkt.get<lp::NextHopFaceIdField>()));
|
||||
}
|
||||
else {
|
||||
NFD_LOG_FACE_WARN("received NextHopFaceId, but local fields disabled: DROP");
|
||||
@@ -179,6 +231,7 @@ GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstP
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::CachePolicyField>()) {
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received CachePolicy with Interest: DROP");
|
||||
return;
|
||||
}
|
||||
@@ -199,26 +252,22 @@ GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
auto data = make_shared<Data>(netPkt);
|
||||
|
||||
if (firstPkt.has<lp::NackField>()) {
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received Nack with Data: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::NextHopFaceIdField>()) {
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received NextHopFaceId with Data: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::CachePolicyField>()) {
|
||||
if (m_options.allowLocalFields) {
|
||||
lp::CachePolicyType policy = firstPkt.get<lp::CachePolicyField>().getPolicy();
|
||||
switch (policy) {
|
||||
case lp::CachePolicyType::NO_CACHE:
|
||||
data->setCachingPolicy(ndn::nfd::LocalControlHeader::CachingPolicy::NO_CACHE);
|
||||
break;
|
||||
default:
|
||||
NFD_LOG_FACE_WARN("unrecognized CachePolicyType " << policy << ": DROP");
|
||||
return;
|
||||
}
|
||||
// In case of an invalid CachePolicyType, get<lp::CachePolicyField> will throw,
|
||||
// so it's unnecessary to check here.
|
||||
data->setTag(make_shared<lp::CachePolicyTag>(firstPkt.get<lp::CachePolicyField>()));
|
||||
}
|
||||
else {
|
||||
NFD_LOG_FACE_WARN("received CachePolicy, but local fields disabled: IGNORE");
|
||||
@@ -242,11 +291,13 @@ GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
nack.setHeader(firstPkt.get<lp::NackField>());
|
||||
|
||||
if (firstPkt.has<lp::NextHopFaceIdField>()) {
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received NextHopFaceId with Nack: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::CachePolicyField>()) {
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received CachePolicy with Nack: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -30,16 +30,54 @@
|
||||
#include "core/logger.hpp"
|
||||
|
||||
#include "link-service.hpp"
|
||||
|
||||
#include <ndn-cxx/lp/packet.hpp>
|
||||
#include "lp-fragmenter.hpp"
|
||||
#include "lp-reassembler.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief counters provided by GenericLinkService
|
||||
* \note The type name 'GenericLinkServiceCounters' is implementation detail.
|
||||
* Use 'GenericLinkService::Counters' in public API.
|
||||
*/
|
||||
class GenericLinkServiceCounters : public virtual LinkService::Counters
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
GenericLinkServiceCounters(const LpReassembler& reassembler);
|
||||
|
||||
/** \brief count of failed fragmentations
|
||||
*/
|
||||
PacketCounter nFragmentationErrors;
|
||||
|
||||
/** \brief count of outgoing LpPackets dropped due to exceeding MTU limit
|
||||
*
|
||||
* If this counter is non-zero, the operator should enable fragmentation.
|
||||
*/
|
||||
PacketCounter nOutOverMtu;
|
||||
|
||||
/** \brief count of invalid LpPackets dropped before reassembly
|
||||
*/
|
||||
PacketCounter nInLpInvalid;
|
||||
|
||||
/** \brief count of network-layer packets currently being reassembled
|
||||
*/
|
||||
SizeCounter<LpReassembler> nReassembling;
|
||||
|
||||
/** \brief count of dropped partial network-layer packets due to reassembly timeout
|
||||
*/
|
||||
PacketCounter nReassemblyTimeouts;
|
||||
|
||||
/** \brief count of invalid reassembled network-layer packets dropped
|
||||
*/
|
||||
PacketCounter nInNetInvalid;
|
||||
};
|
||||
|
||||
/** \brief GenericLinkService is a LinkService that implements the NDNLPv2 protocol
|
||||
* \sa http://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
|
||||
*/
|
||||
class GenericLinkService : public LinkService
|
||||
, protected virtual GenericLinkServiceCounters
|
||||
{
|
||||
public:
|
||||
/** \brief Options that control the behavior of GenericLinkService
|
||||
@@ -50,13 +88,31 @@ public:
|
||||
Options();
|
||||
|
||||
public:
|
||||
// TODO #3171: fragmentation and reassembly options
|
||||
|
||||
/** \brief enables encoding of IncomingFaceId, and decoding of NextHopFaceId and CachePolicy
|
||||
*/
|
||||
bool allowLocalFields;
|
||||
|
||||
/** \brief enables fragmentation
|
||||
*/
|
||||
bool allowFragmentation;
|
||||
|
||||
/** \brief options for fragmentation
|
||||
*/
|
||||
LpFragmenter::Options fragmenterOptions;
|
||||
|
||||
/** \brief enables reassembly
|
||||
*/
|
||||
bool allowReassembly;
|
||||
|
||||
/** \brief options for reassembly
|
||||
*/
|
||||
LpReassembler::Options reassemblerOptions;
|
||||
};
|
||||
|
||||
/** \brief counters provided by GenericLinkService
|
||||
*/
|
||||
typedef GenericLinkServiceCounters Counters;
|
||||
|
||||
explicit
|
||||
GenericLinkService(const Options& options = Options());
|
||||
|
||||
@@ -70,39 +126,62 @@ public:
|
||||
void
|
||||
setOptions(const Options& options);
|
||||
|
||||
private: // send path entrypoint
|
||||
/** \brief sends Interest
|
||||
virtual const Counters&
|
||||
getCounters() const DECL_OVERRIDE;
|
||||
|
||||
private: // send path
|
||||
/** \brief send Interest
|
||||
*/
|
||||
void
|
||||
doSendInterest(const Interest& interest) DECL_OVERRIDE;
|
||||
|
||||
/** \brief sends Data
|
||||
/** \brief send Data
|
||||
*/
|
||||
void
|
||||
doSendData(const Data& data) DECL_OVERRIDE;
|
||||
|
||||
/** \brief sends Nack
|
||||
* This class does not send out a Nack.
|
||||
/** \brief send Nack
|
||||
*/
|
||||
void
|
||||
doSendNack(const ndn::lp::Nack& nack) DECL_OVERRIDE;
|
||||
|
||||
private: // receive path entrypoint
|
||||
/** \brief receives Packet
|
||||
/** \brief encode local fields from tags onto outgoing LpPacket
|
||||
* \param pkt LpPacket containing a complete network layer packet
|
||||
*/
|
||||
static void
|
||||
encodeLocalFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket);
|
||||
|
||||
/** \brief send a complete network layer packet
|
||||
* \param pkt LpPacket containing a complete network layer packet
|
||||
*/
|
||||
void
|
||||
sendNetPacket(lp::Packet&& pkt);
|
||||
|
||||
/** \brief assign a sequence number to an LpPacket
|
||||
*/
|
||||
void
|
||||
assignSequence(lp::Packet& pkt);
|
||||
|
||||
/** \brief assign consecutive sequence numbers to LpPackets
|
||||
*/
|
||||
void
|
||||
assignSequences(std::vector<lp::Packet>& pkts);
|
||||
|
||||
private: // receive path
|
||||
/** \brief receive Packet from Transport
|
||||
*/
|
||||
void
|
||||
doReceivePacket(Transport::Packet&& packet) DECL_OVERRIDE;
|
||||
|
||||
private: // encoding and decoding
|
||||
/** \brief encode IncomingFaceId into LpPacket and verify local fields
|
||||
/** \brief decode incoming network-layer packet
|
||||
* \param netPkt reassembled network-layer packet
|
||||
* \param firstPkt LpPacket of first fragment
|
||||
*
|
||||
* If decoding is successful, a receive signal is emitted;
|
||||
* otherwise, a warning is logged.
|
||||
*/
|
||||
static bool
|
||||
encodeLocalFields(const Interest& interest, lp::Packet& lpPacket);
|
||||
|
||||
/** \brief encode CachingPolicy and IncomingFaceId into LpPacket and verify local fields
|
||||
*/
|
||||
static bool
|
||||
encodeLocalFields(const Data& data, lp::Packet& lpPacket);
|
||||
void
|
||||
decodeNetPacket(const Block& netPkt, const lp::Packet& firstPkt);
|
||||
|
||||
/** \brief decode incoming Interest
|
||||
* \param netPkt reassembled network-layer packet; TLV-TYPE must be Interest
|
||||
@@ -142,6 +221,9 @@ private: // encoding and decoding
|
||||
|
||||
private:
|
||||
Options m_options;
|
||||
LpFragmenter m_fragmenter;
|
||||
LpReassembler m_reassembler;
|
||||
lp::Sequence m_lastSeqNo;
|
||||
};
|
||||
|
||||
inline const GenericLinkService::Options&
|
||||
@@ -156,6 +238,12 @@ GenericLinkService::setOptions(const GenericLinkService::Options& options)
|
||||
m_options = options;
|
||||
}
|
||||
|
||||
inline const GenericLinkService::Counters&
|
||||
GenericLinkService::getCounters() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "internal-face.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "internal-transport.hpp"
|
||||
#include "lp-face-wrapper.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
|
||||
namespace nfd {
|
||||
@@ -38,19 +37,16 @@ makeInternalFace(ndn::KeyChain& clientKeyChain)
|
||||
GenericLinkService::Options serviceOpts;
|
||||
serviceOpts.allowLocalFields = true;
|
||||
|
||||
auto face = make_unique<LpFace>(make_unique<GenericLinkService>(serviceOpts),
|
||||
make_unique<InternalForwarderTransport>());
|
||||
auto faceW = make_shared<LpFaceWrapper>(std::move(face));
|
||||
// TODO#3172 eliminate wrapper
|
||||
auto face = make_shared<Face>(make_unique<GenericLinkService>(serviceOpts),
|
||||
make_unique<InternalForwarderTransport>());
|
||||
|
||||
InternalForwarderTransport* forwarderTransport =
|
||||
static_cast<InternalForwarderTransport*>(faceW->getLpFace()->getTransport());
|
||||
auto forwarderTransport = static_cast<InternalForwarderTransport*>(face->getTransport());
|
||||
auto clientTransport = make_shared<InternalClientTransport>();
|
||||
clientTransport->connectToForwarder(forwarderTransport);
|
||||
|
||||
auto clientFace = make_shared<ndn::Face>(clientTransport, getGlobalIoService(), clientKeyChain);
|
||||
|
||||
return std::make_tuple(faceW, clientFace);
|
||||
return std::make_tuple(face, clientFace);
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
|
||||
@@ -40,10 +40,20 @@ InternalForwarderTransport::InternalForwarderTransport(
|
||||
this->setScope(scope);
|
||||
this->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
|
||||
this->setLinkType(linkType);
|
||||
this->setMtu(MTU_UNLIMITED);
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -62,6 +62,9 @@ public:
|
||||
receiveFromLink(const Block& packet) DECL_OVERRIDE;
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
doClose() DECL_OVERRIDE;
|
||||
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "link-service.hpp"
|
||||
#include "lp-face.hpp"
|
||||
#include "transport.hpp"
|
||||
#include "face.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
@@ -35,7 +34,6 @@ NFD_LOG_INIT("LinkService");
|
||||
LinkService::LinkService()
|
||||
: m_face(nullptr)
|
||||
, m_transport(nullptr)
|
||||
, m_counters(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -44,14 +42,13 @@ LinkService::~LinkService()
|
||||
}
|
||||
|
||||
void
|
||||
LinkService::setFaceAndTransport(LpFace& face, Transport& transport)
|
||||
LinkService::setFaceAndTransport(Face& face, Transport& transport)
|
||||
{
|
||||
BOOST_ASSERT(m_face == nullptr);
|
||||
BOOST_ASSERT(m_transport == nullptr);
|
||||
|
||||
m_face = &face;
|
||||
m_transport = &transport;
|
||||
m_counters = &m_face->getMutableCounters();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -60,7 +57,7 @@ LinkService::sendInterest(const Interest& interest)
|
||||
BOOST_ASSERT(m_transport != nullptr);
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
++m_counters->getNOutInterests();
|
||||
++this->nOutInterests;
|
||||
|
||||
doSendInterest(interest);
|
||||
}
|
||||
@@ -71,7 +68,7 @@ LinkService::sendData(const Data& data)
|
||||
BOOST_ASSERT(m_transport != nullptr);
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
++m_counters->getNOutDatas();
|
||||
++this->nOutData;
|
||||
|
||||
doSendData(data);
|
||||
}
|
||||
@@ -82,7 +79,7 @@ LinkService::sendNack(const ndn::lp::Nack& nack)
|
||||
BOOST_ASSERT(m_transport != nullptr);
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
// TODO#3177 increment counter
|
||||
++this->nOutNacks;
|
||||
|
||||
doSendNack(nack);
|
||||
}
|
||||
@@ -92,7 +89,7 @@ LinkService::receiveInterest(const Interest& interest)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
++m_counters->getNInInterests();
|
||||
++this->nInInterests;
|
||||
|
||||
afterReceiveInterest(interest);
|
||||
}
|
||||
@@ -102,7 +99,7 @@ LinkService::receiveData(const Data& data)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
++m_counters->getNInDatas();
|
||||
++this->nInData;
|
||||
|
||||
afterReceiveData(data);
|
||||
}
|
||||
@@ -112,7 +109,7 @@ LinkService::receiveNack(const ndn::lp::Nack& nack)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
// TODO#3177 increment counter
|
||||
++this->nInNacks;
|
||||
|
||||
afterReceiveNack(nack);
|
||||
}
|
||||
@@ -120,7 +117,7 @@ LinkService::receiveNack(const ndn::lp::Nack& nack)
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const FaceLogHelper<LinkService>& flh)
|
||||
{
|
||||
const LpFace* face = flh.obj.getFace();
|
||||
const Face* face = flh.obj.getFace();
|
||||
if (face == nullptr) {
|
||||
os << "[id=0,local=unknown,remote=unknown] ";
|
||||
}
|
||||
|
||||
@@ -26,19 +26,57 @@
|
||||
#ifndef NFD_DAEMON_FACE_LINK_SERVICE_HPP
|
||||
#define NFD_DAEMON_FACE_LINK_SERVICE_HPP
|
||||
|
||||
#include "core/counter.hpp"
|
||||
#include "transport.hpp"
|
||||
#include "face-log.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
class LpFace;
|
||||
class Face;
|
||||
|
||||
/** \brief the upper part of an LpFace
|
||||
* \sa LpFace
|
||||
/** \brief counters provided by LinkService
|
||||
* \note The type name 'LinkServiceCounters' is implementation detail.
|
||||
* Use 'LinkService::Counters' in public API.
|
||||
*/
|
||||
class LinkService : noncopyable
|
||||
class LinkServiceCounters
|
||||
{
|
||||
public:
|
||||
/** \brief count of incoming Interests
|
||||
*/
|
||||
PacketCounter nInInterests;
|
||||
|
||||
/** \brief count of outgoing Interests
|
||||
*/
|
||||
PacketCounter nOutInterests;
|
||||
|
||||
/** \brief count of incoming Data
|
||||
*/
|
||||
PacketCounter nInData;
|
||||
|
||||
/** \brief count of outgoing Data
|
||||
*/
|
||||
PacketCounter nOutData;
|
||||
|
||||
/** \brief count of incoming Nacks
|
||||
*/
|
||||
PacketCounter nInNacks;
|
||||
|
||||
/** \brief count of outgoing Nacks
|
||||
*/
|
||||
PacketCounter nOutNacks;
|
||||
};
|
||||
|
||||
/** \brief the upper part of a Face
|
||||
* \sa Face
|
||||
*/
|
||||
class LinkService : protected virtual LinkServiceCounters, noncopyable
|
||||
{
|
||||
public:
|
||||
/** \brief counters provided by LinkService
|
||||
*/
|
||||
typedef LinkServiceCounters Counters;
|
||||
|
||||
public:
|
||||
LinkService();
|
||||
|
||||
@@ -49,11 +87,11 @@ public:
|
||||
* \pre setFaceAndTransport has not been called
|
||||
*/
|
||||
void
|
||||
setFaceAndTransport(LpFace& face, Transport& transport);
|
||||
setFaceAndTransport(Face& face, Transport& transport);
|
||||
|
||||
/** \return Face to which this LinkService is attached
|
||||
*/
|
||||
const LpFace*
|
||||
const Face*
|
||||
getFace() const;
|
||||
|
||||
/** \return Transport to which this LinkService is attached
|
||||
@@ -66,6 +104,9 @@ public:
|
||||
Transport*
|
||||
getTransport();
|
||||
|
||||
virtual const Counters&
|
||||
getCounters() const;
|
||||
|
||||
public: // upper interface to be used by forwarding
|
||||
/** \brief send Interest
|
||||
* \pre setTransport has been called
|
||||
@@ -97,21 +138,11 @@ public: // upper interface to be used by forwarding
|
||||
*/
|
||||
signal::Signal<LinkService, lp::Nack> afterReceiveNack;
|
||||
|
||||
private: // upper interface to be overridden in subclass (send path entrypoint)
|
||||
/** \brief performs LinkService specific operations to send an Interest
|
||||
public: // lower interface to be invoked by Transport
|
||||
/** \brief performs LinkService specific operations to receive a lower-layer packet
|
||||
*/
|
||||
virtual void
|
||||
doSendInterest(const Interest& interest) = 0;
|
||||
|
||||
/** \brief performs LinkService specific operations to send a Data
|
||||
*/
|
||||
virtual void
|
||||
doSendData(const Data& data) = 0;
|
||||
|
||||
/** \brief performs LinkService specific operations to send a Nack
|
||||
*/
|
||||
virtual void
|
||||
doSendNack(const lp::Nack& nack) = 0;
|
||||
void
|
||||
receivePacket(Transport::Packet&& packet);
|
||||
|
||||
protected: // upper interface to be invoked in subclass (receive path termination)
|
||||
/** \brief delivers received Interest to forwarding
|
||||
@@ -129,29 +160,38 @@ protected: // upper interface to be invoked in subclass (receive path terminatio
|
||||
void
|
||||
receiveNack(const lp::Nack& nack);
|
||||
|
||||
public: // lower interface to be invoked by Transport
|
||||
/** \brief performs LinkService specific operations to receive a lower-layer packet
|
||||
*/
|
||||
void
|
||||
receivePacket(Transport::Packet&& packet);
|
||||
|
||||
protected: // lower interface to be invoked in subclass (send path termination)
|
||||
/** \brief sends a lower-layer packet via Transport
|
||||
*/
|
||||
void
|
||||
sendPacket(Transport::Packet&& packet);
|
||||
|
||||
private: // upper interface to be overridden in subclass (send path entrypoint)
|
||||
/** \brief performs LinkService specific operations to send an Interest
|
||||
*/
|
||||
virtual void
|
||||
doSendInterest(const Interest& interest) = 0;
|
||||
|
||||
/** \brief performs LinkService specific operations to send a Data
|
||||
*/
|
||||
virtual void
|
||||
doSendData(const Data& data) = 0;
|
||||
|
||||
/** \brief performs LinkService specific operations to send a Nack
|
||||
*/
|
||||
virtual void
|
||||
doSendNack(const lp::Nack& nack) = 0;
|
||||
|
||||
private: // lower interface to be overridden in subclass
|
||||
virtual void
|
||||
doReceivePacket(Transport::Packet&& packet) = 0;
|
||||
|
||||
private:
|
||||
LpFace* m_face;
|
||||
Face* m_face;
|
||||
Transport* m_transport;
|
||||
NetworkLayerCounters* m_counters; // TODO#3177 change into NetCounters
|
||||
};
|
||||
|
||||
inline const LpFace*
|
||||
inline const Face*
|
||||
LinkService::getFace() const
|
||||
{
|
||||
return m_face;
|
||||
@@ -169,6 +209,12 @@ LinkService::getTransport()
|
||||
return m_transport;
|
||||
}
|
||||
|
||||
inline const LinkService::Counters&
|
||||
LinkService::getCounters() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void
|
||||
LinkService::receivePacket(Transport::Packet&& packet)
|
||||
{
|
||||
|
||||
@@ -1,219 +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_DAEMON_FACE_LOCAL_FACE_HPP
|
||||
#define NFD_DAEMON_FACE_LOCAL_FACE_HPP
|
||||
|
||||
#include "face.hpp"
|
||||
#include <ndn-cxx/management/nfd-control-parameters.hpp>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
using ndn::nfd::LocalControlFeature;
|
||||
using ndn::nfd::LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID;
|
||||
using ndn::nfd::LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID;
|
||||
|
||||
/** \brief represents a face
|
||||
*/
|
||||
class LocalFace : public Face
|
||||
{
|
||||
public:
|
||||
LocalFace(const FaceUri& remoteUri, const FaceUri& localUri);
|
||||
|
||||
/** \brief get whether any LocalControlHeader feature is enabled
|
||||
*
|
||||
* \returns true if any feature is enabled.
|
||||
*/
|
||||
bool
|
||||
isLocalControlHeaderEnabled() const;
|
||||
|
||||
/** \brief get whether a specific LocalControlHeader feature is enabled
|
||||
*
|
||||
* \param feature The feature.
|
||||
* \returns true if the specified feature is enabled.
|
||||
*/
|
||||
bool
|
||||
isLocalControlHeaderEnabled(LocalControlFeature feature) const;
|
||||
|
||||
/** \brief enable or disable a LocalControlHeader feature
|
||||
*
|
||||
* \param feature The feature. Cannot be LOCAL_CONTROL_FEATURE_ANY
|
||||
* or LOCAL_CONTROL_FEATURE_MAX
|
||||
* \param enabled true/false enable/disable the feature
|
||||
*/
|
||||
void
|
||||
setLocalControlHeaderFeature(LocalControlFeature feature, bool enabled = true);
|
||||
|
||||
public:
|
||||
|
||||
static const size_t LOCAL_CONTROL_FEATURE_MAX = 3; /// upper bound of LocalControlFeature enum
|
||||
static const size_t LOCAL_CONTROL_FEATURE_ANY = 0; /// any feature
|
||||
|
||||
protected:
|
||||
// statically overridden from Face
|
||||
|
||||
/** \brief Decode block into Interest/Data, considering potential LocalControlHeader
|
||||
*
|
||||
* If LocalControlHeader is present, the encoded data is filtered out, based
|
||||
* on enabled features on the face.
|
||||
*/
|
||||
bool
|
||||
decodeAndDispatchInput(const Block& element);
|
||||
|
||||
// LocalFace-specific methods
|
||||
|
||||
/** \brief Check if LocalControlHeader needs to be included, taking into account
|
||||
* both set parameters in supplied LocalControlHeader and features
|
||||
* enabled on the local face.
|
||||
*/
|
||||
bool
|
||||
isEmptyFilteredLocalControlHeader(const ndn::nfd::LocalControlHeader& header) const;
|
||||
|
||||
/** \brief Create LocalControlHeader, considering enabled features
|
||||
*/
|
||||
template<class Packet>
|
||||
Block
|
||||
filterAndEncodeLocalControlHeader(const Packet& packet);
|
||||
|
||||
private:
|
||||
std::vector<bool> m_localControlHeaderFeatures;
|
||||
};
|
||||
|
||||
inline
|
||||
LocalFace::LocalFace(const FaceUri& remoteUri, const FaceUri& localUri)
|
||||
: Face(remoteUri, localUri, true)
|
||||
, m_localControlHeaderFeatures(LocalFace::LOCAL_CONTROL_FEATURE_MAX)
|
||||
{
|
||||
}
|
||||
|
||||
inline bool
|
||||
LocalFace::isLocalControlHeaderEnabled() const
|
||||
{
|
||||
return m_localControlHeaderFeatures[LOCAL_CONTROL_FEATURE_ANY];
|
||||
}
|
||||
|
||||
inline bool
|
||||
LocalFace::isLocalControlHeaderEnabled(LocalControlFeature feature) const
|
||||
{
|
||||
BOOST_ASSERT(0 < feature &&
|
||||
static_cast<size_t>(feature) < m_localControlHeaderFeatures.size());
|
||||
return m_localControlHeaderFeatures[feature];
|
||||
}
|
||||
|
||||
inline void
|
||||
LocalFace::setLocalControlHeaderFeature(LocalControlFeature feature, bool enabled/* = true*/)
|
||||
{
|
||||
BOOST_ASSERT(0 < feature &&
|
||||
static_cast<size_t>(feature) < m_localControlHeaderFeatures.size());
|
||||
|
||||
m_localControlHeaderFeatures[feature] = enabled;
|
||||
|
||||
m_localControlHeaderFeatures[LOCAL_CONTROL_FEATURE_ANY] =
|
||||
std::find(m_localControlHeaderFeatures.begin() + 1,
|
||||
m_localControlHeaderFeatures.end(), true) <
|
||||
m_localControlHeaderFeatures.end();
|
||||
// 'find(..) < .end()' instead of 'find(..) != .end()' due to LLVM Bug 16816
|
||||
}
|
||||
|
||||
inline bool
|
||||
LocalFace::decodeAndDispatchInput(const Block& element)
|
||||
{
|
||||
try {
|
||||
const Block& payload = ndn::nfd::LocalControlHeader::getPayload(element);
|
||||
|
||||
// If received LocalControlHeader, but it is not enabled on the face
|
||||
if ((&payload != &element) && !this->isLocalControlHeaderEnabled())
|
||||
return false;
|
||||
|
||||
if (payload.type() == tlv::Interest)
|
||||
{
|
||||
shared_ptr<Interest> i = make_shared<Interest>();
|
||||
i->wireDecode(payload);
|
||||
if (&payload != &element)
|
||||
{
|
||||
uint8_t mask = 0;
|
||||
if (this->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID)) {
|
||||
mask |= ndn::nfd::LocalControlHeader::ENCODE_NEXT_HOP;
|
||||
}
|
||||
i->getLocalControlHeader().wireDecode(element, mask);
|
||||
}
|
||||
|
||||
this->emitSignal(onReceiveInterest, *i);
|
||||
}
|
||||
else if (payload.type() == tlv::Data)
|
||||
{
|
||||
shared_ptr<Data> d = make_shared<Data>();
|
||||
d->wireDecode(payload);
|
||||
|
||||
/// \todo Uncomment and correct the following when we have more
|
||||
/// options in LocalControlHeader that apply for incoming
|
||||
/// Data packets (if ever)
|
||||
// if (&payload != &element)
|
||||
// {
|
||||
//
|
||||
// d->getLocalControlHeader().wireDecode(element,
|
||||
// false,
|
||||
// false);
|
||||
// }
|
||||
|
||||
this->emitSignal(onReceiveData, *d);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (const tlv::Error&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
LocalFace::isEmptyFilteredLocalControlHeader(const ndn::nfd::LocalControlHeader& header) const
|
||||
{
|
||||
if (!this->isLocalControlHeaderEnabled())
|
||||
return true;
|
||||
|
||||
uint8_t mask = 0;
|
||||
if (this->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID)) {
|
||||
mask |= ndn::nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID;
|
||||
}
|
||||
return header.empty(mask);
|
||||
}
|
||||
|
||||
template<class Packet>
|
||||
inline Block
|
||||
LocalFace::filterAndEncodeLocalControlHeader(const Packet& packet)
|
||||
{
|
||||
uint8_t mask = 0;
|
||||
if (this->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID)) {
|
||||
mask |= ndn::nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID;
|
||||
}
|
||||
return packet.getLocalControlHeader().wireEncode(packet, mask);
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_LOCAL_FACE_HPP
|
||||
@@ -1,102 +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/>.
|
||||
*/
|
||||
|
||||
#include "lp-face-wrapper.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
LpFaceWrapper::LpFaceWrapper(unique_ptr<LpFace> face)
|
||||
: Face(face->getRemoteUri(), face->getLocalUri(),
|
||||
face->getScope() == ndn::nfd::FACE_SCOPE_LOCAL,
|
||||
face->getLinkType() == ndn::nfd::LINK_TYPE_MULTI_ACCESS)
|
||||
, m_face(std::move(face))
|
||||
{
|
||||
this->Face::setPersistency(m_face->getPersistency());
|
||||
m_face->afterReceiveInterest.connect(bind(&LpFaceWrapper::dispatchInterest, this, _1));
|
||||
m_face->afterReceiveData.connect(bind(&LpFaceWrapper::dispatchData, this, _1));
|
||||
m_face->afterReceiveNack.connect(bind(&LpFaceWrapper::dispatchNack, this, _1));
|
||||
m_face->afterStateChange.connect(bind(&LpFaceWrapper::handleStateChange, this, _1, _2));
|
||||
}
|
||||
|
||||
void
|
||||
LpFaceWrapper::setPersistency(ndn::nfd::FacePersistency persistency)
|
||||
{
|
||||
this->Face::setPersistency(persistency);
|
||||
m_face->setPersistency(persistency);
|
||||
}
|
||||
|
||||
void
|
||||
LpFaceWrapper::setId(nfd::FaceId faceId)
|
||||
{
|
||||
this->Face::setId(faceId);
|
||||
|
||||
FaceId lpId = static_cast<FaceId>(faceId);
|
||||
if (faceId == nfd::INVALID_FACEID) {
|
||||
lpId = INVALID_FACEID;
|
||||
}
|
||||
m_face->setId(lpId);
|
||||
}
|
||||
|
||||
void
|
||||
LpFaceWrapper::dispatchInterest(const Interest& interest)
|
||||
{
|
||||
this->emitSignal(onReceiveInterest, interest);
|
||||
}
|
||||
|
||||
void
|
||||
LpFaceWrapper::dispatchData(const Data& data)
|
||||
{
|
||||
this->emitSignal(onReceiveData, data);
|
||||
}
|
||||
|
||||
void
|
||||
LpFaceWrapper::dispatchNack(const ndn::lp::Nack& nack)
|
||||
{
|
||||
this->emitSignal(onReceiveNack, nack);
|
||||
}
|
||||
|
||||
void
|
||||
LpFaceWrapper::handleStateChange(FaceState oldState, FaceState newState)
|
||||
{
|
||||
if (newState != FaceState::CLOSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (oldState) {
|
||||
case FaceState::CLOSING:
|
||||
this->fail("LpFace closed");
|
||||
break;
|
||||
case FaceState::FAILED:
|
||||
this->fail("LpFace failed");
|
||||
break;
|
||||
default:
|
||||
BOOST_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -1,140 +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_DAEMON_FACE_LP_FACE_WRAPPER_HPP
|
||||
#define NFD_DAEMON_FACE_LP_FACE_WRAPPER_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "face.hpp"
|
||||
#include "lp-face.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief an adaptor to provide old Face APIs from an LpFace
|
||||
* \sa LpFace
|
||||
* \note When LpFace is adapted by LpFaceWrapper,
|
||||
* FaceId and counters will come from old Face rather than LpFace.
|
||||
*/
|
||||
class LpFaceWrapper : public Face
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
LpFaceWrapper(unique_ptr<LpFace> face);
|
||||
|
||||
LpFace*
|
||||
getLpFace();
|
||||
|
||||
virtual void
|
||||
sendInterest(const Interest& interest) DECL_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
sendData(const Data& data) DECL_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
sendNack(const lp::Nack& nack) DECL_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
close() DECL_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
isUp() const DECL_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
setPersistency(ndn::nfd::FacePersistency persistency) DECL_OVERRIDE;
|
||||
|
||||
virtual const FaceCounters&
|
||||
getCounters() const DECL_OVERRIDE;
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
setId(nfd::FaceId faceId) DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
void
|
||||
dispatchInterest(const Interest& interest);
|
||||
|
||||
void
|
||||
dispatchData(const Data& data);
|
||||
|
||||
void
|
||||
dispatchNack(const lp::Nack& nack);
|
||||
|
||||
void
|
||||
handleStateChange(FaceState oldState, FaceState newState);
|
||||
|
||||
private:
|
||||
unique_ptr<LpFace> m_face;
|
||||
};
|
||||
|
||||
inline LpFace*
|
||||
LpFaceWrapper::getLpFace()
|
||||
{
|
||||
return m_face.get();
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFaceWrapper::sendInterest(const Interest& interest)
|
||||
{
|
||||
this->emitSignal(onSendInterest, interest);
|
||||
m_face->sendInterest(interest);
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFaceWrapper::sendData(const Data& data)
|
||||
{
|
||||
this->emitSignal(onSendData, data);
|
||||
m_face->sendData(data);
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFaceWrapper::sendNack(const lp::Nack& nack)
|
||||
{
|
||||
this->emitSignal(onSendNack, nack);
|
||||
m_face->sendNack(nack);
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFaceWrapper::close()
|
||||
{
|
||||
m_face->close();
|
||||
}
|
||||
|
||||
inline bool
|
||||
LpFaceWrapper::isUp() const
|
||||
{
|
||||
return m_face->getState() == FaceState::UP;
|
||||
}
|
||||
|
||||
inline const FaceCounters&
|
||||
LpFaceWrapper::getCounters() const
|
||||
{
|
||||
return m_face->getCounters();
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_LP_FACE_WRAPPER_HPP
|
||||
@@ -1,311 +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_DAEMON_LP_FACE_HPP
|
||||
#define NFD_DAEMON_LP_FACE_HPP
|
||||
|
||||
#include "transport.hpp"
|
||||
#include "link-service.hpp"
|
||||
#include "face-log.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief identifies a face
|
||||
*/
|
||||
typedef uint64_t FaceId;
|
||||
|
||||
/// indicates an invalid FaceId
|
||||
const FaceId INVALID_FACEID = 0;
|
||||
/// identifies the InternalFace used in management
|
||||
const FaceId FACEID_INTERNAL_FACE = 1;
|
||||
/// identifies a packet comes from the ContentStore, in LocalControlHeader incomingFaceId
|
||||
const FaceId FACEID_CONTENT_STORE = 254;
|
||||
/// identifies the NullFace that drops every packet
|
||||
const FaceId FACEID_NULL = 255;
|
||||
/// upper bound of reserved FaceIds
|
||||
const FaceId FACEID_RESERVED_MAX = 255;
|
||||
|
||||
/** \brief indicates the state of a face
|
||||
*/
|
||||
typedef TransportState FaceState;
|
||||
|
||||
/** \brief generalization of a network interface
|
||||
*
|
||||
* A face generalizes a network interface.
|
||||
* It provides network-layer packet delivery services on a physical interface,
|
||||
* an overlay tunnel, or a link to a local application, with best-effort.
|
||||
*
|
||||
* A face combines two parts: LinkService and Transport.
|
||||
* Transport is the lower part, which provides TLV block delivery services with best-effort.
|
||||
* LinkService is the upper part, which translates between network-layer packets
|
||||
* and TLV blocks, and may provide additional services such as fragmentation and reassembly.
|
||||
*
|
||||
* We are in the process of refactoring face system to use this LinkService+Transport
|
||||
* architecture. During this process, the "face" is named LpFace, and we implement a
|
||||
* LpFaceWrapper class as an adaptor to the old Face APIs. After the completion of refactoring,
|
||||
* LpFace will be renamed to Face.
|
||||
*/
|
||||
class LpFace
|
||||
#ifndef WITH_TESTS
|
||||
DECL_CLASS_FINAL
|
||||
#endif
|
||||
: noncopyable
|
||||
{
|
||||
public:
|
||||
LpFace(unique_ptr<LinkService> service, unique_ptr<Transport> transport);
|
||||
|
||||
LinkService*
|
||||
getLinkService();
|
||||
|
||||
Transport*
|
||||
getTransport();
|
||||
|
||||
public: // upper interface connected to forwarding
|
||||
/** \brief sends Interest on Face
|
||||
*/
|
||||
void
|
||||
sendInterest(const Interest& interest);
|
||||
|
||||
/** \brief sends Data on Face
|
||||
*/
|
||||
void
|
||||
sendData(const Data& data);
|
||||
|
||||
/** \brief sends Nack on Face
|
||||
*/
|
||||
void
|
||||
sendNack(const lp::Nack& nack);
|
||||
|
||||
/** \brief signals on Interest received
|
||||
*/
|
||||
signal::Signal<LinkService, Interest>& afterReceiveInterest;
|
||||
|
||||
/** \brief signals on Data received
|
||||
*/
|
||||
signal::Signal<LinkService, Data>& afterReceiveData;
|
||||
|
||||
/** \brief signals on Nack received
|
||||
*/
|
||||
signal::Signal<LinkService, lp::Nack>& afterReceiveNack;
|
||||
|
||||
public: // static properties
|
||||
/** \return face ID
|
||||
*/
|
||||
FaceId
|
||||
getId() const;
|
||||
|
||||
/** \brief sets face ID
|
||||
* \note Normally, this should only be invoked by FaceTable.
|
||||
*/
|
||||
void
|
||||
setId(FaceId id);
|
||||
|
||||
/** \return a FaceUri representing local endpoint
|
||||
*/
|
||||
FaceUri
|
||||
getLocalUri() const;
|
||||
|
||||
/** \return a FaceUri representing remote endpoint
|
||||
*/
|
||||
FaceUri
|
||||
getRemoteUri() const;
|
||||
|
||||
/** \return whether face is local or non-local for scope control purpose
|
||||
*/
|
||||
ndn::nfd::FaceScope
|
||||
getScope() const;
|
||||
|
||||
/** \return face persistency setting
|
||||
*/
|
||||
ndn::nfd::FacePersistency
|
||||
getPersistency() const;
|
||||
|
||||
/** \brief changes face persistency setting
|
||||
*/
|
||||
void
|
||||
setPersistency(ndn::nfd::FacePersistency persistency);
|
||||
|
||||
/** \return whether face is point-to-point or multi-access
|
||||
*/
|
||||
ndn::nfd::LinkType
|
||||
getLinkType() const;
|
||||
|
||||
public: // dynamic properties
|
||||
/** \return face state
|
||||
*/
|
||||
FaceState
|
||||
getState() const;
|
||||
|
||||
/** \brief signals after face state changed
|
||||
*/
|
||||
signal::Signal<Transport, FaceState/*old*/, FaceState/*new*/>& afterStateChange;
|
||||
|
||||
/** \brief request the face to be closed
|
||||
*
|
||||
* This operation is effective only if face is in UP or DOWN state,
|
||||
* otherwise it has no effect.
|
||||
* The face changes state to CLOSING, and performs cleanup procedure.
|
||||
* The state will be changed to CLOSED when cleanup is complete, which may
|
||||
* happen synchronously or asynchronously.
|
||||
*
|
||||
* \warning the face must not be deallocated until its state changes to CLOSED
|
||||
*/
|
||||
void
|
||||
close();
|
||||
|
||||
const FaceCounters&
|
||||
getCounters() const;
|
||||
|
||||
FaceCounters&
|
||||
getMutableCounters();
|
||||
|
||||
private:
|
||||
FaceId m_id;
|
||||
unique_ptr<LinkService> m_service;
|
||||
unique_ptr<Transport> m_transport;
|
||||
FaceCounters m_counters;
|
||||
};
|
||||
|
||||
inline LinkService*
|
||||
LpFace::getLinkService()
|
||||
{
|
||||
return m_service.get();
|
||||
}
|
||||
|
||||
inline Transport*
|
||||
LpFace::getTransport()
|
||||
{
|
||||
return m_transport.get();
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFace::sendInterest(const Interest& interest)
|
||||
{
|
||||
m_service->sendInterest(interest);
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFace::sendData(const Data& data)
|
||||
{
|
||||
m_service->sendData(data);
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFace::sendNack(const lp::Nack& nack)
|
||||
{
|
||||
m_service->sendNack(nack);
|
||||
}
|
||||
|
||||
inline FaceId
|
||||
LpFace::getId() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFace::setId(FaceId id)
|
||||
{
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
inline FaceUri
|
||||
LpFace::getLocalUri() const
|
||||
{
|
||||
return m_transport->getLocalUri();
|
||||
}
|
||||
|
||||
inline FaceUri
|
||||
LpFace::getRemoteUri() const
|
||||
{
|
||||
return m_transport->getRemoteUri();
|
||||
}
|
||||
|
||||
inline ndn::nfd::FaceScope
|
||||
LpFace::getScope() const
|
||||
{
|
||||
return m_transport->getScope();
|
||||
}
|
||||
|
||||
inline ndn::nfd::FacePersistency
|
||||
LpFace::getPersistency() const
|
||||
{
|
||||
return m_transport->getPersistency();
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFace::setPersistency(ndn::nfd::FacePersistency persistency)
|
||||
{
|
||||
return m_transport->setPersistency(persistency);
|
||||
}
|
||||
|
||||
inline ndn::nfd::LinkType
|
||||
LpFace::getLinkType() const
|
||||
{
|
||||
return m_transport->getLinkType();
|
||||
}
|
||||
|
||||
inline FaceState
|
||||
LpFace::getState() const
|
||||
{
|
||||
return m_transport->getState();
|
||||
}
|
||||
|
||||
inline void
|
||||
LpFace::close()
|
||||
{
|
||||
m_transport->close();
|
||||
}
|
||||
|
||||
inline const FaceCounters&
|
||||
LpFace::getCounters() const
|
||||
{
|
||||
return m_counters;
|
||||
}
|
||||
|
||||
inline FaceCounters&
|
||||
LpFace::getMutableCounters()
|
||||
{
|
||||
return m_counters;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_base_of<LpFace, T>::value, std::ostream&>::type
|
||||
operator<<(std::ostream& os, const FaceLogHelper<T>& flh)
|
||||
{
|
||||
const LpFace& face = flh.obj;
|
||||
os << "[id=" << face.getId() << ",local=" << face.getLocalUri() <<
|
||||
",remote=" << face.getRemoteUri() << "] ";
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
|
||||
// using face::FaceId; // TODO uncomment in #3172
|
||||
using face::LpFace;
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_LP_FACE_HPP
|
||||
@@ -0,0 +1,162 @@
|
||||
/* -*- 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/>.
|
||||
*/
|
||||
|
||||
#include "lp-fragmenter.hpp"
|
||||
#include "link-service.hpp"
|
||||
#include <ndn-cxx/encoding/tlv.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INIT("LpFragmenter");
|
||||
|
||||
static_assert(lp::tlv::LpPacket < 253, "LpPacket TLV-TYPE must fit in 1 octet");
|
||||
static_assert(lp::tlv::Sequence < 253, "Sequence TLV-TYPE must fit in 1 octet");
|
||||
static_assert(lp::tlv::FragIndex < 253, "FragIndex TLV-TYPE must fit in 1 octet");
|
||||
static_assert(lp::tlv::FragCount < 253, "FragCount TLV-TYPE must fit in 1 octet");
|
||||
static_assert(lp::tlv::Fragment < 253, "Fragment TLV-TYPE must fit in 1 octet");
|
||||
|
||||
/** \brief maximum overhead on a single fragment,
|
||||
* not counting other NDNLPv2 headers
|
||||
*/
|
||||
static const size_t MAX_SINGLE_FRAG_OVERHEAD =
|
||||
1 + 9 + // LpPacket TLV-TYPE and TLV-LENGTH
|
||||
1 + 1 + 8 + // Sequence TLV
|
||||
1 + 9; // Fragment TLV-TYPE and TLV-LENGTH
|
||||
|
||||
/** \brief maximum overhead of adding fragmentation to payload,
|
||||
* not counting other NDNLPv2 headers
|
||||
*/
|
||||
static const size_t MAX_FRAG_OVERHEAD =
|
||||
1 + 9 + // LpPacket TLV-TYPE and TLV-LENGTH
|
||||
1 + 1 + 8 + // Sequence TLV
|
||||
1 + 1 + 8 + // FragIndex TLV
|
||||
1 + 1 + 8 + // FragCount TLV
|
||||
1 + 9; // Fragment TLV-TYPE and TLV-LENGTH
|
||||
|
||||
LpFragmenter::Options::Options()
|
||||
: nMaxFragments(400)
|
||||
{
|
||||
}
|
||||
|
||||
LpFragmenter::LpFragmenter(const LpFragmenter::Options& options, const LinkService* linkService)
|
||||
: m_options(options)
|
||||
, m_linkService(linkService)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
LpFragmenter::setOptions(const Options& options)
|
||||
{
|
||||
m_options = options;
|
||||
}
|
||||
|
||||
const LinkService*
|
||||
LpFragmenter::getLinkService() const
|
||||
{
|
||||
return m_linkService;
|
||||
}
|
||||
|
||||
std::tuple<bool, std::vector<lp::Packet>>
|
||||
LpFragmenter::fragmentPacket(const lp::Packet& packet, size_t mtu)
|
||||
{
|
||||
BOOST_ASSERT(packet.has<lp::FragmentField>());
|
||||
BOOST_ASSERT(!packet.has<lp::FragIndexField>());
|
||||
BOOST_ASSERT(!packet.has<lp::FragCountField>());
|
||||
|
||||
if (MAX_SINGLE_FRAG_OVERHEAD + packet.wireEncode().size() <= mtu) {
|
||||
// fast path: fragmentation not needed
|
||||
// To qualify for fast path, the packet must have space for adding a sequence number,
|
||||
// because another NDNLPv2 feature may require the sequence number.
|
||||
return std::make_tuple(true, std::vector<lp::Packet>{packet});
|
||||
}
|
||||
|
||||
ndn::Buffer::const_iterator netPktBegin, netPktEnd;
|
||||
std::tie(netPktBegin, netPktEnd) = packet.get<lp::FragmentField>();
|
||||
size_t netPktSize = std::distance(netPktBegin, netPktEnd);
|
||||
|
||||
// compute size of other NDNLPv2 headers to be placed on the first fragment
|
||||
size_t firstHeaderSize = 0;
|
||||
const Block& packetWire = packet.wireEncode();
|
||||
if (packetWire.type() == lp::tlv::LpPacket) {
|
||||
for (const Block& element : packetWire.elements()) {
|
||||
if (element.type() != lp::tlv::Fragment) {
|
||||
firstHeaderSize += element.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// compute payload size
|
||||
if (MAX_FRAG_OVERHEAD + firstHeaderSize + 1 > mtu) { // 1-octet fragment
|
||||
NFD_LOG_FACE_WARN("fragmentation error, MTU too small for first fragment: DROP");
|
||||
return std::make_tuple(false, std::vector<lp::Packet>{});
|
||||
}
|
||||
size_t firstPayloadSize = std::min(netPktSize, mtu - firstHeaderSize - MAX_FRAG_OVERHEAD);
|
||||
size_t payloadSize = mtu - MAX_FRAG_OVERHEAD;
|
||||
size_t fragCount = 1 + ((netPktSize - firstPayloadSize) / payloadSize) +
|
||||
((netPktSize - firstPayloadSize) % payloadSize != 0);
|
||||
|
||||
// compute FragCount
|
||||
if (fragCount > m_options.nMaxFragments) {
|
||||
NFD_LOG_FACE_WARN("fragmentation error, FragCount over limit: DROP");
|
||||
return std::make_pair(false, std::vector<lp::Packet>{});
|
||||
}
|
||||
|
||||
// populate fragments
|
||||
std::vector<lp::Packet> frags(fragCount);
|
||||
frags.front() = packet; // copy input packet to preserve other NDNLPv2 fields
|
||||
size_t fragIndex = 0;
|
||||
auto fragBegin = netPktBegin,
|
||||
fragEnd = fragBegin + firstPayloadSize;
|
||||
while (fragBegin < netPktEnd) {
|
||||
lp::Packet& frag = frags[fragIndex];
|
||||
frag.add<lp::FragIndexField>(fragIndex);
|
||||
frag.add<lp::FragCountField>(fragCount);
|
||||
frag.set<lp::FragmentField>(std::make_pair(fragBegin, fragEnd));
|
||||
BOOST_ASSERT(frag.wireEncode().size() <= mtu);
|
||||
|
||||
++fragIndex;
|
||||
fragBegin = fragEnd;
|
||||
fragEnd = std::min(netPktEnd, fragBegin + payloadSize);
|
||||
}
|
||||
BOOST_ASSERT(fragIndex == fragCount);
|
||||
|
||||
return std::make_pair(true, frags);
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const FaceLogHelper<LpFragmenter>& flh)
|
||||
{
|
||||
if (flh.obj.getLinkService() == nullptr) {
|
||||
os << "[id=0,local=unknown,remote=unknown] ";
|
||||
}
|
||||
else {
|
||||
os << FaceLogHelper<LinkService>(*flh.obj.getLinkService());
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,92 @@
|
||||
/* -*- 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_DAEMON_FACE_LP_FRAGMENTER_HPP
|
||||
#define NFD_DAEMON_FACE_LP_FRAGMENTER_HPP
|
||||
|
||||
#include "face-log.hpp"
|
||||
|
||||
#include <ndn-cxx/lp/packet.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
class LinkService;
|
||||
|
||||
/** \brief fragments network-layer packets into NDNLPv2 link-layer packets
|
||||
* \sa http://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
|
||||
*/
|
||||
class LpFragmenter
|
||||
{
|
||||
public:
|
||||
/** \brief Options that control the behavior of LpFragmenter
|
||||
*/
|
||||
class Options
|
||||
{
|
||||
public:
|
||||
Options();
|
||||
|
||||
public:
|
||||
/** \brief maximum number of fragments in a packet
|
||||
*/
|
||||
size_t nMaxFragments;
|
||||
};
|
||||
|
||||
explicit
|
||||
LpFragmenter(const Options& options = Options(), const LinkService* linkService = nullptr);
|
||||
|
||||
/** \brief set options for fragmenter
|
||||
*/
|
||||
void
|
||||
setOptions(const Options& options);
|
||||
|
||||
/** \return LinkService that owns this instance
|
||||
*
|
||||
* This is only used for logging, and may be nullptr.
|
||||
*/
|
||||
const LinkService*
|
||||
getLinkService() const;
|
||||
|
||||
/** \brief fragments a network-layer packet into link-layer packets
|
||||
* \param packet an LpPacket that contains a network-layer packet;
|
||||
* must have Fragment field, must not have FragIndex and FragCount fields
|
||||
* \param mtu maximum allowable LpPacket size after fragmentation and sequence number assignment
|
||||
* \return whether fragmentation succeeded, fragmented packets without sequence number
|
||||
*/
|
||||
std::tuple<bool, std::vector<lp::Packet>>
|
||||
fragmentPacket(const lp::Packet& packet, size_t mtu);
|
||||
|
||||
private:
|
||||
Options m_options;
|
||||
const LinkService* m_linkService;
|
||||
};
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const FaceLogHelper<LpFragmenter>& flh);
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_LP_FRAGMENTER_HPP
|
||||
@@ -0,0 +1,176 @@
|
||||
/* -*- 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/>.
|
||||
*/
|
||||
|
||||
#include "lp-reassembler.hpp"
|
||||
#include "link-service.hpp"
|
||||
#include <numeric>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INIT("LpReassembler");
|
||||
|
||||
LpReassembler::Options::Options()
|
||||
: nMaxFragments(400)
|
||||
, reassemblyTimeout(time::milliseconds(500))
|
||||
{
|
||||
}
|
||||
|
||||
LpReassembler::LpReassembler(const LpReassembler::Options& options, const LinkService* linkService)
|
||||
: m_options(options)
|
||||
, m_linkService(linkService)
|
||||
{
|
||||
}
|
||||
|
||||
std::tuple<bool, Block, lp::Packet>
|
||||
LpReassembler::receiveFragment(Transport::EndpointId remoteEndpoint, const lp::Packet& packet)
|
||||
{
|
||||
BOOST_ASSERT(packet.has<lp::FragmentField>());
|
||||
|
||||
static auto FALSE_RETURN = std::make_tuple(false, Block(), lp::Packet());
|
||||
|
||||
// read and check FragIndex and FragCount
|
||||
uint64_t fragIndex = 0;
|
||||
uint64_t fragCount = 1;
|
||||
if (packet.has<lp::FragIndexField>()) {
|
||||
fragIndex = packet.get<lp::FragIndexField>();
|
||||
}
|
||||
if (packet.has<lp::FragCountField>()) {
|
||||
fragCount = packet.get<lp::FragCountField>();
|
||||
}
|
||||
|
||||
if (fragIndex >= fragCount) {
|
||||
NFD_LOG_FACE_WARN("reassembly error, FragIndex>=FragCount: DROP");
|
||||
return FALSE_RETURN;
|
||||
}
|
||||
|
||||
if (fragCount > m_options.nMaxFragments) {
|
||||
NFD_LOG_FACE_WARN("reassembly error, FragCount over limit: DROP");
|
||||
return FALSE_RETURN;
|
||||
}
|
||||
|
||||
// check for fast path
|
||||
if (fragIndex == 0 && fragCount == 1) {
|
||||
ndn::Buffer::const_iterator fragBegin, fragEnd;
|
||||
std::tie(fragBegin, fragEnd) = packet.get<lp::FragmentField>();
|
||||
Block netPkt(&*fragBegin, std::distance(fragBegin, fragEnd));
|
||||
return std::make_tuple(true, netPkt, packet);
|
||||
}
|
||||
|
||||
// check Sequence and compute message identifier
|
||||
if (!packet.has<lp::SequenceField>()) {
|
||||
NFD_LOG_FACE_WARN("reassembly error, Sequence missing: DROP");
|
||||
return FALSE_RETURN;
|
||||
}
|
||||
lp::Sequence messageIdentifier = packet.get<lp::SequenceField>() - fragIndex;
|
||||
Key key = std::make_tuple(remoteEndpoint, messageIdentifier);
|
||||
|
||||
// add to PartialPacket
|
||||
PartialPacket& pp = m_partialPackets[key];
|
||||
if (pp.fragCount == 0) { // new PartialPacket
|
||||
pp.fragCount = fragCount;
|
||||
pp.nReceivedFragments = 0;
|
||||
pp.fragments.resize(fragCount);
|
||||
}
|
||||
else {
|
||||
if (fragCount != pp.fragCount) {
|
||||
NFD_LOG_FACE_WARN("reassembly error, FragCount changed: DROP");
|
||||
return FALSE_RETURN;
|
||||
}
|
||||
}
|
||||
|
||||
if (pp.fragments[fragIndex].has<lp::SequenceField>()) {
|
||||
NFD_LOG_FACE_TRACE("fragment already received: DROP");
|
||||
return FALSE_RETURN;
|
||||
}
|
||||
|
||||
pp.fragments[fragIndex] = packet;
|
||||
++pp.nReceivedFragments;
|
||||
|
||||
// check complete condition
|
||||
if (pp.nReceivedFragments == pp.fragCount) {
|
||||
Block reassembled = doReassembly(key);
|
||||
lp::Packet firstFrag(std::move(pp.fragments[0]));
|
||||
m_partialPackets.erase(key);
|
||||
return std::make_tuple(true, reassembled, firstFrag);
|
||||
}
|
||||
|
||||
// set drop timer
|
||||
pp.dropTimer = scheduler::schedule(m_options.reassemblyTimeout,
|
||||
bind(&LpReassembler::timeoutPartialPacket, this, key));
|
||||
|
||||
return FALSE_RETURN;
|
||||
}
|
||||
|
||||
Block
|
||||
LpReassembler::doReassembly(const Key& key)
|
||||
{
|
||||
PartialPacket& pp = m_partialPackets[key];
|
||||
|
||||
size_t payloadSize = std::accumulate(pp.fragments.begin(), pp.fragments.end(), 0,
|
||||
[&] (size_t sum, const lp::Packet& pkt) -> size_t {
|
||||
ndn::Buffer::const_iterator fragBegin, fragEnd;
|
||||
std::tie(fragBegin, fragEnd) = pkt.get<lp::FragmentField>();
|
||||
return sum + std::distance(fragBegin, fragEnd);
|
||||
});
|
||||
|
||||
ndn::Buffer fragBuffer(payloadSize);
|
||||
ndn::Buffer::iterator it = fragBuffer.begin();
|
||||
|
||||
for (const lp::Packet& frag : pp.fragments) {
|
||||
ndn::Buffer::const_iterator fragBegin, fragEnd;
|
||||
std::tie(fragBegin, fragEnd) = frag.get<lp::FragmentField>();
|
||||
it = std::copy(fragBegin, fragEnd, it);
|
||||
}
|
||||
|
||||
return Block(&*(fragBuffer.cbegin()), std::distance(fragBuffer.cbegin(), fragBuffer.cend()));
|
||||
}
|
||||
|
||||
void
|
||||
LpReassembler::timeoutPartialPacket(const Key& key)
|
||||
{
|
||||
auto it = m_partialPackets.find(key);
|
||||
if (it == m_partialPackets.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->beforeTimeout(std::get<0>(key), it->second.nReceivedFragments);
|
||||
m_partialPackets.erase(it);
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const FaceLogHelper<LpReassembler>& flh)
|
||||
{
|
||||
if (flh.obj.getLinkService() == nullptr) {
|
||||
os << "[id=0,local=unknown,remote=unknown] ";
|
||||
}
|
||||
else {
|
||||
os << FaceLogHelper<LinkService>(*flh.obj.getLinkService());
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,160 @@
|
||||
/* -*- 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_DAEMON_FACE_LP_REASSEMBLER_HPP
|
||||
#define NFD_DAEMON_FACE_LP_REASSEMBLER_HPP
|
||||
|
||||
#include "core/scheduler.hpp"
|
||||
#include "face-log.hpp"
|
||||
#include "transport.hpp"
|
||||
|
||||
#include <ndn-cxx/lp/packet.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
class LinkService;
|
||||
|
||||
/** \brief reassembles fragmented network-layer packets
|
||||
* \sa http://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
|
||||
*/
|
||||
class LpReassembler : noncopyable
|
||||
{
|
||||
public:
|
||||
/** \brief Options that control the behavior of LpReassembler
|
||||
*/
|
||||
class Options
|
||||
{
|
||||
public:
|
||||
Options();
|
||||
|
||||
public:
|
||||
/** \brief maximum number of fragments in a packet
|
||||
*
|
||||
* LpPackets with FragCount over this limit are dropped.
|
||||
*/
|
||||
size_t nMaxFragments;
|
||||
|
||||
/** \brief timeout before a partially reassembled packet is dropped
|
||||
*/
|
||||
time::nanoseconds reassemblyTimeout;
|
||||
};
|
||||
|
||||
explicit
|
||||
LpReassembler(const Options& options = Options(), const LinkService* linkService = nullptr);
|
||||
|
||||
/** \brief set options for reassembler
|
||||
*/
|
||||
void
|
||||
setOptions(const Options& options);
|
||||
|
||||
/** \return LinkService that owns this instance
|
||||
*
|
||||
* This is only used for logging, and may be nullptr.
|
||||
*/
|
||||
const LinkService*
|
||||
getLinkService() const;
|
||||
|
||||
/** \brief adds received fragment to buffer
|
||||
* \param remoteEndpoint endpoint whose sends the packet
|
||||
* \param packet received fragment;
|
||||
* must have Fragment field
|
||||
* \return whether network-layer packet has been completely received,
|
||||
* the reassembled network-layer packet,
|
||||
* and the first fragment for inspecting other NDNLPv2 headers
|
||||
* \throw tlv::Error packet is malformed
|
||||
*/
|
||||
std::tuple<bool, Block, lp::Packet>
|
||||
receiveFragment(Transport::EndpointId remoteEndpoint, const lp::Packet& packet);
|
||||
|
||||
/** \brief count of partial packets
|
||||
*/
|
||||
size_t
|
||||
size() const;
|
||||
|
||||
/** \brief signals before a partial packet is dropped due to timeout
|
||||
*
|
||||
* If a partial packet is incomplete and no new fragment is received
|
||||
* within Options::reassemblyTimeout, it would be dropped due to timeout.
|
||||
* Before it's erased, this signal is emitted with the remote endpoint,
|
||||
* and the number of fragments being dropped.
|
||||
*/
|
||||
signal::Signal<LpReassembler, Transport::EndpointId, size_t> beforeTimeout;
|
||||
|
||||
private:
|
||||
/** \brief holds all fragments of packet until reassembled
|
||||
*/
|
||||
struct PartialPacket
|
||||
{
|
||||
std::vector<lp::Packet> fragments;
|
||||
size_t fragCount; ///< total fragments
|
||||
size_t nReceivedFragments; ///< number of received fragments
|
||||
scheduler::ScopedEventId dropTimer;
|
||||
};
|
||||
|
||||
/** \brief index key for PartialPackets
|
||||
*/
|
||||
typedef std::tuple<
|
||||
Transport::EndpointId, // remoteEndpoint
|
||||
lp::Sequence // message identifier (sequence of the first fragment)
|
||||
> Key;
|
||||
|
||||
Block
|
||||
doReassembly(const Key& key);
|
||||
|
||||
void
|
||||
timeoutPartialPacket(const Key& key);
|
||||
|
||||
private:
|
||||
Options m_options;
|
||||
std::map<Key, PartialPacket> m_partialPackets;
|
||||
const LinkService* m_linkService;
|
||||
};
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const FaceLogHelper<LpReassembler>& flh);
|
||||
|
||||
inline void
|
||||
LpReassembler::setOptions(const Options& options)
|
||||
{
|
||||
m_options = options;
|
||||
}
|
||||
|
||||
inline const LinkService*
|
||||
LpReassembler::getLinkService() const
|
||||
{
|
||||
return m_linkService;
|
||||
}
|
||||
|
||||
inline size_t
|
||||
LpReassembler::size() const
|
||||
{
|
||||
return m_partialPackets.size();
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_LP_REASSEMBLER_HPP
|
||||
@@ -50,6 +50,15 @@ 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)
|
||||
{
|
||||
@@ -78,5 +87,16 @@ MulticastUdpTransport::doClose()
|
||||
DatagramTransport::doClose();
|
||||
}
|
||||
|
||||
template<>
|
||||
Transport::EndpointId
|
||||
DatagramTransport<boost::asio::ip::udp, Multicast>::makeEndpointId(const protocol::endpoint& ep)
|
||||
{
|
||||
// IPv6 multicast is not supported
|
||||
BOOST_ASSERT(ep.address().is_v4());
|
||||
|
||||
return (static_cast<uint64_t>(ep.port()) << 32) |
|
||||
static_cast<uint64_t>(ep.address().to_v4().to_ulong());
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -31,10 +31,18 @@
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
// Explicit specialization of makeEndpointId for the UDP multicast case.
|
||||
// Note that this "shall be declared before the first use of the specialization
|
||||
// that would cause an implicit instantiation to take place, in every translation
|
||||
// unit in which such a use occurs".
|
||||
template<>
|
||||
Transport::EndpointId
|
||||
DatagramTransport<boost::asio::ip::udp, Multicast>::makeEndpointId(const protocol::endpoint& ep);
|
||||
|
||||
/**
|
||||
* \brief A Transport that communicates on a UDP multicast group
|
||||
*/
|
||||
class MulticastUdpTransport : public DatagramTransport<boost::asio::ip::udp, Multicast>
|
||||
class MulticastUdpTransport DECL_CLASS_FINAL : public DatagramTransport<boost::asio::ip::udp, Multicast>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -46,14 +54,19 @@ public:
|
||||
*/
|
||||
MulticastUdpTransport(const protocol::endpoint& localEndpoint,
|
||||
const protocol::endpoint& multicastGroup,
|
||||
protocol::socket&& recvSocket, protocol::socket&& sendSocket);
|
||||
protocol::socket&& recvSocket,
|
||||
protocol::socket&& sendSocket);
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
|
||||
|
||||
private:
|
||||
virtual void
|
||||
doSend(Transport::Packet&& packet) DECL_OVERRIDE;
|
||||
doSend(Transport::Packet&& packet) DECL_FINAL;
|
||||
|
||||
virtual void
|
||||
doClose() DECL_OVERRIDE;
|
||||
doClose() DECL_FINAL;
|
||||
|
||||
private:
|
||||
protocol::endpoint m_multicastGroup;
|
||||
|
||||
@@ -1,108 +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/>.
|
||||
*/
|
||||
|
||||
#include "ndnlp-data.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace ndnlp {
|
||||
|
||||
std::tuple<bool, NdnlpData>
|
||||
NdnlpData::fromBlock(const Block& wire)
|
||||
{
|
||||
if (wire.type() != tlv::NdnlpData) {
|
||||
// top element is not NdnlpData
|
||||
return std::make_tuple(false, NdnlpData());
|
||||
}
|
||||
wire.parse();
|
||||
const Block::element_container& elements = wire.elements();
|
||||
if (elements.size() < 2) {
|
||||
// NdnlpData element has incorrect number of children
|
||||
return std::make_tuple(false, NdnlpData());
|
||||
}
|
||||
|
||||
NdnlpData parsed;
|
||||
|
||||
const Block& sequenceElement = elements.front();
|
||||
if (sequenceElement.type() != tlv::NdnlpSequence) {
|
||||
// NdnlpSequence element is missing
|
||||
return std::make_tuple(false, NdnlpData());
|
||||
}
|
||||
if (sequenceElement.value_size() != sizeof(uint64_t)) {
|
||||
// NdnlpSequence element has incorrect length
|
||||
return std::make_tuple(false, NdnlpData());
|
||||
}
|
||||
parsed.seq = be64toh(*reinterpret_cast<const uint64_t*>(&*sequenceElement.value_begin()));
|
||||
|
||||
const Block& payloadElement = elements.back();
|
||||
if (payloadElement.type() != tlv::NdnlpPayload) {
|
||||
// NdnlpPayload element is missing
|
||||
return std::make_tuple(false, NdnlpData());
|
||||
}
|
||||
parsed.payload = payloadElement;
|
||||
|
||||
if (elements.size() == 2) { // single wire packet
|
||||
parsed.fragIndex = 0;
|
||||
parsed.fragCount = 1;
|
||||
return std::make_tuple(true, parsed);
|
||||
}
|
||||
if (elements.size() != 4) {
|
||||
// NdnlpData element has incorrect number of children
|
||||
return std::make_tuple(false, NdnlpData());
|
||||
}
|
||||
|
||||
const Block& fragIndexElement = elements.at(1);
|
||||
if (fragIndexElement.type() != tlv::NdnlpFragIndex) {
|
||||
// NdnlpFragIndex element is missing
|
||||
return std::make_tuple(false, NdnlpData());
|
||||
}
|
||||
uint64_t fragIndex = ndn::readNonNegativeInteger(fragIndexElement);
|
||||
if (fragIndex > std::numeric_limits<uint16_t>::max()) {
|
||||
// NdnlpFragIndex is too large
|
||||
return std::make_tuple(false, NdnlpData());
|
||||
}
|
||||
parsed.fragIndex = static_cast<uint16_t>(fragIndex);
|
||||
|
||||
const Block& fragCountElement = elements.at(2);
|
||||
if (fragCountElement.type() != tlv::NdnlpFragCount) {
|
||||
// NdnlpFragCount element is missing
|
||||
return std::make_tuple(false, NdnlpData());
|
||||
}
|
||||
uint64_t fragCount = ndn::readNonNegativeInteger(fragCountElement);
|
||||
if (fragCount > std::numeric_limits<uint16_t>::max()) {
|
||||
// NdnlpFragCount is too large
|
||||
return std::make_tuple(false, NdnlpData());
|
||||
}
|
||||
parsed.fragCount = static_cast<uint16_t>(fragCount);
|
||||
|
||||
if (parsed.fragIndex >= parsed.fragCount) {
|
||||
// NdnlpFragIndex must be less than NdnlpFragCount
|
||||
return std::make_tuple(false, NdnlpData());
|
||||
}
|
||||
|
||||
return std::make_tuple(true, parsed);
|
||||
}
|
||||
|
||||
} // namespace ndnlp
|
||||
} // namespace nfd
|
||||
@@ -1,152 +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/>.
|
||||
*/
|
||||
|
||||
#include "ndnlp-partial-message-store.hpp"
|
||||
#include "core/logger.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace ndnlp {
|
||||
|
||||
NFD_LOG_INIT("NdnlpPartialMessageStore");
|
||||
|
||||
PartialMessage::PartialMessage()
|
||||
: m_fragCount(0)
|
||||
, m_received(0)
|
||||
, m_totalLength(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
PartialMessage::add(uint16_t fragIndex, uint16_t fragCount, const Block& payload)
|
||||
{
|
||||
if (m_received == 0) { // first packet
|
||||
m_fragCount = fragCount;
|
||||
m_payloads.resize(fragCount);
|
||||
}
|
||||
|
||||
if (m_fragCount != fragCount || fragIndex >= m_fragCount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_payloads[fragIndex].empty()) { // duplicate
|
||||
return false;
|
||||
}
|
||||
|
||||
m_payloads[fragIndex] = payload;
|
||||
++m_received;
|
||||
m_totalLength += payload.value_size();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PartialMessage::isComplete() const
|
||||
{
|
||||
return m_received == m_fragCount;
|
||||
}
|
||||
|
||||
std::tuple<bool, Block>
|
||||
PartialMessage::reassemble()
|
||||
{
|
||||
BOOST_ASSERT(this->isComplete());
|
||||
|
||||
ndn::BufferPtr buffer = make_shared<ndn::Buffer>(m_totalLength);
|
||||
ndn::Buffer::iterator buf = buffer->begin();
|
||||
for (const Block& payload : m_payloads) {
|
||||
buf = std::copy(payload.value_begin(), payload.value_end(), buf);
|
||||
}
|
||||
BOOST_ASSERT(buf == buffer->end());
|
||||
|
||||
return Block::fromBuffer(buffer, 0);
|
||||
}
|
||||
|
||||
std::tuple<bool, Block>
|
||||
PartialMessage::reassembleSingle(const NdnlpData& fragment)
|
||||
{
|
||||
BOOST_ASSERT(fragment.fragCount == 1);
|
||||
|
||||
try {
|
||||
return std::make_tuple(true, fragment.payload.blockFromValue());
|
||||
}
|
||||
catch (tlv::Error&) {
|
||||
return std::make_tuple(false, Block());
|
||||
}
|
||||
}
|
||||
|
||||
PartialMessageStore::PartialMessageStore(const time::nanoseconds& idleDuration)
|
||||
: m_idleDuration(idleDuration)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
PartialMessageStore::receive(const NdnlpData& pkt)
|
||||
{
|
||||
bool isReassembled = false;
|
||||
Block reassembled;
|
||||
|
||||
if (pkt.fragCount == 1) { // single fragment
|
||||
std::tie(isReassembled, reassembled) = PartialMessage::reassembleSingle(pkt);
|
||||
}
|
||||
else {
|
||||
uint64_t messageIdentifier = pkt.seq - pkt.fragIndex;
|
||||
PartialMessage& pm = m_partialMessages[messageIdentifier];
|
||||
this->scheduleCleanup(messageIdentifier, pm);
|
||||
|
||||
pm.add(pkt.fragIndex, pkt.fragCount, pkt.payload);
|
||||
|
||||
if (pm.isComplete()) {
|
||||
std::tie(isReassembled, reassembled) = pm.reassemble();
|
||||
m_partialMessages.erase(messageIdentifier);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isReassembled) {
|
||||
NFD_LOG_TRACE(pkt.seq << " reassemble error");
|
||||
return;
|
||||
}
|
||||
|
||||
NFD_LOG_TRACE(pkt.seq << " deliver");
|
||||
this->onReceive(reassembled);
|
||||
}
|
||||
|
||||
void
|
||||
PartialMessageStore::scheduleCleanup(uint64_t messageIdentifier,
|
||||
PartialMessage& partialMessage)
|
||||
{
|
||||
partialMessage.expiry = scheduler::schedule(m_idleDuration,
|
||||
bind(&PartialMessageStore::cleanup, this, messageIdentifier));
|
||||
}
|
||||
|
||||
void
|
||||
PartialMessageStore::cleanup(uint64_t messageIdentifier)
|
||||
{
|
||||
NFD_LOG_TRACE(messageIdentifier << " cleanup");
|
||||
m_partialMessages.erase(messageIdentifier);
|
||||
}
|
||||
|
||||
} // namespace ndnlp
|
||||
} // namespace nfd
|
||||
@@ -1,117 +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_DAEMON_FACE_NDNLP_PARTIAL_MESSAGE_STORE_HPP
|
||||
#define NFD_DAEMON_FACE_NDNLP_PARTIAL_MESSAGE_STORE_HPP
|
||||
|
||||
#include "ndnlp-data.hpp"
|
||||
#include "core/scheduler.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace ndnlp {
|
||||
|
||||
/** \brief represents a partially received message
|
||||
*/
|
||||
class PartialMessage
|
||||
{
|
||||
public:
|
||||
PartialMessage();
|
||||
|
||||
PartialMessage(const PartialMessage&) = delete;
|
||||
|
||||
PartialMessage&
|
||||
operator=(const PartialMessage&) = delete;
|
||||
|
||||
PartialMessage(PartialMessage&&) = default;
|
||||
|
||||
PartialMessage&
|
||||
operator=(PartialMessage&&) = default;
|
||||
|
||||
bool
|
||||
add(uint16_t fragIndex, uint16_t fragCount, const Block& payload);
|
||||
|
||||
bool
|
||||
isComplete() const;
|
||||
|
||||
/** \brief reassemble network layer packet
|
||||
* \pre isComplete() == true
|
||||
* \return whether success, network layer packet
|
||||
*/
|
||||
std::tuple<bool, Block>
|
||||
reassemble();
|
||||
|
||||
/** \brief reassemble network layer packet from a single fragment
|
||||
* \pre fragment.fragCount == 1
|
||||
* \return whether success, network layer packet
|
||||
*/
|
||||
static std::tuple<bool, Block>
|
||||
reassembleSingle(const NdnlpData& fragment);
|
||||
|
||||
public:
|
||||
scheduler::ScopedEventId expiry;
|
||||
|
||||
private:
|
||||
size_t m_fragCount;
|
||||
size_t m_received;
|
||||
std::vector<Block> m_payloads;
|
||||
size_t m_totalLength;
|
||||
};
|
||||
|
||||
/** \brief provides reassembly feature at receiver
|
||||
*/
|
||||
class PartialMessageStore : noncopyable
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
PartialMessageStore(const time::nanoseconds& idleDuration = time::milliseconds(100));
|
||||
|
||||
/** \brief receive a NdnlpData packet
|
||||
*
|
||||
* Reassembly errors will be ignored.
|
||||
*/
|
||||
void
|
||||
receive(const NdnlpData& pkt);
|
||||
|
||||
/** \brief fires when network layer packet is received
|
||||
*/
|
||||
signal::Signal<PartialMessageStore, Block> onReceive;
|
||||
|
||||
private:
|
||||
void
|
||||
scheduleCleanup(uint64_t messageIdentifier, PartialMessage& partialMessage);
|
||||
|
||||
void
|
||||
cleanup(uint64_t messageIdentifier);
|
||||
|
||||
private:
|
||||
std::unordered_map<uint64_t, PartialMessage> m_partialMessages;
|
||||
|
||||
time::nanoseconds m_idleDuration;
|
||||
};
|
||||
|
||||
} // namespace ndnlp
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_NDNLP_PARTIAL_MESSAGE_STORE_HPP
|
||||
@@ -1,50 +0,0 @@
|
||||
/* -*- 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
|
||||
*
|
||||
* 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 "ndnlp-sequence-generator.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace ndnlp {
|
||||
|
||||
SequenceBlock::SequenceBlock(uint64_t start, size_t count)
|
||||
: m_start(start)
|
||||
, m_count(count)
|
||||
{
|
||||
}
|
||||
|
||||
SequenceGenerator::SequenceGenerator()
|
||||
: m_next(0)
|
||||
{
|
||||
}
|
||||
|
||||
SequenceBlock
|
||||
SequenceGenerator::nextBlock(size_t count)
|
||||
{
|
||||
SequenceBlock sb(m_next, count);
|
||||
m_next += count;
|
||||
return sb;
|
||||
}
|
||||
|
||||
} // namespace ndnlp
|
||||
} // namespace nfd
|
||||
@@ -1,90 +0,0 @@
|
||||
/* -*- 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
|
||||
*
|
||||
* 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_NDNLP_SEQUENCE_GENERATOR_HPP
|
||||
#define NFD_DAEMON_FACE_NDNLP_SEQUENCE_GENERATOR_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace ndnlp {
|
||||
|
||||
/** \brief represents a block of sequence numbers
|
||||
*/
|
||||
class SequenceBlock
|
||||
{
|
||||
public:
|
||||
SequenceBlock(uint64_t start, size_t count);
|
||||
|
||||
/** \return{ the pos-th sequence number }
|
||||
*/
|
||||
uint64_t
|
||||
operator[](size_t pos) const;
|
||||
|
||||
size_t
|
||||
count() const;
|
||||
|
||||
private:
|
||||
uint64_t m_start;
|
||||
size_t m_count;
|
||||
};
|
||||
|
||||
inline uint64_t
|
||||
SequenceBlock::operator[](size_t pos) const
|
||||
{
|
||||
if (pos >= m_count)
|
||||
BOOST_THROW_EXCEPTION(std::out_of_range("pos"));
|
||||
return m_start + static_cast<uint64_t>(pos);
|
||||
}
|
||||
|
||||
inline size_t
|
||||
SequenceBlock::count() const
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
/** \class SequenceGenerator
|
||||
* \brief generates sequence numbers
|
||||
*/
|
||||
class SequenceGenerator : noncopyable
|
||||
{
|
||||
public:
|
||||
SequenceGenerator();
|
||||
|
||||
/** \brief generates a block of consecutive sequence numbers
|
||||
*
|
||||
* This block must not overlap with a recent block.
|
||||
*/
|
||||
SequenceBlock
|
||||
nextBlock(size_t count);
|
||||
|
||||
private:
|
||||
/// next sequence number
|
||||
uint64_t m_next;
|
||||
};
|
||||
|
||||
} // namespace ndnlp
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_NDNLP_SEQUENCE_GENERATOR_HPP
|
||||
@@ -1,135 +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/>.
|
||||
*/
|
||||
|
||||
#include "ndnlp-slicer.hpp"
|
||||
|
||||
#include <ndn-cxx/encoding/encoding-buffer.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace ndnlp {
|
||||
|
||||
Slicer::Slicer(size_t mtu)
|
||||
: m_mtu(mtu)
|
||||
{
|
||||
this->estimateOverhead();
|
||||
}
|
||||
|
||||
Slicer::~Slicer()
|
||||
{
|
||||
}
|
||||
|
||||
template<bool T>
|
||||
size_t
|
||||
Slicer::encodeFragment(ndn::EncodingImpl<T>& blk,
|
||||
uint64_t seq, uint16_t fragIndex, uint16_t fragCount,
|
||||
const uint8_t* payload, size_t payloadSize)
|
||||
{
|
||||
size_t totalLength = 0;
|
||||
|
||||
// NdnlpPayload
|
||||
size_t payloadLength = blk.prependByteArray(payload, payloadSize);
|
||||
totalLength += payloadLength;
|
||||
totalLength += blk.prependVarNumber(payloadLength);
|
||||
totalLength += blk.prependVarNumber(tlv::NdnlpPayload);
|
||||
|
||||
bool needFragIndexAndCount = fragCount > 1;
|
||||
if (needFragIndexAndCount) {
|
||||
// NdnlpFragCount
|
||||
size_t fragCountLength = blk.prependNonNegativeInteger(fragCount);
|
||||
totalLength += fragCountLength;
|
||||
totalLength += blk.prependVarNumber(fragCountLength);
|
||||
totalLength += blk.prependVarNumber(tlv::NdnlpFragCount);
|
||||
|
||||
// NdnlpFragIndex
|
||||
size_t fragIndexLength = blk.prependNonNegativeInteger(fragIndex);
|
||||
totalLength += fragIndexLength;
|
||||
totalLength += blk.prependVarNumber(fragIndexLength);
|
||||
totalLength += blk.prependVarNumber(tlv::NdnlpFragIndex);
|
||||
}
|
||||
|
||||
// NdnlpSequence
|
||||
uint64_t sequenceBE = htobe64(seq);
|
||||
size_t sequenceLength = blk.prependByteArray(
|
||||
reinterpret_cast<uint8_t*>(&sequenceBE), sizeof(sequenceBE));
|
||||
totalLength += sequenceLength;
|
||||
totalLength += blk.prependVarNumber(sequenceLength);
|
||||
totalLength += blk.prependVarNumber(tlv::NdnlpSequence);
|
||||
|
||||
// NdnlpData
|
||||
totalLength += blk.prependVarNumber(totalLength);
|
||||
totalLength += blk.prependVarNumber(tlv::NdnlpData);
|
||||
|
||||
return totalLength;
|
||||
}
|
||||
|
||||
void
|
||||
Slicer::estimateOverhead()
|
||||
{
|
||||
// estimate fragment size with all header fields at largest possible size
|
||||
ndn::EncodingEstimator estimator;
|
||||
size_t estimatedSize = this->encodeFragment(estimator,
|
||||
std::numeric_limits<uint64_t>::max(),
|
||||
std::numeric_limits<uint16_t>::max() - 1,
|
||||
std::numeric_limits<uint16_t>::max(),
|
||||
nullptr, m_mtu);
|
||||
|
||||
size_t overhead = estimatedSize - m_mtu; // minus payload length in estimation
|
||||
m_maxPayload = m_mtu - overhead;
|
||||
}
|
||||
|
||||
PacketArray
|
||||
Slicer::slice(const Block& block)
|
||||
{
|
||||
BOOST_ASSERT(block.hasWire());
|
||||
const uint8_t* networkPacket = block.wire();
|
||||
size_t networkPacketSize = block.size();
|
||||
|
||||
uint16_t fragCount = static_cast<uint16_t>(
|
||||
(networkPacketSize / m_maxPayload) +
|
||||
(networkPacketSize % m_maxPayload == 0 ? 0 : 1)
|
||||
);
|
||||
PacketArray pa = make_shared<std::vector<Block>>();
|
||||
pa->reserve(fragCount);
|
||||
SequenceBlock seqBlock = m_seqgen.nextBlock(fragCount);
|
||||
|
||||
for (uint16_t fragIndex = 0; fragIndex < fragCount; ++fragIndex) {
|
||||
size_t payloadOffset = fragIndex * m_maxPayload;
|
||||
const uint8_t* payload = networkPacket + payloadOffset;
|
||||
size_t payloadSize = std::min(m_maxPayload, networkPacketSize - payloadOffset);
|
||||
|
||||
ndn::EncodingBuffer buffer(m_mtu, 0);
|
||||
size_t pktSize = this->encodeFragment(buffer,
|
||||
seqBlock[fragIndex], fragIndex, fragCount, payload, payloadSize);
|
||||
|
||||
BOOST_VERIFY(pktSize <= m_mtu);
|
||||
|
||||
pa->push_back(buffer.block());
|
||||
}
|
||||
|
||||
return pa;
|
||||
}
|
||||
|
||||
} // namespace ndnlp
|
||||
} // namespace nfd
|
||||
+17
-27
@@ -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-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.
|
||||
@@ -24,31 +24,21 @@
|
||||
*/
|
||||
|
||||
#include "null-face.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "internal-transport.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
// FIB might restrict creating a nexthop record toward non-local face in /localhost namespace.
|
||||
// NullFace has isLocal=true to enable creating a "blackhole" FIB entry under /localhost.
|
||||
// FIB could restrict creating a nexthop record toward non-local face in /localhost namespace.
|
||||
// NullFace has scope=local to enable creating a "blackhole" FIB entry under /localhost.
|
||||
|
||||
NullFace::NullFace(const FaceUri& uri)
|
||||
: Face(uri, uri, true)
|
||||
shared_ptr<Face>
|
||||
makeNullFace(const FaceUri& uri)
|
||||
{
|
||||
return make_shared<Face>(make_unique<GenericLinkService>(),
|
||||
make_unique<InternalForwarderTransport>(uri, uri, ndn::nfd::FACE_SCOPE_LOCAL));
|
||||
}
|
||||
|
||||
void
|
||||
NullFace::sendInterest(const Interest& interest)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NullFace::sendData(const Data& data)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NullFace::close()
|
||||
{
|
||||
this->fail("close");
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
+12
-24
@@ -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-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.
|
||||
@@ -29,26 +29,14 @@
|
||||
#include "face.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/**
|
||||
* \brief a Face that has no underlying transport and drops every packet
|
||||
/** \return a Face that has no underlying transport and drops every packet
|
||||
*/
|
||||
class NullFace : public Face
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
NullFace(const FaceUri& uri = FaceUri("null://"));
|
||||
|
||||
void
|
||||
sendInterest(const Interest& interest) DECL_OVERRIDE;
|
||||
|
||||
void
|
||||
sendData(const Data& data) DECL_OVERRIDE;
|
||||
|
||||
void
|
||||
close() DECL_OVERRIDE;
|
||||
};
|
||||
shared_ptr<Face>
|
||||
makeNullFace(const FaceUri& uri = FaceUri("null://"));
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_NULL_FACE_HPP
|
||||
@@ -26,27 +26,11 @@
|
||||
#ifndef NFD_DAEMON_FACE_PROTOCOL_FACTORY_HPP
|
||||
#define NFD_DAEMON_FACE_PROTOCOL_FACTORY_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
#include "channel.hpp"
|
||||
#include <ndn-cxx/encoding/nfd-constants.hpp>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
class Channel;
|
||||
class Face;
|
||||
|
||||
/**
|
||||
* \brief Prototype for the callback that is invoked when the face
|
||||
* is created (as a response to incoming connection or after
|
||||
* connection is established)
|
||||
*/
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Abstract base class for all protocol factories
|
||||
*/
|
||||
|
||||
@@ -1,363 +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_DAEMON_FACE_STREAM_FACE_HPP
|
||||
#define NFD_DAEMON_FACE_STREAM_FACE_HPP
|
||||
|
||||
#include "face.hpp"
|
||||
#include "local-face.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
|
||||
#include <queue>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
// forward declaration
|
||||
template<class T, class U, class V> struct StreamFaceSenderImpl;
|
||||
|
||||
template<class Protocol, class FaceBase = Face>
|
||||
class StreamFace : public FaceBase
|
||||
{
|
||||
public:
|
||||
typedef Protocol protocol;
|
||||
|
||||
StreamFace(const FaceUri& remoteUri, const FaceUri& localUri,
|
||||
typename protocol::socket socket, bool isOnDemand);
|
||||
|
||||
// from FaceBase
|
||||
void
|
||||
sendInterest(const Interest& interest) DECL_OVERRIDE;
|
||||
|
||||
void
|
||||
sendData(const Data& data) DECL_OVERRIDE;
|
||||
|
||||
void
|
||||
close() DECL_OVERRIDE;
|
||||
|
||||
protected:
|
||||
void
|
||||
processErrorCode(const boost::system::error_code& error);
|
||||
|
||||
void
|
||||
sendFromQueue();
|
||||
|
||||
void
|
||||
handleSend(const boost::system::error_code& error,
|
||||
size_t nBytesSent);
|
||||
|
||||
void
|
||||
handleReceive(const boost::system::error_code& error,
|
||||
size_t nBytesReceived);
|
||||
|
||||
void
|
||||
shutdownSocket();
|
||||
|
||||
void
|
||||
deferredClose(const shared_ptr<Face>& face);
|
||||
|
||||
protected:
|
||||
typename protocol::socket m_socket;
|
||||
|
||||
NFD_LOG_INCLASS_DECLARE();
|
||||
|
||||
private:
|
||||
uint8_t m_inputBuffer[ndn::MAX_NDN_PACKET_SIZE];
|
||||
size_t m_inputBufferSize;
|
||||
std::queue<Block> m_sendQueue;
|
||||
|
||||
friend struct StreamFaceSenderImpl<Protocol, FaceBase, Interest>;
|
||||
friend struct StreamFaceSenderImpl<Protocol, FaceBase, Data>;
|
||||
};
|
||||
|
||||
// All inherited classes must use
|
||||
// NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(StreamFace, <specialization-parameter>, "Name");
|
||||
|
||||
|
||||
/** \brief Class allowing validation of the StreamFace use
|
||||
*
|
||||
* For example, partial specialization based on boost::asio::ip::tcp should check
|
||||
* that local endpoint is loopback
|
||||
*
|
||||
* @throws Face::Error if validation failed
|
||||
*/
|
||||
template<class Protocol, class U>
|
||||
struct StreamFaceValidator
|
||||
{
|
||||
static void
|
||||
validateSocket(const typename Protocol::socket& socket)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class T, class FaceBase>
|
||||
inline
|
||||
StreamFace<T, FaceBase>::StreamFace(const FaceUri& remoteUri, const FaceUri& localUri,
|
||||
typename StreamFace::protocol::socket socket, bool isOnDemand)
|
||||
: FaceBase(remoteUri, localUri)
|
||||
, m_socket(std::move(socket))
|
||||
, m_inputBufferSize(0)
|
||||
{
|
||||
NFD_LOG_FACE_INFO("Creating face");
|
||||
|
||||
this->setPersistency(isOnDemand ? ndn::nfd::FACE_PERSISTENCY_ON_DEMAND : ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
|
||||
StreamFaceValidator<T, FaceBase>::validateSocket(m_socket);
|
||||
|
||||
m_socket.async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
|
||||
bind(&StreamFace<T, FaceBase>::handleReceive, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
|
||||
template<class Protocol, class FaceBase, class Packet>
|
||||
struct StreamFaceSenderImpl
|
||||
{
|
||||
static void
|
||||
send(StreamFace<Protocol, FaceBase>& face, const Packet& packet)
|
||||
{
|
||||
bool wasQueueEmpty = face.m_sendQueue.empty();
|
||||
face.m_sendQueue.push(packet.wireEncode());
|
||||
|
||||
if (wasQueueEmpty)
|
||||
face.sendFromQueue();
|
||||
}
|
||||
};
|
||||
|
||||
// partial specialization (only classes can be partially specialized)
|
||||
template<class Protocol, class Packet>
|
||||
struct StreamFaceSenderImpl<Protocol, LocalFace, Packet>
|
||||
{
|
||||
static void
|
||||
send(StreamFace<Protocol, LocalFace>& face, const Packet& packet)
|
||||
{
|
||||
bool wasQueueEmpty = face.m_sendQueue.empty();
|
||||
|
||||
if (!face.isEmptyFilteredLocalControlHeader(packet.getLocalControlHeader()))
|
||||
{
|
||||
face.m_sendQueue.push(face.filterAndEncodeLocalControlHeader(packet));
|
||||
}
|
||||
face.m_sendQueue.push(packet.wireEncode());
|
||||
|
||||
if (wasQueueEmpty)
|
||||
face.sendFromQueue();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
StreamFace<T, U>::sendInterest(const Interest& interest)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
this->emitSignal(onSendInterest, interest);
|
||||
StreamFaceSenderImpl<T, U, Interest>::send(*this, interest);
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
StreamFace<T, U>::sendData(const Data& data)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
this->emitSignal(onSendData, data);
|
||||
StreamFaceSenderImpl<T, U, Data>::send(*this, data);
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
StreamFace<T, U>::close()
|
||||
{
|
||||
if (!m_socket.is_open())
|
||||
return;
|
||||
|
||||
NFD_LOG_FACE_INFO("Closing face");
|
||||
|
||||
shutdownSocket();
|
||||
this->fail("Face closed");
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
StreamFace<T, U>::processErrorCode(const boost::system::error_code& error)
|
||||
{
|
||||
if (error == boost::asio::error::operation_aborted || // when cancel() is called
|
||||
error == boost::asio::error::shut_down) // after shutdown() is called
|
||||
return;
|
||||
|
||||
if (!m_socket.is_open())
|
||||
{
|
||||
this->fail("Connection closed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (error != boost::asio::error::eof)
|
||||
NFD_LOG_FACE_WARN("Send or receive operation failed: " << error.message());
|
||||
|
||||
shutdownSocket();
|
||||
|
||||
if (error == boost::asio::error::eof)
|
||||
this->fail("Connection closed");
|
||||
else
|
||||
this->fail(error.message());
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
StreamFace<T, U>::sendFromQueue()
|
||||
{
|
||||
boost::asio::async_write(m_socket, boost::asio::buffer(m_sendQueue.front()),
|
||||
bind(&StreamFace<T, U>::handleSend, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
StreamFace<T, U>::handleSend(const boost::system::error_code& error,
|
||||
size_t nBytesSent)
|
||||
{
|
||||
if (error)
|
||||
return processErrorCode(error);
|
||||
|
||||
BOOST_ASSERT(!m_sendQueue.empty());
|
||||
|
||||
NFD_LOG_FACE_TRACE("Successfully sent: " << nBytesSent << " bytes");
|
||||
this->getMutableCounters().getNOutBytes() += nBytesSent;
|
||||
|
||||
m_sendQueue.pop();
|
||||
if (!m_sendQueue.empty())
|
||||
sendFromQueue();
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
StreamFace<T, U>::handleReceive(const boost::system::error_code& error,
|
||||
size_t nBytesReceived)
|
||||
{
|
||||
if (error)
|
||||
return processErrorCode(error);
|
||||
|
||||
NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes");
|
||||
this->getMutableCounters().getNInBytes() += nBytesReceived;
|
||||
|
||||
m_inputBufferSize += nBytesReceived;
|
||||
|
||||
size_t offset = 0;
|
||||
|
||||
bool isOk = true;
|
||||
Block element;
|
||||
while (m_inputBufferSize - offset > 0) {
|
||||
std::tie(isOk, element) = Block::fromBuffer(m_inputBuffer + offset, m_inputBufferSize - offset);
|
||||
if (!isOk)
|
||||
break;
|
||||
|
||||
offset += element.size();
|
||||
|
||||
BOOST_ASSERT(offset <= m_inputBufferSize);
|
||||
|
||||
if (!this->decodeAndDispatchInput(element)) {
|
||||
NFD_LOG_FACE_WARN("Received unrecognized TLV block of type " << element.type());
|
||||
// ignore unknown packet and proceed
|
||||
}
|
||||
}
|
||||
|
||||
if (!isOk && m_inputBufferSize == ndn::MAX_NDN_PACKET_SIZE && offset == 0)
|
||||
{
|
||||
NFD_LOG_FACE_WARN("Failed to parse incoming packet or packet too large to process");
|
||||
shutdownSocket();
|
||||
this->fail("Failed to parse incoming packet or packet too large to process");
|
||||
return;
|
||||
}
|
||||
|
||||
if (offset > 0)
|
||||
{
|
||||
if (offset != m_inputBufferSize)
|
||||
{
|
||||
std::copy(m_inputBuffer + offset, m_inputBuffer + m_inputBufferSize,
|
||||
m_inputBuffer);
|
||||
m_inputBufferSize -= offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_inputBufferSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
m_socket.async_receive(boost::asio::buffer(m_inputBuffer + m_inputBufferSize,
|
||||
ndn::MAX_NDN_PACKET_SIZE - m_inputBufferSize),
|
||||
bind(&StreamFace<T, U>::handleReceive, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
StreamFace<T, U>::shutdownSocket()
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
// Cancel all outstanding operations and shutdown the socket
|
||||
// so that no further sends or receives are possible.
|
||||
// Use the non-throwing variants and ignore errors, if any.
|
||||
boost::system::error_code error;
|
||||
m_socket.cancel(error);
|
||||
m_socket.shutdown(protocol::socket::shutdown_both, error);
|
||||
|
||||
// ensure that the Face object is alive at least until all pending
|
||||
// handlers are dispatched
|
||||
getGlobalIoService().post(bind(&StreamFace<T, U>::deferredClose,
|
||||
this, this->shared_from_this()));
|
||||
|
||||
// Some bug or feature of Boost.Asio (see http://redmine.named-data.net/issues/1856):
|
||||
//
|
||||
// When shutdownSocket is called from within a socket event (e.g., from handleReceive),
|
||||
// m_socket.shutdown() does not trigger the cancellation of the handleSend callback.
|
||||
// Instead, handleSend is invoked as nothing bad happened.
|
||||
//
|
||||
// In order to prevent the assertion in handleSend from failing, we clear the queue
|
||||
// and close the socket in deferredClose, i.e., after all callbacks scheduled up to
|
||||
// this point have been executed. If more send operations are scheduled after this
|
||||
// point, they will fail because the socket has been shutdown, and their callbacks
|
||||
// will be invoked with error code == asio::error::shut_down.
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
StreamFace<T, U>::deferredClose(const shared_ptr<Face>& face)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
// clear send queue
|
||||
std::queue<Block> emptyQueue;
|
||||
std::swap(emptyQueue, m_sendQueue);
|
||||
|
||||
// use the non-throwing variant and ignore errors, if any
|
||||
boost::system::error_code error;
|
||||
m_socket.close(error);
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_STREAM_FACE_HPP
|
||||
@@ -51,16 +51,16 @@ public:
|
||||
explicit
|
||||
StreamTransport(typename protocol::socket&& socket);
|
||||
|
||||
virtual void
|
||||
doSend(Transport::Packet&& packet) DECL_OVERRIDE;
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
doClose() DECL_OVERRIDE;
|
||||
|
||||
protected:
|
||||
void
|
||||
deferredClose();
|
||||
|
||||
virtual void
|
||||
doSend(Transport::Packet&& packet) DECL_OVERRIDE;
|
||||
|
||||
void
|
||||
sendFromQueue();
|
||||
|
||||
@@ -81,42 +81,25 @@ protected:
|
||||
NFD_LOG_INCLASS_DECLARE();
|
||||
|
||||
private:
|
||||
uint8_t m_inputBuffer[ndn::MAX_NDN_PACKET_SIZE];
|
||||
size_t m_inputBufferSize;
|
||||
uint8_t m_receiveBuffer[ndn::MAX_NDN_PACKET_SIZE];
|
||||
size_t m_receiveBufferSize;
|
||||
std::queue<Block> m_sendQueue;
|
||||
};
|
||||
|
||||
// All derived classes must use
|
||||
// NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(StreamTransport, <specialization-parameter>, "Name");
|
||||
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
StreamTransport<T>::StreamTransport(typename StreamTransport::protocol::socket&& socket)
|
||||
: m_socket(std::move(socket))
|
||||
, m_inputBufferSize(0)
|
||||
, m_receiveBufferSize(0)
|
||||
{
|
||||
m_socket.async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
|
||||
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));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void
|
||||
StreamTransport<T>::doSend(Transport::Packet&& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
bool wasQueueEmpty = m_sendQueue.empty();
|
||||
m_sendQueue.push(packet.packet);
|
||||
|
||||
if (wasQueueEmpty)
|
||||
sendFromQueue();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void
|
||||
void
|
||||
StreamTransport<T>::doClose()
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
@@ -148,7 +131,7 @@ StreamTransport<T>::doClose()
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void
|
||||
void
|
||||
StreamTransport<T>::deferredClose()
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
@@ -165,7 +148,20 @@ StreamTransport<T>::deferredClose()
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void
|
||||
void
|
||||
StreamTransport<T>::doSend(Transport::Packet&& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
bool wasQueueEmpty = m_sendQueue.empty();
|
||||
m_sendQueue.push(packet.packet);
|
||||
|
||||
if (wasQueueEmpty)
|
||||
sendFromQueue();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
StreamTransport<T>::sendFromQueue()
|
||||
{
|
||||
boost::asio::async_write(m_socket, boost::asio::buffer(m_sendQueue.front()),
|
||||
@@ -175,7 +171,7 @@ StreamTransport<T>::sendFromQueue()
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void
|
||||
void
|
||||
StreamTransport<T>::handleSend(const boost::system::error_code& error,
|
||||
size_t nBytesSent)
|
||||
{
|
||||
@@ -192,7 +188,7 @@ StreamTransport<T>::handleSend(const boost::system::error_code& error,
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void
|
||||
void
|
||||
StreamTransport<T>::handleReceive(const boost::system::error_code& error,
|
||||
size_t nBytesReceived)
|
||||
{
|
||||
@@ -201,26 +197,24 @@ StreamTransport<T>::handleReceive(const boost::system::error_code& error,
|
||||
|
||||
NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes");
|
||||
|
||||
m_inputBufferSize += nBytesReceived;
|
||||
m_receiveBufferSize += nBytesReceived;
|
||||
|
||||
size_t offset = 0;
|
||||
|
||||
bool isOk = true;
|
||||
Block element;
|
||||
while (m_inputBufferSize - offset > 0) {
|
||||
std::tie(isOk, element) = Block::fromBuffer(m_inputBuffer + offset, m_inputBufferSize - offset);
|
||||
while (m_receiveBufferSize - offset > 0) {
|
||||
std::tie(isOk, element) = Block::fromBuffer(m_receiveBuffer + offset, m_receiveBufferSize - offset);
|
||||
if (!isOk)
|
||||
break;
|
||||
|
||||
offset += element.size();
|
||||
BOOST_ASSERT(offset <= m_receiveBufferSize);
|
||||
|
||||
BOOST_ASSERT(offset <= m_inputBufferSize);
|
||||
|
||||
Transport::Packet packet(std::move(element));
|
||||
this->receive(std::move(packet));
|
||||
this->receive(Transport::Packet(std::move(element)));
|
||||
}
|
||||
|
||||
if (!isOk && m_inputBufferSize == ndn::MAX_NDN_PACKET_SIZE && offset == 0) {
|
||||
if (!isOk && m_receiveBufferSize == ndn::MAX_NDN_PACKET_SIZE && offset == 0) {
|
||||
NFD_LOG_FACE_WARN("Failed to parse incoming packet or packet too large to process");
|
||||
this->setState(TransportState::FAILED);
|
||||
doClose();
|
||||
@@ -228,24 +222,24 @@ StreamTransport<T>::handleReceive(const boost::system::error_code& error,
|
||||
}
|
||||
|
||||
if (offset > 0) {
|
||||
if (offset != m_inputBufferSize) {
|
||||
std::copy(m_inputBuffer + offset, m_inputBuffer + m_inputBufferSize, m_inputBuffer);
|
||||
m_inputBufferSize -= offset;
|
||||
if (offset != m_receiveBufferSize) {
|
||||
std::copy(m_receiveBuffer + offset, m_receiveBuffer + m_receiveBufferSize, m_receiveBuffer);
|
||||
m_receiveBufferSize -= offset;
|
||||
}
|
||||
else {
|
||||
m_inputBufferSize = 0;
|
||||
m_receiveBufferSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
m_socket.async_receive(boost::asio::buffer(m_inputBuffer + m_inputBufferSize,
|
||||
ndn::MAX_NDN_PACKET_SIZE - m_inputBufferSize),
|
||||
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>
|
||||
inline void
|
||||
void
|
||||
StreamTransport<T>::processErrorCode(const boost::system::error_code& error)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
+21
-23
@@ -24,14 +24,15 @@
|
||||
*/
|
||||
|
||||
#include "tcp-channel.hpp"
|
||||
#include "tcp-face.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "tcp-transport.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
NFD_LOG_INIT("TcpChannel");
|
||||
|
||||
using namespace boost::asio;
|
||||
namespace ip = boost::asio::ip;
|
||||
|
||||
TcpChannel::TcpChannel(const tcp::Endpoint& localEndpoint)
|
||||
: m_localEndpoint(localEndpoint)
|
||||
@@ -43,7 +44,7 @@ TcpChannel::TcpChannel(const tcp::Endpoint& localEndpoint)
|
||||
|
||||
void
|
||||
TcpChannel::listen(const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onAcceptFailed,
|
||||
const FaceCreationFailedCallback& onAcceptFailed,
|
||||
int backlog/* = tcp::acceptor::max_connections*/)
|
||||
{
|
||||
if (isListening()) {
|
||||
@@ -65,8 +66,8 @@ TcpChannel::listen(const FaceCreatedCallback& onFaceCreated,
|
||||
|
||||
void
|
||||
TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
|
||||
const TcpChannel::FaceCreatedCallback& onFaceCreated,
|
||||
const TcpChannel::ConnectFailedCallback& onConnectFailed,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed,
|
||||
const time::seconds& timeout/* = time::seconds(4)*/)
|
||||
{
|
||||
auto it = m_channelFaces.find(remoteEndpoint);
|
||||
@@ -94,7 +95,7 @@ TcpChannel::size() const
|
||||
}
|
||||
|
||||
void
|
||||
TcpChannel::createFace(ip::tcp::socket socket,
|
||||
TcpChannel::createFace(ip::tcp::socket&& socket,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
bool isOnDemand)
|
||||
{
|
||||
@@ -103,21 +104,18 @@ TcpChannel::createFace(ip::tcp::socket socket,
|
||||
|
||||
auto it = m_channelFaces.find(remoteEndpoint);
|
||||
if (it == m_channelFaces.end()) {
|
||||
tcp::Endpoint localEndpoint = socket.local_endpoint();
|
||||
auto persistency = isOnDemand ? ndn::nfd::FACE_PERSISTENCY_ON_DEMAND
|
||||
: ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
|
||||
auto linkService = make_unique<face::GenericLinkService>();
|
||||
auto transport = make_unique<face::TcpTransport>(std::move(socket), persistency);
|
||||
face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
|
||||
if (localEndpoint.address().is_loopback() &&
|
||||
remoteEndpoint.address().is_loopback())
|
||||
face = make_shared<TcpLocalFace>(FaceUri(remoteEndpoint), FaceUri(localEndpoint),
|
||||
std::move(socket), isOnDemand);
|
||||
else
|
||||
face = make_shared<TcpFace>(FaceUri(remoteEndpoint), FaceUri(localEndpoint),
|
||||
std::move(socket), isOnDemand);
|
||||
|
||||
face->onFail.connectSingleShot([this, remoteEndpoint] (const std::string&) {
|
||||
NFD_LOG_TRACE("Erasing " << remoteEndpoint << " from channel face map");
|
||||
m_channelFaces.erase(remoteEndpoint);
|
||||
});
|
||||
m_channelFaces[remoteEndpoint] = face;
|
||||
connectFaceClosedSignal(*face,
|
||||
[this, remoteEndpoint] {
|
||||
NFD_LOG_TRACE("Erasing " << remoteEndpoint << " from channel face map");
|
||||
m_channelFaces.erase(remoteEndpoint);
|
||||
});
|
||||
}
|
||||
else {
|
||||
// we already have a face for this endpoint, just reuse it
|
||||
@@ -135,7 +133,7 @@ TcpChannel::createFace(ip::tcp::socket socket,
|
||||
|
||||
void
|
||||
TcpChannel::accept(const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onAcceptFailed)
|
||||
const FaceCreationFailedCallback& onAcceptFailed)
|
||||
{
|
||||
m_acceptor.async_accept(m_acceptSocket, bind(&TcpChannel::handleAccept, this,
|
||||
boost::asio::placeholders::error,
|
||||
@@ -145,7 +143,7 @@ TcpChannel::accept(const FaceCreatedCallback& onFaceCreated,
|
||||
void
|
||||
TcpChannel::handleAccept(const boost::system::error_code& error,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onAcceptFailed)
|
||||
const FaceCreationFailedCallback& onAcceptFailed)
|
||||
{
|
||||
if (error) {
|
||||
if (error == boost::asio::error::operation_aborted) // when the socket is closed by someone
|
||||
@@ -170,7 +168,7 @@ TcpChannel::handleConnect(const boost::system::error_code& error,
|
||||
const shared_ptr<ip::tcp::socket>& socket,
|
||||
const scheduler::EventId& connectTimeoutEvent,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onConnectFailed)
|
||||
const FaceCreationFailedCallback& onConnectFailed)
|
||||
{
|
||||
scheduler::cancel(connectTimeoutEvent);
|
||||
|
||||
@@ -202,7 +200,7 @@ TcpChannel::handleConnect(const boost::system::error_code& error,
|
||||
|
||||
void
|
||||
TcpChannel::handleConnectTimeout(const shared_ptr<ip::tcp::socket>& socket,
|
||||
const ConnectFailedCallback& onConnectFailed)
|
||||
const FaceCreationFailedCallback& onConnectFailed)
|
||||
{
|
||||
NFD_LOG_DEBUG("Connect to remote endpoint timed out");
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
*/
|
||||
void
|
||||
listen(const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onAcceptFailed,
|
||||
const FaceCreationFailedCallback& onAcceptFailed,
|
||||
int backlog = boost::asio::ip::tcp::acceptor::max_connections);
|
||||
|
||||
/**
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
void
|
||||
connect(const tcp::Endpoint& remoteEndpoint,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onConnectFailed,
|
||||
const FaceCreationFailedCallback& onConnectFailed,
|
||||
const time::seconds& timeout = time::seconds(4));
|
||||
|
||||
/**
|
||||
@@ -88,29 +88,29 @@ public:
|
||||
|
||||
private:
|
||||
void
|
||||
createFace(boost::asio::ip::tcp::socket socket,
|
||||
createFace(boost::asio::ip::tcp::socket&& socket,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
bool isOnDemand);
|
||||
|
||||
void
|
||||
accept(const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onConnectFailed);
|
||||
const FaceCreationFailedCallback& onAcceptFailed);
|
||||
|
||||
void
|
||||
handleAccept(const boost::system::error_code& error,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onConnectFailed);
|
||||
const FaceCreationFailedCallback& onAcceptFailed);
|
||||
|
||||
void
|
||||
handleConnect(const boost::system::error_code& error,
|
||||
const shared_ptr<boost::asio::ip::tcp::socket>& socket,
|
||||
const scheduler::EventId& connectTimeoutEvent,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onConnectFailed);
|
||||
const FaceCreationFailedCallback& onConnectFailed);
|
||||
|
||||
void
|
||||
handleConnectTimeout(const shared_ptr<boost::asio::ip::tcp::socket>& socket,
|
||||
const ConnectFailedCallback& onConnectFailed);
|
||||
const FaceCreationFailedCallback& onConnectFailed);
|
||||
|
||||
private:
|
||||
std::map<tcp::Endpoint, shared_ptr<Face>> m_channelFaces;
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/* -*- 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
|
||||
*
|
||||
* 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 "tcp-face.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(StreamFace, TcpFace::protocol, "TcpFace");
|
||||
|
||||
NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(StreamFace,
|
||||
TcpLocalFace::protocol, LocalFace,
|
||||
"TcpLocalFace");
|
||||
|
||||
TcpFace::TcpFace(const FaceUri& remoteUri, const FaceUri& localUri,
|
||||
protocol::socket socket, bool isOnDemand)
|
||||
: StreamFace<protocol>(remoteUri, localUri, std::move(socket), isOnDemand)
|
||||
{
|
||||
}
|
||||
|
||||
TcpLocalFace::TcpLocalFace(const FaceUri& remoteUri, const FaceUri& localUri,
|
||||
protocol::socket socket, bool isOnDemand)
|
||||
: StreamFace<protocol, LocalFace>(remoteUri, localUri, std::move(socket), isOnDemand)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
@@ -1,80 +0,0 @@
|
||||
/* -*- 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
|
||||
*
|
||||
* 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_TCP_FACE_HPP
|
||||
#define NFD_DAEMON_FACE_TCP_FACE_HPP
|
||||
|
||||
#include "stream-face.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/**
|
||||
* \brief Implementation of Face abstraction that uses TCP
|
||||
* as underlying transport mechanism
|
||||
*/
|
||||
class TcpFace : public StreamFace<boost::asio::ip::tcp>
|
||||
{
|
||||
public:
|
||||
TcpFace(const FaceUri& remoteUri, const FaceUri& localUri,
|
||||
protocol::socket socket, bool isOnDemand);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Implementation of Face abstraction that uses TCP
|
||||
* as underlying transport mechanism and is used for
|
||||
* local communication (can enable LocalControlHeader)
|
||||
*/
|
||||
class TcpLocalFace : public StreamFace<boost::asio::ip::tcp, LocalFace>
|
||||
{
|
||||
public:
|
||||
TcpLocalFace(const FaceUri& remoteUri, const FaceUri& localUri,
|
||||
protocol::socket socket, bool isOnDemand);
|
||||
};
|
||||
|
||||
|
||||
/** \brief Class validating use of TcpLocalFace
|
||||
*/
|
||||
template<>
|
||||
struct StreamFaceValidator<TcpLocalFace::protocol, LocalFace>
|
||||
{
|
||||
/** Check that local endpoint is loopback
|
||||
*
|
||||
* @throws Face::Error if validation failed
|
||||
*/
|
||||
static void
|
||||
validateSocket(const TcpLocalFace::protocol::socket& socket)
|
||||
{
|
||||
if (!socket.local_endpoint().address().is_loopback() ||
|
||||
!socket.remote_endpoint().address().is_loopback())
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(Face::Error("TcpLocalFace can be created only on a loopback "
|
||||
"address"));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_TCP_FACE_HPP
|
||||
@@ -23,57 +23,41 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_NDNLP_SLICER_HPP
|
||||
#define NFD_DAEMON_FACE_NDNLP_SLICER_HPP
|
||||
|
||||
#include "ndnlp-tlv.hpp"
|
||||
#include "ndnlp-sequence-generator.hpp"
|
||||
#include "tcp-transport.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace ndnlp {
|
||||
namespace face {
|
||||
|
||||
typedef shared_ptr<std::vector<Block>> PacketArray;
|
||||
NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(StreamTransport, TcpTransport::protocol,
|
||||
"TcpTransport");
|
||||
|
||||
/** \brief provides fragmentation feature at sender
|
||||
*/
|
||||
class Slicer : noncopyable
|
||||
TcpTransport::TcpTransport(protocol::socket&& socket, ndn::nfd::FacePersistency persistency)
|
||||
: StreamTransport(std::move(socket))
|
||||
{
|
||||
public:
|
||||
/** \param mtu maximum size of NDNLP header and payload
|
||||
* \note If NDNLP packets are to be encapsulated in an additional header
|
||||
* (eg. in UDP packets), the caller must deduct such overhead.
|
||||
*/
|
||||
explicit
|
||||
Slicer(size_t mtu);
|
||||
this->setLocalUri(FaceUri(m_socket.local_endpoint()));
|
||||
this->setRemoteUri(FaceUri(m_socket.remote_endpoint()));
|
||||
|
||||
virtual
|
||||
~Slicer();
|
||||
if (m_socket.local_endpoint().address().is_loopback() &&
|
||||
m_socket.remote_endpoint().address().is_loopback())
|
||||
this->setScope(ndn::nfd::FACE_SCOPE_LOCAL);
|
||||
else
|
||||
this->setScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
|
||||
|
||||
PacketArray
|
||||
slice(const Block& block);
|
||||
this->setPersistency(persistency);
|
||||
this->setLinkType(ndn::nfd::LINK_TYPE_POINT_TO_POINT);
|
||||
this->setMtu(MTU_UNLIMITED);
|
||||
|
||||
private:
|
||||
template<bool T>
|
||||
size_t
|
||||
encodeFragment(ndn::EncodingImpl<T>& blk,
|
||||
uint64_t seq, uint16_t fragIndex, uint16_t fragCount,
|
||||
const uint8_t* payload, size_t payloadSize);
|
||||
NFD_LOG_FACE_INFO("Creating transport");
|
||||
}
|
||||
|
||||
/// estimate the size of NDNLP header and maximum payload size per packet
|
||||
void
|
||||
estimateOverhead();
|
||||
void
|
||||
TcpTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
|
||||
{
|
||||
if (newPersistency == ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
|
||||
BOOST_THROW_EXCEPTION(
|
||||
std::invalid_argument("TcpTransport does not support FACE_PERSISTENCY_PERMANENT"));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SequenceGenerator m_seqgen;
|
||||
|
||||
/// maximum packet size
|
||||
size_t m_mtu;
|
||||
|
||||
/// maximum payload size
|
||||
size_t m_maxPayload;
|
||||
};
|
||||
|
||||
} // namespace ndnlp
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_NDNLP_SLICER_HPP
|
||||
@@ -22,22 +22,29 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_NDNLP_TLV_HPP
|
||||
#define NFD_DAEMON_FACE_NDNLP_TLV_HPP
|
||||
#ifndef NFD_DAEMON_FACE_TCP_TRANSPORT_HPP
|
||||
#define NFD_DAEMON_FACE_TCP_TRANSPORT_HPP
|
||||
|
||||
#include "stream-transport.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace tlv {
|
||||
namespace face {
|
||||
|
||||
enum
|
||||
/**
|
||||
* \brief A Transport that communicates on a connected TCP socket
|
||||
*/
|
||||
class TcpTransport DECL_CLASS_FINAL : public StreamTransport<boost::asio::ip::tcp>
|
||||
{
|
||||
NdnlpData = 80,
|
||||
NdnlpSequence = 81,
|
||||
NdnlpFragIndex = 82,
|
||||
NdnlpFragCount = 83,
|
||||
NdnlpPayload = 84
|
||||
public:
|
||||
TcpTransport(protocol::socket&& socket,
|
||||
ndn::nfd::FacePersistency persistency);
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
|
||||
};
|
||||
|
||||
} // namespace tlv
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_NDNLP_TLV_HPP
|
||||
#endif // NFD_DAEMON_FACE_TCP_TRANSPORT_HPP
|
||||
+33
-16
@@ -24,8 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "transport.hpp"
|
||||
#include "lp-face.hpp"
|
||||
#include "link-service.hpp"
|
||||
#include "face.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
@@ -60,15 +59,13 @@ Transport::Packet::Packet(Block&& packet1)
|
||||
Transport::Transport()
|
||||
: m_face(nullptr)
|
||||
, m_service(nullptr)
|
||||
, m_scope(ndn::nfd::FACE_SCOPE_NON_LOCAL)
|
||||
, m_persistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT)
|
||||
, m_linkType(ndn::nfd::LINK_TYPE_POINT_TO_POINT)
|
||||
, m_mtu(MTU_UNLIMITED)
|
||||
, m_scope(ndn::nfd::FACE_SCOPE_NONE)
|
||||
, m_persistency(ndn::nfd::FACE_PERSISTENCY_NONE)
|
||||
, m_linkType(ndn::nfd::LINK_TYPE_NONE)
|
||||
, m_mtu(MTU_INVALID)
|
||||
, m_state(TransportState::UP)
|
||||
, m_counters(nullptr)
|
||||
, m_expirationTime(time::steady_clock::TimePoint::max())
|
||||
{
|
||||
// warning: Subclass constructor must explicitly initialize all static properties
|
||||
// using setters, and should not rely on the defaults here.
|
||||
}
|
||||
|
||||
Transport::~Transport()
|
||||
@@ -76,14 +73,13 @@ Transport::~Transport()
|
||||
}
|
||||
|
||||
void
|
||||
Transport::setFaceAndLinkService(LpFace& face, LinkService& service)
|
||||
Transport::setFaceAndLinkService(Face& face, LinkService& service)
|
||||
{
|
||||
BOOST_ASSERT(m_face == nullptr);
|
||||
BOOST_ASSERT(m_service == nullptr);
|
||||
|
||||
m_face = &face;
|
||||
m_service = &service;
|
||||
m_counters = &m_face->getMutableCounters();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -111,8 +107,10 @@ Transport::send(Packet&& packet)
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO#3177 increment LpPacket counter
|
||||
m_counters->getNOutBytes() += packet.packet.size();
|
||||
if (state == TransportState::UP) {
|
||||
++this->nOutPackets;
|
||||
this->nOutBytes += packet.packet.size();
|
||||
}
|
||||
|
||||
this->doSend(std::move(packet));
|
||||
}
|
||||
@@ -123,12 +121,31 @@ Transport::receive(Packet&& packet)
|
||||
BOOST_ASSERT(this->getMtu() == MTU_UNLIMITED ||
|
||||
packet.packet.size() <= static_cast<size_t>(this->getMtu()));
|
||||
|
||||
// TODO#3177 increment LpPacket counter
|
||||
m_counters->getNInBytes() += packet.packet.size();
|
||||
++this->nInPackets;
|
||||
this->nInBytes += packet.packet.size();
|
||||
|
||||
m_service->receivePacket(std::move(packet));
|
||||
}
|
||||
|
||||
void
|
||||
Transport::setPersistency(ndn::nfd::FacePersistency 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);
|
||||
}
|
||||
|
||||
m_persistency = newPersistency;
|
||||
}
|
||||
|
||||
void
|
||||
Transport::setState(TransportState newState)
|
||||
{
|
||||
@@ -173,7 +190,7 @@ std::ostream&
|
||||
operator<<(std::ostream& os, const FaceLogHelper<Transport>& flh)
|
||||
{
|
||||
const Transport& transport = flh.obj;
|
||||
const LpFace* face = transport.getFace();
|
||||
const Face* face = transport.getFace();
|
||||
FaceId faceId = face == nullptr ? INVALID_FACEID : face->getId();
|
||||
|
||||
os << "[id=" << faceId << ",local=" << transport.getLocalUri()
|
||||
|
||||
+98
-24
@@ -26,15 +26,14 @@
|
||||
#ifndef NFD_DAEMON_FACE_TRANSPORT_HPP
|
||||
#define NFD_DAEMON_FACE_TRANSPORT_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#include "face-counters.hpp"
|
||||
#include "core/counter.hpp"
|
||||
#include "face-log.hpp"
|
||||
#include <ndn-cxx/encoding/nfd-constants.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
class LpFace;
|
||||
class Face;
|
||||
class LinkService;
|
||||
|
||||
/** \brief indicates the state of a transport
|
||||
@@ -51,14 +50,58 @@ enum class TransportState {
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, TransportState state);
|
||||
|
||||
/** \brief counters provided by Transport
|
||||
* \note The type name 'TransportCounters' is implementation detail.
|
||||
* Use 'Transport::Counters' in public API.
|
||||
*/
|
||||
class TransportCounters
|
||||
{
|
||||
public:
|
||||
/** \brief count of incoming packets
|
||||
*
|
||||
* A 'packet' typically means a top-level TLV block.
|
||||
* For a datagram-based transport, an incoming packet that cannot be parsed as TLV
|
||||
* would not be counted.
|
||||
*/
|
||||
PacketCounter nInPackets;
|
||||
|
||||
/** \brief count of outgoing packets
|
||||
*
|
||||
* A 'packet' typically means a top-level TLV block.
|
||||
* This counter is incremented only if transport is UP.
|
||||
*/
|
||||
PacketCounter nOutPackets;
|
||||
|
||||
/** \brief total incoming bytes
|
||||
*
|
||||
* This counter includes headers imposed by NFD (such as NDNLP),
|
||||
* but excludes overhead of underlying protocol (such as IP header).
|
||||
* For a datagram-based transport, an incoming packet that cannot be parsed as TLV
|
||||
* would not be counted.
|
||||
*/
|
||||
ByteCounter nInBytes;
|
||||
|
||||
/** \brief total outgoing bytes
|
||||
*
|
||||
* This counter includes headers imposed by NFD (such as NDNLP),
|
||||
* but excludes overhead of underlying protocol (such as IP header).
|
||||
* This counter is increased only if transport is UP.
|
||||
*/
|
||||
ByteCounter nOutBytes;
|
||||
};
|
||||
|
||||
/** \brief indicates the transport has no limit on payload size
|
||||
*/
|
||||
const ssize_t MTU_UNLIMITED = -1;
|
||||
|
||||
/** \brief the lower part of an LpFace
|
||||
* \sa LpFace
|
||||
/** \brief (for internal use) indicates MTU field is unset
|
||||
*/
|
||||
class Transport : noncopyable
|
||||
const ssize_t MTU_INVALID = -2;
|
||||
|
||||
/** \brief the lower part of a Face
|
||||
* \sa Face
|
||||
*/
|
||||
class Transport : protected virtual TransportCounters, noncopyable
|
||||
{
|
||||
public:
|
||||
/** \brief identifies an endpoint on the link
|
||||
@@ -89,6 +132,18 @@ public:
|
||||
EndpointId remoteEndpoint;
|
||||
};
|
||||
|
||||
/** \brief counters provided by Transport
|
||||
*/
|
||||
typedef TransportCounters Counters;
|
||||
|
||||
/** \brief constructor
|
||||
*
|
||||
* Transport constructor initializes static properties to invalid values.
|
||||
* Subclass constructor must explicitly set every static property.
|
||||
*
|
||||
* This constructor initializes TransportState to UP;
|
||||
* subclass constructor can rely on this default value.
|
||||
*/
|
||||
Transport();
|
||||
|
||||
virtual
|
||||
@@ -99,11 +154,11 @@ public:
|
||||
* \pre setFaceAndLinkService has not been called
|
||||
*/
|
||||
void
|
||||
setFaceAndLinkService(LpFace& face, LinkService& service);
|
||||
setFaceAndLinkService(Face& face, LinkService& service);
|
||||
|
||||
/** \return Face to which this Transport is attached
|
||||
*/
|
||||
const LpFace*
|
||||
const Face*
|
||||
getFace() const;
|
||||
|
||||
/** \return LinkService to which this Transport is attached
|
||||
@@ -116,6 +171,9 @@ public:
|
||||
LinkService*
|
||||
getLinkService();
|
||||
|
||||
virtual const Counters&
|
||||
getCounters() const;
|
||||
|
||||
public: // upper interface
|
||||
/** \brief request the transport to be closed
|
||||
*
|
||||
@@ -195,6 +253,12 @@ public: // dynamic properties
|
||||
*/
|
||||
signal::Signal<Transport, TransportState/*old*/, TransportState/*new*/> afterStateChange;
|
||||
|
||||
/** \return expiration time of the transport
|
||||
* \retval time::steady_clock::TimePoint::max() the transport has indefinite lifetime
|
||||
*/
|
||||
time::steady_clock::TimePoint
|
||||
getExpirationTime() const;
|
||||
|
||||
protected: // properties to be set by subclass
|
||||
void
|
||||
setLocalUri(const FaceUri& uri);
|
||||
@@ -221,17 +285,16 @@ protected: // properties to be set by subclass
|
||||
void
|
||||
setState(TransportState newState);
|
||||
|
||||
void
|
||||
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
|
||||
*
|
||||
* Base class implementation does nothing.
|
||||
*/
|
||||
virtual void
|
||||
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
|
||||
{
|
||||
}
|
||||
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) = 0;
|
||||
|
||||
/** \brief performs Transport specific operations to close the transport
|
||||
*
|
||||
@@ -253,7 +316,7 @@ private: // to be overridden by subclass
|
||||
doSend(Packet&& packet) = 0;
|
||||
|
||||
private:
|
||||
LpFace* m_face;
|
||||
Face* m_face;
|
||||
LinkService* m_service;
|
||||
FaceUri m_localUri;
|
||||
FaceUri m_remoteUri;
|
||||
@@ -262,10 +325,10 @@ private:
|
||||
ndn::nfd::LinkType m_linkType;
|
||||
ssize_t m_mtu;
|
||||
TransportState m_state;
|
||||
LinkLayerCounters* m_counters; // TODO#3177 change into LinkCounters
|
||||
time::steady_clock::TimePoint m_expirationTime;
|
||||
};
|
||||
|
||||
inline const LpFace*
|
||||
inline const Face*
|
||||
Transport::getFace() const
|
||||
{
|
||||
return m_face;
|
||||
@@ -283,6 +346,12 @@ Transport::getLinkService()
|
||||
return m_service;
|
||||
}
|
||||
|
||||
inline const Transport::Counters&
|
||||
Transport::getCounters() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline FaceUri
|
||||
Transport::getLocalUri() const
|
||||
{
|
||||
@@ -325,13 +394,6 @@ Transport::getPersistency() const
|
||||
return m_persistency;
|
||||
}
|
||||
|
||||
inline void
|
||||
Transport::setPersistency(ndn::nfd::FacePersistency persistency)
|
||||
{
|
||||
this->beforeChangePersistency(persistency);
|
||||
m_persistency = persistency;
|
||||
}
|
||||
|
||||
inline ndn::nfd::LinkType
|
||||
Transport::getLinkType() const
|
||||
{
|
||||
@@ -363,6 +425,18 @@ Transport::getState() const
|
||||
return m_state;
|
||||
}
|
||||
|
||||
inline time::steady_clock::TimePoint
|
||||
Transport::getExpirationTime() const
|
||||
{
|
||||
return m_expirationTime;
|
||||
}
|
||||
|
||||
inline void
|
||||
Transport::setExpirationTime(const time::steady_clock::TimePoint& expirationTime)
|
||||
{
|
||||
m_expirationTime = expirationTime;
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const FaceLogHelper<Transport>& flh);
|
||||
|
||||
|
||||
+80
-77
@@ -43,36 +43,19 @@ UdpChannel::UdpChannel(const udp::Endpoint& localEndpoint,
|
||||
setUri(FaceUri(m_localEndpoint));
|
||||
}
|
||||
|
||||
void
|
||||
UdpChannel::listen(const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onReceiveFailed)
|
||||
size_t
|
||||
UdpChannel::size() const
|
||||
{
|
||||
if (isListening()) {
|
||||
NFD_LOG_WARN("[" << m_localEndpoint << "] Already listening");
|
||||
return;
|
||||
}
|
||||
|
||||
m_socket.open(m_localEndpoint.protocol());
|
||||
m_socket.set_option(ip::udp::socket::reuse_address(true));
|
||||
if (m_localEndpoint.address().is_v6())
|
||||
m_socket.set_option(ip::v6_only(true));
|
||||
|
||||
m_socket.bind(m_localEndpoint);
|
||||
m_socket.async_receive_from(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
|
||||
m_remoteEndpoint,
|
||||
bind(&UdpChannel::handleNewPeer, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred,
|
||||
onFaceCreated, onReceiveFailed));
|
||||
return m_channelFaces.size();
|
||||
}
|
||||
|
||||
void
|
||||
UdpChannel::connect(const udp::Endpoint& remoteEndpoint,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onConnectFailed)
|
||||
const FaceCreationFailedCallback& onConnectFailed)
|
||||
{
|
||||
shared_ptr<face::LpFaceWrapper> face;
|
||||
shared_ptr<Face> face;
|
||||
try {
|
||||
face = createFace(remoteEndpoint, persistency).second;
|
||||
}
|
||||
@@ -88,13 +71,77 @@ UdpChannel::connect(const udp::Endpoint& remoteEndpoint,
|
||||
onFaceCreated(face);
|
||||
}
|
||||
|
||||
size_t
|
||||
UdpChannel::size() const
|
||||
void
|
||||
UdpChannel::listen(const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onReceiveFailed)
|
||||
{
|
||||
return m_channelFaces.size();
|
||||
if (isListening()) {
|
||||
NFD_LOG_WARN("[" << m_localEndpoint << "] Already listening");
|
||||
return;
|
||||
}
|
||||
|
||||
m_socket.open(m_localEndpoint.protocol());
|
||||
m_socket.set_option(ip::udp::socket::reuse_address(true));
|
||||
if (m_localEndpoint.address().is_v6())
|
||||
m_socket.set_option(ip::v6_only(true));
|
||||
|
||||
m_socket.bind(m_localEndpoint);
|
||||
this->waitForNewPeer(onFaceCreated, onReceiveFailed);
|
||||
}
|
||||
|
||||
std::pair<bool, shared_ptr<face::LpFaceWrapper>>
|
||||
void
|
||||
UdpChannel::waitForNewPeer(const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onReceiveFailed)
|
||||
{
|
||||
m_socket.async_receive_from(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
|
||||
m_remoteEndpoint,
|
||||
bind(&UdpChannel::handleNewPeer, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred,
|
||||
onFaceCreated, onReceiveFailed));
|
||||
}
|
||||
|
||||
void
|
||||
UdpChannel::handleNewPeer(const boost::system::error_code& error,
|
||||
size_t nBytesReceived,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onReceiveFailed)
|
||||
{
|
||||
if (error) {
|
||||
if (error == boost::asio::error::operation_aborted) // when the socket is closed by someone
|
||||
return;
|
||||
|
||||
NFD_LOG_DEBUG("[" << m_localEndpoint << "] Receive failed: " << error.message());
|
||||
if (onReceiveFailed)
|
||||
onReceiveFailed(error.message());
|
||||
return;
|
||||
}
|
||||
|
||||
NFD_LOG_DEBUG("[" << m_localEndpoint << "] New peer " << m_remoteEndpoint);
|
||||
|
||||
bool isCreated = false;
|
||||
shared_ptr<Face> face;
|
||||
try {
|
||||
std::tie(isCreated, face) = createFace(m_remoteEndpoint, ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
|
||||
}
|
||||
catch (const boost::system::system_error& e) {
|
||||
NFD_LOG_WARN("[" << m_localEndpoint << "] Failed to create face for peer "
|
||||
<< m_remoteEndpoint << ": " << e.what());
|
||||
if (onReceiveFailed)
|
||||
onReceiveFailed(e.what());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCreated)
|
||||
onFaceCreated(face);
|
||||
|
||||
// dispatch the datagram to the face for processing
|
||||
static_cast<face::UnicastUdpTransport*>(face->getTransport())->receiveDatagram(m_inputBuffer, nBytesReceived, error);
|
||||
|
||||
this->waitForNewPeer(onFaceCreated, onReceiveFailed);
|
||||
}
|
||||
|
||||
std::pair<bool, shared_ptr<Face>>
|
||||
UdpChannel::createFace(const udp::Endpoint& remoteEndpoint, ndn::nfd::FacePersistency persistency)
|
||||
{
|
||||
auto it = m_channelFaces.find(remoteEndpoint);
|
||||
@@ -119,62 +166,18 @@ UdpChannel::createFace(const udp::Endpoint& remoteEndpoint, ndn::nfd::FacePersis
|
||||
|
||||
auto linkService = make_unique<face::GenericLinkService>();
|
||||
auto transport = make_unique<face::UnicastUdpTransport>(std::move(socket), persistency, m_idleFaceTimeout);
|
||||
auto lpFace = make_unique<face::LpFace>(std::move(linkService), std::move(transport));
|
||||
auto face = make_shared<face::LpFaceWrapper>(std::move(lpFace));
|
||||
auto face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
|
||||
face->setPersistency(persistency);
|
||||
face->onFail.connectSingleShot([this, remoteEndpoint] (const std::string&) {
|
||||
NFD_LOG_TRACE("Erasing " << remoteEndpoint << " from channel face map");
|
||||
m_channelFaces.erase(remoteEndpoint);
|
||||
});
|
||||
|
||||
m_channelFaces[remoteEndpoint] = face;
|
||||
connectFaceClosedSignal(*face,
|
||||
[this, remoteEndpoint] {
|
||||
NFD_LOG_TRACE("Erasing " << remoteEndpoint << " from channel face map");
|
||||
m_channelFaces.erase(remoteEndpoint);
|
||||
});
|
||||
|
||||
return {true, face};
|
||||
}
|
||||
|
||||
void
|
||||
UdpChannel::handleNewPeer(const boost::system::error_code& error,
|
||||
size_t nBytesReceived,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onReceiveFailed)
|
||||
{
|
||||
if (error) {
|
||||
if (error == boost::asio::error::operation_aborted) // when the socket is closed by someone
|
||||
return;
|
||||
|
||||
NFD_LOG_DEBUG("[" << m_localEndpoint << "] Receive failed: " << error.message());
|
||||
if (onReceiveFailed)
|
||||
onReceiveFailed(error.message());
|
||||
return;
|
||||
}
|
||||
|
||||
NFD_LOG_DEBUG("[" << m_localEndpoint << "] New peer " << m_remoteEndpoint);
|
||||
|
||||
bool created;
|
||||
shared_ptr<face::LpFaceWrapper> face;
|
||||
try {
|
||||
std::tie(created, face) = createFace(m_remoteEndpoint, ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
|
||||
}
|
||||
catch (const boost::system::system_error& e) {
|
||||
NFD_LOG_WARN("[" << m_localEndpoint << "] Failed to create face for peer "
|
||||
<< m_remoteEndpoint << ": " << e.what());
|
||||
if (onReceiveFailed)
|
||||
onReceiveFailed(e.what());
|
||||
return;
|
||||
}
|
||||
|
||||
if (created)
|
||||
onFaceCreated(face);
|
||||
|
||||
// dispatch the datagram to the face for processing
|
||||
static_cast<face::UnicastUdpTransport*>(face->getLpFace()->getTransport())->receiveDatagram(m_inputBuffer, nBytesReceived, error);
|
||||
|
||||
m_socket.async_receive_from(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
|
||||
m_remoteEndpoint,
|
||||
bind(&UdpChannel::handleNewPeer, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred,
|
||||
onFaceCreated, onReceiveFailed));
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
+26
-23
@@ -27,7 +27,6 @@
|
||||
#define NFD_DAEMON_FACE_UDP_CHANNEL_HPP
|
||||
|
||||
#include "channel.hpp"
|
||||
#include "lp-face-wrapper.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
@@ -54,6 +53,23 @@ public:
|
||||
UdpChannel(const udp::Endpoint& localEndpoint,
|
||||
const time::seconds& timeout);
|
||||
|
||||
/**
|
||||
* \brief Get number of faces in the channel
|
||||
*/
|
||||
size_t
|
||||
size() const;
|
||||
|
||||
/**
|
||||
* \brief Create a face by establishing connection to remote endpoint
|
||||
*
|
||||
* \throw UdpChannel::Error if bind or connect on the socket fail
|
||||
*/
|
||||
void
|
||||
connect(const udp::Endpoint& remoteEndpoint,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onConnectFailed);
|
||||
|
||||
/**
|
||||
* \brief Enable listening on the local endpoint, accept connections,
|
||||
* and create faces when remote host makes a connection
|
||||
@@ -68,31 +84,15 @@ public:
|
||||
*/
|
||||
void
|
||||
listen(const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onReceiveFailed);
|
||||
|
||||
/**
|
||||
* \brief Create a face by establishing connection to remote endpoint
|
||||
*
|
||||
* \throw UdpChannel::Error if bind or connect on the socket fail
|
||||
*/
|
||||
void
|
||||
connect(const udp::Endpoint& remoteEndpoint,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onConnectFailed);
|
||||
|
||||
/**
|
||||
* \brief Get number of faces in the channel
|
||||
*/
|
||||
size_t
|
||||
size() const;
|
||||
const FaceCreationFailedCallback& onReceiveFailed);
|
||||
|
||||
bool
|
||||
isListening() const;
|
||||
|
||||
private:
|
||||
std::pair<bool, shared_ptr<face::LpFaceWrapper>>
|
||||
createFace(const udp::Endpoint& remoteEndpoint, ndn::nfd::FacePersistency persistency);
|
||||
void
|
||||
waitForNewPeer(const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onReceiveFailed);
|
||||
|
||||
/**
|
||||
* \brief The channel has received a new packet from a remote
|
||||
@@ -102,10 +102,13 @@ private:
|
||||
handleNewPeer(const boost::system::error_code& error,
|
||||
size_t nBytesReceived,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onReceiveFailed);
|
||||
const FaceCreationFailedCallback& onReceiveFailed);
|
||||
|
||||
std::pair<bool, shared_ptr<Face>>
|
||||
createFace(const udp::Endpoint& remoteEndpoint, ndn::nfd::FacePersistency persistency);
|
||||
|
||||
private:
|
||||
std::map<udp::Endpoint, shared_ptr<face::LpFaceWrapper>> m_channelFaces;
|
||||
std::map<udp::Endpoint, shared_ptr<Face>> m_channelFaces;
|
||||
|
||||
udp::Endpoint m_localEndpoint;
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
#include "udp-factory.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "lp-face-wrapper.hpp"
|
||||
#include "multicast-udp-transport.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
#include "core/network-interface.hpp"
|
||||
@@ -127,7 +126,7 @@ UdpFactory::createChannel(const std::string& localIp, const std::string& localPo
|
||||
return createChannel(endpoint, timeout);
|
||||
}
|
||||
|
||||
shared_ptr<face::LpFaceWrapper>
|
||||
shared_ptr<Face>
|
||||
UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint,
|
||||
const udp::Endpoint& multicastEndpoint,
|
||||
const std::string& networkInterfaceName/* = ""*/)
|
||||
@@ -210,18 +209,15 @@ UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint,
|
||||
auto transport = make_unique<face::MulticastUdpTransport>(localEndpoint, multicastEndpoint,
|
||||
std::move(receiveSocket),
|
||||
std::move(sendSocket));
|
||||
auto lpFace = make_unique<face::LpFace>(std::move(linkService), std::move(transport));
|
||||
face = make_shared<face::LpFaceWrapper>(std::move(lpFace));
|
||||
face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
|
||||
face->onFail.connectSingleShot([this, localEndpoint] (const std::string& reason) {
|
||||
m_multicastFaces.erase(localEndpoint);
|
||||
});
|
||||
m_multicastFaces[localEndpoint] = face;
|
||||
connectFaceClosedSignal(*face, [this, localEndpoint] { m_multicastFaces.erase(localEndpoint); });
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
shared_ptr<face::LpFaceWrapper>
|
||||
shared_ptr<Face>
|
||||
UdpFactory::createMulticastFace(const std::string& localIp,
|
||||
const std::string& multicastIp,
|
||||
const std::string& multicastPort,
|
||||
@@ -294,7 +290,7 @@ UdpFactory::findChannel(const udp::Endpoint& localEndpoint) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
shared_ptr<face::LpFaceWrapper>
|
||||
shared_ptr<Face>
|
||||
UdpFactory::findMulticastFace(const udp::Endpoint& localEndpoint) const
|
||||
{
|
||||
auto i = m_multicastFaces.find(localEndpoint);
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<udp::Endpoint, shared_ptr<face::LpFaceWrapper>> MulticastFaceMap;
|
||||
typedef std::map<udp::Endpoint, shared_ptr<Face>> MulticastFaceMap;
|
||||
|
||||
/**
|
||||
* \brief Create UDP-based channel using udp::Endpoint
|
||||
@@ -128,12 +128,12 @@ public:
|
||||
* \see http://www.boost.org/doc/libs/1_42_0/doc/html/boost_asio/reference/ip__udp/endpoint.html
|
||||
* for details on ways to create udp::Endpoint
|
||||
*/
|
||||
shared_ptr<face::LpFaceWrapper>
|
||||
shared_ptr<Face>
|
||||
createMulticastFace(const udp::Endpoint& localEndpoint,
|
||||
const udp::Endpoint& multicastEndpoint,
|
||||
const std::string& networkInterfaceName = "");
|
||||
|
||||
shared_ptr<face::LpFaceWrapper>
|
||||
shared_ptr<Face>
|
||||
createMulticastFace(const std::string& localIp,
|
||||
const std::string& multicastIp,
|
||||
const std::string& multicastPort,
|
||||
@@ -181,7 +181,7 @@ private:
|
||||
* \returns shared pointer to the existing multicast UdpFace object
|
||||
* or nullptr when such face does not exist
|
||||
*/
|
||||
shared_ptr<face::LpFaceWrapper>
|
||||
shared_ptr<Face>
|
||||
findMulticastFace(const udp::Endpoint& localEndpoint) const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -41,10 +41,9 @@ NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(DatagramTransport, UnicastUdpTran
|
||||
|
||||
UnicastUdpTransport::UnicastUdpTransport(protocol::socket&& socket,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
const time::seconds& idleTimeout)
|
||||
time::nanoseconds idleTimeout)
|
||||
: DatagramTransport(std::move(socket))
|
||||
, m_idleTimeout(idleTimeout)
|
||||
, m_lastIdleCheck(time::steady_clock::now())
|
||||
{
|
||||
this->setLocalUri(FaceUri(m_socket.local_endpoint()));
|
||||
this->setRemoteUri(FaceUri(m_socket.remote_endpoint()));
|
||||
@@ -76,29 +75,38 @@ UnicastUdpTransport::UnicastUdpTransport(protocol::socket&& socket,
|
||||
#endif
|
||||
|
||||
if (getPersistency() == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND &&
|
||||
m_idleTimeout > time::seconds::zero()) {
|
||||
m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout, bind(&UnicastUdpTransport::closeIfIdle, this));
|
||||
m_idleTimeout > time::nanoseconds::zero()) {
|
||||
scheduleClosureWhenIdle();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UnicastUdpTransport::closeIfIdle()
|
||||
UnicastUdpTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
|
||||
{
|
||||
// transport can be switched from on-demand to non-on-demand mode
|
||||
// (non-on-demand -> on-demand transition is not allowed)
|
||||
if (getPersistency() == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
|
||||
if (newPersistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND &&
|
||||
m_idleTimeout > time::nanoseconds::zero()) {
|
||||
scheduleClosureWhenIdle();
|
||||
}
|
||||
else {
|
||||
m_closeIfIdleEvent.cancel();
|
||||
setExpirationTime(time::steady_clock::TimePoint::max());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UnicastUdpTransport::scheduleClosureWhenIdle()
|
||||
{
|
||||
m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout, [this] {
|
||||
if (!hasBeenUsedRecently()) {
|
||||
NFD_LOG_FACE_INFO("Closing due to inactivity");
|
||||
this->close();
|
||||
}
|
||||
else {
|
||||
resetRecentUsage();
|
||||
|
||||
m_lastIdleCheck = time::steady_clock::now();
|
||||
m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout, bind(&UnicastUdpTransport::closeIfIdle, this));
|
||||
scheduleClosureWhenIdle();
|
||||
}
|
||||
}
|
||||
// else do nothing and do not reschedule the event
|
||||
});
|
||||
setExpirationTime(time::steady_clock::now() + m_idleTimeout);
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
|
||||
@@ -35,20 +35,23 @@ namespace face {
|
||||
/**
|
||||
* \brief A Transport that communicates on a unicast UDP socket
|
||||
*/
|
||||
class UnicastUdpTransport : public DatagramTransport<boost::asio::ip::udp, Unicast>
|
||||
class UnicastUdpTransport DECL_CLASS_FINAL : public DatagramTransport<boost::asio::ip::udp, Unicast>
|
||||
{
|
||||
public:
|
||||
UnicastUdpTransport(protocol::socket&& socket,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
const time::seconds& idleTimeout);
|
||||
time::nanoseconds idleTimeout);
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
|
||||
|
||||
private:
|
||||
void
|
||||
closeIfIdle();
|
||||
scheduleClosureWhenIdle();
|
||||
|
||||
private:
|
||||
const time::seconds m_idleTimeout;
|
||||
time::steady_clock::TimePoint m_lastIdleCheck;
|
||||
const time::nanoseconds m_idleTimeout;
|
||||
scheduler::ScopedEventId m_closeIfIdleEvent;
|
||||
};
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
#include "unix-stream-channel.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "lp-face-wrapper.hpp"
|
||||
#include "unix-stream-transport.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
|
||||
@@ -58,7 +57,7 @@ UnixStreamChannel::~UnixStreamChannel()
|
||||
|
||||
void
|
||||
UnixStreamChannel::listen(const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onAcceptFailed,
|
||||
const FaceCreationFailedCallback& onAcceptFailed,
|
||||
int backlog/* = acceptor::max_connections*/)
|
||||
{
|
||||
if (isListening()) {
|
||||
@@ -109,7 +108,7 @@ UnixStreamChannel::listen(const FaceCreatedCallback& onFaceCreated,
|
||||
|
||||
void
|
||||
UnixStreamChannel::accept(const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onAcceptFailed)
|
||||
const FaceCreationFailedCallback& onAcceptFailed)
|
||||
{
|
||||
m_acceptor.async_accept(m_socket, bind(&UnixStreamChannel::handleAccept, this,
|
||||
boost::asio::placeholders::error,
|
||||
@@ -119,7 +118,7 @@ UnixStreamChannel::accept(const FaceCreatedCallback& onFaceCreated,
|
||||
void
|
||||
UnixStreamChannel::handleAccept(const boost::system::error_code& error,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onAcceptFailed)
|
||||
const FaceCreationFailedCallback& onAcceptFailed)
|
||||
{
|
||||
if (error) {
|
||||
if (error == boost::asio::error::operation_aborted) // when the socket is closed by someone
|
||||
@@ -135,8 +134,7 @@ UnixStreamChannel::handleAccept(const boost::system::error_code& error,
|
||||
|
||||
auto linkService = make_unique<face::GenericLinkService>();
|
||||
auto transport = make_unique<face::UnixStreamTransport>(std::move(m_socket));
|
||||
auto lpFace = make_unique<face::LpFace>(std::move(linkService), std::move(transport));
|
||||
auto face = make_shared<face::LpFaceWrapper>(std::move(lpFace));
|
||||
auto face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
onFaceCreated(face);
|
||||
|
||||
// prepare accepting the next connection
|
||||
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
*/
|
||||
void
|
||||
listen(const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onAcceptFailed,
|
||||
const FaceCreationFailedCallback& onAcceptFailed,
|
||||
int backlog = boost::asio::local::stream_protocol::acceptor::max_connections);
|
||||
|
||||
bool
|
||||
@@ -81,12 +81,12 @@ public:
|
||||
private:
|
||||
void
|
||||
accept(const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onAcceptFailed);
|
||||
const FaceCreationFailedCallback& onAcceptFailed);
|
||||
|
||||
void
|
||||
handleAccept(const boost::system::error_code& error,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const ConnectFailedCallback& onAcceptFailed);
|
||||
const FaceCreationFailedCallback& onAcceptFailed);
|
||||
|
||||
private:
|
||||
unix_stream::Endpoint m_endpoint;
|
||||
|
||||
@@ -36,7 +36,7 @@ UnixStreamTransport::UnixStreamTransport(protocol::socket&& socket)
|
||||
{
|
||||
static_assert(
|
||||
std::is_same<std::remove_cv<protocol::socket::native_handle_type>::type, int>::value,
|
||||
"The native handle type for UnixStreamFace sockets must be 'int'"
|
||||
"The native handle type for UnixStreamTransport sockets must be 'int'"
|
||||
);
|
||||
|
||||
this->setLocalUri(FaceUri(m_socket.local_endpoint()));
|
||||
@@ -46,7 +46,16 @@ UnixStreamTransport::UnixStreamTransport(protocol::socket&& socket)
|
||||
this->setLinkType(ndn::nfd::LINK_TYPE_POINT_TO_POINT);
|
||||
this->setMtu(MTU_UNLIMITED);
|
||||
|
||||
NFD_LOG_FACE_INFO("Creating Transport");
|
||||
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
|
||||
|
||||
@@ -38,11 +38,15 @@ namespace face {
|
||||
/**
|
||||
* \brief A Transport that communicates on a stream-oriented Unix domain socket
|
||||
*/
|
||||
class UnixStreamTransport : public StreamTransport<boost::asio::local::stream_protocol>
|
||||
class UnixStreamTransport DECL_CLASS_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
|
||||
|
||||
@@ -24,10 +24,9 @@
|
||||
*/
|
||||
|
||||
#include "websocket-channel.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "websocket-transport.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
#include "core/scheduler.hpp"
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
namespace nfd {
|
||||
|
||||
@@ -35,23 +34,23 @@ NFD_LOG_INIT("WebSocketChannel");
|
||||
|
||||
WebSocketChannel::WebSocketChannel(const websocket::Endpoint& localEndpoint)
|
||||
: m_localEndpoint(localEndpoint)
|
||||
, m_isListening(false)
|
||||
, m_pingInterval(10000)
|
||||
{
|
||||
setUri(FaceUri(m_localEndpoint, "ws"));
|
||||
|
||||
// Setup WebSocket server
|
||||
// Be quiet
|
||||
m_server.clear_access_channels(websocketpp::log::alevel::all);
|
||||
m_server.clear_error_channels(websocketpp::log::alevel::all);
|
||||
m_server.clear_error_channels(websocketpp::log::elevel::all);
|
||||
|
||||
m_server.set_message_handler(bind(&WebSocketChannel::handleMessage, this, _1, _2));
|
||||
// Setup WebSocket server
|
||||
m_server.init_asio(&getGlobalIoService());
|
||||
m_server.set_open_handler(bind(&WebSocketChannel::handleOpen, this, _1));
|
||||
m_server.set_close_handler(bind(&WebSocketChannel::handleClose, this, _1));
|
||||
m_server.init_asio(&getGlobalIoService());
|
||||
m_server.set_message_handler(bind(&WebSocketChannel::handleMessage, this, _1, _2));
|
||||
|
||||
// Detect disconnections using ping-pong messages
|
||||
m_server.set_pong_handler(bind(&WebSocketChannel::handlePong, this, _1, _2));
|
||||
m_server.set_pong_timeout_handler(bind(&WebSocketChannel::handlePongTimeout, this, _1, _2));
|
||||
m_server.set_pong_handler(bind(&WebSocketChannel::handlePong, this, _1));
|
||||
m_server.set_pong_timeout_handler(bind(&WebSocketChannel::handlePongTimeout, this, _1));
|
||||
|
||||
// Always set SO_REUSEADDR flag
|
||||
m_server.set_reuse_addr(true);
|
||||
@@ -60,32 +59,40 @@ WebSocketChannel::WebSocketChannel(const websocket::Endpoint& localEndpoint)
|
||||
void
|
||||
WebSocketChannel::setPingInterval(time::milliseconds interval)
|
||||
{
|
||||
BOOST_ASSERT(!m_server.is_listening());
|
||||
|
||||
m_pingInterval = interval;
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketChannel::setPongTimeout(time::milliseconds timeout)
|
||||
{
|
||||
BOOST_ASSERT(!m_server.is_listening());
|
||||
|
||||
m_server.set_pong_timeout(static_cast<long>(timeout.count()));
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketChannel::handlePongTimeout(websocketpp::connection_hdl hdl, std::string msg)
|
||||
WebSocketChannel::handlePongTimeout(websocketpp::connection_hdl hdl)
|
||||
{
|
||||
auto it = m_channelFaces.find(hdl);
|
||||
if (it != m_channelFaces.end()) {
|
||||
NFD_LOG_TRACE(__func__ << ": " << it->second->getRemoteUri());
|
||||
it->second->close();
|
||||
m_channelFaces.erase(it);
|
||||
static_cast<face::WebSocketTransport*>(it->second->getTransport())->handlePongTimeout();
|
||||
}
|
||||
else {
|
||||
NFD_LOG_WARN("Pong timeout on unknown transport");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketChannel::handlePong(websocketpp::connection_hdl hdl, std::string msg)
|
||||
WebSocketChannel::handlePong(websocketpp::connection_hdl hdl)
|
||||
{
|
||||
auto it = m_channelFaces.find(hdl);
|
||||
if (it != m_channelFaces.end()) {
|
||||
NFD_LOG_TRACE("Pong from " << it->second->getRemoteUri());
|
||||
static_cast<face::WebSocketTransport*>(it->second->getTransport())->handlePong();
|
||||
}
|
||||
else {
|
||||
NFD_LOG_WARN("Pong received on unknown transport");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,62 +102,24 @@ WebSocketChannel::handleMessage(websocketpp::connection_hdl hdl,
|
||||
{
|
||||
auto it = m_channelFaces.find(hdl);
|
||||
if (it != m_channelFaces.end()) {
|
||||
it->second->handleReceive(msg->get_payload());
|
||||
static_cast<face::WebSocketTransport*>(it->second->getTransport())->receiveMessage(msg->get_payload());
|
||||
}
|
||||
else {
|
||||
NFD_LOG_WARN("Message received on unknown transport");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketChannel::handleOpen(websocketpp::connection_hdl hdl)
|
||||
{
|
||||
try {
|
||||
std::string remote = "wsclient://" + m_server.get_con_from_hdl(hdl)->get_remote_endpoint();
|
||||
auto face = make_shared<WebSocketFace>(FaceUri(remote), this->getUri(),
|
||||
hdl, ref(m_server));
|
||||
m_onFaceCreatedCallback(face);
|
||||
m_channelFaces[hdl] = face;
|
||||
// Schedule ping message
|
||||
scheduler::EventId pingEvent = scheduler::schedule(m_pingInterval,
|
||||
bind(&WebSocketChannel::sendPing,
|
||||
this, hdl));
|
||||
face->setPingEventId(pingEvent);
|
||||
}
|
||||
catch (const FaceUri::Error& e) {
|
||||
NFD_LOG_WARN(e.what());
|
||||
websocketpp::lib::error_code ec;
|
||||
m_server.close(hdl, websocketpp::close::status::normal, "closed by channel", ec);
|
||||
// ignore error on close
|
||||
}
|
||||
catch (const websocketpp::exception& e) {
|
||||
NFD_LOG_WARN("Cannot get remote connection: " << e.what());
|
||||
websocketpp::lib::error_code ec;
|
||||
m_server.close(hdl, websocketpp::close::status::normal, "closed by channel", ec);
|
||||
// ignore error on close
|
||||
}
|
||||
}
|
||||
auto linkService = make_unique<face::GenericLinkService>();
|
||||
auto transport = make_unique<face::WebSocketTransport>(hdl, ref(m_server), m_pingInterval);
|
||||
auto face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
|
||||
void
|
||||
WebSocketChannel::sendPing(websocketpp::connection_hdl hdl)
|
||||
{
|
||||
auto it = m_channelFaces.find(hdl);
|
||||
if (it != m_channelFaces.end()) {
|
||||
NFD_LOG_TRACE("Sending ping to " << it->second->getRemoteUri());
|
||||
m_channelFaces[hdl] = face;
|
||||
connectFaceClosedSignal(*face, [this, hdl] { m_channelFaces.erase(hdl); });
|
||||
|
||||
websocketpp::lib::error_code ec;
|
||||
m_server.ping(hdl, "NFD-WebSocket", ec);
|
||||
if (ec)
|
||||
{
|
||||
NFD_LOG_WARN("Failed to ping " << it->second->getRemoteUri() << ": " << ec.message());
|
||||
it->second->close();
|
||||
m_channelFaces.erase(it);
|
||||
return;
|
||||
}
|
||||
|
||||
// Schedule next ping message
|
||||
scheduler::EventId pingEvent = scheduler::schedule(m_pingInterval,
|
||||
bind(&WebSocketChannel::sendPing,
|
||||
this, hdl));
|
||||
it->second->setPingEventId(pingEvent);
|
||||
}
|
||||
m_onFaceCreatedCallback(face);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -158,20 +127,20 @@ WebSocketChannel::handleClose(websocketpp::connection_hdl hdl)
|
||||
{
|
||||
auto it = m_channelFaces.find(hdl);
|
||||
if (it != m_channelFaces.end()) {
|
||||
NFD_LOG_TRACE(__func__ << ": " << it->second->getRemoteUri());
|
||||
it->second->close();
|
||||
m_channelFaces.erase(it);
|
||||
}
|
||||
else {
|
||||
NFD_LOG_WARN("Close on unknown transport");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketChannel::listen(const FaceCreatedCallback& onFaceCreated)
|
||||
{
|
||||
if (isListening()) {
|
||||
if (m_server.is_listening()) {
|
||||
NFD_LOG_WARN("[" << m_localEndpoint << "] Already listening");
|
||||
return;
|
||||
}
|
||||
m_isListening = true;
|
||||
|
||||
m_onFaceCreatedCallback = onFaceCreated;
|
||||
m_server.listen(m_localEndpoint);
|
||||
|
||||
@@ -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-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.
|
||||
@@ -21,13 +21,13 @@
|
||||
*
|
||||
* 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_WEBSOCKET_CHANNEL_HPP
|
||||
#define NFD_DAEMON_FACE_WEBSOCKET_CHANNEL_HPP
|
||||
|
||||
#include "channel.hpp"
|
||||
#include "websocket-face.hpp"
|
||||
#include "websocketpp.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
@@ -46,9 +46,7 @@ public:
|
||||
*
|
||||
* To enable creation of faces upon incoming connections,
|
||||
* one needs to explicitly call WebSocketChannel::listen method.
|
||||
* The created socket is bound to the localEndpoint.
|
||||
*
|
||||
* \throw WebSocketChannel::Error if bind on the socket fails
|
||||
* The created channel is bound to the localEndpoint.
|
||||
*/
|
||||
explicit
|
||||
WebSocketChannel(const websocket::Endpoint& localEndpoint);
|
||||
@@ -56,9 +54,8 @@ public:
|
||||
/**
|
||||
* \brief Enable listening on the local endpoint, accept connections,
|
||||
* and create faces when remote host makes a connection
|
||||
* \param onFaceCreated Callback to notify successful creation of the face
|
||||
*
|
||||
* \throws WebSocketChannel::Error if called multiple times
|
||||
* \param onFaceCreated Callback to notify successful creation of a face
|
||||
*/
|
||||
void
|
||||
listen(const FaceCreatedCallback& onFaceCreated);
|
||||
@@ -73,24 +70,26 @@ public:
|
||||
isListening() const;
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
/** \pre listen hasn't been invoked
|
||||
*/
|
||||
void
|
||||
setPingInterval(time::milliseconds interval);
|
||||
|
||||
/** \pre listen hasn't been invoked
|
||||
*/
|
||||
void
|
||||
setPongTimeout(time::milliseconds timeout);
|
||||
|
||||
void
|
||||
handlePong(websocketpp::connection_hdl hdl);
|
||||
|
||||
void
|
||||
handlePongTimeout(websocketpp::connection_hdl hdl);
|
||||
|
||||
private:
|
||||
void
|
||||
sendPing(websocketpp::connection_hdl hdl);
|
||||
|
||||
void
|
||||
handlePong(websocketpp::connection_hdl hdl, std::string msg);
|
||||
|
||||
void
|
||||
handlePongTimeout(websocketpp::connection_hdl hdl, std::string msg);
|
||||
|
||||
void
|
||||
handleMessage(websocketpp::connection_hdl hdl, websocket::Server::message_ptr msg);
|
||||
handleMessage(websocketpp::connection_hdl hdl,
|
||||
websocket::Server::message_ptr msg);
|
||||
|
||||
void
|
||||
handleOpen(websocketpp::connection_hdl hdl);
|
||||
@@ -102,26 +101,17 @@ private:
|
||||
websocket::Endpoint m_localEndpoint;
|
||||
websocket::Server m_server;
|
||||
|
||||
std::map<websocketpp::connection_hdl, shared_ptr<WebSocketFace>,
|
||||
std::map<websocketpp::connection_hdl, shared_ptr<Face>,
|
||||
std::owner_less<websocketpp::connection_hdl>> m_channelFaces;
|
||||
|
||||
/**
|
||||
* Callback for face creation
|
||||
*/
|
||||
FaceCreatedCallback m_onFaceCreatedCallback;
|
||||
|
||||
/**
|
||||
* \brief If true, it means the function listen has already been called
|
||||
*/
|
||||
bool m_isListening;
|
||||
|
||||
time::milliseconds m_pingInterval;
|
||||
};
|
||||
|
||||
inline bool
|
||||
WebSocketChannel::isListening() const
|
||||
{
|
||||
return m_isListening;
|
||||
return m_server.is_listening();
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
@@ -1,131 +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/>.
|
||||
*/
|
||||
|
||||
#include "websocket-face.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
NFD_LOG_INIT("WebSocketFace");
|
||||
|
||||
WebSocketFace::WebSocketFace(const FaceUri& remoteUri, const FaceUri& localUri,
|
||||
websocketpp::connection_hdl hdl,
|
||||
websocket::Server& server)
|
||||
: Face(remoteUri, localUri)
|
||||
, m_handle(hdl)
|
||||
, m_server(server)
|
||||
, m_closed(false)
|
||||
{
|
||||
NFD_LOG_FACE_INFO("Creating face");
|
||||
this->setPersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketFace::sendInterest(const Interest& interest)
|
||||
{
|
||||
if (m_closed)
|
||||
return;
|
||||
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
this->emitSignal(onSendInterest, interest);
|
||||
|
||||
const Block& payload = interest.wireEncode();
|
||||
this->getMutableCounters().getNOutBytes() += payload.size();
|
||||
|
||||
websocketpp::lib::error_code ec;
|
||||
m_server.send(m_handle, payload.wire(), payload.size(),
|
||||
websocketpp::frame::opcode::binary, ec);
|
||||
if (ec)
|
||||
NFD_LOG_FACE_WARN("Failed to send Interest: " << ec.message());
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketFace::sendData(const Data& data)
|
||||
{
|
||||
if (m_closed)
|
||||
return;
|
||||
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
this->emitSignal(onSendData, data);
|
||||
|
||||
const Block& payload = data.wireEncode();
|
||||
this->getMutableCounters().getNOutBytes() += payload.size();
|
||||
|
||||
websocketpp::lib::error_code ec;
|
||||
m_server.send(m_handle, payload.wire(), payload.size(),
|
||||
websocketpp::frame::opcode::binary, ec);
|
||||
if (ec)
|
||||
NFD_LOG_FACE_WARN("Failed to send Data: " << ec.message());
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketFace::close()
|
||||
{
|
||||
if (m_closed)
|
||||
return;
|
||||
|
||||
NFD_LOG_FACE_INFO("Closing face");
|
||||
|
||||
m_closed = true;
|
||||
scheduler::cancel(m_pingEventId);
|
||||
websocketpp::lib::error_code ec;
|
||||
m_server.close(m_handle, websocketpp::close::status::normal, "closed by nfd", ec);
|
||||
// ignore error on close
|
||||
fail("Face closed");
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketFace::handleReceive(const std::string& msg)
|
||||
{
|
||||
// Copy message into Face internal buffer
|
||||
if (msg.size() > ndn::MAX_NDN_PACKET_SIZE)
|
||||
{
|
||||
NFD_LOG_FACE_WARN("Received WebSocket message is too big (" << msg.size() << " bytes)");
|
||||
return;
|
||||
}
|
||||
|
||||
NFD_LOG_FACE_TRACE("Received: " << msg.size() << " bytes");
|
||||
this->getMutableCounters().getNInBytes() += msg.size();
|
||||
|
||||
// Try to parse message data
|
||||
bool isOk = false;
|
||||
Block element;
|
||||
std::tie(isOk, element) = Block::fromBuffer(reinterpret_cast<const uint8_t*>(msg.c_str()),
|
||||
msg.size());
|
||||
if (!isOk)
|
||||
{
|
||||
NFD_LOG_FACE_WARN("Received block is invalid or too large to process");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this->decodeAndDispatchInput(element))
|
||||
{
|
||||
NFD_LOG_FACE_WARN("Received unrecognized TLV block of type " << element.type());
|
||||
// ignore unknown packet and proceed
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,167 @@
|
||||
/* -*- 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/>.
|
||||
*/
|
||||
|
||||
#include "websocket-transport.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INIT("WebSocketTransport");
|
||||
|
||||
WebSocketTransport::WebSocketTransport(websocketpp::connection_hdl hdl,
|
||||
websocket::Server& server,
|
||||
time::milliseconds pingInterval)
|
||||
: m_handle(hdl)
|
||||
, m_server(server)
|
||||
, m_pingInterval(pingInterval)
|
||||
{
|
||||
const auto& sock = m_server.get_con_from_hdl(hdl)->get_socket();
|
||||
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())
|
||||
this->setScope(ndn::nfd::FACE_SCOPE_LOCAL);
|
||||
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);
|
||||
this->setMtu(MTU_UNLIMITED);
|
||||
|
||||
this->schedulePing();
|
||||
|
||||
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)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
websocketpp::lib::error_code error;
|
||||
m_server.send(m_handle, packet.packet.wire(), packet.packet.size(),
|
||||
websocketpp::frame::opcode::binary, error);
|
||||
if (error)
|
||||
return processErrorCode(error);
|
||||
|
||||
NFD_LOG_FACE_TRACE("Successfully sent: " << packet.packet.size() << " bytes");
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketTransport::receiveMessage(const std::string& msg)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE("Received: " << msg.size() << " bytes");
|
||||
|
||||
bool isOk = false;
|
||||
Block element;
|
||||
std::tie(isOk, element) = Block::fromBuffer(reinterpret_cast<const uint8_t*>(msg.c_str()), msg.size());
|
||||
if (!isOk) {
|
||||
NFD_LOG_FACE_WARN("Failed to parse message payload");
|
||||
return;
|
||||
}
|
||||
|
||||
this->receive(Transport::Packet(std::move(element)));
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketTransport::schedulePing()
|
||||
{
|
||||
m_pingEventId = scheduler::schedule(m_pingInterval, bind(&WebSocketTransport::sendPing, this));
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketTransport::sendPing()
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
++this->nOutPings;
|
||||
|
||||
websocketpp::lib::error_code error;
|
||||
m_server.ping(m_handle, "NFD-WebSocket", error);
|
||||
if (error)
|
||||
return processErrorCode(error);
|
||||
|
||||
this->schedulePing();
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketTransport::handlePong()
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
++this->nInPongs;
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketTransport::handlePongTimeout()
|
||||
{
|
||||
NFD_LOG_FACE_WARN(__func__);
|
||||
this->setState(TransportState::FAILED);
|
||||
doClose();
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketTransport::processErrorCode(const websocketpp::lib::error_code& error)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
if (getState() == TransportState::CLOSING ||
|
||||
getState() == TransportState::FAILED ||
|
||||
getState() == TransportState::CLOSED)
|
||||
// transport is shutting down, ignore any errors
|
||||
return;
|
||||
|
||||
NFD_LOG_FACE_WARN("Send or ping operation failed: " << error.message());
|
||||
|
||||
this->setState(TransportState::FAILED);
|
||||
doClose();
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketTransport::doClose()
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
m_pingEventId.cancel();
|
||||
|
||||
// use the non-throwing variant and ignore errors, if any
|
||||
websocketpp::lib::error_code error;
|
||||
m_server.close(m_handle, websocketpp::close::status::normal, "closed by NFD", error);
|
||||
|
||||
this->setState(TransportState::CLOSED);
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,117 @@
|
||||
/* -*- 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_DAEMON_FACE_WEBSOCKET_TRANSPORT_HPP
|
||||
#define NFD_DAEMON_FACE_WEBSOCKET_TRANSPORT_HPP
|
||||
|
||||
#include "transport.hpp"
|
||||
#include "websocketpp.hpp"
|
||||
#include "core/scheduler.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief counters provided by WebSocketTransport
|
||||
* \note The type name 'WebSocketTransportCounters' is implementation detail.
|
||||
* Use 'WebSocketTransport::Counters' in public API.
|
||||
*/
|
||||
class WebSocketTransportCounters : public virtual Transport::Counters
|
||||
{
|
||||
public:
|
||||
/** \brief count of outgoing Pings
|
||||
*/
|
||||
PacketCounter nOutPings;
|
||||
|
||||
/** \brief count of incoming Pongs
|
||||
*/
|
||||
PacketCounter nInPongs;
|
||||
};
|
||||
|
||||
/** \brief A Transport that communicates on a WebSocket connection
|
||||
*/
|
||||
class WebSocketTransport DECL_CLASS_FINAL : public Transport
|
||||
, protected virtual WebSocketTransportCounters
|
||||
{
|
||||
public:
|
||||
/** \brief counters provided by WebSocketTransport
|
||||
*/
|
||||
typedef WebSocketTransportCounters Counters;
|
||||
|
||||
WebSocketTransport(websocketpp::connection_hdl hdl,
|
||||
websocket::Server& server,
|
||||
time::milliseconds pingInterval);
|
||||
|
||||
virtual const Counters&
|
||||
getCounters() const DECL_OVERRIDE;
|
||||
|
||||
/** \brief Translates a message into a Block
|
||||
* and delivers it to the link service
|
||||
*/
|
||||
void
|
||||
receiveMessage(const std::string& msg);
|
||||
|
||||
void
|
||||
handlePong();
|
||||
|
||||
void
|
||||
handlePongTimeout();
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
|
||||
|
||||
virtual void
|
||||
doClose() DECL_FINAL;
|
||||
|
||||
private:
|
||||
virtual void
|
||||
doSend(Transport::Packet&& packet) DECL_FINAL;
|
||||
|
||||
void
|
||||
schedulePing();
|
||||
|
||||
void
|
||||
sendPing();
|
||||
|
||||
void
|
||||
processErrorCode(const websocketpp::lib::error_code& error);
|
||||
|
||||
private:
|
||||
websocketpp::connection_hdl m_handle;
|
||||
websocket::Server& m_server;
|
||||
time::milliseconds m_pingInterval;
|
||||
scheduler::ScopedEventId m_pingEventId;
|
||||
};
|
||||
|
||||
inline const WebSocketTransport::Counters&
|
||||
WebSocketTransport::getCounters() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_WEBSOCKET_TRANSPORT_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-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.
|
||||
@@ -27,14 +27,25 @@
|
||||
#define NFD_DAEMON_FACE_WEBSOCKETPP_HPP
|
||||
|
||||
#ifndef HAVE_WEBSOCKET
|
||||
#error "This file must not be included when WebSocket Face support is disabled"
|
||||
#endif
|
||||
#error "Cannot include this file when WebSocket support is disabled"
|
||||
#endif // HAVE_WEBSOCKET
|
||||
|
||||
// suppress websocketpp warnings
|
||||
#pragma GCC system_header
|
||||
#pragma clang system_header
|
||||
|
||||
#include <websocketpp/config/asio_no_tls_client.hpp>
|
||||
#include <websocketpp/client.hpp>
|
||||
#include "websocketpp/config/asio_no_tls.hpp"
|
||||
#include "websocketpp/server.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace websocket {
|
||||
|
||||
typedef websocketpp::client<websocketpp::config::asio_client> Client;
|
||||
typedef websocketpp::server<websocketpp::config::asio> Server;
|
||||
|
||||
} // namespace websocket
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_WEBSOCKETPP_HPP
|
||||
@@ -115,7 +115,7 @@ bool
|
||||
AccessStrategy::sendToLastNexthop(const Face& inFace, shared_ptr<pit::Entry> pitEntry, MtInfo& mi,
|
||||
shared_ptr<fib::Entry> fibEntry)
|
||||
{
|
||||
if (mi.lastNexthop == INVALID_FACEID) {
|
||||
if (mi.lastNexthop == face::INVALID_FACEID) {
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " no-last-nexthop");
|
||||
return false;
|
||||
}
|
||||
@@ -231,7 +231,7 @@ AccessStrategy::updateMeasurements(const Face& inFace, const Data& data,
|
||||
}
|
||||
|
||||
AccessStrategy::MtInfo::MtInfo()
|
||||
: lastNexthop(INVALID_FACEID)
|
||||
: lastNexthop(face::INVALID_FACEID)
|
||||
, rtt(1, time::milliseconds(1), 0.1)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -34,8 +34,14 @@ 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)
|
||||
, m_retxSuppression(RETX_SUPPRESSION_INITIAL,
|
||||
RetxSuppressionExponential::DEFAULT_MULTIPLIER,
|
||||
RETX_SUPPRESSION_MAX)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,9 @@ public:
|
||||
public:
|
||||
static const Name STRATEGY_NAME;
|
||||
|
||||
private:
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
static const time::milliseconds RETX_SUPPRESSION_INITIAL;
|
||||
static const time::milliseconds RETX_SUPPRESSION_MAX;
|
||||
RetxSuppressionExponential m_retxSuppression;
|
||||
};
|
||||
|
||||
|
||||
@@ -50,16 +50,15 @@ ClientControlStrategy::afterReceiveInterest(const Face& inFace,
|
||||
shared_ptr<fib::Entry> fibEntry,
|
||||
shared_ptr<pit::Entry> pitEntry)
|
||||
{
|
||||
// Strategy needn't check whether LocalControlHeader-NextHopFaceId is enabled.
|
||||
// LocalFace does this check.
|
||||
if (!interest.getLocalControlHeader().hasNextHopFaceId()) {
|
||||
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>(interest.getNextHopFaceId());
|
||||
FaceId outFaceId = static_cast<FaceId>(*tag);
|
||||
shared_ptr<Face> outFace = this->getFace(outFaceId);
|
||||
if (!static_cast<bool>(outFace)) {
|
||||
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() <<
|
||||
|
||||
@@ -31,8 +31,11 @@
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
/** \brief a forwarding strategy that forwards Interests
|
||||
* according to NextHopFaceId field in LocalControlHeader
|
||||
/** \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.
|
||||
*/
|
||||
class ClientControlStrategy : public BestRouteStrategy
|
||||
{
|
||||
|
||||
+15
-18
@@ -27,6 +27,7 @@
|
||||
#include "forwarder.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
#include "core/logger.hpp"
|
||||
#include "face/channel.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
@@ -34,7 +35,7 @@ NFD_LOG_INIT("FaceTable");
|
||||
|
||||
FaceTable::FaceTable(Forwarder& forwarder)
|
||||
: m_forwarder(forwarder)
|
||||
, m_lastFaceId(FACEID_RESERVED_MAX)
|
||||
, m_lastFaceId(face::FACEID_RESERVED_MAX)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -59,22 +60,22 @@ FaceTable::size() const
|
||||
void
|
||||
FaceTable::add(shared_ptr<Face> face)
|
||||
{
|
||||
if (face->getId() != INVALID_FACEID && m_faces.count(face->getId()) > 0) {
|
||||
if (face->getId() != face::INVALID_FACEID && m_faces.count(face->getId()) > 0) {
|
||||
NFD_LOG_WARN("Trying to add existing face id=" << face->getId() << " to the face table");
|
||||
return;
|
||||
}
|
||||
|
||||
FaceId faceId = ++m_lastFaceId;
|
||||
BOOST_ASSERT(faceId > FACEID_RESERVED_MAX);
|
||||
BOOST_ASSERT(faceId > face::FACEID_RESERVED_MAX);
|
||||
this->addImpl(face, faceId);
|
||||
}
|
||||
|
||||
void
|
||||
FaceTable::addReserved(shared_ptr<Face> face, FaceId faceId)
|
||||
{
|
||||
BOOST_ASSERT(face->getId() == INVALID_FACEID);
|
||||
BOOST_ASSERT(face->getId() == face::INVALID_FACEID);
|
||||
BOOST_ASSERT(m_faces.count(face->getId()) == 0);
|
||||
BOOST_ASSERT(faceId <= FACEID_RESERVED_MAX);
|
||||
BOOST_ASSERT(faceId <= face::FACEID_RESERVED_MAX);
|
||||
this->addImpl(face, faceId);
|
||||
}
|
||||
|
||||
@@ -86,30 +87,26 @@ FaceTable::addImpl(shared_ptr<Face> face, FaceId faceId)
|
||||
NFD_LOG_INFO("Added face id=" << faceId << " remote=" << face->getRemoteUri()
|
||||
<< " local=" << face->getLocalUri());
|
||||
|
||||
face->onReceiveInterest.connect(bind(&Forwarder::startProcessInterest,
|
||||
&m_forwarder, ref(*face), _1));
|
||||
face->onReceiveData.connect(bind(&Forwarder::startProcessData,
|
||||
&m_forwarder, ref(*face), _1));
|
||||
face->onReceiveNack.connect(bind(&Forwarder::startProcessNack,
|
||||
&m_forwarder, ref(*face), _1));
|
||||
face->onFail.connectSingleShot(bind(&FaceTable::remove, this, face, _1));
|
||||
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));
|
||||
|
||||
this->onAdd(face);
|
||||
this->afterAdd(face);
|
||||
}
|
||||
|
||||
void
|
||||
FaceTable::remove(shared_ptr<Face> face, const std::string& reason)
|
||||
FaceTable::remove(shared_ptr<Face> face)
|
||||
{
|
||||
this->onRemove(face);
|
||||
this->beforeRemove(face);
|
||||
|
||||
FaceId faceId = face->getId();
|
||||
m_faces.erase(faceId);
|
||||
face->setId(INVALID_FACEID);
|
||||
face->setId(face::INVALID_FACEID);
|
||||
|
||||
NFD_LOG_INFO("Removed face id=" << faceId <<
|
||||
" remote=" << face->getRemoteUri() <<
|
||||
" local=" << face->getLocalUri() <<
|
||||
" (" << reason << ")");
|
||||
" local=" << face->getLocalUri());
|
||||
|
||||
m_forwarder.getFib().removeNextHopFromAllEntries(face);
|
||||
|
||||
|
||||
+10
-12
@@ -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-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.
|
||||
@@ -75,22 +75,20 @@ public: // enumeration
|
||||
public: // signals
|
||||
/** \brief fires after a Face is added
|
||||
*/
|
||||
signal::Signal<FaceTable, shared_ptr<Face>> onAdd;
|
||||
signal::Signal<FaceTable, shared_ptr<Face>> afterAdd;
|
||||
|
||||
/** \brief fires before a Face is removed
|
||||
*
|
||||
* FaceId is valid when this event is fired
|
||||
*/
|
||||
signal::Signal<FaceTable, shared_ptr<Face>> onRemove;
|
||||
signal::Signal<FaceTable, shared_ptr<Face>> beforeRemove;
|
||||
|
||||
private:
|
||||
void
|
||||
addImpl(shared_ptr<Face> face, FaceId faceId);
|
||||
|
||||
// remove is private because it's a handler of face.onFail signal.
|
||||
// face->close() closes the face and triggers .remove()
|
||||
void
|
||||
remove(shared_ptr<Face> face, const std::string& reason);
|
||||
remove(shared_ptr<Face> face);
|
||||
|
||||
ForwardRange
|
||||
getForwardRange() const;
|
||||
|
||||
@@ -26,24 +26,21 @@
|
||||
#ifndef NFD_DAEMON_FW_FORWARDER_COUNTERS_HPP
|
||||
#define NFD_DAEMON_FW_FORWARDER_COUNTERS_HPP
|
||||
|
||||
#include "face/face-counters.hpp"
|
||||
#include "core/counter.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/** \brief contains counters on forwarder
|
||||
/** \brief counters provided by Forwarder
|
||||
*/
|
||||
class ForwarderCounters : public NetworkLayerCounters
|
||||
class ForwarderCounters
|
||||
{
|
||||
public:
|
||||
/** \brief copy current obseverations to a struct
|
||||
* \param recipient an object with set methods for counters
|
||||
*/
|
||||
template<typename R>
|
||||
void
|
||||
copyTo(R& recipient) const
|
||||
{
|
||||
this->NetworkLayerCounters::copyTo(recipient);
|
||||
}
|
||||
PacketCounter nInInterests;
|
||||
PacketCounter nOutInterests;
|
||||
PacketCounter nInData;
|
||||
PacketCounter nOutData;
|
||||
PacketCounter nInNacks;
|
||||
PacketCounter nOutNacks;
|
||||
};
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
+37
-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,
|
||||
@@ -104,11 +104,11 @@ Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
|
||||
// receive Interest
|
||||
NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
|
||||
" interest=" << interest.getName());
|
||||
const_cast<Interest&>(interest).setIncomingFaceId(inFace.getId());
|
||||
++m_counters.getNInInterests();
|
||||
interest.setTag(make_shared<lp::IncomingFaceIdTag>(inFace.getId()));
|
||||
++m_counters.nInInterests;
|
||||
|
||||
// /localhost scope control
|
||||
bool isViolatingLocalhost = !inFace.isLocal() &&
|
||||
bool isViolatingLocalhost = inFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
|
||||
LOCALHOST_NAME.isPrefixOf(interest.getName());
|
||||
if (isViolatingLocalhost) {
|
||||
NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
|
||||
@@ -117,16 +117,23 @@ Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
|
||||
return;
|
||||
}
|
||||
|
||||
// detect duplicate Nonce with Dead Nonce List
|
||||
bool hasDuplicateNonceInDnl = m_deadNonceList.has(interest.getName(), interest.getNonce());
|
||||
if (hasDuplicateNonceInDnl) {
|
||||
// goto Interest loop pipeline
|
||||
this->onInterestLoop(inFace, interest);
|
||||
return;
|
||||
}
|
||||
|
||||
// PIT insert
|
||||
shared_ptr<pit::Entry> pitEntry = m_pit.insert(interest).first;
|
||||
|
||||
// detect duplicate Nonce
|
||||
int dnw = pitEntry->findNonce(interest.getNonce(), inFace);
|
||||
bool hasDuplicateNonce = (dnw != pit::DUPLICATE_NONCE_NONE) ||
|
||||
m_deadNonceList.has(interest.getName(), interest.getNonce());
|
||||
if (hasDuplicateNonce) {
|
||||
// detect duplicate Nonce in PIT entry
|
||||
bool hasDuplicateNonceInPit = pitEntry->findNonce(interest.getNonce(), inFace) !=
|
||||
pit::DUPLICATE_NONCE_NONE;
|
||||
if (hasDuplicateNonceInPit) {
|
||||
// goto Interest loop pipeline
|
||||
this->onInterestLoop(inFace, interest, pitEntry);
|
||||
this->onInterestLoop(inFace, interest);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -147,11 +154,10 @@ Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onInterestLoop(Face& inFace, const Interest& interest,
|
||||
shared_ptr<pit::Entry> pitEntry)
|
||||
Forwarder::onInterestLoop(Face& inFace, const Interest& interest)
|
||||
{
|
||||
// if multi-access face, drop
|
||||
if (inFace.isMultiAccess()) {
|
||||
if (inFace.getLinkType() == ndn::nfd::LINK_TYPE_MULTI_ACCESS) {
|
||||
NFD_LOG_DEBUG("onInterestLoop face=" << inFace.getId() <<
|
||||
" interest=" << interest.getName() <<
|
||||
" drop");
|
||||
@@ -244,7 +250,7 @@ Forwarder::onContentStoreHit(const Face& inFace,
|
||||
{
|
||||
NFD_LOG_DEBUG("onContentStoreHit interest=" << interest.getName());
|
||||
|
||||
const_pointer_cast<Data>(data.shared_from_this())->setIncomingFaceId(FACEID_CONTENT_STORE);
|
||||
data.setTag(make_shared<lp::IncomingFaceIdTag>(face::FACEID_CONTENT_STORE));
|
||||
// XXX should we lookup PIT for other Interests that also match csMatch?
|
||||
|
||||
// set PIT straggler timer
|
||||
@@ -284,7 +290,7 @@ void
|
||||
Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace,
|
||||
bool wantNewNonce)
|
||||
{
|
||||
if (outFace.getId() == INVALID_FACEID) {
|
||||
if (outFace.getId() == face::INVALID_FACEID) {
|
||||
NFD_LOG_WARN("onOutgoingInterest face=invalid interest=" << pitEntry->getName());
|
||||
return;
|
||||
}
|
||||
@@ -317,7 +323,7 @@ Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace,
|
||||
|
||||
// send Interest
|
||||
outFace.sendInterest(*interest);
|
||||
++m_counters.getNOutInterests();
|
||||
++m_counters.nOutInterests;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -370,11 +376,11 @@ Forwarder::onIncomingData(Face& inFace, const Data& data)
|
||||
{
|
||||
// receive Data
|
||||
NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() << " data=" << data.getName());
|
||||
const_cast<Data&>(data).setIncomingFaceId(inFace.getId());
|
||||
++m_counters.getNInDatas();
|
||||
data.setTag(make_shared<lp::IncomingFaceIdTag>(inFace.getId()));
|
||||
++m_counters.nInData;
|
||||
|
||||
// /localhost scope control
|
||||
bool isViolatingLocalhost = !inFace.isLocal() &&
|
||||
bool isViolatingLocalhost = inFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
|
||||
LOCALHOST_NAME.isPrefixOf(data.getName());
|
||||
if (isViolatingLocalhost) {
|
||||
NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() <<
|
||||
@@ -439,7 +445,7 @@ void
|
||||
Forwarder::onDataUnsolicited(Face& inFace, const Data& data)
|
||||
{
|
||||
// accept to cache?
|
||||
bool acceptToCache = inFace.isLocal();
|
||||
bool acceptToCache = inFace.getScope() == ndn::nfd::FACE_SCOPE_LOCAL;
|
||||
if (acceptToCache) {
|
||||
// CS insert
|
||||
m_cs.insert(data, true);
|
||||
@@ -453,14 +459,14 @@ Forwarder::onDataUnsolicited(Face& inFace, const Data& data)
|
||||
void
|
||||
Forwarder::onOutgoingData(const Data& data, Face& outFace)
|
||||
{
|
||||
if (outFace.getId() == INVALID_FACEID) {
|
||||
if (outFace.getId() == face::INVALID_FACEID) {
|
||||
NFD_LOG_WARN("onOutgoingData face=invalid data=" << data.getName());
|
||||
return;
|
||||
}
|
||||
NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() << " data=" << data.getName());
|
||||
|
||||
// /localhost scope control
|
||||
bool isViolatingLocalhost = !outFace.isLocal() &&
|
||||
bool isViolatingLocalhost = outFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
|
||||
LOCALHOST_NAME.isPrefixOf(data.getName());
|
||||
if (isViolatingLocalhost) {
|
||||
NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() <<
|
||||
@@ -473,14 +479,18 @@ Forwarder::onOutgoingData(const Data& data, Face& outFace)
|
||||
|
||||
// send Data
|
||||
outFace.sendData(data);
|
||||
++m_counters.getNOutDatas();
|
||||
++m_counters.nOutData;
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onIncomingNack(Face& inFace, const lp::Nack& nack)
|
||||
{
|
||||
// receive Nack
|
||||
nack.setTag(make_shared<lp::IncomingFaceIdTag>(inFace.getId()));
|
||||
++m_counters.nInNacks;
|
||||
|
||||
// if multi-access face, drop
|
||||
if (inFace.isMultiAccess()) {
|
||||
if (inFace.getLinkType() == ndn::nfd::LINK_TYPE_MULTI_ACCESS) {
|
||||
NFD_LOG_DEBUG("onIncomingNack face=" << inFace.getId() <<
|
||||
" nack=" << nack.getInterest().getName() <<
|
||||
"~" << nack.getReason() << " face-is-multi-access");
|
||||
@@ -533,7 +543,7 @@ void
|
||||
Forwarder::onOutgoingNack(shared_ptr<pit::Entry> pitEntry, const Face& outFace,
|
||||
const lp::NackHeader& nack)
|
||||
{
|
||||
if (outFace.getId() == INVALID_FACEID) {
|
||||
if (outFace.getId() == face::INVALID_FACEID) {
|
||||
NFD_LOG_WARN("onOutgoingNack face=invalid" <<
|
||||
" nack=" << pitEntry->getInterest().getName() <<
|
||||
"~" << nack.getReason() << " no-in-record");
|
||||
@@ -552,7 +562,7 @@ Forwarder::onOutgoingNack(shared_ptr<pit::Entry> pitEntry, const Face& outFace,
|
||||
}
|
||||
|
||||
// if multi-access face, drop
|
||||
if (outFace.isMultiAccess()) {
|
||||
if (outFace.getLinkType() == ndn::nfd::LINK_TYPE_MULTI_ACCESS) {
|
||||
NFD_LOG_DEBUG("onOutgoingNack face=" << outFace.getId() <<
|
||||
" nack=" << pitEntry->getInterest().getName() <<
|
||||
"~" << nack.getReason() << " face-is-multi-access");
|
||||
@@ -572,6 +582,7 @@ Forwarder::onOutgoingNack(shared_ptr<pit::Entry> pitEntry, const Face& outFace,
|
||||
|
||||
// send Nack on face
|
||||
const_cast<Face&>(outFace).sendNack(nackPkt);
|
||||
++m_counters.nOutNacks;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
|
||||
@@ -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.
|
||||
@@ -132,8 +132,7 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE: // pipelines
|
||||
/** \brief Interest loop pipeline
|
||||
*/
|
||||
VIRTUAL_WITH_TESTS void
|
||||
onInterestLoop(Face& inFace, const Interest& interest,
|
||||
shared_ptr<pit::Entry> pitEntry);
|
||||
onInterestLoop(Face& inFace, const Interest& interest);
|
||||
|
||||
/** \brief Content Store miss pipeline
|
||||
*/
|
||||
|
||||
@@ -33,8 +33,8 @@ namespace fw {
|
||||
NFD_LOG_INIT("Strategy");
|
||||
|
||||
Strategy::Strategy(Forwarder& forwarder, const Name& name)
|
||||
: afterAddFace(forwarder.getFaceTable().onAdd)
|
||||
, beforeRemoveFace(forwarder.getFaceTable().onRemove)
|
||||
: afterAddFace(forwarder.getFaceTable().afterAdd)
|
||||
, beforeRemoveFace(forwarder.getFaceTable().beforeRemove)
|
||||
, m_name(name)
|
||||
, m_forwarder(forwarder)
|
||||
, m_measurements(m_forwarder.getMeasurements(),
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
#include "core/network-interface.hpp"
|
||||
#include "face/generic-link-service.hpp"
|
||||
#include "face/lp-face-wrapper.hpp"
|
||||
#include "face/tcp-factory.hpp"
|
||||
#include "face/udp-factory.hpp"
|
||||
#include "fw/face-table.hpp"
|
||||
@@ -42,7 +41,7 @@
|
||||
|
||||
#ifdef HAVE_LIBPCAP
|
||||
#include "face/ethernet-factory.hpp"
|
||||
#include "face/ethernet-face.hpp"
|
||||
#include "face/ethernet-transport.hpp"
|
||||
#endif // HAVE_LIBPCAP
|
||||
|
||||
#ifdef HAVE_WEBSOCKET
|
||||
@@ -77,9 +76,9 @@ FaceManager::FaceManager(FaceTable& faceTable,
|
||||
|
||||
auto postNotification = registerNotificationStream("events");
|
||||
m_faceAddConn =
|
||||
m_faceTable.onAdd.connect(bind(&FaceManager::afterFaceAdded, this, _1, postNotification));
|
||||
m_faceTable.afterAdd.connect(bind(&FaceManager::afterFaceAdded, this, _1, postNotification));
|
||||
m_faceRemoveConn =
|
||||
m_faceTable.onRemove.connect(bind(&FaceManager::afterFaceRemoved, this, _1, postNotification));
|
||||
m_faceTable.beforeRemove.connect(bind(&FaceManager::afterFaceRemoved, this, _1, postNotification));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -173,20 +172,14 @@ FaceManager::enableLocalControl(const Name& topPrefix, const Interest& interest,
|
||||
const ControlParameters& parameters,
|
||||
const ndn::mgmt::CommandContinuation& done)
|
||||
{
|
||||
auto result = extractLocalControlParameters(interest, parameters, done);
|
||||
if (!result.isValid) {
|
||||
Face* face = findFaceForLocalControl(interest, parameters, done);
|
||||
if (!face) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.face) {
|
||||
result.face->setLocalControlHeaderFeature(result.feature, true);
|
||||
return done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
|
||||
}
|
||||
|
||||
// TODO#3226 redesign enable-local-control
|
||||
// For now, enable-local-control will enable all local fields in GenericLinkService.
|
||||
BOOST_ASSERT(result.lpFace != nullptr);
|
||||
auto service = dynamic_cast<face::GenericLinkService*>(result.lpFace->getLinkService());
|
||||
auto service = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
|
||||
if (service == nullptr) {
|
||||
return done(ControlResponse(503, "LinkService type not supported"));
|
||||
}
|
||||
@@ -204,20 +197,14 @@ FaceManager::disableLocalControl(const Name& topPrefix, const Interest& interest
|
||||
const ControlParameters& parameters,
|
||||
const ndn::mgmt::CommandContinuation& done)
|
||||
{
|
||||
auto result = extractLocalControlParameters(interest, parameters, done);
|
||||
if (!result.isValid) {
|
||||
Face* face = findFaceForLocalControl(interest, parameters, done);
|
||||
if (!face) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.face) {
|
||||
result.face->setLocalControlHeaderFeature(result.feature, false);
|
||||
return done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
|
||||
}
|
||||
|
||||
// TODO#3226 redesign disable-local-control
|
||||
// For now, disable-local-control will disable all local fields in GenericLinkService.
|
||||
BOOST_ASSERT(result.lpFace != nullptr);
|
||||
auto service = dynamic_cast<face::GenericLinkService*>(result.lpFace->getLinkService());
|
||||
auto service = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
|
||||
if (service == nullptr) {
|
||||
return done(ControlResponse(503, "LinkService type not supported"));
|
||||
}
|
||||
@@ -230,46 +217,41 @@ FaceManager::disableLocalControl(const Name& topPrefix, const Interest& interest
|
||||
.setBody(parameters.wireEncode()));
|
||||
}
|
||||
|
||||
FaceManager::ExtractLocalControlParametersResult
|
||||
FaceManager::extractLocalControlParameters(const Interest& request,
|
||||
const ControlParameters& parameters,
|
||||
const ndn::mgmt::CommandContinuation& done)
|
||||
Face*
|
||||
FaceManager::findFaceForLocalControl(const Interest& request,
|
||||
const ControlParameters& parameters,
|
||||
const ndn::mgmt::CommandContinuation& done)
|
||||
{
|
||||
ExtractLocalControlParametersResult result;
|
||||
result.isValid = false;
|
||||
result.lpFace = nullptr;
|
||||
shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = request.getTag<lp::IncomingFaceIdTag>();
|
||||
// NDNLPv2 says "application MUST be prepared to receive a packet without IncomingFaceId field",
|
||||
// but it's fine to assert IncomingFaceId is available, because InternalFace lives inside NFD
|
||||
// and is initialized synchronously with IncomingFaceId field enabled.
|
||||
BOOST_ASSERT(incomingFaceIdTag != nullptr);
|
||||
|
||||
auto face = m_faceTable.get(request.getIncomingFaceId());
|
||||
auto face = m_faceTable.get(*incomingFaceIdTag);
|
||||
if (face == nullptr) {
|
||||
NFD_LOG_DEBUG("FaceId " << request.getIncomingFaceId() << " not found");
|
||||
NFD_LOG_DEBUG("FaceId " << *incomingFaceIdTag << " not found");
|
||||
done(ControlResponse(410, "Face not found"));
|
||||
return result;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!face->isLocal()) {
|
||||
if (face->getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL) {
|
||||
NFD_LOG_DEBUG("Cannot enable local control on non-local FaceId " << face->getId());
|
||||
done(ControlResponse(412, "Face is non-local"));
|
||||
return result;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
result.isValid = true;
|
||||
result.face = dynamic_pointer_cast<LocalFace>(face);
|
||||
if (result.face == nullptr) {
|
||||
auto lpFaceW = dynamic_pointer_cast<face::LpFaceWrapper>(face);
|
||||
BOOST_ASSERT(lpFaceW != nullptr);
|
||||
result.lpFace = lpFaceW->getLpFace();
|
||||
}
|
||||
result.feature = parameters.getLocalControlFeature();
|
||||
|
||||
return result;
|
||||
return face.get();
|
||||
}
|
||||
|
||||
void
|
||||
FaceManager::listFaces(const Name& topPrefix, const Interest& interest,
|
||||
ndn::mgmt::StatusDatasetContext& context)
|
||||
{
|
||||
auto now = time::steady_clock::now();
|
||||
for (const auto& face : m_faceTable) {
|
||||
context.append(face->getFaceStatus().wireEncode());
|
||||
ndn::nfd::FaceStatus status = collectFaceStatus(*face, now);
|
||||
context.append(status.wireEncode());
|
||||
}
|
||||
context.end();
|
||||
}
|
||||
@@ -311,10 +293,13 @@ FaceManager::queryFaces(const Name& topPrefix, const Interest& interest,
|
||||
return context.reject(ControlResponse(400, "Malformed filter"));
|
||||
}
|
||||
|
||||
auto now = time::steady_clock::now();
|
||||
for (const auto& face : m_faceTable) {
|
||||
if (doesMatchFilter(faceFilter, face)) {
|
||||
context.append(face->getFaceStatus().wireEncode());
|
||||
if (!doesMatchFilter(faceFilter, face)) {
|
||||
continue;
|
||||
}
|
||||
ndn::nfd::FaceStatus status = collectFaceStatus(*face, now);
|
||||
context.append(status.wireEncode());
|
||||
}
|
||||
|
||||
context.end();
|
||||
@@ -345,7 +330,7 @@ FaceManager::doesMatchFilter(const ndn::nfd::FaceQueryFilter& filter, shared_ptr
|
||||
}
|
||||
|
||||
if (filter.hasFaceScope() &&
|
||||
(filter.getFaceScope() == ndn::nfd::FACE_SCOPE_LOCAL) != face->isLocal()) {
|
||||
filter.getFaceScope() != face->getScope()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -355,20 +340,58 @@ FaceManager::doesMatchFilter(const ndn::nfd::FaceQueryFilter& filter, shared_ptr
|
||||
}
|
||||
|
||||
if (filter.hasLinkType() &&
|
||||
(filter.getLinkType() == ndn::nfd::LINK_TYPE_MULTI_ACCESS) != face->isMultiAccess()) {
|
||||
filter.getLinkType() != face->getLinkType()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ndn::nfd::FaceStatus
|
||||
FaceManager::collectFaceStatus(const Face& face, const time::steady_clock::TimePoint& now)
|
||||
{
|
||||
ndn::nfd::FaceStatus status;
|
||||
|
||||
collectFaceProperties(face, status);
|
||||
|
||||
time::steady_clock::TimePoint expirationTime = face.getExpirationTime();
|
||||
if (expirationTime != time::steady_clock::TimePoint::max()) {
|
||||
status.setExpirationPeriod(std::max(time::milliseconds(0),
|
||||
time::duration_cast<time::milliseconds>(expirationTime - now)));
|
||||
}
|
||||
|
||||
const face::FaceCounters& counters = face.getCounters();
|
||||
status.setNInInterests(counters.nInInterests)
|
||||
.setNOutInterests(counters.nOutInterests)
|
||||
.setNInDatas(counters.nInData)
|
||||
.setNOutDatas(counters.nOutData)
|
||||
.setNInNacks(counters.nInNacks)
|
||||
.setNOutNacks(counters.nOutNacks)
|
||||
.setNInBytes(counters.nInBytes)
|
||||
.setNOutBytes(counters.nOutBytes);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
template<typename FaceTraits>
|
||||
void
|
||||
FaceManager::collectFaceProperties(const Face& face, FaceTraits& traits)
|
||||
{
|
||||
traits.setFaceId(face.getId())
|
||||
.setRemoteUri(face.getRemoteUri().toString())
|
||||
.setLocalUri(face.getLocalUri().toString())
|
||||
.setFaceScope(face.getScope())
|
||||
.setFacePersistency(face.getPersistency())
|
||||
.setLinkType(face.getLinkType());
|
||||
}
|
||||
|
||||
void
|
||||
FaceManager::afterFaceAdded(shared_ptr<Face> face,
|
||||
const ndn::mgmt::PostNotification& post)
|
||||
{
|
||||
ndn::nfd::FaceEventNotification notification;
|
||||
notification.setKind(ndn::nfd::FACE_EVENT_CREATED);
|
||||
face->copyStatusTo(notification);
|
||||
collectFaceProperties(*face, notification);
|
||||
|
||||
post(notification.wireEncode());
|
||||
}
|
||||
@@ -379,7 +402,7 @@ FaceManager::afterFaceRemoved(shared_ptr<Face> face,
|
||||
{
|
||||
ndn::nfd::FaceEventNotification notification;
|
||||
notification.setKind(ndn::nfd::FACE_EVENT_DESTROYED);
|
||||
face->copyStatusTo(notification);
|
||||
collectFaceProperties(*face, notification);
|
||||
|
||||
post(notification.wireEncode());
|
||||
}
|
||||
@@ -670,7 +693,7 @@ FaceManager::processSectionUdp(const ConfigSection& configSection, bool isDryRun
|
||||
m_factories.insert(std::make_pair("udp6", factory));
|
||||
}
|
||||
|
||||
std::set<shared_ptr<face::LpFaceWrapper>> multicastFacesToRemove;
|
||||
std::set<shared_ptr<Face>> multicastFacesToRemove;
|
||||
for (const auto& i : factory->getMulticastFaces()) {
|
||||
multicastFacesToRemove.insert(i.second);
|
||||
}
|
||||
@@ -752,7 +775,7 @@ FaceManager::processSectionEther(const ConfigSection& configSection, bool isDryR
|
||||
m_factories.insert(std::make_pair("ether", factory));
|
||||
}
|
||||
|
||||
std::set<shared_ptr<EthernetFace>> multicastFacesToRemove;
|
||||
std::set<shared_ptr<Face>> multicastFacesToRemove;
|
||||
for (const auto& i : factory->getMulticastFaces()) {
|
||||
multicastFacesToRemove.insert(i.second);
|
||||
}
|
||||
@@ -768,7 +791,7 @@ FaceManager::processSectionEther(const ConfigSection& configSection, bool isDryR
|
||||
catch (const EthernetFactory::Error& factoryError) {
|
||||
NFD_LOG_ERROR(factoryError.what() << ", continuing");
|
||||
}
|
||||
catch (const EthernetFace::Error& faceError) {
|
||||
catch (const face::EthernetTransport::Error& faceError) {
|
||||
NFD_LOG_ERROR(faceError.what() << ", continuing");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,9 @@
|
||||
#define NFD_DAEMON_MGMT_FACE_MANAGER_HPP
|
||||
|
||||
#include "manager-base.hpp"
|
||||
#include "face/local-face.hpp"
|
||||
#include <ndn-cxx/management/nfd-face-status.hpp>
|
||||
#include <ndn-cxx/management/nfd-face-query-filter.hpp>
|
||||
#include "face/face.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
@@ -36,10 +37,6 @@ class FaceTable;
|
||||
class NetworkInterfaceInfo;
|
||||
class ProtocolFactory;
|
||||
|
||||
namespace face {
|
||||
class LpFace;
|
||||
} // namespace face
|
||||
|
||||
/**
|
||||
* @brief implement the Face Management of NFD Management Protocol.
|
||||
* @sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt
|
||||
@@ -88,18 +85,10 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE: // helpers for ControlCommand
|
||||
afterCreateFaceFailure(const std::string& reason,
|
||||
const ndn::mgmt::CommandContinuation& done);
|
||||
|
||||
struct ExtractLocalControlParametersResult
|
||||
{
|
||||
bool isValid;
|
||||
shared_ptr<LocalFace> face;
|
||||
face::LpFace* lpFace;
|
||||
LocalControlFeature feature;
|
||||
};
|
||||
|
||||
ExtractLocalControlParametersResult
|
||||
extractLocalControlParameters(const Interest& request,
|
||||
const ControlParameters& parameters,
|
||||
const ndn::mgmt::CommandContinuation& done);
|
||||
Face*
|
||||
findFaceForLocalControl(const Interest& request,
|
||||
const ControlParameters& parameters,
|
||||
const ndn::mgmt::CommandContinuation& done);
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE: // StatusDataset
|
||||
void
|
||||
@@ -118,6 +107,18 @@ private: // helpers for StatusDataset handler
|
||||
bool
|
||||
doesMatchFilter(const ndn::nfd::FaceQueryFilter& filter, shared_ptr<Face> face);
|
||||
|
||||
/** \brief get status of face, including properties and counters
|
||||
*/
|
||||
static ndn::nfd::FaceStatus
|
||||
collectFaceStatus(const Face& face, const time::steady_clock::TimePoint& now);
|
||||
|
||||
/** \brief copy face properties into traits
|
||||
* \tparam FaceTraits either FaceStatus or FaceEventNotification
|
||||
*/
|
||||
template<typename FaceTraits>
|
||||
static void
|
||||
collectFaceProperties(const Face& face, FaceTraits& traits);
|
||||
|
||||
private: // NotificationStream
|
||||
void
|
||||
afterFaceAdded(shared_ptr<Face> face,
|
||||
|
||||
@@ -142,7 +142,12 @@ FibManager::setFaceForSelfRegistration(const Interest& request, ControlParameter
|
||||
{
|
||||
bool isSelfRegistration = (parameters.getFaceId() == 0);
|
||||
if (isSelfRegistration) {
|
||||
parameters.setFaceId(request.getIncomingFaceId());
|
||||
shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = request.getTag<lp::IncomingFaceIdTag>();
|
||||
// NDNLPv2 says "application MUST be prepared to receive a packet without IncomingFaceId field",
|
||||
// but it's fine to assert IncomingFaceId is available, because InternalFace lives inside NFD
|
||||
// and is initialized synchronously with IncomingFaceId field enabled.
|
||||
BOOST_ASSERT(incomingFaceIdTag != nullptr);
|
||||
parameters.setFaceId(*incomingFaceIdTag);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,12 +37,11 @@ ForwarderStatusManager::ForwarderStatusManager(Forwarder& forwarder, Dispatcher&
|
||||
, m_startTimestamp(time::system_clock::now())
|
||||
{
|
||||
m_dispatcher.addStatusDataset("status", ndn::mgmt::makeAcceptAllAuthorization(),
|
||||
bind(&ForwarderStatusManager::listStatus, this, _1, _2, _3));
|
||||
bind(&ForwarderStatusManager::listGeneralStatus, this, _1, _2, _3));
|
||||
}
|
||||
|
||||
void
|
||||
ForwarderStatusManager::listStatus(const Name& topPrefix, const Interest& interest,
|
||||
ndn::mgmt::StatusDatasetContext& context)
|
||||
ndn::nfd::ForwarderStatus
|
||||
ForwarderStatusManager::collectGeneralStatus()
|
||||
{
|
||||
ndn::nfd::ForwarderStatus status;
|
||||
|
||||
@@ -56,10 +55,37 @@ ForwarderStatusManager::listStatus(const Name& topPrefix, const Interest& intere
|
||||
status.setNMeasurementsEntries(m_forwarder.getMeasurements().size());
|
||||
status.setNCsEntries(m_forwarder.getCs().size());
|
||||
|
||||
m_forwarder.getCounters().copyTo(status);
|
||||
const ForwarderCounters& counters = m_forwarder.getCounters();
|
||||
status.setNInInterests(counters.nInInterests)
|
||||
.setNOutInterests(counters.nOutInterests)
|
||||
.setNInDatas(counters.nInData)
|
||||
.setNOutDatas(counters.nOutData)
|
||||
.setNInNacks(counters.nInNacks)
|
||||
.setNOutNacks(counters.nOutNacks);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void
|
||||
ForwarderStatusManager::listGeneralStatus(const Name& topPrefix, const Interest& interest,
|
||||
ndn::mgmt::StatusDatasetContext& context)
|
||||
{
|
||||
static const PartialName PREFIX_STATUS("status");
|
||||
static const PartialName PREFIX_STATUS_GENERAL("status/general");
|
||||
|
||||
PartialName subPrefix = interest.getName().getSubName(topPrefix.size());
|
||||
if (subPrefix == PREFIX_STATUS_GENERAL || subPrefix == PREFIX_STATUS) {
|
||||
context.setPrefix(Name(topPrefix).append(PREFIX_STATUS_GENERAL));
|
||||
}
|
||||
else {
|
||||
context.reject(ndn::mgmt::ControlResponse().setCode(404));
|
||||
return;
|
||||
}
|
||||
// TODO#3379 register the dataset at status/general, and delete these conditions
|
||||
|
||||
context.setExpiry(STATUS_SERVER_DEFAULT_FRESHNESS);
|
||||
|
||||
auto status = this->collectGeneralStatus();
|
||||
status.wireEncode().parse();
|
||||
for (const auto& subblock : status.wireEncode().elements()) {
|
||||
context.append(subblock);
|
||||
|
||||
@@ -43,9 +43,14 @@ public:
|
||||
ForwarderStatusManager(Forwarder& forwarder, Dispatcher& dispatcher);
|
||||
|
||||
private:
|
||||
ndn::nfd::ForwarderStatus
|
||||
collectGeneralStatus();
|
||||
|
||||
/** \brief provide general status dataset
|
||||
*/
|
||||
void
|
||||
listStatus(const Name& topPrefix, const Interest& interest,
|
||||
ndn::mgmt::StatusDatasetContext& context);
|
||||
listGeneralStatus(const Name& topPrefix, const Interest& interest,
|
||||
ndn::mgmt::StatusDatasetContext& context);
|
||||
|
||||
private:
|
||||
Forwarder& m_forwarder;
|
||||
|
||||
+4
-4
@@ -90,9 +90,9 @@ Nfd::initialize()
|
||||
|
||||
initializeManagement();
|
||||
|
||||
m_forwarder->getFaceTable().addReserved(make_shared<NullFace>(), FACEID_NULL);
|
||||
m_forwarder->getFaceTable().addReserved(make_shared<NullFace>(FaceUri("contentstore://")),
|
||||
FACEID_CONTENT_STORE);
|
||||
FaceTable& faceTable = m_forwarder->getFaceTable();
|
||||
faceTable.addReserved(face::makeNullFace(), face::FACEID_NULL);
|
||||
faceTable.addReserved(face::makeNullFace(FaceUri("contentstore://")), face::FACEID_CONTENT_STORE);
|
||||
|
||||
PrivilegeHelper::drop();
|
||||
|
||||
@@ -145,7 +145,7 @@ void
|
||||
Nfd::initializeManagement()
|
||||
{
|
||||
std::tie(m_internalFace, m_internalClientFace) = face::makeInternalFace(m_keyChain);
|
||||
m_forwarder->getFaceTable().addReserved(m_internalFace, FACEID_INTERNAL_FACE);
|
||||
m_forwarder->getFaceTable().addReserved(m_internalFace, face::FACEID_INTERNAL_FACE);
|
||||
m_dispatcher.reset(new ndn::mgmt::Dispatcher(*m_internalClientFace, m_keyChain));
|
||||
|
||||
m_validator.reset(new CommandValidator());
|
||||
|
||||
+7
-8
@@ -34,19 +34,14 @@
|
||||
#include <ndn-cxx/util/network-monitor.hpp>
|
||||
|
||||
namespace ndn {
|
||||
|
||||
class Face;
|
||||
|
||||
namespace mgmt {
|
||||
|
||||
class Dispatcher;
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace mgmt
|
||||
} // namespace ndn
|
||||
|
||||
namespace nfd {
|
||||
|
||||
class Face;
|
||||
class Forwarder;
|
||||
class FibManager;
|
||||
class FaceManager;
|
||||
@@ -54,6 +49,10 @@ class StrategyChoiceManager;
|
||||
class ForwarderStatusManager;
|
||||
class CommandValidator;
|
||||
|
||||
namespace face {
|
||||
class Face;
|
||||
} // namespace face
|
||||
|
||||
/**
|
||||
* \brief Class representing NFD instance
|
||||
* This class can be used to initialize all components of NFD
|
||||
@@ -110,7 +109,7 @@ private:
|
||||
unique_ptr<Forwarder> m_forwarder;
|
||||
|
||||
ndn::KeyChain& m_keyChain;
|
||||
shared_ptr<Face> m_internalFace;
|
||||
shared_ptr<face::Face> m_internalFace;
|
||||
shared_ptr<ndn::Face> m_internalClientFace;
|
||||
unique_ptr<CommandValidator> m_validator;
|
||||
|
||||
|
||||
@@ -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,
|
||||
@@ -41,9 +41,7 @@ Policy::~Policy()
|
||||
void
|
||||
Policy::setLimit(size_t nMaxEntries)
|
||||
{
|
||||
BOOST_ASSERT(nMaxEntries > 0);
|
||||
m_limit = nMaxEntries;
|
||||
|
||||
this->evictEntries();
|
||||
}
|
||||
|
||||
|
||||
+13
-11
@@ -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,
|
||||
@@ -78,18 +78,22 @@ Cs::setPolicy(unique_ptr<Policy> policy)
|
||||
m_policy->setLimit(limit);
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
Cs::insert(const Data& data, bool isUnsolicited)
|
||||
{
|
||||
NFD_LOG_DEBUG("insert " << data.getName());
|
||||
|
||||
// recognize CachingPolicy
|
||||
using ndn::nfd::LocalControlHeader;
|
||||
const LocalControlHeader& lch = data.getLocalControlHeader();
|
||||
if (lch.hasCachingPolicy()) {
|
||||
LocalControlHeader::CachingPolicy policy = lch.getCachingPolicy();
|
||||
if (policy == LocalControlHeader::CachingPolicy::NO_CACHE) {
|
||||
return false;
|
||||
if (m_policy->getLimit() == 0) {
|
||||
// shortcut for disabled CS
|
||||
return;
|
||||
}
|
||||
|
||||
// recognize CachePolicy
|
||||
shared_ptr<lp::CachePolicyTag> tag = data.getTag<lp::CachePolicyTag>();
|
||||
if (tag != nullptr) {
|
||||
lp::CachePolicyType policy = tag->get().getPolicy();
|
||||
if (policy == lp::CachePolicyType::NO_CACHE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,8 +116,6 @@ Cs::insert(const Data& data, bool isUnsolicited)
|
||||
else {
|
||||
m_policy->afterInsert(it);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+2
-3
@@ -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,
|
||||
@@ -69,9 +69,8 @@ public:
|
||||
Cs(size_t nMaxPackets = 10, unique_ptr<Policy> policy = makeDefaultPolicy());
|
||||
|
||||
/** \brief inserts a Data packet
|
||||
* \return true
|
||||
*/
|
||||
bool
|
||||
void
|
||||
insert(const Data& data, bool isUnsolicited = false);
|
||||
|
||||
typedef std::function<void(const Interest&, const Data& data)> HitCallback;
|
||||
|
||||
@@ -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,
|
||||
@@ -90,11 +90,9 @@ Fib::findLongestPrefixMatch(shared_ptr<name_tree::Entry> nameTreeEntry) const
|
||||
shared_ptr<fib::Entry>
|
||||
Fib::findLongestPrefixMatch(const pit::Entry& pitEntry) const
|
||||
{
|
||||
shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.get(pitEntry);
|
||||
|
||||
BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
|
||||
|
||||
return findLongestPrefixMatch(nameTreeEntry);
|
||||
shared_ptr<name_tree::Entry> nte = m_nameTree.findLongestPrefixMatch(pitEntry);
|
||||
BOOST_ASSERT(nte != nullptr);
|
||||
return findLongestPrefixMatch(nte);
|
||||
}
|
||||
|
||||
shared_ptr<fib::Entry>
|
||||
|
||||
@@ -67,6 +67,13 @@ shared_ptr<Entry>
|
||||
Measurements::get(const fib::Entry& fibEntry)
|
||||
{
|
||||
shared_ptr<name_tree::Entry> nte = m_nameTree.get(fibEntry);
|
||||
if (nte == nullptr) {
|
||||
// must be Fib::s_emptyEntry that is unattched
|
||||
BOOST_ASSERT(fibEntry.getPrefix().empty());
|
||||
nte = m_nameTree.lookup(fibEntry.getPrefix());
|
||||
}
|
||||
|
||||
BOOST_ASSERT(nte != nullptr);
|
||||
return this->get(*nte);
|
||||
}
|
||||
|
||||
@@ -74,6 +81,8 @@ shared_ptr<Entry>
|
||||
Measurements::get(const pit::Entry& pitEntry)
|
||||
{
|
||||
shared_ptr<name_tree::Entry> nte = m_nameTree.get(pitEntry);
|
||||
|
||||
BOOST_ASSERT(nte != nullptr);
|
||||
return this->get(*nte);
|
||||
}
|
||||
|
||||
|
||||
Loaded 100 of 218 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user