Compare commits

...
210 Commits
Author SHA1 Message Date
Alexander Afanasyev 19e2e6d858 docs+build: Prepare release 0.5.1
Change-Id: If6c2cf06d604c6541bedec6cf87731f1f593eae4
Refs: #3859
2017-01-25 16:16:33 -05:00
Junxiao Shi c31080d470 mgmt: Create UDP multicast faces according to whitelist/blacklist
refs #1712

Change-Id: Ia957bb1a3a3a0108d06716bfb25ecd29c6952d62
2017-01-25 14:17:55 -05:00
Junxiao Shi b47247dad9 face: ProtocolFactory registry
refs #3904

Change-Id: Ic7c8b3d6138b7c27d4189a2e15cc646055ad1294
2017-01-25 14:17:45 -05:00
Davide Pesavento 8a84773fdb ci: preserve environment when running tests as superuser
Change-Id: I18c59d6411169c4bf0742fd0c581c9c1f747806b
2017-01-25 09:29:49 -05:00
Junxiao Shi 55e21b9e17 table: clear StrategyInfo only if Strategy type differs
refs #3868

Change-Id: I164ccba3bd6c69cef9d2ebba303f8d8d941aac99
2017-01-25 09:29:02 -05:00
Junxiao Shi 7d30d8556a tests: rewrite StrategyChoiceManager test suite
refs #3868

Change-Id: I3ff124bcbf8a8a0b2badfc9adedbbaa09f91e72f
2017-01-22 03:29:26 +00:00
Junxiao Shi 64d99f21eb face: process face_system.udp config section in UdpFactory
refs #3904

Change-Id: I8edf69c152f7c164cbab2b482d6b138cbf89d3e2
2017-01-21 23:06:36 +00:00
Junxiao Shi 1b65ca1900 tests: delete BOOST_CHECK_NO_THROW in ProtocolFactory test suites
This makes exception message appear in testing logs, which
simplifies debugging.

refs #3904

Change-Id: I7d1a36c1c66d885a03e6a6d283e2907364f7f31a
2017-01-21 23:04:41 +00:00
Junxiao Shi 3409cd399d face: process face_system.websocket config section in WebSocketFactory
refs #3904

Change-Id: I8e30a54ab0664432cebf5d74e0467e9bfba60f2f
2017-01-18 15:31:27 +00:00
Davide Pesavento 3206565bac face: revert unintended behavior change in Transport::setPersistency
Prior to commit 32dab97321, persistency
transitions from NONE were not logged and before/afterChangePersistency
was not called. Restore that behavior.

This commit also improves test coverage of the persistency-related
functions in the various Transport subclasses.

Change-Id: Ide77c67ea277fca3d1cad5ea131ae0fa259db75c
Refs: #3232
2017-01-15 15:04:19 -05:00
Yanbiao Li 32dab97321 face: Transport::canChangePersistencyTo
Feasibility of transport persistency change can be checked with
Transport::canChangePersistencyTo before executing the actual change.
This enables management to verify persistency and other parameters
in a faces/update command before applying the updates.

Change-Id: Ia283f0daf678f47aad7b78b7e06dee4827f57cab
refs: #3232
2017-01-13 14:30:01 +08:00
Junxiao Shi 7003c609b8 face: process face_system.ether config section in EthernetFactory
This commit also fixes a potential memory access error in EthernetTransport.

refs #3904

Change-Id: I08296e7c6f1039b59b2859d277fc95326af34f52
2017-01-10 13:35:28 +00:00
Alexander Afanasyev 16320cd28b ci: Fix macOS build with Travis-CI
Change-Id: Iabdfd71c4ba8b3c35f6de117da3b42b61cb1dc4e
2017-01-06 04:22:46 +00:00
Junxiao Shi 406deb5971 face: process face_system.unix config section in UnixStreamFactory
refs #3904

Change-Id: I8f8772054ece2971758efd0599ef06fd3b778735
2017-01-05 20:07:44 +00:00
Junxiao Shi 38b24c7b94 face: process face_system.tcp config section in TcpFactory
refs #3904

Change-Id: I509f07e6835a96c7ba05137529f29da76a6514fd
2017-01-05 02:59:31 +00:00
Junxiao Shi 530cf00d68 table: StrategyChoice::insert return value includes error description
The error description is used in the response to a strategy-choice/set
management command failure.

refs #3868

Change-Id: I14e0eb4dc311806a90ebfe60fa17177d2809d104
2017-01-03 14:43:16 +00:00
Alexander Afanasyev 465056e9c6 ci: Fix bug with coverage report generation
Many files were missing from the report because the build path was
excluded.

Change-Id: Ia7ecdf4a81b8d37cff6c3fd14c5de3407648d91c
2016-12-30 16:19:46 -08:00
Junxiao Shi 91f6ee0c72 fw: instantiate strategy of next higher version
When an exact strategy version is unavailable, strategy registry now
instantiates the next higher version which can offer backwards compatibility.

All existing strategies do not support other versions.

refs #3868

Change-Id: Id2cf9ae3a1fa078ce8be815eea9396f5aa81ecbb
2016-12-29 21:44:44 +00:00
Junxiao Shi b859031855 face: FaceSystem class
FaceSystem class is the entry point of NFD's face system. It owns
ProtocolFactory objects that are created from face_system section of
NFD configuration file. This responsibility is split from FaceManager.

This commit also adds test coverage for face_system.websocket config
section processing routine.

refs #3904

Change-Id: If9a23c23b81f03d2b76c29febb3f29e6007d595b
2016-12-29 21:22:25 +00:00
Eric Newberry 81a9a86305 ci: speed up code-coverage jobs
some documentation updates

refs #3809

Change-Id: I0c837a3b8f0f5e5e15d20ba41418bf17660fffb5
2016-12-28 22:52:35 -07:00
Junxiao Shi 7f566dd0e5 table: StrategyChoice no longer supports installed instances
All strategies should be registered in the strategy registry.

refs #3868

Change-Id: Ie89b0ffaf9943e591f9f2d80546b013d5cc16ff8
2016-12-27 02:28:31 +00:00
Junxiao Shi 65800d22e7 mgmt: change strategy-choice/set response codes
If the specified strategy name cannot be instantiated,
respond with 404 status code.

refs #3868

Change-Id: I8275923f149ec9c2ed82e485e933d16320bd3a03
2016-12-25 21:05:45 +00:00
Junxiao Shi 4cb74319f9 fw: delete deprecated Strategy::getName in favor of getInstanceName
This commit also renames strategy_choice::Entry::getStrategyName
to getStrategyInstanceName.

refs #3868

Change-Id: I40301e744fc236918d6be1c1262eba952198e22f
2016-12-25 20:48:47 +00:00
Junxiao Shi 3aba7548f4 table: make FIB and StrategyChoice iterators default-constructible
They were previously not default-constructible when compiled with gcc 4.8.4.

refs #3882

Change-Id: I2431c869fb61b7adbe83d5551705981bf8618280
2016-12-24 02:42:52 +00:00
Junxiao Shi 593887c8d0 mgmt: use strategy registry in TablesConfigSection
refs #3868

Change-Id: I3500505f11d8dbfa37bb57c283bd4847ab0f11e5
2016-12-24 02:39:29 +00:00
Junxiao Shi 0e4a1f112d tests: register instead of install DummyStrategy
refs #3868

Change-Id: I5e44582625be51ef874e2a92e4bb7cc22d5b607b
2016-12-24 02:39:01 +00:00
Junxiao Shi 18739c4ac1 fw: pass parameters to Strategy subclass constructors
refs #3868

Change-Id: I1a09e7353c047d548065c4ed669d1f7993676428
2016-12-22 08:03:00 +00:00
Nick Gordon 947192570d rib: ReadvertiseDestination
refs: #3818

Change-Id: I453d69c4a100ede9065756fe16cb60c19aea33db
2016-12-19 11:58:31 -08:00
Alexander Afanasyev 2a00194316 tools: Add NDN-FCH stage (service to get "closest" NDN hub) to ndn-autoconfig
Change-Id: Ia2b0bf93d3d25b45713eeba58924e64871715bdb
Refs: #3800
2016-12-18 15:08:13 -08:00
Junxiao Shi 9137e9e2ae tools: nfd-status-http-server returns HTTP 504 when NFD is not running
504 Gateway Timeout is a better HTTP response code than 200 OK
in this situation.

refs #3863

Change-Id: Ib41e07a8a33c5408cb8fcb2fe85c9d0f1bd1ed6b
2016-12-15 21:31:50 +00:00
Junxiao Shi 890afe9d85 tests: add StrategyTester to strategy registry
refs #3868

Change-Id: Iaeb684b03726cf8c0aa9eb3ca8e52537f892fb1b
2016-12-15 14:34:34 +00:00
Junxiao Shi d0e276f66a tools: autoconfig MulticastDiscovery warns on Nack
refs #3704

Change-Id: Iff86770cf0bf7df7da08ef9b57101c645da0a301
2016-12-14 23:13:39 +00:00
Niv Sardi 5e8755c774 docs: Fix typos in manpages
Change-Id: I0231775c7d509c992e782144e7838dce793f7e5f
2016-12-14 09:27:24 -08:00
Junxiao Shi 037f4ab4b6 fw: move STRATEGY_NAME to getStrategyName static function
This avoids potential problems with static initialization order.

refs #3868

Change-Id: I13f0ff6c51c0a3bd43af7993233ff63a4bca9cf9
2016-12-13 04:27:06 +00:00
Junxiao Shi f15058ab06 table: don't share Strategy instance among StrategyChoice entries
For a Strategy type registered in the strategy registry,
a new instance is created for each StrategyChoice entry that uses it.

StrategyChoice::install is deprecated. An installed strategy instance
is still shared among StrategyChoice entries that use it. This will
be removed after unit tests switch to use the strategy registry.

refs #3868

Change-Id: Ibca685e6b6668f64fa1a503e3575867e8babdfe1
2016-12-11 20:15:05 +00:00
Junxiao Shi c34d167b91 fw: refactor Strategy registry
Strategy registry is moved into Strategy class.
Strategy instantiation logic is implemented in Strategy::create.
These are in preparation of supporting Strategy parameters.

refs #3868

Change-Id: If36a08ad25a00a7008a5eccc8cfe4f6c63638676
2016-12-09 15:57:59 +00:00
Junxiao Shi b4a5acd890 mgmt: tables.cs_policy config option
refs #3148

Change-Id: Icf30bbe508c1c491949d9fcb433fdfa16842d312
2016-12-07 19:59:18 +00:00
Junxiao Shi a88911105c tools: ndn-autoconfig MulticastDiscovery uses FaceQueryDataset
refs #2426

Change-Id: Ib9dcd77564d80b403199e9079d4753dadb96e350
2016-12-06 21:11:33 +00:00
Junxiao Shi 7ee00fb680 table: cs::Policy::getPolicyNames
refs #3148

Change-Id: I06f66e9780b9c5c4820ba18cca5fbc9b1061eae0
2016-12-04 21:23:00 +00:00
Junxiao Shi c29c0b01a7 fw: don't expose UnsolicitedDataPolicy::Registry
UnsolicitedDataPolicy::Registry was mistakenly made public when
implementing getPolicyNames.

refs #2181

Change-Id: Ib2e68360aef2e7d3695273f8ef2b6c0c67bd914a
2016-12-04 21:11:44 +00:00
Junxiao Shi 9db735958c fw: UnsolicitedDataPolicy::getPolicyNames
refs #2181

Change-Id: Ie2abcd7503d1079734e6386fbab37cadd186e07c
2016-12-01 23:43:11 +00:00
Junxiao Shi 57cda13f7b fw: delete deprecated Strategy::sendInterest overload and violatesScope
refs #1756, #3841

Change-Id: Idd5fb5692435c864a0a9b140992e615b280243a3
2016-12-01 23:43:01 +00:00
Ashlesh Gawande 2a73f35ce6 fw: localhop scope restriction in ASF strategy
refs: #3841, #1756

Change-Id: Ic82e7055ace9d3f8eca8f9bad94603692ff321d5
2016-12-01 17:27:02 -06:00
Weiwei Liu aaa58a6c10 rib: fix incorrect operator<< output
refs #3423

Change-Id: I22137a1ad2c3b64d74b7ba2fe6b5f7f55486c276
2016-11-29 23:48:28 -07:00
Junxiao Shi 52fa45c6ee tools: ndn-autoconfig code style corrections
refs #2426

Change-Id: Ied8de3b3f839e07090fc71f41cd01f4e5b4987f3
2016-11-29 21:18:13 +00:00
Junxiao Shi 934f5055ab tools: deprecate nfd-status command line options
nfd-status command line options are deprecated in favor of
nfdc subcommands such as 'nfdc face list' and 'nfdc status report xml'.

'nfd-status' without command line options is kept as an alias of
'nfdc status report' and is not deprecated.

refs #3780

Change-Id: Ib54b239062b4987295e22c7eb94b75c030f7308a
2016-11-28 17:13:35 -08:00
Davide Pesavento 26c82ca131 tests: no need to use a logger in TestVersion
refs #1575

Change-Id: I48aae470b579b7df669606e6d2bda3dff8de364f
2016-11-27 07:46:22 -08:00
Junxiao Shi 52555b06d4 table: CS policy registry
refs #3148

Change-Id: I058357839e514787405952569d1abf402375d1ea
2016-11-25 21:39:06 +00:00
Junxiao Shi e21b3f3dc4 fw: localhop scope restriction in best-route v1, multicast, ncc strategies
canForwardToLegacy function no longer checks scope. Strategies using this
function shall use wouldViolateScope separately.

refs #3841, #1756

Change-Id: Ib1bd3f9fe19e4cadfa27e86dcc730d16cfd4b0db
2016-11-24 14:13:46 +00:00
Eric Newberry ee400b5235 face: GenericLinkService encodes and decodes CongestionMark field
refs #3797

Change-Id: Ia6b00a36f3e7ed9ec98e41dee7e2f97eaf235ddd
2016-11-24 14:12:48 +00:00
Junxiao Shi e273333fba tools: nfd-status-http-server invokes nfdc
`nfdc status report xml` command is invoked instead of legacy `nfd-status`.

refs #3780

Change-Id: I30ee00b59c388186b030757c815c147f74d000d1
2016-11-24 14:11:40 +00:00
Eric Newberry 6d932e83d2 tools: display face flags in nfdc and nfd-status-http-server
refs #3733

Change-Id: Idd66ffb7594079d2738253d035792300fe3febef
2016-11-24 05:05:43 +00:00
Junxiao Shi ae889380da tools: nfdc status commands
refs #3780

Change-Id: I5222aacc0a7134978e9496c68a3b915dac4aee18
2016-11-23 04:52:51 +00:00
Junxiao Shi a7f9a29e74 fw: localhop scope restriction in AccessStrategy
AccessStrategy now properly invokes reject pending Interest action
when an Interest cannot be forwarded.

Fw/TestStrategyScopeControl test suite is introduced to test localhost and
localhop scope control in strategies.

refs #3841, #1756

Change-Id: I7ae0d9f07ad6673363045a8c0341dfb78e088672
2016-11-22 16:31:38 +00:00
Junxiao Shi a6350d9395 tests: DummyStrategy forwards specific Interest
refs #1756

Change-Id: I252364ef75f5a74e61828e35385c272b1a8b4581
2016-11-22 14:22:25 +00:00
Junxiao Shi 6c13562d23 tools: nfdc help command
refs #3780

Change-Id: Ibd0e37bad127a38e582864fadd81afadc74baf48
2016-11-21 14:30:33 +00:00
Junxiao Shi 00dc91423e fw: localhop scope restriction in BestRouteStrategy2
localhop scope rules are implemented as wouldViolateScope function;
the old violatesScope function is now deprecated.
Strategy::sendInterest overload without specific Interest packet is also
deprecated. BestRouteStrategy2 has switched to use the new overload.

refs #3841, #1756

Change-Id: Ic117f01926eadddf1da3ccb580b52a3903a70c89
2016-11-21 14:23:12 +00:00
Davide Pesavento ac767aad0f core: Network: fix uncaught bad_lexical_cast in isValidCidr()
Change-Id: Ibeac1bb5d637324e880f00a0ae0ff9e65506efd4
Refs: #3858
2016-11-20 02:35:06 +01:00
Davide Pesavento 89567d3b31 core: Network: misc code cleanups
Change-Id: Idc37b5f834220e8e980958953785806687435f36
Refs: #3858
2016-11-20 02:19:25 +01:00
Weiwei Liu dcdf6212cc face: support permanent persistency in TcpTransport
refs #3167

Change-Id: I217c5f0fe0dfbbd759861ee262920cc03394b0ed
2016-11-19 02:43:53 +01:00
Junxiao Shi c5f651f014 fw: allow strategies to pick outgoing Interest
This commit changes outgoing Interest pipeline and Strategy API,
to give strategies an opportunity to pick an outgoing Interest that
matches the Interest table entry.
No strategy is updated in this commit.

refs #1756

Change-Id: Iffad77ef0078c437070039fca6b24a85df13bda7
2016-11-17 22:58:12 +00:00
Junxiao Shi a274292b93 table: pit::Entry checks Interest matches entry when updating in/out-record
pit::Entry::canMatch is the single place to determine whether an Interest
matches an Interest table entry. This condition is asserted when an in/out-
record is inserted or updated. This prevents a strategy from incorrectly
picking an Interest that is incompatible with the Interest table entry.

refs #1756

Change-Id: Ibf61a0e2e32b7a0e04e581f01ef07b791c6010a2
2016-11-17 22:53:23 +00:00
Ashlesh Gawande d3ac777f7b fw: Check out record exists before calculating RTT in ASF
Change-Id: Ie7f2db50b21d314a5df998e4220f64de14861d3e
refs: #3829
2016-11-14 12:59:49 -06:00
Eric Newberry ecc45cbc7e rib: use faces/update instead of faces/enable-local-control to enable local fields
refs #3734

Change-Id: Ic7a39a9b3297103bbe36bf5955e52523b9f8baa4
2016-11-08 19:57:12 +00:00
Eric Newberry 1b4ba050cc mgmt: send FACE_EVENT_UP and FACE_EVENT_DOWN notifications
refs #3794

Change-Id: I98cc9db2652454d8fd09975b619433046e9bc7ca
2016-11-06 09:39:04 -07:00
Davide Pesavento 5f47aa6140 core: use C++11 <random> instead of Boost.Random
Change-Id: I8f22965b86c681581762a47995f29f888421a558
Refs: #3599
2016-11-04 17:56:14 +01:00
Nick Gordon 89c4cca866 rib: route addition and removal signals
refs: #3818

Change-Id: Ic47afeba4b4133a2092b26ecd49adbaac0505781
2016-11-03 13:51:49 -06:00
Eric Newberry 27bdd1a325 build: load sanitizers last in wscript to prevent Boost link failure
refs #3828

Change-Id: I582095027dd0330cdad76accd0e2ffe5382840b0
2016-11-01 18:28:31 -07:00
Eric Newberry 6db5ce1912 ci: set Travis CI Xcode version and update NODE_LABELS to 10.11
refs #3833

Change-Id: Ie6eea82b165390fbf88ab08766c25daa10c60370
2016-10-31 16:08:30 -07:00
susmit 91e1d7ce48 mgmt: create Ethernet multicast faces according to whitelist/blacklist
Refs: #1712

Change-Id: Iaabaeaf58e460c86ca58f9099b5c2b904a5a5c93
2016-10-26 20:45:02 -06:00
Davide Pesavento 97210d5b15 tests: respect naming conventions and improve nesting of some test suites
Change-Id: I65af858bc6d10197c6ee11111fa9f7c1faa617ef
Refs: #2497
2016-10-14 15:45:48 +02:00
Alexander Afanasyev 436f3bd9fe build: Do not fail the build in debug mode when using deprecated declarations
The original motivation of this change was to avoid compilation failure
in debug mode on macOS 10.12.

Change-Id: I15437050555646b2458989f3788fce4c1e354e48
Refs: #3795
2016-10-13 16:42:59 -07:00
Davide Pesavento 7de0444d06 ci: ensure XML test reports do not clobber the output of previous runs
This was broken since commit e0edc4c06d

Change-Id: I369e9ad2cb3345ef3a707799e86c3c3beaf83788
Refs: #3418, #3750
2016-10-13 14:41:20 +00:00
Weiwei Liu 7c7951391c tools: fetch face dataset with StatusDataset client in nfd-autoreg
refs #3659

Change-Id: I60b0947cbaf47d2e69cd3f3604ffc46f96ad91a1
2016-10-11 10:43:24 -07:00
Weiwei Liu 6e21cdb13f rib: fetch face dataset with StatusDataset client
refs #3620

Change-Id: Ibf1a0e064e105389d6b733b2d1f0791dff356208
2016-10-06 16:21:31 -07:00
Alexander Afanasyev 67019110d7 docs+build: Prepare for version 0.5.0 release
Change-Id: I0f7fbd26d6d3f22c1d14ff10b53c1276abe0aa0c
Refs: #3762
2016-10-04 16:51:28 -07:00
Davide Pesavento 9a00fabed7 tests: merge TcpChannel and UdpChannel test suites using test case templates
Change-Id: Id56bb036db53494d4d250f9ea68a3ded78b33ddb
Refs: #3514
2016-10-03 18:52:44 +02:00
Eric Newberry c05918c860 mgmt: add Flags field to faces/list and faces/query in FaceManager
refs #3732

Change-Id: I6532962831efa780d1737412a8dfb2125f296f16
2016-10-03 09:43:42 -07:00
Eric Newberry f40551a061 face+mgmt: enable local fields through ProtocolFactory::createFace
refs #3731

Change-Id: I569dae59cda150ffcb1c0ff1d01a575d8850beca
2016-09-23 01:16:23 -07:00
Junxiao Shi d8205106cc mgmt: ForwarderStatusManager answers only status/general
GeneralStatus dataset at /localhost/nfd/status prefix was deprecated
and is now removed.

refs #3379

Change-Id: I9ce8bba9b11823b6a1a159703cc9f8050656ab53
2016-09-22 18:08:45 +00:00
Davide Pesavento cffb4e5bce Add Travis CI badge to README
Change-Id: I352dbee34ba17d6526eb305add548e0eb3b953f5
2016-09-20 15:54:06 +02:00
Davide Pesavento 3495b8009c face: fix TestWebSocketTransport/StaticPropertiesNonLocalIpv4 on Travis CI
Don't assume that the local address of the client is the same as the remote
address seen by the server. The client may be behind a NAT, for example.

Change-Id: I2de084830c364e28c49de8fdbce60b46f76727ad
Refs: #3676
2016-09-20 15:53:31 +02:00
Junxiao Shi c143afea10 tools: various improvements in nfdc
* use same underlying type for ParseMode and AvailableIn,
  to avoid potential errors when converting between them
* simplify AvailableIn stream output operator with text::Separator
* allow CommandParser::addCommand to accept bitwise OR'ed modes
* qualify nfdc logging sources with 'nfdc.' prefix

refs #3780

Change-Id: I2eee3d562184daf27305c2d5f2892637b63421c2
2016-09-20 13:04:51 +00:00
Junxiao Shi c69f9210d9 fw: deprecate ClientControlStrategy
It becomes unnecessary because NextHopFaceId is honored universally.

refs #3783

Change-Id: I4c0c48f10ae58aa2603998f195f43d54e81bfcf2
2016-09-19 21:21:03 +00:00
Davide Pesavento 043c50147c ci: enable AddressSanitizer for unit tests
Change-Id: Iaf4c24f7e6f79d2915bf8ef78cff398876091c73
Refs: #2589
2016-09-19 17:23:32 +00:00
Davide Pesavento e94804bd48 rib: fix use-after-free in Rib::erase and RibManagerFixture::clearRib
Change-Id: Ia4c2211f6c48d852e3b73dc84e298d26ad14f708
Refs: #3787
2016-09-19 17:23:21 +00:00
Junxiao Shi e342e8de70 fw: honor NextHopFaceId universally
NextHopFaceId usage no longer depends on client-control strategy.

refs #3783

Change-Id: Ie49c453f90fa34b517b576fe401c8e4e8f23eab7
2016-09-18 16:48:00 +00:00
Junxiao Shi c06746182b core: delete unused SegmentPublisher
SegmentPublisher was used in RibStatusPublisher which has been deleted.

refs #2857

Change-Id: I2c294f58a6444a99a2453057e4718cef27afe517
2016-09-17 12:32:35 +00:00
Junxiao Shi fc6515d2f7 tests: delete unused malformed.ndncert
malformed.ndncert was used in CommandValidator test suite
which has been deleted.

refs #2063

Change-Id: I7d123822c06fc2ccc4301c62ae7d312662659e38
2016-09-17 12:26:39 +00:00
Junxiao Shi 3d1eb091c0 tools: nfdc status commands
These commands are added to nfdc:

    status show
    face list
    channel list
    strategy list
    fib list
    route list

They are implemented by calling into legacy nfd-status procedures,
and currently do not support filtering arguments.
Future commits will re-implement them directly with StatusReport.

refs #3749

Change-Id: I11f3f074966649c3732969ffa22f9b3938bb4bac
2016-09-14 19:20:20 +00:00
Junxiao Shi bf6acd5cc9 tools: normalize nfdc exit codes
refs #3749

Change-Id: I0c81dff095c170390f62de82badc0cca7b53392d
2016-09-14 03:57:57 +00:00
Junxiao Shi 737c43cdad tools: nfdc creates Face and KeyChain in main function
refs #3749

Change-Id: I169ad766634371b0192ebae640355298b78aaaa4
2016-09-14 02:51:44 +00:00
Alexander Afanasyev 0fc97486ff build: Do not fail build when -Winfinite-recursion warning is generated
Change-Id: I6370a0a5a938de15924f8e139ea34b32ed20e063
Refs: #3358
2016-09-13 18:33:15 +00:00
Davide Pesavento e0edc4c06d ci: make unit tests execution compatible with different versions of Boost
This commit also unifies the coding style of CI scripts.

Change-Id: Iae73f63d8a997dbfde9233b6ee7f53a3d9644ef6
Refs: #3750
2016-09-13 18:29:52 +00:00
Davide Pesavento 0a5e5e2fa5 ci: fix gcovr invocation
Change-Id: If74633cfb67725b43a55d7b190b178137ad2c420
Refs: #3418
2016-09-13 18:29:33 +00:00
Junxiao Shi 8527f86de4 fw: correct typo in Strategy test suite
refs #3664

Change-Id: I34711f6552892ee467e0d03b0ff4c8a9c7d3b513
2016-09-12 21:32:35 +00:00
Alexander Afanasyev 6459e64f36 core: initialize Boost.Log backend through ndn-cxx
ndn-cxx logging facility and NFD logging both use Boost.Log.
When each of ndn-cxx and NFD adds a std::clog sink, messages are
appearing twice on OS X, resulting in scrambled log output.

This commit removes NFD's Boost.Log backend initialization and
let ndn-cxx logging facility initialize Boost.Log.

Change-Id: Ib25efe5c924d530424c275f9c8f168683f4ef039
Refs: #3761
2016-09-12 10:01:36 -07:00
Junxiao Shi 25c6ce41d5 mgmt+rib: include ndn-cxx/mgmt/nfd/*
refs #3760

Change-Id: I9a2e3012af2f72495ce3259fa4f51ebaa8ea7096
2016-09-09 13:49:59 +00:00
Junxiao Shi cbc8e947bf daemon+rib: add proper #include line for NDNLPv2 tags
refs #3755

Change-Id: I3ab279405aca7c7139e8d0e8e662eb3ea7200045
2016-09-06 03:17:45 +00:00
Junxiao Shi 0dba01018c fw: improve Strategy::lookupFib test coverage
refs #3664

Change-Id: I0ae2e2f99d91306930718d43982ca1744640e533
2016-09-06 01:57:53 +00:00
Eric Newberry b5aa7f58e8 mgmt: add faces/update command
refs #3731

Change-Id: I79777a10feecb2de83276371100cc86a43d0e76d
2016-09-05 09:33:17 -07:00
Junxiao Shi 64567bb12a tools: nfdc command line parser
refs #3749

Change-Id: Ief301152212a6d501f0396b2c9834e860ddaf6c5
2016-09-04 16:00:27 +00:00
Junxiao Shi 58320f7156 fw: UnsolicitedDataPolicy registry
refs #2181

Change-Id: I39f5dd02a224f9d872bde29f29aab05f64bb6e06
2016-09-04 04:40:34 +00:00
Yanbiao Li 5ad19febad rib: keep AutoPrefixPropagator log levels symmetric
Change-Id: Iabf254706dba0ea7843495912be4154321a91993
refs: #3524
2016-09-03 07:16:46 +00:00
Junxiao Shi 88f5f7392b fw: change default UnsolicitedDataPolicy to drop-all
refs #2181

Change-Id: I5e70a6f7d025462e96e852159343b478c8404ea7
2016-09-03 07:11:37 +00:00
Eric Newberry 4260241659 mgmt+face: move protocol-specific face creation checks into protocol factories
Also brought implementation of faces/create in line with design

refs #3731

Change-Id: I4f48079136b42c7fdbd4fdfba37116d2565f9dc1
2016-09-02 18:56:24 -07:00
Davide Pesavento 231ddd7508 ci: stop adding capabilities before running unit tests
This ensures that all tests pass (or are automatically skipped)
when run as an unprivileged user.

Change-Id: If8b66fd6555de455648576565b1c6cbd02695d1b
Refs: #3418
2016-09-02 22:20:00 +00:00
Junxiao Shi cf0f3ce319 fw: move Forwarder::lookupFib to Strategy::lookupFib
refs #3664

Change-Id: Ib4dd2354d853f7d6455bf08bb6b863b5f77076c1
2016-09-02 13:01:59 +00:00
Davide Pesavento aaa5dd3a00 tests: add callgrind start/stop macros in benchmark programs
Change-Id: Ibd875f4275431ebcbeba2fffe319956580714553
Refs: #3610
2016-09-02 12:33:33 +00:00
Alexander Afanasyev a269f47bc7 docs: Fix syntax for python3
Change-Id: I52fc914f462a87efae49115827163db09a5212d1
2016-08-31 18:59:55 -07:00
Junxiao Shi 9685cc5682 mgmt: tables.cs_unsolicited_policy config option
This commit introduces tests/check-typeid.hpp which provides
unit testing tools to validate runtime type information.

refs #2181

Change-Id: I987c9875517001ea82878cbe2646839a03ad54f3
2016-08-29 12:47:05 +00:00
Junxiao Shi 2f741327e6 tools: legacy nfdc parses command with Boost.Program_options
refs #3749

Change-Id: I5274e0a2594323729834cd8001308ec699fbe6d6
2016-08-29 00:53:18 +00:00
Junxiao Shi 8c39bf0b9f tools: rename nfd::tools::nfdc::OutputFormat to ReportFormat
refs #3749

Change-Id: I4984d056c26f9ecbda25103ad60dc50bb60a4dec
2016-08-28 23:54:13 +00:00
Junxiao Shi e0fa33b2a0 fw: delete deprecated BroadcastStrategy
refs #3206

Change-Id: Ifa5e2ac08ce236a4c20b6b49abe5c40cdc74652b
2016-08-26 02:27:38 +00:00
Junxiao Shi fc02186460 table: StrategyInfoHost stores StrategyInfo as unique_ptr
refs #3205

Change-Id: Ia194ca94717347848d257096549cfec5df1ba6c9
2016-08-25 21:51:18 +00:00
Junxiao Shi 2af9ca368b table: move CS limit change logging to cs::Policy
refs #2181

Change-Id: Ifffc72b4f8c84b9caa254ce30b57a42d83fa5b11
2016-08-25 21:51:02 +00:00
Junxiao Shi 0cc125c365 mgmt: TablesConfigSection constructor accepts Forwarder&
refs #2181

Change-Id: I1a87dd573f25f3806bc1b1f3c60ec9eef0eca4e3
2016-08-25 21:50:04 +00:00
Junxiao Shi 36b22256c1 fw: additional unsolicited Data policies
refs #2181

Change-Id: I439a77f8f48ad194459dc2391cd0ad8d0860b83e
2016-08-25 13:22:21 +00:00
Junxiao Shi fbe8efea55 fw: UnsolicitedDataPolicy
The decision of whether to cache or drop an unsolicited Data is moved from
Data unsolicited pipeline to UnsolicitedDataPolicy.

refs #2181

Change-Id: Iba3e72c2214e0ac5f6f305c2c1c0ed182b008e85
2016-08-22 16:02:30 +00:00
Junxiao Shi 2e526d70d2 rib: delete RibStatusPublisher
RibStatusPublisher is unused since RibManager switches to ndn::mgmt::Dispatcher.

This commit also corrects a typo in rib-entry.hpp

refs #2857

Change-Id: I968a836e46c9a7e70513d45c90099678ef587f86
2016-08-22 16:02:13 +00:00
Junxiao Shi 06d6ba666d rib: add proper #include line for ndn::OBufferStream
refs #3741

Change-Id: If08719fac9e977bd5d68c1aba491738eacbfa900
2016-08-22 15:59:03 +00:00
Junxiao Shi 37175489ca mgmt: delete CommandValidator
CommandValidator has been replaced with CommandAuthenticator.

refs #2063

Change-Id: I6569db6ff103de5f56cac480e334f32ff9f9a40f
2016-08-22 03:59:15 +00:00
Junxiao Shi 9ddf1b5c26 mgmt: NfdManagerBase::makeAuthorization uses CommandAuthenticator
This commit also eliminates Forwarder in Mgmt/TestFaceManager/CreateFace test suite
and uses FaceTable directly.

refs #2063

Change-Id: I596e8c2a12dad64ee75082f384955f30d574f53e
2016-08-22 03:58:55 +00:00
Junxiao Shi 217384025e core: change ManagerBase::authorize to makeAuthorization
refs #2063

Change-Id: I0e6faced6e4e1733362e3ec018e2ee60fcefafa1
2016-08-22 03:58:28 +00:00
Junxiao Shi 29b4128397 rib+tools: adapt to Controller::CommandFailCallback with ControlResponse
refs #3739

Change-Id: Icf5b3ed0bd997730a024bad2ccd258c8168b4ccb
2016-08-22 03:47:02 +00:00
Junxiao Shi 331ade75da tools: merge nfd-status into nfdc
nfd-status functionality is accessible through `nfdc legacy-nfd-status` subcommand,
and nfd-status is replaced with a shell script calling this subcommand.

refs #3749

Change-Id: Iab03f3bc9ddb4333a0b6ca5fb9c67f54e9960ab4
2016-08-19 14:07:19 +00:00
Junxiao Shi d243d71bf5 tools: split nfdc into multiple files
refs #3749

Change-Id: I24a3fd287773d0577d438e9ca24dc1dfab335a4f
2016-08-19 06:45:31 +00:00
Junxiao Shi 5b3feb6008 table: rename StrategyInfoHost::getOrCreateStrategyInfo to insertStrategyInfo
refs #3205

Change-Id: Icd3ab9e4fdb5a2ffc39a8d0e0c713e22f13fe28c
2016-08-19 01:51:41 +00:00
Junxiao Shi d7631279f7 mgmt: CommandAuthenticator
refs #2063

Change-Id: I19a82d8d1fdfb3cc5a003166b1a8c1c32bbf24b5
2016-08-17 04:16:31 +00:00
Junxiao Shi f5409d434a table: Pit::deleteInOutRecords accepts Entry* instead of shared_ptr
refs #3164

Change-Id: I512da6200d4d744d5631fc78900795d19ad5dd52
2016-08-17 02:47:12 +00:00
Davide Pesavento 1c2c6c45e2 table: silence unused variable warning in release builds
Warning introduced in commit 80f9fcdaa1

refs #3164

Change-Id: I3e97a1f6adf3beedc4b5608cac75a276735891cb
2016-08-16 12:36:06 +00:00
Junxiao Shi b30863e0e2 table: simplify StrategyChoice iterator with Boost.Range
This commit also improves Doxygen in NameTree, Fib, and Pit enumeration.

refs #3738

Change-Id: Ibb56f958df4d1bc2564192d905cfc2e499a7875e
2016-08-15 21:32:01 +00:00
Junxiao Shi 13ad4b7a42 table: simplify FIB iterator with Boost.Range
refs #3738

Change-Id: I0bfe985c9dac86a67988f77a89f4d2694c4fd9f5
2016-08-15 04:51:21 +00:00
Junxiao Shi 9f6ca60f74 table: declare name_tree::Range type
Declare that NameTree enumeration returns name_tree::Range type
instead of an unspecified type usable with range-based for.

refs #3738

Change-Id: I132c583704d0c6164077abf70a694e833b448e85
2016-08-15 04:50:29 +00:00
Junxiao Shi dbef6dc8e2 table: Pit::erase accepts Entry* instead of shared_ptr
refs #3164

Change-Id: I9ff47c80865da42b09870c632707dffd78ed76b9
2016-08-15 02:58:36 +00:00
Junxiao Shi 3248205bb7 table: PIT iterator dereferences to const shared_ptr<pit::Entry>&
refs #3164

Change-Id: Id857e214a727917009f865c2cfac782077844799
2016-08-15 02:05:17 +00:00
Junxiao Shi 09cf13cd9f table: move PIT iterator to a separate file
This commit only moves code around and renames variables.
There's no functional change.

refs #3164

Change-Id: Icb6b249cc0c07fcfe42f7a6d6987de31285566e7
2016-08-15 02:05:00 +00:00
Junxiao Shi 8ff0a86e18 tests: don't store shared_ptr<pit::Entry> in StrategyTester
refs #3205

Change-Id: I20ed5023fe07ba71d8df56a02228013acb8a8cb6
2016-08-13 04:50:50 +00:00
Junxiao Shi b9420cf0c1 fw: accept const shared_ptr<pit::Entry>& in Forwarder pipelines and Strategy actions
refs #3205

Change-Id: Ia683fb1a9e301270f99bcdd4d97493abf3dbec9f
2016-08-13 04:38:52 +00:00
Junxiao Shi 340d5533ea table: make name_tree::Node the sole owner of name_tree::Entry
This commit also improves name_tree::Entry test coverage.

refs #3687

Change-Id: I92375f29fbebab82c67da7dff2ea7a2952ba2cca
2016-08-13 04:00:35 +00:00
Junxiao Shi e7258ffa88 table: cleanupOnFaceRemoval doesn't rely on shared_ptr<name_tree::Entry> anymore
refs #3687

Change-Id: I3901f053bf370ca5a19a0fea72aec8eb58fcfe10
2016-08-12 23:55:47 +00:00
Junxiao Shi dd8f66140b table: NameTree::findLongestPrefixMatch accepts all table entry types
This simplifies longest prefix match procedures in FIB and StrategyChoice.

refs #3687

Change-Id: I9aa93232124b91bae7890d065337ac9389e8398e
2016-08-12 15:42:52 +00:00
Junxiao Shi 15e98b00f5 fw: pass const shared_ptr<pit::Entry>& to Strategy triggers
refs #3205

Change-Id: I8f227c57ee6733526f0569de81f20677210cafa4
2016-08-12 11:21:44 +00:00
Junxiao Shi 759993b922 table: delete unnecessary name_tree::Iterator destructor
refs #3687

Change-Id: Iccb755c0b1234d31bea84797db348fd229b2fde9
2016-08-12 11:19:08 +00:00
Junxiao Shi 7f35843d58 table: NameTree::lookup return Entry& instead of shared_ptr
refs #3687

Change-Id: Ie86057337dd36ff2bc6ef3ea0c73fd4ffc4b13d0
2016-08-11 17:06:33 +00:00
Junxiao Shi f2420fc7a3 table: ensure NameTree::lookup(tableEntry) does not return nullptr
NameTree::lookup(tableEntry) is always equivalent to NameTree::lookup(Name).
NameTree::getEntry(tableEntry) should be used when inserting new name tree entry is undesired.

refs #3687

Change-Id: I0b17cd07dde83341976cfe66c85855dfb2fa6e89
2016-08-11 13:18:21 +00:00
Junxiao Shi 811c010098 table: NameTree findExactMatch, findLongestPrefixMatch return Entry*
refs #3687

Change-Id: I32752fd711b9641228fbb7f356e72144780cf9ec
2016-08-10 04:12:45 +00:00
Davide Pesavento 67f30273dd build: add waf-tool to simplify building with AddressSanitizer & friends
Change-Id: I769be2650c0c174b9e12e0832a5d2eea9bcad2d6
Refs: #2589
2016-08-10 01:55:16 +00:00
Junxiao Shi 352fc82185 fw: AccessStrategy test suite avoid deprecated ndn::Face::expressInterest overload
refs #3703

Change-Id: Ib8f79d56551315c4ebc54f1574a4afbe95b99d9f
2016-08-09 03:53:05 +00:00
Junxiao Shi 9ede5bd312 tests: TopologyTester avoid deprecated ndn::Face::expressInterest overload
refs #3702

Change-Id: I6dcb76be1fcfaa184068390b5ab25640d21a937b
2016-08-09 03:51:27 +00:00
Junxiao Shi e3cf285ee7 table: delete deprecated functions in NameTree
NameTree::eraseEntryIfEmpty is renamed to eraseIfEmpty;
the deprecated overload that accepts shared_ptr<name_tree::Entry> is deleted.
name_tree::Entry::getPrefix is deleted in favor of getName.

This commit also improves Doxygen in NameTree class.

refs #3687

Change-Id: Ia98ca676ce6d3bc7b2e97328adccac911c8167d7
2016-08-09 03:50:56 +00:00
Junxiao Shi f9f7cf35ae tests: fix assertion failure in PIT+FIB benchmark
refs #3571

Change-Id: Icb06adfd9460cd65fdd77428d79f0f75d1e71133
2016-08-08 05:51:06 +00:00
Junxiao Shi b660b4c9c0 table: refactor NameTree hashtable
refs #3687

Change-Id: I908c1d7e67da861fc86a756fc0bc69b99ee696f7
2016-08-06 20:47:44 +00:00
Junxiao Shi 029401f6cc table: refactor NameTree iterator
refs #3687

Change-Id: Icf5be98d79cfaa27597f62832fcd0189df2731d1
2016-08-05 12:55:14 +00:00
Junxiao Shi 9f5b01dfd8 core: move common.hpp to core/
Headers in core/ are now included as `#include "core/*.hpp"`.
This allows NFD to rely less on include paths when used as a submodule in
another codebase, such as ndnSIM and NFD-Android.

refs #3127

Change-Id: Ia38f3c97427e17ff7b5401281f1fe875b5d5313e
2016-08-05 03:54:28 +00:00
Junxiao Shi 38f4ce9f25 tools: refactor nfd-status
refs #3658

Change-Id: Ia347074bea802eba5f539208e276e849a60db8a4
2016-08-04 10:01:52 +00:00
Junxiao Shi 9cff779038 table: pit::FaceRecord stores Face& instead of shared_ptr
refs #3164

Change-Id: Ib23ab2341a37213fee791f2070f13b76da851d53
2016-08-01 21:45:11 +00:00
Junxiao Shi 02b73f5705 table: delete PIT in-record and out-record when face is destroyed
refs #3685

Change-Id: I3c20417c9a30db69c90c9d59a30af1529bc1f98e
2016-07-28 01:48:27 +00:00
Junxiao Shi 2570f3ec4f table: NameTree code style corrections
refs #3687

Change-Id: I25cfac1d8b11236c251c2ab717facb82b62dcb10
2016-07-27 02:48:29 +00:00
Junxiao Shi dcffdaafb5 fw: decouple Forwarder and FaceTable
refs #3679

Change-Id: I449e20e58a0a67a7172bdf3ab02b0d655149690f
2016-07-26 02:23:56 +00:00
Junxiao Shi 80f9fcdaa1 table: don't use shared_ptr in Measurements
refs #3164

Change-Id: I7705d00ac155b15b5db69809610b68e96360a0ae
2016-07-24 22:52:28 -07:00
Junxiao Shi 71d12148c8 daemon: display extended exception information in NfdRunner::run
refs #2541

Change-Id: I1fdc22571e7bce74d430b7938951170765b72bff
2016-07-23 20:10:18 +00:00
Junxiao Shi d23de8b9ef tests: don't inline functions in test-common.hpp
This commit also adds a signData(Data&) overload.

refs #1694

Change-Id: I8e3ff5be7c6734dec8b481d6c20eb6b6eaef0725
2016-07-23 20:05:42 +00:00
Eric Newberry 4a4ccfe7d6 face: Set FaceScope to local for IPv4-mapped IPv6 loopback addresses
refs #3682

Change-Id: I33c22d3585c8fee081b1317cdd6587ec0f0e4ef5
2016-07-23 09:40:27 -07:00
Junxiao Shi 5149320e5b tools: don't use deprecated ndn::encoding::dataBlock
refs #2950

Change-Id: Ibda4af7ab50df5a7f5700d7db5de1da938b7e020
2016-07-23 02:03:08 +00:00
Eric Newberry cb27ea8185 build: Fix build issue with Boost.Asio on Ubuntu+clang
refs #3588

Change-Id: Ica155f22fa615eed8a14b5765cdce0f6e480b1de
2016-07-20 19:59:57 +02:00
Junxiao Shi ae04d34c17 fw: FaceTable signals use Face& instead of shared_ptr
refs #3205

Change-Id: I53ecd0d6a13d379eb1dfb872041bdde8501f05e7
2016-07-19 13:20:22 +00:00
Junxiao Shi b84e6743be fw: FaceTable iterator dereferences to Face& instead of shared_ptr
This commit also improves the speed and reliability of
Mgmt/TestFaceManager/CreateFace test suite.

refs #3205

Change-Id: Idd013488ced2d7f8072ef8a3d910f94da2e0c8ac
2016-07-19 13:16:22 +00:00
Junxiao Shi 5b43f9a74d fw: FaceTable::get returns Face* instead of shared_ptr
refs #3205

Change-Id: I1c61493382fe065389266ff3519ab2b265fe4f79
2016-07-19 13:15:56 +00:00
Junxiao Shi 581cf00ee8 core: fix NFD_LOG compilation error with Boost 1.59
refs #3674

Change-Id: I58ea54478cc333fbfb57c8319d0ccd94c944c75f
2016-07-18 11:48:20 -07:00
Junxiao Shi a49a1abf12 table: StrategyChoice uses unique_ptr instead of shared_ptr
refs #3164

Change-Id: Id3110f72aab83982b0768e596a04bad9f7336975
2016-07-15 18:24:36 +00:00
Junxiao Shi 3978c92af1 table: fix uninitialised memory error in DeadNonceList test suite
refs #2359

Change-Id: I90c1597e4b49edc036cad8225f85edb9ed1437a6
2016-07-15 18:24:11 +00:00
Junxiao Shi 221b6fec69 tests: don't use makeDummyClientFace
refs #3383

Change-Id: I1803a6f482a4e6bf43363cd08a73c4bbcb26d0a2
2016-07-14 18:21:56 +00:00
Junxiao Shi ff10da6575 table: attach unique_ptr<strategy_choice::Entry> onto NameTree
refs #3164

Change-Id: I5cce7e43dba77cdaaa07347ec7ffca13f242113c
2016-07-13 17:57:43 +00:00
Junxiao Shi af9aa366fd docs: ndn-tlv-ping => ndn-tools in INSTALL
refs #2525

Change-Id: I4c137dc838f399bab3dc1dc4128ea4e39d003b13
2016-07-13 13:18:07 +00:00
Junxiao Shi a6de4290c8 table: don't use shared_ptr in FIB
refs #3164

Change-Id: I5b5eb47d60f6bf5b6389c32ac840f793767e4334
2016-07-12 02:08:10 +00:00
Junxiao Shi 8d843148d2 fw: eliminate fibEntry in Strategy API
Strategy::lookupFib can be used to obtain FIB entry.
FIB lookup is skipped when strategy does not need it.

refs #3205

Change-Id: Icba67229cbc261d9def44ffa91461ea4b09982b2
2016-07-11 22:42:42 +00:00
Junxiao Shi 05cc50ae37 fw: Forwarder::lookupFib
refs #3664

Change-Id: I0e0cc3de997653c93db9b7c89e81ea73b4fb12ac
2016-07-11 22:38:21 +00:00
Junxiao Shi b260017fec rib+tools: delete NRD
refs #3570

Change-Id: I9a6e8eb6c74ea5e09a2e724805f07ca4e58af51c
2016-07-11 08:53:53 +00:00
Vince Lehman 8a4c29e8db fw: Adaptive SRTT-based Forwarding strategy
refs: #3566

Change-Id: Idae198bb0c2ae25e25aeceec0552b1c11be89c14
2016-07-11 08:49:35 +00:00
Junxiao Shi fde3f54d67 rib: register /localhost|localhop/nfd/rib in FIB
refs #2857

Change-Id: If3a471c1c5dbe514929ce5d02a4741960dedc02b
2016-07-10 19:54:53 +00:00
Yanbiao Li cf0db02ced rib: refactor RibManager to use ManagementDispatcher
Change-Id: I3f689de7d043e85531f0b3f4accf65345cde5d9e
refs: #2857
2016-07-09 09:43:19 +08:00
Eric Newberry 25a84074ab websocketpp: Update WebSocket++ to version 0.7.0
refs #3588

Change-Id: Ief26695554bf0bfff374ba47496aaf9b75f9c630
2016-06-20 20:13:33 -07:00
Junxiao Shi 891f47bcfa fw: outgoing Interest pipeline prefers newest in-record
refs #3642

Change-Id: I591a9a9c2efdcb4607b69f2c3be584110f9e14aa
2016-06-20 00:02:11 +00:00
Junxiao Shi d41d6077ce fw: use UnitTestTimeFixture in Forwarder tests
refs #3642

Change-Id: I284716a6e6b4bd83bd9eaf9e952f4b966f0d57e5
2016-06-19 23:35:27 +00:00
Alexander Afanasyev 3d1874af59 build: Adjust order of link flags
The previous order of flags (unintentionally) had `-lboost_log` flag
specified before `-lndn-cxx`.  Incidentally, the order adjustment avoids
a symbol collision between the two libraries that prevented nfd-status
and nfdc from working on Ubuntu 14.04. A proper fix will follow (see #2859).

Change-Id: I68a5d37b013c1bf91b25e707a04ab1f66298a7f4
Refs: #3650
2016-06-19 12:30:15 -07:00
Alexander Afanasyev 6ca6cf7474 core: Specify fully-qualified namespaces in logging macros
Without the full specification, compilation may fail if the logging
used outside ::nfd namespace, e.g., in NFD tools.

Change-Id: I24d733acf920bc90521ac457ae1fe6c846a1fe3e
2016-06-17 16:24:01 -07:00
Alexander Afanasyev 67079664ae ci: Add installation of openssl dependency
Change-Id: Iea19a3a617d770687b4f131a068601255a6c94cf
Refs: #3643
2016-06-15 12:36:08 -07:00
Weiwei Liu f5aee94f15 tests: fix running with non-root user
Refs: #3418

Change-Id: If7f5c05baaff0cf748c87c77057517928539df0d
2016-05-31 11:44:00 -07:00
Junxiao Shi 2879779804 table: fix Pit::find leak of NameTreeEntry
refs #3619

Change-Id: If1043a08c9f4f8bb53cad77d2b6f21991553e1cc
2016-05-26 18:10:18 +00:00
Junxiao Shi b184e5324d table: NameTree::getEntry
NameTree::get is renamed to NameTree::lookup.
NameTree::getEntry is introduced to return the NameTreeEntry on which a table entry is attached.
tableEntry::m_nameTreeEntry is changed to weak_ptr to avoid circular shared_ptr reference.

refs #3608, #3619

Change-Id: I425b6a2eb5fe3024bbaff4ff766eb6739be54b02
2016-05-26 18:09:57 +00:00
spirosmastorakis ff920303df table: fix Pit::erase crash when Interest name contains implicit digest
refs #3608

Change-Id: I41e0cd327b9dcc5f2d3a83f4cebff40c2d302fc1
2016-05-26 18:09:31 +00:00
Alexander Afanasyev e0d71b0bc0 build+tests: Correct detection of privilege elevation/drop and the corresponding test case
Change-Id: I005c2846474a00aeeb3e63a1e9761a3f8bc0a572
Refs: #3494, #3632, #3633
2016-05-25 19:07:11 -07:00
Yumin Xia ab49745afe core: use Boost.Log for logging
This makes the logging backend asynchronous

Change-Id: Ib3417e2ae424c5ae7237c071dc4698ca9769a33c
Refs: #2513
2016-05-11 11:33:13 +08:00
Weiwei Liu ace83ac938 tools: display Nack counters in nfd-status
refs #3569

Change-Id: I59e76d421502417a13efbf088284d278da07bae4
2016-04-27 12:15:54 -07:00
Spencer Lee 75142a10be face: improve UnixStreamChannel test suite
Change-Id: I41eaa3c7d1dea9effdc2e597926b110c9a703084
Refs: #3372
2016-04-27 12:15:06 -07:00
Davide Pesavento b84bd3a8c4 common: remove DECL_FINAL/OVERRIDE macros; use C++11 keywords directly
Change-Id: I71a148b0df7c95387b2caa8e2b9fe93b03ca2399
Refs: #3599
2016-04-27 12:15:06 -07:00
Davide Pesavento cafae24473 build: require gcc >= 4.8.2 and boost >= 1.54.0
Change-Id: I6778f55f43e517a3d1d28387e953412a5292f063
Refs: #3599
2016-04-27 12:15:06 -07:00
Davide Pesavento cc7bee7d80 docs+ci: Ubuntu 12.04 is no longer supported
Change-Id: I423a0f22662383f52413d12dc26d2a4ed08579e2
Refs: #3599, #3600
2016-04-27 12:15:06 -07:00
Alexander Afanasyev 6602b3b179 ci: Update Travis-CI to use Ubuntu Linux 14.04 (trusty) and OS X 10.9 VMs
Due to resource constraints, this commit also makes Travis-CI to build
only once (debug, without precompiled headers, with tests).

Change-Id: I65ec64bca545093efae384dd00b51bbeaf7d9b65
Refs: #3360
2016-04-26 18:43:19 -07:00
Weiwei Liu 4f1afaca16 tests: face system benchmark
Change-Id: Ia2d9125486c57f949e5c855ae6b8d95ffd5aa6e3
Refs: #3567
2016-04-17 20:53:55 -07:00
Yumin Xia d72f092052 tests: PIT and FIB benchmark
Change-Id: I906f82f42dc6ca5dbf0871fae99c47fdda62c7a5
Refs: #3571
2016-04-14 09:00:55 -07:00
Junxiao Shi 8744c97a4d fw: hasPendingOutRecords considers Nack
refs #3545

Change-Id: I986187f58e60090518df2a55a8bd9c1f05771b03
2016-04-12 16:20:35 -07:00
Yanbiao Li df846e5904 core: allow ManagerBase be inherited by RibManager
Change-Id: Ie2613e32460fb109a9f9302a0cc4b4b3400ba9f4
refs: #2857
2016-04-12 14:10:55 -07:00
Davide Pesavento eee53aa5d5 tests: skip IPv6 tests if IPv6 is not available
This commit also renames the getAvailableInterfaceIp() API
to getTestIp(), and improves its expressiveness.

Change-Id: I4b0080fb5e85cd523305ecb14183ef6acb34b5cd
Refs: #3367
2016-04-11 19:58:45 +02:00
Junxiao Shi f3410d8c59 fw: use scope_prefix::LOCALHOST in Forwarder
refs #3546

Change-Id: I10a05b642284e7466746cac121d13e7948ca8667
2016-04-05 13:49:44 -07:00
Junxiao Shi 4846f37117 table: simplify pit::Entry API
refs #3546

Change-Id: I6a9cb83b9e56ce1d1bb6047049378c51781605af
2016-04-05 13:39:30 -07:00
Hila Ben Abraham 39a79be5ae fw: NccStrategy explore potential upstreams
ref: #3411

Change-Id: I30593e01b15a28a32011831659cce6e457633791
2016-03-30 22:00:55 -07:00
Junxiao Shi fef73e4b86 table+fw: move forwarding semantics out of PIT entry
refs #3546

Change-Id: I1e6f87fd81176c116b6d758156da1cf96ea03608
2016-03-29 14:15:05 -07:00
Weiwei Liu 2c5a01a67d tools: nfd-status retrieves ForwarderStatus with SegmentFetcher
refs: #3380

Change-Id: I8fbfba38204c7a111a3940ef751e4ebf61890df2
2016-03-26 23:27:26 -07:00
426 changed files with 28150 additions and 15243 deletions

No files matched your search

+2 -1
View File
@@ -2,7 +2,8 @@
.waf-1*
.waf3-*
.lock*
**/*.pyc
*.pyc
*.pyo
build/
VERSION
unit-tests.conf
+7 -15
View File
@@ -4,26 +4,18 @@ set -e
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
source "$JDIR"/util.sh
if has OSX $NODE_LABELS; then
if has OSX-10.8 $NODE_LABELS; then
EXTRA_FLAGS=--c++11
fi
set -x
set -x
if has OSX $NODE_LABELS; then
brew update
brew upgrade
brew install boost pkg-config cryptopp $EXTRA_FLAGS
brew install boost pkg-config cryptopp openssl
brew cleanup
fi
if has Ubuntu $NODE_LABELS; then
BOOST_PKG=libboost-all-dev
if has Ubuntu-12.04 $NODE_LABELS; then
BOOST_PKG=libboost1.48-all-dev
fi
set -x
sudo apt-get update -qq -y
sudo apt-get -qq -y install build-essential pkg-config $BOOST_PKG \
libcrypto++-dev libsqlite3-dev libpcap-dev
sudo apt-get -qq update
sudo apt-get -qq install build-essential pkg-config libboost-all-dev \
libcrypto++-dev libsqlite3-dev libssl-dev \
libpcap-dev
fi
+6 -5
View File
@@ -1,11 +1,12 @@
#!/usr/bin/env bash
set -x
set -e
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
source "$JDIR"/util.sh
pushd ${CACHE_DIR:-/tmp} >/dev/null
set -x
pushd "${CACHE_DIR:-/tmp}" >/dev/null
INSTALLED_VERSION=$((cd ndn-cxx && git rev-parse HEAD) 2>/dev/null || echo NONE)
@@ -28,9 +29,9 @@ sudo rm -f /usr/local/lib/pkgconfig/libndn-cxx*
pushd ndn-cxx >/dev/null
./waf configure -j1 --color=yes --enable-shared --disable-static --without-osx-keychain
./waf -j1 --color=yes
sudo ./waf install -j1 --color=yes
./waf -j1 --color=yes configure --enable-shared --disable-static --without-osx-keychain
./waf -j1 --color=yes build
sudo ./waf -j1 --color=yes install
popd >/dev/null
popd >/dev/null
+24 -16
View File
@@ -1,7 +1,11 @@
#!/usr/bin/env bash
set -x
set -e
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
source "$JDIR"/util.sh
set -x
git submodule init
git submodule sync
git submodule update
@@ -9,25 +13,29 @@ git submodule update
# Cleanup
sudo ./waf -j1 --color=yes distclean
# Configure/build in optimized mode with tests and precompiled headers
./waf -j1 --color=yes configure --with-tests
./waf -j1 --color=yes build
if [[ $JOB_NAME != *"code-coverage" && $JOB_NAME != *"limited-build" ]]; then
# Configure/build in optimized mode with tests
./waf -j1 --color=yes configure --with-tests
./waf -j1 --color=yes build
# Cleanup
sudo ./waf -j1 --color=yes distclean
# Cleanup
sudo ./waf -j1 --color=yes distclean
# Configure/build in optimized mode without tests and with precompiled headers
./waf -j1 --color=yes configure
./waf -j1 --color=yes build
# Configure/build in optimized mode without tests
./waf -j1 --color=yes configure
./waf -j1 --color=yes build
# Cleanup
sudo ./waf -j1 --color=yes distclean
# Configure/build in debug mode
if [[ "$JOB_NAME" == *"code-coverage" ]]; then
COVERAGE="--with-coverage"
# Cleanup
sudo ./waf -j1 --color=yes distclean
fi
./waf -j1 --color=yes configure --debug --with-tests --without-pch $COVERAGE
# Configure/build in debug mode with tests and without precompiled headers
if [[ $JOB_NAME == *"code-coverage" ]]; then
COVERAGE="--with-coverage"
elif ! has OSX-10.9 $NODE_LABELS && ! has OSX-10.11 $NODE_LABELS; then
ASAN="--with-sanitizer=address"
fi
./waf -j1 --color=yes configure --debug --with-tests --without-pch $COVERAGE $ASAN
./waf -j1 --color=yes build
# (tests will be run against debug version)
+37 -24
View File
@@ -1,41 +1,54 @@
#!/usr/bin/env bash
set -x
set -e
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
source "$JDIR"/util.sh
set -x
# Prepare environment
rm -Rf ~/.ndnx ~/.ndn
rm -Rf ~/.ndn
if has OSX $NODE_LABELS; then
security unlock-keychain -p "named-data"
sudo chgrp admin /dev/bpf*
sudo chmod g+rw /dev/bpf*
fi
if has Linux $NODE_LABELS; then
sudo setcap cap_net_raw,cap_net_admin=eip `pwd`/build/unit-tests-core || true
sudo setcap cap_net_raw,cap_net_admin=eip `pwd`/build/unit-tests-daemon || true
sudo setcap cap_net_raw,cap_net_admin=eip `pwd`/build/unit-tests-rib || true
security unlock-keychain -p named-data
fi
ndnsec-keygen "/tmp/jenkins/$NODE_NAME" | ndnsec-install-cert -
# Run unit tests
# Core
if [[ -n $XUNIT ]]; then
./build/unit-tests-core -l all -- --log_format2=XML --log_sink2=build/xunit-core-report.xml
sudo ./build/unit-tests-core -t TestPrivilegeHelper -l all -- --log_format2=XML --log_sink2=build/xunit-core-sudo-report.xml
BOOST_VERSION=$(python -c "import sys; sys.path.append('build/c4che'); import _cache; print(_cache.BOOST_VERSION_NUMBER);")
./build/unit-tests-daemon -l all -- --log_format2=XML --log_sink2=build/xunit-daemon-report.xml
ut_log_args() {
if (( BOOST_VERSION >= 106200 )); then
echo --logger=HRF,test_suite,stdout:XML,all,build/xunit-${1:-report}.xml
else
if [[ -n $XUNIT ]]; then
echo --log_level=all $( (( BOOST_VERSION >= 106000 )) && echo -- ) \
--log_format2=XML --log_sink2=build/xunit-${1:-report}.xml
else
echo --log_level=test_suite
fi
fi
}
./build/unit-tests-rib -l all -- --log_format2=XML --log_sink2=build/xunit-rib-report.xml
else
./build/unit-tests-core -l test_suite
sudo ./build/unit-tests-core -t TestPrivilegeHelper -l test_suite
ASAN_OPTIONS="color=always"
ASAN_OPTIONS+=":detect_leaks=false"
ASAN_OPTIONS+=":detect_stack_use_after_return=true"
ASAN_OPTIONS+=":check_initialization_order=true"
ASAN_OPTIONS+=":strict_init_order=true"
ASAN_OPTIONS+=":detect_invalid_pointer_pairs=1"
ASAN_OPTIONS+=":detect_container_overflow=false"
ASAN_OPTIONS+=":strict_string_checks=true"
ASAN_OPTIONS+=":strip_path_prefix=${PWD}/"
export ASAN_OPTIONS
./build/unit-tests-daemon -l test_suite
# First run all tests as unprivileged user
./build/unit-tests-core $(ut_log_args core)
./build/unit-tests-daemon $(ut_log_args daemon)
./build/unit-tests-rib $(ut_log_args rib)
./build/unit-tests-tools $(ut_log_args tools)
./build/unit-tests-rib -l test_suite
fi
# Then use sudo to run those tests that need superuser powers
sudo -E ./build/unit-tests-core -t TestPrivilegeHelper $(ut_log_args core-privilege)
sudo -E ./build/unit-tests-daemon -t Face/TestEthernetTransport $(ut_log_args daemon-ethernet)
sudo -E ./build/unit-tests-daemon -t Face/*Factory/ProcessConfig $(ut_log_args daemon-face-config)
sudo -E ./build/unit-tests-daemon -t Mgmt/TestGeneralConfigSection/UserAndGroupConfig,NoUserConfig $(ut_log_args daemon-user-config)
+8 -4
View File
@@ -1,11 +1,15 @@
#!/usr/bin/env bash
set -x
set -e
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
source "$JDIR"/util.sh
if [[ "$JOB_NAME" == *"code-coverage" ]]; then
BASE="`pwd | sed -e 's|/|\\\/|g'`\\"
(cd build && gcovr -x -f $BASE/core -f $BASE/daemon -f $BASE/rib -r ../ -o coverage.xml ./)
set -x
if [[ $JOB_NAME == *"code-coverage" ]]; then
gcovr --object-directory=build \
--output=build/coverage.xml \
--exclude="$PWD/(tests|websocketpp)" \
--root=. \
--xml
fi
+6 -5
View File
@@ -9,17 +9,17 @@ Environment Variables Used in Build Scripts
The list should include at least `[OS_TYPE]`, `[DISTRO_TYPE]`, and `[DISTRO_VERSION]`.
Possible values for Linux OS:
Possible values for Linux:
* `[OS_TYPE]`: `Linux`
* `[DISTRO_TYPE]`: `Ubuntu`
* `[DISTRO_VERSION]`: `Ubuntu-12.04`, `Ubuntu-14.04`, `Ubuntu-15.04`
* `[DISTRO_VERSION]`: `Ubuntu-14.04`, `Ubuntu-16.04`
Possible values of OSX OS:
Possible values for OS X / macOS:
* `[OS_TYPE]`: `OSX`
* `[DISTRO_TYPE]`: `OSX` (can be absent)
* `[DISTRO_VERSION]`: `OSX-10.10`, `OSX-10.9`, `OSX-10.8`, `OSX-10.7`
* `[DISTRO_VERSION]`: `OSX-10.10`, `OSX-10.11`, `OSX-10.12`
- `JOB_NAME`: optional variable to define type of the job. Depending on the defined job type,
the build scripts can perform different tasks.
@@ -27,7 +27,8 @@ Environment Variables Used in Build Scripts
Possible values:
* empty: default build process
* `code-coverage` (Linux OS is assumed): build process with code coverage analysis
* `code-coverage` (Linux OS is assumed): debug build with tests and code coverage analysis
* `limited-build`: only a single debug build with tests
- `CACHE_DIR`: the variable defines a path to folder containing cached files from previous builds,
e.g., a compiled version of ndn-cxx library. If not set, `/tmp` is used.
+13 -4
View File
@@ -1,9 +1,18 @@
has() {
local saved_xtrace
[[ $- == *x* ]] && saved_xtrace=-x || saved_xtrace=+x
set +x
local p=$1
shift
local x
for x in "$@"; do
[[ "${x}" == "${p}" ]] && return 0
local i ret=1
for i in "$@"; do
if [[ "${i}" == "${p}" ]]; then
ret=0
break
fi
done
return 1
set ${saved_xtrace}
return ${ret}
}
+22 -9
View File
@@ -1,15 +1,28 @@
sudo: true
language: cpp
os:
- linux
compiler:
- gcc
sudo: required
language: generic
env:
global:
- JOB_NAME=limited-build
matrix:
include:
- os: linux
dist: trusty
env:
- CXX=g++
- NODE_LABELS="Linux Ubuntu Ubuntu-14.04"
- os: linux
dist: trusty
env:
- CXX=clang++
- NODE_LABELS="Linux Ubuntu Ubuntu-14.04"
- os: osx
osx_image: xcode8.2
env:
- CXX=clang++
- NODE_LABELS="OSX OSX-10.12"
notifications:
email:
on_success: always
on_failure: always
script:
- if [[ $TRAVIS_OS_NAME == linux ]]; then export NODE_LABELS="Linux Ubuntu Ubuntu-12.04"; fi
- if [[ $TRAVIS_OS_NAME == osx ]]; then export NODE_LABELS="OSX OSX-10.10"; fi
- echo $NODE_LABELS
- ./.jenkins
+25 -58
View File
@@ -1,63 +1,30 @@
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
"""
Copyright (c) 2014-2016, Regents of the University of California,
Arizona Board of Regents,
Colorado State University,
University Pierre & Marie Curie, Sorbonne University,
Washington University in St. Louis,
Beijing Institute of Technology,
The University of Memphis.
This file is part of NFD (Named Data Networking Forwarding Daemon).
See AUTHORS.md for complete list of NFD authors and contributors.
NFD is free software: you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
"""
from waflib.Configure import conf
OVERRIDE = '''
class Base
{
virtual void
f(int a);
};
class Derived : public Base
{
virtual void
f(int a) override;
};
'''
@conf
def check_override(self):
self.check_cxx(msg='Checking for override specifier',
fragment=OVERRIDE,
define_name='HAVE_CXX_OVERRIDE',
features='cxx', mandatory=False)
FINAL = '''
class Base
{
virtual void
f(int a);
};
class Derived : public Base
{
virtual void
f(int a) final;
};
'''
@conf
def check_final(self):
self.check_cxx(msg='Checking for final specifier on method',
fragment=FINAL,
define_name='HAVE_CXX_FINAL',
features='cxx', mandatory=False)
CLASS_FINAL = '''
class A final
{
};
'''
@conf
def check_class_final(self):
self.check_cxx(msg='Checking for final specifier on class',
fragment=CLASS_FINAL,
define_name='HAVE_CXX_CLASS_FINAL',
features='cxx', mandatory=False)
def configure(conf):
conf.check_override()
conf.check_final()
conf.check_class_final()
pass
+6 -8
View File
@@ -60,7 +60,7 @@ def add_supported_cxxflags(self, cxxflags):
supportedFlags += [flag]
self.end_msg(' '.join(supportedFlags))
self.env.CXXFLAGS = supportedFlags + self.env.CXXFLAGS
self.env.prepend_value('CXXFLAGS', supportedFlags)
@Configure.conf
def add_supported_linkflags(self, linkflags):
@@ -78,7 +78,7 @@ def add_supported_linkflags(self, linkflags):
supportedFlags += [flag]
self.end_msg(' '.join(supportedFlags))
self.env.LINKFLAGS = supportedFlags + self.env.LINKFLAGS
self.env.prepend_value('LINKFLAGS', supportedFlags)
class CompilerFlags(object):
@@ -108,6 +108,7 @@ class GccBasicFlags(CompilerFlags):
'-Werror',
'-Wno-unused-parameter',
'-Wno-error=maybe-uninitialized', # Bug #1615
'-Wno-error=deprecated-declarations', # Bug #3795
]
return flags
@@ -126,16 +127,12 @@ class GccFlags(GccBasicFlags):
def getGeneralFlags(self, conf):
flags = super(GccFlags, self).getGeneralFlags(conf)
version = tuple(int(i) for i in conf.env['CC_VERSION'])
if version < (4, 6, 0):
if version < (4, 8, 2):
conf.fatal('The version of gcc you are using (%s) is too old.\n' %
'.'.join(conf.env['CC_VERSION']) +
'The minimum supported gcc version is 4.6.0.')
elif version < (4, 7, 0):
flags['CXXFLAGS'] += ['-std=c++0x']
'The minimum supported gcc version is 4.8.2.')
else:
flags['CXXFLAGS'] += ['-std=c++11']
if version < (4, 8, 0):
flags['DEFINES'] += ['_GLIBCXX_USE_NANOSLEEP'] # Bug #2499
return flags
def getDebugFlags(self, conf):
@@ -172,6 +169,7 @@ class ClangFlags(GccBasicFlags):
'-Wno-error=unneeded-internal-declaration', # Bug #1588
'-Wno-error=deprecated-register',
'-Wno-error=keyword-macro', # Bug #3235
'-Wno-error=infinite-recursion', # Bug #3358
]
return flags
+22
View File
@@ -0,0 +1,22 @@
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
def options(opt):
opt.add_option('--with-sanitizer', action='store', default='', dest='sanitizers',
help='Comma-separated list of compiler sanitizers to enable [default=none]')
def configure(conf):
for san in conf.options.sanitizers.split(','):
if not san:
continue
sanflag = '-fsanitize=%s' % san
conf.start_msg('Checking if compiler supports %s' % sanflag)
if conf.check_cxx(cxxflags=['-Werror', sanflag, '-fno-omit-frame-pointer'],
linkflags=[sanflag], mandatory=False):
conf.end_msg('yes')
conf.env.append_unique('CXXFLAGS', [sanflag, '-fno-omit-frame-pointer'])
conf.env.append_unique('LINKFLAGS', [sanflag])
else:
conf.end_msg('no', color='RED')
conf.fatal('%s sanitizer is not supported by the current compiler' % san)
-11
View File
@@ -6,23 +6,12 @@
from waflib import Configure
IS_DEFAULT_CONSTRUCTIBLE_CHECK = '''
#include <type_traits>
static_assert(std::is_default_constructible<int>::value, "");
'''
IS_MOVE_CONSTRUCTIBLE_CHECK = '''
#include <type_traits>
static_assert(std::is_move_constructible<int>::value, "");
'''
def configure(conf):
if conf.check_cxx(msg='Checking for std::is_default_constructible',
fragment=IS_DEFAULT_CONSTRUCTIBLE_CHECK,
features='cxx', mandatory=False):
conf.define('HAVE_IS_DEFAULT_CONSTRUCTIBLE', 1)
conf.env['HAVE_IS_DEFAULT_CONSTRUCTIBLE'] = True
if conf.check_cxx(msg='Checking for std::is_move_constructible',
fragment=IS_MOVE_CONSTRUCTIBLE_CHECK,
features='cxx', mandatory=False):
+7 -10
View File
@@ -1,17 +1,14 @@
# encoding: utf-8
from waflib import Options, Logs, Errors
from waflib.Configure import conf
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
from waflib import Options, Logs, Errors, Configure
import re
def addWebsocketOptions(self, opt):
opt.add_option('--without-websocket', action='store_false', default=True,
dest='with_websocket',
help='Disable WebSocket face support')
dest='with_websocket', help='Disable WebSocket face support')
setattr(Options.OptionsContext, "addWebsocketOptions", addWebsocketOptions)
@conf
@Configure.conf
def checkWebsocket(self, **kw):
if not self.options.with_websocket:
return
@@ -36,8 +33,8 @@ def checkWebsocket(self, **kw):
# Looking for the following:
# static int const major_version = 0;
# static int const minor_version = 5;
# static int const patch_version = 1;
# static int const minor_version = 7;
# static int const patch_version = 0;
version = [None, None, None]
@@ -71,7 +68,7 @@ def checkWebsocket(self, **kw):
Logs.warn(' git submodule init && git submodule update')
Logs.warn('Otherwise, manually download and extract websocketpp library:')
Logs.warn(' mkdir websocketpp')
Logs.warn(' curl -L https://github.com/zaphoyd/websocketpp/archive/0.5.1.tar.gz > websocket.tar.gz')
Logs.warn(' curl -L https://github.com/zaphoyd/websocketpp/archive/0.7.0.tar.gz > websocket.tar.gz')
Logs.warn(' tar zxf websocket.tar.gz -C websocketpp/ --strip 1')
Logs.warn('Alternatively, WebSocket support can be disabled with --without-websocket')
self.fatal("The configuration failed")
+2 -2
View File
@@ -43,7 +43,7 @@ volunteers.
* University Pierre & Marie Curie, Sorbonne University
* Davide Pesavento <http://www.lip6.fr/actualite/personnes-fiche.php?ident=D1469>
* Davide Pesavento <https://www.linkedin.com/in/davidepesavento>
* Giulio Grassi <http://www.lip6.fr/actualite/personnes-fiche.php?ident=D1461>
* Giovanni Pau <http://www.cs.ucla.edu/~gpau/Giovanni_Paus_Home_Page/Home.html>
@@ -73,7 +73,7 @@ in the library:
* Tai-Lin Chu <https://www.linkedin.com/pub/tai-lin-chu/55/5b2/669>
* Spyridon Mastorakis <http://cs.ucla.edu/~mastorakis/>
* Eric Newberry <http://ericnewberry.com>
* Eric Newberry <http://cs.arizona.edu/~enewberry/>
* Yukai Tu <tuyukai1994@gmail.com>
* João Pereira <http://website.jpereira.co.uk>
* Mathias Gibbens <gibmat@cs.arizona.edu>
+1 -1
View File
@@ -14,7 +14,7 @@ NFD relies on third-party software and libraries, licensed under the following l
- SQLite is in [public domain](http://www.sqlite.org/copyright.html)
- WebSocket++ library licensed under conditions of
[BSD license](https://github.com/zaphoyd/websocketpp/blob/ac5d7ea5af9734de965688b54a7860259887b537/COPYING)
[BSD license](https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/COPYING)
- Libpcap library licensed under conditions of
[a 3-clause BSD license](http://www.tcpdump.org/license.html).
+4 -4
View File
@@ -30,12 +30,12 @@ Include the following license boilerplate into all `.hpp` and `.cpp` files:
*/
If you are affiliated to an NSF-supported NDN project institution, please use the [NDN Team License
Boilerplate](http://redmine.named-data.net/projects/nfd/wiki/NDN_Team_License_Boilerplate_(NFD)).
Boilerplate](https://redmine.named-data.net/projects/nfd/wiki/NDN_Team_License_Boilerplate_(NFD)).
Recommendations
---------------
NFD code is subject to NFD [code style](http://redmine.named-data.net/projects/nfd/wiki/CodeStyle).
NFD code is subject to NFD [code style](https://redmine.named-data.net/projects/nfd/wiki/CodeStyle).
Running unit-tests
@@ -57,7 +57,7 @@ The simplest way to run tests, is just to run the compiled binary without any pa
# Run NFD RIB management tests
./build/unit-tests-rib
However, [Boost.Test framework](http://www.boost.org/doc/libs/1_48_0/libs/test/doc/html/)
However, [Boost.Test framework](http://www.boost.org/doc/libs/1_54_0/libs/test/doc/html/index.html)
is very flexible and allows a number of run-time customization of what tests should be run.
For example, it is possible to choose to run only a specific test suite, only a specific
test case within a suite, or specific test cases within specific test suites:
@@ -90,5 +90,5 @@ or `-p` to show progress bar:
There are many more command line options available, information about
which can be obtained either from the command line using `--help`
switch, or online on [Boost.Test library](http://www.boost.org/doc/libs/1_48_0/libs/test/doc/html/)
switch, or online on [Boost.Test library](http://www.boost.org/doc/libs/1_54_0/libs/test/doc/html/index.html)
website.
+7 -5
View File
@@ -1,15 +1,17 @@
NFD - Named Data Networking Forwarding Daemon
=============================================
[![Build Status](https://travis-ci.org/named-data/NFD.svg?branch=master)](https://travis-ci.org/named-data/NFD)
For complete documentation, including step-by-step installation instructions and
tutorials, please visit the [NFD homepage](http://named-data.net/doc/NFD/).
tutorials, please visit the [NFD homepage](https://named-data.net/doc/NFD/).
## Overview
NFD is a network forwarder that implements and evolves together with the Named Data
Networking (NDN) [protocol](http://named-data.net/doc/ndn-tlv/). After the initial
Networking (NDN) [protocol](https://named-data.net/doc/ndn-tlv/). After the initial
release, NFD will become a core component of the
[NDN Platform](http://named-data.net/codebase/platform/) and will follow the same release
[NDN Platform](https://named-data.net/codebase/platform/) and will follow the same release
cycle.
NFD is an open and free software package licensed under GPL 3.0 license and is the
@@ -19,14 +21,14 @@ limitation, refer to
[`COPYING.md`](https://github.com/named-data/NFD/blob/master/COPYING.md).
NFD is developed by a community effort. Although the first release was mostly done by the
members of [NSF-sponsored NDN project team](http://named-data.net/project/participants/),
members of [NSF-sponsored NDN project team](https://named-data.net/project/participants/),
it already contains significant contributions from people outside the project team (for
more details, refer to
[`AUTHORS.md`](https://github.com/named-data/NFD/blob/master/AUTHORS.md)). We strongly
encourage participation from all interested parties, since broader community support is
key for NDN to succeed as a new Internet architecture. Bug reports and feedback are
highly appreciated and can be made through
[Redmine site](http://redmine.named-data.net/projects/nfd) and the
[Redmine site](https://redmine.named-data.net/projects/nfd) and the
[ndn-interest mailing list](http://www.lists.cs.ucla.edu/mailman/listinfo/ndn-interest).
The main design goal of NFD is to support diverse experimentation of NDN technology. The
+67
View File
@@ -0,0 +1,67 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NFD_CORE_ASSERTS_HPP
#define NFD_CORE_ASSERTS_HPP
#include "common.hpp"
#include <boost/concept/assert.hpp>
#include <boost/concept_check.hpp>
#include <type_traits>
namespace nfd {
namespace detail {
// As of Boost 1.54.0, the internal implementation of BOOST_CONCEPT_ASSERT does not allow
// multiple assertions on the same line, so we have to combine multiple concepts together.
template<typename T>
class StlForwardIteratorConcept : public boost::ForwardIterator<T>
, public boost::DefaultConstructible<T>
{
};
} // namespace detail
} // namespace nfd
/** \brief assert T is default constructible
* \sa http://en.cppreference.com/w/cpp/concept/DefaultConstructible
*/
#define NFD_ASSERT_DEFAULT_CONSTRUCTIBLE(T) \
static_assert(std::is_default_constructible<T>::value, \
#T " must be default-constructible"); \
BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<T>))
/** \brief assert T is a forward iterator
* \sa http://en.cppreference.com/w/cpp/concept/ForwardIterator
* \note A forward iterator should be default constructible, but boost::ForwardIterator follows
* SGI standard which doesn't require DefaultConstructible, so a separate check is needed.
*/
#define NFD_ASSERT_FORWARD_ITERATOR(T) \
BOOST_CONCEPT_ASSERT((::nfd::detail::StlForwardIteratorConcept<T>)); \
static_assert(std::is_default_constructible<T>::value, \
#T " must be default-constructible")
#endif // NFD_CORE_ASSERTS_HPP
+7 -36
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -23,51 +23,23 @@
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NFD_COMMON_HPP
#define NFD_COMMON_HPP
#ifndef NFD_CORE_COMMON_HPP
#define NFD_CORE_COMMON_HPP
#include "config.hpp"
#include "core/config.hpp"
#ifdef WITH_TESTS
#define VIRTUAL_WITH_TESTS virtual
#define PUBLIC_WITH_TESTS_ELSE_PROTECTED public
#define PUBLIC_WITH_TESTS_ELSE_PRIVATE public
#define PROTECTED_WITH_TESTS_ELSE_PRIVATE protected
#define FINAL_UNLESS_WITH_TESTS
#else
#define VIRTUAL_WITH_TESTS
#define PUBLIC_WITH_TESTS_ELSE_PROTECTED protected
#define PUBLIC_WITH_TESTS_ELSE_PRIVATE private
#define PROTECTED_WITH_TESTS_ELSE_PRIVATE private
#endif
/** \def DECL_OVERRIDE
* \brief expands to 'override' if compiler supports 'override' specifier,
* otherwise expands to nothing
*/
#ifdef HAVE_CXX_OVERRIDE
#define DECL_OVERRIDE override
#else
#define DECL_OVERRIDE
#endif
/** \def DECL_FINAL
* \brief expands to 'final' if compiler supports 'final' specifier on method,
* otherwise expands to nothing
*/
#ifdef HAVE_CXX_FINAL
#define DECL_FINAL final
#else
#define DECL_FINAL
#endif
/** \def DECL_CLASS_FINAL
* \brief expands to 'final' if compiler supports 'final' specifier on class,
* otherwise expands to nothing
*/
#ifdef HAVE_CXX_CLASS_FINAL
#define DECL_CLASS_FINAL final
#else
#define DECL_CLASS_FINAL
#define FINAL_UNLESS_WITH_TESTS final
#endif
#include <cstddef>
@@ -93,7 +65,6 @@
#include <ndn-cxx/util/face-uri.hpp>
#include <ndn-cxx/util/signal.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/asio.hpp>
#include <boost/assert.hpp>
#include <boost/lexical_cast.hpp>
@@ -146,4 +117,4 @@ namespace signal = ndn::util::signal;
} // namespace nfd
#endif // NFD_COMMON_HPP
#endif // NFD_CORE_COMMON_HPP
+20 -26
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -59,10 +59,10 @@ ConfigFile::ignoreUnknownSection(const std::string& filename,
}
bool
ConfigFile::parseYesNo(const ConfigSection::value_type& option,
ConfigFile::parseYesNo(const ConfigSection& node, const std::string& key,
const std::string& sectionName)
{
auto value = option.second.get_value<std::string>();
auto value = node.get_value<std::string>();
if (value == "yes") {
return true;
@@ -72,7 +72,7 @@ ConfigFile::parseYesNo(const ConfigSection::value_type& option,
}
BOOST_THROW_EXCEPTION(Error("Invalid value \"" + value + "\" for option \"" +
option.first + "\" in \"" + sectionName + "\" section"));
key + "\" in \"" + sectionName + "\" section"));
}
void
@@ -85,14 +85,10 @@ ConfigFile::addSectionHandler(const std::string& sectionName,
void
ConfigFile::parse(const std::string& filename, bool isDryRun)
{
std::ifstream inputFile;
inputFile.open(filename.c_str());
if (!inputFile.good() || !inputFile.is_open())
{
std::string msg = "Failed to read configuration file: ";
msg += filename;
BOOST_THROW_EXCEPTION(Error(msg));
}
std::ifstream inputFile(filename);
if (!inputFile.good() || !inputFile.is_open()) {
BOOST_THROW_EXCEPTION(Error("Failed to read configuration file: " + filename));
}
parse(inputFile, isDryRun, filename);
inputFile.close();
}
@@ -107,18 +103,16 @@ ConfigFile::parse(const std::string& input, bool isDryRun, const std::string& fi
void
ConfigFile::parse(std::istream& input, bool isDryRun, const std::string& filename)
{
try
{
boost::property_tree::read_info(input, m_global);
}
catch (const boost::property_tree::info_parser_error& error)
{
std::stringstream msg;
msg << "Failed to parse configuration file";
msg << " " << filename;
msg << " " << error.message() << " line " << error.line();
BOOST_THROW_EXCEPTION(Error(msg.str()));
}
try {
boost::property_tree::read_info(input, m_global);
}
catch (const boost::property_tree::info_parser_error& error) {
std::stringstream msg;
msg << "Failed to parse configuration file";
msg << " " << filename;
msg << " " << error.message() << " line " << error.line();
BOOST_THROW_EXCEPTION(Error(msg.str()));
}
process(isDryRun, filename);
}
@@ -144,7 +138,7 @@ ConfigFile::process(bool isDryRun, const std::string& filename) const
for (const auto& i : m_global) {
try {
ConfigSectionHandler subscriber = m_subscriptions.at(i.first);
const ConfigSectionHandler& subscriber = m_subscriptions.at(i.first);
subscriber(i.second, isDryRun, filename);
}
catch (const std::out_of_range&) {
@@ -153,4 +147,4 @@ ConfigFile::process(bool isDryRun, const std::string& filename) const
}
}
}
} // namespace nfd
+55 -37
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -32,19 +32,29 @@
namespace nfd {
/** \brief a config file section
*/
typedef boost::property_tree::ptree ConfigSection;
/// \brief callback for config file sections
typedef function<void(const ConfigSection& /*section*/,
bool /*isDryRun*/,
const std::string& /*filename*/)> ConfigSectionHandler;
/** \brief an optional config file section
*/
typedef boost::optional<const ConfigSection&> OptionalConfigSection;
/// \brief callback for config file sections without a subscribed handler
typedef function<void(const std::string& /*filename*/,
const std::string& /*sectionName*/,
const ConfigSection& /*section*/,
bool /*isDryRun*/)> UnknownConfigSectionHandler;
/** \brief callback to process a config file section
*/
typedef function<void(const ConfigSection& section,
bool isDryRun,
const std::string& filename)> ConfigSectionHandler;
/** \brief callback to process a config file section without a \p ConfigSectionHandler
*/
typedef function<void(const std::string& filename,
const std::string& sectionName,
const ConfigSection& section,
bool isDryRun)> UnknownConfigSectionHandler;
/** \brief configuration file parsing utility
*/
class ConfigFile : noncopyable
{
public:
@@ -61,6 +71,7 @@ public:
explicit
ConfigFile(UnknownConfigSectionHandler unknownSectionCallback = throwErrorOnUnknownSection);
public: // unknown section handlers
static void
throwErrorOnUnknownSection(const std::string& filename,
const std::string& sectionName,
@@ -73,27 +84,50 @@ public:
const ConfigSection& section,
bool isDryRun);
/**
* \brief parse a config option that can be either "yes" or "no"
*
* \return true if "yes", false if "no"
* \throw Error the value is neither "yes" nor "no"
public: // parse helpers
/** \brief parse a config option that can be either "yes" or "no"
* \retval true "yes"
* \retval false "no"
* \throw Error the value is neither "yes" nor "no"
*/
static bool
parseYesNo(const ConfigSection::value_type& option,
const std::string& sectionName);
parseYesNo(const ConfigSection& node, const std::string& key, const std::string& sectionName);
static bool
parseYesNo(const ConfigSection::value_type& option, const std::string& sectionName)
{
return parseYesNo(option.second, option.first, sectionName);
}
/**
* \brief parse a numeric (integral or floating point) config option
* \tparam T an arithmetic type
*
* \return the numeric value of the parsed option
* \throw Error the value cannot be converted to the specified type
*/
template <typename T>
static typename std::enable_if<std::is_arithmetic<T>::value, T>::type
parseNumber(const ConfigSection::value_type& option,
const std::string& sectionName);
template<typename T>
static T
parseNumber(const ConfigSection& node, const std::string& key, const std::string& sectionName)
{
static_assert(std::is_arithmetic<T>::value, "T must be an arithmetic type");
boost::optional<T> value = node.get_value_optional<T>();
if (value) {
return *value;
}
BOOST_THROW_EXCEPTION(Error("Invalid value \"" + node.get_value<std::string>() +
"\" for option \"" + key + "\" in \"" + sectionName + "\" section"));
}
template <typename T>
static T
parseNumber(const ConfigSection::value_type& option, const std::string& sectionName)
{
return parseNumber<T>(option.second, option.first, sectionName);
}
public: // setup and parsing
/// \brief setup notification of configuration file sections
void
addSectionHandler(const std::string& sectionName,
@@ -146,22 +180,6 @@ private:
ConfigSection m_global;
};
template <typename T>
inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type
ConfigFile::parseNumber(const ConfigSection::value_type& option,
const std::string& sectionName)
{
auto value = option.second.get_value<std::string>();
try {
return boost::lexical_cast<T>(value);
}
catch (const boost::bad_lexical_cast&) {
BOOST_THROW_EXCEPTION(Error("Invalid value \"" + value + "\" for option \"" +
option.first + "\" in \"" + sectionName + "\" section"));
}
}
} // namespace nfd
#endif // NFD_CORE_CONFIG_FILE_HPP
+2 -1
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,6 +27,7 @@
#define NFD_CORE_EXTENDED_ERROR_MESSAGE_HPP
#include <boost/exception/get_error_info.hpp>
#include <sstream>
namespace nfd {
+33 -16
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -25,6 +25,9 @@
#include "logger-factory.hpp"
#include <ndn-cxx/util/logging.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/range/adaptor/map.hpp>
#ifdef HAVE_CUSTOM_LOGGER
@@ -53,6 +56,15 @@ LoggerFactory::LoggerFactory()
m_levelNames["DEBUG"] = LOG_DEBUG;
m_levelNames["TRACE"] = LOG_TRACE;
m_levelNames["ALL"] = LOG_ALL;
// Let ndn-cxx logging facility initialize Boost.Log backend,
// so that only one sink is attached to Boost.Log core.
ndn::util::Logging::setDestination(std::clog);
}
LoggerFactory::~LoggerFactory()
{
ndn::util::Logging::flush();
}
void
@@ -64,8 +76,7 @@ LoggerFactory::setConfigFile(ConfigFile& config)
LogLevel
LoggerFactory::parseLevel(const std::string& level)
{
std::string upperLevel = level;
boost::to_upper(upperLevel);
std::string upperLevel = boost::to_upper_copy(level);
// std::cerr << "parsing level: " << upperLevel << std::endl;;
// std::cerr << "# levels: " << m_levelNames.size() << std::endl;
@@ -112,19 +123,19 @@ LoggerFactory::onConfig(const ConfigSection& section,
bool isDryRun,
const std::string& filename)
{
// log
// {
// ; default_level specifies the logging level for modules
// ; that are not explicitly named. All debugging levels
// ; listed above the selected value are enabled.
//
// default_level INFO
//
// ; You may also override the default for specific modules:
//
// FibManager DEBUG
// Forwarder WARN
// }
// log
// {
// ; default_level specifies the logging level for modules
// ; that are not explicitly named. All debugging levels
// ; listed above the selected value are enabled.
//
// default_level INFO
//
// ; You may also override the default for specific modules:
//
// FibManager DEBUG
// Forwarder WARN
// }
if (!isDryRun) {
ConfigSection::const_assoc_iterator item = section.find("default_level");
@@ -173,6 +184,12 @@ LoggerFactory::setDefaultLevel(LogLevel level)
}
}
void
LoggerFactory::flushBackend()
{
ndn::util::Logging::flush();
}
Logger&
LoggerFactory::create(const std::string& moduleName)
{
+8 -1
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -35,6 +35,8 @@
#include "config-file.hpp"
#include "logger.hpp"
#include <mutex>
namespace nfd {
class LoggerFactory : noncopyable
@@ -77,10 +79,15 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
setDefaultLevel(LogLevel level);
void
flushBackend();
private:
LoggerFactory();
~LoggerFactory();
Logger&
createLogger(const std::string& moduleName);
+6 -10
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -36,25 +36,23 @@
namespace nfd {
std::mutex g_logMutex;
Logger::Logger(const std::string& name, LogLevel level)
: m_moduleName(name)
, m_enabledLogLevel(level)
{
}
const char*
Logger::now()
std::ostream&
operator<<(std::ostream& os, const LoggerTimestamp&)
{
using namespace ndn::time;
static const microseconds::rep ONE_SECOND = 1000000;
microseconds::rep microsecondsSinceEpoch = duration_cast<microseconds>(
system_clock::now().time_since_epoch()).count();
system_clock::now().time_since_epoch()).count();
// 10 (whole seconds) + '.' + 6 (fraction) + '\0'
static char buffer[10 + 1 + 6 + 1];
char buffer[10 + 1 + 6 + 1];
BOOST_ASSERT_MSG(microsecondsSinceEpoch / ONE_SECOND <= 9999999999L,
"whole seconds cannot fit in 10 characters");
@@ -66,9 +64,7 @@ Logger::now()
microsecondsSinceEpoch / ONE_SECOND,
microsecondsSinceEpoch % ONE_SECOND);
// It's okay to return a statically allocated buffer, because Logger::now() is invoked
// only once per log macro.
return buffer;
return os << buffer;
}
} // namespace nfd
+40 -24
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -31,8 +31,8 @@
#ifdef HAVE_CUSTOM_LOGGER
#include "custom-logger.hpp"
#else
#include <mutex>
#include <boost/log/common.hpp>
#include <boost/log/sources/logger.hpp>
namespace nfd {
@@ -84,12 +84,8 @@ public:
m_moduleName = name;
}
/** \return string representation of time since epoch: seconds.microseconds
* \warning Return value is in a statically allocated buffer,
* which subsequent calls will overwrite.
*/
static const char*
now();
public:
boost::log::sources::logger boostLogger;
private:
std::string m_moduleName;
@@ -103,6 +99,20 @@ operator<<(std::ostream& output, const Logger& logger)
return output;
}
/**
* \brief a tag that writes a timestamp upon stream output
*/
struct LoggerTimestamp
{
};
/**
* \brief write a timestamp to \p os
* \note This function is thread-safe.
*/
std::ostream&
operator<<(std::ostream& os, const LoggerTimestamp&);
} // namespace nfd
#include "core/logger-factory.hpp"
@@ -110,36 +120,42 @@ operator<<(std::ostream& output, const Logger& logger)
namespace nfd {
#define NFD_LOG_INIT(name) \
static nfd::Logger& g_logger = nfd::LoggerFactory::create(name)
static ::nfd::Logger& g_logger = ::nfd::LoggerFactory::create(name)
#define NFD_LOG_INCLASS_DECLARE() \
static nfd::Logger& g_logger
static ::nfd::Logger& g_logger
#define NFD_LOG_INCLASS_DEFINE(cls, name) \
nfd::Logger& cls::g_logger = nfd::LoggerFactory::create(name)
::nfd::Logger& cls::g_logger = ::nfd::LoggerFactory::create(name)
#define NFD_LOG_INCLASS_TEMPLATE_DEFINE(cls, name) \
template<class T> \
nfd::Logger& cls<T>::g_logger = nfd::LoggerFactory::create(name)
::nfd::Logger& cls<T>::g_logger = ::nfd::LoggerFactory::create(name)
#define NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(cls, specialization, name) \
template<> \
nfd::Logger& cls<specialization>::g_logger = nfd::LoggerFactory::create(name)
::nfd::Logger& cls<specialization>::g_logger = ::nfd::LoggerFactory::create(name)
#define NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(cls, s1, s2, name) \
template<> \
nfd::Logger& cls<s1, s2>::g_logger = nfd::LoggerFactory::create(name)
::nfd::Logger& cls<s1, s2>::g_logger = ::nfd::LoggerFactory::create(name)
extern std::mutex g_logMutex;
#if (BOOST_VERSION >= 105900) && (BOOST_VERSION < 106000)
// workaround Boost bug 11549
#define NFD_BOOST_LOG(x) BOOST_LOG(x) << ""
#else
#define NFD_BOOST_LOG(x) BOOST_LOG(x)
#endif
#define NFD_LOG(level, msg, expression) \
do { \
if (g_logger.isEnabled(::nfd::LOG_##level)) { \
std::lock_guard<std::mutex> lock(::nfd::g_logMutex); \
std::clog << ::nfd::Logger::now() << " "#msg": " \
<< "[" << g_logger << "] " << expression << "\n"; \
} \
} while (false)
#define NFD_LOG_LINE(msg, expression) \
::nfd::LoggerTimestamp{} << " "#msg": " << "[" << g_logger << "] " << expression
#define NFD_LOG(level, msg, expression) \
do { \
if (g_logger.isEnabled(::nfd::LOG_##level)) { \
NFD_BOOST_LOG(g_logger.boostLogger) << NFD_LOG_LINE(msg, expression); \
} \
} while (false)
#define NFD_LOG_TRACE(expression) NFD_LOG(TRACE, TRACE, expression)
#define NFD_LOG_DEBUG(expression) NFD_LOG(DEBUG, DEBUG, expression)
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -31,13 +31,10 @@ using ndn::mgmt::ValidateParameters;
using ndn::mgmt::Authorization;
ManagerBase::ManagerBase(Dispatcher& dispatcher,
CommandValidator& validator,
const std::string& module)
: m_dispatcher(dispatcher)
, m_validator(validator)
, m_mgmtModuleName(module)
, m_module(module)
{
m_validator.addSupportedPrivilege(module);
}
void
@@ -55,20 +52,6 @@ ManagerBase::registerNotificationStream(const std::string& verb)
return m_dispatcher.addNotificationStream(makeRelPrefix(verb));
}
void
ManagerBase::authorize(const Name& prefix, const Interest& interest,
const ndn::mgmt::ControlParameters* params,
ndn::mgmt::AcceptContinuation accept,
ndn::mgmt::RejectContinuation reject)
{
BOOST_ASSERT(params != nullptr);
BOOST_ASSERT(typeid(*params) == typeid(ndn::nfd::ControlParameters));
m_validator.validate(interest,
bind(&ManagerBase::extractRequester, this, interest, accept),
bind([&] { reject(ndn::mgmt::RejectReply::STATUS403); }));
}
void
ManagerBase::extractRequester(const Interest& interest,
ndn::mgmt::AcceptContinuation accept)
@@ -116,5 +99,4 @@ ManagerBase::handleCommand(shared_ptr<nfd::ControlCommand> command,
handler(*command, prefix, interest, parameters, done);
}
} // namespace nfd
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -23,16 +23,15 @@
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NFD_DAEMON_MGMT_MANAGER_BASE_HPP
#define NFD_DAEMON_MGMT_MANAGER_BASE_HPP
#ifndef NFD_CORE_MANAGER_BASE_HPP
#define NFD_CORE_MANAGER_BASE_HPP
#include "common.hpp"
#include "mgmt/command-validator.hpp"
#include <ndn-cxx/mgmt/dispatcher.hpp>
#include <ndn-cxx/management/nfd-control-command.hpp>
#include <ndn-cxx/management/nfd-control-response.hpp>
#include <ndn-cxx/management/nfd-control-parameters.hpp>
#include <ndn-cxx/mgmt/nfd/control-command.hpp>
#include <ndn-cxx/mgmt/nfd/control-response.hpp>
#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
namespace nfd {
@@ -43,10 +42,10 @@ using ndn::nfd::ControlResponse;
using ndn::nfd::ControlParameters;
/**
* @brief a collection of common functions shared by all NFD managers,
* @brief a collection of common functions shared by all NFD managers and RIB manager,
* such as communicating with the dispatcher and command validator.
*/
class ManagerBase : public noncopyable
class ManagerBase : noncopyable
{
public:
class Error : public std::runtime_error
@@ -61,9 +60,14 @@ public:
public:
ManagerBase(Dispatcher& dispatcher,
CommandValidator& validator,
const std::string& module);
const std::string&
getModule() const
{
return m_module;
}
PUBLIC_WITH_TESTS_ELSE_PROTECTED: // registrations to the dispatcher
// difference from mgmt::ControlCommand: accepts nfd::ControlParameters
@@ -84,27 +88,7 @@ PUBLIC_WITH_TESTS_ELSE_PROTECTED: // registrations to the dispatcher
ndn::mgmt::PostNotification
registerNotificationStream(const std::string& verb);
PUBLIC_WITH_TESTS_ELSE_PRIVATE: // command validation
/**
* @brief validate a request for ControlCommand.
*
* This is called by the dispatcher.
*
* @pre params != null
* @pre typeid(*params) == typeid(ndn::nfd::ControlParameters)
*
* @param prefix the top prefix
* @param interest a request for ControlCommand
* @param params the parameters for ControlCommand
* @param accept callback of successful validation, take the requester string as a argument
* @param reject callback of failure in validation, take the action code as a argument
*/
void
authorize(const Name& prefix, const Interest& interest,
const ndn::mgmt::ControlParameters* params,
ndn::mgmt::AcceptContinuation accept,
ndn::mgmt::RejectContinuation reject);
PUBLIC_WITH_TESTS_ELSE_PROTECTED:
/**
* @brief extract a requester from a ControlCommand request
*
@@ -117,7 +101,13 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE: // command validation
extractRequester(const Interest& interest,
ndn::mgmt::AcceptContinuation accept);
PUBLIC_WITH_TESTS_ELSE_PRIVATE: // helpers
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/**
* @return an authorization function for specified management module and verb
*/
virtual ndn::mgmt::Authorization
makeAuthorization(const std::string& verb) = 0;
/**
* @brief validate the @p parameters for a given @p command
*
@@ -150,15 +140,14 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE: // helpers
makeRelPrefix(const std::string& verb);
private:
Dispatcher& m_dispatcher;
CommandValidator& m_validator;
std::string m_mgmtModuleName;
Dispatcher& m_dispatcher;
std::string m_module;
};
inline PartialName
ManagerBase::makeRelPrefix(const std::string& verb)
{
return PartialName(m_mgmtModuleName).append(verb);
return PartialName(m_module).append(verb);
}
template<typename Command>
@@ -170,11 +159,11 @@ ManagerBase::registerCommandHandler(const std::string& verb,
m_dispatcher.addControlCommand<ControlParameters>(
makeRelPrefix(verb),
bind(&ManagerBase::authorize, this, _1, _2, _3, _4, _5),
makeAuthorization(verb),
bind(&ManagerBase::validateParameters, cref(*command), _1),
bind(&ManagerBase::handleCommand, command, handler, _1, _2, _3, _4));
}
} // namespace nfd
#endif // NFD_DAEMON_MGMT_MANAGER_BASE_HPP
#endif // NFD_CORE_MANAGER_BASE_HPP
+129
View File
@@ -0,0 +1,129 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "network-interface-predicate.hpp"
#include "config-file.hpp"
#include "network-interface.hpp"
#include "network.hpp"
namespace nfd {
NetworkInterfacePredicate::NetworkInterfacePredicate()
{
this->clear();
}
void
NetworkInterfacePredicate::clear()
{
m_whitelist = std::set<std::string>{"*"};
m_blacklist.clear();
}
static void
parseList(std::set<std::string>& set, const boost::property_tree::ptree& list, const std::string& section)
{
set.clear();
for (const auto& item : list) {
if (item.first == "*") {
// insert wildcard
set.insert(item.first);
}
else if (item.first == "ifname") {
// very basic sanity check for interface names
auto name = item.second.get_value<std::string>();
if (name.empty()) {
BOOST_THROW_EXCEPTION(ConfigFile::Error("Empty interface name in \"" + section + "\" section"));
}
set.insert(name);
}
else if (item.first == "ether") {
// validate ethernet address
auto addr = item.second.get_value<std::string>();
if (ethernet::Address::fromString(addr).isNull()) {
BOOST_THROW_EXCEPTION(ConfigFile::Error("Malformed ether address \"" + addr +
"\" in \"" + section + "\" section"));
}
set.insert(addr);
}
else if (item.first == "subnet") {
// example subnet: 10.0.0.0/8
auto cidr = item.second.get_value<std::string>();
if (!Network::isValidCidr(cidr)) {
BOOST_THROW_EXCEPTION(ConfigFile::Error("Malformed subnet declaration \"" + cidr +
"\" in \"" + section + "\" section"));
}
set.insert(cidr);
}
}
}
void
NetworkInterfacePredicate::parseWhitelist(const boost::property_tree::ptree& list)
{
parseList(m_whitelist, list, "whitelist");
}
void
NetworkInterfacePredicate::parseBlacklist(const boost::property_tree::ptree& list)
{
parseList(m_blacklist, list, "blacklist");
}
static bool
doesMatchRule(const NetworkInterfaceInfo& netif, const std::string& rule)
{
// if '/' is in rule, this is a subnet, check if IP in subnet
if (rule.find('/') != std::string::npos) {
Network n = boost::lexical_cast<Network>(rule);
for (const auto& addr : netif.ipv4Addresses) {
if (n.doesContain(addr)) {
return true;
}
}
}
return rule == "*" ||
netif.name == rule ||
netif.etherAddress.toString() == rule;
}
bool
NetworkInterfacePredicate::operator()(const NetworkInterfaceInfo& netif) const
{
return std::any_of(m_whitelist.begin(), m_whitelist.end(), bind(&doesMatchRule, netif, _1)) &&
std::none_of(m_blacklist.begin(), m_blacklist.end(), bind(&doesMatchRule, netif, _1));
}
bool
NetworkInterfacePredicate::operator==(const NetworkInterfacePredicate& other) const
{
return this->m_whitelist == other.m_whitelist &&
this->m_blacklist == other.m_blacklist;
}
} // namespace nfd
+80
View File
@@ -0,0 +1,80 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NFD_CORE_NETWORK_INTERFACE_PREDICATE_HPP
#define NFD_CORE_NETWORK_INTERFACE_PREDICATE_HPP
#include "common.hpp"
namespace nfd {
class NetworkInterfaceInfo;
/**
* \brief Represents a predicate to accept or reject a NetworkInterfaceInfo.
*
* The predicate consists of a whitelist and a blacklist. Whitelist and blacklist can contain,
* in no particular order, interface names (e.g., ifname eth0), mac addresses
* (e.g., ether 85:3b:4d:d3:5f:c2), subnets (e.g., subnet 192.0.2.0/24) or a wildcard (*) that matches
* all interfaces. A NetworkInterfaceInfo is accepted if it matches any entry in the whitelist and none
* of the entries in the blacklist.
*/
class NetworkInterfacePredicate
{
public:
NetworkInterfacePredicate();
/**
* \brief Set the whitelist to "*" and clear the blacklist
*/
void
clear();
void
parseWhitelist(const boost::property_tree::ptree& list);
void
parseBlacklist(const boost::property_tree::ptree& list);
bool
operator()(const NetworkInterfaceInfo& netif) const;
bool
operator==(const NetworkInterfacePredicate& other) const;
bool
operator!=(const NetworkInterfacePredicate& other) const
{
return !this->operator==(other);
}
private:
std::set<std::string> m_whitelist;
std::set<std::string> m_blacklist;
};
} // namespace nfd
#endif // NFD_CORE_NETWORK_INTERFACE_PREDICATE_HPP
+96 -69
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-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
@@ -25,19 +25,25 @@
#include "network.hpp"
#include <boost/utility/value_init.hpp>
#include <algorithm>
namespace nfd {
void
Network::print(std::ostream& os) const
Network::Network() = default;
Network::Network(const boost::asio::ip::address& minAddress,
const boost::asio::ip::address& maxAddress)
: m_minAddress(minAddress)
, m_maxAddress(maxAddress)
{
os << m_minAddress << " <-> " << m_maxAddress;
}
const Network&
Network::getMaxRangeV4()
{
using boost::asio::ip::address_v4;
static Network range = Network(address_v4(0), address_v4(0xFFFFFFFF));
static Network range{address_v4{}, address_v4{0xffffffff}};
return range;
}
@@ -47,86 +53,107 @@ Network::getMaxRangeV6()
using boost::asio::ip::address_v6;
static address_v6::bytes_type maxV6 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
static Network range = Network(address_v6(), address_v6(maxV6));
static Network range{address_v6{}, address_v6{maxV6}};
return range;
}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
bool
Network::isValidCidr(const std::string& cidr)
{
auto pos = cidr.find('/');
if (pos == std::string::npos) {
return false;
}
boost::system::error_code invalidIp;
boost::asio::ip::address_v4::from_string(cidr.substr(0, pos), invalidIp);
if (invalidIp) {
return false;
}
auto prefixLenStr = cidr.substr(pos + 1);
if (!std::all_of(prefixLenStr.begin(), prefixLenStr.end(), ::isdigit)) {
return false;
}
int prefixLen = -1;
try {
prefixLen = boost::lexical_cast<int>(prefixLenStr);
}
catch (const boost::bad_lexical_cast&) {
return false;
}
if (prefixLen < 0 || prefixLen > 32) {
return false;
}
return true;
}
std::ostream&
operator<<(std::ostream& os, const Network& network)
{
network.print(os);
return os;
return os << network.m_minAddress << " <-> " << network.m_maxAddress;
}
std::istream&
operator>>(std::istream& is, Network& network)
{
using namespace boost::asio;
namespace ip = boost::asio::ip;
std::string networkStr;
is >> networkStr;
size_t position = networkStr.find('/');
if (position == std::string::npos)
{
network.m_minAddress = ip::address::from_string(networkStr);
network.m_maxAddress = ip::address::from_string(networkStr);
if (position == std::string::npos) {
network.m_minAddress = ip::address::from_string(networkStr);
network.m_maxAddress = ip::address::from_string(networkStr);
}
else {
ip::address address = ip::address::from_string(networkStr.substr(0, position));
size_t mask = boost::lexical_cast<size_t>(networkStr.substr(position+1));
if (address.is_v4()) {
ip::address_v4::bytes_type maskBytes = boost::initialized_value;
for (size_t i = 0; i < mask; i++) {
size_t byteId = i / 8;
size_t bitIndex = 7 - i % 8;
maskBytes[byteId] |= (1 << bitIndex);
}
ip::address_v4::bytes_type addressBytes = address.to_v4().to_bytes();
ip::address_v4::bytes_type min;
ip::address_v4::bytes_type max;
for (size_t i = 0; i < addressBytes.size(); i++) {
min[i] = addressBytes[i] & maskBytes[i];
max[i] = addressBytes[i] | ~(maskBytes[i]);
}
network.m_minAddress = ip::address_v4(min);
network.m_maxAddress = ip::address_v4(max);
}
else
{
ip::address address = ip::address::from_string(networkStr.substr(0, position));
size_t mask = boost::lexical_cast<size_t>(networkStr.substr(position+1));
else {
ip::address_v6::bytes_type maskBytes = boost::initialized_value;
for (size_t i = 0; i < mask; i++) {
size_t byteId = i / 8;
size_t bitIndex = 7 - i % 8;
maskBytes[byteId] |= (1 << bitIndex);
}
if (address.is_v4())
{
ip::address_v4::bytes_type maskBytes = boost::initialized_value;
for (size_t i = 0; i < mask; i++)
{
size_t byteId = i / 8;
size_t bitIndex = 7 - i % 8;
maskBytes[byteId] |= (1 << bitIndex);
}
ip::address_v6::bytes_type addressBytes = address.to_v6().to_bytes();
ip::address_v6::bytes_type min;
ip::address_v6::bytes_type max;
ip::address_v4::bytes_type addressBytes = address.to_v4().to_bytes();
ip::address_v4::bytes_type min;
ip::address_v4::bytes_type max;
for (size_t i = 0; i < addressBytes.size(); i++) {
min[i] = addressBytes[i] & maskBytes[i];
max[i] = addressBytes[i] | ~(maskBytes[i]);
}
for (size_t i = 0; i < addressBytes.size(); i++)
{
min[i] = addressBytes[i] & maskBytes[i];
max[i] = addressBytes[i] | ~(maskBytes[i]);
}
network.m_minAddress = ip::address_v4(min);
network.m_maxAddress = ip::address_v4(max);
}
else
{
ip::address_v6::bytes_type maskBytes = boost::initialized_value;
for (size_t i = 0; i < mask; i++)
{
size_t byteId = i / 8;
size_t bitIndex = 7 - i % 8;
maskBytes[byteId] |= (1 << bitIndex);
}
ip::address_v6::bytes_type addressBytes = address.to_v6().to_bytes();
ip::address_v6::bytes_type min;
ip::address_v6::bytes_type max;
for (size_t i = 0; i < addressBytes.size(); i++)
{
min[i] = addressBytes[i] & maskBytes[i];
max[i] = addressBytes[i] | ~(maskBytes[i]);
}
network.m_minAddress = ip::address_v6(min);
network.m_maxAddress = ip::address_v6(max);
}
network.m_minAddress = ip::address_v6(min);
network.m_maxAddress = ip::address_v6(max);
}
}
return is;
}
+17 -25
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-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
@@ -26,33 +26,22 @@
#ifndef NFD_CORE_NETWORK_HPP
#define NFD_CORE_NETWORK_HPP
#include <boost/asio.hpp>
#include <boost/utility/value_init.hpp>
#include <boost/lexical_cast.hpp>
#include "common.hpp"
namespace nfd {
class Network
{
public:
Network()
{
}
Network();
Network(const boost::asio::ip::address& minAddress,
const boost::asio::ip::address& maxAddress)
: m_minAddress(minAddress)
, m_maxAddress(maxAddress)
{
}
void
print(std::ostream& os) const;
const boost::asio::ip::address& maxAddress);
bool
doesContain(const boost::asio::ip::address& address) const
{
return (m_minAddress <= address && address <= m_maxAddress);
return m_minAddress <= address && address <= m_maxAddress;
}
static const Network&
@@ -61,6 +50,9 @@ public:
static const Network&
getMaxRangeV6();
static bool
isValidCidr(const std::string& cidr);
bool
operator==(const Network& rhs) const
{
@@ -77,11 +69,11 @@ private:
boost::asio::ip::address m_minAddress;
boost::asio::ip::address m_maxAddress;
friend std::istream&
operator>>(std::istream& is, Network& network);
friend std::ostream&
operator<<(std::ostream& os, const Network& network);
friend std::istream&
operator>>(std::istream& is, Network& network);
};
std::ostream&
+7 -13
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,21 +28,15 @@
namespace nfd {
static boost::thread_specific_ptr<boost::random::mt19937> g_rng;
boost::random::mt19937&
std::mt19937&
getGlobalRng()
{
if (g_rng.get() == nullptr) {
g_rng.reset(new boost::random::mt19937());
static boost::thread_specific_ptr<std::mt19937> rng;
if (rng.get() == nullptr) {
std::random_device rd;
rng.reset(new std::mt19937(rd()));
}
return *g_rng;
}
void
resetGlobalRng()
{
g_rng.reset();
return *rng;
}
} // namespace nfd
+16 -14
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-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
@@ -24,24 +24,26 @@
*/
/**
* This file declares the global random number generator
* All random numbers in NFD should use this global random number generator,
* so that the generator can be properly seeded when necessary.
* This file declares the global pseudorandom number generator (PRNG).
*
* This random number generator is not suitable for security purposes;
* security-critical code should use CryptoPP random number generator instead.
* All random numbers generated by NFD should use this global generator,
* so that it can be properly seeded when necessary.
*
* This PRNG is not suitable for security purposes; security-critical
* code must use a cryptographically secure PRNG, such as those provided
* by OpenSSL and Crypto++.
*/
#ifndef NFD_CORE_RANDOM_HPP
#define NFD_CORE_RANDOM_HPP
#include <boost/random/mersenne_twister.hpp>
#include <random>
namespace nfd {
/** \return the global random number generator instance
*/
boost::random::mt19937&
std::mt19937&
getGlobalRng();
} // namespace nfd
-132
View File
@@ -1,132 +0,0 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NFD_CORE_SEGMENT_PUBLISHER_HPP
#define NFD_CORE_SEGMENT_PUBLISHER_HPP
#include "common.hpp"
#include <ndn-cxx/encoding/encoding-buffer.hpp>
#include <ndn-cxx/security/key-chain.hpp>
namespace nfd {
/** \brief provides a publisher of Status Dataset or other segmented octet stream
* \sa http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
*/
template <class FaceBase>
class SegmentPublisher : noncopyable
{
public:
SegmentPublisher(FaceBase& face,
const Name& prefix,
ndn::KeyChain& keyChain,
const time::milliseconds& freshnessPeriod = getDefaultFreshness())
: m_face(face)
, m_prefix(prefix)
, m_keyChain(keyChain)
, m_freshnessPeriod(freshnessPeriod)
{
}
virtual
~SegmentPublisher()
{
}
static size_t
getMaxSegmentSize()
{
static const size_t MAX_SEGMENT_SIZE = ndn::MAX_NDN_PACKET_SIZE >> 1;
return MAX_SEGMENT_SIZE;
}
static constexpr time::milliseconds
getDefaultFreshness()
{
return time::milliseconds(1000);
}
void
publish()
{
ndn::EncodingBuffer buffer;
generate(buffer);
const uint8_t* rawBuffer = buffer.buf();
const uint8_t* segmentBegin = rawBuffer;
const uint8_t* end = rawBuffer + buffer.size();
Name segmentPrefix(m_prefix);
segmentPrefix.appendVersion();
uint64_t segmentNo = 0;
do {
const uint8_t* segmentEnd = segmentBegin + getMaxSegmentSize();
if (segmentEnd > end) {
segmentEnd = end;
}
Name segmentName(segmentPrefix);
segmentName.appendSegment(segmentNo);
shared_ptr<Data> data = make_shared<Data>(segmentName);
data->setContent(segmentBegin, segmentEnd - segmentBegin);
data->setFreshnessPeriod(m_freshnessPeriod);
segmentBegin = segmentEnd;
if (segmentBegin >= end) {
data->setFinalBlockId(segmentName[-1]);
}
publishSegment(data);
++segmentNo;
} while (segmentBegin < end);
}
protected:
/** \brief In a derived class, write the octets into outBuffer.
*/
virtual size_t
generate(ndn::EncodingBuffer& outBuffer) = 0;
private:
void
publishSegment(shared_ptr<Data>& data)
{
m_keyChain.sign(*data);
m_face.put(*data);
}
private:
FaceBase& m_face;
const Name m_prefix;
ndn::KeyChain& m_keyChain;
const time::milliseconds m_freshnessPeriod;
};
} // namespace nfd
#endif // NFD_CORE_SEGMENT_PUBLISHER_HPP
+10 -10
View File
@@ -1,12 +1,12 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
@@ -23,8 +23,8 @@
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NFD_VERSION_HPP
#define NFD_VERSION_HPP
#ifndef NFD_CORE_VERSION_HPP
#define NFD_CORE_VERSION_HPP
namespace nfd {
@@ -71,4 +71,4 @@ namespace nfd {
} // namespace nfd
#endif // NFD_VERSION_HPP
#endif // NFD_CORE_VERSION_HPP
+8 -3
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -41,9 +41,14 @@ typedef function<void(const shared_ptr<Face>& newFace)> FaceCreatedCallback;
* \brief Prototype for the callback that is invoked when the face
* fails to be created
*/
typedef function<void(const std::string& reason)> FaceCreationFailedCallback;
typedef function<void(uint32_t status, const std::string& reason)> FaceCreationFailedCallback;
/** \brief represent a channel that communicates on a local endpoint
* \sa FaceSystem
*
* A channel can listen on a local endpoint and initiate outgoing connection from a local endpoint.
* A channel creates Face objects and retains shared ownership of them.
*/
class Channel : noncopyable
{
public:
+3 -3
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -62,10 +62,10 @@ public:
protected:
virtual void
doClose() DECL_OVERRIDE;
doClose() override;
virtual void
doSend(Transport::Packet&& packet) DECL_OVERRIDE;
doSend(Transport::Packet&& packet) override;
void
handleSend(const boost::system::error_code& error,
+159 -28
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,42 +26,112 @@
#include "ethernet-factory.hpp"
#include "ethernet-transport.hpp"
#include "generic-link-service.hpp"
#include "core/logger.hpp"
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm/copy.hpp>
namespace nfd {
namespace face {
shared_ptr<Face>
EthernetFactory::createMulticastFace(const NetworkInterfaceInfo& interface,
const ethernet::Address& address)
NFD_LOG_INIT("EthernetFactory");
NFD_REGISTER_PROTOCOL_FACTORY(EthernetFactory);
const std::string&
EthernetFactory::getId()
{
if (!address.isMulticast())
BOOST_THROW_EXCEPTION(Error(address.toString() + " is not a multicast address"));
static std::string id("ether");
return id;
}
auto face = findMulticastFace(interface.name, address);
if (face)
return face;
face::GenericLinkService::Options opts;
opts.allowFragmentation = true;
opts.allowReassembly = true;
void
EthernetFactory::processConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context)
{
// ether
// {
// mcast yes
// mcast_group 01:00:5E:00:17:AA
// whitelist
// {
// *
// }
// blacklist
// {
// }
// }
auto linkService = make_unique<face::GenericLinkService>(opts);
auto transport = make_unique<face::EthernetTransport>(interface, address);
face = make_shared<Face>(std::move(linkService), std::move(transport));
MulticastConfig mcastConfig;
auto key = std::make_pair(interface.name, address);
m_multicastFaces[key] = face;
connectFaceClosedSignal(*face, [this, key] { m_multicastFaces.erase(key); });
if (configSection) {
// face_system.ether.mcast defaults to 'yes' but only if face_system.ether section is present
mcastConfig.isEnabled = true;
return face;
for (const auto& pair : *configSection) {
const std::string& key = pair.first;
const ConfigSection& value = pair.second;
if (key == "mcast") {
mcastConfig.isEnabled = ConfigFile::parseYesNo(pair, "ether");
}
else if (key == "mcast_group") {
const std::string& valueStr = value.get_value<std::string>();
mcastConfig.group = ethernet::Address::fromString(valueStr);
if (mcastConfig.group.isNull()) {
BOOST_THROW_EXCEPTION(ConfigFile::Error("face_system.ether.mcast_group: '" +
valueStr + "' cannot be parsed as an Ethernet address"));
}
else if (!mcastConfig.group.isMulticast()) {
BOOST_THROW_EXCEPTION(ConfigFile::Error("face_system.ether.mcast_group: '" +
valueStr + "' is not a multicast address"));
}
}
else if (key == "whitelist") {
mcastConfig.netifPredicate.parseWhitelist(value);
}
else if (key == "blacklist") {
mcastConfig.netifPredicate.parseBlacklist(value);
}
else {
BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system.ether." + key));
}
}
}
if (!context.isDryRun) {
if (m_mcastConfig.isEnabled != mcastConfig.isEnabled) {
if (mcastConfig.isEnabled) {
NFD_LOG_INFO("enabling multicast on " << mcastConfig.group);
}
else {
NFD_LOG_INFO("disabling multicast");
}
}
else if (m_mcastConfig.group != mcastConfig.group) {
NFD_LOG_INFO("changing multicast group from " << m_mcastConfig.group <<
" to " << mcastConfig.group);
}
else if (m_mcastConfig.netifPredicate != mcastConfig.netifPredicate) {
NFD_LOG_INFO("changing whitelist/blacklist");
}
else {
// There's no configuration change, but we still need to re-apply configuration because
// netifs may have changed.
}
m_mcastConfig = mcastConfig;
this->applyConfig(context);
}
}
void
EthernetFactory::createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
bool wantLocalFieldsEnabled,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onConnectFailed)
const FaceCreationFailedCallback& onFailure)
{
BOOST_THROW_EXCEPTION(Error("EthernetFactory does not support 'createFace' operation"));
onFailure(406, "Unsupported protocol");
}
std::vector<shared_ptr<const Channel>>
@@ -71,14 +141,75 @@ EthernetFactory::getChannels() const
}
shared_ptr<Face>
EthernetFactory::findMulticastFace(const std::string& interfaceName,
const ethernet::Address& address) const
EthernetFactory::createMulticastFace(const NetworkInterfaceInfo& netif,
const ethernet::Address& address)
{
auto i = m_multicastFaces.find({interfaceName, address});
if (i != m_multicastFaces.end())
return i->second;
else
return nullptr;
BOOST_ASSERT(address.isMulticast());
auto key = std::make_pair(netif.name, address);
auto found = m_mcastFaces.find(key);
if (found != m_mcastFaces.end()) {
return found->second;
}
face::GenericLinkService::Options opts;
opts.allowFragmentation = true;
opts.allowReassembly = true;
auto linkService = make_unique<face::GenericLinkService>(opts);
auto transport = make_unique<face::EthernetTransport>(netif, address);
auto face = make_shared<Face>(std::move(linkService), std::move(transport));
m_mcastFaces[key] = face;
connectFaceClosedSignal(*face, [this, key] { m_mcastFaces.erase(key); });
return face;
}
void
EthernetFactory::applyConfig(const FaceSystem::ConfigContext& context)
{
// collect old faces
std::set<shared_ptr<Face>> oldFaces;
boost::copy(m_mcastFaces | boost::adaptors::map_values,
std::inserter(oldFaces, oldFaces.end()));
if (m_mcastConfig.isEnabled) {
// determine interfaces on which faces should be created or retained
auto capableNetifs = context.listNetifs() |
boost::adaptors::filtered([this] (const NetworkInterfaceInfo& netif) {
return netif.isUp() && netif.isMulticastCapable() &&
m_mcastConfig.netifPredicate(netif);
});
// create faces
for (const auto& netif : capableNetifs) {
shared_ptr<Face> face;
try {
face = this->createMulticastFace(netif, m_mcastConfig.group);
}
catch (const EthernetTransport::Error& e) {
NFD_LOG_ERROR("Cannot create Ethernet multicast face on " << netif.name << ": " <<
e.what() << ", continuing");
continue;
}
if (face->getId() == face::INVALID_FACEID) {
// new face: register with forwarding
context.addFace(face);
}
else {
// existing face: don't destroy
oldFaces.erase(face);
}
}
}
// destroy old faces that are not needed in new configuration
for (const auto& face : oldFaces) {
face->close();
}
}
} // namespace face
} // namespace nfd
+43 -59
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,85 +27,69 @@
#define NFD_DAEMON_FACE_ETHERNET_FACTORY_HPP
#include "protocol-factory.hpp"
#include "core/network-interface.hpp"
namespace nfd {
namespace face {
/** \brief protocol factory for Ethernet
*
* Currently, only Ethernet multicast is supported.
*/
class EthernetFactory : public ProtocolFactory
{
public:
/**
* \brief Exception of EthernetFactory
static const std::string&
getId();
/** \brief process face_system.ether config section
*/
class Error : public ProtocolFactory::Error
{
public:
explicit
Error(const std::string& what)
: ProtocolFactory::Error(what)
{
}
};
void
processConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context) override;
typedef std::map<std::pair<std::string, ethernet::Address>,
shared_ptr<Face>> MulticastFaceMap;
/**
* \brief Create an EthernetFace to communicate with the given multicast group
*
* If this method is called twice with the same interface and group, only
* one face will be created. Instead, the second call will just retrieve
* the existing face.
*
* \param interface Local network interface
* \param address Ethernet broadcast/multicast destination address
*
* \returns always a valid shared pointer to an EthernetFace object,
* an exception will be thrown if the creation fails
*
* \throws EthernetFactory::Error or EthernetTransport::Error
/** \brief unicast face creation is not supported and will always fail
*/
shared_ptr<Face>
createMulticastFace(const NetworkInterfaceInfo& interface,
const ethernet::Address& address);
/**
* \brief Get map of configured multicast faces
*/
const MulticastFaceMap&
getMulticastFaces() const;
public: // from ProtocolFactory
virtual void
void
createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
bool wantLocalFieldsEnabled,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onConnectFailed) DECL_OVERRIDE;
const FaceCreationFailedCallback& onFailure) override;
virtual std::vector<shared_ptr<const Channel>>
getChannels() const DECL_OVERRIDE;
/** \return empty container, because Ethernet unicast is not supported
*/
std::vector<shared_ptr<const Channel>>
getChannels() const override;
private:
/**
* \brief Look up EthernetFace using specified interface and address
*
* \returns shared pointer to the existing EthernetFace object
* or nullptr when such face does not exist
/** \brief Create a face to communicate on the given Ethernet multicast group
* \param netif local network interface
* \param group multicast group address
* \note Calling this method again with same arguments returns the existing face on the given
* interface and multicast group rather than creating a new one.
* \throw EthernetTransport::Error transport creation fails
*/
shared_ptr<Face>
findMulticastFace(const std::string& interfaceName,
const ethernet::Address& address) const;
createMulticastFace(const NetworkInterfaceInfo& netif, const ethernet::Address& group);
void
applyConfig(const FaceSystem::ConfigContext& context);
private:
MulticastFaceMap m_multicastFaces;
struct MulticastConfig
{
bool isEnabled = false;
ethernet::Address group = ethernet::getDefaultMulticastAddress();
NetworkInterfacePredicate netifPredicate;
};
MulticastConfig m_mcastConfig;
/// (ifname, group) => face
std::map<std::pair<std::string, ethernet::Address>, shared_ptr<Face>> m_mcastFaces;
};
inline const EthernetFactory::MulticastFaceMap&
EthernetFactory::getMulticastFaces() const
{
return m_multicastFaces;
}
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_ETHERNET_FACTORY_HPP
+7 -14
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -120,14 +120,6 @@ EthernetTransport::EthernetTransport(const NetworkInterfaceInfo& interface,
boost::asio::placeholders::bytes_transferred));
}
void EthernetTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
{
if (newPersistency != ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
BOOST_THROW_EXCEPTION(
std::invalid_argument("EthernetTransport supports only FACE_PERSISTENCY_PERMANENT"));
}
}
void EthernetTransport::doSend(Transport::Packet&& packet)
{
NFD_LOG_FACE_TRACE(__func__);
@@ -374,14 +366,15 @@ EthernetTransport::processIncomingPacket(const pcap_pkthdr* header, const uint8_
void
EthernetTransport::processErrorCode(const boost::system::error_code& error)
{
NFD_LOG_FACE_TRACE(__func__);
if (getState() == TransportState::CLOSING ||
// boost::asio::error::operation_aborted must be checked first. In that situation, the Transport
// may already have been destructed, and it's unsafe to call getState() or do logging.
if (error == boost::asio::error::operation_aborted ||
getState() == TransportState::CLOSING ||
getState() == TransportState::FAILED ||
getState() == TransportState::CLOSED ||
error == boost::asio::error::operation_aborted)
getState() == TransportState::CLOSED) {
// transport is shutting down, ignore any errors
return;
}
NFD_LOG_FACE_WARN("Receive operation failed: " << error.message());
}
+7 -10
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,7 +26,7 @@
#ifndef NFD_DAEMON_FACE_ETHERNET_TRANSPORT_HPP
#define NFD_DAEMON_FACE_ETHERNET_TRANSPORT_HPP
#include "common.hpp"
#include "core/common.hpp"
#include "transport.hpp"
#include "core/network-interface.hpp"
@@ -45,7 +45,7 @@ namespace face {
/**
* \brief A multicast Transport that uses raw Ethernet II frames
*/
class EthernetTransport DECL_CLASS_FINAL : public Transport
class EthernetTransport final : public Transport
{
public:
class Error : public std::runtime_error
@@ -65,15 +65,12 @@ public:
const ethernet::Address& mcastAddress);
protected:
virtual void
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
virtual void
doClose() DECL_FINAL;
void
doClose() final;
private:
virtual void
doSend(Transport::Packet&& packet) DECL_FINAL;
void
doSend(Transport::Packet&& packet) final;
/**
* @brief Allocates and initializes a libpcap context for live capture
+130
View File
@@ -0,0 +1,130 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "face-system.hpp"
#include "protocol-factory.hpp"
#include "core/logger.hpp"
#include "fw/face-table.hpp"
namespace nfd {
namespace face {
NFD_LOG_INIT("FaceSystem");
FaceSystem::FaceSystem(FaceTable& faceTable)
: m_faceTable(faceTable)
{
for (const std::string& id : ProtocolFactory::listRegistered()) {
NFD_LOG_TRACE("creating factory " << id);
m_factories[id] = ProtocolFactory::create(id);
}
}
FaceSystem::~FaceSystem() = default;
std::set<const ProtocolFactory*>
FaceSystem::listProtocolFactories() const
{
std::set<const ProtocolFactory*> factories;
for (const auto& p : m_factories) {
factories.insert(p.second.get());
}
return factories;
}
ProtocolFactory*
FaceSystem::getFactoryById(const std::string& id)
{
auto found = m_factories.find(id);
return found == m_factories.end() ? nullptr : found->second.get();
}
ProtocolFactory*
FaceSystem::getFactoryByScheme(const std::string& scheme)
{
auto found = m_factoryByScheme.find(scheme);
return found == m_factoryByScheme.end() ? nullptr : found->second;
}
void
FaceSystem::setConfigFile(ConfigFile& configFile)
{
configFile.addSectionHandler("face_system", bind(&FaceSystem::processConfig, this, _1, _2, _3));
}
void
FaceSystem::processConfig(const ConfigSection& configSection, bool isDryRun, const std::string& filename)
{
ConfigContext context;
context.isDryRun = isDryRun;
context.addFace = bind(&FaceTable::add, &m_faceTable, _1);
context.m_netifs = listNetworkInterfaces();
// process sections in protocol factories
for (const auto& pair : m_factories) {
const std::string& sectionName = pair.first;
ProtocolFactory* factory = pair.second.get();
std::set<std::string> oldProvidedSchemes = factory->getProvidedSchemes();
factory->processConfig(configSection.get_child_optional(sectionName), context);
if (!isDryRun) {
for (const std::string& scheme : factory->getProvidedSchemes()) {
m_factoryByScheme[scheme] = factory;
if (oldProvidedSchemes.erase(scheme) == 0) {
NFD_LOG_TRACE("factory " << sectionName <<
" provides " << scheme << " FaceUri scheme");
}
}
for (const std::string& scheme : oldProvidedSchemes) {
m_factoryByScheme.erase(scheme);
NFD_LOG_TRACE("factory " << sectionName <<
" no longer provides " << scheme << " FaceUri scheme");
}
}
}
// process other sections
std::set<std::string> seenSections;
for (const auto& pair : configSection) {
const std::string& sectionName = pair.first;
// const ConfigSection& subSection = pair.second;
if (!seenSections.insert(sectionName).second) {
BOOST_THROW_EXCEPTION(ConfigFile::Error("Duplicate section face_system." + sectionName));
}
if (m_factories.count(sectionName) > 0) {
continue;
}
///\todo #3521 nicfaces
BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system." + sectionName));
}
}
} // namespace face
} // namespace nfd
+124
View File
@@ -0,0 +1,124 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NFD_DAEMON_FACE_FACE_SYSTEM_HPP
#define NFD_DAEMON_FACE_FACE_SYSTEM_HPP
#include "channel.hpp"
#include "core/config-file.hpp"
#include "core/network-interface.hpp"
#include "core/network-interface-predicate.hpp"
namespace nfd {
class FaceTable;
namespace face {
class ProtocolFactory;
/** \brief entry point of the face system
*
* NFD's face system is organized as a FaceSystem-ProtocolFactory-Channel-Face hierarchy.
* FaceSystem class is the entry point of NFD's face system and owns ProtocolFactory objects.
*/
class FaceSystem : noncopyable
{
public:
explicit
FaceSystem(FaceTable& faceTable);
~FaceSystem();
/** \return ProtocolFactory objects owned by the FaceSystem
*/
std::set<const ProtocolFactory*>
listProtocolFactories() const;
/** \return ProtocolFactory for the specified registered factory id or nullptr if not found
*/
ProtocolFactory*
getFactoryById(const std::string& id);
/** \return ProtocolFactory for the specified FaceUri scheme or nullptr if not found
*/
ProtocolFactory*
getFactoryByScheme(const std::string& scheme);
/** \brief register handler for face_system section of NFD configuration file
*/
void
setConfigFile(ConfigFile& configFile);
/** \brief context for processing a config section in ProtocolFactory
*/
class ConfigContext : noncopyable
{
public:
const std::vector<NetworkInterfaceInfo>&
listNetifs() const
{
///\todo get netifs from NetworkMonitor
return m_netifs;
}
public:
bool isDryRun;
FaceCreatedCallback addFace;
///\todo add NetworkMonitor
private:
std::vector<NetworkInterfaceInfo> m_netifs;
friend class FaceSystem;
};
private:
void
processConfig(const ConfigSection& configSection, bool isDryRun,
const std::string& filename);
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/** \brief config section name => protocol factory
*/
std::map<std::string, unique_ptr<ProtocolFactory>> m_factories;
private:
/** \brief scheme => protocol factory
*
* The same protocol factory may be available under multiple schemes.
*/
std::map<std::string, ProtocolFactory*> m_factoryByScheme;
FaceTable& m_faceTable;
};
} // namespace face
using face::FaceSystem;
} // namespace nfd
#endif // NFD_DAEMON_FACE_FACE_SYSTEM_HPP
+6 -6
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -66,7 +66,7 @@ typedef TransportState FaceState;
*/
class Face
#ifndef WITH_TESTS
DECL_CLASS_FINAL
final
#endif
: public enable_shared_from_this<Face>, noncopyable
{
@@ -74,10 +74,10 @@ public:
Face(unique_ptr<LinkService> service, unique_ptr<Transport> transport);
LinkService*
getLinkService();
getLinkService() const;
Transport*
getTransport();
getTransport() const;
public: // upper interface connected to forwarding
/** \brief sends Interest on Face
@@ -189,13 +189,13 @@ private:
};
inline LinkService*
Face::getLinkService()
Face::getLinkService() const
{
return m_service.get();
}
inline Transport*
Face::getTransport()
Face::getTransport() const
{
return m_transport.get();
}
+28 -14
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -24,6 +24,7 @@
*/
#include "generic-link-service.hpp"
#include <ndn-cxx/lp/tags.hpp>
namespace nfd {
namespace face {
@@ -57,9 +58,7 @@ GenericLinkService::doSendInterest(const Interest& interest)
{
lp::Packet lpPacket(interest.wireEncode());
if (m_options.allowLocalFields) {
encodeLocalFields(interest, lpPacket);
}
encodeLpFields(interest, lpPacket);
this->sendNetPacket(std::move(lpPacket));
}
@@ -69,9 +68,7 @@ GenericLinkService::doSendData(const Data& data)
{
lp::Packet lpPacket(data.wireEncode());
if (m_options.allowLocalFields) {
encodeLocalFields(data, lpPacket);
}
encodeLpFields(data, lpPacket);
this->sendNetPacket(std::move(lpPacket));
}
@@ -82,19 +79,24 @@ GenericLinkService::doSendNack(const lp::Nack& nack)
lp::Packet lpPacket(nack.getInterest().wireEncode());
lpPacket.add<lp::NackField>(nack.getHeader());
if (m_options.allowLocalFields) {
encodeLocalFields(nack, lpPacket);
}
encodeLpFields(nack, lpPacket);
this->sendNetPacket(std::move(lpPacket));
}
void
GenericLinkService::encodeLocalFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket)
GenericLinkService::encodeLpFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket)
{
shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
if (incomingFaceIdTag != nullptr) {
lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
if (m_options.allowLocalFields) {
shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
if (incomingFaceIdTag != nullptr) {
lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
}
}
shared_ptr<lp::CongestionMarkTag> congestionMarkTag = netPkt.getTag<lp::CongestionMarkTag>();
if (congestionMarkTag != nullptr) {
lpPacket.add<lp::CongestionMarkField>(*congestionMarkTag);
}
}
@@ -240,6 +242,10 @@ GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstP
NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
}
if (firstPkt.has<lp::CongestionMarkField>()) {
interest->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
}
this->receiveInterest(*interest);
}
@@ -278,6 +284,10 @@ GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt)
NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
}
if (firstPkt.has<lp::CongestionMarkField>()) {
data->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
}
this->receiveData(*data);
}
@@ -306,6 +316,10 @@ GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt)
NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
}
if (firstPkt.has<lp::CongestionMarkField>()) {
nack.setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
}
this->receiveNack(nack);
}
+12 -11
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,7 +26,7 @@
#ifndef NFD_DAEMON_FACE_GENERIC_LINK_SERVICE_HPP
#define NFD_DAEMON_FACE_GENERIC_LINK_SERVICE_HPP
#include "common.hpp"
#include "core/common.hpp"
#include "core/logger.hpp"
#include "link-service.hpp"
@@ -127,29 +127,30 @@ public:
setOptions(const Options& options);
virtual const Counters&
getCounters() const DECL_OVERRIDE;
getCounters() const override;
private: // send path
/** \brief send Interest
*/
void
doSendInterest(const Interest& interest) DECL_OVERRIDE;
doSendInterest(const Interest& interest) override;
/** \brief send Data
*/
void
doSendData(const Data& data) DECL_OVERRIDE;
doSendData(const Data& data) override;
/** \brief send Nack
*/
void
doSendNack(const ndn::lp::Nack& nack) DECL_OVERRIDE;
doSendNack(const ndn::lp::Nack& nack) override;
/** \brief encode local fields from tags onto outgoing LpPacket
* \param pkt LpPacket containing a complete network layer packet
/** \brief encode link protocol fields from tags onto an outgoing LpPacket
* \param netPkt network-layer packet to extract tags from
* \param lpPacket LpPacket to add link protocol fields to
*/
static void
encodeLocalFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket);
void
encodeLpFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket);
/** \brief send a complete network layer packet
* \param pkt LpPacket containing a complete network layer packet
@@ -171,7 +172,7 @@ private: // receive path
/** \brief receive Packet from Transport
*/
void
doReceivePacket(Transport::Packet&& packet) DECL_OVERRIDE;
doReceivePacket(Transport::Packet&& packet) override;
/** \brief decode incoming network-layer packet
* \param netPkt reassembled network-layer packet
+1 -10
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -45,15 +45,6 @@ InternalForwarderTransport::InternalForwarderTransport(
NFD_LOG_FACE_INFO("Creating transport");
}
void
InternalForwarderTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
{
if (newPersistency != ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
BOOST_THROW_EXCEPTION(
std::invalid_argument("InternalForwarderTransport supports only FACE_PERSISTENCY_PERMANENT"));
}
}
void
InternalForwarderTransport::receiveFromLink(const Block& packet)
{
+19 -22
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -58,19 +58,16 @@ public:
ndn::nfd::FaceScope scope = ndn::nfd::FACE_SCOPE_LOCAL,
ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_POINT_TO_POINT);
virtual void
receiveFromLink(const Block& packet) DECL_OVERRIDE;
void
receiveFromLink(const Block& packet) override;
protected:
virtual void
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_OVERRIDE;
virtual void
doClose() DECL_OVERRIDE;
void
doClose() override;
private:
virtual void
doSend(Packet&& packet) DECL_OVERRIDE;
void
doSend(Packet&& packet) override;
private:
NFD_LOG_INCLASS_DECLARE();
@@ -92,29 +89,29 @@ public:
void
connectToForwarder(InternalForwarderTransport* forwarderTransport);
virtual void
receiveFromLink(const Block& packet) DECL_OVERRIDE;
void
receiveFromLink(const Block& packet) override;
virtual void
close() DECL_OVERRIDE
void
close() override
{
}
virtual void
pause() DECL_OVERRIDE
void
pause() override
{
}
virtual void
resume() DECL_OVERRIDE
void
resume() override
{
}
virtual void
send(const Block& wire) DECL_OVERRIDE;
void
send(const Block& wire) override;
virtual void
send(const Block& header, const Block& payload) DECL_OVERRIDE;
void
send(const Block& header, const Block& payload) override;
private:
NFD_LOG_INCLASS_DECLARE();
+1 -10
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -50,15 +50,6 @@ MulticastUdpTransport::MulticastUdpTransport(const protocol::endpoint& localEndp
NFD_LOG_FACE_INFO("Creating transport");
}
void
MulticastUdpTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
{
if (newPersistency != ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
BOOST_THROW_EXCEPTION(
std::invalid_argument("MulticastUdpTransport supports only FACE_PERSISTENCY_PERMANENT"));
}
}
void
MulticastUdpTransport::doSend(Transport::Packet&& packet)
{
+6 -10
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -42,7 +42,7 @@ DatagramTransport<boost::asio::ip::udp, Multicast>::makeEndpointId(const protoco
/**
* \brief A Transport that communicates on a UDP multicast group
*/
class MulticastUdpTransport DECL_CLASS_FINAL : public DatagramTransport<boost::asio::ip::udp, Multicast>
class MulticastUdpTransport final : public DatagramTransport<boost::asio::ip::udp, Multicast>
{
public:
/**
@@ -57,16 +57,12 @@ public:
protocol::socket&& recvSocket,
protocol::socket&& sendSocket);
protected:
virtual void
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
private:
virtual void
doSend(Transport::Packet&& packet) DECL_FINAL;
void
doSend(Transport::Packet&& packet) final;
virtual void
doClose() DECL_FINAL;
void
doClose() final;
private:
protocol::endpoint m_multicastGroup;
+58
View File
@@ -0,0 +1,58 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "protocol-factory.hpp"
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/copy.hpp>
namespace nfd {
namespace face {
ProtocolFactory::Registry&
ProtocolFactory::getRegistry()
{
static Registry registry;
return registry;
}
unique_ptr<ProtocolFactory>
ProtocolFactory::create(const std::string& id)
{
Registry& registry = getRegistry();
auto found = registry.find(id);
return found == registry.end() ? nullptr : found->second();
}
std::set<std::string>
ProtocolFactory::listRegistered()
{
std::set<std::string> factoryIds;
boost::copy(getRegistry() | boost::adaptors::map_keys,
std::inserter(factoryIds, factoryIds.end()));
return factoryIds;
}
} // namespace face
} // namespace nfd
+121 -7
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,15 +27,48 @@
#define NFD_DAEMON_FACE_PROTOCOL_FACTORY_HPP
#include "channel.hpp"
#include "face-system.hpp"
#include <ndn-cxx/encoding/nfd-constants.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/copy.hpp>
namespace nfd {
namespace face {
/**
* \brief Abstract base class for all protocol factories
/** \brief provide support for an underlying protocol
* \sa FaceSystem
*
* A protocol factory provides support for an underlying protocol and owns Channel objects.
* It can process a subsection of face_system config section and create channels and multicast
* faces accordingly.
*/
class ProtocolFactory
class ProtocolFactory : noncopyable
{
public: // registry
/** \brief register a protocol factory type
* \tparam S subclass of ProtocolFactory
* \param id factory identifier
*/
template<typename PF>
static void
registerType(const std::string& id = PF::getId())
{
Registry& registry = getRegistry();
BOOST_ASSERT(registry.count(id) == 0);
registry[id] = &make_unique<PF>;
}
/** \return a protocol factory instance
* \retval nullptr if factory with \p id is not registered
*/
static unique_ptr<ProtocolFactory>
create(const std::string& id);
/** \return registered protocol factory ids
*/
static std::set<std::string>
listRegistered();
public:
/**
* \brief Base class for all exceptions thrown by protocol factories
@@ -50,24 +83,105 @@ public:
}
};
virtual
~ProtocolFactory() = default;
#ifdef DOXYGEN
/** \return protocol factory id
*
* face_system.factory-id config section is processed by the protocol factory.
*/
static const std::string&
getId();
#endif
/** \brief process face_system subsection that corresponds to this ProtocolFactory type
* \param configSection the configuration section or boost::null to indicate it is omitted
* \param context provides access to data structures and contextual information
* \throw ConfigFile::Error invalid configuration
*
* This function updates \p providedSchemes
*/
virtual void
processConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context)
{
///\todo implement in every subclass and make this pure-virtual
BOOST_THROW_EXCEPTION(Error("processConfig is not implemented"));
}
/** \return FaceUri schemes accepted by this ProtocolFactory
*/
const std::set<std::string>&
getProvidedSchemes()
{
return providedSchemes;
}
/** \brief Try to create Face using the supplied FaceUri
*
* This method should automatically choose channel, based on supplied FaceUri
* and create face.
*
* \throw Error Factory does not support connect operation
* \throw Error specified \p persistency is not supported
* \param uri remote URI of the new face
* \param persistency persistency of the new face
* \param wantLocalFieldsEnabled whether local fields should be enabled on the face
* \param onCreated callback if face creation succeeds
* If a face with the same remote URI already exists, its persistency and
* LocalFieldsEnabled setting will not be modified.
* \param onFailure callback if face creation fails
*/
virtual void
createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
bool wantLocalFieldsEnabled,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onConnectFailed) = 0;
const FaceCreationFailedCallback& onFailure) = 0;
virtual std::vector<shared_ptr<const Channel>>
getChannels() const = 0;
protected:
template<typename ChannelMap>
static std::vector<shared_ptr<const Channel>>
getChannelsFromMap(const ChannelMap& channelMap)
{
std::vector<shared_ptr<const Channel>> channels;
boost::copy(channelMap | boost::adaptors::map_values, std::back_inserter(channels));
return channels;
}
private: // registry
typedef std::function<unique_ptr<ProtocolFactory>()> CreateFunc;
typedef std::map<std::string, CreateFunc> Registry; // indexed by factory id
static Registry&
getRegistry();
protected:
/** \brief FaceUri schemes provided by this ProtocolFactory
*/
std::set<std::string> providedSchemes;
};
} // namespace face
using face::ProtocolFactory;
} // namespace nfd
/** \brief registers a protocol factory
*
* This macro should appear once in .cpp of each protocol factory.
*/
#define NFD_REGISTER_PROTOCOL_FACTORY(PF) \
static class NfdAuto ## PF ## ProtocolFactoryRegistrationClass \
{ \
public: \
NfdAuto ## PF ## ProtocolFactoryRegistrationClass() \
{ \
::nfd::face::ProtocolFactory::registerType<PF>(); \
} \
} g_nfdAuto ## PF ## ProtocolFactoryRegistrationVariable
#endif // NFD_DAEMON_FACE_PROTOCOL_FACTORY_HPP
+56 -15
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -53,13 +53,13 @@ public:
protected:
virtual void
doClose() DECL_OVERRIDE;
doClose() override;
void
deferredClose();
virtual void
doSend(Transport::Packet&& packet) DECL_OVERRIDE;
doSend(Transport::Packet&& packet) override;
void
sendFromQueue();
@@ -68,6 +68,9 @@ protected:
handleSend(const boost::system::error_code& error,
size_t nBytesSent);
void
startReceive();
void
handleReceive(const boost::system::error_code& error,
size_t nBytesReceived);
@@ -75,6 +78,15 @@ protected:
void
processErrorCode(const boost::system::error_code& error);
virtual void
handleError(const boost::system::error_code& error);
void
resetReceiveBuffer();
void
resetSendQueue();
protected:
typename protocol::socket m_socket;
@@ -92,10 +104,7 @@ StreamTransport<T>::StreamTransport(typename StreamTransport::protocol::socket&&
: m_socket(std::move(socket))
, m_receiveBufferSize(0)
{
m_socket.async_receive(boost::asio::buffer(m_receiveBuffer, ndn::MAX_NDN_PACKET_SIZE),
bind(&StreamTransport<T>::handleReceive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
startReceive();
}
template<class T>
@@ -136,9 +145,7 @@ StreamTransport<T>::deferredClose()
{
NFD_LOG_FACE_TRACE(__func__);
// clear send queue
std::queue<Block> emptyQueue;
std::swap(emptyQueue, m_sendQueue);
resetSendQueue();
// use the non-throwing variant and ignore errors, if any
boost::system::error_code error;
@@ -153,6 +160,9 @@ StreamTransport<T>::doSend(Transport::Packet&& packet)
{
NFD_LOG_FACE_TRACE(__func__);
if (getState() != TransportState::UP)
return;
bool wasQueueEmpty = m_sendQueue.empty();
m_sendQueue.push(packet.packet);
@@ -187,6 +197,19 @@ StreamTransport<T>::handleSend(const boost::system::error_code& error,
sendFromQueue();
}
template<class T>
void
StreamTransport<T>::startReceive()
{
BOOST_ASSERT(getState() == TransportState::UP);
m_socket.async_receive(boost::asio::buffer(m_receiveBuffer + m_receiveBufferSize,
ndn::MAX_NDN_PACKET_SIZE - m_receiveBufferSize),
bind(&StreamTransport<T>::handleReceive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
template<class T>
void
StreamTransport<T>::handleReceive(const boost::system::error_code& error,
@@ -231,11 +254,7 @@ StreamTransport<T>::handleReceive(const boost::system::error_code& error,
}
}
m_socket.async_receive(boost::asio::buffer(m_receiveBuffer + m_receiveBufferSize,
ndn::MAX_NDN_PACKET_SIZE - m_receiveBufferSize),
bind(&StreamTransport<T>::handleReceive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
startReceive();
}
template<class T>
@@ -252,6 +271,13 @@ StreamTransport<T>::processErrorCode(const boost::system::error_code& error)
// transport is shutting down, ignore any errors
return;
handleError(error);
}
template<class T>
void
StreamTransport<T>::handleError(const boost::system::error_code& error)
{
if (error != boost::asio::error::eof)
NFD_LOG_FACE_WARN("Send or receive operation failed: " << error.message());
@@ -259,6 +285,21 @@ StreamTransport<T>::processErrorCode(const boost::system::error_code& error)
doClose();
}
template<class T>
void
StreamTransport<T>::resetReceiveBuffer()
{
m_receiveBufferSize = 0;
}
template<class T>
void
StreamTransport<T>::resetSendQueue()
{
std::queue<Block> emptyQueue;
std::swap(emptyQueue, m_sendQueue);
}
} // namespace face
} // namespace nfd
+18 -10
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -66,6 +66,7 @@ TcpChannel::listen(const FaceCreatedCallback& onFaceCreated,
void
TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
bool wantLocalFieldsEnabled,
const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onConnectFailed,
const time::seconds& timeout/* = time::seconds(4)*/)
@@ -83,8 +84,8 @@ TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
clientSocket->async_connect(remoteEndpoint,
bind(&TcpChannel::handleConnect, this,
boost::asio::placeholders::error,
clientSocket, connectTimeoutEvent,
boost::asio::placeholders::error, clientSocket,
wantLocalFieldsEnabled, connectTimeoutEvent,
onFaceCreated, onConnectFailed));
}
@@ -96,8 +97,9 @@ TcpChannel::size() const
void
TcpChannel::createFace(ip::tcp::socket&& socket,
const FaceCreatedCallback& onFaceCreated,
bool isOnDemand)
bool isOnDemand,
bool wantLocalFieldsEnabled,
const FaceCreatedCallback& onFaceCreated)
{
shared_ptr<Face> face;
tcp::Endpoint remoteEndpoint = socket.remote_endpoint();
@@ -107,7 +109,12 @@ TcpChannel::createFace(ip::tcp::socket&& socket,
auto persistency = isOnDemand ? ndn::nfd::FACE_PERSISTENCY_ON_DEMAND
: ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
auto linkService = make_unique<face::GenericLinkService>();
auto options = linkService->getOptions();
options.allowLocalFields = wantLocalFieldsEnabled;
linkService->setOptions(options);
auto transport = make_unique<face::TcpTransport>(std::move(socket), persistency);
face = make_shared<Face>(std::move(linkService), std::move(transport));
m_channelFaces[remoteEndpoint] = face;
@@ -151,13 +158,13 @@ TcpChannel::handleAccept(const boost::system::error_code& error,
NFD_LOG_DEBUG("[" << m_localEndpoint << "] Accept failed: " << error.message());
if (onAcceptFailed)
onAcceptFailed(error.message());
onAcceptFailed(500, "Accept failed: " + error.message());
return;
}
NFD_LOG_DEBUG("[" << m_localEndpoint << "] Connection from " << m_acceptSocket.remote_endpoint());
createFace(std::move(m_acceptSocket), onFaceCreated, true);
createFace(std::move(m_acceptSocket), true, false, onFaceCreated);
// prepare accepting the next connection
accept(onFaceCreated, onAcceptFailed);
@@ -166,6 +173,7 @@ TcpChannel::handleAccept(const boost::system::error_code& error,
void
TcpChannel::handleConnect(const boost::system::error_code& error,
const shared_ptr<ip::tcp::socket>& socket,
bool wantLocalFieldsEnabled,
const scheduler::EventId& connectTimeoutEvent,
const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onConnectFailed)
@@ -189,13 +197,13 @@ TcpChannel::handleConnect(const boost::system::error_code& error,
socket->close();
if (onConnectFailed)
onConnectFailed(error.message());
onConnectFailed(504, "Connect failed: " + error.message());
return;
}
NFD_LOG_DEBUG("[" << m_localEndpoint << "] Connected to " << socket->remote_endpoint());
createFace(std::move(*socket), onFaceCreated, false);
createFace(std::move(*socket), false, wantLocalFieldsEnabled, onFaceCreated);
}
void
@@ -209,7 +217,7 @@ TcpChannel::handleConnectTimeout(const shared_ptr<ip::tcp::socket>& socket,
socket->close(error);
if (onConnectFailed)
onConnectFailed("Connect to remote endpoint timed out");
onConnectFailed(504, "Connect to remote endpoint timed out");
}
} // namespace nfd
+6 -3
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -73,6 +73,7 @@ public:
*/
void
connect(const tcp::Endpoint& remoteEndpoint,
bool wantLocalFieldsEnabled,
const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onConnectFailed,
const time::seconds& timeout = time::seconds(4));
@@ -89,8 +90,9 @@ public:
private:
void
createFace(boost::asio::ip::tcp::socket&& socket,
const FaceCreatedCallback& onFaceCreated,
bool isOnDemand);
bool isOnDemand,
bool wantLocalFieldsEnabled,
const FaceCreatedCallback& onFaceCreated);
void
accept(const FaceCreatedCallback& onFaceCreated,
@@ -104,6 +106,7 @@ private:
void
handleConnect(const boost::system::error_code& error,
const shared_ptr<boost::asio::ip::tcp::socket>& socket,
bool wantLocalFieldsEnabled,
const scheduler::EventId& connectTimeoutEvent,
const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onConnectFailed);
+143 -42
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -25,13 +25,150 @@
#include "tcp-factory.hpp"
#include "core/logger.hpp"
#include "core/network-interface.hpp"
namespace nfd {
namespace face {
namespace ip = boost::asio::ip;
NFD_LOG_INIT("TcpFactory");
NFD_REGISTER_PROTOCOL_FACTORY(TcpFactory);
const std::string&
TcpFactory::getId()
{
static std::string id("tcp");
return id;
}
void
TcpFactory::processConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context)
{
// tcp
// {
// listen yes
// port 6363
// enable_v4 yes
// enable_v6 yes
// }
if (!configSection) {
if (!context.isDryRun && !m_channels.empty()) {
NFD_LOG_WARN("Cannot disable tcp4 and tcp6 channels after initialization");
}
return;
}
bool wantListen = true;
uint16_t port = 6363;
bool enableV4 = true;
bool enableV6 = true;
for (const auto& pair : *configSection) {
const std::string& key = pair.first;
if (key == "listen") {
wantListen = ConfigFile::parseYesNo(pair, "face_system.tcp");
}
else if (key == "port") {
port = ConfigFile::parseNumber<uint16_t>(pair, "face_system.tcp");
}
else if (key == "enable_v4") {
enableV4 = ConfigFile::parseYesNo(pair, "face_system.tcp");
}
else if (key == "enable_v6") {
enableV6 = ConfigFile::parseYesNo(pair, "face_system.tcp");
}
else {
BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system.tcp." + key));
}
}
if (!enableV4 && !enableV6) {
BOOST_THROW_EXCEPTION(ConfigFile::Error(
"IPv4 and IPv6 TCP channels have been disabled. Remove face_system.tcp section to disable "
"TCP channels or enable at least one channel type."));
}
if (!context.isDryRun) {
providedSchemes.insert("tcp");
if (enableV4) {
tcp::Endpoint endpoint(ip::tcp::v4(), port);
shared_ptr<TcpChannel> v4Channel = this->createChannel(endpoint);
if (wantListen && !v4Channel->isListening()) {
v4Channel->listen(context.addFace, nullptr);
}
providedSchemes.insert("tcp4");
}
else if (providedSchemes.count("tcp4") > 0) {
NFD_LOG_WARN("Cannot close tcp4 channel after its creation");
}
if (enableV6) {
tcp::Endpoint endpoint(ip::tcp::v6(), port);
shared_ptr<TcpChannel> v6Channel = this->createChannel(endpoint);
if (wantListen && !v6Channel->isListening()) {
v6Channel->listen(context.addFace, nullptr);
}
providedSchemes.insert("tcp6");
}
else if (providedSchemes.count("tcp6") > 0) {
NFD_LOG_WARN("Cannot close tcp6 channel after its creation");
}
}
}
void
TcpFactory::createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
bool wantLocalFieldsEnabled,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onFailure)
{
BOOST_ASSERT(uri.isCanonical());
if (persistency != ndn::nfd::FACE_PERSISTENCY_PERSISTENT) {
NFD_LOG_TRACE("createFace only supports FACE_PERSISTENCY_PERSISTENT");
onFailure(406, "Outgoing TCP faces only support persistent persistency");
return;
}
tcp::Endpoint endpoint(ip::address::from_string(uri.getHost()),
boost::lexical_cast<uint16_t>(uri.getPort()));
if (endpoint.address().is_multicast()) {
NFD_LOG_TRACE("createFace cannot create multicast faces");
onFailure(406, "Cannot create multicast TCP faces");
return;
}
if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end()) {
NFD_LOG_TRACE("Requested endpoint is prohibited "
"(reserved by NFD or disallowed by face management protocol)");
onFailure(406, "Requested endpoint is prohibited");
return;
}
if (wantLocalFieldsEnabled && !endpoint.address().is_loopback()) {
NFD_LOG_TRACE("createFace cannot create non-local face with local fields enabled");
onFailure(406, "Local fields can only be enabled on faces with local scope");
return;
}
// very simple logic for now
for (const auto& i : m_channels) {
if ((i.first.address().is_v4() && endpoint.address().is_v4()) ||
(i.first.address().is_v6() && endpoint.address().is_v6())) {
i.second->connect(endpoint, wantLocalFieldsEnabled, onCreated, onFailure);
return;
}
}
NFD_LOG_TRACE("No channels available to connect to " + boost::lexical_cast<std::string>(endpoint));
onFailure(504, "No channels available to connect");
}
void
TcpFactory::prohibitEndpoint(const tcp::Endpoint& endpoint)
@@ -52,6 +189,7 @@ TcpFactory::prohibitEndpoint(const tcp::Endpoint& endpoint)
void
TcpFactory::prohibitAllIpv4Endpoints(uint16_t port)
{
///\todo prohibited endpoints need to react to dynamic NIC changes
for (const NetworkInterfaceInfo& nic : listNetworkInterfaces()) {
for (const auto& addr : nic.ipv4Addresses) {
if (addr != ip::address_v4::any()) {
@@ -64,6 +202,7 @@ TcpFactory::prohibitAllIpv4Endpoints(uint16_t port)
void
TcpFactory::prohibitAllIpv6Endpoints(uint16_t port)
{
///\todo prohibited endpoints need to react to dynamic NIC changes
for (const NetworkInterfaceInfo& nic : listNetworkInterfaces()) {
for (const auto& addr : nic.ipv6Addresses) {
if (addr != ip::address_v6::any()) {
@@ -96,49 +235,10 @@ TcpFactory::createChannel(const std::string& localIp, const std::string& localPo
return createChannel(endpoint);
}
void
TcpFactory::createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onConnectFailed)
{
BOOST_ASSERT(uri.isCanonical());
if (persistency != ndn::nfd::FACE_PERSISTENCY_PERSISTENT) {
BOOST_THROW_EXCEPTION(Error("TcpFactory::createFace supports only FACE_PERSISTENCY_PERSISTENT"));
}
tcp::Endpoint endpoint(ip::address::from_string(uri.getHost()),
boost::lexical_cast<uint16_t>(uri.getPort()));
if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end()) {
onConnectFailed("Requested endpoint is prohibited "
"(reserved by this NFD or disallowed by face management protocol)");
return;
}
// very simple logic for now
for (const auto& i : m_channels) {
if ((i.first.address().is_v4() && endpoint.address().is_v4()) ||
(i.first.address().is_v6() && endpoint.address().is_v6())) {
i.second->connect(endpoint, onCreated, onConnectFailed);
return;
}
}
onConnectFailed("No channels available to connect to " + boost::lexical_cast<std::string>(endpoint));
}
std::vector<shared_ptr<const Channel>>
TcpFactory::getChannels() const
{
std::vector<shared_ptr<const Channel>> channels;
channels.reserve(m_channels.size());
for (const auto& i : m_channels)
channels.push_back(i.second);
return channels;
return getChannelsFromMap(m_channels);
}
shared_ptr<TcpChannel>
@@ -151,4 +251,5 @@ TcpFactory::findChannel(const tcp::Endpoint& localEndpoint) const
return nullptr;
}
} // namespace face
} // namespace nfd
+22 -24
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -30,22 +30,28 @@
#include "tcp-channel.hpp"
namespace nfd {
namespace face {
/** \brief protocol factory for TCP over IPv4 and IPv6
*/
class TcpFactory : public ProtocolFactory
{
public:
/**
* \brief Exception of TcpFactory
static const std::string&
getId();
/** \brief process face_system.tcp config section
*/
class Error : public ProtocolFactory::Error
{
public:
explicit
Error(const std::string& what)
: ProtocolFactory::Error(what)
{
}
};
void
processConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context) override;
void
createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
bool wantLocalFieldsEnabled,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onFailure) override;
/**
* \brief Create TCP-based channel using tcp::Endpoint
@@ -59,8 +65,6 @@ public:
* \returns always a valid pointer to a TcpChannel object, an exception
* is thrown if it cannot be created.
*
* \throws TcpFactory::Error
*
* \see http://www.boost.org/doc/libs/1_42_0/doc/html/boost_asio/reference/ip__tcp/endpoint.html
* for details on ways to create tcp::Endpoint
*/
@@ -73,20 +77,13 @@ public:
* This method is just a helper that converts a string representation of localIp and port to
* tcp::Endpoint and calls the other createChannel overload.
*
* \throws TcpFactory::Error or std::runtime_error
* \throws std::runtime_error
*/
shared_ptr<TcpChannel>
createChannel(const std::string& localIp, const std::string& localPort);
public: // from ProtocolFactory
virtual void
createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onConnectFailed) DECL_OVERRIDE;
virtual std::vector<shared_ptr<const Channel>>
getChannels() const DECL_OVERRIDE;
std::vector<shared_ptr<const Channel>>
getChannels() const override;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
@@ -115,6 +112,7 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
std::set<tcp::Endpoint> m_prohibitedEndpoints;
};
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_TCP_FACTORY_HPP
+116 -8
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,11 +28,16 @@
namespace nfd {
namespace face {
NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(StreamTransport, TcpTransport::protocol,
"TcpTransport");
NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(StreamTransport, TcpTransport::protocol, "TcpTransport");
time::milliseconds TcpTransport::s_initialReconnectWait = time::seconds(1);
time::milliseconds TcpTransport::s_maxReconnectWait = time::minutes(5);
float TcpTransport::s_reconnectWaitMultiplier = 2.0f;
TcpTransport::TcpTransport(protocol::socket&& socket, ndn::nfd::FacePersistency persistency)
: StreamTransport(std::move(socket))
, m_remoteEndpoint(m_socket.remote_endpoint())
, m_nextReconnectWait(s_initialReconnectWait)
{
this->setLocalUri(FaceUri(m_socket.local_endpoint()));
this->setRemoteUri(FaceUri(m_socket.remote_endpoint()));
@@ -50,14 +55,117 @@ TcpTransport::TcpTransport(protocol::socket&& socket, ndn::nfd::FacePersistency
NFD_LOG_FACE_INFO("Creating transport");
}
void
TcpTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
bool
TcpTransport::canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const
{
if (newPersistency == ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
BOOST_THROW_EXCEPTION(
std::invalid_argument("TcpTransport does not support FACE_PERSISTENCY_PERMANENT"));
return true;
}
void
TcpTransport::afterChangePersistency(ndn::nfd::FacePersistency oldPersistency)
{
// if persistency was changed from permanent to any other value
if (oldPersistency == ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
if (this->getState() == TransportState::DOWN) {
// non-permanent transport cannot be in DOWN state, so fail hard
this->setState(TransportState::FAILED);
doClose();
}
}
}
void
TcpTransport::handleError(const boost::system::error_code& error)
{
if (this->getPersistency() == ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
NFD_LOG_FACE_TRACE("TCP socket error: " << error.message());
this->setState(TransportState::DOWN);
// cancel all outstanding operations
boost::system::error_code error;
m_socket.cancel(error);
// do this asynchronously because there could be some callbacks still pending
getGlobalIoService().post([this] { reconnect(); });
}
else {
StreamTransport::handleError(error);
}
}
void
TcpTransport::reconnect()
{
NFD_LOG_FACE_TRACE(__func__);
if (getState() == TransportState::CLOSING ||
getState() == TransportState::FAILED ||
getState() == TransportState::CLOSED) {
// transport is shutting down, don't attempt to reconnect
return;
}
BOOST_ASSERT(getPersistency() == ndn::nfd::FACE_PERSISTENCY_PERMANENT);
BOOST_ASSERT(getState() == TransportState::DOWN);
// recreate the socket
m_socket = protocol::socket(m_socket.get_io_service());
this->resetReceiveBuffer();
this->resetSendQueue();
m_reconnectEvent = scheduler::schedule(m_nextReconnectWait,
[this] { handleReconnectTimeout(); });
m_socket.async_connect(m_remoteEndpoint,
[this] (const boost::system::error_code& error) { handleReconnect(error); });
}
void
TcpTransport::handleReconnect(const boost::system::error_code& error)
{
if (getState() == TransportState::CLOSING ||
getState() == TransportState::FAILED ||
getState() == TransportState::CLOSED ||
error == boost::asio::error::operation_aborted) {
// transport is shutting down, abort the reconnection attempt and ignore any errors
return;
}
if (error) {
NFD_LOG_FACE_TRACE("Reconnection attempt failed: " << error.message());
return;
}
m_reconnectEvent.cancel();
m_nextReconnectWait = s_initialReconnectWait;
this->setLocalUri(FaceUri(m_socket.local_endpoint()));
NFD_LOG_FACE_TRACE("TCP connection reestablished");
this->setState(TransportState::UP);
this->startReceive();
}
void
TcpTransport::handleReconnectTimeout()
{
// abort the reconnection attempt
boost::system::error_code error;
m_socket.close(error);
// exponentially back off the reconnection timer
m_nextReconnectWait =
std::min(time::duration_cast<time::milliseconds>(m_nextReconnectWait * s_reconnectWaitMultiplier),
s_maxReconnectWait);
// do this asynchronously because there could be some callbacks still pending
getGlobalIoService().post([this] { reconnect(); });
}
void
TcpTransport::doClose()
{
m_reconnectEvent.cancel();
StreamTransport::doClose();
}
} // namespace face
} // namespace nfd
+60 -12
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-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
@@ -20,28 +21,75 @@
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
**/
*/
#ifndef NFD_DAEMON_FACE_TCP_TRANSPORT_HPP
#define NFD_DAEMON_FACE_TCP_TRANSPORT_HPP
#include "stream-transport.hpp"
#include "core/scheduler.hpp"
namespace nfd {
namespace face {
/**
* \brief A Transport that communicates on a connected TCP socket
*
* When persistency is set to permanent, whenever the TCP connection is severed, the transport
* state is set to DOWN, and the connection is retried periodically with exponential backoff
* until it is reestablished
*/
class TcpTransport DECL_CLASS_FINAL : public StreamTransport<boost::asio::ip::tcp>
class TcpTransport FINAL_UNLESS_WITH_TESTS : public StreamTransport<boost::asio::ip::tcp>
{
public:
TcpTransport(protocol::socket&& socket,
ndn::nfd::FacePersistency persistency);
TcpTransport(protocol::socket&& socket, ndn::nfd::FacePersistency persistency);
protected:
virtual void
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
bool
canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const final;
void
afterChangePersistency(ndn::nfd::FacePersistency oldPersistency) final;
void
doClose() final;
void
handleError(const boost::system::error_code& error) final;
PROTECTED_WITH_TESTS_ELSE_PRIVATE:
VIRTUAL_WITH_TESTS void
reconnect();
VIRTUAL_WITH_TESTS void
handleReconnect(const boost::system::error_code& error);
VIRTUAL_WITH_TESTS void
handleReconnectTimeout();
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/** \brief how long to wait before the first reconnection attempt after the TCP connection has been severed
*/
static time::milliseconds s_initialReconnectWait;
/** \brief maximum amount of time to wait before a reconnection attempt
*/
static time::milliseconds s_maxReconnectWait;
/** \brief multiplier for the exponential backoff of the reconnection timer
*/
static float s_reconnectWaitMultiplier;
private:
typename protocol::endpoint m_remoteEndpoint;
/** \note valid only when persistency is set to permanent
*/
scheduler::ScopedEventId m_reconnectEvent;
/** \note valid only when persistency is set to permanent
*/
time::milliseconds m_nextReconnectWait;
};
} // namespace face
+40 -16
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -68,9 +68,7 @@ Transport::Transport()
{
}
Transport::~Transport()
{
}
Transport::~Transport() = default;
void
Transport::setFaceAndLinkService(Face& face, LinkService& service)
@@ -91,7 +89,7 @@ Transport::close()
this->setState(TransportState::CLOSING);
this->doClose();
// warning: don't access any fields after this:
// warning: don't access any members after this:
// the Transport may be deallocated if doClose changes state to CLOSED
}
@@ -127,23 +125,49 @@ Transport::receive(Packet&& packet)
m_service->receivePacket(std::move(packet));
}
bool
Transport::canChangePersistencyTo(ndn::nfd::FacePersistency newPersistency) const
{
// not changing, or setting initial persistency in subclass constructor
if (m_persistency == newPersistency || m_persistency == ndn::nfd::FACE_PERSISTENCY_NONE) {
return true;
}
if (newPersistency == ndn::nfd::FACE_PERSISTENCY_NONE) {
NFD_LOG_FACE_TRACE("cannot change persistency to NONE");
return false;
}
return this->canChangePersistencyToImpl(newPersistency);
}
bool
Transport::canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const
{
return false;
}
void
Transport::setPersistency(ndn::nfd::FacePersistency newPersistency)
{
BOOST_ASSERT(canChangePersistencyTo(newPersistency));
if (m_persistency == newPersistency) {
return;
}
if (newPersistency == ndn::nfd::FACE_PERSISTENCY_NONE) {
throw std::runtime_error("invalid persistency transition");
}
if (m_persistency != ndn::nfd::FACE_PERSISTENCY_NONE) {
this->beforeChangePersistency(newPersistency);
NFD_LOG_FACE_DEBUG("setPersistency " << m_persistency << " -> " << newPersistency);
}
auto oldPersistency = m_persistency;
m_persistency = newPersistency;
if (oldPersistency != ndn::nfd::FACE_PERSISTENCY_NONE) {
NFD_LOG_FACE_INFO("setPersistency " << oldPersistency << " -> " << newPersistency);
this->afterChangePersistency(oldPersistency);
}
}
void
Transport::afterChangePersistency(ndn::nfd::FacePersistency oldPersistency)
{
}
void
@@ -174,7 +198,7 @@ Transport::setState(TransportState newState)
}
if (!isValid) {
throw std::runtime_error("invalid state transition");
BOOST_THROW_EXCEPTION(std::runtime_error("invalid state transition"));
}
NFD_LOG_FACE_INFO("setState " << m_state << " -> " << newState);
@@ -182,7 +206,7 @@ Transport::setState(TransportState newState)
TransportState oldState = m_state;
m_state = newState;
afterStateChange(oldState, newState);
// warning: don't access any fields after this:
// warning: don't access any members after this:
// the Transport may be deallocated in the signal handler if newState is CLOSED
}
+28 -6
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -221,10 +221,21 @@ public: // static properties
ndn::nfd::FacePersistency
getPersistency() const;
/** \brief check whether the face persistency can be changed to \p newPersistency
*
* This function serves as the external API, and invokes the protected function
* canChangePersistencyToImpl to perform further checks if \p newPersistency differs
* from the current persistency.
*
* \return true if the change can be performed, false otherwise
*/
bool
canChangePersistencyTo(ndn::nfd::FacePersistency newPersistency) const;
/** \brief changes face persistency setting
*/
void
setPersistency(ndn::nfd::FacePersistency persistency);
setPersistency(ndn::nfd::FacePersistency newPersistency);
/** \return whether face is point-to-point or multi-access
*/
@@ -289,12 +300,23 @@ protected: // properties to be set by subclass
setExpirationTime(const time::steady_clock::TimePoint& expirationTime);
protected: // to be overridden by subclass
/** \brief invoked before persistency is changed
* \throw std::invalid_argument new persistency is not supported
* \throw std::runtime_error transition is disallowed
/** \brief invoked by canChangePersistencyTo to perform the check
*
* Base class implementation returns false.
*
* \param newPersistency the new persistency, guaranteed to be different from current persistency
*/
virtual bool
canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const;
/** \brief invoked after the persistency has been changed
*
* The base class implementation does nothing.
* When overridden in a subclass, the function should update internal states
* after persistency setting has been changed.
*/
virtual void
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) = 0;
afterChangePersistency(ndn::nfd::FacePersistency oldPersistency);
/** \brief performs Transport specific operations to close the transport
*
+7 -5
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -62,7 +62,7 @@ UdpChannel::connect(const udp::Endpoint& remoteEndpoint,
catch (const boost::system::system_error& e) {
NFD_LOG_WARN("[" << m_localEndpoint << "] Connect failed: " << e.what());
if (onConnectFailed)
onConnectFailed(e.what());
onConnectFailed(504, std::string("Connect failed: ") + e.what());
return;
}
@@ -113,7 +113,7 @@ UdpChannel::handleNewPeer(const boost::system::error_code& error,
NFD_LOG_DEBUG("[" << m_localEndpoint << "] Receive failed: " << error.message());
if (onReceiveFailed)
onReceiveFailed(error.message());
onReceiveFailed(500, "Receive failed: " + error.message());
return;
}
@@ -128,7 +128,7 @@ UdpChannel::handleNewPeer(const boost::system::error_code& error,
NFD_LOG_WARN("[" << m_localEndpoint << "] Failed to create face for peer "
<< m_remoteEndpoint << ": " << e.what());
if (onReceiveFailed)
onReceiveFailed(e.what());
onReceiveFailed(504, "Failed to create face for peer");
return;
}
@@ -146,8 +146,10 @@ UdpChannel::createFace(const udp::Endpoint& remoteEndpoint, ndn::nfd::FacePersis
{
auto it = m_channelFaces.find(remoteEndpoint);
if (it != m_channelFaces.end()) {
// we already have a face for this endpoint, just reuse it
// we already have a face for this endpoint, so reuse it
auto face = it->second;
// TODO #3232: Remove persistency transitions from faces/create
// only on-demand -> persistent -> permanent transition is allowed
bool isTransitionAllowed = persistency != face->getPersistency() &&
(face->getPersistency() == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND ||
+2 -5
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,13 +27,10 @@
#define NFD_DAEMON_FACE_UDP_CHANNEL_HPP
#include "channel.hpp"
#include "udp-protocol.hpp"
namespace nfd {
namespace udp {
typedef boost::asio::ip::udp::endpoint Endpoint;
} // namespace udp
/**
* \brief Class implementing UDP-based channel to create faces
*/
+282 -73
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,19 +27,222 @@
#include "generic-link-service.hpp"
#include "multicast-udp-transport.hpp"
#include "core/global-io.hpp"
#include "core/network-interface.hpp"
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm/copy.hpp>
#ifdef __linux__
#include <cerrno> // for errno
#include <cstring> // for std::strerror()
#include <sys/socket.h> // for setsockopt()
#endif
#endif // __linux__
namespace nfd {
namespace face {
namespace ip = boost::asio::ip;
NFD_LOG_INIT("UdpFactory");
NFD_REGISTER_PROTOCOL_FACTORY(UdpFactory);
const std::string&
UdpFactory::getId()
{
static std::string id("udp");
return id;
}
void
UdpFactory::processConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context)
{
// udp
// {
// port 6363
// enable_v4 yes
// enable_v6 yes
// idle_timeout 600
// keep_alive_interval 25 ; acceptable but ignored
// mcast yes
// mcast_group 224.0.23.170
// mcast_port 56363
// whitelist
// {
// *
// }
// blacklist
// {
// }
// }
uint16_t port = 6363;
bool enableV4 = false;
bool enableV6 = false;
uint32_t idleTimeout = 600;
MulticastConfig mcastConfig;
if (configSection) {
// These default to 'yes' but only if face_system.udp section is present
enableV4 = enableV6 = mcastConfig.isEnabled = true;
for (const auto& pair : *configSection) {
const std::string& key = pair.first;
const ConfigSection& value = pair.second;
if (key == "port") {
port = ConfigFile::parseNumber<uint16_t>(pair, "face_system.udp");
}
else if (key == "enable_v4") {
enableV4 = ConfigFile::parseYesNo(pair, "face_system.udp");
}
else if (key == "enable_v6") {
enableV6 = ConfigFile::parseYesNo(pair, "face_system.udp");
}
else if (key == "idle_timeout") {
idleTimeout = ConfigFile::parseNumber<uint32_t>(pair, "face_system.udp");
}
else if (key == "keep_alive_interval") {
// ignored
}
else if (key == "mcast") {
mcastConfig.isEnabled = ConfigFile::parseYesNo(pair, "face_system.udp");
}
else if (key == "mcast_group") {
const std::string& valueStr = value.get_value<std::string>();
boost::system::error_code ec;
mcastConfig.group.address(boost::asio::ip::address_v4::from_string(valueStr, ec));
if (ec) {
BOOST_THROW_EXCEPTION(ConfigFile::Error("face_system.udp.mcast_group: '" +
valueStr + "' cannot be parsed as an IPv4 address"));
}
else if (!mcastConfig.group.address().is_multicast()) {
BOOST_THROW_EXCEPTION(ConfigFile::Error("face_system.udp.mcast_group: '" +
valueStr + "' is not a multicast address"));
}
}
else if (key == "mcast_port") {
mcastConfig.group.port(ConfigFile::parseNumber<uint16_t>(pair, "face_system.udp"));
}
else if (key == "whitelist") {
mcastConfig.netifPredicate.parseWhitelist(value);
}
else if (key == "blacklist") {
mcastConfig.netifPredicate.parseBlacklist(value);
}
else {
BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system.udp." + key));
}
}
if (!enableV4 && !enableV6 && !mcastConfig.isEnabled) {
BOOST_THROW_EXCEPTION(ConfigFile::Error(
"IPv4 and IPv6 UDP channels and UDP multicast have been disabled. "
"Remove face_system.udp section to disable UDP channels or enable at least one of them."));
}
}
if (!context.isDryRun) {
if (enableV4) {
udp::Endpoint endpoint(ip::udp::v4(), port);
shared_ptr<UdpChannel> v4Channel = this->createChannel(endpoint, time::seconds(idleTimeout));
if (!v4Channel->isListening()) {
v4Channel->listen(context.addFace, nullptr);
}
providedSchemes.insert("udp");
providedSchemes.insert("udp4");
}
else if (providedSchemes.count("udp4") > 0) {
NFD_LOG_WARN("Cannot close udp4 channel after its creation");
}
if (enableV6) {
udp::Endpoint endpoint(ip::udp::v6(), port);
shared_ptr<UdpChannel> v6Channel = this->createChannel(endpoint, time::seconds(idleTimeout));
if (!v6Channel->isListening()) {
v6Channel->listen(context.addFace, nullptr);
}
providedSchemes.insert("udp");
providedSchemes.insert("udp6");
}
else if (providedSchemes.count("udp6") > 0) {
NFD_LOG_WARN("Cannot close udp6 channel after its creation");
}
if (m_mcastConfig.isEnabled != mcastConfig.isEnabled) {
if (mcastConfig.isEnabled) {
NFD_LOG_INFO("enabling multicast on " << mcastConfig.group);
}
else {
NFD_LOG_INFO("disabling multicast");
}
}
else if (m_mcastConfig.group != mcastConfig.group) {
NFD_LOG_INFO("changing multicast group from " << m_mcastConfig.group <<
" to " << mcastConfig.group);
}
else if (m_mcastConfig.netifPredicate != mcastConfig.netifPredicate) {
NFD_LOG_INFO("changing whitelist/blacklist");
}
else {
// There's no configuration change, but we still need to re-apply configuration because
// netifs may have changed.
}
m_mcastConfig = mcastConfig;
this->applyMulticastConfig(context);
}
}
void
UdpFactory::createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
bool wantLocalFieldsEnabled,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onFailure)
{
BOOST_ASSERT(uri.isCanonical());
if (persistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
NFD_LOG_TRACE("createFace does not support FACE_PERSISTENCY_ON_DEMAND");
onFailure(406, "Outgoing unicast UDP faces do not support on-demand persistency");
return;
}
udp::Endpoint endpoint(ip::address::from_string(uri.getHost()),
boost::lexical_cast<uint16_t>(uri.getPort()));
if (endpoint.address().is_multicast()) {
NFD_LOG_TRACE("createFace does not support multicast faces");
onFailure(406, "Cannot create multicast UDP faces");
return;
}
if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end()) {
NFD_LOG_TRACE("Requested endpoint is prohibited "
"(reserved by this NFD or disallowed by face management protocol)");
onFailure(406, "Requested endpoint is prohibited");
return;
}
if (wantLocalFieldsEnabled) {
// UDP faces are never local
NFD_LOG_TRACE("createFace cannot create non-local face with local fields enabled");
onFailure(406, "Local fields can only be enabled on faces with local scope");
return;
}
// very simple logic for now
for (const auto& i : m_channels) {
if ((i.first.address().is_v4() && endpoint.address().is_v4()) ||
(i.first.address().is_v6() && endpoint.address().is_v6())) {
i.second->connect(endpoint, persistency, onCreated, onFailure);
return;
}
}
NFD_LOG_TRACE("No channels available to connect to " + boost::lexical_cast<std::string>(endpoint));
onFailure(504, "No channels available to connect");
}
void
UdpFactory::prohibitEndpoint(const udp::Endpoint& endpoint)
@@ -110,7 +313,7 @@ UdpFactory::createChannel(const udp::Endpoint& endpoint,
"endpoint is already allocated for a UDP multicast face"));
}
channel = make_shared<UdpChannel>(endpoint, timeout);
channel = std::make_shared<UdpChannel>(endpoint, timeout);
m_channels[endpoint] = channel;
prohibitEndpoint(endpoint);
@@ -126,6 +329,22 @@ UdpFactory::createChannel(const std::string& localIp, const std::string& localPo
return createChannel(endpoint, timeout);
}
std::vector<shared_ptr<const Channel>>
UdpFactory::getChannels() const
{
return getChannelsFromMap(m_channels);
}
shared_ptr<UdpChannel>
UdpFactory::findChannel(const udp::Endpoint& localEndpoint) const
{
auto i = m_channels.find(localEndpoint);
if (i != m_channels.end())
return i->second;
else
return nullptr;
}
shared_ptr<Face>
UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint,
const udp::Endpoint& multicastEndpoint,
@@ -203,16 +422,16 @@ UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint,
": " + std::strerror(errno)));
}
}
#endif
#endif // __linux__
auto linkService = make_unique<face::GenericLinkService>();
auto transport = make_unique<face::MulticastUdpTransport>(localEndpoint, multicastEndpoint,
std::move(receiveSocket),
std::move(sendSocket));
auto linkService = make_unique<GenericLinkService>();
auto transport = make_unique<MulticastUdpTransport>(localEndpoint, multicastEndpoint,
std::move(receiveSocket),
std::move(sendSocket));
face = make_shared<Face>(std::move(linkService), std::move(transport));
m_multicastFaces[localEndpoint] = face;
connectFaceClosedSignal(*face, [this, localEndpoint] { m_multicastFaces.erase(localEndpoint); });
m_mcastFaces[localEndpoint] = face;
connectFaceClosedSignal(*face, [this, localEndpoint] { m_mcastFaces.erase(localEndpoint); });
return face;
}
@@ -230,74 +449,64 @@ UdpFactory::createMulticastFace(const std::string& localIp,
return createMulticastFace(localEndpoint, multicastEndpoint, networkInterfaceName);
}
void
UdpFactory::createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onConnectFailed)
{
BOOST_ASSERT(uri.isCanonical());
if (persistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
BOOST_THROW_EXCEPTION(Error("UdpFactory::createFace does not support FACE_PERSISTENCY_ON_DEMAND"));
}
udp::Endpoint endpoint(ip::address::from_string(uri.getHost()),
boost::lexical_cast<uint16_t>(uri.getPort()));
if (endpoint.address().is_multicast()) {
onConnectFailed("The provided address is multicast. Please use createMulticastFace method");
return;
}
if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end()) {
onConnectFailed("Requested endpoint is prohibited "
"(reserved by this NFD or disallowed by face management protocol)");
return;
}
// very simple logic for now
for (const auto& i : m_channels) {
if ((i.first.address().is_v4() && endpoint.address().is_v4()) ||
(i.first.address().is_v6() && endpoint.address().is_v6())) {
i.second->connect(endpoint, persistency, onCreated, onConnectFailed);
return;
}
}
onConnectFailed("No channels available to connect to " + boost::lexical_cast<std::string>(endpoint));
}
std::vector<shared_ptr<const Channel>>
UdpFactory::getChannels() const
{
std::vector<shared_ptr<const Channel>> channels;
channels.reserve(m_channels.size());
for (const auto& i : m_channels)
channels.push_back(i.second);
return channels;
}
shared_ptr<UdpChannel>
UdpFactory::findChannel(const udp::Endpoint& localEndpoint) const
{
auto i = m_channels.find(localEndpoint);
if (i != m_channels.end())
return i->second;
else
return nullptr;
}
shared_ptr<Face>
UdpFactory::findMulticastFace(const udp::Endpoint& localEndpoint) const
{
auto i = m_multicastFaces.find(localEndpoint);
if (i != m_multicastFaces.end())
auto i = m_mcastFaces.find(localEndpoint);
if (i != m_mcastFaces.end())
return i->second;
else
return nullptr;
}
void
UdpFactory::applyMulticastConfig(const FaceSystem::ConfigContext& context)
{
// collect old faces
std::set<shared_ptr<Face>> oldFaces;
boost::copy(m_mcastFaces | boost::adaptors::map_values,
std::inserter(oldFaces, oldFaces.end()));
if (m_mcastConfig.isEnabled) {
// determine interfaces on which faces should be created or retained
auto capableNetifRange = context.listNetifs() |
boost::adaptors::filtered([this] (const NetworkInterfaceInfo& netif) {
return netif.isUp() && netif.isMulticastCapable() &&
!netif.ipv4Addresses.empty() &&
m_mcastConfig.netifPredicate(netif);
});
bool needIfname = false;
#ifdef __linux__
std::vector<NetworkInterfaceInfo> capableNetifs;
boost::copy(capableNetifRange, std::back_inserter(capableNetifs));
// on Linux, ifname is needed to create more than one UDP multicast face on the same group
needIfname = capableNetifs.size() > 1;
#else
auto& capableNetifs = capableNetifRange;
#endif // __linux__
// create faces
for (const auto& netif : capableNetifs) {
udp::Endpoint localEndpoint(netif.ipv4Addresses.front(), m_mcastConfig.group.port());
shared_ptr<Face> face = this->createMulticastFace(localEndpoint, m_mcastConfig.group,
needIfname ? netif.name : "");
if (face->getId() == INVALID_FACEID) {
// new face: register with forwarding
context.addFace(face);
}
else {
// existing face: don't destroy
oldFaces.erase(face);
}
}
}
// destroy old faces that are not needed in new configuration
for (const auto& face : oldFaces) {
face->close();
}
}
} // namespace face
} // namespace nfd
+39 -27
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -30,9 +30,13 @@
#include "udp-channel.hpp"
namespace nfd {
namespace face {
/// @todo IPv6 multicast support not implemented
/** \brief protocol factory for UDP over IPv4 and IPv6
*
* UDP unicast is available over both IPv4 and IPv6.
* UDP multicast is available over IPv4 only.
*/
class UdpFactory : public ProtocolFactory
{
public:
@@ -49,7 +53,21 @@ public:
}
};
typedef std::map<udp::Endpoint, shared_ptr<Face>> MulticastFaceMap;
static const std::string&
getId();
/** \brief process face_system.udp config section
*/
void
processConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context) override;
void
createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
bool wantLocalFieldsEnabled,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onFailure) override;
/**
* \brief Create UDP-based channel using udp::Endpoint
@@ -97,6 +115,9 @@ public:
createChannel(const std::string& localIp, const std::string& localPort,
const time::seconds& timeout = time::seconds(600));
std::vector<shared_ptr<const Channel>>
getChannels() const override;
/**
* \brief Create MulticastUdpFace using udp::Endpoint
*
@@ -139,22 +160,6 @@ public:
const std::string& multicastPort,
const std::string& networkInterfaceName = "");
/**
* \brief Get map of configured multicast faces
*/
const MulticastFaceMap&
getMulticastFaces() const;
public: // from ProtocolFactory
virtual void
createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onConnectFailed) DECL_OVERRIDE;
virtual std::vector<shared_ptr<const Channel>>
getChannels() const DECL_OVERRIDE;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
prohibitEndpoint(const udp::Endpoint& endpoint);
@@ -184,20 +189,27 @@ private:
shared_ptr<Face>
findMulticastFace(const udp::Endpoint& localEndpoint) const;
void
applyMulticastConfig(const FaceSystem::ConfigContext& context);
private:
std::map<udp::Endpoint, shared_ptr<UdpChannel>> m_channels;
MulticastFaceMap m_multicastFaces;
struct MulticastConfig
{
bool isEnabled = false;
udp::Endpoint group = udp::getDefaultMulticastGroup();
NetworkInterfacePredicate netifPredicate;
};
MulticastConfig m_mcastConfig;
std::map<udp::Endpoint, shared_ptr<Face>> m_mcastFaces;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
std::set<udp::Endpoint> m_prohibitedEndpoints;
};
inline const UdpFactory::MulticastFaceMap&
UdpFactory::getMulticastFaces() const
{
return m_multicastFaces;
}
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_UDP_FACTORY_HPP
+2 -2
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -29,7 +29,7 @@ namespace nfd {
namespace udp {
ssize_t
computeMtu(const boost::asio::ip::udp::endpoint& localEndpoint)
computeMtu(const Endpoint& localEndpoint)
{
size_t mtu = 0;
if (localEndpoint.address().is_v4()) { // IPv4
+14 -3
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,15 +26,26 @@
#ifndef NFD_DAEMON_FACE_UDP_PROTOCOL_HPP
#define NFD_DAEMON_FACE_UDP_PROTOCOL_HPP
#include "common.hpp"
#include "core/common.hpp"
namespace nfd {
namespace udp {
typedef boost::asio::ip::udp::endpoint Endpoint;
/** \brief computes maximum payload size in a UDP packet
*/
ssize_t
computeMtu(const boost::asio::ip::udp::endpoint& localEndpoint);
computeMtu(const Endpoint& localEndpoint);
/** \return default multicast group: 224.0.23.170:56363
*/
inline Endpoint
getDefaultMulticastGroup()
{
// 224.0.23.170:56363
return {boost::asio::ip::address_v4(0xE00017AA), 56363};
}
} // namespace udp
} // namespace nfd
+10 -4
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -80,10 +80,16 @@ UnicastUdpTransport::UnicastUdpTransport(protocol::socket&& socket,
}
}
void
UnicastUdpTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
bool
UnicastUdpTransport::canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const
{
if (newPersistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND &&
return true;
}
void
UnicastUdpTransport::afterChangePersistency(ndn::nfd::FacePersistency oldPersistency)
{
if (getPersistency() == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND &&
m_idleTimeout > time::nanoseconds::zero()) {
scheduleClosureWhenIdle();
}
+7 -4
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -35,7 +35,7 @@ namespace face {
/**
* \brief A Transport that communicates on a unicast UDP socket
*/
class UnicastUdpTransport DECL_CLASS_FINAL : public DatagramTransport<boost::asio::ip::udp, Unicast>
class UnicastUdpTransport final : public DatagramTransport<boost::asio::ip::udp, Unicast>
{
public:
UnicastUdpTransport(protocol::socket&& socket,
@@ -43,8 +43,11 @@ public:
time::nanoseconds idleTimeout);
protected:
virtual void
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
bool
canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const final;
void
afterChangePersistency(ndn::nfd::FacePersistency oldPersistency) final;
private:
void
+2 -2
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -126,7 +126,7 @@ UnixStreamChannel::handleAccept(const boost::system::error_code& error,
NFD_LOG_DEBUG("[" << m_endpoint << "] Accept failed: " << error.message());
if (onAcceptFailed)
onAcceptFailed(error.message());
onAcceptFailed(500, "Accept failed: " + error.message());
return;
}
+9 -8
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-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
@@ -20,7 +21,7 @@
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
**/
*/
#ifndef NFD_DAEMON_FACE_UNIX_STREAM_CHANNEL_HPP
#define NFD_DAEMON_FACE_UNIX_STREAM_CHANNEL_HPP
@@ -59,7 +60,7 @@ public:
explicit
UnixStreamChannel(const unix_stream::Endpoint& endpoint);
~UnixStreamChannel() DECL_OVERRIDE;
~UnixStreamChannel() override;
/**
* \brief Enable listening on the local endpoint, accept connections,
+65 -18
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -24,10 +24,71 @@
*/
#include "unix-stream-factory.hpp"
#include "core/logger.hpp"
#include <boost/filesystem.hpp> // for canonical()
#include <boost/filesystem.hpp>
namespace nfd {
namespace face {
NFD_LOG_INIT("UnixStreamFactory");
NFD_REGISTER_PROTOCOL_FACTORY(UnixStreamFactory);
const std::string&
UnixStreamFactory::getId()
{
static std::string id("unix");
return id;
}
void
UnixStreamFactory::processConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context)
{
// unix
// {
// path /var/run/nfd.sock
// }
if (!configSection) {
if (!context.isDryRun && !m_channels.empty()) {
NFD_LOG_WARN("Cannot disable unix channel after initialization");
}
return;
}
std::string path = "/var/run/nfd.sock";
for (const auto& pair : *configSection) {
const std::string& key = pair.first;
const ConfigSection& value = pair.second;
if (key == "path") {
path = value.get_value<std::string>();
}
else {
BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system.unix." + key));
}
}
if (!context.isDryRun) {
auto channel = this->createChannel(path);
if (!channel->isListening()) {
channel->listen(context.addFace, nullptr);
}
}
}
void
UnixStreamFactory::createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
bool wantLocalFieldsEnabled,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onFailure)
{
onFailure(406, "Unsupported protocol");
}
shared_ptr<UnixStreamChannel>
UnixStreamFactory::createChannel(const std::string& unixSocketPath)
@@ -45,25 +106,10 @@ UnixStreamFactory::createChannel(const std::string& unixSocketPath)
return channel;
}
void
UnixStreamFactory::createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onConnectFailed)
{
BOOST_THROW_EXCEPTION(Error("UnixStreamFactory does not support 'createFace' operation"));
}
std::vector<shared_ptr<const Channel>>
UnixStreamFactory::getChannels() const
{
std::vector<shared_ptr<const Channel>> channels;
channels.reserve(m_channels.size());
for (const auto& i : m_channels)
channels.push_back(i.second);
return channels;
return getChannelsFromMap(m_channels);
}
shared_ptr<UnixStreamChannel>
@@ -76,4 +122,5 @@ UnixStreamFactory::findChannel(const unix_stream::Endpoint& endpoint) const
return nullptr;
}
} // namespace face
} // namespace nfd
+21 -23
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -30,22 +30,28 @@
#include "unix-stream-channel.hpp"
namespace nfd {
namespace face {
/** \brief protocol factory for stream-oriented Unix sockets
*/
class UnixStreamFactory : public ProtocolFactory
{
public:
/**
* \brief Exception of UnixStreamFactory
static const std::string&
getId();
/** \brief process face_system.unix config section
*/
class Error : public ProtocolFactory::Error
{
public:
explicit
Error(const std::string& what)
: ProtocolFactory::Error(what)
{
}
};
void
processConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context) override;
void
createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
bool wantLocalFieldsEnabled,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onFailure) override;
/**
* \brief Create stream-oriented Unix channel using specified socket path
@@ -56,21 +62,12 @@ public:
*
* \returns always a valid pointer to a UnixStreamChannel object,
* an exception will be thrown if the channel cannot be created.
*
* \throws UnixStreamFactory::Error
*/
shared_ptr<UnixStreamChannel>
createChannel(const std::string& unixSocketPath);
public: // from ProtocolFactory
virtual void
createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onConnectFailed) DECL_OVERRIDE;
virtual std::vector<shared_ptr<const Channel>>
getChannels() const DECL_OVERRIDE;
std::vector<shared_ptr<const Channel>>
getChannels() const override;
private:
/**
@@ -86,6 +83,7 @@ private:
std::map<unix_stream::Endpoint, shared_ptr<UnixStreamChannel>> m_channels;
};
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_UNIX_STREAM_FACTORY_HPP
+1 -10
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -49,14 +49,5 @@ UnixStreamTransport::UnixStreamTransport(protocol::socket&& socket)
NFD_LOG_FACE_INFO("Creating transport");
}
void
UnixStreamTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
{
if (newPersistency != ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
BOOST_THROW_EXCEPTION(
std::invalid_argument("UnixStreamTransport supports only FACE_PERSISTENCY_ON_DEMAND"));
}
}
} // namespace face
} // namespace nfd
+2 -6
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -38,15 +38,11 @@ namespace face {
/**
* \brief A Transport that communicates on a stream-oriented Unix domain socket
*/
class UnixStreamTransport DECL_CLASS_FINAL : public StreamTransport<boost::asio::local::stream_protocol>
class UnixStreamTransport final : public StreamTransport<boost::asio::local::stream_protocol>
{
public:
explicit
UnixStreamTransport(protocol::socket&& socket);
protected:
virtual void
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
};
} // namespace face
+98 -17
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -24,11 +24,106 @@
*/
#include "websocket-factory.hpp"
#include "core/logger.hpp"
namespace nfd {
namespace face {
namespace ip = boost::asio::ip;
NFD_LOG_INIT("WebSocketFactory");
NFD_REGISTER_PROTOCOL_FACTORY(WebSocketFactory);
const std::string&
WebSocketFactory::getId()
{
static std::string id("websocket");
return id;
}
void
WebSocketFactory::processConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context)
{
// websocket
// {
// listen yes
// port 9696
// enable_v4 yes
// enable_v6 yes
// }
bool wantListen = false;
uint16_t port = 9696;
bool enableV4 = true;
bool enableV6 = true;
if (configSection) {
wantListen = true;
for (const auto& pair : *configSection) {
const std::string& key = pair.first;
if (key == "listen") {
wantListen = ConfigFile::parseYesNo(pair, "face_system.websocket");
}
else if (key == "port") {
port = ConfigFile::parseNumber<uint16_t>(pair, "face_system.websocket");
}
else if (key == "enable_v4") {
enableV4 = ConfigFile::parseYesNo(pair, "face_system.websocket");
}
else if (key == "enable_v6") {
enableV6 = ConfigFile::parseYesNo(pair, "face_system.websocket");
}
else {
BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system.websocket." + key));
}
}
}
if (!enableV4 && !enableV6) {
BOOST_THROW_EXCEPTION(ConfigFile::Error(
"IPv4 and IPv6 WebSocket channels have been disabled. Remove face_system.websocket section "
"to disable WebSocket channels or enable at least one channel type."));
}
if (!enableV4 && enableV6) {
// websocketpp's IPv6 socket always accepts IPv4 connections.
BOOST_THROW_EXCEPTION(ConfigFile::Error("NFD does not allow pure IPv6 WebSocket channel."));
}
if (!context.isDryRun) {
if (!wantListen) {
if (!m_channels.empty()) {
NFD_LOG_WARN("Cannot close WebSocket channel after initialization");
}
return;
}
BOOST_ASSERT(enableV4);
websocket::Endpoint endpoint(enableV6 ? ip::tcp::v6() : ip::tcp::v4(), port);
auto channel = this->createChannel(endpoint);
if (!channel->isListening()) {
channel->listen(context.addFace);
if (m_channels.size() > 1) {
NFD_LOG_WARN("Adding WebSocket channel for new endpoint; cannot close existing channels");
}
}
}
}
void
WebSocketFactory::createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
bool wantLocalFieldsEnabled,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onFailure)
{
onFailure(406, "Unsupported protocol");
}
shared_ptr<WebSocketChannel>
WebSocketFactory::createChannel(const websocket::Endpoint& endpoint)
{
@@ -50,25 +145,10 @@ WebSocketFactory::createChannel(const std::string& localIp, const std::string& l
return createChannel(endpoint);
}
void
WebSocketFactory::createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onConnectFailed)
{
BOOST_THROW_EXCEPTION(Error("WebSocketFactory does not support 'createFace' operation"));
}
std::vector<shared_ptr<const Channel>>
WebSocketFactory::getChannels() const
{
std::vector<shared_ptr<const Channel>> channels;
channels.reserve(m_channels.size());
for (const auto& i : m_channels)
channels.push_back(i.second);
return channels;
return getChannelsFromMap(m_channels);
}
shared_ptr<WebSocketChannel>
@@ -81,4 +161,5 @@ WebSocketFactory::findChannel(const websocket::Endpoint& endpoint) const
return nullptr;
}
} // namespace face
} // namespace nfd
+23 -25
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -30,22 +30,30 @@
#include "websocket-channel.hpp"
namespace nfd {
namespace face {
/** \brief protocol factory for WebSocket
*/
class WebSocketFactory : public ProtocolFactory
{
public:
/**
* \brief Exception of WebSocketFactory
static const std::string&
getId();
/** \brief process face_system.websocket config section
*/
class Error : public ProtocolFactory::Error
{
public:
explicit
Error(const std::string& what)
: ProtocolFactory::Error(what)
{
}
};
void
processConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context) override;
/** \brief unicast face creation is not supported and will always fail
*/
void
createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
bool wantLocalFieldsEnabled,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onFailure) override;
/**
* \brief Create WebSocket-based channel using websocket::Endpoint
@@ -58,8 +66,6 @@ public:
*
* \returns always a valid pointer to a WebSocketChannel object, an exception
* is thrown if it cannot be created.
*
* \throws WebSocketFactory::Error
*/
shared_ptr<WebSocketChannel>
createChannel(const websocket::Endpoint& localEndpoint);
@@ -69,21 +75,12 @@ public:
*
* This method is just a helper that converts a string representation of localIp and port to
* websocket::Endpoint and calls the other createChannel overload.
*
* \throws WebSocketFactory::Error
*/
shared_ptr<WebSocketChannel>
createChannel(const std::string& localIp, const std::string& localPort);
public: // from ProtocolFactory
virtual void
createFace(const FaceUri& uri,
ndn::nfd::FacePersistency persistency,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onConnectFailed) DECL_OVERRIDE;
virtual std::vector<shared_ptr<const Channel>>
getChannels() const DECL_OVERRIDE;
std::vector<shared_ptr<const Channel>>
getChannels() const override;
private:
/**
@@ -99,6 +96,7 @@ private:
std::map<websocket::Endpoint, shared_ptr<WebSocketChannel>> m_channels;
};
} // namespace face
} // namespace nfd
#endif // NFD_DAEMON_FACE_WEBSOCKET_FACTORY_HPP
+24 -13
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -30,6 +30,24 @@ namespace face {
NFD_LOG_INIT("WebSocketTransport");
static bool
isLoopback(const boost::asio::ip::address& addr)
{
if (addr.is_loopback()) {
return true;
}
// Workaround for loopback IPv4-mapped IPv6 addresses
// see https://svn.boost.org/trac/boost/ticket/9084
else if (addr.is_v6()) {
auto addr6 = addr.to_v6();
if (addr6.is_v4_mapped()) {
return addr6.to_v4().is_loopback();
}
}
return false;
}
WebSocketTransport::WebSocketTransport(websocketpp::connection_hdl hdl,
websocket::Server& server,
time::milliseconds pingInterval)
@@ -41,11 +59,13 @@ WebSocketTransport::WebSocketTransport(websocketpp::connection_hdl hdl,
this->setLocalUri(FaceUri(sock.local_endpoint(), "ws"));
this->setRemoteUri(FaceUri(sock.remote_endpoint(), "wsclient"));
if (sock.local_endpoint().address().is_loopback() &&
sock.remote_endpoint().address().is_loopback())
if (isLoopback(sock.local_endpoint().address()) &&
isLoopback(sock.remote_endpoint().address())) {
this->setScope(ndn::nfd::FACE_SCOPE_LOCAL);
else
}
else {
this->setScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
}
this->setPersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
this->setLinkType(ndn::nfd::LINK_TYPE_POINT_TO_POINT);
@@ -56,15 +76,6 @@ WebSocketTransport::WebSocketTransport(websocketpp::connection_hdl hdl,
NFD_LOG_FACE_INFO("Creating transport");
}
void
WebSocketTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
{
if (newPersistency != ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
BOOST_THROW_EXCEPTION(
std::invalid_argument("WebSocketTransport supports only FACE_PERSISTENCY_ON_DEMAND"));
}
}
void
WebSocketTransport::doSend(Transport::Packet&& packet)
{
+9 -12
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2017, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -51,8 +51,8 @@ public:
/** \brief A Transport that communicates on a WebSocket connection
*/
class WebSocketTransport DECL_CLASS_FINAL : public Transport
, protected virtual WebSocketTransportCounters
class WebSocketTransport final : public Transport
, protected virtual WebSocketTransportCounters
{
public:
/** \brief counters provided by WebSocketTransport
@@ -63,8 +63,8 @@ public:
websocket::Server& server,
time::milliseconds pingInterval);
virtual const Counters&
getCounters() const DECL_OVERRIDE;
const Counters&
getCounters() const final;
/** \brief Translates a message into a Block
* and delivers it to the link service
@@ -79,15 +79,12 @@ public:
handlePongTimeout();
protected:
virtual void
beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
virtual void
doClose() DECL_FINAL;
void
doClose() final;
private:
virtual void
doSend(Transport::Packet&& packet) DECL_FINAL;
void
doSend(Transport::Packet&& packet) final;
void
schedulePing();
+93 -65
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -24,40 +24,49 @@
*/
#include "access-strategy.hpp"
#include "algorithm.hpp"
#include "core/logger.hpp"
namespace nfd {
namespace fw {
NFD_LOG_INIT("AccessStrategy");
const Name AccessStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/access/%FD%01");
NFD_REGISTER_STRATEGY(AccessStrategy);
AccessStrategy::AccessStrategy(Forwarder& forwarder, const Name& name)
: Strategy(forwarder, name)
: Strategy(forwarder)
, m_removeFaceInfoConn(this->beforeRemoveFace.connect(
bind(&AccessStrategy::removeFaceInfo, this, _1)))
{
ParsedInstanceName parsed = parseInstanceName(name);
if (!parsed.parameters.empty()) {
BOOST_THROW_EXCEPTION(std::invalid_argument("AccessStrategy does not accept parameters"));
}
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
BOOST_THROW_EXCEPTION(std::invalid_argument(
"AccessStrategy does not support version " + std::to_string(*parsed.version)));
}
this->setInstanceName(makeInstanceName(name, getStrategyName()));
}
AccessStrategy::~AccessStrategy()
const Name&
AccessStrategy::getStrategyName()
{
static Name strategyName("/localhost/nfd/strategy/access/%FD%01");
return strategyName;
}
void
AccessStrategy::afterReceiveInterest(const Face& inFace,
const Interest& interest,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry)
AccessStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry)
{
RetxSuppression::Result suppressResult = m_retxSuppression.decide(inFace, interest, *pitEntry);
switch (suppressResult) {
case RetxSuppression::NEW:
this->afterReceiveNewInterest(inFace, interest, fibEntry, pitEntry);
this->afterReceiveNewInterest(inFace, interest, pitEntry);
break;
case RetxSuppression::FORWARD:
this->afterReceiveRetxInterest(inFace, interest, fibEntry, pitEntry);
this->afterReceiveRetxInterest(inFace, interest, pitEntry);
break;
case RetxSuppression::SUPPRESS:
NFD_LOG_DEBUG(interest << " interestFrom " << inFace.getId() << " retx-suppress");
@@ -69,13 +78,12 @@ AccessStrategy::afterReceiveInterest(const Face& inFace,
}
void
AccessStrategy::afterReceiveNewInterest(const Face& inFace,
const Interest& interest,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry)
AccessStrategy::afterReceiveNewInterest(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry)
{
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
Name miName;
shared_ptr<MtInfo> mi;
MtInfo* mi = nullptr;
std::tie(miName, mi) = this->findPrefixMeasurements(*pitEntry);
// has measurements for Interest Name?
@@ -84,7 +92,7 @@ AccessStrategy::afterReceiveNewInterest(const Face& inFace,
" new-interest mi=" << miName);
// send to last working nexthop
bool isSentToLastNexthop = this->sendToLastNexthop(inFace, pitEntry, *mi, fibEntry);
bool isSentToLastNexthop = this->sendToLastNexthop(inFace, interest, pitEntry, *mi, fibEntry);
if (isSentToLastNexthop) {
return;
@@ -98,22 +106,26 @@ AccessStrategy::afterReceiveNewInterest(const Face& inFace,
// no measurements, or last working nexthop unavailable
// multicast to all nexthops except incoming face
this->multicast(pitEntry, fibEntry, {inFace.getId()});
int nMulticastSent = this->multicast(inFace, interest, pitEntry, fibEntry);
if (nMulticastSent < 1) {
this->rejectPendingInterest(pitEntry);
}
}
void
AccessStrategy::afterReceiveRetxInterest(const Face& inFace,
const Interest& interest,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry)
AccessStrategy::afterReceiveRetxInterest(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry)
{
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
NFD_LOG_DEBUG(interest << " interestFrom " << inFace.getId() << " retx-forward");
this->multicast(pitEntry, fibEntry, {inFace.getId()});
this->multicast(inFace, interest, pitEntry, fibEntry);
}
bool
AccessStrategy::sendToLastNexthop(const Face& inFace, shared_ptr<pit::Entry> pitEntry, MtInfo& mi,
shared_ptr<fib::Entry> fibEntry)
AccessStrategy::sendToLastNexthop(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry, MtInfo& mi,
const fib::Entry& fibEntry)
{
if (mi.lastNexthop == face::INVALID_FACEID) {
NFD_LOG_DEBUG(pitEntry->getInterest() << " no-last-nexthop");
@@ -125,13 +137,13 @@ AccessStrategy::sendToLastNexthop(const Face& inFace, shared_ptr<pit::Entry> pit
return false;
}
shared_ptr<Face> face = this->getFace(mi.lastNexthop);
if (face == nullptr || !fibEntry->hasNextHop(face)) {
Face* outFace = this->getFace(mi.lastNexthop);
if (outFace == nullptr || !fibEntry.hasNextHop(*outFace)) {
NFD_LOG_DEBUG(pitEntry->getInterest() << " last-nexthop-gone");
return false;
}
if (pitEntry->violatesScope(*face)) {
if (wouldViolateScope(inFace, interest, *outFace)) {
NFD_LOG_DEBUG(pitEntry->getInterest() << " last-nexthop-violates-scope");
return false;
}
@@ -140,68 +152,83 @@ AccessStrategy::sendToLastNexthop(const Face& inFace, shared_ptr<pit::Entry> pit
NFD_LOG_DEBUG(pitEntry->getInterest() << " interestTo " << mi.lastNexthop <<
" last-nexthop rto=" << time::duration_cast<time::microseconds>(rto).count());
this->sendInterest(pitEntry, face);
this->sendInterest(pitEntry, *outFace, interest);
// schedule RTO timeout
shared_ptr<PitInfo> pi = pitEntry->getOrCreateStrategyInfo<PitInfo>();
PitInfo* pi = pitEntry->insertStrategyInfo<PitInfo>().first;
pi->rtoTimer = scheduler::schedule(rto,
bind(&AccessStrategy::afterRtoTimeout, this, weak_ptr<pit::Entry>(pitEntry),
weak_ptr<fib::Entry>(fibEntry), inFace.getId(), mi.lastNexthop));
inFace.getId(), mi.lastNexthop));
return true;
}
void
AccessStrategy::afterRtoTimeout(weak_ptr<pit::Entry> pitWeak, weak_ptr<fib::Entry> fibWeak,
FaceId inFace, FaceId firstOutFace)
AccessStrategy::afterRtoTimeout(weak_ptr<pit::Entry> pitWeak, FaceId inFaceId, FaceId firstOutFaceId)
{
shared_ptr<pit::Entry> pitEntry = pitWeak.lock();
BOOST_ASSERT(pitEntry != nullptr);
// pitEntry can't become nullptr, because RTO timer should be cancelled upon pitEntry destruction
// if pitEntry is gone, RTO timer should have been cancelled
shared_ptr<fib::Entry> fibEntry = fibWeak.lock();
if (fibEntry == nullptr) {
NFD_LOG_DEBUG(pitEntry->getInterest() << " timeoutFrom " << firstOutFace << " fib-gone");
Face* inFace = this->getFace(inFaceId);
if (inFace == nullptr) {
NFD_LOG_DEBUG(pitEntry->getInterest() << " timeoutFrom " << firstOutFaceId <<
" inFace-gone " << inFaceId);
return;
}
NFD_LOG_DEBUG(pitEntry->getInterest() << " timeoutFrom " << firstOutFace <<
" multicast-except " << inFace << ',' << firstOutFace);
this->multicast(pitEntry, fibEntry, {inFace, firstOutFace});
pit::InRecordCollection::iterator inRecord = pitEntry->getInRecord(*inFace);
BOOST_ASSERT(inRecord != pitEntry->in_end());
// in-record is erased only if Interest is satisfied, and RTO timer should have been cancelled
// note: if this strategy is extended to send Nacks, that would also erase in-record,
// and RTO timer should be cancelled in that case as well
const Interest& interest = inRecord->getInterest();
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
NFD_LOG_DEBUG(pitEntry->getInterest() << " timeoutFrom " << firstOutFaceId <<
" multicast-except " << firstOutFaceId);
this->multicast(*inFace, interest, pitEntry, fibEntry, firstOutFaceId);
}
void
AccessStrategy::multicast(shared_ptr<pit::Entry> pitEntry, shared_ptr<fib::Entry> fibEntry,
std::unordered_set<FaceId> exceptFaces)
int
AccessStrategy::multicast(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry, const fib::Entry& fibEntry,
FaceId exceptFace)
{
for (const fib::NextHop& nexthop : fibEntry->getNextHops()) {
shared_ptr<Face> face = nexthop.getFace();
if (exceptFaces.count(face->getId()) > 0) {
int nSent = 0;
for (const fib::NextHop& nexthop : fibEntry.getNextHops()) {
Face& outFace = nexthop.getFace();
if (&outFace == &inFace || outFace.getId() == exceptFace ||
wouldViolateScope(inFace, interest, outFace)) {
continue;
}
NFD_LOG_DEBUG(pitEntry->getInterest() << " interestTo " << face->getId() <<
NFD_LOG_DEBUG(pitEntry->getInterest() << " interestTo " << outFace.getId() <<
" multicast");
this->sendInterest(pitEntry, face);
this->sendInterest(pitEntry, outFace, interest);
++nSent;
}
return nSent;
}
void
AccessStrategy::beforeSatisfyInterest(shared_ptr<pit::Entry> pitEntry,
AccessStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
const Face& inFace, const Data& data)
{
shared_ptr<PitInfo> pi = pitEntry->getStrategyInfo<PitInfo>();
PitInfo* pi = pitEntry->getStrategyInfo<PitInfo>();
if (pi != nullptr) {
pi->rtoTimer.cancel();
}
if (pitEntry->getInRecords().empty()) { // already satisfied by another upstream
if (!pitEntry->hasInRecords()) { // already satisfied by another upstream
NFD_LOG_DEBUG(pitEntry->getInterest() << " dataFrom " << inFace.getId() <<
" not-fastest");
return;
}
pit::OutRecordCollection::const_iterator outRecord = pitEntry->getOutRecord(inFace);
if (outRecord == pitEntry->getOutRecords().end()) { // no OutRecord
pit::OutRecordCollection::iterator outRecord = pitEntry->getOutRecord(inFace);
if (outRecord == pitEntry->out_end()) { // no out-record
NFD_LOG_DEBUG(pitEntry->getInterest() << " dataFrom " << inFace.getId() <<
" no-out-record");
return;
@@ -217,10 +244,11 @@ void
AccessStrategy::updateMeasurements(const Face& inFace, const Data& data,
const RttEstimator::Duration& rtt)
{
///\todo move FaceInfoTable out of AccessStrategy instance, to Measurements or somewhere else
FaceInfo& fi = m_fit[inFace.getId()];
fi.rtt.addMeasurement(rtt);
shared_ptr<MtInfo> mi = this->addPrefixMeasurements(data);
MtInfo* mi = this->addPrefixMeasurements(data);
if (mi->lastNexthop != inFace.getId()) {
mi->lastNexthop = inFace.getId();
mi->rtt = fi.rtt;
@@ -236,26 +264,26 @@ AccessStrategy::MtInfo::MtInfo()
{
}
std::tuple<Name, shared_ptr<AccessStrategy::MtInfo>>
std::tuple<Name, AccessStrategy::MtInfo*>
AccessStrategy::findPrefixMeasurements(const pit::Entry& pitEntry)
{
shared_ptr<measurements::Entry> me = this->getMeasurements().findLongestPrefixMatch(pitEntry);
measurements::Entry* me = this->getMeasurements().findLongestPrefixMatch(pitEntry);
if (me == nullptr) {
return std::forward_as_tuple(Name(), nullptr);
return std::make_tuple(Name(), nullptr);
}
shared_ptr<MtInfo> mi = me->getStrategyInfo<MtInfo>();
MtInfo* mi = me->getStrategyInfo<MtInfo>();
BOOST_ASSERT(mi != nullptr);
// XXX after runtime strategy change, it's possible that me exists but mi doesn't exist;
// this case needs another longest prefix match until mi is found
return std::forward_as_tuple(me->getName(), mi);
return std::make_tuple(me->getName(), mi);
}
shared_ptr<AccessStrategy::MtInfo>
AccessStrategy::MtInfo*
AccessStrategy::addPrefixMeasurements(const Data& data)
{
shared_ptr<measurements::Entry> me;
if (data.getName().size() >= 1) {
measurements::Entry* me = nullptr;
if (!data.getName().empty()) {
me = this->getMeasurements().get(data.getName().getPrefix(-1));
}
if (me == nullptr) { // parent of Data Name is not in this strategy, or Data Name is empty
@@ -267,7 +295,7 @@ AccessStrategy::addPrefixMeasurements(const Data& data)
static const time::nanoseconds ME_LIFETIME = time::seconds(8);
this->getMeasurements().extendLifetime(*me, ME_LIFETIME);
return me->getOrCreateStrategyInfo<MtInfo>();
return me->insertStrategyInfo<MtInfo>().first;
}
AccessStrategy::FaceInfo::FaceInfo()
@@ -276,9 +304,9 @@ AccessStrategy::FaceInfo::FaceInfo()
}
void
AccessStrategy::removeFaceInfo(shared_ptr<Face> face)
AccessStrategy::removeFaceInfo(const Face& face)
{
m_fit.erase(face->getId());
m_fit.erase(face.getId());
}
} // namespace fw
+26 -33
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -49,21 +49,20 @@ namespace fw {
class AccessStrategy : public Strategy
{
public:
AccessStrategy(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
explicit
AccessStrategy(Forwarder& forwarder, const Name& name = getStrategyName());
virtual
~AccessStrategy();
static const Name&
getStrategyName();
public: // triggers
virtual void
afterReceiveInterest(const Face& inFace,
const Interest& interest,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry) DECL_OVERRIDE;
afterReceiveInterest(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry) override;
virtual void
beforeSatisfyInterest(shared_ptr<pit::Entry> pitEntry,
const Face& inFace, const Data& data) DECL_OVERRIDE;
beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
const Face& inFace, const Data& data) override;
private: // StrategyInfo
/** \brief StrategyInfo on PIT entry
@@ -101,13 +100,13 @@ private: // StrategyInfo
/** \brief find per-prefix measurements for Interest
*/
std::tuple<Name, shared_ptr<MtInfo>>
std::tuple<Name, MtInfo*>
findPrefixMeasurements(const pit::Entry& pitEntry);
/** \brief get or create pre-prefix measurements for incoming Data
* \note This function creates MtInfo but doesn't update it.
*/
shared_ptr<MtInfo>
MtInfo*
addPrefixMeasurements(const Data& data);
/** \brief global per-face StrategyInfo
@@ -124,47 +123,41 @@ private: // StrategyInfo
typedef std::unordered_map<FaceId, FaceInfo> FaceInfoTable;
void
removeFaceInfo(shared_ptr<Face> face);
removeFaceInfo(const Face& face);
private: // forwarding procedures
void
afterReceiveNewInterest(const Face& inFace,
const Interest& interest,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry);
afterReceiveNewInterest(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry);
void
afterReceiveRetxInterest(const Face& inFace,
const Interest& interest,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry);
afterReceiveRetxInterest(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry);
/** \brief send to last working nexthop
* \return whether an Interest is sent
*/
bool
sendToLastNexthop(const Face& inFace, shared_ptr<pit::Entry> pitEntry, MtInfo& mi,
shared_ptr<fib::Entry> fibEntry);
sendToLastNexthop(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry, MtInfo& mi,
const fib::Entry& fibEntry);
void
afterRtoTimeout(weak_ptr<pit::Entry> pitWeak, weak_ptr<fib::Entry> fibWeak,
FaceId inFace, FaceId firstOutFace);
afterRtoTimeout(weak_ptr<pit::Entry> pitWeak, FaceId inFaceId, FaceId firstOutFaceId);
/** \brief multicast to all nexthops
* \param exceptFaces don't forward to those faces
* \param exceptFace don't forward to this face; also, inFace is always excluded
* \return how many Interests are sent
*/
void
multicast(shared_ptr<pit::Entry> pitEntry,
shared_ptr<fib::Entry> fibEntry,
std::unordered_set<FaceId> exceptFaces = std::unordered_set<FaceId>());
int
multicast(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry, const fib::Entry& fibEntry,
FaceId exceptFace = face::INVALID_FACEID);
void
updateMeasurements(const Face& inFace, const Data& data,
const RttEstimator::Duration& rtt);
public:
static const Name STRATEGY_NAME;
private:
FaceInfoTable m_fit;
RetxSuppressionFixed m_retxSuppression;
+124
View File
@@ -0,0 +1,124 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "algorithm.hpp"
namespace nfd {
namespace scope_prefix {
const Name LOCALHOST("ndn:/localhost");
const Name LOCALHOP("ndn:/localhop");
} // namespace scope_prefix
namespace fw {
bool
wouldViolateScope(const Face& inFace, const Interest& interest, const Face& outFace)
{
if (outFace.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) {
// forwarding to a local face is always allowed
return false;
}
if (scope_prefix::LOCALHOST.isPrefixOf(interest.getName())) {
// localhost Interests cannot be forwarded to a non-local face
return true;
}
if (scope_prefix::LOCALHOP.isPrefixOf(interest.getName())) {
// localhop Interests can be forwarded to a non-local face only if it comes from a local face
return inFace.getScope() != ndn::nfd::FACE_SCOPE_LOCAL;
}
// Interest name is not subject to scope control
return false;
}
bool
canForwardToLegacy(const pit::Entry& pitEntry, const Face& face)
{
time::steady_clock::TimePoint now = time::steady_clock::now();
bool hasUnexpiredOutRecord = std::any_of(pitEntry.out_begin(), pitEntry.out_end(),
[&face, &now] (const pit::OutRecord& outRecord) {
return &outRecord.getFace() == &face && outRecord.getExpiry() >= now;
});
if (hasUnexpiredOutRecord) {
return false;
}
bool hasUnexpiredOtherInRecord = std::any_of(pitEntry.in_begin(), pitEntry.in_end(),
[&face, &now] (const pit::InRecord& inRecord) {
return &inRecord.getFace() != &face && inRecord.getExpiry() >= now;
});
if (!hasUnexpiredOtherInRecord) {
return false;
}
return true;
}
int
findDuplicateNonce(const pit::Entry& pitEntry, uint32_t nonce, const Face& face)
{
int dnw = DUPLICATE_NONCE_NONE;
for (const pit::InRecord& inRecord : pitEntry.getInRecords()) {
if (inRecord.getLastNonce() == nonce) {
if (&inRecord.getFace() == &face) {
dnw |= DUPLICATE_NONCE_IN_SAME;
}
else {
dnw |= DUPLICATE_NONCE_IN_OTHER;
}
}
}
for (const pit::OutRecord& outRecord : pitEntry.getOutRecords()) {
if (outRecord.getLastNonce() == nonce) {
if (&outRecord.getFace() == &face) {
dnw |= DUPLICATE_NONCE_OUT_SAME;
}
else {
dnw |= DUPLICATE_NONCE_OUT_OTHER;
}
}
}
return dnw;
}
bool
hasPendingOutRecords(const pit::Entry& pitEntry)
{
time::steady_clock::TimePoint now = time::steady_clock::now();
return std::any_of(pitEntry.out_begin(), pitEntry.out_end(),
[&now] (const pit::OutRecord& outRecord) {
return outRecord.getExpiry() >= now &&
outRecord.getIncomingNack() == nullptr;
});
}
} // namespace fw
} // namespace nfd
+114
View File
@@ -0,0 +1,114 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NFD_DAEMON_FW_PIT_ALGORITHM_HPP
#define NFD_DAEMON_FW_PIT_ALGORITHM_HPP
#include "table/pit-entry.hpp"
/** \file
* This file contains common algorithms used by forwarding strategies.
*/
namespace nfd {
/** \brief contain name prefixes that affect namespace-based scope control
* \sa https://redmine.named-data.net/projects/nfd/wiki/ScopeControl
*/
namespace scope_prefix {
/** \brief ndn:/localhost
*
* The localhost scope limits propagation to the applications on the originating host.
*
* Interest and Data packets under prefix ndn:/localhost are restricted by these rules:
* \li Interest can come from and go to local faces only.
* \li Data can come from and go to local faces only.
*/
extern const Name LOCALHOST;
/** \brief ndn:/localhop
*
* The localhop scope limits propagation to no further than the next node.
*
* Interest packets under prefix ndn:/localhop are restricted by these rules:
* \li If an Interest is received from a local face, it can be forwarded to a non-local face.
* \li If an Interest is received from a non-local face, it cannot be forwarded to a non-local face.
* \li In either case the Interest can be forwarded to a local face.
* \li PIT entry can be satisfied by Data from any source.
*
* Data packets under prefix ndn:/localhop are unrestricted.
*/
extern const Name LOCALHOP;
} // namespace scope_prefix
namespace fw {
/** \brief determine whether forwarding the Interest in \p pitEntry to \p outFace would violate scope
* \sa https://redmine.named-data.net/projects/nfd/wiki/ScopeControl
*/
bool
wouldViolateScope(const Face& inFace, const Interest& interest, const Face& outFace);
/** \brief decide whether Interest can be forwarded to face
*
* \return true if out-record of this face does not exist or has expired,
* and there is an in-record not of this face
*
* \note This algorithm has a weakness that it does not permit consumer retransmissions
* before out-record expires. Therefore, it's not recommended to use this function
* in new strategies.
* \todo find a better name for this function
*/
bool
canForwardToLegacy(const pit::Entry& pitEntry, const Face& face);
/** \brief indicates where duplicate Nonces are found
*/
enum DuplicateNonceWhere {
DUPLICATE_NONCE_NONE = 0, ///< no duplicate Nonce is found
DUPLICATE_NONCE_IN_SAME = (1 << 0), ///< in-record of same face
DUPLICATE_NONCE_IN_OTHER = (1 << 1), ///< in-record of other face
DUPLICATE_NONCE_OUT_SAME = (1 << 2), ///< out-record of same face
DUPLICATE_NONCE_OUT_OTHER = (1 << 3) ///< out-record of other face
};
/** \brief determine whether \p pitEntry has duplicate Nonce \p nonce
* \return OR'ed DuplicateNonceWhere
*/
int
findDuplicateNonce(const pit::Entry& pitEntry, uint32_t nonce, const Face& face);
/** \brief determine whether \p pitEntry has any pending out-records
* \return true if there is at least one out-record waiting for Data
*/
bool
hasPendingOutRecords(const pit::Entry& pitEntry);
} // namespace fw
} // namespace nfd
#endif // NFD_DAEMON_FW_PIT_ALGORITHM_HPP
+272
View File
@@ -0,0 +1,272 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "asf-measurements.hpp"
namespace nfd {
namespace fw {
namespace asf {
NFD_LOG_INIT("AsfMeasurements");
const RttStats::Rtt RttStats::RTT_TIMEOUT(-1.0);
const RttStats::Rtt RttStats::RTT_NO_MEASUREMENT(0.0);
const double RttStats::ALPHA = 0.125;
RttStats::RttStats()
: m_srtt(RTT_NO_MEASUREMENT)
, m_rtt(RTT_NO_MEASUREMENT)
{
}
void
RttStats::addRttMeasurement(RttEstimator::Duration& durationRtt)
{
m_rtt = static_cast<RttStats::Rtt>(durationRtt.count());
m_rttEstimator.addMeasurement(durationRtt);
m_srtt = computeSrtt(m_srtt, m_rtt);
}
RttStats::Rtt
RttStats::computeSrtt(Rtt previousSrtt, Rtt currentRtt)
{
if (previousSrtt == RTT_NO_MEASUREMENT) {
return currentRtt;
}
return Rtt(ALPHA * currentRtt + (1 - ALPHA) * previousSrtt);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
FaceInfo::FaceInfo()
: m_isTimeoutScheduled(false)
{
}
FaceInfo::~FaceInfo()
{
cancelTimeoutEvent();
scheduler::cancel(m_measurementExpirationId);
}
void
FaceInfo::setTimeoutEvent(const scheduler::EventId& id, const Name& interestName)
{
if (!m_isTimeoutScheduled) {
m_timeoutEventId = id;
m_isTimeoutScheduled = true;
m_lastInterestName = interestName;
}
else {
BOOST_THROW_EXCEPTION(FaceInfo::Error("Tried to schedule a timeout for a face that already has a timeout scheduled."));
}
}
void
FaceInfo::cancelTimeoutEvent()
{
scheduler::cancel(m_timeoutEventId);
m_isTimeoutScheduled = false;
}
void
FaceInfo::cancelTimeoutEvent(const Name& prefix)
{
if (isTimeoutScheduled() && doesNameMatchLastInterest(prefix)) {
cancelTimeoutEvent();
}
}
bool
FaceInfo::doesNameMatchLastInterest(const Name& name)
{
return m_lastInterestName.isPrefixOf(name);
}
void
FaceInfo::recordRtt(const shared_ptr<pit::Entry>& pitEntry, const Face& inFace)
{
// Calculate RTT
pit::OutRecordCollection::const_iterator outRecord = pitEntry->getOutRecord(inFace);
if (outRecord == pitEntry->out_end()) { // no out-record
NFD_LOG_TRACE(pitEntry->getInterest() << " dataFrom inFace=" << inFace.getId() << " no-out-record");
return;
}
time::steady_clock::Duration steadyRtt = time::steady_clock::now() - outRecord->getLastRenewed();
RttEstimator::Duration durationRtt = time::duration_cast<RttEstimator::Duration>(steadyRtt);
m_rttStats.addRttMeasurement(durationRtt);
NFD_LOG_TRACE("Recording RTT for FaceId: " << inFace.getId()
<< " RTT: " << m_rttStats.getRtt()
<< " SRTT: " << m_rttStats.getSrtt());
}
void
FaceInfo::recordTimeout(const Name& interestName)
{
m_rttStats.recordTimeout();
cancelTimeoutEvent(interestName);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
NamespaceInfo::NamespaceInfo()
: m_isProbingDue(false)
, m_hasFirstProbeBeenScheduled(false)
{
}
FaceInfo*
NamespaceInfo::getFaceInfo(const fib::Entry& fibEntry, const Face& face)
{
FaceInfoTable::iterator it = m_fit.find(face.getId());
if (it != m_fit.end()) {
return &it->second;
}
else {
return nullptr;
}
}
FaceInfo&
NamespaceInfo::getOrCreateFaceInfo(const fib::Entry& fibEntry, const Face& face)
{
FaceInfoTable::iterator it = m_fit.find(face.getId());
FaceInfo* info = nullptr;
if (it == m_fit.end()) {
const auto& pair = m_fit.insert(std::make_pair(face.getId(), FaceInfo()));
info = &pair.first->second;
extendFaceInfoLifetime(*info, face);
}
else {
info = &it->second;
}
return *info;
}
void
NamespaceInfo::expireFaceInfo(nfd::face::FaceId faceId)
{
m_fit.erase(faceId);
}
void
NamespaceInfo::extendFaceInfoLifetime(FaceInfo& info, const Face& face)
{
// Cancel previous expiration
scheduler::cancel(info.getMeasurementExpirationEventId());
// Refresh measurement
scheduler::EventId id = scheduler::schedule(AsfMeasurements::MEASUREMENTS_LIFETIME,
bind(&NamespaceInfo::expireFaceInfo, this, face.getId()));
info.setMeasurementExpirationEventId(id);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
constexpr time::microseconds AsfMeasurements::MEASUREMENTS_LIFETIME;
AsfMeasurements::AsfMeasurements(MeasurementsAccessor& measurements)
: m_measurements(measurements)
{
}
FaceInfo*
AsfMeasurements::getFaceInfo(const fib::Entry& fibEntry, const Interest& interest, const Face& face)
{
NamespaceInfo& info = getOrCreateNamespaceInfo(fibEntry, interest);
return info.getFaceInfo(fibEntry, face);
}
FaceInfo&
AsfMeasurements::getOrCreateFaceInfo(const fib::Entry& fibEntry, const Interest& interest, const Face& face)
{
NamespaceInfo& info = getOrCreateNamespaceInfo(fibEntry, interest);
return info.getOrCreateFaceInfo(fibEntry, face);
}
NamespaceInfo*
AsfMeasurements::getNamespaceInfo(const Name& prefix)
{
measurements::Entry* me = m_measurements.findLongestPrefixMatch(prefix);
if (me == nullptr) {
return nullptr;
}
// Set or update entry lifetime
extendLifetime(*me);
NamespaceInfo* info = me->insertStrategyInfo<NamespaceInfo>().first;
BOOST_ASSERT(info != nullptr);
return info;
}
NamespaceInfo&
AsfMeasurements::getOrCreateNamespaceInfo(const fib::Entry& fibEntry, const Interest& interest)
{
measurements::Entry* me = m_measurements.get(fibEntry);
// If the FIB entry is not under the strategy's namespace, find a part of the prefix
// that falls under the strategy's namespace
for (size_t prefixLen = fibEntry.getPrefix().size() + 1;
me == nullptr && prefixLen <= interest.getName().size(); ++prefixLen) {
me = m_measurements.get(interest.getName().getPrefix(prefixLen));
}
// Either the FIB entry or the Interest's name must be under this strategy's namespace
BOOST_ASSERT(me != nullptr);
// Set or update entry lifetime
extendLifetime(*me);
NamespaceInfo* info = me->insertStrategyInfo<NamespaceInfo>().first;
BOOST_ASSERT(info != nullptr);
return *info;
}
void
AsfMeasurements::extendLifetime(measurements::Entry& me)
{
m_measurements.extendLifetime(me, MEASUREMENTS_LIFETIME);
}
} // namespace asf
} // namespace fw
} // namespace nfd
+312
View File
@@ -0,0 +1,312 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NFD_DAEMON_FW_ASF_MEASUREMENTS_HPP
#define NFD_DAEMON_FW_ASF_MEASUREMENTS_HPP
#include "fw/rtt-estimator.hpp"
#include "fw/strategy-info.hpp"
#include "table/measurements-accessor.hpp"
namespace nfd {
namespace fw {
namespace asf {
class RttStats
{
public:
typedef time::duration<double, boost::micro> Rtt;
RttStats();
void
addRttMeasurement(RttEstimator::Duration& durationRtt);
void
recordTimeout()
{
m_rtt = RTT_TIMEOUT;
}
Rtt
getRtt() const
{
return m_rtt;
}
Rtt
getSrtt() const
{
return m_srtt;
}
RttEstimator::Duration
computeRto() const
{
return m_rttEstimator.computeRto();
}
private:
static Rtt
computeSrtt(Rtt previousSrtt, Rtt currentRtt);
public:
static const Rtt RTT_TIMEOUT;
static const Rtt RTT_NO_MEASUREMENT;
private:
Rtt m_srtt;
Rtt m_rtt;
RttEstimator m_rttEstimator;
static const double ALPHA;
};
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/** \brief Strategy information for each face in a namespace
*/
class FaceInfo
{
public:
class Error : public std::runtime_error
{
public:
explicit
Error(const std::string& what)
: std::runtime_error(what)
{
}
};
FaceInfo();
~FaceInfo();
void
setTimeoutEvent(const scheduler::EventId& id, const Name& interestName);
void
setMeasurementExpirationEventId(const scheduler::EventId& id)
{
m_measurementExpirationId = id;
}
const scheduler::EventId&
getMeasurementExpirationEventId()
{
return m_measurementExpirationId;
}
void
cancelTimeoutEvent(const Name& prefix);
bool
isTimeoutScheduled() const
{
return m_isTimeoutScheduled;
}
void
recordRtt(const shared_ptr<pit::Entry>& pitEntry, const Face& inFace);
void
recordTimeout(const Name& interestName);
bool
isTimeout() const
{
return getRtt() == RttStats::RTT_TIMEOUT;
}
RttEstimator::Duration
computeRto() const
{
return m_rttStats.computeRto();
}
RttStats::Rtt
getRtt() const
{
return m_rttStats.getRtt();
}
RttStats::Rtt
getSrtt() const
{
return m_rttStats.getSrtt();
}
bool
hasSrttMeasurement() const
{
return getSrtt() != RttStats::RTT_NO_MEASUREMENT;
}
private:
void
cancelTimeoutEvent();
bool
doesNameMatchLastInterest(const Name& name);
private:
RttStats m_rttStats;
Name m_lastInterestName;
// Timeout associated with measurement
scheduler::EventId m_measurementExpirationId;
// RTO associated with Interest
scheduler::EventId m_timeoutEventId;
bool m_isTimeoutScheduled;
};
typedef std::unordered_map<face::FaceId, FaceInfo> FaceInfoTable;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/** \brief stores stategy information about each face in this namespace
*/
class NamespaceInfo : public StrategyInfo
{
public:
NamespaceInfo();
static constexpr int
getTypeId()
{
return 1030;
}
FaceInfo&
getOrCreateFaceInfo(const fib::Entry& fibEntry, const Face& face);
FaceInfo*
getFaceInfo(const fib::Entry& fibEntry, const Face& face);
void
expireFaceInfo(nfd::face::FaceId faceId);
void
extendFaceInfoLifetime(FaceInfo& info, const Face& face);
FaceInfo&
get(nfd::face::FaceId faceId)
{
return m_fit.at(faceId);
}
FaceInfoTable::iterator
find(nfd::face::FaceId faceId)
{
return m_fit.find(faceId);
}
FaceInfoTable::iterator
end()
{
return m_fit.end();
}
const FaceInfoTable::iterator
insert(nfd::face::FaceId faceId)
{
const auto& pair = m_fit.insert(std::make_pair(faceId, FaceInfo()));
return pair.first;
}
bool
isProbingDue() const
{
return m_isProbingDue;
}
void
setIsProbingDue(bool isProbingDue)
{
m_isProbingDue = isProbingDue;
}
bool
isFirstProbeScheduled() const
{
return m_hasFirstProbeBeenScheduled;
}
void
setHasFirstProbeBeenScheduled(bool hasBeenScheduled)
{
m_hasFirstProbeBeenScheduled = hasBeenScheduled;
}
private:
FaceInfoTable m_fit;
bool m_isProbingDue;
bool m_hasFirstProbeBeenScheduled;
};
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/** \brief Helper class to retrieve and create strategy measurements
*/
class AsfMeasurements : noncopyable
{
public:
explicit
AsfMeasurements(MeasurementsAccessor& measurements);
FaceInfo*
getFaceInfo(const fib::Entry& fibEntry, const Interest& interest, const Face& face);
FaceInfo&
getOrCreateFaceInfo(const fib::Entry& fibEntry, const Interest& interest, const Face& face);
NamespaceInfo*
getNamespaceInfo(const Name& prefix);
NamespaceInfo&
getOrCreateNamespaceInfo(const fib::Entry& fibEntry, const Interest& interest);
private:
void
extendLifetime(measurements::Entry& me);
public:
static constexpr time::microseconds MEASUREMENTS_LIFETIME = time::seconds(300);
private:
MeasurementsAccessor& m_measurements;
};
} // namespace asf
} // namespace fw
} // namespace nfd
#endif // NFD_DAEMON_FW_ASF_MEASUREMENTS_HPP
+194
View File
@@ -0,0 +1,194 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "asf-probing-module.hpp"
#include "core/random.hpp"
#include "algorithm.hpp"
namespace nfd {
namespace fw {
namespace asf {
constexpr time::seconds ProbingModule::DEFAULT_PROBING_INTERVAL;
static_assert(ProbingModule::DEFAULT_PROBING_INTERVAL < AsfMeasurements::MEASUREMENTS_LIFETIME,
"ProbingModule::DEFAULT_PROBING_INTERVAL must be less than AsfMeasurements::MEASUREMENTS_LIFETIME");
ProbingModule::ProbingModule(AsfMeasurements& measurements)
: m_probingInterval(DEFAULT_PROBING_INTERVAL)
, m_measurements(measurements)
{
}
void
ProbingModule::scheduleProbe(const fib::Entry& fibEntry, const time::milliseconds& interval)
{
Name prefix = fibEntry.getPrefix();
// Set the probing flag for the namespace to true after passed interval of time
scheduler::schedule(interval, [this, prefix] {
NamespaceInfo* info = m_measurements.getNamespaceInfo(prefix);
if (info == nullptr) {
// fib::Entry with the passed prefix has been removed or the fib::Entry has
// a name that is not controlled by the AsfStrategy
return;
}
else {
info->setIsProbingDue(true);
}
});
}
Face*
ProbingModule::getFaceToProbe(const Face& inFace,
const Interest& interest,
const fib::Entry& fibEntry,
const Face& faceUsed)
{
FaceInfoFacePairSet rankedFaces(
[] (FaceInfoFacePair pairLhs, FaceInfoFacePair pairRhs) -> bool {
// Sort by RTT
// If a face has timed-out, rank it behind non-timed-out faces
FaceInfo& lhs = *pairLhs.first;
FaceInfo& rhs = *pairRhs.first;
return (!lhs.isTimeout() && rhs.isTimeout()) ||
(lhs.isTimeout() == rhs.isTimeout() && lhs.getSrtt() < rhs.getSrtt());
});
// Put eligible faces into rankedFaces. If a face does not have an RTT measurement,
// immediately pick the face for probing
for (const fib::NextHop& hop : fibEntry.getNextHops()) {
Face& hopFace = hop.getFace();
// Don't send probe Interest back to the incoming face or use the same face
// as the forwarded Interest or use a face that violates scope
if (hopFace.getId() == inFace.getId() || hopFace.getId() == faceUsed.getId() ||
wouldViolateScope(inFace, interest, hopFace)) {
continue;
}
FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace);
// If no RTT has been recorded, probe this face
if (info == nullptr || !info->hasSrttMeasurement()) {
return &hopFace;
}
// Add FaceInfo to container sorted by RTT
rankedFaces.insert(std::make_pair(info, &hopFace));
}
if (rankedFaces.empty()) {
// No Face to probe
return nullptr;
}
return getFaceBasedOnProbability(rankedFaces);
}
bool
ProbingModule::isProbingNeeded(const fib::Entry& fibEntry, const Interest& interest)
{
// Return the probing status flag for a namespace
NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
// If a first probe has not been scheduled for a namespace
if (!info.isFirstProbeScheduled()) {
// Schedule first probe between 0 and 5 seconds
uint64_t interval = getRandomNumber(0, 5000);
scheduleProbe(fibEntry, time::milliseconds(interval));
info.setHasFirstProbeBeenScheduled(true);
}
return info.isProbingDue();
}
void
ProbingModule::afterForwardingProbe(const fib::Entry& fibEntry, const Interest& interest)
{
// After probing is done, need to set probing flag to false and
// schedule another future probe
NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
info.setIsProbingDue(false);
scheduleProbe(fibEntry, m_probingInterval);
}
Face*
ProbingModule::getFaceBasedOnProbability(const FaceInfoFacePairSet& rankedFaces)
{
double randomNumber = getRandomNumber(0, 1);
uint64_t rankSum = ((rankedFaces.size() + 1) * rankedFaces.size()) / 2;
uint64_t rank = 1;
double offset = 0.0;
for (const FaceInfoFacePair pair : rankedFaces) {
double probability = getProbingProbability(rank++, rankSum, rankedFaces.size());
// Is the random number within the bounds of this face's probability + the previous faces'
// probability?
//
// e.g. (FaceId: 1, p=0.5), (FaceId: 2, p=0.33), (FaceId: 3, p=0.17)
// randomNumber = 0.92
//
// The face with FaceId: 3 should be picked
// (0.68 < 0.5 + 0.33 + 0.17) == true
//
if (randomNumber <= offset + probability) {
// Found face to probe
return pair.second;
}
offset += probability;
}
// Given a set of Faces, this method should always select a Face to probe
BOOST_ASSERT(false);
return nullptr;
}
double
ProbingModule::getProbingProbability(uint64_t rank, uint64_t rankSum, uint64_t nFaces)
{
// p = n + 1 - j ; n: # faces
// ---------
// sum(ranks)
return static_cast<double>(nFaces + 1 - rank) / rankSum;
}
double
ProbingModule::getRandomNumber(double start, double end)
{
std::uniform_real_distribution<double> dist(start, end);
return dist(getGlobalRng());
}
} // namespace asf
} // namespace fw
} // namespace nfd
+85
View File
@@ -0,0 +1,85 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NFD_DAEMON_FW_ASF_PROBING_MODULE_HPP
#define NFD_DAEMON_FW_ASF_PROBING_MODULE_HPP
#include "asf-measurements.hpp"
namespace nfd {
namespace fw {
namespace asf {
/** \brief ASF Probing Module
*/
class ProbingModule
{
public:
explicit
ProbingModule(AsfMeasurements& measurements);
void
scheduleProbe(const fib::Entry& fibEntry, const time::milliseconds& interval);
Face*
getFaceToProbe(const Face& inFace,
const Interest& interest,
const fib::Entry& fibEntry,
const Face& faceUsed);
bool
isProbingNeeded(const fib::Entry& fibEntry, const Interest& interest);
void
afterForwardingProbe(const fib::Entry& fibEntry, const Interest& interest);
private:
// Used to associate FaceInfo with the face in a NextHop
typedef std::pair<FaceInfo*, Face*> FaceInfoFacePair;
typedef std::function<bool(FaceInfoFacePair, FaceInfoFacePair)> FaceInfoPredicate;
typedef std::set<FaceInfoFacePair, FaceInfoPredicate> FaceInfoFacePairSet;
Face*
getFaceBasedOnProbability(const FaceInfoFacePairSet& rankedFaces);
double
getProbingProbability(uint64_t rank, uint64_t rankSum, uint64_t nFaces);
double
getRandomNumber(double start, double end);
public:
static constexpr time::seconds DEFAULT_PROBING_INTERVAL = time::seconds(60);
private:
time::seconds m_probingInterval;
AsfMeasurements& m_measurements;
};
} // namespace asf
} // namespace fw
} // namespace nfd
#endif // NFD_DAEMON_FW_ASF_PROBING_MODULE_HPP
+309
View File
@@ -0,0 +1,309 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "asf-strategy.hpp"
#include "algorithm.hpp"
#include "core/logger.hpp"
namespace nfd {
namespace fw {
namespace asf {
NFD_LOG_INIT("AsfStrategy");
NFD_REGISTER_STRATEGY(AsfStrategy);
const time::milliseconds AsfStrategy::RETX_SUPPRESSION_INITIAL(10);
const time::milliseconds AsfStrategy::RETX_SUPPRESSION_MAX(250);
AsfStrategy::AsfStrategy(Forwarder& forwarder, const Name& name)
: Strategy(forwarder)
, m_measurements(getMeasurements())
, m_probing(m_measurements)
, m_retxSuppression(RETX_SUPPRESSION_INITIAL,
RetxSuppressionExponential::DEFAULT_MULTIPLIER,
RETX_SUPPRESSION_MAX)
{
ParsedInstanceName parsed = parseInstanceName(name);
if (!parsed.parameters.empty()) {
BOOST_THROW_EXCEPTION(std::invalid_argument("AsfStrategy does not accept parameters"));
}
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
BOOST_THROW_EXCEPTION(std::invalid_argument(
"AsfStrategy does not support version " + std::to_string(*parsed.version)));
}
this->setInstanceName(makeInstanceName(name, getStrategyName()));
}
const Name&
AsfStrategy::getStrategyName()
{
static Name strategyName("/localhost/nfd/strategy/asf/%FD%01");
return strategyName;
}
void
AsfStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry)
{
// Should the Interest be suppressed?
RetxSuppression::Result suppressResult = m_retxSuppression.decide(inFace, interest, *pitEntry);
switch (suppressResult) {
case RetxSuppression::NEW:
case RetxSuppression::FORWARD:
break;
case RetxSuppression::SUPPRESS:
NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " suppressed");
return;
}
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
const fib::NextHopList& nexthops = fibEntry.getNextHops();
if (nexthops.size() == 0) {
sendNoRouteNack(inFace, interest, pitEntry);
this->rejectPendingInterest(pitEntry);
return;
}
Face* faceToUse = getBestFaceForForwarding(fibEntry, interest, inFace);
if (faceToUse == nullptr) {
sendNoRouteNack(inFace, interest, pitEntry);
this->rejectPendingInterest(pitEntry);
return;
}
forwardInterest(interest, fibEntry, pitEntry, *faceToUse);
// If necessary, send probe
if (m_probing.isProbingNeeded(fibEntry, interest)) {
Face* faceToProbe = m_probing.getFaceToProbe(inFace, interest, fibEntry, *faceToUse);
if (faceToProbe != nullptr) {
bool wantNewNonce = true;
forwardInterest(interest, fibEntry, pitEntry, *faceToProbe, wantNewNonce);
m_probing.afterForwardingProbe(fibEntry, interest);
}
}
}
void
AsfStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
const Face& inFace, const Data& data)
{
NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(pitEntry->getName());
if (namespaceInfo == nullptr) {
NFD_LOG_TRACE("Could not find measurements entry for " << pitEntry->getName());
return;
}
// Record the RTT between the Interest out to Data in
FaceInfo& faceInfo = namespaceInfo->get(inFace.getId());
faceInfo.recordRtt(pitEntry, inFace);
// Extend lifetime for measurements associated with Face
namespaceInfo->extendFaceInfoLifetime(faceInfo, inFace);
if (faceInfo.isTimeoutScheduled()) {
faceInfo.cancelTimeoutEvent(data.getName());
}
}
void
AsfStrategy::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
const shared_ptr<pit::Entry>& pitEntry)
{
NFD_LOG_DEBUG("Nack for " << nack.getInterest() << " from=" << inFace.getId() << ": " << nack.getReason());
onTimeout(pitEntry->getName(), inFace.getId());
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void
AsfStrategy::forwardInterest(const Interest& interest,
const fib::Entry& fibEntry,
const shared_ptr<pit::Entry>& pitEntry,
Face& outFace,
bool wantNewNonce)
{
if (wantNewNonce) {
//Send probe: interest with new Nonce
Interest probeInterest(interest);
probeInterest.refreshNonce();
NFD_LOG_TRACE("Sending probe for " << probeInterest << probeInterest.getNonce()
<< " to FaceId: " << outFace.getId());
this->sendInterest(pitEntry, outFace, probeInterest);
}
else {
this->sendInterest(pitEntry, outFace, interest);
}
FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interest, outFace);
// Refresh measurements since Face is being used for forwarding
NamespaceInfo& namespaceInfo = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
namespaceInfo.extendFaceInfoLifetime(faceInfo, outFace);
if (!faceInfo.isTimeoutScheduled()) {
// Estimate and schedule timeout
RttEstimator::Duration timeout = faceInfo.computeRto();
NFD_LOG_TRACE("Scheduling timeout for " << fibEntry.getPrefix()
<< " FaceId: " << outFace.getId()
<< " in " << time::duration_cast<time::milliseconds>(timeout) << " ms");
scheduler::EventId id = scheduler::schedule(timeout,
bind(&AsfStrategy::onTimeout, this, interest.getName(), outFace.getId()));
faceInfo.setTimeoutEvent(id, interest.getName());
}
}
struct FaceStats
{
Face* face;
RttStats::Rtt rtt;
RttStats::Rtt srtt;
uint64_t cost;
};
double
getValueForSorting(const FaceStats& stats)
{
// These values allow faces with no measurements to be ranked better than timeouts
// srtt < RTT_NO_MEASUREMENT < RTT_TIMEOUT
static const RttStats::Rtt SORTING_RTT_TIMEOUT = time::microseconds::max();
static const RttStats::Rtt SORTING_RTT_NO_MEASUREMENT = SORTING_RTT_TIMEOUT / 2;
if (stats.rtt == RttStats::RTT_TIMEOUT) {
return SORTING_RTT_TIMEOUT.count();
}
else if (stats.rtt == RttStats::RTT_NO_MEASUREMENT) {
return SORTING_RTT_NO_MEASUREMENT.count();
}
else {
return stats.srtt.count();
}
}
Face*
AsfStrategy::getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest,
const Face& inFace)
{
NFD_LOG_TRACE("Looking for best face for " << fibEntry.getPrefix());
typedef std::function<bool(const FaceStats&, const FaceStats&)> FaceStatsPredicate;
typedef std::set<FaceStats, FaceStatsPredicate> FaceStatsSet;
FaceStatsSet rankedFaces(
[] (const FaceStats& lhs, const FaceStats& rhs) -> bool {
// Sort by RTT and then by cost
double lhsValue = getValueForSorting(lhs);
double rhsValue = getValueForSorting(rhs);
if (lhsValue < rhsValue) {
return true;
}
else if (lhsValue == rhsValue) {
return lhs.cost < rhs.cost;
}
else {
return false;
}
});
for (const fib::NextHop& hop : fibEntry.getNextHops()) {
Face& hopFace = hop.getFace();
if (hopFace.getId() == inFace.getId() || wouldViolateScope(inFace, interest, hopFace)) {
continue;
}
FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace);
if (info == nullptr) {
FaceStats stats = {&hopFace,
RttStats::RTT_NO_MEASUREMENT,
RttStats::RTT_NO_MEASUREMENT,
hop.getCost()};
rankedFaces.insert(stats);
}
else {
FaceStats stats = {&hopFace, info->getRtt(), info->getSrtt(), hop.getCost()};
rankedFaces.insert(stats);
}
}
FaceStatsSet::iterator it = rankedFaces.begin();
if (it != rankedFaces.end()) {
return it->face;
}
else {
return nullptr;
}
}
void
AsfStrategy::onTimeout(const Name& interestName, face::FaceId faceId)
{
NFD_LOG_TRACE("FaceId: " << faceId << " for " << interestName << " has timed-out");
NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(interestName);
if (namespaceInfo == nullptr) {
NFD_LOG_TRACE("FibEntry for " << interestName << " has been removed since timeout scheduling");
return;
}
FaceInfoTable::iterator it = namespaceInfo->find(faceId);
if (it == namespaceInfo->end()) {
it = namespaceInfo->insert(faceId);
}
FaceInfo& faceInfo = it->second;
faceInfo.recordTimeout(interestName);
}
void
AsfStrategy::sendNoRouteNack(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry)
{
NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " noNextHop");
lp::NackHeader nackHeader;
nackHeader.setReason(lp::NackReason::NO_ROUTE);
this->sendNack(pitEntry, inFace, nackHeader);
}
} // namespace asf
} // namespace fw
} // namespace nfd
+101
View File
@@ -0,0 +1,101 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NFD_DAEMON_FW_ASF_STRATEGY_HPP
#define NFD_DAEMON_FW_ASF_STRATEGY_HPP
#include "asf-measurements.hpp"
#include "asf-probing-module.hpp"
#include "fw/retx-suppression-exponential.hpp"
#include "fw/strategy.hpp"
namespace nfd {
namespace fw {
namespace asf {
/** \brief Adaptive SRTT-based Forwarding Strategy
*
* \see Vince Lehman, Ashlesh Gawande, Rodrigo Aldecoa, Dmitri Krioukov, Beichuan Zhang, Lixia Zhang, and Lan Wang,
* "An Experimental Investigation of Hyperbolic Routing with a Smart Forwarding Plane in NDN,"
* NDN Technical Report NDN-0042, 2016. http://named-data.net/techreports.html
*/
class AsfStrategy : public Strategy
{
public:
explicit
AsfStrategy(Forwarder& forwarder, const Name& name = getStrategyName());
static const Name&
getStrategyName();
public: // triggers
virtual void
afterReceiveInterest(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry) override;
virtual void
beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
const Face& inFace, const Data& data) override;
virtual void
afterReceiveNack(const Face& inFace, const lp::Nack& nack,
const shared_ptr<pit::Entry>& pitEntry) override;
private:
void
forwardInterest(const Interest& interest,
const fib::Entry& fibEntry,
const shared_ptr<pit::Entry>& pitEntry,
Face& outFace,
bool wantNewNonce = false);
Face*
getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest, const Face& inFace);
void
onTimeout(const Name& interestName, face::FaceId faceId);
void
sendNoRouteNack(const Face& inFace, const Interest& interest, const shared_ptr<pit::Entry>& pitEntry);
private:
AsfMeasurements m_measurements;
ProbingModule m_probing;
private:
RetxSuppressionExponential m_retxSuppression;
static const time::milliseconds RETX_SUPPRESSION_INITIAL;
static const time::milliseconds RETX_SUPPRESSION_MAX;
};
} // namespace asf
using asf::AsfStrategy;
} // namespace fw
} // namespace nfd
#endif // NFD_DAEMON_FW_ASF_STRATEGY_HPP
+40 -30
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -24,51 +24,61 @@
*/
#include "best-route-strategy.hpp"
#include "algorithm.hpp"
namespace nfd {
namespace fw {
const Name BestRouteStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/best-route/%FD%01");
NFD_REGISTER_STRATEGY(BestRouteStrategy);
BestRouteStrategy::BestRouteStrategy(Forwarder& forwarder, const Name& name)
: Strategy(forwarder, name)
BestRouteStrategyBase::BestRouteStrategyBase(Forwarder& forwarder)
: Strategy(forwarder)
{
}
BestRouteStrategy::~BestRouteStrategy()
{
}
static inline bool
predicate_PitEntry_canForwardTo_NextHop(shared_ptr<pit::Entry> pitEntry,
const fib::NextHop& nexthop)
{
return pitEntry->canForwardTo(*nexthop.getFace());
}
void
BestRouteStrategy::afterReceiveInterest(const Face& inFace,
const Interest& interest,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry)
BestRouteStrategyBase::afterReceiveInterest(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry)
{
if (pitEntry->hasUnexpiredOutRecords()) {
if (hasPendingOutRecords(*pitEntry)) {
// not a new Interest, don't forward
return;
}
const fib::NextHopList& nexthops = fibEntry->getNextHops();
fib::NextHopList::const_iterator it = std::find_if(nexthops.begin(), nexthops.end(),
bind(&predicate_PitEntry_canForwardTo_NextHop, pitEntry, _1));
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
const fib::NextHopList& nexthops = fibEntry.getNextHops();
if (it == nexthops.end()) {
this->rejectPendingInterest(pitEntry);
return;
for (fib::NextHopList::const_iterator it = nexthops.begin(); it != nexthops.end(); ++it) {
Face& outFace = it->getFace();
if (!wouldViolateScope(inFace, interest, outFace) &&
canForwardToLegacy(*pitEntry, outFace)) {
this->sendInterest(pitEntry, outFace, interest);
return;
}
}
shared_ptr<Face> outFace = it->getFace();
this->sendInterest(pitEntry, outFace);
this->rejectPendingInterest(pitEntry);
}
NFD_REGISTER_STRATEGY(BestRouteStrategy);
BestRouteStrategy::BestRouteStrategy(Forwarder& forwarder, const Name& name)
: BestRouteStrategyBase(forwarder)
{
ParsedInstanceName parsed = parseInstanceName(name);
if (!parsed.parameters.empty()) {
BOOST_THROW_EXCEPTION(std::invalid_argument("BestRouteStrategy does not accept parameters"));
}
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
BOOST_THROW_EXCEPTION(std::invalid_argument(
"BestRouteStrategy does not support version " + std::to_string(*parsed.version)));
}
this->setInstanceName(makeInstanceName(name, getStrategyName()));
}
const Name&
BestRouteStrategy::getStrategyName()
{
static Name strategyName("/localhost/nfd/strategy/best-route/%FD%01");
return strategyName;
}
} // namespace fw
+26 -23
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-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
@@ -31,6 +31,17 @@
namespace nfd {
namespace fw {
class BestRouteStrategyBase : public Strategy
{
public:
void
afterReceiveInterest(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry) override;
protected:
BestRouteStrategyBase(Forwarder& forwarder);
};
/** \brief Best Route strategy version 1
*
* This strategy forwards a new Interest to the lowest-cost nexthop
@@ -38,26 +49,18 @@ namespace fw {
* Subsequent similar Interests or consumer retransmissions are suppressed
* until after InterestLifetime expiry.
*
* \deprecated This strategy is superceded by Best Route strategy version 2,
* which allows consumer retransmissions. This version is kept for
* comparison purposes and is not recommended for general usage.
* \note This strategy is superceded by Best Route strategy version 2,
* which allows consumer retransmissions. This version is kept for
* comparison purposes and is not recommended for general usage.
*/
class BestRouteStrategy : public Strategy
class BestRouteStrategy : public BestRouteStrategyBase
{
public:
BestRouteStrategy(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
explicit
BestRouteStrategy(Forwarder& forwarder, const Name& name = getStrategyName());
virtual
~BestRouteStrategy();
virtual void
afterReceiveInterest(const Face& inFace,
const Interest& interest,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry) DECL_OVERRIDE;
public:
static const Name STRATEGY_NAME;
static const Name&
getStrategyName();
};
} // namespace fw
+69 -56
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -24,55 +24,71 @@
*/
#include "best-route-strategy2.hpp"
#include "algorithm.hpp"
#include "core/logger.hpp"
namespace nfd {
namespace fw {
NFD_LOG_INIT("BestRouteStrategy2");
const Name BestRouteStrategy2::STRATEGY_NAME("ndn:/localhost/nfd/strategy/best-route/%FD%04");
NFD_REGISTER_STRATEGY(BestRouteStrategy2);
const time::milliseconds BestRouteStrategy2::RETX_SUPPRESSION_INITIAL(10);
const time::milliseconds BestRouteStrategy2::RETX_SUPPRESSION_MAX(250);
BestRouteStrategy2::BestRouteStrategy2(Forwarder& forwarder, const Name& name)
: Strategy(forwarder, name)
: Strategy(forwarder)
, m_retxSuppression(RETX_SUPPRESSION_INITIAL,
RetxSuppressionExponential::DEFAULT_MULTIPLIER,
RETX_SUPPRESSION_MAX)
{
ParsedInstanceName parsed = parseInstanceName(name);
if (!parsed.parameters.empty()) {
BOOST_THROW_EXCEPTION(std::invalid_argument("BestRouteStrategy2 does not accept parameters"));
}
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
BOOST_THROW_EXCEPTION(std::invalid_argument(
"BestRouteStrategy2 does not support version " + std::to_string(*parsed.version)));
}
this->setInstanceName(makeInstanceName(name, getStrategyName()));
}
const Name&
BestRouteStrategy2::getStrategyName()
{
static Name strategyName("/localhost/nfd/strategy/best-route/%FD%04");
return strategyName;
}
/** \brief determines whether a NextHop is eligible
* \param pitEntry PIT entry
* \param inFace incoming face of current Interest
* \param interest incoming Interest
* \param nexthop next hop
* \param currentDownstream incoming FaceId of current Interest
* \param wantUnused if true, NextHop must not have unexpired OutRecord
* \param pitEntry PIT entry
* \param wantUnused if true, NextHop must not have unexpired out-record
* \param now time::steady_clock::now(), ignored if !wantUnused
*/
static inline bool
predicate_NextHop_eligible(const shared_ptr<pit::Entry>& pitEntry,
const fib::NextHop& nexthop, FaceId currentDownstream,
bool wantUnused = false,
time::steady_clock::TimePoint now = time::steady_clock::TimePoint::min())
isNextHopEligible(const Face& inFace, const Interest& interest,
const fib::NextHop& nexthop,
const shared_ptr<pit::Entry>& pitEntry,
bool wantUnused = false,
time::steady_clock::TimePoint now = time::steady_clock::TimePoint::min())
{
shared_ptr<Face> upstream = nexthop.getFace();
const Face& outFace = nexthop.getFace();
// upstream is current downstream
if (upstream->getId() == currentDownstream)
// do not forward back to the same face
if (&outFace == &inFace)
return false;
// forwarding would violate scope
if (pitEntry->violatesScope(*upstream))
if (wouldViolateScope(inFace, interest, outFace))
return false;
if (wantUnused) {
// NextHop must not have unexpired OutRecord
pit::OutRecordCollection::const_iterator outRecord = pitEntry->getOutRecord(*upstream);
if (outRecord != pitEntry->getOutRecords().end() &&
outRecord->getExpiry() > now) {
// nexthop must not have unexpired out-record
pit::OutRecordCollection::iterator outRecord = pitEntry->getOutRecord(outFace);
if (outRecord != pitEntry->out_end() && outRecord->getExpiry() > now) {
return false;
}
}
@@ -80,21 +96,21 @@ predicate_NextHop_eligible(const shared_ptr<pit::Entry>& pitEntry,
return true;
}
/** \brief pick an eligible NextHop with earliest OutRecord
* \note It is assumed that every nexthop has an OutRecord
/** \brief pick an eligible NextHop with earliest out-record
* \note It is assumed that every nexthop has an out-record.
*/
static inline fib::NextHopList::const_iterator
findEligibleNextHopWithEarliestOutRecord(const shared_ptr<pit::Entry>& pitEntry,
findEligibleNextHopWithEarliestOutRecord(const Face& inFace, const Interest& interest,
const fib::NextHopList& nexthops,
FaceId currentDownstream)
const shared_ptr<pit::Entry>& pitEntry)
{
fib::NextHopList::const_iterator found = nexthops.end();
time::steady_clock::TimePoint earliestRenewed = time::steady_clock::TimePoint::max();
for (fib::NextHopList::const_iterator it = nexthops.begin(); it != nexthops.end(); ++it) {
if (!predicate_NextHop_eligible(pitEntry, *it, currentDownstream))
if (!isNextHopEligible(inFace, interest, *it, pitEntry))
continue;
pit::OutRecordCollection::const_iterator outRecord = pitEntry->getOutRecord(*it->getFace());
BOOST_ASSERT(outRecord != pitEntry->getOutRecords().end());
pit::OutRecordCollection::iterator outRecord = pitEntry->getOutRecord(it->getFace());
BOOST_ASSERT(outRecord != pitEntry->out_end());
if (outRecord->getLastRenewed() < earliestRenewed) {
found = it;
earliestRenewed = outRecord->getLastRenewed();
@@ -104,19 +120,24 @@ findEligibleNextHopWithEarliestOutRecord(const shared_ptr<pit::Entry>& pitEntry,
}
void
BestRouteStrategy2::afterReceiveInterest(const Face& inFace,
const Interest& interest,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry)
BestRouteStrategy2::afterReceiveInterest(const Face& inFace, const Interest& interest,
const shared_ptr<pit::Entry>& pitEntry)
{
const fib::NextHopList& nexthops = fibEntry->getNextHops();
RetxSuppression::Result suppression = m_retxSuppression.decide(inFace, interest, *pitEntry);
if (suppression == RetxSuppression::SUPPRESS) {
NFD_LOG_DEBUG(interest << " from=" << inFace.getId()
<< " suppressed");
return;
}
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
const fib::NextHopList& nexthops = fibEntry.getNextHops();
fib::NextHopList::const_iterator it = nexthops.end();
RetxSuppression::Result suppression = m_retxSuppression.decide(inFace, interest, *pitEntry);
if (suppression == RetxSuppression::NEW) {
// forward to nexthop with lowest cost except downstream
it = std::find_if(nexthops.begin(), nexthops.end(),
bind(&predicate_NextHop_eligible, pitEntry, _1, inFace.getId(),
bind(&isNextHopEligible, cref(inFace), interest, _1, pitEntry,
false, time::steady_clock::TimePoint::min()));
if (it == nexthops.end()) {
@@ -130,41 +151,35 @@ BestRouteStrategy2::afterReceiveInterest(const Face& inFace,
return;
}
shared_ptr<Face> outFace = it->getFace();
this->sendInterest(pitEntry, outFace);
Face& outFace = it->getFace();
this->sendInterest(pitEntry, outFace, interest);
NFD_LOG_DEBUG(interest << " from=" << inFace.getId()
<< " newPitEntry-to=" << outFace->getId());
return;
}
if (suppression == RetxSuppression::SUPPRESS) {
NFD_LOG_DEBUG(interest << " from=" << inFace.getId()
<< " suppressed");
<< " newPitEntry-to=" << outFace.getId());
return;
}
// find an unused upstream with lowest cost except downstream
it = std::find_if(nexthops.begin(), nexthops.end(),
bind(&predicate_NextHop_eligible, pitEntry, _1, inFace.getId(),
bind(&isNextHopEligible, cref(inFace), interest, _1, pitEntry,
true, time::steady_clock::now()));
if (it != nexthops.end()) {
shared_ptr<Face> outFace = it->getFace();
this->sendInterest(pitEntry, outFace);
Face& outFace = it->getFace();
this->sendInterest(pitEntry, outFace, interest);
NFD_LOG_DEBUG(interest << " from=" << inFace.getId()
<< " retransmit-unused-to=" << outFace->getId());
<< " retransmit-unused-to=" << outFace.getId());
return;
}
// find an eligible upstream that is used earliest
it = findEligibleNextHopWithEarliestOutRecord(pitEntry, nexthops, inFace.getId());
it = findEligibleNextHopWithEarliestOutRecord(inFace, interest, nexthops, pitEntry);
if (it == nexthops.end()) {
NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " retransmitNoNextHop");
}
else {
shared_ptr<Face> outFace = it->getFace();
this->sendInterest(pitEntry, outFace);
Face& outFace = it->getFace();
this->sendInterest(pitEntry, outFace, interest);
NFD_LOG_DEBUG(interest << " from=" << inFace.getId()
<< " retransmit-retry-to=" << outFace->getId());
<< " retransmit-retry-to=" << outFace.getId());
}
}
@@ -186,8 +201,7 @@ compareLessSevere(lp::NackReason x, lp::NackReason y)
void
BestRouteStrategy2::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry)
const shared_ptr<pit::Entry>& pitEntry)
{
int nOutRecordsNotNacked = 0;
Face* lastFaceNotNacked = nullptr;
@@ -196,7 +210,7 @@ BestRouteStrategy2::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
const lp::NackHeader* inNack = outR.getIncomingNack();
if (inNack == nullptr) {
++nOutRecordsNotNacked;
lastFaceNotNacked = outR.getFace().get();
lastFaceNotNacked = &outR.getFace();
continue;
}
@@ -208,8 +222,8 @@ BestRouteStrategy2::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
if (nOutRecordsNotNacked == 1) {
BOOST_ASSERT(lastFaceNotNacked != nullptr);
pit::InRecordCollection::const_iterator inR = pitEntry->getInRecord(*lastFaceNotNacked);
if (inR != pitEntry->getInRecords().end()) {
pit::InRecordCollection::iterator inR = pitEntry->getInRecord(*lastFaceNotNacked);
if (inR != pitEntry->in_end()) {
// one out-record not Nacked, which is also a downstream
NFD_LOG_DEBUG(nack.getInterest() << " nack-from=" << inFace.getId() <<
" nack=" << nack.getReason() <<
@@ -228,7 +242,6 @@ BestRouteStrategy2::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
return;
}
NFD_LOG_DEBUG(nack.getInterest() << " nack-from=" << inFace.getId() <<
" nack=" << nack.getReason() <<
" nack-to=all out-nack=" << outNack.getReason());
+8 -9
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -52,20 +52,19 @@ namespace fw {
class BestRouteStrategy2 : public Strategy
{
public:
BestRouteStrategy2(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
explicit
BestRouteStrategy2(Forwarder& forwarder, const Name& name = getStrategyName());
static const Name&
getStrategyName();
virtual void
afterReceiveInterest(const Face& inFace, const Interest& interest,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry) DECL_OVERRIDE;
const shared_ptr<pit::Entry>& pitEntry) override;
virtual void
afterReceiveNack(const Face& inFace, const lp::Nack& nack,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry) DECL_OVERRIDE;
public:
static const Name STRATEGY_NAME;
const shared_ptr<pit::Entry>& pitEntry) override;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
static const time::milliseconds RETX_SUPPRESSION_INITIAL;
+18 -32
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -30,44 +30,30 @@ namespace nfd {
namespace fw {
NFD_LOG_INIT("ClientControlStrategy");
const Name
ClientControlStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/client-control/%FD%01");
NFD_REGISTER_STRATEGY(ClientControlStrategy);
ClientControlStrategy::ClientControlStrategy(Forwarder& forwarder, const Name& name)
: BestRouteStrategy(forwarder, name)
: BestRouteStrategyBase(forwarder)
{
ParsedInstanceName parsed = parseInstanceName(name);
if (!parsed.parameters.empty()) {
BOOST_THROW_EXCEPTION(std::invalid_argument("ClientControlStrategy does not accept parameters"));
}
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
BOOST_THROW_EXCEPTION(std::invalid_argument(
"ClientControlStrategy does not support version " + std::to_string(*parsed.version)));
}
this->setInstanceName(makeInstanceName(name, getStrategyName()));
NFD_LOG_WARN("NextHopFaceId field is honored universally and "
"it's unnecessary to set client-control strategy.");
}
ClientControlStrategy::~ClientControlStrategy()
const Name&
ClientControlStrategy::getStrategyName()
{
}
void
ClientControlStrategy::afterReceiveInterest(const Face& inFace,
const Interest& interest,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry)
{
shared_ptr<lp::NextHopFaceIdTag> tag = interest.getTag<lp::NextHopFaceIdTag>();
if (tag == nullptr) {
this->BestRouteStrategy::afterReceiveInterest(inFace, interest, fibEntry, pitEntry);
return;
}
FaceId outFaceId = static_cast<FaceId>(*tag);
shared_ptr<Face> outFace = this->getFace(outFaceId);
if (outFace == nullptr) {
// If outFace doesn't exist, it's better to reject the Interest
// than to use BestRouteStrategy.
NFD_LOG_WARN("Interest " << interest.getName() <<
" NextHopFaceId=" << outFaceId << " non-existent face");
this->rejectPendingInterest(pitEntry);
return;
}
this->sendInterest(pitEntry, outFace);
static Name strategyName("/localhost/nfd/strategy/client-control/%FD%02");
return strategyName;
}
} // namespace fw
+14 -25
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-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
@@ -31,28 +31,17 @@
namespace nfd {
namespace fw {
/** \brief a forwarding strategy controlled by client application
*
* The consumer may specify the nexthop for an Interest in NDNLPv2 NextHopFaceId field.
* If NextHopFaceId field is omitted, the Interest is forwarded to
* the FIB nexthop with lowest routing cost.
/** \brief identical to BestRouteStrategy v1, for backwards compatibility
* \deprecated NextHopFaceId field is honored universally and it's unnecessary to set this strategy
*/
class ClientControlStrategy : public BestRouteStrategy
class ClientControlStrategy : public BestRouteStrategyBase
{
public:
ClientControlStrategy(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
explicit
ClientControlStrategy(Forwarder& forwarder, const Name& name = getStrategyName());
virtual
~ClientControlStrategy();
virtual void
afterReceiveInterest(const Face& inFace,
const Interest& interest,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry) DECL_OVERRIDE;
public:
static const Name STRATEGY_NAME;
static const Name&
getStrategyName();
};
} // namespace fw
+22 -24
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -25,30 +25,30 @@
#include "face-table.hpp"
#include "forwarder.hpp"
#include "core/asserts.hpp"
#include "core/global-io.hpp"
#include "core/logger.hpp"
#include "face/channel.hpp"
namespace nfd {
NFD_ASSERT_FORWARD_ITERATOR(FaceTable::const_iterator);
NFD_LOG_INIT("FaceTable");
FaceTable::FaceTable(Forwarder& forwarder)
: m_forwarder(forwarder)
, m_lastFaceId(face::FACEID_RESERVED_MAX)
FaceTable::FaceTable()
: m_lastFaceId(face::FACEID_RESERVED_MAX)
{
}
FaceTable::~FaceTable()
{
}
shared_ptr<Face>
Face*
FaceTable::get(FaceId id) const
{
std::map<FaceId, shared_ptr<Face> >::const_iterator i = m_faces.find(id);
return (i == m_faces.end()) ? (shared_ptr<Face>()) : (i->second);
auto i = m_faces.find(id);
if (i == m_faces.end()) {
return nullptr;
}
return i->second.get();
}
size_t
@@ -87,29 +87,27 @@ FaceTable::addImpl(shared_ptr<Face> face, FaceId faceId)
NFD_LOG_INFO("Added face id=" << faceId << " remote=" << face->getRemoteUri()
<< " local=" << face->getLocalUri());
face->afterReceiveInterest.connect(bind(&Forwarder::startProcessInterest, &m_forwarder, ref(*face), _1));
face->afterReceiveData.connect(bind(&Forwarder::startProcessData, &m_forwarder, ref(*face), _1));
face->afterReceiveNack.connect(bind(&Forwarder::startProcessNack, &m_forwarder, ref(*face), _1));
connectFaceClosedSignal(*face, bind(&FaceTable::remove, this, face));
connectFaceClosedSignal(*face, bind(&FaceTable::remove, this, faceId));
this->afterAdd(face);
this->afterAdd(*face);
}
void
FaceTable::remove(shared_ptr<Face> face)
FaceTable::remove(FaceId faceId)
{
this->beforeRemove(face);
auto i = m_faces.find(faceId);
BOOST_ASSERT(i != m_faces.end());
shared_ptr<Face> face = i->second;
FaceId faceId = face->getId();
m_faces.erase(faceId);
this->beforeRemove(*face);
m_faces.erase(i);
face->setId(face::INVALID_FACEID);
NFD_LOG_INFO("Removed face id=" << faceId <<
" remote=" << face->getRemoteUri() <<
" local=" << face->getLocalUri());
m_forwarder.getFib().removeNextHopFromAllEntries(face);
// defer Face deallocation, so that Transport isn't deallocated during afterStateChange signal
getGlobalIoService().post([face] {});
}
@@ -117,7 +115,7 @@ FaceTable::remove(shared_ptr<Face> face)
FaceTable::ForwardRange
FaceTable::getForwardRange() const
{
return m_faces | boost::adaptors::map_values;
return m_faces | boost::adaptors::map_values | boost::adaptors::indirected;
}
FaceTable::const_iterator
+28 -22
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,42 +27,49 @@
#define NFD_DAEMON_FW_FACE_TABLE_HPP
#include "face/face.hpp"
#include <boost/range/adaptor/indirected.hpp>
#include <boost/range/adaptor/map.hpp>
namespace nfd {
class Forwarder;
/** \brief container of all Faces
/** \brief container of all faces
*/
class FaceTable : noncopyable
{
public:
explicit
FaceTable(Forwarder& forwarder);
FaceTable();
VIRTUAL_WITH_TESTS
~FaceTable();
VIRTUAL_WITH_TESTS void
/** \brief add a face
*
* FaceTable obtains shared ownership of the face.
* The channel or protocol factory that creates the face may retain ownership.
*/
void
add(shared_ptr<Face> face);
/// add a special Face with a reserved FaceId
VIRTUAL_WITH_TESTS void
/** \brief add a special face with a reserved FaceId
*/
void
addReserved(shared_ptr<Face> face, FaceId faceId);
VIRTUAL_WITH_TESTS shared_ptr<Face>
/** \brief get face by FaceId
* \return a face if found, nullptr if not found;
* face->shared_from_this() can be used if shared_ptr<Face> is desired
*/
Face*
get(FaceId id) const;
/** \return count of faces
*/
size_t
size() const;
public: // enumeration
typedef std::map<FaceId, shared_ptr<Face>> FaceMap;
typedef boost::select_second_const_range<FaceMap> ForwardRange;
typedef boost::indirected_range<const boost::select_second_const_range<FaceMap>> ForwardRange;
/** \brief ForwardIterator for shared_ptr<Face>
/** \brief ForwardIterator for Face&
*/
typedef boost::range_iterator<ForwardRange>::type const_iterator;
@@ -73,28 +80,27 @@ public: // enumeration
end() const;
public: // signals
/** \brief fires after a Face is added
/** \brief fires after a face is added
*/
signal::Signal<FaceTable, shared_ptr<Face>> afterAdd;
signal::Signal<FaceTable, Face&> afterAdd;
/** \brief fires before a Face is removed
/** \brief fires before a face is removed
*
* FaceId is valid when this event is fired
* When this signal is emitted, face is still in FaceTable and has valid FaceId.
*/
signal::Signal<FaceTable, shared_ptr<Face>> beforeRemove;
signal::Signal<FaceTable, Face&> beforeRemove;
private:
void
addImpl(shared_ptr<Face> face, FaceId faceId);
void
remove(shared_ptr<Face> face);
remove(FaceId faceId);
ForwardRange
getForwardRange() const;
private:
Forwarder& m_forwarder;
FaceId m_lastFaceId;
FaceMap m_faces;
};
+104 -179
View File
@@ -24,32 +24,53 @@
*/
#include "forwarder.hpp"
#include "core/logger.hpp"
#include "core/random.hpp"
#include "algorithm.hpp"
#include "best-route-strategy2.hpp"
#include "strategy.hpp"
#include <boost/random/uniform_int_distribution.hpp>
#include "core/logger.hpp"
#include "table/cleanup.hpp"
#include <ndn-cxx/lp/tags.hpp>
namespace nfd {
NFD_LOG_INIT("Forwarder");
using fw::Strategy;
const Name Forwarder::LOCALHOST_NAME("ndn:/localhost");
static Name
getDefaultStrategyName()
{
return fw::BestRouteStrategy2::getStrategyName();
}
Forwarder::Forwarder()
: m_faceTable(*this)
: m_unsolicitedDataPolicy(new fw::DefaultUnsolicitedDataPolicy())
, m_fib(m_nameTree)
, m_pit(m_nameTree)
, m_measurements(m_nameTree)
, m_strategyChoice(m_nameTree, fw::makeDefaultStrategy(*this))
, m_strategyChoice(*this)
{
fw::installStrategies(*this);
m_faceTable.afterAdd.connect([this] (Face& face) {
face.afterReceiveInterest.connect(
[this, &face] (const Interest& interest) {
this->startProcessInterest(face, interest);
});
face.afterReceiveData.connect(
[this, &face] (const Data& data) {
this->startProcessData(face, data);
});
face.afterReceiveNack.connect(
[this, &face] (const lp::Nack& nack) {
this->startProcessNack(face, nack);
});
});
m_faceTable.beforeRemove.connect([this] (Face& face) {
cleanupOnFaceRemoval(m_nameTree, m_fib, m_pit, face);
});
m_strategyChoice.setDefaultStrategy(getDefaultStrategyName());
}
Forwarder::~Forwarder()
{
}
Forwarder::~Forwarder() = default;
void
Forwarder::startProcessInterest(Face& face, const Interest& interest)
@@ -109,7 +130,7 @@ Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
// /localhost scope control
bool isViolatingLocalhost = inFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
LOCALHOST_NAME.isPrefixOf(interest.getName());
scope_prefix::LOCALHOST.isPrefixOf(interest.getName());
if (isViolatingLocalhost) {
NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
" interest=" << interest.getName() << " violates /localhost");
@@ -129,8 +150,8 @@ Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
shared_ptr<pit::Entry> pitEntry = m_pit.insert(interest).first;
// detect duplicate Nonce in PIT entry
bool hasDuplicateNonceInPit = pitEntry->findNonce(interest.getNonce(), inFace) !=
pit::DUPLICATE_NONCE_NONE;
bool hasDuplicateNonceInPit = fw::findDuplicateNonce(*pitEntry, interest.getNonce(), inFace) !=
fw::DUPLICATE_NONCE_NONE;
if (hasDuplicateNonceInPit) {
// goto Interest loop pipeline
this->onInterestLoop(inFace, interest);
@@ -138,12 +159,10 @@ Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
}
// cancel unsatisfy & straggler timer
this->cancelUnsatisfyAndStragglerTimer(pitEntry);
this->cancelUnsatisfyAndStragglerTimer(*pitEntry);
// is pending?
const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
bool isPending = inRecords.begin() != inRecords.end();
if (!isPending) {
if (!pitEntry->hasInRecords()) {
m_cs.find(interest,
bind(&Forwarder::onContentStoreHit, this, ref(inFace), pitEntry, _1, _2),
bind(&Forwarder::onContentStoreMiss, this, ref(inFace), pitEntry, _1));
@@ -176,77 +195,39 @@ Forwarder::onInterestLoop(Face& inFace, const Interest& interest)
}
void
Forwarder::onContentStoreMiss(const Face& inFace,
shared_ptr<pit::Entry> pitEntry,
Forwarder::onContentStoreMiss(const Face& inFace, const shared_ptr<pit::Entry>& pitEntry,
const Interest& interest)
{
NFD_LOG_DEBUG("onContentStoreMiss interest=" << interest.getName());
shared_ptr<Face> face = const_pointer_cast<Face>(inFace.shared_from_this());
// insert InRecord
pitEntry->insertOrUpdateInRecord(face, interest);
// insert in-record
pitEntry->insertOrUpdateInRecord(const_cast<Face&>(inFace), interest);
// set PIT unsatisfy timer
this->setUnsatisfyTimer(pitEntry);
shared_ptr<fib::Entry> fibEntry;
// has Link object?
if (!interest.hasLink()) {
// FIB lookup with Interest name
fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
NFD_LOG_TRACE("onContentStoreMiss noLinkObject");
}
else {
const Link& link = interest.getLink();
// in producer region?
if (m_networkRegionTable.isInProducerRegion(link)) {
// FIB lookup with Interest name
fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
NFD_LOG_TRACE("onContentStoreMiss inProducerRegion");
}
// has SelectedDelegation?
else if (interest.hasSelectedDelegation()) {
// FIB lookup with SelectedDelegation
fibEntry = m_fib.findLongestPrefixMatch(interest.getSelectedDelegation());
NFD_LOG_TRACE("onContentStoreMiss hasSelectedDelegation=" << interest.getSelectedDelegation());
}
else {
// FIB lookup with first delegation Name
fibEntry = m_fib.findLongestPrefixMatch(link.getDelegations().begin()->second);
// in default-free zone?
bool isDefaultFreeZone = !(fibEntry->getPrefix().size() == 0 && fibEntry->hasNextHops());
if (isDefaultFreeZone) {
// choose and set SelectedDelegation
for (const std::pair<uint32_t, Name>& delegation : link.getDelegations()) {
const Name& delegationName = delegation.second;
fibEntry = m_fib.findLongestPrefixMatch(delegationName);
if (fibEntry->hasNextHops()) {
const_cast<Interest&>(interest).setSelectedDelegation(delegationName);
NFD_LOG_TRACE("onContentStoreMiss enterDefaultFreeZone"
<< " setSelectedDelegation=" << delegationName);
break;
}
}
}
else {
NFD_LOG_TRACE("onContentStoreMiss inConsumerRegion");
}
// has NextHopFaceId?
shared_ptr<lp::NextHopFaceIdTag> nextHopTag = interest.getTag<lp::NextHopFaceIdTag>();
if (nextHopTag != nullptr) {
// chosen NextHop face exists?
Face* nextHopFace = m_faceTable.get(*nextHopTag);
if (nextHopFace != nullptr) {
NFD_LOG_DEBUG("onContentStoreMiss interest=" << interest.getName() << " nexthop-faceid=" << nextHopFace->getId());
// go to outgoing Interest pipeline
// scope control is unnecessary, because privileged app explicitly wants to forward
this->onOutgoingInterest(pitEntry, *nextHopFace, interest);
}
return;
}
// dispatch to strategy
BOOST_ASSERT(fibEntry != nullptr);
this->dispatchToStrategy(pitEntry, bind(&Strategy::afterReceiveInterest, _1,
cref(inFace), cref(interest), fibEntry, pitEntry));
// dispatch to strategy: after incoming Interest
this->dispatchToStrategy(*pitEntry,
[&] (fw::Strategy& strategy) { strategy.afterReceiveInterest(inFace, interest, pitEntry); });
}
void
Forwarder::onContentStoreHit(const Face& inFace,
shared_ptr<pit::Entry> pitEntry,
const Interest& interest,
const Data& data)
Forwarder::onContentStoreHit(const Face& inFace, const shared_ptr<pit::Entry>& pitEntry,
const Interest& interest, const Data& data)
{
NFD_LOG_DEBUG("onContentStoreHit interest=" << interest.getName());
@@ -260,76 +241,24 @@ Forwarder::onContentStoreHit(const Face& inFace,
this->onOutgoingData(data, *const_pointer_cast<Face>(inFace.shared_from_this()));
}
/** \brief compare two InRecords for picking outgoing Interest
* \return true if b is preferred over a
*
* This function should be passed to std::max_element over InRecordCollection.
* The outgoing Interest picked is the last incoming Interest
* that does not come from outFace.
* If all InRecords come from outFace, it's fine to pick that. This happens when
* there's only one InRecord that comes from outFace. The legit use is for
* vehicular network; otherwise, strategy shouldn't send to the sole inFace.
*/
static inline bool
compare_pickInterest(const pit::InRecord& a, const pit::InRecord& b, const Face* outFace)
{
bool isOutFaceA = a.getFace().get() == outFace;
bool isOutFaceB = b.getFace().get() == outFace;
if (!isOutFaceA && isOutFaceB) {
return false;
}
if (isOutFaceA && !isOutFaceB) {
return true;
}
return a.getLastRenewed() > b.getLastRenewed();
}
void
Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace,
bool wantNewNonce)
Forwarder::onOutgoingInterest(const shared_ptr<pit::Entry>& pitEntry, Face& outFace, const Interest& interest)
{
if (outFace.getId() == face::INVALID_FACEID) {
NFD_LOG_WARN("onOutgoingInterest face=invalid interest=" << pitEntry->getName());
return;
}
NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
" interest=" << pitEntry->getName());
// scope control
if (pitEntry->violatesScope(outFace)) {
NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
" interest=" << pitEntry->getName() << " violates scope");
return;
}
// pick Interest
const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
pit::InRecordCollection::const_iterator pickedInRecord = std::max_element(
inRecords.begin(), inRecords.end(), bind(&compare_pickInterest, _1, _2, &outFace));
BOOST_ASSERT(pickedInRecord != inRecords.end());
shared_ptr<Interest> interest = const_pointer_cast<Interest>(
pickedInRecord->getInterest().shared_from_this());
if (wantNewNonce) {
interest = make_shared<Interest>(*interest);
static boost::random::uniform_int_distribution<uint32_t> dist;
interest->setNonce(dist(getGlobalRng()));
}
// insert OutRecord
pitEntry->insertOrUpdateOutRecord(outFace.shared_from_this(), *interest);
// insert out-record
pitEntry->insertOrUpdateOutRecord(outFace, interest);
// send Interest
outFace.sendInterest(*interest);
outFace.sendInterest(interest);
++m_counters.nOutInterests;
}
void
Forwarder::onInterestReject(shared_ptr<pit::Entry> pitEntry)
Forwarder::onInterestReject(const shared_ptr<pit::Entry>& pitEntry)
{
if (pitEntry->hasUnexpiredOutRecords()) {
if (fw::hasPendingOutRecords(*pitEntry)) {
NFD_LOG_ERROR("onInterestReject interest=" << pitEntry->getName() <<
" cannot reject forwarded Interest");
return;
@@ -337,28 +266,28 @@ Forwarder::onInterestReject(shared_ptr<pit::Entry> pitEntry)
NFD_LOG_DEBUG("onInterestReject interest=" << pitEntry->getName());
// cancel unsatisfy & straggler timer
this->cancelUnsatisfyAndStragglerTimer(pitEntry);
this->cancelUnsatisfyAndStragglerTimer(*pitEntry);
// set PIT straggler timer
this->setStragglerTimer(pitEntry, false);
}
void
Forwarder::onInterestUnsatisfied(shared_ptr<pit::Entry> pitEntry)
Forwarder::onInterestUnsatisfied(const shared_ptr<pit::Entry>& pitEntry)
{
NFD_LOG_DEBUG("onInterestUnsatisfied interest=" << pitEntry->getName());
// invoke PIT unsatisfied callback
this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeExpirePendingInterest, _1,
pitEntry));
this->dispatchToStrategy(*pitEntry,
[&] (fw::Strategy& strategy) { strategy.beforeExpirePendingInterest(pitEntry); });
// goto Interest Finalize pipeline
this->onInterestFinalize(pitEntry, false);
}
void
Forwarder::onInterestFinalize(shared_ptr<pit::Entry> pitEntry, bool isSatisfied,
const time::milliseconds& dataFreshnessPeriod)
Forwarder::onInterestFinalize(const shared_ptr<pit::Entry>& pitEntry, bool isSatisfied,
time::milliseconds dataFreshnessPeriod)
{
NFD_LOG_DEBUG("onInterestFinalize interest=" << pitEntry->getName() <<
(isSatisfied ? " satisfied" : " unsatisfied"));
@@ -367,8 +296,8 @@ Forwarder::onInterestFinalize(shared_ptr<pit::Entry> pitEntry, bool isSatisfied,
this->insertDeadNonceList(*pitEntry, isSatisfied, dataFreshnessPeriod, 0);
// PIT delete
this->cancelUnsatisfyAndStragglerTimer(pitEntry);
m_pit.erase(pitEntry);
this->cancelUnsatisfyAndStragglerTimer(*pitEntry);
m_pit.erase(pitEntry.get());
}
void
@@ -381,7 +310,7 @@ Forwarder::onIncomingData(Face& inFace, const Data& data)
// /localhost scope control
bool isViolatingLocalhost = inFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
LOCALHOST_NAME.isPrefixOf(data.getName());
scope_prefix::LOCALHOST.isPrefixOf(data.getName());
if (isViolatingLocalhost) {
NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() <<
" data=" << data.getName() << " violates /localhost");
@@ -402,29 +331,29 @@ Forwarder::onIncomingData(Face& inFace, const Data& data)
std::set<Face*> pendingDownstreams;
// foreach PitEntry
auto now = time::steady_clock::now();
for (const shared_ptr<pit::Entry>& pitEntry : pitMatches) {
NFD_LOG_DEBUG("onIncomingData matching=" << pitEntry->getName());
// cancel unsatisfy & straggler timer
this->cancelUnsatisfyAndStragglerTimer(pitEntry);
this->cancelUnsatisfyAndStragglerTimer(*pitEntry);
// remember pending downstreams
const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
for (const pit::InRecord& inRecord : inRecords) {
if (inRecord.getExpiry() > time::steady_clock::now()) {
pendingDownstreams.insert(inRecord.getFace().get());
for (const pit::InRecord& inRecord : pitEntry->getInRecords()) {
if (inRecord.getExpiry() > now) {
pendingDownstreams.insert(&inRecord.getFace());
}
}
// invoke PIT satisfy callback
this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeSatisfyInterest, _1,
pitEntry, cref(inFace), cref(data)));
this->dispatchToStrategy(*pitEntry,
[&] (fw::Strategy& strategy) { strategy.beforeSatisfyInterest(pitEntry, inFace, data); });
// Dead Nonce List insert if necessary (for OutRecord of inFace)
// Dead Nonce List insert if necessary (for out-record of inFace)
this->insertDeadNonceList(*pitEntry, true, data.getFreshnessPeriod(), &inFace);
// mark PIT satisfied
pitEntry->deleteInRecords();
pitEntry->clearInRecords();
pitEntry->deleteOutRecord(inFace);
// set PIT straggler timer
@@ -445,15 +374,15 @@ void
Forwarder::onDataUnsolicited(Face& inFace, const Data& data)
{
// accept to cache?
bool acceptToCache = inFace.getScope() == ndn::nfd::FACE_SCOPE_LOCAL;
if (acceptToCache) {
fw::UnsolicitedDataDecision decision = m_unsolicitedDataPolicy->decide(inFace, data);
if (decision == fw::UnsolicitedDataDecision::CACHE) {
// CS insert
m_cs.insert(data, true);
}
NFD_LOG_DEBUG("onDataUnsolicited face=" << inFace.getId() <<
" data=" << data.getName() <<
(acceptToCache ? " cached" : " not cached"));
" decision=" << decision);
}
void
@@ -467,7 +396,7 @@ Forwarder::onOutgoingData(const Data& data, Face& outFace)
// /localhost scope control
bool isViolatingLocalhost = outFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
LOCALHOST_NAME.isPrefixOf(data.getName());
scope_prefix::LOCALHOST.isPrefixOf(data.getName());
if (isViolatingLocalhost) {
NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() <<
" data=" << data.getName() << " violates /localhost");
@@ -510,7 +439,7 @@ Forwarder::onIncomingNack(Face& inFace, const lp::Nack& nack)
// has out-record?
pit::OutRecordCollection::iterator outRecord = pitEntry->getOutRecord(inFace);
// if no out-record found, drop
if (outRecord == pitEntry->getOutRecords().end()) {
if (outRecord == pitEntry->out_end()) {
NFD_LOG_DEBUG("onIncomingNack face=" << inFace.getId() <<
" nack=" << nack.getInterest().getName() <<
"~" << nack.getReason() << " no-out-record");
@@ -534,13 +463,12 @@ Forwarder::onIncomingNack(Face& inFace, const lp::Nack& nack)
outRecord->setIncomingNack(nack);
// trigger strategy: after receive NACK
shared_ptr<fib::Entry> fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
this->dispatchToStrategy(pitEntry, bind(&Strategy::afterReceiveNack, _1,
cref(inFace), cref(nack), fibEntry, pitEntry));
this->dispatchToStrategy(*pitEntry,
[&] (fw::Strategy& strategy) { strategy.afterReceiveNack(inFace, nack, pitEntry); });
}
void
Forwarder::onOutgoingNack(shared_ptr<pit::Entry> pitEntry, const Face& outFace,
Forwarder::onOutgoingNack(const shared_ptr<pit::Entry>& pitEntry, const Face& outFace,
const lp::NackHeader& nack)
{
if (outFace.getId() == face::INVALID_FACEID) {
@@ -551,10 +479,10 @@ Forwarder::onOutgoingNack(shared_ptr<pit::Entry> pitEntry, const Face& outFace,
}
// has in-record?
pit::InRecordCollection::const_iterator inRecord = pitEntry->getInRecord(outFace);
pit::InRecordCollection::iterator inRecord = pitEntry->getInRecord(outFace);
// if no in-record found, drop
if (inRecord == pitEntry->getInRecords().end()) {
if (inRecord == pitEntry->in_end()) {
NFD_LOG_DEBUG("onOutgoingNack face=" << outFace.getId() <<
" nack=" << pitEntry->getInterest().getName() <<
"~" << nack.getReason() << " no-in-record");
@@ -592,17 +520,15 @@ compare_InRecord_expiry(const pit::InRecord& a, const pit::InRecord& b)
}
void
Forwarder::setUnsatisfyTimer(shared_ptr<pit::Entry> pitEntry)
Forwarder::setUnsatisfyTimer(const shared_ptr<pit::Entry>& pitEntry)
{
const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
pit::InRecordCollection::const_iterator lastExpiring =
std::max_element(inRecords.begin(), inRecords.end(),
&compare_InRecord_expiry);
pit::InRecordCollection::iterator lastExpiring =
std::max_element(pitEntry->in_begin(), pitEntry->in_end(), &compare_InRecord_expiry);
time::steady_clock::TimePoint lastExpiry = lastExpiring->getExpiry();
time::nanoseconds lastExpiryFromNow = lastExpiry - time::steady_clock::now();
if (lastExpiryFromNow <= time::seconds(0)) {
// TODO all InRecords are already expired; will this happen?
time::nanoseconds lastExpiryFromNow = lastExpiry - time::steady_clock::now();
if (lastExpiryFromNow <= time::seconds::zero()) {
// TODO all in-records are already expired; will this happen?
}
scheduler::cancel(pitEntry->m_unsatisfyTimer);
@@ -611,8 +537,8 @@ Forwarder::setUnsatisfyTimer(shared_ptr<pit::Entry> pitEntry)
}
void
Forwarder::setStragglerTimer(shared_ptr<pit::Entry> pitEntry, bool isSatisfied,
const time::milliseconds& dataFreshnessPeriod)
Forwarder::setStragglerTimer(const shared_ptr<pit::Entry>& pitEntry, bool isSatisfied,
time::milliseconds dataFreshnessPeriod)
{
time::nanoseconds stragglerTime = time::milliseconds(100);
@@ -622,10 +548,10 @@ Forwarder::setStragglerTimer(shared_ptr<pit::Entry> pitEntry, bool isSatisfied,
}
void
Forwarder::cancelUnsatisfyAndStragglerTimer(shared_ptr<pit::Entry> pitEntry)
Forwarder::cancelUnsatisfyAndStragglerTimer(pit::Entry& pitEntry)
{
scheduler::cancel(pitEntry->m_unsatisfyTimer);
scheduler::cancel(pitEntry->m_stragglerTimer);
scheduler::cancel(pitEntry.m_unsatisfyTimer);
scheduler::cancel(pitEntry.m_stragglerTimer);
}
static inline void
@@ -637,8 +563,7 @@ insertNonceToDnl(DeadNonceList& dnl, const pit::Entry& pitEntry,
void
Forwarder::insertDeadNonceList(pit::Entry& pitEntry, bool isSatisfied,
const time::milliseconds& dataFreshnessPeriod,
Face* upstream)
time::milliseconds dataFreshnessPeriod, Face* upstream)
{
// need Dead Nonce List insert?
bool needDnl = false;
@@ -665,7 +590,7 @@ Forwarder::insertDeadNonceList(pit::Entry& pitEntry, bool isSatisfied,
}
else {
// insert outgoing Nonce of a specific face
pit::OutRecordCollection::const_iterator outRecord = pitEntry.getOutRecord(*upstream);
pit::OutRecordCollection::iterator outRecord = pitEntry.getOutRecord(*upstream);
if (outRecord != pitEntry.getOutRecords().end()) {
m_deadNonceList.add(pitEntry.getName(), outRecord->getLastNonce());
}
Loaded 100 of 426 files, more files were not shown because too many files have changed in this diff. Show more