Compare commits

...
61 Commits
Author SHA1 Message Date
Alexander Afanasyev 2d1b64066c docs: Add missing item in the release notes for version 0.3.2
Change-Id: Iba4f70c2125a702905e11c1db7846495ef377a97
Refs: #2618
2015-05-12 21:15:06 -07:00
Alexander Afanasyev ed808ab2c9 docs+build: Prepare release of version 0.3.2
Change-Id: I43223e09c2201c7d3185a3d8929a691ae963c5d1
Refs: #2618
2015-05-12 13:36:59 -07:00
Junxiao Shi 7b0f4d1dd8 fw: AccessStrategy extends measurements lifetime
refs #2452

Change-Id: I79ffcc65cb222854c163c5df339bb1061785a518
2015-05-12 13:36:59 -07:00
Alexander Afanasyev 483d652d95 build: Disable precompiled headers on OS X with clang < 6.1.0
Change-Id: I4e88f35d6e649eb5b2eefef868ac29576e293877
Refs: #2804
2015-05-12 13:36:59 -07:00
Alexander Afanasyev 1c85221192 build: Update waf to version 1.8.9 (with custom patches)
https://github.com/cawka/waf/tree/2a098b1e9bc626c19cbd47c1f670758c17edf54c

Change-Id: I1e6c352f6ffa272e896391b983fee4cca7cdf8a6
Refs: #2792
2015-05-06 14:51:38 -07:00
Wentao Shang d397d7773c face: switch to non-throwing version of websocketpp APIs
Change-Id: I0291dff14373cadeec16d44c73d9db43011fff4b
Refs: #2630
2015-04-29 18:20:27 -07:00
Vince Lehman f91ab74da9 rib: Stop removed namespace from inheriting ancestor route
refs: #2757

Change-Id: I9f9e18109f0d8ee45571d23a6eea7f254302a56f
2015-04-27 10:00:14 -05:00
Davide Pesavento db9d37edab Fix several "defined but not used" warnings with gcc-5
GCC 5 is able to prove that in some translation units the static Logger
instance is defined but never used, and generates an unused variable
warning for each one of them. These warnings become fatal errors when
building in debug mode, due to -Werror.

Silence the compiler by not declaring the unused variables.

refs #2767

Change-Id: Icacc579d917d660582221ef090954ec827f46149
2015-04-24 10:25:56 -07:00
Alexander Afanasyev ce81230b09 build: Emulate std::to_string when it is missing
Change-Id: I4a08cf4abe7a2064a0c53d29582cbb761a1d131f
Refs: #2743
2015-04-14 23:37:03 -07:00
Mathias Gibbens 802c092d1a face: Use C version of snprintf
Change-Id: I18f85f6debda47af17a4006699f1283dc75b735d
Refs: #2299
2015-04-14 14:47:20 -07:00
Junxiao Shi e8f4246e13 docs: update Planned Features - face enhancements
refs #2617

Change-Id: I64dd36025bf1baf0f93a631d02c7d2a6754c6eba
2015-04-06 21:37:28 -07:00
Alexander Afanasyev cdb8f364c1 build: Tweak default pkg-config search paths
Change-Id: Id9b656104b00fd18c9302165b0eeeffd17f6c87a
Fixes: #2711
2015-03-31 17:19:35 -07:00
Alexander Afanasyev e06b627f31 build: Update waf to version 1.8.8-dev (with custom patches)
https://github.com/cawka/waf/tree/8f714a523d3b8c66f2949aaa8db91d6f7be55e55

This patch also ensures that unused-local-typedef warning does not
generate errors.

Change-Id: I024438c338d0455df11508779c10a2737d25caab
Refs: #2209, #2657
2015-03-26 14:36:02 -05:00
multicast proxy d6474640da tools: Fix hanging of nfdc on wrong input
Change-Id: I4fd4fb95d3dee72f5e0b8bc2435f7fffca87e5e3
Refs: #2690
2015-03-26 14:36:02 -05:00
Vince Lehman 9dcfc40f21 rib: Fix TestFibUpdates/EraseFace on Ubuntu 14.04 32-bit
Change-Id: I1381bc3eb813a1afad9b666fba30688216ee38dc
Refs: #2697
2015-03-26 12:34:26 -07:00
Davide Pesavento 2231ab526f Get rid of the last use of ndn::dns in NFD
Change-Id: I9a3188379a4755f5535af05a860a2e3a12ddc8ba
Refs: #2422
2015-03-19 13:13:25 -07:00
mzhang4 eab7249b74 table: change ContentStore lookup API to allow async implementations
refs: #2411

Change-Id: Ifbb4179c34cf10a7913f8113a2f9238476d8eafa
2015-03-19 04:59:33 -07:00
Davide Pesavento 292e5e1436 face: use move semantics for sockets where possible
Change-Id: I2af595073f862c570c1ce0dcb3717f3d2b9cfd71
Refs: #2613
2015-03-17 21:32:49 -07:00
taylorchu 5ae2877796 build: make wscript compatible with python3
Change-Id: I5b29d85d0b758ec2d154eb71a2637cd73658807a
Refs: #2625
2015-03-17 16:45:27 -07:00
Vince Lehman 76c751ce80 rib: Perform FIB updates before modifying RIB
refs: #1941

Change-Id: I1457f71ddd1c120daae48308d5cc02a7c0ecf93d
2015-03-13 19:57:39 -07:00
Junxiao Shi e4eec13108 face: avoid deprecated Block::fromBuffer overloads
This commit also does some cleanups in NDNLP PartialMessageStore.

refs #2553

Change-Id: I6a74929e58d38bde1a9ac365f7d5c42862d37592
2015-03-13 15:40:49 -07:00
Davide Pesavento 6ad890a098 face: Stop using shared_ptr to manage acceptors
This commit also includes a major cleanup of all channels.

Change-Id: I10db9709e0cba6a0691a86482c60b5dbb2956f68
Refs: #2613
2015-03-11 22:04:40 +01:00
Alexander Afanasyev 8896478926 build: Update version number to 0.3.1
Change-Id: Ibbb64815f3d334c830bee734928813bbf99308bf
Refs: #2588
2015-03-03 20:10:59 -08:00
Alexander Afanasyev 58ad5d4dd7 docs: Prepare release notes for version 0.3.1
Change-Id: Ic7ff46a119f1dd5b898338ddc6673262aef026e0
Refs: #2588
2015-03-03 12:30:28 -08:00
Wentao Shang ce07470031 face: update websocketpp to version 0.5.1
Change-Id: Id5ce36532d30c7d37da466762b335b740e67ad67
2015-03-02 21:07:34 -08:00
Junxiao Shi ebaf7b61fc table: delete nfd::cs::skip_list::Entry
This type is part of the old ContentStore implementation,
which should have been deleted during the merge.

refs #2254

Change-Id: Ib64ee8a65b39bd191d8bdcf4e71ebd5460d342a9
2015-03-02 10:40:03 -08:00
Junxiao Shi 083f778321 face: no exceptions in NDNLP PartialMessageStore
refs #2261

Change-Id: I711502be23bb4b3691eb44fc63332ffd0bfb8d34
2015-03-01 20:46:11 -07:00
Junxiao Shi 78926c9083 face/rib/tools: avoid deprecate Block::fromBuffer overloads
refs #2553

Change-Id: I32ea424ab7547f59fea2fca70ad6f41cd90bab58
2015-02-28 23:02:31 -07:00
Alexander Afanasyev e84044e87d tests: Fix segfault in TableNameTree test suite when all test logs are enabled
Change-Id: I0acb886d38a09b764cb3e324490a7c52b945d4fa
Refs: #2564
2015-02-27 11:31:19 -08:00
Davide Pesavento 9427941781 face: refactor handling of LinkType face trait
This commit also includes some cleanups, fixes EthernetFace to report
the correct LinkType, and makes (get|set)Description non-virtual.

Change-Id: I53909d7bfa02a92641b523a766359413c966aae6
Refs: #2563
2015-02-27 15:12:16 +01:00
Davide Pesavento 13b76f0937 face: copy also the link type in copyStatusTo
Change-Id: I3787210328f326fd788e7f0f3e23493e4dfa9ddd
Refs: #2563
2015-02-26 18:45:19 +01:00
Davide Pesavento be40fb1e56 face: Introduce Face-specific logging macros
Change-Id: I169065de664d4c4394ccd08673bbe1f881c4d7e0
Refs: #2450
2015-02-26 18:42:59 +01:00
Junxiao Shi 684fa0f89d fw: use RetxSuppressionExponential in best-route
Retransmission suppression algorithm of best route strategy
is changed from fixed interval to exponential backoff.
This is a semantical change which requires an increment of the
strategy's version number from 2 to 3.
Version 2 is not retained because it's mostly same as version 3.

refs #1913

Change-Id: I0f18511a3b96384b071024864e638ae3b3ec7080
2015-02-23 21:39:57 -07:00
Davide Pesavento 0e97a97603 table: Reduce priority of DeadNonceList log messages
Change-Id: Id0419b9c38ec693b6111ce5b8f91a6d1aa04f705
2015-02-23 14:57:19 -08:00
Vince Lehman ff8b39746b rib: Change register/unregister logging to INFO
refs: #2547

Change-Id: Iedf72cb9c9f36742ea43650f8cdd4a9450c987de
2015-02-23 12:45:26 -08:00
Junxiao Shi 35b16b1984 table: ContentStore recognizes CachingPolicy-NoCache
refs #2185

Change-Id: Id3dab8936c4dafc96c5d8933d7e75c6cc2e31ff2
2015-02-21 21:42:11 -07:00
Spyridon Mastorakis d0381c05a6 tests: Change to updated naming conventions
Change-Id: I9351c669282c3c02fd533237489beeb10fe7d15e
Refs: #2497
2015-02-21 13:02:47 -08:00
Minsheng Zhang 60d06d8770 tools: change prefix of routable-prefixes packet to under /localhop/nfd
refs #2512

Change-Id: Ib399e61b3d7b84f7993a5b887ff6b5b7c3e93a45
2015-02-20 16:49:15 -06:00
Junxiao Shi 0d6d036e4f docs: change prefix of routable-prefixes packet to under /localhop/nfd
refs #2479

Change-Id: I49c02bbfe5eed282c33ecfe99ce8b1894a1b7d23
2015-02-20 08:21:16 -08:00
Chengyu Fan addecff68b management: clarify the inconsistency in UDP face timeouts in nfd.conf
refs #2473

Change-Id: Iceeda5f03bc426dfab1e67cf508996d3fe96ac42
2015-02-18 07:18:29 -08:00
Alexander Afanasyev 4d384fcce5 tests: Revert changes to s_normalUid/s_normalGid in MgmtGeneralConfigSection test suite
If changes to s_normalUid/s_normalGid are not reverted, the subsequent call
to PrivilegeHelper::drop() will throw exception if test cases run by an
unprivileged user.

Change-Id: I27e8b159d61e1b5f6dd21879f36ed63667f5c045
Refs: #2521
2015-02-17 09:22:29 -08:00
Junxiao Shi faf3eb0823 fw: register strategy with macro
refs #2410

Change-Id: Ifa79c194c58d0ebe1bca6236fc0a47debe2da05e
2015-02-16 22:30:16 -07:00
Junxiao Shi 73b909a514 fw: RetxSuppressionExponential
refs #1913

Change-Id: I9bb2bae8d7600722920534f646cc8056b3d4843a
2015-02-16 16:23:28 -08:00
Alexander Afanasyev a4ff44ce6f face: Update code to work with updated LocalControlHeader implementation
Change-Id: I3a73269ad30cfd8d7e366115aae08728f17c3b17
Refs: #2183
2015-02-16 11:40:06 -08:00
Alexander Afanasyev 90c20face8 face: Properly handle error conditions in UdpChannel::newPeer
Change-Id: Ia34eb738a6cc8977bbcba91f0055fe4623df4d32
Refs: #2516
2015-02-15 12:43:57 -08:00
Alexander Afanasyev baba2535e1 face: Remove Tcp|UdpChannel::connect overloads that perform DNS resolution
Change-Id: Ib5da2a43d1e33654940aa42f568b6a604c171e3e
Refs: #2422
2015-02-15 12:43:57 -08:00
Alexander Afanasyev c3ea5a7886 rib: Use only a forward declaration of RibManager in the header of Nrd class
Change-Id: I8a681dc9a75ac8cdabc289e685ec6a505cfb5aac
2015-02-15 12:43:57 -08:00
Alexander Afanasyev 2bda6f8d9c daemon: Replace shared_ptr with unique_ptr in Nfd
Change-Id: I97d39ddb793abfe4552002c94778b95e6b96f869
Refs: #2496
2015-02-15 12:43:57 -08:00
Alexander Afanasyev f08a7376e9 daemon+rib: Merge nrd and nfd into a single process (separate threads)
Change-Id: I41952d5b8ee29f109130c570e0d13ccad6970d2f
Refs: #2489
2015-02-15 12:43:49 -08:00
Alexander Afanasyev 63df436e5f core: Make global random generator thread-local
Change-Id: Ib17ea05592445cf99af9726ef7799ead813ca0fe
Refs: #2489
2015-02-15 11:58:52 -08:00
Alexander Afanasyev 6b34ab9cec core: Make logger thread-safe
Change-Id: Ic45dc0912da9c2e3f074d3f74921bfe33741bf63
Refs: #2489
2015-02-14 12:26:32 -08:00
Alexander Afanasyev 5d57f97fa7 core: Make global io_service and scheduler thread-local
Change-Id: I3d6b6cd3ca7a6e53b0dc0f4cae7a2f3270c7fd50
Refs: #2489
2015-02-14 12:25:19 -08:00
Alexander Afanasyev 9cfeecaa2f core: Prevent exception throwing when dropping privileges is not supported and not requested
The exception still be thrown, if config file requests privilege dropping.

Change-Id: I856207958354410fa45da7ccc73b46b99f74d9e7
Refs: #2515
2015-02-12 16:44:24 -08:00
Alexander Afanasyev 6f570de8d7 core: Make PrivilegeHeper::drop|raise no-op operations on platforms that do not support drop/elevation of privileges
Change-Id: I13b53ba27cee59d58b816d060501499517e6dc37
2015-02-11 20:59:09 -08:00
Alexander Afanasyev 31367925c6 rib: Refactor initialization of NRD instance
This commit also makes Face used inside NRD be adaptive to nfd.conf.
More specifically, it will use the same unix socket path as specified in
face_system.unix section.  If this section is not present, it will use
the same tcp port as specified in face_system.tcp section.  If tcp
section is also absent, nrd will abort execution.

Change-Id: I48f75ddf972f259055cd61824e3c228ca1d6a639
Refs: #2496
2015-02-11 16:13:26 -08:00
Alexander Afanasyev 31c781e453 daemon: Refactor initialization of NFD instance
Change-Id: Ie4181a0b65e249c7067a11e941dcea77f010e4b1
Refs: #2496
2015-02-10 19:12:05 -08:00
Alexander Afanasyev 8269a05874 core: Allow customization of Logger and LoggerFactory
Change-Id: I48a8217ab4cfb34ce2993f11a26266723d8d2923
Refs: #2433
2015-02-10 19:12:04 -08:00
Alexander Afanasyev 95ff7112aa tests: Fix compilation due to refactoring of EncodingImpl in ndn-cxx library
Change-Id: I3b96dd01fef810dfd2cd57d910a46f137a13879e
Refs: #2494
2015-02-10 19:11:33 -08:00
Alexander Afanasyev c0273e3505 core: Extend ConfigFile to support passing a parsed ConfigSection
Change-Id: I955220c08d8e6ed07c77d82149f6ff3ae48b2b12
Refs: #2495
2015-02-09 13:33:45 -08:00
Junxiao Shi a788e25e70 fw: rename RetransmissionSuppression to RetxSuppressionFixed
This commit also declares RetxSuppression base class as the API
for any retransmission suppression decision algorithms,
so that other algorithms can be introduced.

refs #1913

Change-Id: I5539565d2dd238d1421f5bd828fde4ecfba0a820
2015-02-04 06:56:03 -08:00
Alexander Afanasyev 3056e08c9e docs: Update link to the right version of developer's guide
Change-Id: I6a39507df56141d648728bebc9f6305584ecb067
2015-02-03 16:00:31 -08:00
201 changed files with 7071 additions and 5388 deletions

No files matched your search

+1 -1
View File
@@ -25,7 +25,7 @@ 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 CorePrivilegeHelper -l test_suite
sudo ./build/unit-tests-core -t TestPrivilegeHelper -l test_suite
# Daemon
./build/unit-tests-daemon -l test_suite
+31 -4
View File
@@ -18,10 +18,37 @@ class Derived : public Base
@conf
def check_override(self):
if self.check_cxx(msg='Checking for override specifier',
fragment=OVERRIDE,
features='cxx', mandatory=False):
self.define('HAVE_CXX_OVERRIDE', 1)
self.check_cxx(msg='Checking for override specifier',
fragment=OVERRIDE,
define_name='HAVE_CXX_OVERRIDE',
features='cxx', mandatory=False)
STD_TO_STRING = '''
#include <string>
int
main(int argc, char** argv)
{
std::string s = std::to_string(0);
s = std::to_string(0l);
s = std::to_string(0ll);
s = std::to_string(0u);
s = std::to_string(0ul);
s = std::to_string(0ull);
s = std::to_string(0.0f);
s = std::to_string(0.0);
s = std::to_string(0.0l);
s.clear();
return 0;
}
'''
@conf
def check_std_to_string(self):
self.check_cxx(msg='Checking for std::to_string',
fragment=STD_TO_STRING,
define_name='HAVE_STD_TO_STRING',
features='cxx', mandatory=False)
def configure(conf):
conf.check_override()
conf.check_std_to_string()
+1
View File
@@ -139,6 +139,7 @@ class ClangFlags(GccBasicFlags):
flags['CXXFLAGS'] += ['-std=c++11',
'-Wno-error=unneeded-internal-declaration', # Bug #1588
'-Wno-error=deprecated-register',
'-Wno-error=unused-local-typedef', # Bug #2657
]
if Utils.unversioned_sys_platform() == "darwin":
flags['CXXFLAGS'] += ['-stdlib=libc++']
+5
View File
@@ -67,6 +67,11 @@ def options(opt):
def configure(conf):
if (conf.options.with_pch and conf.env['COMPILER_CXX'] in PCH_COMPILER_OPTIONS.keys()):
if Utils.unversioned_sys_platform() == "darwin" and conf.env['CXX_NAME'] == 'clang':
version = tuple(int(i) for i in conf.env['CC_VERSION'])
if version < (6, 1, 0):
# Issue #2804
return
conf.env.WITH_PCH = True
flags = PCH_COMPILER_OPTIONS[conf.env['COMPILER_CXX']]
conf.env.CXXPCH_F = flags[0]
+3 -3
View File
@@ -36,8 +36,8 @@ def checkWebsocket(self, **kw):
# Looking for the following:
# static int const major_version = 0;
# static int const minor_version = 3;
# static int const patch_version = 0;
# static int const minor_version = 5;
# static int const patch_version = 1;
version = [None, None, None]
@@ -71,7 +71,7 @@ def checkWebsocket(self, **kw):
Logs.warn(' git submodule init && git submodule update')
Logs.warn('Otherwise, manually download and extract websocketpp library:')
Logs.warn(' mkdir websocketpp')
Logs.warn(' curl -L https://github.com/zaphoyd/websocketpp/tarball/4309749dd98937b8a7be5dc0bfe679ba201c5512 > websocket.tar.gz')
Logs.warn(' curl -L https://github.com/zaphoyd/websocketpp/archive/0.5.1.tar.gz > websocket.tar.gz')
Logs.warn(' tar zxf websocket.tar.gz -C websocketpp/ --strip 1')
Logs.warn('Alternatively, WebSocket support can be disabled with --without-websocket')
self.fatal("The configuration failed")
+2
View File
@@ -62,6 +62,7 @@ volunteers.
* Syed Obaid Amin <http://obaidamin.weebly.com/>
* Vince Lehman <vslehman@memphis.edu>
* Minsheng Zhang <mzhang4@memphis.edu>
* Lan Wang <http://www.cs.memphis.edu/~lanwang/>
## Project contributors
@@ -71,3 +72,4 @@ people who have reported bugs, submitted patches, and implemented new features
in the library:
* Tai-Lin Chu <https://www.linkedin.com/pub/tai-lin-chu/55/5b2/669>
* Spyridon Mastorakis <http://cs.ucla.edu/~mastorakis/>
+16 -3
View File
@@ -57,11 +57,12 @@
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <string>
#include <ndn-cxx/common.hpp>
#include <ndn-cxx/interest.hpp>
#include <ndn-cxx/data.hpp>
#include <ndn-cxx/util/event-emitter.hpp> // deprecated
#include <ndn-cxx/util/face-uri.hpp>
#include <ndn-cxx/util/signal.hpp>
#include <boost/algorithm/string.hpp>
@@ -80,7 +81,6 @@ using boost::noncopyable;
using std::shared_ptr;
using std::unique_ptr;
using std::weak_ptr;
using std::bad_weak_ptr;
using std::make_shared;
using std::enable_shared_from_this;
@@ -98,7 +98,7 @@ using ndn::Data;
using ndn::Name;
using ndn::Exclude;
using ndn::Block;
using ndn::util::EventEmitter; // deprecated
using ndn::util::FaceUri;
namespace tlv {
// Don't write "namespace tlv = ndn::tlv", because NFD can add other members into this namespace.
@@ -111,4 +111,17 @@ namespace signal = ndn::util::signal;
} // namespace nfd
// Some platforms are missing std::to_string (issue #2743)
#ifndef HAVE_STD_TO_STRING
namespace std {
template<typename V>
inline std::string
to_string(const V& v)
{
return boost::lexical_cast<std::string>(v);
}
} // namespace std
#endif // HAVE_STD_TO_STRING
#endif // NFD_COMMON_HPP
+27 -38
View File
@@ -7,23 +7,17 @@ when they die.
Initial setup
-------------
Edit `net.named-data.nfd` and `net.named-data.nrd` correcting paths for `nfd` and `nfd`
binaries, configuration file, and log files.
Edit `net.named-data.nfd` correcting paths for `nfd` binary, configuration and log files.
# Copy launchd.plist for nfd (forwarding daemon)
# Copy launchd.plist for NFD
sudo cp net.named-data.nfd.plist /Library/LaunchDaemons/
sudo chown root /Library/LaunchDaemons/net.named-data.nfd.plist
# Copy launchd.plist for nrd (RIB management daemon)
sudo cp net.named-data.nrd.plist /Library/LaunchDaemons/
sudo chown root /Library/LaunchDaemons/net.named-data.nrd.plist
### Assumptions in the default scripts
* `nfd` and `nrd` are installed into `/usr/local/bin`
* `nfd` is installed into `/usr/local/bin`
* Configuration file is `/usr/local/etc/ndn/nfd.conf`
* `nfd` will be run as root
* `nrd` will be run as user `ndn` and group `ndn`
* Log files will be written to `/usr/local/var/log/ndn` folder, which is owned by user `ndn`
### Creating users
@@ -62,29 +56,24 @@ Folder `/usr/local/var/log/ndn` should be created and assigned proper user and g
sudo mkdir -p /usr/local/var/log/ndn
sudo chown -R ndn:ndn /usr/local/var/log/ndn
`HOME` directories for `nfd` and `nrd` should be created and configured with correct
library's config file and contain proper NDN security credentials for signing Data
packets. This is necessary since default private key storage on OSX (`osx-keychain`) does
not support non-interactive access, and file-based private key storage needs to be used:
`HOME` directory for `nfd` should be created and configured with correct library's config file
and contain proper NDN security credentials for signing Data packets. This is necessary since
default private key storage on OSX (`osx-keychain`) does not support non-interactive access,
and file-based private key storage needs to be used:
# Generate self-signed NDN certificate for nfd (owned by root)
sudo mkdir -p /usr/local/var/lib/ndn/nfd/.ndn
sudo sh -c 'echo tpm=file > /usr/local/var/lib/ndn/nfd/.ndn/client.conf'
sudo HOME=/usr/local/var/lib/ndn/nfd ndnsec-keygen /localhost/daemons/nfd | \
sudo HOME=/usr/local/var/lib/ndn/nfd ndnsec-install-cert -
# Generate self-signed NDN certificate for nrd (owned by ndn)
sudo mkdir -p /usr/local/var/lib/ndn/nrd/.ndn
sudo chown -R ndn:ndn /usr/local/var/lib/ndn/nrd
sudo -u ndn -g ndn sh -c 'echo tpm=file > /usr/local/var/lib/ndn/nrd/.ndn/client.conf'
sudo -u ndn -g ndn HOME=/usr/local/var/lib/ndn/nrd ndnsec-keygen /localhost/daemons/nrd | \
sudo -u ndn -g ndn HOME=/usr/local/var/lib/ndn/nrd ndnsec-install-cert -
# Create HOME and generate self-signed NDN certificate for nfd
sudo -s -- ' \
mkdir -p /usr/local/var/lib/ndn/nfd/.ndn; \
export HOME=/usr/local/var/lib/ndn/nfd; \
echo tpm=tpm-file > /usr/local/var/lib/ndn/nfd/.ndn/client.conf; \
ndnsec-keygen /localhost/daemons/nfd | ndnsec-install-cert -; \
'
### Configuring NFD's security
NFD sample configuration allows anybody to create faces, add nexthops to FIB,
and set strategy choice for namespaces. While such settings could be a good start, it is
generally not a good idea to run NFD in this mode.
NFD sample configuration allows anybody to create faces, add nexthops to FIB, and set strategy
choice for namespaces. While such settings could be a good start, it is generally not a good
idea to run NFD in this mode.
While thorough discussion about security configuration of NFD is outside the scope of this
document, at least the following change should be done to nfd.conf in authorize section:
@@ -93,7 +82,7 @@ document, at least the following change should be done to nfd.conf in authorize
{
authorize
{
certfile certs/localhost_daemons_nrd.ndncert
certfile certs/localhost_daemons_nfd.ndncert
privileges
{
faces
@@ -114,25 +103,25 @@ document, at least the following change should be done to nfd.conf in authorize
}
While this configuration still allows management of faces and updating strategy choice by
anybody, only NFD's RIB Manager Daemon (`nrd`) is allowed to manage FIB.
anybody, only NFD's RIB Manager (i.e., NFD itself) is allowed to manage FIB.
As the final step to make this configuration work, nrd's self-signed certificate needs to
be exported into `localhost_daemons_nrd.ndncert` file:
As the final step to make this configuration work, NFD's self-signed certificate needs to
be exported into `localhost_daemons_nfd.ndncert` file:
sudo mkdir /usr/local/etc/ndn/certs
sudo sh -c 'sudo -u ndn -g ndn HOME=/usr/local/var/lib/ndn/nrd \
ndnsec-dump-certificate -i /localhost/daemons/nrd \
> /usr/local/etc/ndn/certs/localhost_daemons_nrd.ndncert'
sudo -s -- '\
mkdir -p /usr/local/etc/ndn/certs || true; \
export HOME=/usr/local/var/lib/ndn/nfd; \
ndnsec-dump-certificate -i /localhost/daemons/nfd > \
/usr/local/etc/ndn/certs/localhost_daemons_nfd.ndncert; \
'
Enable auto-start
-----------------
sudo launchctl load -w /Library/LaunchDaemons/net.named-data.nfd.plist
sudo launchctl load -w /Library/LaunchDaemons/net.named-data.nrd.plist
Disable auto-start
------------------
sudo launchctl unload -w /Library/LaunchDaemons/net.named-data.nfd.plist
sudo launchctl unload -w /Library/LaunchDaemons/net.named-data.nrd.plist
@@ -1,25 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd" >
<plist version='1.0'>
<dict>
<key>Label</key><string>net.named-data.nrd</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/nrd</string>
<string>--config</string>
<string>/usr/local/etc/ndn/nfd.conf</string>
</array>
<key>UserName</key><string>ndn</string>
<key>GroupName</key><string>ndn</string>
<key>EnvironmentVariables</key>
<dict>
<key>HOME</key><string>/usr/local/var/lib/ndn/nrd</string>
</dict>
<key>Debug</key><true/>
<key>Disabled</key><true/>
<key>KeepAlive</key><true/>
<key>StandardErrorPath</key><string>/usr/local/var/log/ndn/nrd.log</string>
<key>ProcessType</key><string>Background</string>
</dict>
</plist>
+26 -45
View File
@@ -8,26 +8,18 @@ when they die.
Initial setup
-------------
Edit `nfd.conf` and `nrd.conf` correcting paths for `nfd` and `nfd` binaries,
configuration file, and log files.
* Edit `nfd.conf` correcting paths for `nfd` binary, configuration and log files.
# Copy upstart config file for nfd (forwarding daemon)
sudo cp nfd.conf /etc/init/
* Copy upstart config file for NFD
# Copy upstart config file for nrd (RIB management daemon)
sudo cp nrd.conf /etc/init/
# Copy upstart config file for nfd-watcher (will restart NFD when network change detected)
sudo cp nfd-watcher.conf /etc/init/
sudo cp nfd.conf /etc/init/
### Assumptions in the default scripts
* `nfd` and `nrd` are installed into `/usr/local/bin`
* `nfd` is installed into `/usr/local/bin`
* Configuration file is `/usr/local/etc/ndn/nfd.conf`
* `nfd` will be run as root
* `nrd` will be run as user `ndn` and group `ndn`
* Log files will be written to `/usr/local/var/log/ndn` folder, which is owned by user `ndn`
* Whenever network connectivity changes, both `nfd` and `nrd` are restarted
### Creating users
@@ -53,19 +45,15 @@ Folder `/usr/local/var/log/ndn` should be created and assigned proper user and g
sudo mkdir -p /usr/local/var/log/ndn
sudo chown -R ndn:ndn /usr/local/var/log/ndn
`HOME` directories for `nfd` and `nrd` should be created prior to starting. This is
necessary to manage unique security credentials for the deamons.
`HOME` directory for `nfd` should be created prior to starting. This is necessary to manage
unique security credentials for the deamon.
# Create HOME and generate self-signed NDN certificate for nfd
sudo mkdir -p /usr/local/var/lib/ndn/nfd/.ndn
sudo HOME=/usr/local/var/lib/ndn/nfd ndnsec-keygen /localhost/daemons/nfd | \
sudo HOME=/usr/local/var/lib/ndn/nfd ndnsec-install-cert -
# Create HOME and generate self-signed NDN certificate for nrd
sudo mkdir -p /usr/local/var/lib/ndn/nrd/.ndn
sudo chown -R ndn:ndn /usr/local/var/lib/ndn/nrd
sudo -u ndn -g ndn HOME=/usr/local/var/lib/ndn/nrd ndnsec-keygen /localhost/daemons/nrd | \
sudo -u ndn -g ndn HOME=/usr/local/var/lib/ndn/nrd ndnsec-install-cert -
sudo -s -- ' \
mkdir -p /usr/local/var/lib/ndn/nfd/.ndn; \
export HOME=/usr/local/var/lib/ndn/nfd; \
ndnsec-keygen /localhost/daemons/nfd | ndnsec-install-cert -; \
'
### Configuring NFD's security
@@ -81,7 +69,7 @@ section:
{
authorize
{
certfile certs/localhost_daemons_nrd.ndncert
certfile certs/localhost_daemons_nfd.ndncert
privileges
{
faces
@@ -102,43 +90,36 @@ section:
}
While this configuration still allows management of faces and updating strategy choice by
anybody, only NFD's RIB Manager Daemon (`nrd`) is allowed to manage FIB.
anybody, only NFD's RIB Manager (i.e., NFD itself) is allowed to manage FIB.
As the final step to make this configuration work, nrd's self-signed certificate needs to
be exported into `localhost_daemons_nrd.ndncert` file:
As the final step to make this configuration work, nfd's self-signed certificate needs to
be exported into `localhost_daemons_nfd.ndncert` file:
sudo mkdir /usr/local/etc/ndn/certs
sudo sh -c 'sudo -u ndn -g ndn HOME=/usr/local/var/lib/ndn/nrd \
ndnsec-dump-certificate -i /localhost/daemons/nrd \
> /usr/local/etc/ndn/certs/localhost_daemons_nrd.ndncert'
sudo -s -- '\
mkdir -p /usr/local/etc/ndn/certs || true; \
export HOME=/usr/local/var/lib/ndn/nfd; \
ndnsec-dump-certificate -i /localhost/daemons/nfd > \
/usr/local/etc/ndn/certs/localhost_daemons_nfd.ndncert; \
'
Enable auto-start
-----------------
After copying the provided upstart scripts, `nfd` and `nrd` daemons will automatically run
after the reboot. To manually start them, use the following commands:
After copying the provided upstart script, `nfd` daemon will automatically run after the reboot.
To manually start them, use the following commands:
sudo start nfd
# nrd will be automatically started by upstart
Note that an additional upstart job, ``nfd-watcher``, will automatically monitor for
network connectivity changes, such as when network interface gets connected, disconnected,
or IP addresses of the network interface get updated. When ``nfd-watcher`` detects the
event, it will restart `nfd` and `nrd`.
Disable auto-start
------------------
To stop `nrd` and `nfd` daemon, use the following commands:
To stop `nfd` daemon, use the following commands:
sudo stop nfd
# nrd will be automatically stopped by upstart
Note that as long as upstart files are present in `/etc/init/`, the daemons will
automatically start after the reboot. To permanently stop `nfd` and `nrd` daemons, delete
Note that as long as upstart files are present in `/etc/init/`, the daemon will
automatically start after the reboot. To permanently stop `nfd` daemon, delete
the upstart files:
sudo rm /etc/init/nfd.conf
sudo rm /etc/init/nrd.conf
sudo rm /etc/init/nfd-watcher.conf
-13
View File
@@ -1,13 +0,0 @@
# nfd-watcher.conf
#
# Restarting NDN Forwarding Daemon on network connectivity changes
start on (net-device-up or
net-device-removed or
net-device-changed)
task
script
status nfd | grep -q start/ || stop
restart nfd
end script
+9
View File
@@ -14,4 +14,13 @@ env HOME=/usr/local/var/lib/ndn/nfd
export HOME
exec /usr/local/bin/nfd --config /usr/local/etc/ndn/nfd.conf 2>> /usr/local/var/log/ndn/nfd.log
post-start script
if [ -f /usr/local/etc/ndn/nfd-init.sh ]; then
sleep 2 # post-start is executed just after nfd process starts, but there is no guarantee
# that all initialization has been finished
. /usr/local/etc/ndn/nfd-init.sh
fi
end script
post-stop exec sleep 2
-22
View File
@@ -1,22 +0,0 @@
# nrd.conf
#
# NDN RIB Manager Daemon
description "NDN RIB Manager Daemon"
start on started nfd
stop on stopping nfd
respawn
respawn limit unlimited
setuid ndn
setgid ndn
pre-start exec sleep 2
script
export HOME=/usr/local/var/lib/ndn/nrd
/usr/local/bin/nrd --config /usr/local/etc/ndn/nfd.conf 2>> /usr/local/var/log/ndn/nrd.log
end script
post-stop exec sleep 2
+7 -2
View File
@@ -30,8 +30,6 @@
namespace nfd {
NFD_LOG_INIT("ConfigFile");
void
ConfigFile::throwErrorOnUnknownSection(const std::string& filename,
const std::string& sectionName,
@@ -108,6 +106,13 @@ ConfigFile::parse(std::istream& input, bool isDryRun, const std::string& filenam
process(isDryRun, filename);
}
void
ConfigFile::parse(const ConfigSection& config, bool isDryRun, const std::string& filename)
{
m_global = config;
process(isDryRun, filename);
}
void
ConfigFile::process(bool isDryRun, const std::string& filename)
{
+11 -2
View File
@@ -91,7 +91,7 @@ public:
/**
* \param input configuration (as a string) to parse
* \param isDryRun true if performing a dry run of configuration, false otherwise
* \param filename optional convenience argument to provide more detailed error messages
* \param filename logical filename of the config file, can appear in error messages
* \throws ConfigFile::Error if file not found
* \throws ConfigFile::Error if parse error
*/
@@ -101,12 +101,21 @@ public:
/**
* \param input stream to parse
* \param isDryRun true if performing a dry run of configuration, false otherwise
* \param filename optional convenience argument to provide more detailed error messages
* \param filename logical filename of the config file, can appear in error messages
* \throws ConfigFile::Error if parse error
*/
void
parse(std::istream& input, bool isDryRun, const std::string& filename);
/**
* \param config ConfigSection that needs to be processed
* \param isDryRun true if performing a dry run of configuration, false otherwise
* \param filename logical filename of the config file, can appear in error messages
* \throws ConfigFile::Error if parse error
*/
void
parse(const ConfigSection& config, bool isDryRun, const std::string& filename);
private:
void
+13 -10
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,9 +21,10 @@
*
* 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 "global-io.hpp"
#include <boost/thread/tss.hpp>
namespace nfd {
@@ -32,13 +34,14 @@ void
resetGlobalScheduler();
} // namespace scheduler
static shared_ptr<boost::asio::io_service> g_ioService;
static boost::thread_specific_ptr<boost::asio::io_service> g_ioService;
boost::asio::io_service&
getGlobalIoService()
{
if (!static_cast<bool>(g_ioService)) {
g_ioService = make_shared<boost::asio::io_service>();
if (g_ioService.get() == nullptr) {
g_ioService.reset(new boost::asio::io_service());
}
return *g_ioService;
}
+78 -82
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,10 +21,16 @@
*
* 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 "logger-factory.hpp"
#include <boost/range/adaptor/map.hpp>
#ifdef HAVE_CUSTOM_LOGGER
#error "This file should not be compiled when custom logger is used"
#endif
namespace nfd {
NFD_LOG_INIT("LoggerFactory");
@@ -65,44 +72,37 @@ LoggerFactory::parseLevel(const std::string& level)
// std::cerr << m_levelNames.begin()->first << std::endl;
LevelMap::const_iterator levelIt = m_levelNames.find(upperLevel);
if (levelIt != m_levelNames.end())
{
return levelIt->second;
}
try
{
uint32_t levelNo = boost::lexical_cast<uint32_t>(level);
if (levelIt != m_levelNames.end()) {
return levelIt->second;
}
try {
uint32_t levelNo = boost::lexical_cast<uint32_t>(level);
if ((boost::lexical_cast<uint32_t>(LOG_NONE) <= levelNo &&
levelNo <= boost::lexical_cast<uint32_t>(LOG_TRACE)) ||
levelNo == LOG_ALL)
{
return static_cast<LogLevel>(levelNo);
}
if ((boost::lexical_cast<uint32_t>(LOG_NONE) <= levelNo &&
levelNo <= boost::lexical_cast<uint32_t>(LOG_TRACE)) ||
levelNo == LOG_ALL) {
return static_cast<LogLevel>(levelNo);
}
catch (const boost::bad_lexical_cast& error)
{
}
throw LoggerFactory::Error("Unsupported logging level \"" +
level + "\"");
}
catch (const boost::bad_lexical_cast& error) {
}
throw LoggerFactory::Error("Unsupported logging level \"" + level + "\"");
}
LogLevel
LoggerFactory::extractLevel(const ConfigSection& item, const std::string& key)
{
std::string levelString;
try
{
levelString = item.get_value<std::string>();
}
catch (const boost::property_tree::ptree_error& error)
{
}
try {
levelString = item.get_value<std::string>();
}
catch (const boost::property_tree::ptree_error& error) {
}
if (levelString.empty())
{
throw LoggerFactory::Error("No logging level found for option \"" + key + "\"");
}
if (levelString.empty()) {
throw LoggerFactory::Error("No logging level found for option \"" + key + "\"");
}
return parseLevel(levelString);
}
@@ -126,58 +126,51 @@ LoggerFactory::onConfig(const ConfigSection& section,
// Forwarder WARN
// }
if (!isDryRun)
{
ConfigSection::const_assoc_iterator item = section.find("default_level");
if (item != section.not_found())
{
LogLevel level = extractLevel(item->second, "default_level");
setDefaultLevel(level);
}
else
{
setDefaultLevel(LOG_INFO);
}
if (!isDryRun) {
ConfigSection::const_assoc_iterator item = section.find("default_level");
if (item != section.not_found()) {
LogLevel level = extractLevel(item->second, "default_level");
setDefaultLevel(level);
}
for (ConfigSection::const_iterator item = section.begin();
item != section.end();
++item)
{
LogLevel level = extractLevel(item->second, item->first);
if (item->first == "default_level")
{
// do nothing
}
else
{
LoggerMap::iterator loggerIt = m_loggers.find(item->first);
if (loggerIt == m_loggers.end())
{
NFD_LOG_DEBUG("Failed to configure logging level for module \"" <<
item->first << "\" (module not found)");
}
else if (!isDryRun)
{
// std::cerr << "changing level for module " << item->first << " to " << level << std::endl;
loggerIt->second.setLogLevel(level);
}
}
else {
setDefaultLevel(LOG_INFO);
}
}
for (const auto& i : section) {
LogLevel level = extractLevel(i.second, i.first);
if (i.first == "default_level") {
// do nothing
}
else {
std::unique_lock<std::mutex> lock(m_loggersGuard);
LoggerMap::iterator loggerIt = m_loggers.find(i.first);
if (loggerIt == m_loggers.end()) {
lock.unlock();
NFD_LOG_DEBUG("Failed to configure logging level for module \"" <<
i.first << "\" (module not found)");
}
else if (!isDryRun) {
loggerIt->second.setLogLevel(level);
lock.unlock();
NFD_LOG_DEBUG("Changing level for module " << i.first << " to " << level);
}
}
}
}
void
LoggerFactory::setDefaultLevel(LogLevel level)
{
// std::cerr << "changing to default_level " << level << std::endl;
std::lock_guard<std::mutex> lock(m_loggersGuard);
m_defaultLevel = level;
for (LoggerMap::iterator i = m_loggers.begin(); i != m_loggers.end(); ++i)
{
// std::cerr << "changing " << i->first << " to default " << m_defaultLevel << std::endl;
i->second.setLogLevel(m_defaultLevel);
}
for (auto&& logger : m_loggers) {
// std::cerr << "changing " << i->first << " to default " << m_defaultLevel << std::endl;
logger.second.setLogLevel(m_defaultLevel);
}
}
Logger&
@@ -192,6 +185,8 @@ LoggerFactory::createLogger(const std::string& moduleName)
// std::cerr << "creating logger for " << moduleName
// << " with level " << m_defaultLevel << std::endl;
std::lock_guard<std::mutex> lock(m_loggersGuard);
std::pair<LoggerMap::iterator, bool> loggerIt =
m_loggers.insert(NameAndLogger(moduleName, Logger(moduleName, m_defaultLevel)));
@@ -201,11 +196,12 @@ LoggerFactory::createLogger(const std::string& moduleName)
std::list<std::string>
LoggerFactory::getModules() const
{
std::lock_guard<std::mutex> lock(m_loggersGuard);
std::list<std::string> modules;
for (LoggerMap::const_iterator i = m_loggers.begin(); i != m_loggers.end(); ++i)
{
modules.push_back(i->first);
}
for (const auto& loggerName : m_loggers | boost::adaptors::map_keys) {
modules.push_back(loggerName);
}
return modules;
}
+16 -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,12 +21,17 @@
*
* 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_LOGGER_FACTORY_HPP
#define NFD_CORE_LOGGER_FACTORY_HPP
#include "common.hpp"
#ifdef HAVE_CUSTOM_LOGGER
#include "custom-logger-factory.hpp"
#else
#include "config-file.hpp"
#include "logger.hpp"
@@ -95,6 +101,7 @@ private:
typedef std::pair<std::string, Logger> NameAndLogger;
LoggerMap m_loggers;
mutable std::mutex m_loggersGuard;
LogLevel m_defaultLevel;
};
@@ -107,4 +114,6 @@ LoggerFactory::getDefaultLevel() const
} // namespace nfd
#endif // HAVE_CUSTOM_LOGGER
#endif // NFD_CORE_LOGGER_FACTORY_HPP
+7
View File
@@ -24,6 +24,11 @@
*/
#include "logger.hpp"
#ifdef HAVE_CUSTOM_LOGGER
#error "This file should not be compiled when custom logger is used"
#endif
#include <ndn-cxx/util/time.hpp>
#include <cinttypes>
#include <stdio.h>
@@ -31,6 +36,8 @@
namespace nfd {
std::mutex g_logMutex;
Logger::Logger(const std::string& name, LogLevel level)
: m_moduleName(name)
, m_enabledLogLevel(level)
+22 -19
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.
@@ -28,19 +28,25 @@
#include "common.hpp"
#ifdef HAVE_CUSTOM_LOGGER
#include "custom-logger.hpp"
#else
#include <mutex>
namespace nfd {
/** \brief indicates a log level
* \note This type is internal. Logger should be accessed through NFD_LOG_* macros.
*/
enum LogLevel {
LOG_FATAL = -1, // fatal (will be logged unconditionally)
LOG_NONE = 0, // no messages
LOG_ERROR = 1, // serious error messages
LOG_WARN = 2, // warning messages
LOG_INFO = 3, // informational messages
LOG_DEBUG = 4, // debug messages
LOG_TRACE = 5, // trace messages (most verbose)
// LOG_FATAL is not a level and is logged unconditionally
LOG_ALL = 255 // all messages
};
@@ -57,10 +63,7 @@ public:
bool
isEnabled(LogLevel level) const
{
// std::cerr << m_moduleName <<
// " enabled = " << m_enabledLogLevel
// << " level = " << level << std::endl;
return (m_enabledLogLevel >= level);
return m_enabledLogLevel >= level;
}
void
@@ -127,12 +130,15 @@ nfd::Logger& cls<specialization>::g_logger = nfd::LoggerFactory::create(name)
template<> \
nfd::Logger& cls<s1, s2>::g_logger = nfd::LoggerFactory::create(name)
extern std::mutex g_logMutex;
#define NFD_LOG(level, msg, expression) \
do { \
if (g_logger.isEnabled(::nfd::LOG_##level)) \
if (g_logger.isEnabled(::nfd::LOG_##level)) { \
std::lock_guard<std::mutex> lock(::nfd::g_logMutex); \
std::clog << ::nfd::Logger::now() << " "#msg": " \
<< "[" << g_logger << "] " << expression << "\n"; \
} \
} while (false)
#define NFD_LOG_TRACE(expression) NFD_LOG(TRACE, TRACE, expression)
@@ -140,13 +146,10 @@ do { \
#define NFD_LOG_INFO(expression) NFD_LOG(INFO, INFO, expression)
#define NFD_LOG_WARN(expression) NFD_LOG(WARN, WARNING, expression)
#define NFD_LOG_ERROR(expression) NFD_LOG(ERROR, ERROR, expression)
#define NFD_LOG_FATAL(expression) \
do { \
std::clog << ::nfd::Logger::now() << " FATAL: " \
<< "[" << g_logger << "] " << expression << "\n"; \
} while (false)
#define NFD_LOG_FATAL(expression) NFD_LOG(FATAL, FATAL, expression)
} // namespace nfd
#endif // HAVE_CUSTOM_LOGGER
#endif // NFD_CORE_LOGGER_HPP
+5 -3
View File
@@ -131,7 +131,9 @@ PrivilegeHelper::initialize(const std::string& userName, const std::string& grou
s_normalUid = passwd.pw_uid;
}
#else
throw Error("Dropping and raising privileges is not supported on this platform");
if (!userName.empty() || !groupName.empty()) {
throw Error("Dropping and raising privileges is not supported on this platform");
}
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
}
@@ -159,7 +161,7 @@ PrivilegeHelper::drop()
NFD_LOG_INFO("dropped to effective uid=" << ::geteuid() << " gid=" << ::getegid());
#else
throw Error("Dropping privileges is not supported on this platform");
NFD_LOG_WARN("Dropping privileges is not supported on this platform");
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
}
@@ -186,7 +188,7 @@ PrivilegeHelper::raise()
}
NFD_LOG_INFO("elevated to effective uid=" << ::geteuid() << " gid=" << ::getegid());
#else
throw Error("Elevating privileges is not supported on this platform");
NFD_LOG_WARN("Elevating privileges is not supported on this platform");
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
}
+1 -1
View File
@@ -71,7 +71,7 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
static void
raise();
private:
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
static uid_t s_normalUid;
static gid_t s_normalGid;
+19 -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.
@@ -24,15 +24,25 @@
*/
#include "random.hpp"
#include <boost/thread/tss.hpp>
namespace nfd {
static boost::random::mt19937 g_rng;
static boost::thread_specific_ptr<boost::random::mt19937> g_rng;
boost::random::mt19937&
getGlobalRng()
{
return g_rng;
if (g_rng.get() == nullptr) {
g_rng.reset(new boost::random::mt19937());
}
return *g_rng;
}
void
resetGlobalRng()
{
g_rng.reset();
}
} // namespace nfd
+14 -11
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,17 +26,20 @@
#include "scheduler.hpp"
#include "global-io.hpp"
#include <boost/thread/tss.hpp>
namespace nfd {
namespace scheduler {
static shared_ptr<Scheduler> g_scheduler;
static boost::thread_specific_ptr<Scheduler> g_scheduler;
inline Scheduler&
Scheduler&
getGlobalScheduler()
{
if (!static_cast<bool>(g_scheduler)) {
g_scheduler = make_shared<Scheduler>(ref(getGlobalIoService()));
if (g_scheduler.get() == nullptr) {
g_scheduler.reset(new Scheduler(getGlobalIoService()));
}
return *g_scheduler;
}
+3 -1
View File
@@ -25,10 +25,12 @@
#ifndef NFD_DAEMON_FACE_CHANNEL_HPP
#define NFD_DAEMON_FACE_CHANNEL_HPP
#include "face.hpp"
#include "common.hpp"
namespace nfd {
class Face;
class Channel : noncopyable
{
public:
+72 -87
View File
@@ -28,14 +28,13 @@
#include "face.hpp"
#include "core/global-io.hpp"
#include "core/logger.hpp"
namespace nfd {
class Unicast {};
class Multicast {};
struct Unicast {};
struct Multicast {};
template<class Protocol, class Type = Unicast>
template<class Protocol, class Addressing = Unicast>
class DatagramFace : public Face
{
public:
@@ -44,14 +43,9 @@ public:
/** \brief Construct datagram face
*
* \param socket Protocol-specific socket for the created face
* \param isOnDemand If true, the face can be closed after it remains
* unused for a certain amount of time
*/
DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
const shared_ptr<typename protocol::socket>& socket,
bool isOnDemand);
~DatagramFace() DECL_OVERRIDE;
typename protocol::socket socket);
// from Face
void
@@ -68,18 +62,6 @@ public:
size_t nBytesReceived,
const boost::system::error_code& error);
/**
* \brief Set m_hasBeenUsedRecently to false
*/
void
resetRecentUsage();
bool
hasBeenUsedRecently() const;
void
setOnDemand(bool isOnDemand);
protected:
void
processErrorCode(const boost::system::error_code& error);
@@ -99,97 +81,108 @@ protected:
void
closeSocket();
bool
hasBeenUsedRecently() const;
/**
* \brief Set m_hasBeenUsedRecently to false
*/
void
resetRecentUsage();
protected:
shared_ptr<typename protocol::socket> m_socket;
uint8_t m_inputBuffer[ndn::MAX_NDN_PACKET_SIZE];
bool m_hasBeenUsedRecently;
typename protocol::socket m_socket;
NFD_LOG_INCLASS_DECLARE();
private:
uint8_t m_inputBuffer[ndn::MAX_NDN_PACKET_SIZE];
bool m_hasBeenUsedRecently;
};
template<class T, class U>
inline
DatagramFace<T, U>::DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
const shared_ptr<typename DatagramFace::protocol::socket>& socket,
bool isOnDemand)
: Face(remoteUri, localUri)
, m_socket(socket)
typename DatagramFace::protocol::socket socket)
: Face(remoteUri, localUri, false, std::is_same<U, Multicast>::value)
, m_socket(std::move(socket))
{
setOnDemand(isOnDemand);
NFD_LOG_FACE_INFO("Creating face");
m_socket->async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE), 0,
bind(&DatagramFace<T, U>::handleReceive, this, _1, _2));
}
template<class T, class U>
inline
DatagramFace<T, U>::~DatagramFace()
{
m_socket.async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
bind(&DatagramFace<T, U>::handleReceive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
template<class T, class U>
inline void
DatagramFace<T, U>::sendInterest(const Interest& interest)
{
this->emitSignal(onSendInterest, interest);
const Block& payload = interest.wireEncode();
m_socket->async_send(boost::asio::buffer(payload.wire(), payload.size()),
bind(&DatagramFace<T, U>::handleSend, this, _1, _2, payload));
NFD_LOG_FACE_TRACE(__func__);
// anything else should be done here?
this->emitSignal(onSendInterest, interest);
const Block& payload = interest.wireEncode();
m_socket.async_send(boost::asio::buffer(payload.wire(), payload.size()),
bind(&DatagramFace<T, U>::handleSend, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred,
payload));
}
template<class T, class U>
inline void
DatagramFace<T, U>::sendData(const Data& data)
{
this->emitSignal(onSendData, data);
const Block& payload = data.wireEncode();
m_socket->async_send(boost::asio::buffer(payload.wire(), payload.size()),
bind(&DatagramFace<T, U>::handleSend, this, _1, _2, payload));
NFD_LOG_FACE_TRACE(__func__);
// anything else should be done here?
this->emitSignal(onSendData, data);
const Block& payload = data.wireEncode();
m_socket.async_send(boost::asio::buffer(payload.wire(), payload.size()),
bind(&DatagramFace<T, U>::handleSend, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred,
payload));
}
template<class T, class U>
inline void
DatagramFace<T, U>::close()
{
if (!m_socket->is_open())
if (!m_socket.is_open())
return;
NFD_LOG_INFO("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
<< "] Closing face");
NFD_LOG_FACE_INFO("Closing face");
closeSocket();
fail("Face closed");
this->fail("Face closed");
}
template<class T, class U>
inline void
DatagramFace<T, U>::processErrorCode(const boost::system::error_code& error)
{
if (error == boost::asio::error::operation_aborted) // when socket is closed by someone
if (error == boost::asio::error::operation_aborted) // when cancel() is called
return;
// this should be unnecessary, but just in case
if (!m_socket->is_open()) {
if (!m_socket.is_open()) {
this->fail("Tunnel closed");
return;
}
if (error != boost::asio::error::eof)
NFD_LOG_WARN("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
<< "] Send or receive operation failed, closing face: "
<< error.message());
NFD_LOG_FACE_WARN("Send or receive operation failed: " << error.message());
closeSocket();
if (error == boost::asio::error::eof)
this->fail("Tunnel closed");
else
this->fail("Send or receive operation failed: " + error.message());
this->fail(error.message());
}
template<class T, class U>
@@ -202,8 +195,7 @@ DatagramFace<T, U>::handleSend(const boost::system::error_code& error,
if (error)
return processErrorCode(error);
NFD_LOG_TRACE("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
<< "] Successfully sent: " << nBytesSent << " bytes");
NFD_LOG_FACE_TRACE("Successfully sent: " << nBytesSent << " bytes");
this->getMutableCounters().getNOutBytes() += nBytesSent;
}
@@ -214,9 +206,11 @@ DatagramFace<T, U>::handleReceive(const boost::system::error_code& error,
{
receiveDatagram(m_inputBuffer, nBytesReceived, error);
if (m_socket->is_open())
m_socket->async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE), 0,
bind(&DatagramFace<T, U>::handleReceive, this, _1, _2));
if (m_socket.is_open())
m_socket.async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
bind(&DatagramFace<T, U>::handleReceive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
template<class T, class U>
@@ -225,37 +219,32 @@ DatagramFace<T, U>::receiveDatagram(const uint8_t* buffer,
size_t nBytesReceived,
const boost::system::error_code& error)
{
if (error || nBytesReceived == 0)
if (error)
return processErrorCode(error);
NFD_LOG_TRACE("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
<< "] Received: " << nBytesReceived << " bytes");
NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes");
this->getMutableCounters().getNInBytes() += nBytesReceived;
bool isOk = false;
Block element;
bool isOk = Block::fromBuffer(buffer, nBytesReceived, element);
std::tie(isOk, element) = Block::fromBuffer(buffer, nBytesReceived);
if (!isOk)
{
NFD_LOG_WARN("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
<< "] Failed to parse incoming packet");
NFD_LOG_FACE_WARN("Failed to parse incoming packet");
// This message won't extend the face lifetime
return;
}
if (element.size() != nBytesReceived)
{
NFD_LOG_WARN("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
<< "] Received datagram size and decoded "
<< "element size don't match");
NFD_LOG_FACE_WARN("Received datagram size and decoded element size don't match");
// This message won't extend the face lifetime
return;
}
if (!this->decodeAndDispatchInput(element))
{
NFD_LOG_WARN("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
<< "] Received unrecognized block of type ["
<< element.type() << "]");
NFD_LOG_FACE_WARN("Received unrecognized TLV block of type " << element.type());
// This message won't extend the face lifetime
return;
}
@@ -267,16 +256,19 @@ template<class T, class U>
inline void
DatagramFace<T, U>::keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face)
{
NFD_LOG_FACE_TRACE(__func__);
}
template<class T, class U>
inline void
DatagramFace<T, U>::closeSocket()
{
NFD_LOG_FACE_TRACE(__func__);
// use the non-throwing variants and ignore errors, if any
boost::system::error_code error;
m_socket->shutdown(protocol::socket::shutdown_both, error);
m_socket->close(error);
m_socket.shutdown(protocol::socket::shutdown_both, error);
m_socket.close(error);
// after this, handlers will be called with an error code
// ensure that the Face object is alive at least until all pending
@@ -286,10 +278,10 @@ DatagramFace<T, U>::closeSocket()
}
template<class T, class U>
inline void
DatagramFace<T, U>::setOnDemand(bool isOnDemand)
inline bool
DatagramFace<T, U>::hasBeenUsedRecently() const
{
Face::setOnDemand(isOnDemand);
return m_hasBeenUsedRecently;
}
template<class T, class U>
@@ -299,13 +291,6 @@ DatagramFace<T, U>::resetRecentUsage()
m_hasBeenUsedRecently = false;
}
template<class T, class U>
inline bool
DatagramFace<T, U>::hasBeenUsedRecently() const
{
return m_hasBeenUsedRecently;
}
} // namespace nfd
#endif // NFD_DAEMON_FACE_DATAGRAM_FACE_HPP
+80 -97
View File
@@ -25,13 +25,12 @@
#include "ethernet-face.hpp"
#include "core/global-io.hpp"
#include "core/logger.hpp"
#include <pcap/pcap.h>
#include <cerrno> // for errno
#include <cstdio> // for std::snprintf()
#include <cstring> // for std::strerror() and std::strncpy()
#include <stdio.h> // for snprintf()
#include <arpa/inet.h> // for htons() and ntohs()
#include <net/ethernet.h> // for struct ether_header
#include <net/if.h> // for struct ifreq
@@ -63,12 +62,12 @@ NFD_LOG_INIT("EthernetFace");
const time::nanoseconds EthernetFace::REASSEMBLER_LIFETIME = time::seconds(60);
EthernetFace::EthernetFace(const shared_ptr<boost::asio::posix::stream_descriptor>& socket,
EthernetFace::EthernetFace(boost::asio::posix::stream_descriptor socket,
const NetworkInterfaceInfo& interface,
const ethernet::Address& address)
: Face(FaceUri(address), FaceUri::fromDev(interface.name))
: Face(FaceUri(address), FaceUri::fromDev(interface.name), false, true)
, m_pcap(nullptr, pcap_close)
, m_socket(socket)
, m_socket(std::move(socket))
#if defined(__linux__)
, m_interfaceIndex(interface.index)
#endif
@@ -79,8 +78,7 @@ EthernetFace::EthernetFace(const shared_ptr<boost::asio::posix::stream_descripto
, m_nDropped(0)
#endif
{
NFD_LOG_INFO("Creating ethernet face on " << m_interfaceName << ": "
<< m_srcAddress << " <--> " << m_destAddress);
NFD_LOG_FACE_INFO("Creating face on " << m_interfaceName << "/" << m_srcAddress);
pcapInit();
int fd = pcap_get_selectable_fd(m_pcap.get());
@@ -90,43 +88,42 @@ EthernetFace::EthernetFace(const shared_ptr<boost::asio::posix::stream_descripto
// need to duplicate the fd, otherwise both pcap_close()
// and stream_descriptor::close() will try to close the
// same fd and one of them will fail
m_socket->assign(::dup(fd));
m_socket.assign(::dup(fd));
m_interfaceMtu = getInterfaceMtu();
NFD_LOG_DEBUG("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] Interface MTU is: " << m_interfaceMtu);
NFD_LOG_FACE_DEBUG("Interface MTU is: " << m_interfaceMtu);
m_slicer.reset(new ndnlp::Slicer(m_interfaceMtu));
char filter[100];
std::snprintf(filter, sizeof(filter),
"(ether proto 0x%x) && (ether dst %s) && (not ether src %s)",
ethernet::ETHERTYPE_NDN,
m_destAddress.toString().c_str(),
m_srcAddress.toString().c_str());
// std::snprintf not found in some environments
// http://redmine.named-data.net/issues/2299 for more information
snprintf(filter, sizeof(filter),
"(ether proto 0x%x) && (ether dst %s) && (not ether src %s)",
ethernet::ETHERTYPE_NDN,
m_destAddress.toString().c_str(),
m_srcAddress.toString().c_str());
setPacketFilter(filter);
if (!m_destAddress.isBroadcast() && !joinMulticastGroup())
{
NFD_LOG_WARN("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] Falling back to promiscuous mode");
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,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
EthernetFace::~EthernetFace()
{
m_socket.async_read_some(boost::asio::null_buffers(),
bind(&EthernetFace::handleRead, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void
EthernetFace::sendInterest(const Interest& interest)
{
NFD_LOG_FACE_TRACE(__func__);
this->emitSignal(onSendInterest, interest);
ndnlp::PacketArray pa = m_slicer->slice(interest.wireEncode());
for (const auto& packet : *pa) {
sendPacket(packet);
@@ -136,7 +133,10 @@ EthernetFace::sendInterest(const Interest& interest)
void
EthernetFace::sendData(const Data& data)
{
NFD_LOG_FACE_TRACE(__func__);
this->emitSignal(onSendData, data);
ndnlp::PacketArray pa = m_slicer->slice(data.wireEncode());
for (const auto& packet : *pa) {
sendPacket(packet);
@@ -149,13 +149,12 @@ EthernetFace::close()
if (!m_pcap)
return;
NFD_LOG_INFO("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] Closing face");
NFD_LOG_FACE_INFO("Closing face");
boost::system::error_code error;
m_socket->cancel(error); // ignore errors
m_socket->close(error); // ignore errors
m_pcap.reset(nullptr);
m_socket.cancel(error); // ignore errors
m_socket.close(error); // ignore errors
m_pcap.reset();
fail("Face closed");
}
@@ -184,8 +183,7 @@ EthernetFace::pcapInit()
if (pcap_setdirection(m_pcap.get(), PCAP_D_IN) < 0)
// no need to throw on failure, BPF will filter unwanted packets anyway
NFD_LOG_WARN("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] pcap_setdirection failed: " << pcap_geterr(m_pcap.get()));
NFD_LOG_FACE_WARN("pcap_setdirection failed: " << pcap_geterr(m_pcap.get()));
}
void
@@ -211,12 +209,11 @@ EthernetFace::joinMulticastGroup()
mr.mr_alen = m_destAddress.size();
std::copy(m_destAddress.begin(), m_destAddress.end(), mr.mr_address);
if (::setsockopt(m_socket->native_handle(), SOL_PACKET,
if (::setsockopt(m_socket.native_handle(), SOL_PACKET,
PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == 0)
return true; // success
NFD_LOG_WARN("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] setsockopt(PACKET_ADD_MEMBERSHIP) failed: " << std::strerror(errno));
NFD_LOG_FACE_WARN("setsockopt(PACKET_ADD_MEMBERSHIP) failed: " << std::strerror(errno));
#endif
#if defined(SIOCADDMULTI)
@@ -250,7 +247,7 @@ EthernetFace::joinMulticastGroup()
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");
#else
int fd = m_socket->native_handle();
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);
@@ -262,8 +259,7 @@ EthernetFace::joinMulticastGroup()
if (::ioctl(fd, SIOCADDMULTI, &ifr) == 0)
return true; // success
NFD_LOG_WARN("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] ioctl(SIOCADDMULTI) failed: " << std::strerror(errno));
NFD_LOG_FACE_WARN("ioctl(SIOCADDMULTI) failed: " << std::strerror(errno));
#endif
return false;
@@ -274,8 +270,7 @@ EthernetFace::sendPacket(const ndn::Block& block)
{
if (!m_pcap)
{
NFD_LOG_WARN("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] Trying to send on closed face");
NFD_LOG_FACE_WARN("Trying to send on closed face");
return fail("Face closed");
}
@@ -309,8 +304,7 @@ EthernetFace::sendPacket(const ndn::Block& block)
return fail("Failed to inject frame");
}
NFD_LOG_TRACE("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] Successfully sent: " << block.size() << " bytes");
NFD_LOG_FACE_TRACE("Successfully sent: " << block.size() << " bytes");
this->getMutableCounters().getNOutBytes() += block.size();
}
@@ -332,7 +326,7 @@ EthernetFace::handleRead(const boost::system::error_code& error, size_t)
}
else if (ret == 0)
{
NFD_LOG_WARN("[id:" << getId() << ",endpoint:" << m_interfaceName << "] Read timeout");
NFD_LOG_FACE_WARN("Read timeout");
}
else
{
@@ -344,34 +338,30 @@ EthernetFace::handleRead(const boost::system::error_code& error, size_t)
ret = pcap_stats(m_pcap.get(), &ps);
if (ret < 0)
{
NFD_LOG_DEBUG("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] pcap_stats failed: " << pcap_geterr(m_pcap.get()));
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_DEBUG("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] Detected " << ps.ps_drop - m_nDropped << " dropped packet(s)");
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,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
m_socket.async_read_some(boost::asio::null_buffers(),
bind(&EthernetFace::handleRead, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void
EthernetFace::processIncomingPacket(const pcap_pkthdr* header, const uint8_t* packet)
{
size_t length = header->caplen;
if (length < ethernet::HDR_LEN + ethernet::MIN_DATA_LEN)
{
NFD_LOG_WARN("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] Received frame is too short (" << length << " bytes)");
return;
}
if (length < ethernet::HDR_LEN + ethernet::MIN_DATA_LEN) {
NFD_LOG_FACE_WARN("Received frame is too short (" << length << " bytes)");
return;
}
const ether_header* eh = reinterpret_cast<const ether_header*>(packet);
const ethernet::Address sourceAddress(eh->ether_shost);
@@ -388,36 +378,31 @@ EthernetFace::processIncomingPacket(const pcap_pkthdr* header, const uint8_t* pa
length -= ethernet::HDR_LEN;
/// \todo Reserve space in front and at the back of the underlying buffer
Block fragment;
bool isOk = Block::fromBuffer(packet, length, fragment);
if (!isOk)
{
NFD_LOG_WARN("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] Block received from " << sourceAddress.toString()
<< " is invalid or too large to process");
return;
}
bool isOk = false;
Block fragmentBlock;
std::tie(isOk, fragmentBlock) = Block::fromBuffer(packet, length);
if (!isOk) {
NFD_LOG_FACE_WARN("Block received from " << sourceAddress.toString()
<< " is invalid or too large to process");
return;
}
NFD_LOG_TRACE("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] Received: " << fragment.size() << " bytes from "
<< sourceAddress.toString());
this->getMutableCounters().getNInBytes() += fragment.size();
NFD_LOG_FACE_TRACE("Received: " << fragmentBlock.size() << " bytes from "
<< sourceAddress.toString());
this->getMutableCounters().getNInBytes() += fragmentBlock.size();
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_TRACE("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] All fragments received from " << sourceAddress.toString());
if (!decodeAndDispatchInput(block))
NFD_LOG_WARN("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] Received unrecognized TLV block of type " << block.type()
<< " from " << sourceAddress.toString());
});
}
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,
@@ -425,14 +410,14 @@ EthernetFace::processIncomingPacket(const pcap_pkthdr* header, const uint8_t* pa
BOOST_VERIFY(m_reassemblers.erase(sourceAddress) == 1);
});
try {
reassembler.pms->receiveNdnlpData(fragment);
}
catch (const ndnlp::ParseError& e) {
NFD_LOG_WARN("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] Received invalid NDNLP fragment from "
<< sourceAddress.toString() << " : " << e.what());
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);
}
void
@@ -446,18 +431,17 @@ EthernetFace::processErrorCode(const boost::system::error_code& error)
if (error == boost::asio::error::eof)
{
msg = "Face closed";
NFD_LOG_DEBUG("[id:" << getId() << ",endpoint:" << m_interfaceName << "] " << msg);
}
else
{
msg = "Receive operation failed: " + error.message();
NFD_LOG_WARN("[id:" << getId() << ",endpoint:" << m_interfaceName << "] " << msg);
NFD_LOG_FACE_WARN(msg);
}
fail(msg);
}
size_t
EthernetFace::getInterfaceMtu() const
EthernetFace::getInterfaceMtu()
{
#ifdef SIOCGIFMTU
#if defined(__APPLE__) || defined(__FreeBSD__)
@@ -466,7 +450,7 @@ EthernetFace::getInterfaceMtu() const
udp::socket sock(ref(getGlobalIoService()), udp::v4());
int fd = sock.native_handle();
#else
int fd = m_socket->native_handle();
int fd = m_socket.native_handle();
#endif
ifreq ifr{};
@@ -475,8 +459,7 @@ EthernetFace::getInterfaceMtu() const
if (::ioctl(fd, SIOCGIFMTU, &ifr) == 0)
return static_cast<size_t>(ifr.ifr_mtu);
NFD_LOG_WARN("[id:" << getId() << ",endpoint:" << m_interfaceName
<< "] Failed to get interface MTU: " << std::strerror(errno));
NFD_LOG_FACE_WARN("Failed to get interface MTU: " << std::strerror(errno));
#endif
return ethernet::MAX_DATA_LEN;
+3 -5
View File
@@ -60,12 +60,10 @@ public:
Error(const std::string& what) : Face::Error(what) {}
};
EthernetFace(const shared_ptr<boost::asio::posix::stream_descriptor>& socket,
EthernetFace(boost::asio::posix::stream_descriptor socket,
const NetworkInterfaceInfo& interface,
const ethernet::Address& address);
~EthernetFace() DECL_OVERRIDE;
/// send an Interest
void
sendInterest(const Interest& interest) DECL_OVERRIDE;
@@ -138,7 +136,7 @@ private:
* @brief Returns the MTU of the underlying network interface
*/
size_t
getInterfaceMtu() const;
getInterfaceMtu();
private:
struct Reassembler
@@ -148,7 +146,7 @@ private:
};
unique_ptr<pcap_t, void(*)(pcap_t*)> m_pcap;
shared_ptr<boost::asio::posix::stream_descriptor> m_socket;
boost::asio::posix::stream_descriptor m_socket;
#if defined(__linux__)
int m_interfaceIndex;
+2 -4
View File
@@ -31,8 +31,6 @@
namespace nfd {
NFD_LOG_INIT("EthernetFactory");
shared_ptr<EthernetFace>
EthernetFactory::createMulticastFace(const NetworkInterfaceInfo& interface,
const ethernet::Address &address)
@@ -44,8 +42,8 @@ EthernetFactory::createMulticastFace(const NetworkInterfaceInfo& interface,
if (face)
return face;
auto socket = make_shared<boost::asio::posix::stream_descriptor>(ref(getGlobalIoService()));
face = make_shared<EthernetFace>(socket, interface, address);
face = make_shared<EthernetFace>(boost::asio::posix::stream_descriptor(getGlobalIoService()),
interface, address);
auto key = std::make_pair(interface.name, address);
face->onFail.connectSingleShot([this, key] (const std::string& reason) {
+15 -51
View File
@@ -25,14 +25,17 @@
#include "face.hpp"
#include <ndn-cxx/management/nfd-face-event-notification.hpp>
namespace nfd {
Face::Face(const FaceUri& remoteUri, const FaceUri& localUri, bool isLocal)
Face::Face(const FaceUri& remoteUri, const FaceUri& localUri, bool isLocal, bool isMultiAccess)
: m_id(INVALID_FACEID)
, m_isLocal(isLocal)
, m_remoteUri(remoteUri)
, m_localUri(localUri)
, m_isLocal(isLocal)
, m_isOnDemand(false)
, m_isMultiAccess(isMultiAccess)
, m_isFailed(false)
{
onReceiveInterest.connect([this] (const ndn::Interest&) { ++m_counters.getNInInterests(); });
@@ -45,37 +48,6 @@ Face::~Face()
{
}
FaceId
Face::getId() const
{
return m_id;
}
// this method is private and should be used only by the FaceTable
void
Face::setId(FaceId faceId)
{
m_id = faceId;
}
void
Face::setDescription(const std::string& description)
{
m_description = description;
}
const std::string&
Face::getDescription() const
{
return m_description;
}
bool
Face::isMultiAccess() const
{
return false;
}
bool
Face::isUp() const
{
@@ -126,22 +98,14 @@ void
Face::copyStatusTo(FaceTraits& traits) const
{
traits.setFaceId(getId())
.setRemoteUri(getRemoteUri().toString())
.setLocalUri(getLocalUri().toString());
if (isLocal()) {
traits.setFaceScope(ndn::nfd::FACE_SCOPE_LOCAL);
}
else {
traits.setFaceScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
}
if (isOnDemand()) {
traits.setFacePersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
}
else {
traits.setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
}
.setRemoteUri(getRemoteUri().toString())
.setLocalUri(getLocalUri().toString())
.setFaceScope(isLocal() ? ndn::nfd::FACE_SCOPE_LOCAL
: ndn::nfd::FACE_SCOPE_NON_LOCAL)
.setFacePersistency(isOnDemand() ? ndn::nfd::FACE_PERSISTENCY_ON_DEMAND
: ndn::nfd::FACE_PERSISTENCY_PERSISTENT)
.setLinkType(isMultiAccess() ? ndn::nfd::LINK_TYPE_MULTI_ACCESS
: ndn::nfd::LINK_TYPE_POINT_TO_POINT);
}
template void
@@ -154,11 +118,11 @@ ndn::nfd::FaceStatus
Face::getFaceStatus() const
{
ndn::nfd::FaceStatus status;
copyStatusTo(status);
copyStatusTo(status);
this->getCounters().copyTo(status);
return status;
}
} //namespace nfd
} // namespace nfd
+105 -42
View File
@@ -27,11 +27,10 @@
#define NFD_DAEMON_FACE_FACE_HPP
#include "common.hpp"
#include "core/logger.hpp"
#include "face-counters.hpp"
#include <ndn-cxx/util/face-uri.hpp>
#include <ndn-cxx/management/nfd-face-status.hpp>
#include <ndn-cxx/management/nfd-face-event-notification.hpp>
namespace nfd {
@@ -52,7 +51,6 @@ const FaceId FACEID_NULL = 255;
/// upper bound of reserved FaceIds
const FaceId FACEID_RESERVED_MAX = 255;
using ndn::util::FaceUri;
/** \brief represents a face
*/
@@ -72,7 +70,8 @@ public:
}
};
Face(const FaceUri& remoteUri, const FaceUri& localUri, bool isLocal = false);
Face(const FaceUri& remoteUri, const FaceUri& localUri,
bool isLocal = false, bool isMultiAccess = false);
virtual
~Face();
@@ -112,27 +111,31 @@ public: // attributes
FaceId
getId() const;
/** \brief Set the description
*
* This is typically invoked by mgmt on set description command
/** \brief Get the description
*/
virtual void
setDescription(const std::string& description);
/// Get the description
virtual const std::string&
const std::string&
getDescription() const;
/** \brief Set the face description
*
* This is typically invoked by management on set description command
*/
void
setDescription(const std::string& description);
/** \brief Get whether face is connected to a local app
*/
bool
isLocal() const;
/** \brief Get whether packets sent this Face may reach multiple peers
*
* In this base class this property is always false.
/** \brief Get whether face is created on demand or explicitly via FaceManagement protocol
*/
virtual bool
bool
isOnDemand() const;
/** \brief Get whether packets sent by this face may reach multiple peers
*/
bool
isMultiAccess() const;
/** \brief Get whether underlying communication is up
@@ -142,11 +145,6 @@ public: // attributes
virtual bool
isUp() const;
/** \brief Get whether face is created on demand or explicitly via FaceManagement protocol
*/
bool
isOnDemand() const;
const FaceCounters&
getCounters() const;
@@ -171,51 +169,95 @@ public: // attributes
virtual ndn::nfd::FaceStatus
getFaceStatus() const;
protected:
// this is a non-virtual method
bool
decodeAndDispatchInput(const Block& element);
FaceCounters&
getMutableCounters();
PUBLIC_WITH_TESTS_ELSE_PROTECTED:
void
setOnDemand(bool isOnDemand);
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(onSendInterest)
DECLARE_SIGNAL_EMIT(onSendData)
private:
// this method should be used only by the FaceTable
void
setId(FaceId faceId);
private:
FaceId m_id;
std::string m_description;
bool m_isLocal; // for scoping purposes
FaceCounters m_counters;
FaceUri m_remoteUri;
FaceUri m_localUri;
const FaceUri m_remoteUri;
const FaceUri m_localUri;
const bool m_isLocal;
bool m_isOnDemand;
const bool m_isMultiAccess;
bool m_isFailed;
// allow setting FaceId
friend class FaceTable;
};
inline FaceId
Face::getId() const
{
return m_id;
}
inline void
Face::setId(FaceId faceId)
{
m_id = faceId;
}
inline const std::string&
Face::getDescription() const
{
return m_description;
}
inline void
Face::setDescription(const std::string& description)
{
m_description = description;
}
inline bool
Face::isLocal() const
{
return m_isLocal;
}
inline bool
Face::isOnDemand() const
{
return m_isOnDemand;
}
inline void
Face::setOnDemand(bool isOnDemand)
{
m_isOnDemand = isOnDemand;
}
inline bool
Face::isMultiAccess() const
{
return m_isMultiAccess;
}
inline const FaceCounters&
Face::getCounters() const
{
@@ -240,17 +282,38 @@ Face::getLocalUri() const
return m_localUri;
}
inline void
Face::setOnDemand(bool isOnDemand)
{
m_isOnDemand = isOnDemand;
}
inline bool
Face::isOnDemand() const
{
return m_isOnDemand;
}
/** \defgroup FaceLogging Face logging macros
*
* These macros augment the log message with some face-specific information,
* such as the face ID, that are useful to distinguish which face produced the
* message. It is strongly recommended to use these macros instead of the
* generic ones for all logging inside Face subclasses.
* @{
*/
#define NFD_LOG_FACE(level, msg) \
NFD_LOG_##level("[id=" << this->getId() << \
",local=" << this->getLocalUri() << \
",remote=" << this->getRemoteUri() << \
"] " << msg)
/** \brief Log a message at TRACE level */
#define NFD_LOG_FACE_TRACE(msg) NFD_LOG_FACE(TRACE, msg)
/** \brief Log a message at DEBUG level */
#define NFD_LOG_FACE_DEBUG(msg) NFD_LOG_FACE(DEBUG, msg)
/** \brief Log a message at INFO level */
#define NFD_LOG_FACE_INFO(msg) NFD_LOG_FACE(INFO, msg)
/** \brief Log a message at WARN level */
#define NFD_LOG_FACE_WARN(msg) NFD_LOG_FACE(WARN, msg)
/** \brief Log a message at ERROR level */
#define NFD_LOG_FACE_ERROR(msg) NFD_LOG_FACE(ERROR, msg)
/** @} */
} // namespace nfd
+15 -8
View File
@@ -152,9 +152,11 @@ LocalFace::decodeAndDispatchInput(const Block& element)
i->wireDecode(payload);
if (&payload != &element)
{
i->getLocalControlHeader().wireDecode(element,
false,
this->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID));
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);
@@ -193,17 +195,22 @@ LocalFace::isEmptyFilteredLocalControlHeader(const ndn::nfd::LocalControlHeader&
if (!this->isLocalControlHeaderEnabled())
return true;
return header.empty(this->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID),
false);
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)
{
return packet.getLocalControlHeader().wireEncode(packet,
this->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID),
false);
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
+17 -27
View File
@@ -31,17 +31,13 @@ NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(DatagramFace,
MulticastUdpFace::protocol, Multicast,
"MulticastUdpFace");
MulticastUdpFace::MulticastUdpFace(const shared_ptr<MulticastUdpFace::protocol::socket>& recvSocket,
const shared_ptr<MulticastUdpFace::protocol::socket>& sendSocket,
const MulticastUdpFace::protocol::endpoint& localEndpoint,
const MulticastUdpFace::protocol::endpoint& multicastEndpoint)
: DatagramFace<protocol, Multicast>(FaceUri(multicastEndpoint),
FaceUri(localEndpoint),
recvSocket, false)
, m_multicastGroup(multicastEndpoint)
, m_sendSocket(sendSocket)
MulticastUdpFace::MulticastUdpFace(const protocol::endpoint& multicastGroup,
const FaceUri& localUri,
protocol::socket recvSocket, protocol::socket sendSocket)
: DatagramFace(FaceUri(multicastGroup), localUri, std::move(recvSocket))
, m_multicastGroup(multicastGroup)
, m_sendSocket(std::move(sendSocket))
{
NFD_LOG_INFO("Creating multicast UDP face for group " << m_multicastGroup);
}
const MulticastUdpFace::protocol::endpoint&
@@ -50,38 +46,32 @@ MulticastUdpFace::getMulticastGroup() const
return m_multicastGroup;
}
void
MulticastUdpFace::sendBlock(const Block& block)
{
m_sendSocket->async_send_to(boost::asio::buffer(block.wire(), block.size()),
m_multicastGroup,
bind(&MulticastUdpFace::handleSend, this, _1, _2, block));
}
void
MulticastUdpFace::sendInterest(const Interest& interest)
{
NFD_LOG_FACE_TRACE(__func__);
this->emitSignal(onSendInterest, interest);
NFD_LOG_DEBUG("Sending interest");
sendBlock(interest.wireEncode());
}
void
MulticastUdpFace::sendData(const Data& data)
{
/// \todo After this method implements duplicate suppression, onSendData signal should
/// be emitted only when data is actually sent out
NFD_LOG_FACE_TRACE(__func__);
/// \todo After this face implements duplicate suppression, onSendData should
/// be emitted only when data is actually sent out. See also #2555
this->emitSignal(onSendData, data);
NFD_LOG_DEBUG("Sending data");
sendBlock(data.wireEncode());
}
bool
MulticastUdpFace::isMultiAccess() const
void
MulticastUdpFace::sendBlock(const Block& block)
{
return true;
m_sendSocket.async_send_to(boost::asio::buffer(block.wire(), block.size()), m_multicastGroup,
bind(&MulticastUdpFace::handleSend, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred,
block));
}
} // namespace nfd
+3 -8
View File
@@ -40,10 +40,8 @@ public:
/**
* \brief Creates a UDP-based face for multicast communication
*/
MulticastUdpFace(const shared_ptr<protocol::socket>& recvSocket,
const shared_ptr<protocol::socket>& sendSocket,
const protocol::endpoint& localEndpoint,
const protocol::endpoint& multicastEndpoint);
MulticastUdpFace(const protocol::endpoint& multicastGroup, const FaceUri& localUri,
protocol::socket recvSocket, protocol::socket sendSocket);
const protocol::endpoint&
getMulticastGroup() const;
@@ -55,16 +53,13 @@ public:
void
sendData(const Data& data) DECL_OVERRIDE;
bool
isMultiAccess() const DECL_OVERRIDE;
private:
void
sendBlock(const Block& block);
private:
protocol::endpoint m_multicastGroup;
shared_ptr<protocol::socket> m_sendSocket;
protocol::socket m_sendSocket;
};
} // namespace nfd
+108
View File
@@ -0,0 +1,108 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ndnlp-data.hpp"
namespace nfd {
namespace ndnlp {
std::tuple<bool, NdnlpData>
NdnlpData::fromBlock(const Block& wire)
{
if (wire.type() != tlv::NdnlpData) {
// top element is not NdnlpData
return std::make_tuple(false, NdnlpData());
}
wire.parse();
const Block::element_container& elements = wire.elements();
if (elements.size() < 2) {
// NdnlpData element has incorrect number of children
return std::make_tuple(false, NdnlpData());
}
NdnlpData parsed;
const Block& sequenceElement = elements.front();
if (sequenceElement.type() != tlv::NdnlpSequence) {
// NdnlpSequence element is missing
return std::make_tuple(false, NdnlpData());
}
if (sequenceElement.value_size() != sizeof(uint64_t)) {
// NdnlpSequence element has incorrect length
return std::make_tuple(false, NdnlpData());
}
parsed.seq = be64toh(*reinterpret_cast<const uint64_t*>(&*sequenceElement.value_begin()));
const Block& payloadElement = elements.back();
if (payloadElement.type() != tlv::NdnlpPayload) {
// NdnlpPayload element is missing
return std::make_tuple(false, NdnlpData());
}
parsed.payload = payloadElement;
if (elements.size() == 2) { // single wire packet
parsed.fragIndex = 0;
parsed.fragCount = 1;
return std::make_tuple(true, parsed);
}
if (elements.size() != 4) {
// NdnlpData element has incorrect number of children
return std::make_tuple(false, NdnlpData());
}
const Block& fragIndexElement = elements.at(1);
if (fragIndexElement.type() != tlv::NdnlpFragIndex) {
// NdnlpFragIndex element is missing
return std::make_tuple(false, NdnlpData());
}
uint64_t fragIndex = ndn::readNonNegativeInteger(fragIndexElement);
if (fragIndex > std::numeric_limits<uint16_t>::max()) {
// NdnlpFragIndex is too large
return std::make_tuple(false, NdnlpData());
}
parsed.fragIndex = static_cast<uint16_t>(fragIndex);
const Block& fragCountElement = elements.at(2);
if (fragCountElement.type() != tlv::NdnlpFragCount) {
// NdnlpFragCount element is missing
return std::make_tuple(false, NdnlpData());
}
uint64_t fragCount = ndn::readNonNegativeInteger(fragCountElement);
if (fragCount > std::numeric_limits<uint16_t>::max()) {
// NdnlpFragCount is too large
return std::make_tuple(false, NdnlpData());
}
parsed.fragCount = static_cast<uint16_t>(fragCount);
if (parsed.fragIndex >= parsed.fragCount) {
// NdnlpFragIndex must be less than NdnlpFragCount
return std::make_tuple(false, NdnlpData());
}
return std::make_tuple(true, parsed);
}
} // namespace ndnlp
} // namespace nfd
@@ -1,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/>.
**/
*/
#ifndef NFD_DAEMON_FACE_NDNLP_PARSE_HPP
#define NFD_DAEMON_FACE_NDNLP_PARSE_HPP
@@ -31,14 +32,6 @@
namespace nfd {
namespace ndnlp {
struct ParseError : public std::runtime_error
{
ParseError(const std::string& what)
: std::runtime_error(what)
{
}
};
/** \brief represents a NdnlpData packet
*
* NdnlpData ::= NDNLP-DATA-TYPE TLV-LENGTH
@@ -51,17 +44,16 @@ class NdnlpData
{
public:
/** \brief parse a NdnlpData packet
*
* \exception ParseError packet is malformated
* \return whether \p wire has a valid NdnlpData packet, and the parsed packet
*/
void
wireDecode(const Block& wire);
static std::tuple<bool, NdnlpData>
fromBlock(const Block& wire);
public:
uint64_t m_seq;
uint16_t m_fragIndex;
uint16_t m_fragCount;
Block m_payload;
uint64_t seq;
uint16_t fragIndex;
uint16_t fragCount;
Block payload;
};
} // namespace ndnlp
-92
View File
@@ -1,92 +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-parse.hpp"
namespace nfd {
namespace ndnlp {
void
NdnlpData::wireDecode(const Block& wire)
{
if (wire.type() != tlv::NdnlpData) {
throw ParseError("top element is not NdnlpData");
}
wire.parse();
const Block::element_container& elements = wire.elements();
if (elements.size() < 2) {
throw ParseError("NdnlpData element has incorrect number of children");
}
const Block& sequenceElement = elements.front();
if (sequenceElement.type() != tlv::NdnlpSequence) {
throw ParseError("NdnlpSequence element is missing");
}
if (sequenceElement.value_size() != sizeof(uint64_t)) {
throw ParseError("NdnlpSequence element has incorrect length");
}
m_seq = be64toh(*reinterpret_cast<const uint64_t*>(&*sequenceElement.value_begin()));
const Block& payloadElement = elements.back();
if (payloadElement.type() != tlv::NdnlpPayload) {
throw ParseError("NdnlpPayload element is missing");
}
m_payload = payloadElement;
if (elements.size() == 2) { // single wire packet
m_fragIndex = 0;
m_fragCount = 1;
return;
}
if (elements.size() != 4) {
throw ParseError("NdnlpData element has incorrect number of children");
}
const Block& fragIndexElement = elements.at(1);
if (fragIndexElement.type() != tlv::NdnlpFragIndex) {
throw ParseError("NdnlpFragIndex element is missing");
}
uint64_t fragIndex = ndn::readNonNegativeInteger(fragIndexElement);
if (fragIndex > std::numeric_limits<uint16_t>::max()) {
throw ParseError("NdnlpFragIndex is too large");
}
m_fragIndex = static_cast<uint16_t>(fragIndex);
const Block& fragCountElement = elements.at(2);
if (fragCountElement.type() != tlv::NdnlpFragCount) {
throw ParseError("NdnlpFragCount element is missing");
}
uint64_t fragCount = ndn::readNonNegativeInteger(fragCountElement);
if (fragCount > std::numeric_limits<uint16_t>::max()) {
throw ParseError("NdnlpFragCount is too large");
}
m_fragCount = static_cast<uint16_t>(fragCount);
if (m_fragIndex >= m_fragCount) {
throw ParseError("NdnlpFragIndex must be less than NdnlpFragCount");
}
}
} // namespace ndnlp
} // namespace nfd
+50 -26
View File
@@ -24,10 +24,13 @@
*/
#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)
@@ -63,21 +66,32 @@ PartialMessage::isComplete() const
return m_received == m_fragCount;
}
Block
std::tuple<bool, Block>
PartialMessage::reassemble()
{
BOOST_ASSERT(this->isComplete());
ndn::BufferPtr buffer = make_shared<ndn::Buffer>(m_totalLength);
uint8_t* buf = buffer->get();
for (std::vector<Block>::const_iterator it = m_payloads.begin();
it != m_payloads.end(); ++it) {
const Block& payload = *it;
memcpy(buf, payload.value(), payload.value_size());
buf += payload.value_size();
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(buffer);
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)
@@ -85,29 +99,38 @@ PartialMessageStore::PartialMessageStore(const time::nanoseconds& idleDuration)
{
}
PartialMessageStore::~PartialMessageStore()
{
}
void
PartialMessageStore::receiveNdnlpData(const Block& pkt)
PartialMessageStore::receive(const NdnlpData& pkt)
{
NdnlpData parsed;
parsed.wireDecode(pkt);
if (parsed.m_fragCount == 1) { // single fragment
this->onReceive(parsed.m_payload.blockFromValue());
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;
}
uint64_t messageIdentifier = parsed.m_seq - parsed.m_fragIndex;
PartialMessage& pm = m_partialMessages[messageIdentifier];
this->scheduleCleanup(messageIdentifier, pm);
pm.add(parsed.m_fragIndex, parsed.m_fragCount, parsed.m_payload);
if (pm.isComplete()) {
this->onReceive(pm.reassemble());
this->cleanup(messageIdentifier);
}
NFD_LOG_TRACE(pkt.seq << " deliver");
this->onReceive(reassembled);
}
void
@@ -121,6 +144,7 @@ PartialMessageStore::scheduleCleanup(uint64_t messageIdentifier,
void
PartialMessageStore::cleanup(uint64_t messageIdentifier)
{
NFD_LOG_TRACE(messageIdentifier << " cleanup");
m_partialMessages.erase(messageIdentifier);
}
+13 -13
View File
@@ -26,7 +26,7 @@
#ifndef NFD_DAEMON_FACE_NDNLP_PARTIAL_MESSAGE_STORE_HPP
#define NFD_DAEMON_FACE_NDNLP_PARTIAL_MESSAGE_STORE_HPP
#include "ndnlp-parse.hpp"
#include "ndnlp-data.hpp"
#include "core/scheduler.hpp"
namespace nfd {
@@ -56,15 +56,19 @@ public:
isComplete() const;
/** \brief reassemble network layer packet
*
* isComplete() must be true before calling this method
*
* \exception ndn::Block::Error packet is malformated
* \return network layer packet
* \pre isComplete() == true
* \return whether success, network layer packet
*/
Block
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;
@@ -83,16 +87,12 @@ public:
explicit
PartialMessageStore(const time::nanoseconds& idleDuration = time::milliseconds(100));
virtual
~PartialMessageStore();
/** \brief receive a NdnlpData packet
*
* \exception ParseError NDNLP packet is malformated
* \exception ndn::Block::Error network layer packet is malformated
* Reassembly errors will be ignored.
*/
void
receiveNdnlpData(const Block& pkt);
receive(const NdnlpData& pkt);
/** \brief fires when network layer packet is received
*/
+3 -3
View File
@@ -26,11 +26,12 @@
#ifndef NFD_DAEMON_FACE_PROTOCOL_FACTORY_HPP
#define NFD_DAEMON_FACE_PROTOCOL_FACTORY_HPP
#include "face.hpp"
#include "common.hpp"
namespace nfd {
class Channel;
class Face;
/**
* \brief Prototype for the callback called when face is created
@@ -69,9 +70,8 @@ public:
const FaceCreatedCallback& onCreated,
const FaceConnectFailedCallback& onConnectFailed) = 0;
virtual std::list<shared_ptr<const Channel> >
virtual std::list<shared_ptr<const Channel>>
getChannels() const = 0;
};
} // namespace nfd
+53 -70
View File
@@ -29,7 +29,6 @@
#include "face.hpp"
#include "local-face.hpp"
#include "core/global-io.hpp"
#include "core/logger.hpp"
namespace nfd {
@@ -42,14 +41,8 @@ class StreamFace : public FaceBase
public:
typedef Protocol protocol;
/**
* \brief Create instance of StreamFace
*/
StreamFace(const FaceUri& remoteUri, const FaceUri& localUri,
const shared_ptr<typename protocol::socket>& socket,
bool isOnDemand);
~StreamFace() DECL_OVERRIDE;
typename protocol::socket socket, bool isOnDemand);
// from FaceBase
void
@@ -83,7 +76,9 @@ protected:
deferredClose(const shared_ptr<Face>& face);
protected:
shared_ptr<typename protocol::socket> m_socket;
typename protocol::socket m_socket;
NFD_LOG_INCLASS_DECLARE();
private:
uint8_t m_inputBuffer[ndn::MAX_NDN_PACKET_SIZE];
@@ -92,8 +87,6 @@ private:
friend struct StreamFaceSenderImpl<Protocol, FaceBase, Interest>;
friend struct StreamFaceSenderImpl<Protocol, FaceBase, Data>;
NFD_LOG_INCLASS_DECLARE();
};
// All inherited classes must use
@@ -111,7 +104,7 @@ template<class Protocol, class U>
struct StreamFaceValidator
{
static void
validateSocket(typename Protocol::socket& socket)
validateSocket(const typename Protocol::socket& socket)
{
}
};
@@ -120,22 +113,20 @@ struct StreamFaceValidator
template<class T, class FaceBase>
inline
StreamFace<T, FaceBase>::StreamFace(const FaceUri& remoteUri, const FaceUri& localUri,
const shared_ptr<typename StreamFace::protocol::socket>& socket,
bool isOnDemand)
typename StreamFace::protocol::socket socket, bool isOnDemand)
: FaceBase(remoteUri, localUri)
, m_socket(socket)
, m_socket(std::move(socket))
, m_inputBufferSize(0)
{
FaceBase::setOnDemand(isOnDemand);
StreamFaceValidator<T, FaceBase>::validateSocket(*socket);
m_socket->async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE), 0,
bind(&StreamFace<T, FaceBase>::handleReceive, this, _1, _2));
}
NFD_LOG_FACE_INFO("Creating face");
template<class T, class U>
inline
StreamFace<T, U>::~StreamFace()
{
this->setOnDemand(isOnDemand);
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));
}
@@ -178,6 +169,7 @@ 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);
}
@@ -186,6 +178,7 @@ 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);
}
@@ -194,11 +187,10 @@ template<class T, class U>
inline void
StreamFace<T, U>::close()
{
if (!m_socket->is_open())
if (!m_socket.is_open())
return;
NFD_LOG_INFO("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
<< "] Closing face");
NFD_LOG_FACE_INFO("Closing face");
shutdownSocket();
this->fail("Face closed");
@@ -212,36 +204,31 @@ StreamFace<T, U>::processErrorCode(const boost::system::error_code& error)
error == boost::asio::error::shut_down) // after shutdown() is called
return;
if (!m_socket->is_open())
if (!m_socket.is_open())
{
this->fail("Connection closed");
return;
}
if (error != boost::asio::error::eof)
NFD_LOG_WARN("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
<< "] Send or receive operation failed, closing face: "
<< error.message());
NFD_LOG_FACE_WARN("Send or receive operation failed: " << error.message());
shutdownSocket();
if (error == boost::asio::error::eof)
{
this->fail("Connection closed");
}
this->fail("Connection closed");
else
{
this->fail("Send or receive operation failed: " + error.message());
}
this->fail(error.message());
}
template<class T, class U>
inline void
StreamFace<T, U>::sendFromQueue()
{
const Block& block = this->m_sendQueue.front();
boost::asio::async_write(*this->m_socket, boost::asio::buffer(block),
bind(&StreamFace<T, U>::handleSend, this, _1, _2));
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>
@@ -254,8 +241,7 @@ StreamFace<T, U>::handleSend(const boost::system::error_code& error,
BOOST_ASSERT(!m_sendQueue.empty());
NFD_LOG_TRACE("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
<< "] Successfully sent: " << nBytesSent << " bytes");
NFD_LOG_FACE_TRACE("Successfully sent: " << nBytesSent << " bytes");
this->getMutableCounters().getNOutBytes() += nBytesSent;
m_sendQueue.pop();
@@ -271,8 +257,7 @@ StreamFace<T, U>::handleReceive(const boost::system::error_code& error,
if (error)
return processErrorCode(error);
NFD_LOG_TRACE("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
<< "] Received: " << nBytesReceived << " bytes");
NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes");
this->getMutableCounters().getNInBytes() += nBytesReceived;
m_inputBufferSize += nBytesReceived;
@@ -281,29 +266,24 @@ StreamFace<T, U>::handleReceive(const boost::system::error_code& error,
bool isOk = true;
Block element;
while (m_inputBufferSize - offset > 0)
{
isOk = Block::fromBuffer(m_inputBuffer + offset, m_inputBufferSize - offset, element);
if (!isOk)
break;
while (m_inputBufferSize - offset > 0) {
std::tie(isOk, element) = Block::fromBuffer(m_inputBuffer + offset, m_inputBufferSize - offset);
if (!isOk)
break;
offset += element.size();
offset += element.size();
BOOST_ASSERT(offset <= m_inputBufferSize);
BOOST_ASSERT(offset <= m_inputBufferSize);
if (!this->decodeAndDispatchInput(element))
{
NFD_LOG_WARN("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
<< "] Received unrecognized block of type ["
<< element.type() << "]");
// ignore unknown packet and proceed
}
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_WARN("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
<< "] Failed to parse incoming packet or packet too large to process, "
<< "closing face");
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;
@@ -323,21 +303,25 @@ StreamFace<T, U>::handleReceive(const boost::system::error_code& error,
}
}
m_socket->async_receive(boost::asio::buffer(m_inputBuffer + m_inputBufferSize,
ndn::MAX_NDN_PACKET_SIZE - m_inputBufferSize), 0,
bind(&StreamFace<T, U>::handleReceive, this, _1, _2));
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);
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
@@ -347,7 +331,7 @@ StreamFace<T, U>::shutdownSocket()
// 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.
// 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
@@ -361,8 +345,7 @@ template<class T, class U>
inline void
StreamFace<T, U>::deferredClose(const shared_ptr<Face>& face)
{
NFD_LOG_DEBUG("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
<< "] Clearing send queue");
NFD_LOG_FACE_TRACE(__func__);
// clear send queue
std::queue<Block> emptyQueue;
@@ -370,7 +353,7 @@ StreamFace<T, U>::deferredClose(const shared_ptr<Face>& face)
// use the non-throwing variant and ignore errors, if any
boost::system::error_code error;
m_socket->close(error);
m_socket.close(error);
}
} // namespace nfd
+84 -146
View File
@@ -24,6 +24,7 @@
*/
#include "tcp-channel.hpp"
#include "tcp-face.hpp"
#include "core/global-io.hpp"
namespace nfd {
@@ -34,13 +35,10 @@ using namespace boost::asio;
TcpChannel::TcpChannel(const tcp::Endpoint& localEndpoint)
: m_localEndpoint(localEndpoint)
, m_isListening(false)
{
this->setUri(FaceUri(localEndpoint));
}
TcpChannel::~TcpChannel()
, m_acceptor(getGlobalIoService())
, m_acceptSocket(getGlobalIoService())
{
setUri(FaceUri(m_localEndpoint));
}
void
@@ -48,24 +46,21 @@ TcpChannel::listen(const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onAcceptFailed,
int backlog/* = tcp::acceptor::max_connections*/)
{
m_acceptor = make_shared<ip::tcp::acceptor>(ref(getGlobalIoService()));
m_acceptor->open(m_localEndpoint.protocol());
m_acceptor->set_option(ip::tcp::acceptor::reuse_address(true));
if (isListening()) {
NFD_LOG_WARN("[" << m_localEndpoint << "] Already listening");
return;
}
m_acceptor.open(m_localEndpoint.protocol());
m_acceptor.set_option(ip::tcp::acceptor::reuse_address(true));
if (m_localEndpoint.address().is_v6())
{
m_acceptor->set_option(ip::v6_only(true));
}
m_acceptor->bind(m_localEndpoint);
m_acceptor->listen(backlog);
m_acceptor.set_option(ip::v6_only(true));
shared_ptr<ip::tcp::socket> clientSocket =
make_shared<ip::tcp::socket>(ref(getGlobalIoService()));
m_acceptor->async_accept(*clientSocket,
bind(&TcpChannel::handleSuccessfulAccept, this, _1,
clientSocket,
onFaceCreated, onAcceptFailed));
m_acceptor.bind(m_localEndpoint);
m_acceptor.listen(backlog);
m_isListening = true;
// start accepting connections
accept(onFaceCreated, onAcceptFailed);
}
void
@@ -74,47 +69,24 @@ TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
const TcpChannel::ConnectFailedCallback& onConnectFailed,
const time::seconds& timeout/* = time::seconds(4)*/)
{
ChannelFaceMap::iterator i = m_channelFaces.find(remoteEndpoint);
if (i != m_channelFaces.end()) {
onFaceCreated(i->second);
auto it = m_channelFaces.find(remoteEndpoint);
if (it != m_channelFaces.end()) {
onFaceCreated(it->second);
return;
}
shared_ptr<ip::tcp::socket> clientSocket =
make_shared<ip::tcp::socket>(ref(getGlobalIoService()));
auto clientSocket = make_shared<ip::tcp::socket>(ref(getGlobalIoService()));
scheduler::EventId connectTimeoutEvent = scheduler::schedule(timeout,
bind(&TcpChannel::handleFailedConnect, this, clientSocket, onConnectFailed));
bind(&TcpChannel::handleConnectTimeout, this, clientSocket, onConnectFailed));
clientSocket->async_connect(remoteEndpoint,
bind(&TcpChannel::handleSuccessfulConnect, this, _1,
bind(&TcpChannel::handleConnect, this,
boost::asio::placeholders::error,
clientSocket, connectTimeoutEvent,
onFaceCreated, onConnectFailed));
}
void
TcpChannel::connect(const std::string& remoteHost, const std::string& remotePort,
const TcpChannel::FaceCreatedCallback& onFaceCreated,
const TcpChannel::ConnectFailedCallback& onConnectFailed,
const time::seconds& timeout/* = time::seconds(4)*/)
{
shared_ptr<ip::tcp::socket> clientSocket =
make_shared<ip::tcp::socket>(ref(getGlobalIoService()));
ip::tcp::resolver::query query(remoteHost, remotePort);
shared_ptr<ip::tcp::resolver> resolver =
make_shared<ip::tcp::resolver>(ref(getGlobalIoService()));
scheduler::EventId connectTimeoutEvent = scheduler::schedule(timeout,
bind(&TcpChannel::handleFailedConnect, this, clientSocket, onConnectFailed));
resolver->async_resolve(query,
bind(&TcpChannel::handleEndpointResolution, this, _1, _2,
clientSocket, connectTimeoutEvent,
onFaceCreated, onConnectFailed,
resolver));
}
size_t
TcpChannel::size() const
{
@@ -122,35 +94,39 @@ TcpChannel::size() const
}
void
TcpChannel::createFace(const shared_ptr<ip::tcp::socket>& socket,
TcpChannel::createFace(ip::tcp::socket socket,
const FaceCreatedCallback& onFaceCreated,
bool isOnDemand)
{
tcp::Endpoint remoteEndpoint = socket->remote_endpoint();
shared_ptr<Face> face;
tcp::Endpoint remoteEndpoint = socket.remote_endpoint();
ChannelFaceMap::iterator faceMapPos = m_channelFaces.find(remoteEndpoint);
if (faceMapPos == m_channelFaces.end())
{
if (socket->local_endpoint().address().is_loopback())
face = make_shared<TcpLocalFace>(socket, isOnDemand);
else
face = make_shared<TcpFace>(socket, isOnDemand);
auto it = m_channelFaces.find(remoteEndpoint);
if (it == m_channelFaces.end()) {
tcp::Endpoint localEndpoint = socket.local_endpoint();
face->onFail.connectSingleShot(bind(&TcpChannel::afterFaceFailed, this, remoteEndpoint));
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);
m_channelFaces[remoteEndpoint] = face;
}
else
{
// we've already created a a face for this endpoint, just reuse it
face = faceMapPos->second;
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;
}
else {
// we already have a face for this endpoint, just reuse it
face = it->second;
boost::system::error_code error;
socket->shutdown(ip::tcp::socket::shutdown_both, error);
socket->close(error);
}
boost::system::error_code error;
socket.shutdown(ip::tcp::socket::shutdown_both, error);
socket.close(error);
}
// Need to invoke the callback regardless of whether or not we have already created
// the face so that control responses and such can be sent.
@@ -158,50 +134,43 @@ TcpChannel::createFace(const shared_ptr<ip::tcp::socket>& socket,
}
void
TcpChannel::afterFaceFailed(tcp::Endpoint &remoteEndpoint)
TcpChannel::accept(const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onAcceptFailed)
{
NFD_LOG_DEBUG("afterFaceFailed: " << remoteEndpoint);
m_channelFaces.erase(remoteEndpoint);
m_acceptor.async_accept(m_acceptSocket, bind(&TcpChannel::handleAccept, this,
boost::asio::placeholders::error,
onFaceCreated, onAcceptFailed));
}
void
TcpChannel::handleSuccessfulAccept(const boost::system::error_code& error,
const shared_ptr<boost::asio::ip::tcp::socket>& socket,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onAcceptFailed)
TcpChannel::handleAccept(const boost::system::error_code& error,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onAcceptFailed)
{
if (error) {
if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
if (error == boost::asio::error::operation_aborted) // when the socket is closed by someone
return;
NFD_LOG_DEBUG("Connect to remote endpoint failed: "
<< error.category().message(error.value()));
if (static_cast<bool>(onAcceptFailed))
onAcceptFailed("Connect to remote endpoint failed: " +
error.category().message(error.value()));
NFD_LOG_DEBUG("[" << m_localEndpoint << "] Accept failed: " << error.message());
if (onAcceptFailed)
onAcceptFailed(error.message());
return;
}
// prepare accepting the next connection
shared_ptr<ip::tcp::socket> clientSocket =
make_shared<ip::tcp::socket>(ref(getGlobalIoService()));
m_acceptor->async_accept(*clientSocket,
bind(&TcpChannel::handleSuccessfulAccept, this, _1,
clientSocket,
onFaceCreated, onAcceptFailed));
NFD_LOG_DEBUG("[" << m_localEndpoint << "] Connection from " << m_acceptSocket.remote_endpoint());
NFD_LOG_DEBUG("[" << m_localEndpoint << "] "
"<< Connection from " << socket->remote_endpoint());
createFace(socket, onFaceCreated, true);
createFace(std::move(m_acceptSocket), onFaceCreated, true);
// prepare accepting the next connection
accept(onFaceCreated, onAcceptFailed);
}
void
TcpChannel::handleSuccessfulConnect(const boost::system::error_code& error,
const shared_ptr<ip::tcp::socket>& socket,
const scheduler::EventId& connectTimeoutEvent,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onConnectFailed)
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)
{
scheduler::cancel(connectTimeoutEvent);
@@ -214,66 +183,35 @@ TcpChannel::handleSuccessfulConnect(const boost::system::error_code& error,
#else
if (error) {
#endif
if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
if (error == boost::asio::error::operation_aborted) // when the socket is closed by someone
return;
NFD_LOG_WARN("[" << m_localEndpoint << "] Connect failed: " << error.message());
socket->close();
NFD_LOG_DEBUG("Connect to remote endpoint failed: "
<< error.category().message(error.value()));
onConnectFailed("Connect to remote endpoint failed: " +
error.category().message(error.value()));
if (onConnectFailed)
onConnectFailed(error.message());
return;
}
NFD_LOG_DEBUG("[" << m_localEndpoint << "] "
">> Connection to " << socket->remote_endpoint());
NFD_LOG_DEBUG("[" << m_localEndpoint << "] Connected to " << socket->remote_endpoint());
createFace(socket, onFaceCreated, false);
createFace(std::move(*socket), onFaceCreated, false);
}
void
TcpChannel::handleFailedConnect(const shared_ptr<ip::tcp::socket>& socket,
const ConnectFailedCallback& onConnectFailed)
TcpChannel::handleConnectTimeout(const shared_ptr<ip::tcp::socket>& socket,
const ConnectFailedCallback& onConnectFailed)
{
NFD_LOG_DEBUG("Connect to remote endpoint timed out");
onConnectFailed("Connect to remote endpoint timed out");
socket->close(); // abort the connection
}
void
TcpChannel::handleEndpointResolution(const boost::system::error_code& error,
ip::tcp::resolver::iterator remoteEndpoint,
const shared_ptr<boost::asio::ip::tcp::socket>& socket,
const scheduler::EventId& connectTimeoutEvent,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onConnectFailed,
const shared_ptr<ip::tcp::resolver>& resolver)
{
if (error ||
remoteEndpoint == ip::tcp::resolver::iterator())
{
if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
return;
// abort the connection attempt
boost::system::error_code error;
socket->close(error);
socket->close();
scheduler::cancel(connectTimeoutEvent);
NFD_LOG_DEBUG("Remote endpoint hostname or port cannot be resolved: "
<< error.category().message(error.value()));
onConnectFailed("Remote endpoint hostname or port cannot be resolved: " +
error.category().message(error.value()));
return;
}
// got endpoint, now trying to connect (only try the first resolution option)
socket->async_connect(*remoteEndpoint,
bind(&TcpChannel::handleSuccessfulConnect, this, _1,
socket, connectTimeoutEvent,
onFaceCreated, onConnectFailed));
if (onConnectFailed)
onConnectFailed("Connect to remote endpoint timed out");
}
} // namespace nfd
+18 -50
View File
@@ -27,7 +27,6 @@
#define NFD_DAEMON_FACE_TCP_CHANNEL_HPP
#include "channel.hpp"
#include "tcp-face.hpp"
#include "core/scheduler.hpp"
namespace nfd {
@@ -55,9 +54,6 @@ public:
explicit
TcpChannel(const tcp::Endpoint& localEndpoint);
virtual
~TcpChannel();
/**
* \brief Enable listening on the local endpoint, accept connections,
* and create faces when remote host makes a connection
@@ -81,23 +77,6 @@ public:
const ConnectFailedCallback& onConnectFailed,
const time::seconds& timeout = time::seconds(4));
/**
* \brief Create a face by establishing connection to the specified
* remote host and remote port
*
* This method will never block and will return immediately. All
* necessary hostname and port resolution and connection will happen
* in asynchronous mode.
*
* If connection cannot be established within specified timeout, it
* will be aborted.
*/
void
connect(const std::string& remoteHost, const std::string& remotePort,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onConnectFailed,
const time::seconds& timeout = time::seconds(4));
/**
* \brief Get number of faces in the channel
*/
@@ -109,53 +88,42 @@ public:
private:
void
createFace(const shared_ptr<boost::asio::ip::tcp::socket>& socket,
createFace(boost::asio::ip::tcp::socket socket,
const FaceCreatedCallback& onFaceCreated,
bool isOnDemand);
void
afterFaceFailed(tcp::Endpoint &endpoint);
accept(const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onConnectFailed);
void
handleSuccessfulAccept(const boost::system::error_code& error,
const shared_ptr<boost::asio::ip::tcp::socket>& socket,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onConnectFailed);
handleAccept(const boost::system::error_code& error,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onConnectFailed);
void
handleSuccessfulConnect(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);
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);
void
handleFailedConnect(const shared_ptr<boost::asio::ip::tcp::socket>& socket,
const ConnectFailedCallback& onConnectFailed);
void
handleEndpointResolution(const boost::system::error_code& error,
boost::asio::ip::tcp::resolver::iterator remoteEndpoint,
const shared_ptr<boost::asio::ip::tcp::socket>& socket,
const scheduler::EventId& connectTimeoutEvent,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onConnectFailed,
const shared_ptr<boost::asio::ip::tcp::resolver>& resolver);
handleConnectTimeout(const shared_ptr<boost::asio::ip::tcp::socket>& socket,
const ConnectFailedCallback& onConnectFailed);
private:
std::map<tcp::Endpoint, shared_ptr<Face>> m_channelFaces;
tcp::Endpoint m_localEndpoint;
typedef std::map< tcp::Endpoint, shared_ptr<Face> > ChannelFaceMap;
ChannelFaceMap m_channelFaces;
bool m_isListening;
shared_ptr<boost::asio::ip::tcp::acceptor> m_acceptor;
boost::asio::ip::tcp::acceptor m_acceptor;
boost::asio::ip::tcp::socket m_acceptSocket;
};
inline bool
TcpChannel::isListening() const
{
return m_isListening;
return m_acceptor.is_open();
}
} // namespace nfd
+6 -9
View File
@@ -32,18 +32,15 @@ NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(StreamFace,
TcpLocalFace::protocol, LocalFace,
"TcpLocalFace");
TcpFace::TcpFace(const shared_ptr<TcpFace::protocol::socket>& socket, bool isOnDemand)
: StreamFace<protocol>(FaceUri(socket->remote_endpoint()),
FaceUri(socket->local_endpoint()),
socket, isOnDemand)
TcpFace::TcpFace(const FaceUri& remoteUri, const FaceUri& localUri,
protocol::socket socket, bool isOnDemand)
: StreamFace<protocol>(remoteUri, localUri, std::move(socket), isOnDemand)
{
}
TcpLocalFace::TcpLocalFace(const shared_ptr<TcpLocalFace::protocol::socket>& socket,
bool isOnDemand)
: StreamFace<protocol, LocalFace>(FaceUri(socket->remote_endpoint()),
FaceUri(socket->local_endpoint()),
socket, isOnDemand)
TcpLocalFace::TcpLocalFace(const FaceUri& remoteUri, const FaceUri& localUri,
protocol::socket socket, bool isOnDemand)
: StreamFace<protocol, LocalFace>(remoteUri, localUri, std::move(socket), isOnDemand)
{
}
+7 -8
View File
@@ -36,11 +36,10 @@ namespace nfd {
class TcpFace : public StreamFace<boost::asio::ip::tcp>
{
public:
TcpFace(const shared_ptr<protocol::socket>& socket,
bool isOnDemand);
TcpFace(const FaceUri& remoteUri, const FaceUri& localUri,
protocol::socket socket, bool isOnDemand);
};
//
/**
* \brief Implementation of Face abstraction that uses TCP
@@ -50,27 +49,27 @@ public:
class TcpLocalFace : public StreamFace<boost::asio::ip::tcp, LocalFace>
{
public:
TcpLocalFace(const shared_ptr<protocol::socket>& socket,
bool isOnDemand);
TcpLocalFace(const FaceUri& remoteUri, const FaceUri& localUri,
protocol::socket socket, bool isOnDemand);
};
/** \brief Class validating use of TcpLocalFace
*/
template<>
struct StreamFaceValidator<boost::asio::ip::tcp, LocalFace>
struct StreamFaceValidator<TcpLocalFace::protocol, LocalFace>
{
/** Check that local endpoint is loopback
*
* @throws Face::Error if validation failed
*/
static void
validateSocket(boost::asio::ip::tcp::socket& socket)
validateSocket(const TcpLocalFace::protocol::socket& socket)
{
if (!socket.local_endpoint().address().is_loopback() ||
!socket.remote_endpoint().address().is_loopback())
{
throw Face::Error("TcpLocalFace can be created only on loopback interface");
throw Face::Error("TcpLocalFace can be created only on a loopback address");
}
}
};
+84 -178
View File
@@ -24,6 +24,7 @@
*/
#include "udp-channel.hpp"
#include "udp-face.hpp"
#include "core/global-io.hpp"
namespace nfd {
@@ -35,126 +36,54 @@ using namespace boost::asio;
UdpChannel::UdpChannel(const udp::Endpoint& localEndpoint,
const time::seconds& timeout)
: m_localEndpoint(localEndpoint)
, m_isListening(false)
, m_socket(getGlobalIoService())
, m_idleFaceTimeout(timeout)
{
/// \todo the reuse_address works as we want in Linux, but in other system could be different.
/// We need to check this
/// (SO_REUSEADDR doesn't behave uniformly in different OS)
m_socket = make_shared<ip::udp::socket>(ref(getGlobalIoService()));
m_socket->open(m_localEndpoint.protocol());
m_socket->set_option(boost::asio::ip::udp::socket::reuse_address(true));
if (m_localEndpoint.address().is_v6())
{
m_socket->set_option(ip::v6_only(true));
}
try {
m_socket->bind(m_localEndpoint);
}
catch (boost::system::system_error& e) {
//The bind failed, so the socket is useless now
m_socket->close();
throw Error("Failed to properly configure the socket. "
"UdpChannel creation aborted, check the address (" + std::string(e.what()) + ")");
}
this->setUri(FaceUri(localEndpoint));
setUri(FaceUri(m_localEndpoint));
}
void
UdpChannel::listen(const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onListenFailed)
const ConnectFailedCallback& onReceiveFailed)
{
if (m_isListening) {
throw Error("Listen already called on this channel");
if (isListening()) {
NFD_LOG_WARN("[" << m_localEndpoint << "] Already listening");
return;
}
m_isListening = true;
onFaceCreatedNewPeerCallback = onFaceCreated;
onConnectFailedNewPeerCallback = onListenFailed;
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->async_receive_from(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
m_newRemoteEndpoint,
bind(&UdpChannel::newPeer, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
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));
}
void
UdpChannel::connect(const udp::Endpoint& remoteEndpoint,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onConnectFailed)
{
ChannelFaceMap::iterator i = m_channelFaces.find(remoteEndpoint);
if (i != m_channelFaces.end()) {
i->second->setOnDemand(false);
onFaceCreated(i->second);
return;
}
//creating a new socket for the face that will be created soon
shared_ptr<ip::udp::socket> clientSocket =
make_shared<ip::udp::socket>(ref(getGlobalIoService()));
clientSocket->open(m_localEndpoint.protocol());
clientSocket->set_option(ip::udp::socket::reuse_address(true));
shared_ptr<UdpFace> face;
try {
clientSocket->bind(m_localEndpoint);
clientSocket->connect(remoteEndpoint); //@todo connect or async_connect
//(since there is no handshake the connect shouldn't block). If we go for
//async_connect, make sure that if in the meantime we receive a UDP pkt from
//that endpoint nothing bad happen (it's difficult, but it could happen)
face = createFace(remoteEndpoint, false).second;
}
catch (boost::system::system_error& e) {
clientSocket->close();
onConnectFailed("Failed to configure socket (" + std::string(e.what()) + ")");
catch (const boost::system::system_error& e) {
NFD_LOG_WARN("[" << m_localEndpoint << "] Connect failed: " << e.what());
if (onConnectFailed)
onConnectFailed(e.what());
return;
}
createFace(clientSocket, onFaceCreated, false);
}
void
UdpChannel::connect(const std::string& remoteHost,
const std::string& remotePort,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onConnectFailed)
{
ip::udp::resolver::query query(remoteHost, remotePort);
shared_ptr<ip::udp::resolver> resolver =
make_shared<ip::udp::resolver>(ref(getGlobalIoService()));
resolver->async_resolve(query,
bind(&UdpChannel::handleEndpointResolution, this, _1, _2,
onFaceCreated, onConnectFailed,
resolver));
}
void
UdpChannel::handleEndpointResolution(const boost::system::error_code& error,
ip::udp::resolver::iterator remoteEndpoint,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onConnectFailed,
const shared_ptr<ip::udp::resolver>& resolver)
{
if (error != 0 ||
remoteEndpoint == ip::udp::resolver::iterator())
{
if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
return;
NFD_LOG_DEBUG("Remote endpoint hostname or port cannot be resolved: "
<< error.category().message(error.value()));
onConnectFailed("Remote endpoint hostname or port cannot be resolved: " +
error.category().message(error.value()));
return;
}
connect(*remoteEndpoint, onFaceCreated, onConnectFailed);
// Need to invoke the callback regardless of whether or not we had already
// created the face so that control responses and such can be sent
onFaceCreated(face);
}
size_t
@@ -163,102 +92,79 @@ UdpChannel::size() const
return m_channelFaces.size();
}
shared_ptr<UdpFace>
UdpChannel::createFace(const shared_ptr<ip::udp::socket>& socket,
const FaceCreatedCallback& onFaceCreated,
bool isOnDemand)
std::pair<bool, shared_ptr<UdpFace>>
UdpChannel::createFace(const udp::Endpoint& remoteEndpoint, bool isOnDemand)
{
udp::Endpoint remoteEndpoint = socket->remote_endpoint();
auto it = m_channelFaces.find(remoteEndpoint);
if (it != m_channelFaces.end()) {
// we already have a face for this endpoint, just reuse it
if (!isOnDemand)
// only on-demand -> non-on-demand transition is allowed
it->second->setOnDemand(false);
return {false, it->second};
}
shared_ptr<UdpFace> face;
// else, create a new face
ip::udp::socket socket(getGlobalIoService(), m_localEndpoint.protocol());
socket.set_option(ip::udp::socket::reuse_address(true));
socket.bind(m_localEndpoint);
socket.connect(remoteEndpoint);
ChannelFaceMap::iterator faceMapPos = m_channelFaces.find(remoteEndpoint);
if (faceMapPos == m_channelFaces.end())
{
face = make_shared<UdpFace>(socket, isOnDemand, m_idleFaceTimeout);
auto face = make_shared<UdpFace>(FaceUri(remoteEndpoint), FaceUri(m_localEndpoint),
std::move(socket), isOnDemand, m_idleFaceTimeout);
face->onFail.connectSingleShot(bind(&UdpChannel::afterFaceFailed, this, remoteEndpoint));
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;
m_channelFaces[remoteEndpoint] = face;
}
else
{
// we've already created a a face for this endpoint, just reuse it
face = faceMapPos->second;
boost::system::error_code error;
socket->shutdown(ip::udp::socket::shutdown_both, error);
socket->close(error);
}
// Need to invoke the callback regardless of whether or not we have already created
// the face so that control responses and such can be sent.
onFaceCreated(face);
return face;
return {true, face};
}
void
UdpChannel::newPeer(const boost::system::error_code& error,
size_t nBytesReceived)
UdpChannel::handleNewPeer(const boost::system::error_code& error,
size_t nBytesReceived,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onReceiveFailed)
{
NFD_LOG_DEBUG("UdpChannel::newPeer from " << m_newRemoteEndpoint);
shared_ptr<UdpFace> face;
ChannelFaceMap::iterator i = m_channelFaces.find(m_newRemoteEndpoint);
if (i != m_channelFaces.end()) {
//The face already exists.
//Usually this shouldn't happen, because the channel creates a Udpface
//as soon as it receives a pkt from a new endpoint and then the
//traffic is dispatched by the kernel directly to the face.
//However, if the node receives multiple packets from the same endpoint
//"at the same time", while the channel is creating the face the kernel
//could dispatch the other pkts to the channel because the face is not yet
//ready. In this case, the channel has to pass the pkt to the face
NFD_LOG_DEBUG("The creation of the face for the remote endpoint "
<< m_newRemoteEndpoint
<< " is in progress");
face = i->second;
}
else {
shared_ptr<ip::udp::socket> clientSocket =
make_shared<ip::udp::socket>(ref(getGlobalIoService()));
clientSocket->open(m_localEndpoint.protocol());
clientSocket->set_option(ip::udp::socket::reuse_address(true));
clientSocket->bind(m_localEndpoint);
boost::system::error_code ec;
clientSocket->connect(m_newRemoteEndpoint, ec);
if (ec) {
NFD_LOG_WARN("Error while creating on-demand UDP face from " << m_newRemoteEndpoint << ": "
<< boost::system::system_error(ec).what());
if (error) {
if (error == boost::asio::error::operation_aborted) // when the socket is closed by someone
return;
}
face = createFace(clientSocket,
onFaceCreatedNewPeerCallback,
true);
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<UdpFace> face;
try {
std::tie(created, face) = createFace(m_remoteEndpoint, true);
}
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
face->receiveDatagram(m_inputBuffer, nBytesReceived, error);
m_socket->async_receive_from(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
m_newRemoteEndpoint,
bind(&UdpChannel::newPeer, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void
UdpChannel::afterFaceFailed(udp::Endpoint &endpoint)
{
NFD_LOG_DEBUG("afterFaceFailed: " << endpoint);
m_channelFaces.erase(endpoint);
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
+28 -69
View File
@@ -27,8 +27,6 @@
#define NFD_DAEMON_FACE_UDP_CHANNEL_HPP
#include "channel.hpp"
#include "core/global-io.hpp"
#include "udp-face.hpp"
namespace nfd {
@@ -36,22 +34,14 @@ namespace udp {
typedef boost::asio::ip::udp::endpoint Endpoint;
} // namespace udp
class UdpFace;
/**
* \brief Class implementing UDP-based channel to create faces
*
*
*/
class UdpChannel : public Channel
{
public:
/**
* \brief Exception of UdpChannel
*/
struct Error : public std::runtime_error
{
Error(const std::string& what) : runtime_error(what) {}
};
/**
* \brief Create UDP channel for the local endpoint
*
@@ -79,7 +69,7 @@ public:
*/
void
listen(const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onAcceptFailed);
const ConnectFailedCallback& onReceiveFailed);
/**
* \brief Create a face by establishing connection to remote endpoint
@@ -90,21 +80,6 @@ public:
connect(const udp::Endpoint& remoteEndpoint,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onConnectFailed);
/**
* \brief Create a face by establishing connection to the specified
* remote host and remote port
*
* This method will never block and will return immediately. All
* necessary hostname and port resolution and connection will happen
* in asynchronous mode.
*
* If connection cannot be established within specified timeout, it
* will be aborted.
*/
void
connect(const std::string& remoteHost, const std::string& remotePort,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onConnectFailed);
/**
* \brief Get number of faces in the channel
@@ -112,68 +87,52 @@ public:
size_t
size() const;
bool
isListening() const;
private:
shared_ptr<UdpFace>
createFace(const shared_ptr<boost::asio::ip::udp::socket>& socket,
const FaceCreatedCallback& onFaceCreated,
bool isOnDemand);
void
afterFaceFailed(udp::Endpoint& endpoint);
std::pair<bool, shared_ptr<UdpFace>>
createFace(const udp::Endpoint& remoteEndpoint, bool isOnDemand);
/**
* \brief The UdpChannel has received a new pkt from a remote endpoint not yet
* associated with any UdpFace
* \brief The channel has received a new packet from a remote
* endpoint that is not associated with any UdpFace yet
*/
void
newPeer(const boost::system::error_code& error, size_t nBytesReceived);
void
handleEndpointResolution(const boost::system::error_code& error,
boost::asio::ip::udp::resolver::iterator remoteEndpoint,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onConnectFailed,
const shared_ptr<boost::asio::ip::udp::resolver>& resolver);
handleNewPeer(const boost::system::error_code& error,
size_t nBytesReceived,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onReceiveFailed);
private:
std::map<udp::Endpoint, shared_ptr<UdpFace>> m_channelFaces;
udp::Endpoint m_localEndpoint;
/**
* \brief Endpoint used to store the information about the last new remote endpoint
* \brief The latest peer that started communicating with us
*/
udp::Endpoint m_newRemoteEndpoint;
/**
* Callbacks for face creation.
* New communications are detected using async_receive_from.
* Its handler has a fixed signature. No space for the face callback
*/
FaceCreatedCallback onFaceCreatedNewPeerCallback;
// @todo remove the onConnectFailedNewPeerCallback if it remains unused
ConnectFailedCallback onConnectFailedNewPeerCallback;
udp::Endpoint m_remoteEndpoint;
/**
* \brief Socket used to "accept" new communication
**/
shared_ptr<boost::asio::ip::udp::socket> m_socket;
uint8_t m_inputBuffer[ndn::MAX_NDN_PACKET_SIZE];
typedef std::map< udp::Endpoint, shared_ptr<UdpFace> > ChannelFaceMap;
ChannelFaceMap m_channelFaces;
/**
* \brief If true, it means the function listen has already been called
*/
bool m_isListening;
boost::asio::ip::udp::socket m_socket;
/**
* \brief every time m_idleFaceTimeout expires all the idle (and on-demand)
* faces will be removed
* \brief When this timeout expires, all idle on-demand faces will be closed
*/
time::seconds m_idleFaceTimeout;
uint8_t m_inputBuffer[ndn::MAX_NDN_PACKET_SIZE];
};
inline bool
UdpChannel::isListening() const
{
return m_socket.is_open();
}
} // namespace nfd
#endif // NFD_DAEMON_FACE_UDP_CHANNEL_HPP
+22 -33
View File
@@ -37,15 +37,15 @@ namespace nfd {
NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(DatagramFace, UdpFace::protocol, "UdpFace");
UdpFace::UdpFace(const shared_ptr<UdpFace::protocol::socket>& socket,
bool isOnDemand,
UdpFace::UdpFace(const FaceUri& remoteUri, const FaceUri& localUri,
protocol::socket socket, bool isOnDemand,
const time::seconds& idleTimeout)
: DatagramFace<protocol>(FaceUri(socket->remote_endpoint()),
FaceUri(socket->local_endpoint()),
socket, isOnDemand)
: DatagramFace(remoteUri, localUri, std::move(socket))
, m_idleTimeout(idleTimeout)
, m_lastIdleCheck(time::steady_clock::now())
{
this->setOnDemand(isOnDemand);
#ifdef __linux__
//
// By default, Linux does path MTU discovery on IPv4 sockets,
@@ -60,42 +60,33 @@ UdpFace::UdpFace(const shared_ptr<UdpFace::protocol::socket>& socket,
// routers along the path to perform fragmentation as needed.
//
const int value = IP_PMTUDISC_DONT;
if (::setsockopt(socket->native_handle(), IPPROTO_IP,
IP_MTU_DISCOVER, &value, sizeof(value)) < 0)
{
NFD_LOG_WARN("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
<< "] Failed to disable path MTU discovery: " << std::strerror(errno));
}
if (::setsockopt(m_socket.native_handle(), IPPROTO_IP,
IP_MTU_DISCOVER, &value, sizeof(value)) < 0) {
NFD_LOG_FACE_WARN("Failed to disable path MTU discovery: " << std::strerror(errno));
}
#endif
if (isOnDemand && m_idleTimeout > time::seconds::zero()) {
m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout,
bind(&UdpFace::closeIfIdle, this));
if (this->isOnDemand() && m_idleTimeout > time::seconds::zero()) {
m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout, bind(&UdpFace::closeIfIdle, this));
}
}
UdpFace::~UdpFace()
{
scheduler::cancel(m_closeIfIdleEvent);
}
ndn::nfd::FaceStatus
UdpFace::getFaceStatus() const
{
auto status = Face::getFaceStatus();
auto status = DatagramFace::getFaceStatus();
if (isOnDemand()) {
time::milliseconds left = m_idleTimeout - time::duration_cast<time::milliseconds>(
time::steady_clock::now() - m_lastIdleCheck);
time::milliseconds left = m_idleTimeout;
left -= time::duration_cast<time::milliseconds>(time::steady_clock::now() - m_lastIdleCheck);
if (left < time::milliseconds::zero())
left = time::milliseconds::zero();
if (hasBeenUsedRecently()) {
status.setExpirationPeriod(left + m_idleTimeout);
}
else {
status.setExpirationPeriod(left);
}
if (hasBeenUsedRecently())
left += m_idleTimeout;
status.setExpirationPeriod(left);
}
return status;
@@ -108,22 +99,20 @@ UdpFace::closeIfIdle()
// (non-on-demand -> on-demand transition is not allowed)
if (isOnDemand()) {
if (!hasBeenUsedRecently()) {
NFD_LOG_INFO("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
<< "] Idle for more than " << m_idleTimeout << ", closing");
NFD_LOG_FACE_INFO("Closing for inactivity");
close();
// #1718 manual test: uncomment, run NFD in valgrind, send in a UDP packet
// expect read-after-free error and crash
// getGlobalIoService().post([this] {
// NFD_LOG_ERROR("Remaining references: " << this->shared_from_this().use_count());
// NFD_LOG_FACE_ERROR("Remaining references: " << this->shared_from_this().use_count());
// });
}
else {
resetRecentUsage();
m_lastIdleCheck = time::steady_clock::now();
m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout,
bind(&UdpFace::closeIfIdle, this));
m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout, bind(&UdpFace::closeIfIdle, this));
}
}
// else do nothing and do not reschedule the event
+9 -8
View File
@@ -32,18 +32,16 @@
namespace nfd {
/**
* \brief Implementation of Face abstraction that uses UDP
* as underlying transport mechanism
* \brief Implementation of Face abstraction that uses
* unicast UDP as underlying transport mechanism
*/
class UdpFace : public DatagramFace<boost::asio::ip::udp>
{
public:
UdpFace(const shared_ptr<protocol::socket>& socket,
bool isOnDemand,
UdpFace(const FaceUri& remoteUri, const FaceUri& localUri,
protocol::socket socket, bool isOnDemand,
const time::seconds& idleTimeout);
~UdpFace() DECL_OVERRIDE;
ndn::nfd::FaceStatus
getFaceStatus() const DECL_OVERRIDE;
@@ -52,9 +50,12 @@ private:
closeIfIdle();
private:
scheduler::EventId m_closeIfIdleEvent;
time::seconds m_idleTimeout;
const time::seconds m_idleTimeout;
time::steady_clock::TimePoint m_lastIdleCheck;
scheduler::ScopedEventId m_closeIfIdleEvent;
// friend because it needs to invoke protected Face::setOnDemand
friend class UdpChannel;
};
} // namespace nfd
+57 -80
View File
@@ -27,8 +27,10 @@
#include "core/global-io.hpp"
#include "core/network-interface.hpp"
#if defined(__linux__)
#include <sys/socket.h>
#ifdef __linux__
#include <cerrno> // for errno
#include <cstring> // for std::strerror()
#include <sys/socket.h> // for setsockopt()
#endif
namespace nfd {
@@ -147,20 +149,20 @@ UdpFactory::createChannel(const std::string& localIp,
shared_ptr<MulticastUdpFace>
UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint,
const udp::Endpoint& multicastEndpoint,
const std::string& networkInterfaceName /* "" */)
const std::string& networkInterfaceName/* = ""*/)
{
//checking if the local and multicast endpoint are already in use for a multicast face
shared_ptr<MulticastUdpFace> multicastFace = findMulticastFace(localEndpoint);
if (static_cast<bool>(multicastFace)) {
if (multicastFace->getMulticastGroup() == multicastEndpoint)
return multicastFace;
// checking if the local and multicast endpoints are already in use for a multicast face
shared_ptr<MulticastUdpFace> face = findMulticastFace(localEndpoint);
if (static_cast<bool>(face)) {
if (face->getMulticastGroup() == multicastEndpoint)
return face;
else
throw Error("Cannot create the requested UDP multicast face, local "
"endpoint is already allocated for a UDP multicast face "
"on a different multicast group");
}
//checking if the local endpoint is already in use for an unicast channel
// checking if the local endpoint is already in use for a unicast channel
shared_ptr<UdpChannel> unicast = findChannel(localEndpoint);
if (static_cast<bool>(unicast)) {
throw Error("Cannot create the requested UDP multicast face, local "
@@ -186,79 +188,63 @@ UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint,
"the multicast group given as input is not a multicast address");
}
shared_ptr<ip::udp::socket> receiveSocket =
make_shared<ip::udp::socket>(ref(getGlobalIoService()));
ip::udp::socket receiveSocket(getGlobalIoService());
receiveSocket.open(multicastEndpoint.protocol());
receiveSocket.set_option(ip::udp::socket::reuse_address(true));
receiveSocket.bind(multicastEndpoint);
shared_ptr<ip::udp::socket> sendSocket =
make_shared<ip::udp::socket>(ref(getGlobalIoService()));
ip::udp::socket sendSocket(getGlobalIoService());
sendSocket.open(multicastEndpoint.protocol());
sendSocket.set_option(ip::udp::socket::reuse_address(true));
sendSocket.set_option(ip::multicast::enable_loopback(false));
sendSocket.bind(udp::Endpoint(ip::address_v4::any(), multicastEndpoint.port()));
if (localEndpoint.address() != ALL_V4_ENDPOINT)
sendSocket.set_option(ip::multicast::outbound_interface(localEndpoint.address().to_v4()));
receiveSocket->open(multicastEndpoint.protocol());
receiveSocket->set_option(ip::udp::socket::reuse_address(true));
sendSocket->open(multicastEndpoint.protocol());
sendSocket->set_option(ip::udp::socket::reuse_address(true));
sendSocket->set_option(ip::multicast::enable_loopback(false));
try {
sendSocket->bind(udp::Endpoint(ip::address_v4::any(), multicastEndpoint.port()));
receiveSocket->bind(multicastEndpoint);
if (localEndpoint.address() != ip::address::from_string("0.0.0.0")) {
sendSocket->set_option(ip::multicast::outbound_interface(localEndpoint.address().to_v4()));
}
sendSocket->set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
sendSocket.set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
localEndpoint.address().to_v4()));
receiveSocket.set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
localEndpoint.address().to_v4()));
receiveSocket->set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
localEndpoint.address().to_v4()));
}
catch (boost::system::system_error& e) {
std::stringstream msg;
msg << "Failed to properly configure the socket, check the address (" << e.what() << ")";
throw Error(msg.str());
}
#if defined(__linux__)
//On linux system, if there are more than one MulticastUdpFace for the same multicast group but
//bound on different network interfaces, the socket has to be bound with the specific interface
//using SO_BINDTODEVICE, otherwise the face will receive packets also from other interfaces.
//Without SO_BINDTODEVICE every MulticastUdpFace that have joined the same multicast group
//on different interfaces will receive the same packet.
//This applies only on linux, for OS X the ip::multicast::join_group is enough to get
//the desired behaviour
#ifdef __linux__
/*
* On Linux, if there is more than one MulticastUdpFace for the same multicast
* group but they are bound to different network interfaces, the socket needs
* to be bound to the specific interface using SO_BINDTODEVICE, otherwise the
* face will receive all packets sent to the other interfaces as well.
* This happens only on Linux. On OS X, the ip::multicast::join_group option
* is enough to get the desired behaviour.
*/
if (!networkInterfaceName.empty()) {
if (::setsockopt(receiveSocket->native_handle(), SOL_SOCKET, SO_BINDTODEVICE,
networkInterfaceName.c_str(), networkInterfaceName.size()+1) == -1){
throw Error("Cannot bind multicast face to " + networkInterfaceName
+ " make sure you have CAP_NET_RAW capability" );
if (::setsockopt(receiveSocket.native_handle(), SOL_SOCKET, SO_BINDTODEVICE,
networkInterfaceName.c_str(), networkInterfaceName.size() + 1) < 0) {
throw Error("Cannot bind multicast face to " + networkInterfaceName +
": " + std::strerror(errno));
}
}
#endif
multicastFace = make_shared<MulticastUdpFace>(receiveSocket, sendSocket,
localEndpoint, multicastEndpoint);
face = make_shared<MulticastUdpFace>(multicastEndpoint, FaceUri(localEndpoint),
std::move(receiveSocket), std::move(sendSocket));
multicastFace->onFail.connectSingleShot(bind(&UdpFactory::afterFaceFailed, this, localEndpoint));
face->onFail.connectSingleShot([this, localEndpoint] (const std::string& reason) {
m_multicastFaces.erase(localEndpoint);
});
m_multicastFaces[localEndpoint] = face;
m_multicastFaces[localEndpoint] = multicastFace;
return multicastFace;
return face;
}
shared_ptr<MulticastUdpFace>
UdpFactory::createMulticastFace(const std::string& localIp,
const std::string& multicastIp,
const std::string& multicastPort,
const std::string& networkInterfaceName /* "" */)
const std::string& networkInterfaceName/* = ""*/)
{
using namespace boost::asio::ip;
udp::Endpoint localEndpoint(address::from_string(localIp),
udp::Endpoint localEndpoint(ip::address::from_string(localIp),
boost::lexical_cast<uint16_t>(multicastPort));
udp::Endpoint multicastEndpoint(address::from_string(multicastIp),
udp::Endpoint multicastEndpoint(ip::address::from_string(multicastIp),
boost::lexical_cast<uint16_t>(multicastPort));
return createMulticastFace(localEndpoint, multicastEndpoint, networkInterfaceName);
}
@@ -268,6 +254,7 @@ UdpFactory::createFace(const FaceUri& uri,
const FaceConnectFailedCallback& onConnectFailed)
{
BOOST_ASSERT(uri.isCanonical());
boost::asio::ip::address ipAddress = boost::asio::ip::address::from_string(uri.getHost());
udp::Endpoint endpoint(ipAddress, boost::lexical_cast<uint16_t>(uri.getPort()));
@@ -276,15 +263,13 @@ UdpFactory::createFace(const FaceUri& uri,
return;
}
if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end())
{
onConnectFailed("Requested endpoint is prohibited "
"(reserved by this NFD or disallowed by face management protocol)");
return;
}
if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end()) {
onConnectFailed("Requested endpoint is prohibited "
"(reserved by this NFD or disallowed by face management protocol)");
return;
}
// very simple logic for now
for (ChannelMap::iterator channel = m_channels.begin();
channel != m_channels.end();
++channel)
@@ -296,6 +281,7 @@ UdpFactory::createFace(const FaceUri& uri,
return;
}
}
onConnectFailed("No channels available to connect to " +
boost::lexical_cast<std::string>(endpoint));
}
@@ -320,17 +306,10 @@ UdpFactory::findMulticastFace(const udp::Endpoint& localEndpoint)
return shared_ptr<MulticastUdpFace>();
}
void
UdpFactory::afterFaceFailed(udp::Endpoint& endpoint)
{
NFD_LOG_DEBUG("afterFaceFailed: " << endpoint);
m_multicastFaces.erase(endpoint);
}
std::list<shared_ptr<const Channel> >
std::list<shared_ptr<const Channel>>
UdpFactory::getChannels() const
{
std::list<shared_ptr<const Channel> > channels;
std::list<shared_ptr<const Channel>> channels;
for (ChannelMap::const_iterator i = m_channels.begin(); i != m_channels.end(); ++i)
{
channels.push_back(i->second);
@@ -339,6 +318,4 @@ UdpFactory::getChannels() const
return channels;
}
} // namespace nfd
+5 -10
View File
@@ -30,10 +30,9 @@
#include "udp-channel.hpp"
#include "multicast-udp-face.hpp"
namespace nfd {
// @todo The multicast support for ipv6 must be implemented
/// @todo IPv6 multicast support not implemented
class UdpFactory : public ProtocolFactory
{
@@ -51,7 +50,7 @@ public:
}
};
typedef std::map< udp::Endpoint, shared_ptr<MulticastUdpFace> > MulticastFaceMap;
typedef std::map<udp::Endpoint, shared_ptr<MulticastUdpFace>> MulticastFaceMap;
explicit
UdpFactory(const std::string& defaultPort = "6363");
@@ -143,13 +142,13 @@ public:
const std::string& multicastPort,
const std::string& networkInterfaceName = "");
// from Factory
// from ProtocolFactory
virtual void
createFace(const FaceUri& uri,
const FaceCreatedCallback& onCreated,
const FaceConnectFailedCallback& onConnectFailed);
virtual std::list<shared_ptr<const Channel> >
virtual std::list<shared_ptr<const Channel>>
getChannels() const;
/**
@@ -159,7 +158,6 @@ public:
getMulticastFaces() const;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
prohibitEndpoint(const udp::Endpoint& endpoint);
@@ -183,7 +181,6 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
shared_ptr<UdpChannel>
findChannel(const udp::Endpoint& localEndpoint);
/**
* \brief Look up multicast UdpFace using specified local endpoint
*
@@ -196,7 +193,7 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
findMulticastFace(const udp::Endpoint& localEndpoint);
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
typedef std::map< udp::Endpoint, shared_ptr<UdpChannel> > ChannelMap;
typedef std::map<udp::Endpoint, shared_ptr<UdpChannel>> ChannelMap;
ChannelMap m_channels;
MulticastFaceMap m_multicastFaces;
@@ -205,14 +202,12 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
std::set<udp::Endpoint> m_prohibitedEndpoints;
};
inline const UdpFactory::MulticastFaceMap&
UdpFactory::getMulticastFaces() const
{
return m_multicastFaces;
}
} // namespace nfd
#endif // NFD_DAEMON_FACE_UDP_FACTORY_HPP
+71 -78
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,9 +21,10 @@
*
* 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 "unix-stream-channel.hpp"
#include "unix-stream-face.hpp"
#include "core/global-io.hpp"
#include <boost/filesystem.hpp>
@@ -32,26 +34,24 @@ namespace nfd {
NFD_LOG_INIT("UnixStreamChannel");
using namespace boost::asio::local;
UnixStreamChannel::UnixStreamChannel(const unix_stream::Endpoint& endpoint)
: m_endpoint(endpoint)
, m_isListening(false)
, m_acceptor(getGlobalIoService())
, m_socket(getGlobalIoService())
{
setUri(FaceUri(endpoint));
setUri(FaceUri(m_endpoint));
}
UnixStreamChannel::~UnixStreamChannel()
{
if (m_isListening)
{
// use the non-throwing variants during destruction
// and ignore any errors
boost::system::error_code error;
m_acceptor->close(error);
NFD_LOG_TRACE("[" << m_endpoint << "] Removing socket file");
boost::filesystem::remove(m_endpoint.path(), error);
}
if (isListening()) {
// use the non-throwing variants during destruction
// and ignore any errors
boost::system::error_code error;
m_acceptor.close(error);
NFD_LOG_DEBUG("[" << m_endpoint << "] Removing socket file");
boost::filesystem::remove(m_endpoint.path(), error);
}
}
void
@@ -59,7 +59,7 @@ UnixStreamChannel::listen(const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onAcceptFailed,
int backlog/* = acceptor::max_connections*/)
{
if (m_isListening) {
if (isListening()) {
NFD_LOG_WARN("[" << m_endpoint << "] Already listening");
return;
}
@@ -69,81 +69,74 @@ UnixStreamChannel::listen(const FaceCreatedCallback& onFaceCreated,
fs::path socketPath(m_endpoint.path());
fs::file_type type = fs::symlink_status(socketPath).type();
if (type == fs::socket_file)
{
boost::system::error_code error;
stream_protocol::socket socket(getGlobalIoService());
socket.connect(m_endpoint, error);
NFD_LOG_TRACE("[" << m_endpoint << "] connect() on existing socket file returned: "
+ error.message());
if (!error)
{
// someone answered, leave the socket alone
throw Error("Socket file at " + m_endpoint.path()
+ " belongs to another NFD process");
}
else if (error == boost::system::errc::connection_refused ||
error == boost::system::errc::timed_out)
{
// no one is listening on the remote side,
// we can safely remove the socket file
NFD_LOG_INFO("[" << m_endpoint << "] Removing stale socket file");
fs::remove(socketPath);
}
if (type == fs::socket_file) {
boost::system::error_code error;
boost::asio::local::stream_protocol::socket socket(getGlobalIoService());
socket.connect(m_endpoint, error);
NFD_LOG_TRACE("[" << m_endpoint << "] connect() on existing socket file returned: "
+ error.message());
if (!error) {
// someone answered, leave the socket alone
throw Error("Socket file at " + m_endpoint.path()
+ " belongs to another NFD process");
}
else if (type != fs::file_not_found)
{
throw Error(m_endpoint.path() + " already exists and is not a socket file");
else if (error == boost::asio::error::connection_refused ||
error == boost::asio::error::timed_out) {
// no one is listening on the remote side,
// we can safely remove the stale socket
NFD_LOG_DEBUG("[" << m_endpoint << "] Removing stale socket file");
fs::remove(socketPath);
}
}
else if (type != fs::file_not_found) {
throw Error(m_endpoint.path() + " already exists and is not a socket file");
}
m_acceptor = make_shared<stream_protocol::acceptor>(ref(getGlobalIoService()));
m_acceptor->open();
m_acceptor->bind(m_endpoint);
m_acceptor->listen(backlog);
m_isListening = true;
m_acceptor.open();
m_acceptor.bind(m_endpoint);
m_acceptor.listen(backlog);
if (::chmod(m_endpoint.path().c_str(), 0666) < 0)
{
throw Error("Failed to chmod() socket file at " + m_endpoint.path());
}
if (::chmod(m_endpoint.path().c_str(), 0666) < 0) {
throw Error("chmod(" + m_endpoint.path() + ") failed: " + std::strerror(errno));
}
shared_ptr<stream_protocol::socket> clientSocket =
make_shared<stream_protocol::socket>(ref(getGlobalIoService()));
m_acceptor->async_accept(*clientSocket,
bind(&UnixStreamChannel::handleSuccessfulAccept, this,
boost::asio::placeholders::error, clientSocket,
onFaceCreated, onAcceptFailed));
// start accepting connections
accept(onFaceCreated, onAcceptFailed);
}
void
UnixStreamChannel::handleSuccessfulAccept(const boost::system::error_code& error,
const shared_ptr<stream_protocol::socket>& socket,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onAcceptFailed)
UnixStreamChannel::accept(const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onAcceptFailed)
{
m_acceptor.async_accept(m_socket, bind(&UnixStreamChannel::handleAccept, this,
boost::asio::placeholders::error,
onFaceCreated, onAcceptFailed));
}
void
UnixStreamChannel::handleAccept(const boost::system::error_code& error,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onAcceptFailed)
{
if (error) {
if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
if (error == boost::asio::error::operation_aborted) // when the socket is closed by someone
return;
NFD_LOG_DEBUG("[" << m_endpoint << "] Connection failed: " << error.message());
onAcceptFailed("Connection failed: " + error.message());
NFD_LOG_DEBUG("[" << m_endpoint << "] Accept failed: " << error.message());
if (onAcceptFailed)
onAcceptFailed(error.message());
return;
}
NFD_LOG_DEBUG("[" << m_endpoint << "] << Incoming connection");
NFD_LOG_DEBUG("[" << m_endpoint << "] Incoming connection");
shared_ptr<stream_protocol::socket> clientSocket =
make_shared<stream_protocol::socket>(ref(getGlobalIoService()));
auto remoteUri = FaceUri::fromFd(m_socket.native_handle());
auto localUri = FaceUri(m_socket.local_endpoint());
auto face = make_shared<UnixStreamFace>(remoteUri, localUri, std::move(m_socket));
onFaceCreated(face);
// prepare accepting the next connection
m_acceptor->async_accept(*clientSocket,
bind(&UnixStreamChannel::handleSuccessfulAccept, this,
boost::asio::placeholders::error, clientSocket,
onFaceCreated, onAcceptFailed));
shared_ptr<UnixStreamFace> face = make_shared<UnixStreamFace>(socket);
onFaceCreated(face);
accept(onFaceCreated, onAcceptFailed);
}
} // namespace nfd
+19 -9
View File
@@ -26,7 +26,6 @@
#define NFD_DAEMON_FACE_UNIX_STREAM_CHANNEL_HPP
#include "channel.hpp"
#include "unix-stream-face.hpp"
namespace nfd {
@@ -60,8 +59,7 @@ public:
explicit
UnixStreamChannel(const unix_stream::Endpoint& endpoint);
virtual
~UnixStreamChannel();
~UnixStreamChannel() DECL_OVERRIDE;
/**
* \brief Enable listening on the local endpoint, accept connections,
@@ -77,19 +75,31 @@ public:
const ConnectFailedCallback& onAcceptFailed,
int backlog = boost::asio::local::stream_protocol::acceptor::max_connections);
bool
isListening() const;
private:
void
handleSuccessfulAccept(const boost::system::error_code& error,
const shared_ptr<boost::asio::local::stream_protocol::socket>& socket,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onConnectFailed);
accept(const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onAcceptFailed);
void
handleAccept(const boost::system::error_code& error,
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onAcceptFailed);
private:
unix_stream::Endpoint m_endpoint;
shared_ptr<boost::asio::local::stream_protocol::acceptor> m_acceptor;
bool m_isListening;
boost::asio::local::stream_protocol::acceptor m_acceptor;
boost::asio::local::stream_protocol::socket m_socket;
};
inline bool
UnixStreamChannel::isListening() const
{
return m_acceptor.is_open();
}
} // namespace nfd
#endif // NFD_DAEMON_FACE_UNIX_STREAM_CHANNEL_HPP
+7 -7
View File
@@ -33,14 +33,14 @@ NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(StreamFace,
UnixStreamFace::protocol, LocalFace,
"UnixStreamFace");
BOOST_STATIC_ASSERT((boost::is_same<UnixStreamFace::protocol::socket::native_handle_type,
int>::value));
UnixStreamFace::UnixStreamFace(const shared_ptr<UnixStreamFace::protocol::socket>& socket)
: StreamFace<protocol, LocalFace>(FaceUri::fromFd(socket->native_handle()),
FaceUri(socket->local_endpoint()),
socket, true)
UnixStreamFace::UnixStreamFace(const FaceUri& remoteUri, const FaceUri& localUri,
protocol::socket socket)
: StreamFace<protocol, LocalFace>(remoteUri, localUri, std::move(socket), true)
{
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'"
);
}
} // namespace nfd
+2 -2
View File
@@ -40,8 +40,8 @@ namespace nfd {
class UnixStreamFace : public StreamFace<boost::asio::local::stream_protocol, LocalFace>
{
public:
explicit
UnixStreamFace(const shared_ptr<protocol::socket>& socket);
UnixStreamFace(const FaceUri& remoteUri, const FaceUri& localUri,
protocol::socket socket);
};
} // namespace nfd
+79 -88
View File
@@ -24,6 +24,8 @@
*/
#include "websocket-channel.hpp"
#include "core/global-io.hpp"
#include "core/scheduler.hpp"
#include <boost/date_time/posix_time/posix_time.hpp>
@@ -31,13 +33,13 @@ namespace nfd {
NFD_LOG_INIT("WebSocketChannel");
using namespace boost::asio;
WebSocketChannel::WebSocketChannel(const websocket::Endpoint& localEndpoint)
: m_localEndpoint(localEndpoint)
, m_isListening(false)
, m_pingInterval(10000)
{
setUri(FaceUri(m_localEndpoint, "ws"));
// Setup WebSocket server
m_server.clear_access_channels(websocketpp::log::alevel::all);
m_server.clear_error_channels(websocketpp::log::alevel::all);
@@ -46,19 +48,19 @@ WebSocketChannel::WebSocketChannel(const websocket::Endpoint& localEndpoint)
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());
// 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));
// Always set SO_REUSEADDR flag
m_server.set_reuse_addr(true);
// Detect disconnection using PONG message
m_server.set_pong_handler(bind(&WebSocketChannel::handlePong, this, _1, _2));
m_server.set_pong_timeout_handler(bind(&WebSocketChannel::handlePongTimeout,
this, _1, _2));
this->setUri(FaceUri(localEndpoint, "ws"));
}
WebSocketChannel::~WebSocketChannel()
void
WebSocketChannel::setPingInterval(time::milliseconds interval)
{
m_pingInterval = interval;
}
void
@@ -70,120 +72,109 @@ WebSocketChannel::setPongTimeout(time::milliseconds timeout)
void
WebSocketChannel::handlePongTimeout(websocketpp::connection_hdl hdl, std::string msg)
{
ChannelFaceMap::iterator it = m_channelFaces.find(hdl);
if (it != m_channelFaces.end())
{
it->second->close();
NFD_LOG_DEBUG("handlePongTimeout: remove " << it->second->getRemoteUri());
m_channelFaces.erase(it);
}
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);
}
}
void
WebSocketChannel::handlePong(websocketpp::connection_hdl hdl, std::string msg)
{
ChannelFaceMap::iterator it = m_channelFaces.find(hdl);
if (it != m_channelFaces.end())
{
NFD_LOG_TRACE("handlePong: from " << it->second->getRemoteUri());
}
auto it = m_channelFaces.find(hdl);
if (it != m_channelFaces.end()) {
NFD_LOG_TRACE("Pong from " << it->second->getRemoteUri());
}
}
void
WebSocketChannel::handleMessage(websocketpp::connection_hdl hdl,
websocket::Server::message_ptr msg)
{
ChannelFaceMap::iterator it = m_channelFaces.find(hdl);
if (it != m_channelFaces.end())
{
it->second->handleReceive(msg->get_payload());
}
auto it = m_channelFaces.find(hdl);
if (it != m_channelFaces.end()) {
it->second->handleReceive(msg->get_payload());
}
}
void
WebSocketChannel::handleOpen(websocketpp::connection_hdl hdl)
{
std::string remote;
try
{
remote = "wsclient://" + m_server.get_con_from_hdl(hdl)->get_remote_endpoint();
}
catch (websocketpp::lib::error_code&)
{
NFD_LOG_DEBUG("handleOpen: cannot get remote uri");
websocketpp::lib::error_code ecode;
m_server.close(hdl, websocketpp::close::status::normal, "closed by channel", ecode);
}
shared_ptr<WebSocketFace> face = ndn::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);
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
}
}
void
WebSocketChannel::sendPing(websocketpp::connection_hdl hdl)
{
ChannelFaceMap::iterator it = m_channelFaces.find(hdl);
if (it != m_channelFaces.end())
{
try
{
m_server.ping(hdl, "NFD-WebSocket");
}
catch (websocketpp::lib::error_code&)
{
it->second->close();
NFD_LOG_DEBUG("sendPing: failed to ping " << it->second->getRemoteUri());
m_channelFaces.erase(it);
}
auto it = m_channelFaces.find(hdl);
if (it != m_channelFaces.end()) {
NFD_LOG_TRACE("Sending ping to " << it->second->getRemoteUri());
NFD_LOG_TRACE("sendPing: to " << it->second->getRemoteUri());
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);
}
// Schedule next ping message
scheduler::EventId pingEvent = scheduler::schedule(m_pingInterval,
bind(&WebSocketChannel::sendPing,
this, hdl));
it->second->setPingEventId(pingEvent);
}
}
void
WebSocketChannel::handleClose(websocketpp::connection_hdl hdl)
{
ChannelFaceMap::iterator it = m_channelFaces.find(hdl);
if (it != m_channelFaces.end())
{
it->second->close();
NFD_LOG_DEBUG("handleClose: remove " << it->second->getRemoteUri());
m_channelFaces.erase(it);
}
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);
}
}
void
WebSocketChannel::listen(const FaceCreatedCallback& onFaceCreated)
{
if (m_isListening)
{
throw Error("Listen already called on this channel");
}
if (isListening()) {
NFD_LOG_WARN("[" << m_localEndpoint << "] Already listening");
return;
}
m_isListening = true;
m_onFaceCreatedCallback = onFaceCreated;
try
{
m_server.listen(m_localEndpoint);
}
catch (websocketpp::lib::error_code ec)
{
throw Error("Failed to listen on local endpoint");
}
m_server.listen(m_localEndpoint);
m_server.start_accept();
}
+6 -32
View File
@@ -27,33 +27,16 @@
#define NFD_DAEMON_FACE_WEBSOCKET_CHANNEL_HPP
#include "channel.hpp"
#include "core/global-io.hpp"
#include "core/scheduler.hpp"
#include "websocket-face.hpp"
namespace nfd {
/**
* \brief Class implementing WebSocket-based channel to create faces
*
*
*/
class WebSocketChannel : public Channel
{
public:
/**
* \brief Exception of WebSocketChannel
*/
class Error : public std::runtime_error
{
public:
explicit
Error(const std::string& what)
: runtime_error(what)
{
}
};
/**
* \brief Create WebSocket channel for the local endpoint
*
@@ -66,9 +49,6 @@ public:
explicit
WebSocketChannel(const websocket::Endpoint& localEndpoint);
virtual
~WebSocketChannel();
/**
* \brief Enable listening on the local endpoint, accept connections,
* and create faces when remote host makes a connection
@@ -88,11 +68,9 @@ public:
bool
isListening() const;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
setPingInterval(time::milliseconds interval)
{
m_pingInterval = interval;
}
setPingInterval(time::milliseconds interval);
void
setPongTimeout(time::milliseconds timeout);
@@ -118,20 +96,16 @@ private:
private:
websocket::Endpoint m_localEndpoint;
websocket::Server m_server;
std::map<websocketpp::connection_hdl, shared_ptr<WebSocketFace>,
std::owner_less<websocketpp::connection_hdl>> m_channelFaces;
/**
* Callbacks for face creation.
* New communications are detected using async_receive_from.
* Its handler has a fixed signature. No space for the face callback
* Callback for face creation
*/
FaceCreatedCallback m_onFaceCreatedCallback;
typedef std::map< websocketpp::connection_hdl, shared_ptr<WebSocketFace>,
std::owner_less<websocketpp::connection_hdl> > ChannelFaceMap;
ChannelFaceMap m_channelFaces;
/**
* \brief If true, it means the function listen has already been called
*/
+32 -32
View File
@@ -37,6 +37,7 @@ WebSocketFace::WebSocketFace(const FaceUri& remoteUri, const FaceUri& localUri,
, m_server(server)
, m_closed(false)
{
NFD_LOG_FACE_INFO("Creating face");
this->setOnDemand(true);
}
@@ -46,18 +47,18 @@ 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();
try {
m_server.send(m_handle, payload.wire(), payload.size(),
websocketpp::frame::opcode::binary);
}
catch (const websocketpp::lib::error_code& e) {
NFD_LOG_WARN("Failed to send Interest: " << e << " (" << e.message() << ")");
}
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
@@ -66,32 +67,34 @@ 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();
try {
m_server.send(m_handle, payload.wire(), payload.size(),
websocketpp::frame::opcode::binary);
}
catch (const websocketpp::lib::error_code& e) {
NFD_LOG_WARN("Failed to send Data: " << e << " (" << e.message() << ")");
}
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 == false)
{
m_closed = true;
scheduler::cancel(m_pingEventId);
websocketpp::lib::error_code ecode;
m_server.close(m_handle, websocketpp::close::status::normal, "closed by nfd", ecode);
if (m_closed)
return;
fail("Face closed");
}
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
@@ -100,30 +103,27 @@ WebSocketFace::handleReceive(const std::string& msg)
// Copy message into Face internal buffer
if (msg.size() > ndn::MAX_NDN_PACKET_SIZE)
{
NFD_LOG_WARN("[id:" << this->getId()
<< "] Received WebSocket message is too big (" << msg.size() << " bytes)");
NFD_LOG_FACE_WARN("Received WebSocket message is too big (" << msg.size() << " bytes)");
return;
}
NFD_LOG_TRACE("[id:" << this->getId()
<< "] Received: " << msg.size() << " bytes");
NFD_LOG_FACE_TRACE("Received: " << msg.size() << " bytes");
this->getMutableCounters().getNInBytes() += msg.size();
// Try to parse message data
bool isOk = false;
Block element;
bool isOk = Block::fromBuffer(reinterpret_cast<const uint8_t*>(msg.c_str()),
msg.size(), element);
std::tie(isOk, element) = Block::fromBuffer(reinterpret_cast<const uint8_t*>(msg.c_str()),
msg.size());
if (!isOk)
{
NFD_LOG_WARN("[id:" << this->getId()
<< "] Received block is invalid or too large to process");
NFD_LOG_FACE_WARN("Received block is invalid or too large to process");
return;
}
if (!this->decodeAndDispatchInput(element))
{
NFD_LOG_WARN("[id:" << this->getId()
<< "] Received unrecognized TLV block of type " << element.type());
NFD_LOG_FACE_WARN("Received unrecognized TLV block of type " << element.type());
// ignore unknown packet and proceed
}
}
-1
View File
@@ -27,7 +27,6 @@
#define NFD_DAEMON_FACE_WEBSOCKET_FACE_HPP
#include "face.hpp"
#include "core/logger.hpp"
#include "core/scheduler.hpp"
#ifndef HAVE_WEBSOCKET
-2
View File
@@ -29,8 +29,6 @@ namespace nfd {
using namespace boost::asio;
NFD_LOG_INIT("WebSocketFactory");
WebSocketFactory::WebSocketFactory(const std::string& defaultPort)
: m_defaultPort(defaultPort)
{
+2 -5
View File
@@ -29,7 +29,6 @@
#include "protocol-factory.hpp"
#include "websocket-channel.hpp"
namespace nfd {
class WebSocketFactory : public ProtocolFactory
@@ -63,8 +62,7 @@ public:
* \returns always a valid pointer to a WebSocketChannel object, an exception
* is thrown if it cannot be created.
*
* \throws WebSocketFactory::Error, TcpResolver::Error
*
* \throws WebSocketFactory::Error
*/
shared_ptr<WebSocketChannel>
createChannel(const websocket::Endpoint& localEndpoint);
@@ -80,7 +78,7 @@ public:
shared_ptr<WebSocketChannel>
createChannel(const std::string& localIp, const std::string& port);
// from Factory
// from ProtocolFactory
virtual void
createFace(const FaceUri& uri,
const FaceCreatedCallback& onCreated,
@@ -90,7 +88,6 @@ public:
getChannels() const;
private:
/**
* \brief Look up WebSocketChannel using specified local endpoint
*
+8 -5
View File
@@ -32,6 +32,7 @@ namespace fw {
NFD_LOG_INIT("AccessStrategy");
const Name AccessStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/access/%FD%01");
NFD_REGISTER_STRATEGY(AccessStrategy);
AccessStrategy::AccessStrategy(Forwarder& forwarder, const Name& name)
: Strategy(forwarder, name)
@@ -50,16 +51,15 @@ AccessStrategy::afterReceiveInterest(const Face& inFace,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry)
{
RetransmissionSuppression::Result suppressResult =
m_retransmissionSuppression.decide(inFace, interest, *pitEntry);
RetxSuppression::Result suppressResult = m_retxSuppression.decide(inFace, interest, *pitEntry);
switch (suppressResult) {
case RetransmissionSuppression::NEW:
case RetxSuppression::NEW:
this->afterReceiveNewInterest(inFace, interest, fibEntry, pitEntry);
break;
case RetransmissionSuppression::FORWARD:
case RetxSuppression::FORWARD:
this->afterReceiveRetxInterest(inFace, interest, fibEntry, pitEntry);
break;
case RetransmissionSuppression::SUPPRESS:
case RetxSuppression::SUPPRESS:
NFD_LOG_DEBUG(interest << " interestFrom " << inFace.getId() << " retx-suppress");
break;
default:
@@ -264,6 +264,9 @@ AccessStrategy::addPrefixMeasurements(const Data& data)
BOOST_ASSERT(me != nullptr);
}
static const time::nanoseconds ME_LIFETIME = time::seconds(8);
this->getMeasurements().extendLifetime(*me, ME_LIFETIME);
return me->getOrCreateStrategyInfo<MtInfo>();
}
+2 -2
View File
@@ -28,7 +28,7 @@
#include "strategy.hpp"
#include "rtt-estimator.hpp"
#include "retransmission-suppression.hpp"
#include "retx-suppression-fixed.hpp"
#include <unordered_set>
#include <unordered_map>
@@ -167,7 +167,7 @@ public:
private:
FaceInfoTable m_fit;
RetransmissionSuppression m_retransmissionSuppression;
RetxSuppressionFixed m_retxSuppression;
signal::ScopedConnection m_removeFaceInfoConn;
};
-42
View File
@@ -1,42 +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_FW_AVAILABLE_STRATEGIES_HPP
#define NFD_DAEMON_FW_AVAILABLE_STRATEGIES_HPP
#include "strategy.hpp"
namespace nfd {
namespace fw {
shared_ptr<Strategy>
makeDefaultStrategy(Forwarder& forwarder);
void
installStrategies(Forwarder& forwarder);
} // namespace fw
} // namespace nfd
#endif // NFD_DAEMON_FW_AVAILABLE_STRATEGIES_HPP
+8 -7
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,6 +29,7 @@ namespace nfd {
namespace fw {
const Name BestRouteStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/best-route/%FD%01");
NFD_REGISTER_STRATEGY(BestRouteStrategy);
BestRouteStrategy::BestRouteStrategy(Forwarder& forwarder, const Name& name)
: Strategy(forwarder, name)
+6 -5
View File
@@ -31,7 +31,8 @@ namespace fw {
NFD_LOG_INIT("BestRouteStrategy2");
const Name BestRouteStrategy2::STRATEGY_NAME("ndn:/localhost/nfd/strategy/best-route/%FD%02");
const Name BestRouteStrategy2::STRATEGY_NAME("ndn:/localhost/nfd/strategy/best-route/%FD%03");
NFD_REGISTER_STRATEGY(BestRouteStrategy2);
BestRouteStrategy2::BestRouteStrategy2(Forwarder& forwarder, const Name& name)
: Strategy(forwarder, name)
@@ -103,9 +104,9 @@ BestRouteStrategy2::afterReceiveInterest(const Face& inFace,
const fib::NextHopList& nexthops = fibEntry->getNextHops();
fib::NextHopList::const_iterator it = nexthops.end();
RetransmissionSuppression::Result suppression =
m_retransmissionSuppression.decide(inFace, interest, *pitEntry);
if (suppression == RetransmissionSuppression::NEW) {
RetxSuppression::Result suppression =
m_retxSuppression.decide(inFace, interest, *pitEntry);
if (suppression == RetxSuppression::NEW) {
// forward to nexthop with lowest cost except downstream
it = std::find_if(nexthops.begin(), nexthops.end(),
bind(&predicate_NextHop_eligible, pitEntry, _1, inFace.getId(),
@@ -124,7 +125,7 @@ BestRouteStrategy2::afterReceiveInterest(const Face& inFace,
return;
}
if (suppression == RetransmissionSuppression::SUPPRESS) {
if (suppression == RetxSuppression::SUPPRESS) {
NFD_LOG_DEBUG(interest << " from=" << inFace.getId()
<< " suppressed");
return;
+7 -7
View File
@@ -27,18 +27,18 @@
#define NFD_DAEMON_FW_BEST_ROUTE_STRATEGY2_HPP
#include "strategy.hpp"
#include "retransmission-suppression.hpp"
#include "retx-suppression-exponential.hpp"
namespace nfd {
namespace fw {
/** \brief Best Route strategy version 2
/** \brief Best Route strategy version 3
*
* This strategy forwards a new Interest to the lowest-cost nexthop (except downstream).
* After that, it recognizes consumer retransmission:
* if a similar Interest arrives from any downstream after MIN_RETRANSMISSION_INTERVAL,
* the strategy forwards the Interest again to the lowest-cost nexthop (except downstream)
* that is not previously used. If all nexthops have been used, the strategy starts over.
* After that, if consumer retransmits the Interest (and is not suppressed according to
* exponential backoff algorithm), the strategy forwards the Interest again to
* the lowest-cost nexthop (except downstream) that is not previously used.
* If all nexthops have been used, the strategy starts over.
*/
class BestRouteStrategy2 : public Strategy
{
@@ -55,7 +55,7 @@ public:
static const Name STRATEGY_NAME;
private:
RetransmissionSuppression m_retransmissionSuppression;
RetxSuppressionExponential m_retxSuppression;
};
} // namespace fw
+8 -7
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,6 +29,7 @@ namespace nfd {
namespace fw {
const Name BroadcastStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/broadcast/%FD%01");
NFD_REGISTER_STRATEGY(BroadcastStrategy);
BroadcastStrategy::BroadcastStrategy(Forwarder& forwarder, const Name& name)
: Strategy(forwarder, name)
+8 -7
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.
@@ -33,6 +33,7 @@ NFD_LOG_INIT("ClientControlStrategy");
const Name
ClientControlStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/client-control/%FD%01");
NFD_REGISTER_STRATEGY(ClientControlStrategy);
ClientControlStrategy::ClientControlStrategy(Forwarder& forwarder, const Name& name)
: BestRouteStrategy(forwarder, name)
+42 -22
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,7 +26,7 @@
#include "forwarder.hpp"
#include "core/logger.hpp"
#include "core/random.hpp"
#include "available-strategies.hpp"
#include "strategy.hpp"
#include <boost/random/uniform_int_distribution.hpp>
namespace nfd {
@@ -91,23 +91,25 @@ Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
bool isPending = inRecords.begin() != inRecords.end();
if (!isPending) {
// CS lookup
const Data* csMatch = m_cs.find(interest);
if (csMatch != 0) {
const_cast<Data*>(csMatch)->setIncomingFaceId(FACEID_CONTENT_STORE);
// XXX should we lookup PIT for other Interests that also match csMatch?
// set PIT straggler timer
this->setStragglerTimer(pitEntry, true, csMatch->getFreshnessPeriod());
// goto outgoing Data pipeline
this->onOutgoingData(*csMatch, inFace);
return;
}
m_cs.find(interest,
bind(&Forwarder::onContentStoreHit, this, ref(inFace), pitEntry, _1, _2),
bind(&Forwarder::onContentStoreMiss, this, ref(inFace), pitEntry, _1));
}
else {
this->onContentStoreMiss(inFace, pitEntry, interest);
}
}
void
Forwarder::onContentStoreMiss(const Face& inFace,
shared_ptr<pit::Entry> pitEntry,
const Interest& interest)
{
NFD_LOG_DEBUG("onContentStoreMiss interest=" << interest.getName());
shared_ptr<Face> face = const_pointer_cast<Face>(inFace.shared_from_this());
// insert InRecord
pitEntry->insertOrUpdateInRecord(inFace.shared_from_this(), interest);
pitEntry->insertOrUpdateInRecord(face, interest);
// set PIT unsatisfy timer
this->setUnsatisfyTimer(pitEntry);
@@ -120,6 +122,24 @@ Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
cref(inFace), cref(interest), fibEntry, pitEntry));
}
void
Forwarder::onContentStoreHit(const Face& inFace,
shared_ptr<pit::Entry> pitEntry,
const Interest& interest,
const Data& data)
{
NFD_LOG_DEBUG("onContentStoreMiss interest=" << interest.getName());
const_pointer_cast<Data>(data.shared_from_this())->setIncomingFaceId(FACEID_CONTENT_STORE);
// XXX should we lookup PIT for other Interests that also match csMatch?
// set PIT straggler timer
this->setStragglerTimer(pitEntry, true, data.getFreshnessPeriod());
// goto outgoing Data pipeline
this->onOutgoingData(data, *const_pointer_cast<Face>(inFace.shared_from_this()));
}
void
Forwarder::onInterestLoop(Face& inFace, const Interest& interest,
shared_ptr<pit::Entry> pitEntry)
+11
View File
@@ -110,6 +110,17 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE: // pipelines
VIRTUAL_WITH_TESTS void
onIncomingInterest(Face& inFace, const Interest& interest);
/** \brief Content Store miss pipeline
*/
void
onContentStoreMiss(const Face& inFace, shared_ptr<pit::Entry> pitEntry, const Interest& interest);
/** \brief Content Store hit pipeline
*/
void
onContentStoreHit(const Face& inFace, shared_ptr<pit::Entry> pitEntry,
const Interest& interest, const Data& data);
/** \brief Interest loop pipeline
*/
VIRTUAL_WITH_TESTS void
+1
View File
@@ -31,6 +31,7 @@ namespace nfd {
namespace fw {
const Name NccStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/ncc/%FD%01");
NFD_REGISTER_STRATEGY(NccStrategy);
NccStrategy::NccStrategy(Forwarder& forwarder, const Name& name)
: Strategy(forwarder, name)
@@ -0,0 +1,97 @@
/* -*- 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 "retx-suppression-exponential.hpp"
namespace nfd {
namespace fw {
const RetxSuppressionExponential::Duration RetxSuppressionExponential::DEFAULT_INITIAL_INTERVAL =
time::milliseconds(1);
const float RetxSuppressionExponential::DEFAULT_MULTIPLIER = 2.0;
const RetxSuppressionExponential::Duration RetxSuppressionExponential::DEFAULT_MAX_INTERVAL =
time::milliseconds(250);
class RetxSuppressionExponential::PitInfo : public StrategyInfo
{
public:
static constexpr int
getTypeId()
{
return 1020;
}
explicit
PitInfo(const Duration& initialInterval)
: suppressionInterval(initialInterval)
{
}
public:
/** \brief if last transmission occurred within suppressionInterval,
* retransmission will be suppressed
*/
Duration suppressionInterval;
};
RetxSuppressionExponential::RetxSuppressionExponential(const Duration& initialInterval,
float multiplier,
const Duration& maxInterval)
: m_initialInterval(initialInterval)
, m_multiplier(multiplier)
, m_maxInterval(maxInterval)
{
BOOST_ASSERT(initialInterval > time::milliseconds::zero());
BOOST_ASSERT(multiplier >= 1.0);
BOOST_ASSERT(maxInterval >= initialInterval);
}
RetxSuppression::Result
RetxSuppressionExponential::decide(const Face& inFace, const Interest& interest,
pit::Entry& pitEntry) const
{
bool isNewPitEntry = !pitEntry.hasUnexpiredOutRecords();
if (isNewPitEntry) {
return NEW;
}
time::steady_clock::TimePoint lastOutgoing = this->getLastOutgoing(pitEntry);
time::steady_clock::TimePoint now = time::steady_clock::now();
time::steady_clock::Duration sinceLastOutgoing = now - lastOutgoing;
shared_ptr<PitInfo> pi = pitEntry.getOrCreateStrategyInfo<PitInfo>(m_initialInterval);
bool shouldSuppress = sinceLastOutgoing < pi->suppressionInterval;
if (shouldSuppress) {
return SUPPRESS;
}
pi->suppressionInterval = std::min(m_maxInterval,
time::duration_cast<Duration>(pi->suppressionInterval * m_multiplier));
return FORWARD;
}
} // namespace fw
} // namespace nfd
@@ -0,0 +1,78 @@
/* -*- 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_FW_RETX_SUPPRESSION_EXPONENTIAL_HPP
#define NFD_DAEMON_FW_RETX_SUPPRESSION_EXPONENTIAL_HPP
#include "retx-suppression.hpp"
namespace nfd {
namespace fw {
/** \brief a retransmission suppression decision algorithm that
* suppresses retransmissions using exponential backoff
*
* The i-th retransmission will be suppressed if the last transmission (out-record)
* occurred within MIN(initialInterval * multiplier^(i-1), maxInterval)
*/
class RetxSuppressionExponential : public RetxSuppression
{
public:
/** \brief time granularity
*/
typedef time::microseconds Duration;
explicit
RetxSuppressionExponential(const Duration& initialInterval = DEFAULT_INITIAL_INTERVAL,
float multiplier = DEFAULT_MULTIPLIER,
const Duration& maxInterval = DEFAULT_MAX_INTERVAL);
/** \brief determines whether Interest is a retransmission,
* and if so, whether it shall be forwarded or suppressed
*/
virtual Result
decide(const Face& inFace, const Interest& interest,
pit::Entry& pitEntry) const DECL_OVERRIDE;
public:
/** \brief StrategyInfo on pit::Entry
*/
class PitInfo;
public:
static const Duration DEFAULT_INITIAL_INTERVAL;
static const float DEFAULT_MULTIPLIER;
static const Duration DEFAULT_MAX_INTERVAL;
private:
const Duration m_initialInterval;
const float m_multiplier;
const Duration m_maxInterval;
};
} // namespace fw
} // namespace nfd
#endif // NFD_DAEMON_FW_RETX_SUPPRESSION_EXPONENTIAL_HPP
+56
View File
@@ -0,0 +1,56 @@
/* -*- 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 "retx-suppression-fixed.hpp"
namespace nfd {
namespace fw {
const time::milliseconds RetxSuppressionFixed::DEFAULT_MIN_RETX_INTERVAL(100);
RetxSuppressionFixed::RetxSuppressionFixed(const time::milliseconds& minRetxInterval)
: m_minRetxInterval(minRetxInterval)
{
BOOST_ASSERT(minRetxInterval > time::milliseconds::zero());
}
RetxSuppression::Result
RetxSuppressionFixed::decide(const Face& inFace, const Interest& interest,
pit::Entry& pitEntry) const
{
bool isNewPitEntry = !pitEntry.hasUnexpiredOutRecords();
if (isNewPitEntry) {
return NEW;
}
time::steady_clock::TimePoint lastOutgoing = this->getLastOutgoing(pitEntry);
time::steady_clock::TimePoint now = time::steady_clock::now();
time::steady_clock::Duration sinceLastOutgoing = now - lastOutgoing;
bool shouldSuppress = sinceLastOutgoing < m_minRetxInterval;
return shouldSuppress ? SUPPRESS : FORWARD;
}
} // namespace fw
} // namespace nfd
+60
View File
@@ -0,0 +1,60 @@
/* -*- 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_FW_RETX_SUPPRESSION_FIXED_HPP
#define NFD_DAEMON_FW_RETX_SUPPRESSION_FIXED_HPP
#include "retx-suppression.hpp"
namespace nfd {
namespace fw {
/** \brief a retransmission suppression decision algorithm that
* suppresses retransmissions within a fixed duration
*/
class RetxSuppressionFixed : public RetxSuppression
{
public:
explicit
RetxSuppressionFixed(const time::milliseconds& minRetxInterval = DEFAULT_MIN_RETX_INTERVAL);
/** \brief determines whether Interest is a retransmission,
* and if so, whether it shall be forwarded or suppressed
*/
virtual Result
decide(const Face& inFace, const Interest& interest,
pit::Entry& pitEntry) const DECL_OVERRIDE;
public:
static const time::milliseconds DEFAULT_MIN_RETX_INTERVAL;
private:
const time::milliseconds m_minRetxInterval;
};
} // namespace fw
} // namespace nfd
#endif // NFD_DAEMON_FW_RETX_SUPPRESSION_FIXED_HPP
@@ -23,24 +23,14 @@
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "retransmission-suppression.hpp"
#include "retx-suppression.hpp"
namespace nfd {
namespace fw {
/// \todo don't use fixed interval; make it adaptive or use exponential back-off #1913
const time::milliseconds RetransmissionSuppression::MIN_RETRANSMISSION_INTERVAL(100);
RetransmissionSuppression::Result
RetransmissionSuppression::decide(const Face& inFace, const Interest& interest,
const pit::Entry& pitEntry)
time::steady_clock::TimePoint
RetxSuppression::getLastOutgoing(const pit::Entry& pitEntry) const
{
bool isNewPitEntry = !pitEntry.hasUnexpiredOutRecords();
if (isNewPitEntry) {
return NEW;
}
// when was the last outgoing Interest?
const pit::OutRecordCollection& outRecords = pitEntry.getOutRecords();
pit::OutRecordCollection::const_iterator lastOutgoing = std::max_element(
outRecords.begin(), outRecords.end(),
@@ -49,10 +39,7 @@ RetransmissionSuppression::decide(const Face& inFace, const Interest& interest,
});
BOOST_ASSERT(lastOutgoing != outRecords.end()); // otherwise it's new PIT entry
time::steady_clock::TimePoint now = time::steady_clock::now();
time::steady_clock::Duration sinceLastOutgoing = now - lastOutgoing->getLastRenewed();
bool shouldSuppress = sinceLastOutgoing < MIN_RETRANSMISSION_INTERVAL;
return shouldSuppress ? SUPPRESS : FORWARD;
return lastOutgoing->getLastRenewed();
}
} // namespace fw
@@ -23,8 +23,8 @@
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NFD_DAEMON_FW_RETRANSMISSION_SUPPRESSION_HPP
#define NFD_DAEMON_FW_RETRANSMISSION_SUPPRESSION_HPP
#ifndef NFD_DAEMON_FW_RETX_SUPPRESSION_HPP
#define NFD_DAEMON_FW_RETX_SUPPRESSION_HPP
#include "strategy.hpp"
@@ -33,7 +33,7 @@ namespace fw {
/** \brief helper for consumer retransmission suppression
*/
class RetransmissionSuppression : noncopyable
class RetxSuppression : noncopyable
{
public:
enum Result {
@@ -53,14 +53,18 @@ public:
/** \brief determines whether Interest is a retransmission,
* and if so, whether it shall be forwarded or suppressed
*/
Result
decide(const Face& inFace, const Interest& interest, const pit::Entry& pitEntry);
virtual Result
decide(const Face& inFace, const Interest& interest, pit::Entry& pitEntry) const = 0;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
static const time::milliseconds MIN_RETRANSMISSION_INTERVAL;
protected:
/** \return last out-record time
* \pre pitEntry has one or more unexpired out-records
*/
time::steady_clock::TimePoint
getLastOutgoing(const pit::Entry& pitEntry) const;
};
} // namespace fw
} // namespace nfd
#endif // NFD_DAEMON_FW_RETRANSMISSION_SUPPRESSION_HPP
#endif // NFD_DAEMON_FW_RETX_SUPPRESSION_HPP
@@ -23,12 +23,8 @@
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "best-route-strategy.hpp"
#include "broadcast-strategy.hpp"
#include "client-control-strategy.hpp"
#include "ncc-strategy.hpp"
#include "strategy-registry.hpp"
#include "best-route-strategy2.hpp"
#include "access-strategy.hpp"
namespace nfd {
namespace fw {
@@ -39,25 +35,28 @@ makeDefaultStrategy(Forwarder& forwarder)
return make_shared<BestRouteStrategy2>(ref(forwarder));
}
template<typename S>
inline void
installStrategy(Forwarder& forwarder)
static std::map<Name, StrategyCreateFunc>&
getStrategyFactories()
{
StrategyChoice& strategyChoice = forwarder.getStrategyChoice();
if (!strategyChoice.hasStrategy(S::STRATEGY_NAME)) {
strategyChoice.install(make_shared<S>(ref(forwarder)));
}
static std::map<Name, StrategyCreateFunc> strategyFactories;
return strategyFactories;
}
void
registerStrategyImpl(const Name& strategyName, const StrategyCreateFunc& createFunc)
{
getStrategyFactories().insert({strategyName, createFunc});
}
void
installStrategies(Forwarder& forwarder)
{
installStrategy<BestRouteStrategy>(forwarder);
installStrategy<BroadcastStrategy>(forwarder);
installStrategy<ClientControlStrategy>(forwarder);
installStrategy<NccStrategy>(forwarder);
installStrategy<BestRouteStrategy2>(forwarder);
installStrategy<AccessStrategy>(forwarder);
StrategyChoice& sc = forwarder.getStrategyChoice();
for (const auto& pair : getStrategyFactories()) {
if (!sc.hasStrategy(pair.first, true)) {
sc.install(pair.second(forwarder));
}
}
}
} // namespace fw
+78
View File
@@ -0,0 +1,78 @@
/* -*- 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_FW_STRATEGY_REGISTRY_HPP
#define NFD_DAEMON_FW_STRATEGY_REGISTRY_HPP
#include "common.hpp"
namespace nfd {
class Forwarder;
namespace fw {
class Strategy;
shared_ptr<Strategy>
makeDefaultStrategy(Forwarder& forwarder);
void
installStrategies(Forwarder& forwarder);
typedef std::function<shared_ptr<Strategy>(Forwarder&)> StrategyCreateFunc;
void
registerStrategyImpl(const Name& strategyName, const StrategyCreateFunc& createFunc);
/** \brief registers a strategy to be installed later
*/
template<typename S>
void
registerStrategy()
{
registerStrategyImpl(S::STRATEGY_NAME,
[] (Forwarder& forwarder) { return make_shared<S>(ref(forwarder)); });
}
/** \brief registers a built-in strategy
*
* This macro should appear once in .cpp of each built-in strategy.
*/
#define NFD_REGISTER_STRATEGY(StrategyType) \
static class NfdAuto ## StrategyType ## StrategyRegistrationClass \
{ \
public: \
NfdAuto ## StrategyType ## StrategyRegistrationClass() \
{ \
::nfd::fw::registerStrategy<StrategyType>(); \
} \
} g_nfdAuto ## StrategyType ## StrategyRegistrationVariable
} // namespace fw
} // namespace nfd
#endif // NFD_DAEMON_FW_STRATEGY_REGISTRY_HPP
+8 -7
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,6 +27,7 @@
#define NFD_DAEMON_FW_STRATEGY_HPP
#include "forwarder.hpp"
#include "strategy-registry.hpp"
#include "table/measurements-accessor.hpp"
namespace nfd {
+165 -278
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.
@@ -23,153 +23,57 @@
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include <getopt.h>
#include <boost/filesystem.hpp>
#include "nfd.hpp"
#include "rib/nrd.hpp"
#include "version.hpp"
#include "core/logger.hpp"
#include "core/global-io.hpp"
#include "core/logger.hpp"
#include "core/privilege-helper.hpp"
#include "fw/forwarder.hpp"
#include "face/null-face.hpp"
#include "mgmt/internal-face.hpp"
#include "mgmt/fib-manager.hpp"
#include "mgmt/face-manager.hpp"
#include "mgmt/strategy-choice-manager.hpp"
#include "mgmt/status-server.hpp"
#include "core/config-file.hpp"
#include "mgmt/general-config-section.hpp"
#include "mgmt/tables-config-section.hpp"
#include <string.h>
#include <boost/filesystem.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/program_options/parsers.hpp>
// boost::thread is used instead of std::thread to guarantee proper cleanup of thread local storage,
// see http://www.boost.org/doc/libs/1_48_0/doc/html/thread/thread_local_storage.html
#include <boost/thread.hpp>
#include <atomic>
#include <condition_variable>
namespace nfd {
NFD_LOG_INIT("NFD");
struct ProgramOptions
{
bool showUsage;
bool showVersion;
bool showModules;
std::string config;
};
class Nfd : noncopyable
/** \brief Executes NFD with RIB manager
*
* NFD (main forwarding procedure) and RIB manager execute in two different threads.
* Each thread has its own instances global io_service and global scheduler.
*
* When either of the daemons fails, execution of non-failed daemon will be terminated as
* well. In other words, when NFD fails, RIB manager will be terminated; when RIB manager
* fails, NFD will be terminated.
*/
class NfdRunner : noncopyable
{
public:
explicit
Nfd(const std::string& configFile)
: m_configFile(configFile)
, m_originalStreamBuf(0)
NfdRunner(const std::string& configFile)
: m_nfd(configFile, m_nfdKeyChain)
, m_configFile(configFile)
, m_terminationSignalSet(getGlobalIoService())
, m_reloadSignalSet(getGlobalIoService())
{
}
m_terminationSignalSet.add(SIGINT);
m_terminationSignalSet.add(SIGTERM);
m_terminationSignalSet.async_wait(bind(&NfdRunner::terminate, this, _1, _2));
~Nfd()
{
if (static_cast<bool>(m_originalStreamBuf)) {
std::clog.rdbuf(m_originalStreamBuf);
}
}
void
initialize()
{
initializeLogging();
m_forwarder = make_shared<Forwarder>();
initializeManagement();
m_forwarder->getFaceTable().addReserved(make_shared<NullFace>(), FACEID_NULL);
m_forwarder->getFaceTable().addReserved(
make_shared<NullFace>(FaceUri("contentstore://")), FACEID_CONTENT_STORE);
PrivilegeHelper::drop();
}
void
initializeLogging()
{
ConfigFile config(&ConfigFile::ignoreUnknownSection);
LoggerFactory::getInstance().setConfigFile(config);
config.parse(m_configFile, true);
config.parse(m_configFile, false);
}
class IgnoreRibAndLogSections
{
public:
void
operator()(const std::string& filename,
const std::string& sectionName,
const ConfigSection& section,
bool isDryRun)
{
// Ignore "log" and sections beginning with "rib_" (intended for rib manager),
// but raise an error if we're missing a handler for an NFD section.
if (sectionName.find("rib") == 0 || sectionName == "log")
{
// do nothing
}
else
{
// missing NFD section
ConfigFile::throwErrorOnUnknownSection(filename, sectionName, section, isDryRun);
}
}
};
void
initializeManagement()
{
m_internalFace = make_shared<InternalFace>();
m_fibManager = make_shared<FibManager>(ref(m_forwarder->getFib()),
bind(&Forwarder::getFace, m_forwarder.get(), _1),
m_internalFace,
ndn::ref(m_keyChain));
m_faceManager = make_shared<FaceManager>(ref(m_forwarder->getFaceTable()),
m_internalFace,
ndn::ref(m_keyChain));
m_strategyChoiceManager =
make_shared<StrategyChoiceManager>(ref(m_forwarder->getStrategyChoice()),
m_internalFace,
ndn::ref(m_keyChain));
m_statusServer = make_shared<StatusServer>(m_internalFace,
ref(*m_forwarder),
ndn::ref(m_keyChain));
ConfigFile config((IgnoreRibAndLogSections()));
general::setConfigFile(config);
TablesConfigSection tablesConfig(m_forwarder->getCs(),
m_forwarder->getPit(),
m_forwarder->getFib(),
m_forwarder->getStrategyChoice(),
m_forwarder->getMeasurements());
tablesConfig.setConfigFile(config);
m_internalFace->getValidator().setConfigFile(config);
m_forwarder->getFaceTable().addReserved(m_internalFace, FACEID_INTERNAL_FACE);
m_faceManager->setConfigFile(config);
// parse config file
config.parse(m_configFile, true);
config.parse(m_configFile, false);
tablesConfig.ensureTablesAreConfigured();
// add FIB entry for NFD Management Protocol
shared_ptr<fib::Entry> entry = m_forwarder->getFib().insert("/localhost/nfd").first;
entry->addNextHop(m_internalFace, 0);
m_reloadSignalSet.add(SIGHUP);
m_reloadSignalSet.async_wait(bind(&NfdRunner::reload, this, _1, _2));
}
static void
@@ -192,137 +96,127 @@ public:
static void
printModules(std::ostream& os)
{
using namespace std;
os << "Available logging modules: \n";
list<string> modules(LoggerFactory::getInstance().getModules());
for (list<string>::const_iterator i = modules.begin(); i != modules.end(); ++i)
{
os << *i << "\n";
}
for (const auto& module : LoggerFactory::getInstance().getModules()) {
os << module << "\n";
}
}
static bool
parseCommandLine(int argc, char** argv, ProgramOptions& options)
void
initialize()
{
options.showUsage = false;
options.showVersion = false;
options.showModules = false;
options.config = DEFAULT_CONFIG_FILE;
m_nfd.initialize();
}
while (true) {
int optionIndex = 0;
static ::option longOptions[] = {
{ "help" , no_argument , 0, 0 },
{ "modules", no_argument , 0, 0 },
{ "config" , required_argument, 0, 0 },
{ "version", no_argument , 0, 0 },
{ 0 , 0 , 0, 0 }
};
int c = getopt_long_only(argc, argv, "", longOptions, &optionIndex);
if (c == -1)
break;
int
run()
{
/** \brief return value
* A non-zero value is assigned when either NFD or RIB manager (running in a separate
* thread) fails.
*/
std::atomic_int retval(0);
switch (c) {
case 0:
switch (optionIndex) {
case 0: // help
options.showUsage = true;
break;
case 1: // modules
options.showModules = true;
break;
case 2: // config
options.config = ::optarg;
break;
case 3: // version
options.showVersion = true;
break;
default:
return false;
boost::asio::io_service* const mainIo = &getGlobalIoService();
boost::asio::io_service* nrdIo = nullptr;
// Mutex and conditional variable to implement synchronization between main and RIB manager
// threads:
// - to block main thread until RIB manager thread starts and initializes nrdIo (to allow
// stopping it later)
std::mutex m;
std::condition_variable cv;
std::string configFile = this->m_configFile; // c++11 lambda cannot capture member variables
boost::thread nrdThread([configFile, &retval, &nrdIo, mainIo, &cv, &m] {
{
std::lock_guard<std::mutex> lock(m);
nrdIo = &getGlobalIoService();
BOOST_ASSERT(nrdIo != mainIo);
}
break;
cv.notify_all(); // notify that nrdIo has been assigned
try {
ndn::KeyChain nrdKeyChain;
// must be created inside a separate thread
rib::Nrd nrd(configFile, nrdKeyChain);
nrd.initialize();
getGlobalIoService().run(); // nrdIo is not thread-safe to use here
}
catch (const std::exception& e) {
NFD_LOG_FATAL(e.what());
retval = 6;
mainIo->stop();
}
{
std::lock_guard<std::mutex> lock(m);
nrdIo = nullptr;
}
});
{
// Wait to guarantee that nrdIo is properly initialized, so it can be used to terminate
// RIB manager thread.
std::unique_lock<std::mutex> lock(m);
cv.wait(lock, [&nrdIo] { return nrdIo != nullptr; });
}
try {
mainIo->run();
}
catch (const std::exception& e) {
NFD_LOG_FATAL(e.what());
retval = 4;
}
catch (const PrivilegeHelper::Error& e) {
NFD_LOG_FATAL(e.what());
retval = 5;
}
{
// nrdIo is guaranteed to be alive at this point
std::lock_guard<std::mutex> lock(m);
if (nrdIo != nullptr) {
nrdIo->stop();
nrdIo = nullptr;
}
}
return true;
nrdThread.join();
return retval;
}
void
terminate(const boost::system::error_code& error,
int signalNo,
boost::asio::signal_set& signalSet)
terminate(const boost::system::error_code& error, int signalNo)
{
if (error)
return;
if (signalNo == SIGINT ||
signalNo == SIGTERM)
{
getGlobalIoService().stop();
NFD_LOG_INFO("Caught signal '" << strsignal(signalNo) << "', exiting...");
}
else
{
signalSet.async_wait(bind(&Nfd::terminate, this, _1, _2, ref(signalSet)));
}
NFD_LOG_INFO("Caught signal '" << ::strsignal(signalNo) << "', exiting...");
getGlobalIoService().stop();
}
void
reload(const boost::system::error_code& error,
int signalNo,
boost::asio::signal_set& signalSet)
reload(const boost::system::error_code& error, int signalNo)
{
if (error)
return;
NFD_LOG_INFO("Caught signal '" << strsignal(signalNo));
NFD_LOG_INFO("Caught signal '" << ::strsignal(signalNo) << "', reloading...");
m_nfd.reloadConfigFile();
////////////////////////
// Reload config file //
////////////////////////
// Logging
initializeLogging();
/// \todo Reopen log file
// Other stuff
ConfigFile config((IgnoreRibAndLogSections()));
general::setConfigFile(config);
TablesConfigSection tablesConfig(m_forwarder->getCs(),
m_forwarder->getPit(),
m_forwarder->getFib(),
m_forwarder->getStrategyChoice(),
m_forwarder->getMeasurements());
tablesConfig.setConfigFile(config);
m_internalFace->getValidator().setConfigFile(config);
m_faceManager->setConfigFile(config);
config.parse(m_configFile, false);
////////////////////////
signalSet.async_wait(bind(&Nfd::reload, this, _1, _2, ref(signalSet)));
m_reloadSignalSet.async_wait(bind(&NfdRunner::reload, this, _1, _2));
}
private:
std::string m_configFile;
ndn::KeyChain m_nfdKeyChain;
Nfd m_nfd;
std::string m_configFile;
shared_ptr<Forwarder> m_forwarder;
shared_ptr<InternalFace> m_internalFace;
shared_ptr<FibManager> m_fibManager;
shared_ptr<FaceManager> m_faceManager;
shared_ptr<StrategyChoiceManager> m_strategyChoiceManager;
shared_ptr<StatusServer> m_statusServer;
shared_ptr<std::ofstream> m_logFile;
std::basic_streambuf<char>* m_originalStreamBuf;
ndn::KeyChain m_keyChain;
boost::asio::signal_set m_terminationSignalSet;
boost::asio::signal_set m_reloadSignalSet;
};
} // namespace nfd
@@ -332,34 +226,50 @@ main(int argc, char** argv)
{
using namespace nfd;
ProgramOptions options;
bool isCommandLineValid = Nfd::parseCommandLine(argc, argv, options);
if (!isCommandLineValid) {
Nfd::printUsage(std::cerr, argv[0]);
namespace po = boost::program_options;
po::options_description description;
std::string configFile = DEFAULT_CONFIG_FILE;
description.add_options()
("help,h", "print this help message")
("version,V", "print version and exit")
("modules,m", "list available logging modules")
("config,c", po::value<std::string>(&configFile), "path to configuration file")
;
po::variables_map vm;
try {
po::store(po::command_line_parser(argc, argv).options(description).run(), vm);
po::notify(vm);
}
catch (const std::exception& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
NfdRunner::printUsage(std::cerr, argv[0]);
return 1;
}
if (options.showUsage) {
Nfd::printUsage(std::cout, argv[0]);
if (vm.count("help") > 0) {
NfdRunner::printUsage(std::cout, argv[0]);
return 0;
}
if (options.showVersion) {
if (vm.count("version") > 0) {
std::cout << NFD_VERSION_BUILD_STRING << std::endl;
return 0;
}
if (options.showModules) {
Nfd::printModules(std::cout);
if (vm.count("modules") > 0) {
NfdRunner::printModules(std::cout);
return 0;
}
Nfd nfdInstance(options.config);
NfdRunner runner(configFile);
try {
nfdInstance.initialize();
runner.initialize();
}
catch (boost::filesystem::filesystem_error& e) {
catch (const boost::filesystem::filesystem_error& e) {
if (e.code() == boost::system::errc::permission_denied) {
NFD_LOG_FATAL("Permissions denied for " << e.path1() << ". " <<
argv[0] << " should be run as superuser");
@@ -381,28 +291,5 @@ main(int argc, char** argv)
return 3;
}
boost::asio::signal_set terminationSignalSet(getGlobalIoService());
terminationSignalSet.add(SIGINT);
terminationSignalSet.add(SIGTERM);
terminationSignalSet.async_wait(bind(&Nfd::terminate, &nfdInstance, _1, _2,
ref(terminationSignalSet)));
boost::asio::signal_set reloadSignalSet(getGlobalIoService());
reloadSignalSet.add(SIGHUP);
reloadSignalSet.async_wait(bind(&Nfd::reload, &nfdInstance, _1, _2,
ref(reloadSignalSet)));
try {
getGlobalIoService().run();
}
catch (const std::exception& e) {
NFD_LOG_FATAL(e.what());
return 4;
}
catch (const PrivilegeHelper::Error& e) {
NFD_LOG_FATAL(e.what());
return 5;
}
return 0;
return runner.run();
}
-8
View File
@@ -24,8 +24,6 @@
*/
#include "channel-status-publisher.hpp"
#include "core/logger.hpp"
#include "face/protocol-factory.hpp"
#include "face/channel.hpp"
@@ -33,9 +31,6 @@
namespace nfd {
NFD_LOG_INIT("ChannelStatusPublisher");
ChannelStatusPublisher::ChannelStatusPublisher(const FactoryMap& factories,
AppFace& face,
const Name& prefix,
@@ -43,13 +38,10 @@ ChannelStatusPublisher::ChannelStatusPublisher(const FactoryMap& factories,
: SegmentPublisher(face, prefix, keyChain)
, m_factories(factories)
{
}
ChannelStatusPublisher::~ChannelStatusPublisher()
{
}
size_t
+3 -3
View File
@@ -380,8 +380,8 @@ FaceManager::processSectionUdp(const ConfigSection& configSection,
// udp
// {
// port 6363 ; UDP unicast port number
// idle_timeout 30 ; idle time (seconds) before closing a UDP unicast face
// keep_alive_interval 25; interval (seconds) between keep-alive refreshes
// idle_timeout 600 ; idle time (seconds) before closing a UDP unicast face
// keep_alive_interval 25 ; interval (seconds) between keep-alive refreshes
// ; NFD creates one UDP multicast face per NIC
// mcast yes ; set to 'no' to disable UDP multicast, default 'yes'
@@ -392,7 +392,7 @@ FaceManager::processSectionUdp(const ConfigSection& configSection,
std::string port = "6363";
bool enableV4 = true;
bool enableV6 = true;
size_t timeout = 30;
size_t timeout = 600;
size_t keepAliveInterval = 25;
bool useMcast = true;
std::string mcastGroup = "224.0.23.170";
+1 -5
View File
@@ -24,16 +24,12 @@
**/
#include "face-query-status-publisher.hpp"
#include "core/logger.hpp"
#include <boost/range/adaptor/reversed.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <ndn-cxx/management/nfd-face-status.hpp>
namespace nfd {
NFD_LOG_INIT("FaceQueryStatusPublisher");
FaceQueryStatusPublisher::FaceQueryStatusPublisher(const FaceTable& faceTable,
AppFace& face,
const Name& prefix,
+1 -8
View File
@@ -23,17 +23,13 @@
**/
#include "face-status-publisher.hpp"
#include "core/logger.hpp"
#include "fw/face-table.hpp"
#include <boost/range/adaptor/reversed.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <ndn-cxx/management/nfd-face-status.hpp>
namespace nfd {
NFD_LOG_INIT("FaceStatusPublisher");
FaceStatusPublisher::FaceStatusPublisher(const FaceTable& faceTable,
AppFace& face,
const Name& prefix,
@@ -41,13 +37,10 @@ FaceStatusPublisher::FaceStatusPublisher(const FaceTable& faceTable,
: SegmentPublisher(face, prefix, keyChain)
, m_faceTable(faceTable)
{
}
FaceStatusPublisher::~FaceStatusPublisher()
{
}
size_t
+1 -1
View File
@@ -79,9 +79,9 @@ FibEnumerationPublisher::generate(ndn::EncodingBuffer& outBuffer)
totalLength += fibEntryLength;
}
NFD_LOG_DEBUG("generate: Total length = " << totalLength);
return totalLength;
}
} // namespace nfd
@@ -24,16 +24,12 @@
**/
#include "strategy-choice-publisher.hpp"
#include "core/logger.hpp"
#include "table/strategy-choice.hpp"
#include <ndn-cxx/management/nfd-strategy-choice.hpp>
namespace nfd {
NFD_LOG_INIT("StrategyChoicePublisher");
StrategyChoicePublisher::StrategyChoicePublisher(const StrategyChoice& strategyChoice,
AppFace& face,
const Name& prefix,
@@ -41,12 +37,10 @@ StrategyChoicePublisher::StrategyChoicePublisher(const StrategyChoice& strategyC
: SegmentPublisher(face, prefix, keyChain)
, m_strategyChoice(strategyChoice)
{
}
StrategyChoicePublisher::~StrategyChoicePublisher()
{
}
size_t
+192
View File
@@ -0,0 +1,192 @@
/* -*- 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 "nfd.hpp"
#include "core/logger-factory.hpp"
#include "core/privilege-helper.hpp"
#include "fw/forwarder.hpp"
#include "face/null-face.hpp"
#include "mgmt/internal-face.hpp"
#include "mgmt/fib-manager.hpp"
#include "mgmt/face-manager.hpp"
#include "mgmt/strategy-choice-manager.hpp"
#include "mgmt/status-server.hpp"
#include "core/config-file.hpp"
#include "mgmt/general-config-section.hpp"
#include "mgmt/tables-config-section.hpp"
namespace nfd {
static const std::string INTERNAL_CONFIG = "internal://nfd.conf";
Nfd::Nfd(const std::string& configFile, ndn::KeyChain& keyChain)
: m_configFile(configFile)
, m_keyChain(keyChain)
{
}
Nfd::Nfd(const ConfigSection& config, ndn::KeyChain& keyChain)
: m_configSection(config)
, m_keyChain(keyChain)
{
}
Nfd::~Nfd()
{
// It is necessary to explicitly define the destructor, because some member variables (e.g.,
// unique_ptr<Forwarder>) are forward-declared, but implicitly declared destructor requires
// complete types for all members when instantiated.
}
void
Nfd::initialize()
{
initializeLogging();
m_forwarder.reset(new Forwarder());
initializeManagement();
m_forwarder->getFaceTable().addReserved(make_shared<NullFace>(), FACEID_NULL);
m_forwarder->getFaceTable().addReserved(make_shared<NullFace>(FaceUri("contentstore://")),
FACEID_CONTENT_STORE);
PrivilegeHelper::drop();
}
void
Nfd::initializeLogging()
{
ConfigFile config(&ConfigFile::ignoreUnknownSection);
LoggerFactory::getInstance().setConfigFile(config);
if (!m_configFile.empty()) {
config.parse(m_configFile, true);
config.parse(m_configFile, false);
}
else {
config.parse(m_configSection, true, INTERNAL_CONFIG);
config.parse(m_configSection, false, INTERNAL_CONFIG);
}
}
static inline void
ignoreRibAndLogSections(const std::string& filename, const std::string& sectionName,
const ConfigSection& section, bool isDryRun)
{
// Ignore "log" and "rib" sections, but raise an error if we're missing a
// handler for an NFD section.
if (sectionName == "rib" || sectionName == "log") {
// do nothing
}
else {
// missing NFD section
ConfigFile::throwErrorOnUnknownSection(filename, sectionName, section, isDryRun);
}
}
void
Nfd::initializeManagement()
{
m_internalFace = make_shared<InternalFace>();
m_fibManager.reset(new FibManager(m_forwarder->getFib(),
bind(&Forwarder::getFace, m_forwarder.get(), _1),
m_internalFace, m_keyChain));
m_faceManager.reset(new FaceManager(m_forwarder->getFaceTable(), m_internalFace, m_keyChain));
m_strategyChoiceManager.reset(new StrategyChoiceManager(m_forwarder->getStrategyChoice(),
m_internalFace, m_keyChain));
m_statusServer.reset(new StatusServer(m_internalFace, *m_forwarder, m_keyChain));
ConfigFile config(&ignoreRibAndLogSections);
general::setConfigFile(config);
TablesConfigSection tablesConfig(m_forwarder->getCs(),
m_forwarder->getPit(),
m_forwarder->getFib(),
m_forwarder->getStrategyChoice(),
m_forwarder->getMeasurements());
tablesConfig.setConfigFile(config);
m_internalFace->getValidator().setConfigFile(config);
m_forwarder->getFaceTable().addReserved(m_internalFace, FACEID_INTERNAL_FACE);
m_faceManager->setConfigFile(config);
// parse config file
if (!m_configFile.empty()) {
config.parse(m_configFile, true);
config.parse(m_configFile, false);
}
else {
config.parse(m_configSection, true, INTERNAL_CONFIG);
config.parse(m_configSection, false, INTERNAL_CONFIG);
}
tablesConfig.ensureTablesAreConfigured();
// add FIB entry for NFD Management Protocol
shared_ptr<fib::Entry> entry = m_forwarder->getFib().insert("/localhost/nfd").first;
entry->addNextHop(m_internalFace, 0);
}
void
Nfd::reloadConfigFile()
{
// Logging
initializeLogging();
/// \todo Reopen log file
// Other stuff
ConfigFile config(&ignoreRibAndLogSections);
general::setConfigFile(config);
TablesConfigSection tablesConfig(m_forwarder->getCs(),
m_forwarder->getPit(),
m_forwarder->getFib(),
m_forwarder->getStrategyChoice(),
m_forwarder->getMeasurements());
tablesConfig.setConfigFile(config);
m_internalFace->getValidator().setConfigFile(config);
m_faceManager->setConfigFile(config);
if (!m_configFile.empty()) {
config.parse(m_configFile, false);
}
else {
config.parse(m_configSection, false, INTERNAL_CONFIG);
}
}
} // namespace nfd
+106
View File
@@ -0,0 +1,106 @@
/* -*- 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_NFD_HPP
#define NFD_DAEMON_NFD_HPP
#include "common.hpp"
#include "core/config-file.hpp"
#include <ndn-cxx/security/key-chain.hpp>
namespace nfd {
class Forwarder;
class InternalFace;
class FibManager;
class FaceManager;
class StrategyChoiceManager;
class StatusServer;
/**
* \brief Class representing NFD instance
* This class can be used to initialize all components of NFD
*/
class Nfd : noncopyable
{
public:
/**
* \brief Create NFD instance using absolute or relative path to \p configFile
*/
Nfd(const std::string& configFile, ndn::KeyChain& keyChain);
/**
* \brief Create NFD instance using a parsed ConfigSection \p config
* This version of the constructor is more appropriate for integrated environments,
* such as NS-3 or android.
* \note When using this version of the constructor, error messages will include
* "internal://nfd.conf" when referring to configuration errors.
*/
Nfd(const ConfigSection& config, ndn::KeyChain& keyChain);
/**
* \brief Destructor
*/
~Nfd();
/**
* \brief Perform initialization of NFD instance
* After initialization, NFD instance can be started by invoking run on globalIoService
*/
void
initialize();
/**
* \brief Reload configuration file and apply update (if any)
*/
void
reloadConfigFile();
private:
void
initializeLogging();
void
initializeManagement();
private:
std::string m_configFile;
ConfigSection m_configSection;
unique_ptr<Forwarder> m_forwarder;
shared_ptr<InternalFace> m_internalFace;
unique_ptr<FibManager> m_fibManager;
unique_ptr<FaceManager> m_faceManager;
unique_ptr<StrategyChoiceManager> m_strategyChoiceManager;
unique_ptr<StatusServer> m_statusServer;
ndn::KeyChain& m_keyChain;
};
} // namespace nfd
#endif // NFD_DAEMON_NFD_HPP
-89
View File
@@ -1,89 +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/>.
*
* \author Ilya Moiseenko <http://ilyamoiseenko.com/>
* \author Junxiao Shi <http://www.cs.arizona.edu/people/shijunxiao/>
* \author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
*/
#ifndef NFD_DAEMON_TABLE_CS_SKIP_LIST_ENTRY_HPP
#define NFD_DAEMON_TABLE_CS_SKIP_LIST_ENTRY_HPP
#include "common.hpp"
#include "cs-entry.hpp"
namespace nfd {
namespace cs {
namespace skip_list {
/** \brief represents an entry in a CS with skip list implementation
*/
class Entry : public cs::Entry
{
public:
typedef std::map<int, std::list<Entry*>::iterator > LayerIterators;
Entry() = default;
/** \brief releases reference counts on shared objects
*/
void
release();
/** \brief saves the iterator pointing to the CS entry on a specific layer of skip list
*/
void
setIterator(int layer, const LayerIterators::mapped_type& layerIterator);
/** \brief removes the iterator pointing to the CS entry on a specific layer of skip list
*/
void
removeIterator(int layer);
/** \brief returns the table containing <layer, iterator> pairs.
*/
const LayerIterators&
getIterators() const;
private:
/** \brief prints <layer, iterator> pairs.
*/
void
printIterators() const;
private:
LayerIterators m_layerIterators;
};
inline const Entry::LayerIterators&
Entry::getIterators() const
{
return m_layerIterators;
}
} // namespace skip_list
} // namespace cs
} // namespace nfd
#endif // NFD_DAEMON_TABLE_CS_SKIP_LIST_ENTRY_HPP
+20 -4
View File
@@ -63,6 +63,16 @@ Cs::insert(const Data& data, bool isUnsolicited)
{
NFD_LOG_DEBUG("insert " << data.getName());
// recognize CachingPolicy
using ndn::nfd::LocalControlHeader;
const LocalControlHeader& lch = data.getLocalControlHeader();
if (lch.hasCachingPolicy()) {
LocalControlHeader::CachingPolicy policy = lch.getCachingPolicy();
if (policy == LocalControlHeader::CachingPolicy::NO_CACHE) {
return false;
}
}
bool isNewEntry = false; TableIt it;
// use .insert because gcc46 does not support .emplace
std::tie(it, isNewEntry) = m_table.insert(EntryImpl(data.shared_from_this(), isUnsolicited));
@@ -87,9 +97,14 @@ Cs::insert(const Data& data, bool isUnsolicited)
return true;
}
const Data*
Cs::find(const Interest& interest) const
void
Cs::find(const Interest& interest,
const HitCallback& hitCallback,
const MissCallback& missCallback) const
{
BOOST_ASSERT(static_cast<bool>(hitCallback));
BOOST_ASSERT(static_cast<bool>(missCallback));
const Name& prefix = interest.getName();
bool isRightmost = interest.getChildSelector() == 1;
NFD_LOG_DEBUG("find " << prefix << (isRightmost ? " R" : " L"));
@@ -110,10 +125,11 @@ Cs::find(const Interest& interest) const
if (match == last) {
NFD_LOG_DEBUG(" no-match");
return nullptr;
missCallback(interest);
return;
}
NFD_LOG_DEBUG(" matching " << match->getName());
return &match->getData();
hitCallback(interest, match->getData());
}
TableIt
+12 -2
View File
@@ -68,10 +68,20 @@ public:
bool
insert(const Data& data, bool isUnsolicited = false);
typedef std::function<void(const Interest&, const Data& data)> HitCallback;
typedef std::function<void(const Interest&)> MissCallback;
/** \brief finds the best matching Data packet
* \param interest the Interest for lookup
* \param hitCallback a callback if a match is found; must not be empty
* \param missCallback a callback if there's no match; must not be empty
* \note A lookup invokes either callback exactly once.
* The callback may be invoked either before or after find() returns
*/
const Data*
find(const Interest& interest) const;
void
find(const Interest& interest,
const HitCallback& hitCallback,
const MissCallback& missCallback) const;
void
erase(const Name& exactName)
+3 -3
View File
@@ -123,7 +123,7 @@ DeadNonceList::mark()
size_t nMarks = this->countMarks();
m_actualMarkCounts.insert(nMarks);
NFD_LOG_DEBUG("mark nMarks=" << nMarks);
NFD_LOG_TRACE("mark nMarks=" << nMarks);
scheduler::schedule(m_markInterval, bind(&DeadNonceList::mark, this));
}
@@ -138,13 +138,13 @@ DeadNonceList::adjustCapacity()
// all counts are above expected count, adjust down
m_capacity = std::max(MIN_CAPACITY,
static_cast<size_t>(m_capacity * CAPACITY_DOWN));
NFD_LOG_DEBUG("adjustCapacity DOWN capacity=" << m_capacity);
NFD_LOG_TRACE("adjustCapacity DOWN capacity=" << m_capacity);
}
else if (equalRange.first == m_actualMarkCounts.end()) {
// all counts are below expected count, adjust up
m_capacity = std::min(MAX_CAPACITY,
static_cast<size_t>(m_capacity * CAPACITY_UP));
NFD_LOG_DEBUG("adjustCapacity UP capacity=" << m_capacity);
NFD_LOG_TRACE("adjustCapacity UP capacity=" << m_capacity);
}
m_actualMarkCounts.clear();
+147 -3
View File
@@ -3,12 +3,155 @@
NFD Release Notes
=================
NFD version 0.3.2 (changes since version 0.3.1)
+++++++++++++++++++++++++++++++++++++++++++++++
Release date: May 12, 2015
New features:
^^^^^^^^^^^^^
- **Tables**
* Change lookup API to allow async implementations of ContentStore (:issue:`2411`)
- **Management**
* Perform FIB updates before modifying RIB (:issue:`1941`)
Updates and bug fixes:
^^^^^^^^^^^^^^^^^^^^^^
- **Documentation**
* Update planned Features: face enhancements (:issue:`2617`)
* Updated NFD's developer guide to reflect new changes and adding a new section on
NFD/ndn-cxx unit testing
- **Face**
* Refactor channel acceptors to avoid use of shared pointers (:issue:`2613`)
* Refactor code to avoid deprecated `Block::fromBuffer` overloads (:issue:`2553`)
* Refactor code to use move semantics for sockets where possible (:issue:`2613`)
* Switch to non-throwing version of websocketpp APIs (:issue:`2630`)
- **Forwarding**
* Extend measurements lifetime in AccessStrategy (:issue:`2452`)
- **Management**
* Stop removed namespace from inheriting ancestor route (:issue:`2757`)
* Fix TestFibUpdates/EraseFace on Ubuntu 14.04 32-bit (:issue:`2697`)
- **Tools**
* Fix hanging of `nfdc` on wrong input (:issue:`2690`)
- **Build**
* Make build scripts compatible with Python 3 (:issue:`2625`)
* Get rid of the last use of ndn::dns in NFD (:issue:`2422`)
* Update waf build system to version 1.8.9 (:issue:`2209`, :issue:`2657`, :issue:`2792`)
* Tweak default pkg-config search paths (:issue:`2711`)
* Use C version of snprintf (:issue:`2299`)
* Emulate `std::to_string` when it is missing (:issue:`2299`)
* Fix several "defined but not used" warnings with gcc-5 (:issue:`2767`)
* Disable precompiled headers on OS X with clang < 6.1.0 (:issue:`2804`)
****************************************************************************
NFD version 0.3.1 (changes since version 0.3.0)
-----------------------------------------------
Release date: March 3, 2015
New features:
^^^^^^^^^^^^^
- ``nfd`` and ``nrd`` daemons are now merged into a single process using separate threads
(:issue:`2489`)
- **Core**
- Extend ConfigFile to support passing a parsed ConfigSection (:issue:`2495`)
- Allow customization of Logger and LoggerFactory (:issue:`2433`)
- Make global io_service, scheduler, and global random generator thread-local, and logger
thread-safe (:issue:`2489`)
- **Forwarding**
- Introduce exponential back-off interest retransmission suppression mechanism and enable
its use in the best-route strategy (:issue:`1913`)
- Strategies are now registered with a macro, making it simpler to introduce new strategies
to NFD codebase (:issue:`2410`)
- **Tables**
- ContentStore now recognizes CachingPolicy-NoCache from LocalControlHeader (:issue:`2185`)
Updates and bug fixes:
^^^^^^^^^^^^^^^^^^^^^^
- **Faces**
- Remove Tcp|UdpChannel::connect overloads that perform DNS resolution (:issue:`2422`)
- Properly handle error conditions in UdpChannel::newPeer (:issue:`2516`)
- Fix inconsistency of UDP face timeouts in sample `nfd.conf` and actual defaults
(:issue:`2473`)
- Introduce Face-specific logging macros (:issue:`2450`)
- Refactor handling of LinkType face trait and fix FaceStatus reporting: the link type was
not properly propagated (:issue:`2563`)
- Avoid exceptions in NDNLP PartialMessageStore (:issue:`2261`)
- Update websocketpp to version 0.5.1
- **Tables**
- Reduce priority of DeadNonceList log messages from DEBUG to TRACE
- **Management**
- Change register/unregister logging in RibManager to INFO level (:issue:`2547`)
- **Tools**
- Change prefix for :ref:`the local hub prefix discovery <local-prefix-discovery>` to be
under ``/localhop/nfd`` (:issue:`2479`, :issue:`2512`)
- **Tests**
- Change naming conventions for unit test files and test suite names (:issue:`2497`)
- Fix segfault in TableNameTree test suite when all test logs are enabled (:issue:`2564`)
****************************************************************************
NFD version 0.3.0 (changes since version 0.2.0)
-----------------------------------------------
Release date: February 2, 2015
New features:
^^^^^^^^^^^^^
@@ -472,8 +615,9 @@ Planned Functions and Features for Next Releases
For congestion control
- Face enhancements
Add fragmentation support for Ethernet face, may add support for new types such as
WiFi direct and WebSockets.
Add faces for new underlying protocols such as WiFi direct.
Introduce the concept of "permanent faces" that can survive socket errors.
Design a new hop-by-hop header that supports fragmentation, reliability improvement, etc.
- Tables
Experiment and evaluate different data structures and algorithms.
+1 -1
View File
@@ -34,7 +34,7 @@ NFD Documentation
**Additional documentation**
* `NFD Developer's Guide <http://named-data.net/wp-content/uploads/2014/07/NFD-developer-guide.pdf>`_
* `NFD Developer's Guide <http://named-data.net/techreport/ndn-0021-3-nfd-developer-guide.pdf>`_
A comprehensive guide to the design and implementation of NFD. The developer's guide also contains
suggestions and hints for anyone wanting to modify or extend NFD.
+3 -3
View File
@@ -6,13 +6,13 @@ Discover local hub prefix
Some applications need to discover prefix(es) under which they can publish data
/ which Interests local hub will be able to forward down to the application.
In order to discover that, applications need to send an interest for
``/localhop/ndn-autoconf/routable-prefixes`` prefix. Response data to the
``/localhop/nfd/rib/routable-prefixes`` prefix. Response data to the
interest contains a list of prefixes and should be encoded as:
::
Response ::= DATA-TYPE TLV-LENGTH
Name (= /localhop/ndn-autoconf/routable-prefixes/[version])
Name (= /localhop/nfd/rib/routable-prefixes/[version]/[segment])
MetaInfo (= ResponseMetaInfo)
Content (= ResponseContent)
Signature
@@ -28,5 +28,5 @@ interest contains a list of prefixes and should be encoded as:
towards the face from which the request has been received. The requester may
process list of the returned names and pick whichever it wants to use.
For now, the ``/localhop/ndn-autoconf/routable-prefixes`` data is served by
For now, the ``/localhop/nfd/rib/routable-prefixes`` data is served by
:ref:`ndn-autoconfig-server`.
+5 -2
View File
@@ -32,7 +32,6 @@ log
;
; Run:
; nfd --modules
; nrd --modules
;
; Or look for NFD_LOG_INIT(<module name>) statements in .cpp files
;
@@ -93,7 +92,11 @@ face_system
port 6363 ; UDP unicast port number
enable_v4 yes ; set to 'no' to disable IPv4 channels, default 'yes'
enable_v6 yes ; set to 'no' to disable IPv6 channels, default 'yes'
idle_timeout 600 ; idle time (seconds) before closing a UDP unicast face
; idle time (seconds) before closing a UDP unicast face, the actual timeout would be
; anywhere within [idle_timeout, 2*idle_timeout), default is 600
idle_timeout 600
keep_alive_interval 25; interval (seconds) between keep-alive refreshes
; UDP multicast settings
+18 -18
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.
@@ -28,27 +28,27 @@
namespace nfd {
namespace rib {
shared_ptr<FibUpdate>
FibUpdate
FibUpdate::createAddUpdate(const Name& name, const uint64_t faceId, const uint64_t cost)
{
shared_ptr<FibUpdate> update = make_shared<FibUpdate>();
FibUpdate update;
update->name = name;
update->faceId = faceId;
update->cost = cost;
update->action = ADD_NEXTHOP;
update.name = name;
update.faceId = faceId;
update.cost = cost;
update.action = ADD_NEXTHOP;
return update;
}
shared_ptr<FibUpdate>
FibUpdate
FibUpdate::createRemoveUpdate(const Name& name, const uint64_t faceId)
{
shared_ptr<FibUpdate> update = make_shared<FibUpdate>();
FibUpdate update;
update->name = name;
update->faceId = faceId;
update->action = REMOVE_NEXTHOP;
update.name = name;
update.faceId = faceId;
update.action = REMOVE_NEXTHOP;
return update;
}
+26 -20
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.
@@ -43,14 +43,22 @@ public:
{
}
static shared_ptr<FibUpdate>
bool
operator==(const FibUpdate& other) const
{
return (this->name == other.name &&
this->faceId == other.faceId &&
this->cost == other.cost &&
this->action == other.action);
}
static FibUpdate
createAddUpdate(const Name& name, const uint64_t faceId, const uint64_t cost);
static shared_ptr<FibUpdate>
static FibUpdate
createRemoveUpdate(const Name& name, const uint64_t faceId);
enum Action
{
enum Action {
ADD_NEXTHOP = 0,
REMOVE_NEXTHOP = 1
};
@@ -69,15 +77,13 @@ operator<<(std::ostream& os, const FibUpdate& update)
<< " Name: " << update.name << ", "
<< "faceId: " << update.faceId << ", ";
if (update.action == FibUpdate::ADD_NEXTHOP)
{
os << "cost: " << update.cost << ", "
<< "action: ADD_NEXTHOP";
}
else
{
os << "action: REMOVE_NEXTHOP";
}
if (update.action == FibUpdate::ADD_NEXTHOP) {
os << "cost: " << update.cost << ", "
<< "action: ADD_NEXTHOP";
}
else {
os << "action: REMOVE_NEXTHOP";
}
os << ")";
Loaded 100 of 201 files, more files were not shown because too many files have changed in this diff. Show more