From 0d97692b4008a338ea9be6d7f0ee0e09aa596b4d Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Sat, 1 Apr 2017 14:35:21 +0000 Subject: [PATCH] tools: nfdc face create command accepts local FaceUri refs #4017 Change-Id: I2d13403f13c30146c53744828ba2a37a6fab7de2 --- docs/manpages/nfdc-face.rst | 35 ++++++++++---- tests/tools/nfdc/face-module.t.cpp | 40 ++++++++++++++++ tools/nfdc/face-module.cpp | 73 ++++++++++++++++++++---------- 3 files changed, 117 insertions(+), 31 deletions(-) diff --git a/docs/manpages/nfdc-face.rst b/docs/manpages/nfdc-face.rst index f393a934..cfec8e27 100644 --- a/docs/manpages/nfdc-face.rst +++ b/docs/manpages/nfdc-face.rst @@ -3,9 +3,9 @@ nfdc-face SYNOPSIS -------- -| nfdc face [list] +| nfdc face [list [[remote] ] [local ] [scheme ]] | nfdc face show [id] -| nfdc face create [remote] [[persistency] ] +| nfdc face create [remote] [[persistency] ] [local ] | nfdc face destroy [face] | nfdc channel [list] @@ -16,11 +16,14 @@ It could be a physical network interface to communicate on a physical link, an overlay communication channel between NFD and a remote node, or an inter-process communication channel between NFD and a local application. -The **nfdc face list** command shows a list of faces, their properties, and statistics. +The **nfdc face list** command shows a list of faces, their properties, and statistics, +optionally filtered by remote endpoint, local endpoint, and FaceUri scheme. +When multiple filters are specified, returned faces must satisfy all filters. The **nfdc face show** command shows properties and statistics of one specific face. -The **nfdc face create** command creates a unicast UDP or TCP face. +The **nfdc face create** command creates a UDP unicast, TCP, or Ethernet unicast face. +Local FaceUri is required for creating Ethernet unicast faces; otherwise it must be omitted. The **nfdc face destroy** command destroys an existing face. @@ -34,14 +37,30 @@ OPTIONS It is displayed in the output of **nfdc face list** and **nfdc face create** commands. - An URI representing the remote endpoint of a face. - Its syntax is: + A URI representing the remote or local endpoint of a face. + Examples: - - udp[4|6]://[:] - - tcp[4|6]://[:] + - udp4://192.0.2.1:6363 + - udp6://[2001:db8::1]:6363 + - udp://example.net + - tcp4://192.0.2.1:6363 + - tcp6://[2001:db8::1]:6363 + - tcp://example.net + - unix:///var/run/nfd.sock + - fd://6 + - ether://[08:00:27:01:01:01] + - dev://eth0 When a hostname is specified, a DNS query is used to obtain the IP address. + + The scheme portion of either remote or local endpoint. + Examples: + + - udp4 + - unix + - dev + Either "persistent" or "permanent". A "persistent" face (the default) is closed when a socket error occurs. diff --git a/tests/tools/nfdc/face-module.t.cpp b/tests/tools/nfdc/face-module.t.cpp index bce68b78..de68fe60 100644 --- a/tests/tools/nfdc/face-module.t.cpp +++ b/tests/tools/nfdc/face-module.t.cpp @@ -247,6 +247,7 @@ BOOST_AUTO_TEST_CASE(Creating) ControlParameters req = MOCK_NFD_MGMT_REQUIRE_COMMAND_IS("/localhost/nfd/faces/create"); BOOST_REQUIRE(req.hasUri()); BOOST_CHECK_EQUAL(req.getUri(), "udp4://159.242.33.78:6363"); + BOOST_CHECK(!req.hasLocalUri()); BOOST_REQUIRE(req.hasFacePersistency()); BOOST_CHECK_EQUAL(req.getFacePersistency(), FacePersistency::FACE_PERSISTENCY_PERSISTENT); @@ -262,6 +263,29 @@ BOOST_AUTO_TEST_CASE(Creating) BOOST_CHECK(err.is_empty()); } +BOOST_AUTO_TEST_CASE(CreatingWithLocalUri) +{ + this->processInterest = [this] (const Interest& interest) { + ControlParameters req = MOCK_NFD_MGMT_REQUIRE_COMMAND_IS("/localhost/nfd/faces/create"); + BOOST_REQUIRE(req.hasUri()); + BOOST_CHECK_EQUAL(req.getUri(), "udp4://22.91.89.51:19903"); + BOOST_REQUIRE(req.hasLocalUri()); + BOOST_CHECK_EQUAL(req.getLocalUri(), "udp4://98.68.23.71:6363"); + BOOST_REQUIRE(req.hasFacePersistency()); + BOOST_CHECK_EQUAL(req.getFacePersistency(), FacePersistency::FACE_PERSISTENCY_PERMANENT); + + ControlParameters resp; + resp.setFaceId(301) + .setFacePersistency(FacePersistency::FACE_PERSISTENCY_PERMANENT); + this->succeedCommand(interest, resp); + }; + + this->execute("face create udp://22.91.89.51:19903 permanent local udp://98.68.23.71"); + BOOST_CHECK_EQUAL(exitCode, 0); + BOOST_CHECK(out.is_equal("face-created id=301 remote=udp4://22.91.89.51:19903 persistency=permanent\n")); + BOOST_CHECK(err.is_empty()); +} + BOOST_AUTO_TEST_CASE(UpgradingPersistency) { bool hasUpdateCommand = false; @@ -319,6 +343,22 @@ BOOST_AUTO_TEST_CASE(SamePersistency) BOOST_CHECK(err.is_empty()); } +BOOST_AUTO_TEST_CASE(ErrorCanonizeRemote) +{ + this->execute("face create invalid://"); + BOOST_CHECK_EQUAL(exitCode, 4); + BOOST_CHECK(out.is_empty()); + BOOST_CHECK(err.is_equal("Error when canonizing 'invalid://': scheme not supported\n")); +} + +BOOST_AUTO_TEST_CASE(ErrorCanonizeLocal) +{ + this->execute("face create udp4://24.37.20.47:6363 local invalid://"); + BOOST_CHECK_EQUAL(exitCode, 4); + BOOST_CHECK(out.is_empty()); + BOOST_CHECK(err.is_equal("Error when canonizing 'invalid://': scheme not supported\n")); +} + BOOST_AUTO_TEST_CASE(ErrorCreate) { this->processInterest = nullptr; // no response diff --git a/tools/nfdc/face-module.cpp b/tools/nfdc/face-module.cpp index f0c9dfc7..2ec37191 100644 --- a/tools/nfdc/face-module.cpp +++ b/tools/nfdc/face-module.cpp @@ -52,7 +52,8 @@ FaceModule::registerCommands(CommandParser& parser) defFaceCreate .setTitle("create a face") .addArg("remote", ArgValueType::FACE_URI, Required::YES, Positional::YES) - .addArg("persistency", ArgValueType::FACE_PERSISTENCY, Required::NO, Positional::YES); + .addArg("persistency", ArgValueType::FACE_PERSISTENCY, Required::NO, Positional::YES) + .addArg("local", ArgValueType::FACE_URI, Required::NO, Positional::NO); parser.addCommand(defFaceCreate, &FaceModule::create); CommandDefinition defFaceDestroy("face", "destroy"); @@ -147,23 +148,30 @@ persistencyLessThan(FacePersistency x, FacePersistency y) void FaceModule::create(ExecuteContext& ctx) { - auto faceUri = ctx.args.get("remote"); + auto remoteUri = ctx.args.get("remote"); + auto localUri = ctx.args.getOptional("local"); auto persistency = ctx.args.get("persistency", FacePersistency::FACE_PERSISTENCY_PERSISTENT); - FaceUri canonicalUri; + FaceUri canonicalRemote; + ndn::optional canonicalLocal; + + auto handleCanonizeError = [&] (const FaceUri& faceUri, const std::string& error) { + ctx.exitCode = 4; + ctx.err << "Error when canonizing '" << faceUri << "': " << error << '\n'; + }; auto printPositiveResult = [&] (const std::string& actionSummary, const ControlParameters& resp) { text::ItemAttributes ia; ctx.out << actionSummary << ' ' << ia("id") << resp.getFaceId() - << ia("remote") << canonicalUri + << ia("remote") << canonicalRemote << ia("persistency") << resp.getFacePersistency() << '\n'; - ///\todo #3956 display local=localUri before 'remote' field + ///\todo #3956 display local FaceUri before 'remote' field }; auto handle409 = [&] (const ControlResponse& resp) { ControlParameters respParams(resp.getBody()); - if (respParams.getUri() != canonicalUri.toString()) { + if (respParams.getUri() != canonicalRemote.toString()) { // we are conflicting with a different face, which is a general error return false; } @@ -183,24 +191,43 @@ FaceModule::create(ExecuteContext& ctx) return true; }; - faceUri.canonize( - [&] (const FaceUri& canonicalUri1) { - canonicalUri = canonicalUri1; - ctx.controller.start( - ControlParameters().setUri(canonicalUri.toString()).setFacePersistency(persistency), - bind(printPositiveResult, "face-created", _1), - [&] (const ControlResponse& resp) { - if (resp.getCode() == 409 && handle409(resp)) { - return; - } - ctx.makeCommandFailureHandler("creating face")(resp); // invoke general error handler - }, - ctx.makeCommandOptions()); - }, - [&] (const std::string& canonizeError) { - ctx.exitCode = 4; - ctx.err << "Error when canonizing FaceUri: " << canonizeError << '\n'; + auto doCreateFace = [&] { + ControlParameters params; + params.setUri(canonicalRemote.toString()); + if (canonicalLocal) { + params.setLocalUri(canonicalLocal->toString()); + } + params.setFacePersistency(persistency); + + ctx.controller.start( + params, + bind(printPositiveResult, "face-created", _1), + [&] (const ControlResponse& resp) { + if (resp.getCode() == 409 && handle409(resp)) { + return; + } + ctx.makeCommandFailureHandler("creating face")(resp); // invoke general error handler + }, + ctx.makeCommandOptions()); + }; + + remoteUri.canonize( + [&] (const FaceUri& canonicalUri) { + canonicalRemote = canonicalUri; + if (localUri) { + localUri->canonize( + [&] (const FaceUri& canonicalUri) { + canonicalLocal = canonicalUri; + doCreateFace(); + }, + bind(handleCanonizeError, *localUri, _1), + ctx.face.getIoService(), ctx.getTimeout()); + } + else { + doCreateFace(); + } }, + bind(handleCanonizeError, remoteUri, _1), ctx.face.getIoService(), ctx.getTimeout()); ctx.face.processEvents();