Compare commits

...
Author SHA1 Message Date
Alexander Afanasyev da3ba96430 docs+build: Prepare release of version 0.4.0
Change-Id: I3af73fed66b44d708532bbda146376b7f7487d28
Refs: #3008
2015-12-29 20:39:40 -08:00
Junxiao Shi 809462490f mgmt: enhance ForwarderStatusManager test suite
Newly added GeneralStatus dataset as well as its legacy counterpart are tested.
The test suite is simplified with ManagerCommonFixture.

refs #3081

Change-Id: I9a00a6f69866c722d7f7fbaa3e207ae6e2ec79f5
2015-12-29 17:53:18 -07:00
Junxiao Shi 498373dd01 mgmt: publish GeneralStatus dataset
In ForwarderStatusManager, publish ForwarderStatus as a dataset at
/localhost/nfd/status/general.
To maintain backwards compatibility, an Interest to /localhost/nfd/status
also retrieves this dataset.

It's intentional not to update the test suite in this commit,
to illustrate that backwards compatibility is maintained.

refs #3081

Change-Id: I9b636e2e621563185303a7304be402c8221c9863
2015-12-29 17:51:26 -07:00
Eric Newberry c64d30aeff mgmt: re-added expiration time to FaceStatus
refs #3381

Change-Id: I57d3166fc6ed52a54c442a80faffe7a7f4051e1d
2015-12-29 13:11:47 -08:00
Alexander Afanasyev 5c47597be9 tools: Automatically start ndn-autoconfig in nfd-start, if enabled in autoconfig.conf
Change-Id: I09d3fff87f00ce8684e6e304e8327f9d03ca18bf
Refs: #2716
2015-12-28 14:15:50 -08:00
Eric Newberry 6d8ee7acc9 tests: MulticastUdpTransport test suite improvements
refs #3346

Change-Id: I31b272b9b99d97ed317cf534d9e1bc4592bde77d
2015-12-24 20:39:56 -07:00
Junxiao Shi cde37ad608 face: face refactoring completion
* delete old Face
* rename LpFace as Face
* eliminate LpFaceWrapper and use new Face

refs #3172

Change-Id: I08c3a5dfb4cc1b9834b30cccd9ab634535d0608c
2015-12-24 01:02:05 -07:00
Junxiao Shi c5401494fe face: UdpChannel minor refactoring
refs #3172

Change-Id: I36d7a27df6d97e8fc1d8ec76e4e25b7987954cf8
2015-12-23 16:33:22 -07:00
Eric Newberry 65caf20092 tests: UnicastUdpTransport test suite improvements
Fixed m_hasBeenUsedRecently uninitialized in DatagramTransport

refs #3307

Change-Id: I786a84009d9cf01e0bb211c872d4375f46c747fd
2015-12-22 11:26:38 -08:00
Davide Pesavento ca25d72064 face: adjust pcap filter in EthernetTransport to accept only untagged frames
Change-Id: Id14d6e57dc9f7c765f0431335b917c2fe74231c4
Refs: #3348
2015-12-21 19:11:07 -08:00
Alexander Afanasyev f22ebaf7f1 tests+ci: Enable dual XML and HRF output of unit test results
This commit also makes unit tests to run against a debug build, to
ensure assertions are properly evaluated (based on suggestion
in I5f4419ea48d4eb333e9d107115ef3df4123f76e5).

Change-Id: I1bbf14f75aab155ed80a36fc4006f7a5d13f1289
Refs: #2252, #2805
2015-12-21 13:50:29 -08:00
Davide Pesavento f35a5a9b08 tests: in LimitedIo, use std::exception_ptr to avoid slicing
Change-Id: I459792cf80ee189842ada84c3a514134bcd79a29
Refs: #3327
2015-12-18 19:21:46 +01:00
Eric Newberry f68f378a23 tests: UnixStreamTransport test suite improvements
refs #3305

Change-Id: I6c6ca52a5e80266920ded811ff45fc568c3e59b9
2015-12-17 23:51:35 -07:00
Eric Newberry 8717e87046 tests: TcpTransport test suite improvements
refs #3306

Change-Id: I3b342b4df13db7996b03de7d1bed65b579798f85
2015-12-09 15:07:08 -07:00
Junxiao Shi 0de23a29c5 face: use IncomingFaceId, NextHopFaceId, CachePolicy tags
This commit replaces all LocalControlHeader usages with these tags,
and deletes LocalFace.

This commit also does minor improvements in RIB test suites.

refs #3339

Change-Id: I14cbfc296a6723a5860bf8bd95d9804d3bac3da5
2015-12-03 20:07:02 +00:00
Muktadir R Chowdhury 6c4a67af0d tools: adapt to ndn-cxx SegmentFetcher API change
Refs: #2734
Change-Id: Ibce8942007d0b26f34b212140a7b4313c4b6a397
2015-12-01 15:15:51 -07:00
Davide Pesavento 35120ea2f1 face: EthernetTransport
This commit replaces NDNLPv1 fragmentation and reassembly
with NDNLPv2 fragmentation and reassembly.

Change-Id: I10751157fcced94d441167ce470aaed79c12bb54
Refs: #3170
2015-11-26 02:53:20 +01:00
Davide Pesavento eee7b97d7b face: MulticastUdpTransport: set remoteEndpoint for received packets
Change-Id: I0d600d94e41a67c2d58ec10cde3cb6c13f619771
Refs: #3262
2015-11-26 02:49:27 +01:00
Davide Pesavento 762912d711 face: use the correct macro to declare classes final
Change-Id: I7f07d49a4b622ea1207b34d0c4a0f830a0141783
2015-11-26 02:40:51 +01:00
Alexander Afanasyev bd916ad7fc docs: Predefine missing DECL_FINAL macro in doxygen configuration file
Change-Id: Ic7e161bba091b49fe507f913259f53f44d49e862
2015-11-25 17:26:29 -08:00
Eric Newberry 4c3e6b89a1 face: NDNLPv2 fragmentation and reassembly
refs #3171

Change-Id: If29035b697b904ee49cb86d9248be488657c6f9e
2015-11-13 15:47:59 -07:00
Junxiao Shi 8c0500fd97 table: fix Measurements::get(Fib::s_emptyEntry) crash
refs #3275

Change-Id: Ie630111a3421f470756412896154f8a51f60d23d
2015-11-11 08:30:16 -07:00
Junxiao Shi da93f1fd0c face: LpFace counters
FaceCounters for LpFace consist of LinkService::Counters and
Transport::Counters. Old FaceCounters class from 2014 face architecture is
renamed as OldFaceCounters, and can be wrapped with new FaceCounters class.
OldFaceCounters is only used in old Face subclasses.

This commit also updates existing face test suites to use new FaceCounters,
updates ForwarderStatus so that it does not rely on FaceCounters,
and moves the logic of copying face properties and counters into management
structs from face system into FaceManager.

refs #3177

Change-Id: I587e8a32fa72bac3af9d750b2c88342740aa08d6
2015-11-11 06:13:16 -07:00
Junxiao Shi 57df288f5b face: LinkService and Transport counters
refs #3177

Change-Id: Idc495c58c3103dae5f01a2b6ebbff47a2c4a5d2b
2015-11-11 06:12:35 -07:00
Junxiao Shi 52e8540a86 fw: increase initial suppression interval in BestRouteStrategy2
refs #3230

Change-Id: I27217a01c066e90f65b5000a29991c938042a810
2015-11-11 06:06:58 -07:00
Davide Pesavento 077df8fbb6 tests: delete unused SimpleNotification class
Change-Id: I6e574146d335f05a247ec25d0c9bd355c955d945
Refs: #2144
2015-11-11 02:27:58 +01:00
Davide Pesavento 8728a25f1d face: override Transport::beforeChangePersistency in all subclasses
This commit also adds the final specifier to some Transport
subclasses in order to improve code generation.

Change-Id: If2979fa1614476a98019ba79cee3961663fc447b
Refs: #3318
2015-11-10 13:07:10 +01:00
Junxiao Shi d5134a7cd4 tests: defer face deallocation in Face/TestTcp and Face/TestWebSocket
Deallocating face immediately at face closing would cause a Signal object
in the transport to be destructed during its execution, which is disallowed.

refs #3322

Change-Id: I4eb23f34305cfecf7d2122e94454a97353707818
2015-11-08 07:53:24 -07:00
Davide Pesavento 47ab029798 face: deduplicate callback typedefs between Channel and ProtocolFactory
This should have been part of commit 1d7e7afd38

Change-Id: I61623152180d4df288fc7dd3c225518e438d2bda
Refs: #3258
2015-11-04 19:49:58 +01:00
Davide Pesavento ed89ccc521 build: enable -Wextra by default
Change-Id: I1e6783fca6530741bf4b81dd13613a6b4235290a
Refs: #3293
2015-11-02 17:44:30 +01:00
Yukai Tu 16aabbcc3b face: TcpTransport
Change-Id: I3ff898225ad1b0c1178490f389048944e24a9f1b
Refs: #3166
2015-10-27 17:16:07 +01:00
Davide Pesavento 9c7c79f2eb tests: fix "defined but not used" build error with gcc-5
Change-Id: If0cce184f88d76333956e5957db91d5b03e16d39
Refs: #2767
2015-10-27 17:07:40 +01:00
Junxiao Shi a044be7ed9 face: refactor NullFace as LinkService+Transport
refs #3278

Change-Id: I424f70f9402823d58d097671bab8c0c2dc4f2d3b
2015-10-27 07:48:11 -07:00
Yukai Tu 2d6d5637c0 face: WebSocketTransport
Change-Id: I28db9cd6f828e4a9fe5895bb7a6152cca5baa9fc
Refs: #3169, #3160
2015-10-26 11:06:08 -07:00
Junxiao Shi 5b8a2b2128 face: change Transport static properties initialization
Transport constructor now initializes static properties to invalid values.
Subclass constructor must explicitly set every static property.

refs #3259

Change-Id: I7ac3819694e0772c33a8a5d573e260f0eb944bff
2015-10-26 10:56:42 -07:00
Alexander Afanasyev abb307c9c5 docs: Fix doxygen links in release notes and displayed version
Change-Id: Ic1ee22e2607f5ab11c38a9adcaabc27a602c65ae
Refs: #3252
2015-10-26 10:11:02 -07:00
188 changed files with 7697 additions and 7939 deletions

No files matched your search

+1 -1
View File
@@ -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)
+9 -8
View File
@@ -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
View File
@@ -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
+3 -2
View File
@@ -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
+3
View File
@@ -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.
+3 -5
View File
@@ -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)
+20 -10
View File
@@ -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
+1 -1
View File
@@ -1 +1 @@
docs/release-notes/release-notes-0.4.0.rst
docs/release-notes-latest.rst
+3
View File
@@ -0,0 +1,3 @@
# Enable ndn-autoconfig to run in parallel with NFD. Disabled by default
# enabled=true
enabled=false
+141
View File
@@ -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
View File
@@ -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
View File
@@ -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
+51 -38
View File
@@ -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
+13 -12
View File
@@ -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
{
+4 -6
View File
@@ -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
+49
View File
@@ -0,0 +1,49 @@
/* -*- 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 "face-counters.hpp"
namespace nfd {
namespace face {
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)
{
}
} // namespace face
} // namespace nfd
+53 -213
View File
@@ -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
View File
@@ -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
View File
@@ -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
+111 -60
View File
@@ -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;
}
+108 -20
View File
@@ -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
+4 -8
View File
@@ -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
+10
View File
@@ -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)
{
+3
View File
@@ -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;
+9 -12
View File
@@ -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] ";
}
+75 -29
View File
@@ -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)
{
-219
View File
@@ -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
-102
View File
@@ -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
-140
View File
@@ -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
-311
View File
@@ -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
+162
View File
@@ -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
+92
View File
@@ -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
+176
View File
@@ -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
+160
View File
@@ -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
+20
View File
@@ -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
+17 -4
View File
@@ -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;
-108
View File
@@ -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
-152
View File
@@ -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
-117
View File
@@ -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
-50
View File
@@ -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
-90
View File
@@ -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
-135
View File
@@ -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
View File
@@ -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
View File
@@ -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
+2 -18
View File
@@ -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
*/
-363
View File
@@ -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
+39 -45
View File
@@ -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
View File
@@ -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");
+7 -7
View File
@@ -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;
-47
View File
@@ -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
-80
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+5 -9
View File
@@ -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);
+4 -4
View File
@@ -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:
+21 -13
View File
@@ -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
+8 -5
View File
@@ -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;
};
+4 -6
View File
@@ -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
+3 -3
View File
@@ -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;
+11 -2
View File
@@ -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
+5 -1
View File
@@ -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
+37 -68
View File
@@ -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);
+25 -35
View File
@@ -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
-131
View File
@@ -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
+167
View File
@@ -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
+117
View File
@@ -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
+20 -9
View File
@@ -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
+2 -2
View File
@@ -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)
{
}
+6
View File
@@ -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)
{
}
+3 -1
View File
@@ -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;
};
+4 -5
View File
@@ -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() <<
+5 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+9 -12
View File
@@ -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
+22 -17
View File
@@ -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() <<
@@ -151,7 +151,7 @@ Forwarder::onInterestLoop(Face& inFace, const Interest& interest,
shared_ptr<pit::Entry> pitEntry)
{
// 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 +244,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 +284,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 +317,7 @@ Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace,
// send Interest
outFace.sendInterest(*interest);
++m_counters.getNOutInterests();
++m_counters.nOutInterests;
}
void
@@ -370,11 +370,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 +439,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 +453,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 +473,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 +537,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 +556,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 +576,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
+2 -2
View File
@@ -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(),
+77 -54
View File
@@ -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");
}
}
+18 -17
View File
@@ -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,
+6 -1
View File
@@ -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);
}
}
+31 -5
View File
@@ -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);
+7 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+5 -6
View File
@@ -83,12 +83,11 @@ 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) {
// 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 false;
}
}
+9
View File
@@ -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);
}
+10 -10
View File
@@ -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.
@@ -47,7 +47,7 @@ bool
Entry::hasLocalInRecord() const
{
return std::any_of(m_inRecords.begin(), m_inRecords.end(),
[] (const InRecord& inRecord) { return inRecord.getFace()->isLocal(); });
[] (const InRecord& inRecord) { return inRecord.getFace()->getScope() == ndn::nfd::FACE_SCOPE_LOCAL; });
}
bool
@@ -78,14 +78,14 @@ bool
Entry::violatesScope(const Face& face) const
{
// /localhost scope
bool isViolatingLocalhost = !face.isLocal() &&
bool isViolatingLocalhost = face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
LOCALHOST_NAME.isPrefixOf(this->getName());
if (isViolatingLocalhost) {
return true;
}
// /localhop scope
bool isViolatingLocalhop = !face.isLocal() &&
bool isViolatingLocalhop = face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
LOCALHOP_NAME.isPrefixOf(this->getName()) &&
!this->hasLocalInRecord();
if (isViolatingLocalhop) {
+1 -1
View File
@@ -1,4 +1,4 @@
NFD Release Notes
=================
.. include:: release-notes/release-notes-0.4.0.rst
.. include:: release-notes-latest.rst
+4 -2
View File
@@ -242,9 +242,11 @@ latex_documents = [
man_pages = [
('manpages/nfd', 'nfd', u'Named Data Networking Forwarding Daemon', None, 1),
('manpages/ndn-autoconfig-server', 'ndn-autoconfig-server',
u'NFD Auto-configuration Server', None, 1),
u'NDN auto-configuration server', None, 1),
('manpages/ndn-autoconfig', 'ndn-autoconfig',
u'NFD Auto-configuration Client', None, 1),
u'NDN auto-configuration client', None, 1),
('manpages/ndn-autoconfig.conf', 'ndn-autoconfig.conf',
u'NDN auto-configuration client configuration file', None, 5),
('manpages/nfdc', 'nfdc',
u'NFD utility to manipulate the forwarding table (FIB)', None, 1),
('manpages/ndn-tlv-peek', 'ndn-tlv-peek', u'NFD consumer', None, 1),
+2 -1
View File
@@ -1929,7 +1929,8 @@ PREDEFINED = DOXYGEN=1 \
PUBLIC_WITH_TESTS_ELSE_PROTECTED=protected \
PROTECTED_WITH_TESTS_ELSE_PRIVATE=private \
VIRTUAL_WITH_TESTS \
DECL_CLASS_FINAL=final
DECL_CLASS_FINAL=final \
DECL_FINAL=final
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The
+1
View File
@@ -10,6 +10,7 @@ Manpages
schema
manpages/nfd-status-http-server
manpages/ndn-autoconfig
manpages/ndn-autoconfig.conf
manpages/ndn-autoconfig-server
misc/local-prefix-discovery
manpages/nfd-autoreg
+22
View File
@@ -0,0 +1,22 @@
.. _ndn-autoconfig.conf:
autoconfig.conf
===============
Overview
--------
Configuration of NDN auto-configuration client daemon in INI format. Comments in the
configuration file must be prefixed with ``#``.
Example of ``autoconfig.conf``:
.. literalinclude:: ../../autoconfig.conf.sample
Options
-------
``enabled``
(default: false) Enable or disable automatic NDN auto-configuration client daemon.
When enabled, NDN auto-configuration client daemon is automatically started by ``nfd-start``.
+24 -4
View File
@@ -8,13 +8,33 @@ Usage
::
ndn-autoconfig
ndn-autoconfig [options]
Description
-----------
Client tool to run :ref:`NDN hub discovery procedure`.
Options
-------
``-h`` or ``--help``
Print usage information.
``-d`` or ``--daemon``
Run ndn-autoconfig in daemon mode, detecting network change events and re-running
auto-discovery procedure. In addition, the auto-discovery procedure is unconditionally
re-run every hour.
NOTE: if connection to NFD fails, the daemon will be terminated.
``-c [FILE]`` or ``--config=[FILE]``
Use the specified configuration file. If `enabled = true` is not specified in the
configuration file, no actions will be performed.
``-V`` or ``--version``
Print version information.
.. _NDN hub discovery procedure:
NDN hub discovery procedure
@@ -40,8 +60,8 @@ This procedure contains three methods to discover a NDN router:
After connecting to an NDN router, two prefixes will be automatically registered:
- /ndn
- /localhop/nfd --- this to inform RIB manager that there is connectivity to the hub
- ``/ndn``
- ``/localhop/nfd`` --- this to inform RIB manager that there is connectivity to the hub
Stage 1: multicast discovery
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -131,4 +151,4 @@ Stage 3
See also
--------
:ref:`ndn-autoconfig-server`
:ref:`ndn-autoconfig-server`, :doc:`ndn-autoconfig.conf`
+1
View File
@@ -0,0 +1 @@
release-notes/release-notes-0.4.0.rst
Loaded 100 of 188 files, more files were not shown because too many files have changed in this diff. Show more