face-module.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2018, Regents of the University of California,
4  * Arizona Board of Regents,
5  * Colorado State University,
6  * University Pierre & Marie Curie, Sorbonne University,
7  * Washington University in St. Louis,
8  * Beijing Institute of Technology,
9  * The University of Memphis.
10  *
11  * This file is part of NFD (Named Data Networking Forwarding Daemon).
12  * See AUTHORS.md for complete list of NFD authors and contributors.
13  *
14  * NFD is free software: you can redistribute it and/or modify it under the terms
15  * of the GNU General Public License as published by the Free Software Foundation,
16  * either version 3 of the License, or (at your option) any later version.
17  *
18  * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20  * PURPOSE. See the GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along with
23  * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 #include "face-module.hpp"
27 #include "find-face.hpp"
28 
29 namespace nfd {
30 namespace tools {
31 namespace nfdc {
32 
33 void
35 {
36  CommandDefinition defFaceList("face", "list");
37  defFaceList
38  .setTitle("print face list")
42  parser.addCommand(defFaceList, &FaceModule::list);
43  parser.addAlias("face", "list", "");
44 
45  CommandDefinition defFaceShow("face", "show");
46  defFaceShow
47  .setTitle("show face information")
49  parser.addCommand(defFaceShow, &FaceModule::show);
50 
51  CommandDefinition defFaceCreate("face", "create");
52  defFaceCreate
53  .setTitle("create a face")
59  .addArg("congestion-marking-interval", ArgValueType::UNSIGNED, Required::NO, Positional::NO)
60  .addArg("default-congestion-threshold", ArgValueType::UNSIGNED, Required::NO, Positional::NO);
61  parser.addCommand(defFaceCreate, &FaceModule::create);
62 
63  CommandDefinition defFaceDestroy("face", "destroy");
64  defFaceDestroy
65  .setTitle("destroy a face")
67  parser.addCommand(defFaceDestroy, &FaceModule::destroy);
68 }
69 
70 void
72 {
73  auto remoteUri = ctx.args.getOptional<FaceUri>("remote");
74  auto localUri = ctx.args.getOptional<FaceUri>("local");
75  auto uriScheme = ctx.args.getOptional<std::string>("scheme");
76 
77  FaceQueryFilter filter;
78  if (remoteUri) {
79  filter.setRemoteUri(remoteUri->toString());
80  }
81  if (localUri) {
82  filter.setLocalUri(localUri->toString());
83  }
84  if (uriScheme) {
85  filter.setUriScheme(*uriScheme);
86  }
87 
88  FindFace findFace(ctx);
89  FindFace::Code res = findFace.execute(filter, true);
90 
91  ctx.exitCode = static_cast<int>(res);
92  switch (res) {
93  case FindFace::Code::OK:
94  for (const FaceStatus& item : findFace.getResults()) {
95  formatItemText(ctx.out, item, false);
96  ctx.out << '\n';
97  }
98  break;
102  ctx.err << findFace.getErrorReason() << '\n';
103  break;
104  default:
105  BOOST_ASSERT_MSG(false, "unexpected FindFace result");
106  break;
107  }
108 }
109 
110 void
112 {
113  uint64_t faceId = ctx.args.get<uint64_t>("id");
114 
115  FindFace findFace(ctx);
116  FindFace::Code res = findFace.execute(faceId);
117 
118  ctx.exitCode = static_cast<int>(res);
119  switch (res) {
120  case FindFace::Code::OK:
121  formatItemText(ctx.out, findFace.getFaceStatus(), true);
122  break;
125  ctx.err << findFace.getErrorReason() << '\n';
126  break;
127  default:
128  BOOST_ASSERT_MSG(false, "unexpected FindFace result");
129  break;
130  }
131 }
132 
135 static bool
136 persistencyLessThan(FacePersistency x, FacePersistency y)
137 {
138  switch (x) {
139  case FacePersistency::FACE_PERSISTENCY_NONE:
140  return y != FacePersistency::FACE_PERSISTENCY_NONE;
141  case FacePersistency::FACE_PERSISTENCY_ON_DEMAND:
142  return y == FacePersistency::FACE_PERSISTENCY_PERSISTENT ||
143  y == FacePersistency::FACE_PERSISTENCY_PERMANENT;
144  case FacePersistency::FACE_PERSISTENCY_PERSISTENT:
145  return y == FacePersistency::FACE_PERSISTENCY_PERMANENT;
146  case FacePersistency::FACE_PERSISTENCY_PERMANENT:
147  return false;
148  }
149  return static_cast<int>(x) < static_cast<int>(y);
150 }
151 
152 void
154 {
155  auto remoteUri = ctx.args.get<FaceUri>("remote");
156  auto localUri = ctx.args.getOptional<FaceUri>("local");
157  auto persistency = ctx.args.get<FacePersistency>("persistency", FacePersistency::FACE_PERSISTENCY_PERSISTENT);
158  auto lpReliability = ctx.args.getTribool("reliability");
159  auto congestionMarking = ctx.args.getTribool("congestion-marking");
160  auto baseCongestionMarkingIntervalMs = ctx.args.getOptional<uint64_t>("congestion-marking-interval");
161  auto defaultCongestionThreshold = ctx.args.getOptional<uint64_t>("default-congestion-threshold");
162 
163  FaceUri canonicalRemote;
164  optional<FaceUri> canonicalLocal;
165 
166  auto handleCanonizeError = [&] (const FaceUri& faceUri, const std::string& error) {
167  ctx.exitCode = 4;
168  ctx.err << "Error when canonizing '" << faceUri << "': " << error << '\n';
169  };
170 
171  auto printPositiveResult = [&] (const std::string& actionSummary, const ControlParameters& resp) {
173  ctx.out << actionSummary << ' '
174  << ia("id") << resp.getFaceId()
175  << ia("local") << resp.getLocalUri()
176  << ia("remote") << resp.getUri()
177  << ia("persistency") << resp.getFacePersistency();
178  printFaceParams(ctx.out, ia, resp);
179  };
180 
181  auto updateFace = [&printPositiveResult] (ControlParameters respParams, ControlParameters resp) {
182  // faces/update response does not have FaceUris, copy from faces/create response
183  resp.setLocalUri(respParams.getLocalUri())
184  .setUri(respParams.getUri());
185  printPositiveResult("face-updated", resp);
186  };
187 
188  auto handle409 = [&] (const ControlResponse& resp) {
189  ControlParameters respParams(resp.getBody());
190  if (respParams.getUri() != canonicalRemote.toString()) {
191  // we are conflicting with a different face, which is a general error
192  return false;
193  }
194 
195  if (persistencyLessThan(respParams.getFacePersistency(), persistency)) {
196  // need to upgrade persistency
197  ControlParameters params;
198  params.setFaceId(respParams.getFaceId()).setFacePersistency(persistency);
199  if (!boost::logic::indeterminate(lpReliability)) {
200  params.setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED, lpReliability);
201  }
202  ctx.controller.start<ndn::nfd::FaceUpdateCommand>(
203  params,
204  bind(updateFace, respParams, _1),
205  ctx.makeCommandFailureHandler("upgrading face persistency"),
206  ctx.makeCommandOptions());
207  }
208  else if ((!boost::logic::indeterminate(lpReliability) &&
209  lpReliability != respParams.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)) ||
210  (!boost::logic::indeterminate(congestionMarking) &&
211  congestionMarking != respParams.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)) ||
212  baseCongestionMarkingIntervalMs ||
213  defaultCongestionThreshold) {
214  ControlParameters params;
215  params.setFaceId(respParams.getFaceId());
216 
217  if (!boost::logic::indeterminate(lpReliability) &&
218  lpReliability != respParams.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)) {
219  params.setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED, lpReliability);
220  }
221  if (!boost::logic::indeterminate(congestionMarking) &&
222  congestionMarking != respParams.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)) {
223  params.setFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED, congestionMarking);
224  }
225 
226  if (baseCongestionMarkingIntervalMs) {
227  params.setBaseCongestionMarkingInterval(time::milliseconds(*baseCongestionMarkingIntervalMs));
228  }
229 
230  if (defaultCongestionThreshold) {
231  params.setDefaultCongestionThreshold(*defaultCongestionThreshold);
232  }
233 
234  ctx.controller.start<ndn::nfd::FaceUpdateCommand>(
235  params,
236  bind(updateFace, respParams, _1),
237  ctx.makeCommandFailureHandler("updating face"),
238  ctx.makeCommandOptions());
239  }
240  else {
241  // don't do anything
242  printPositiveResult("face-exists", respParams);
243  }
244  return true;
245  };
246 
247  auto doCreateFace = [&] {
248  ControlParameters params;
249  params.setUri(canonicalRemote.toString());
250  if (canonicalLocal) {
251  params.setLocalUri(canonicalLocal->toString());
252  }
253  params.setFacePersistency(persistency);
254  if (!boost::logic::indeterminate(lpReliability)) {
255  params.setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED, lpReliability);
256  }
257  if (!boost::logic::indeterminate(congestionMarking)) {
258  params.setFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED, congestionMarking);
259  }
260  if (baseCongestionMarkingIntervalMs) {
261  params.setBaseCongestionMarkingInterval(time::milliseconds(*baseCongestionMarkingIntervalMs));
262  }
263  if (defaultCongestionThreshold) {
264  params.setDefaultCongestionThreshold(*defaultCongestionThreshold);
265  }
266 
267  ctx.controller.start<ndn::nfd::FaceCreateCommand>(
268  params,
269  bind(printPositiveResult, "face-created", _1),
270  [&] (const ControlResponse& resp) {
271  if (resp.getCode() == 409 && handle409(resp)) {
272  return;
273  }
274  ctx.makeCommandFailureHandler("creating face")(resp); // invoke general error handler
275  },
276  ctx.makeCommandOptions());
277  };
278 
279  remoteUri.canonize(
280  [&] (const FaceUri& canonicalUri) {
281  canonicalRemote = canonicalUri;
282  if (localUri) {
283  localUri->canonize(
284  [&] (const FaceUri& canonicalUri) {
285  canonicalLocal = canonicalUri;
286  doCreateFace();
287  },
288  bind(handleCanonizeError, *localUri, _1),
289  ctx.face.getIoService(), ctx.getTimeout());
290  }
291  else {
292  doCreateFace();
293  }
294  },
295  bind(handleCanonizeError, remoteUri, _1),
296  ctx.face.getIoService(), ctx.getTimeout());
297 
298  ctx.face.processEvents();
299 }
300 
301 void
303 {
304  const boost::any& faceIdOrUri = ctx.args.at("face");
305 
306  FindFace findFace(ctx);
307  FindFace::Code res = findFace.execute(faceIdOrUri);
308 
309  ctx.exitCode = static_cast<int>(res);
310  switch (res) {
311  case FindFace::Code::OK:
312  break;
316  ctx.err << findFace.getErrorReason() << '\n';
317  return;
319  ctx.err << "Multiple faces match specified remote FaceUri. Re-run the command with a FaceId:";
321  ctx.err << '\n';
322  return;
323  default:
324  BOOST_ASSERT_MSG(false, "unexpected FindFace result");
325  return;
326  }
327 
328  const FaceStatus& face = findFace.getFaceStatus();
329 
330  ctx.controller.start<ndn::nfd::FaceDestroyCommand>(
331  ControlParameters().setFaceId(face.getFaceId()),
332  [&] (const ControlParameters& resp) {
333  ctx.out << "face-destroyed ";
335  ctx.out << ia("id") << face.getFaceId()
336  << ia("local") << face.getLocalUri()
337  << ia("remote") << face.getRemoteUri()
338  << ia("persistency") << face.getFacePersistency();
339  printFaceParams(ctx.out, ia, resp);
340  },
341  ctx.makeCommandFailureHandler("destroying face"),
342  ctx.makeCommandOptions());
343 
344  ctx.face.processEvents();
345 }
346 
347 void
348 FaceModule::fetchStatus(Controller& controller,
349  const std::function<void()>& onSuccess,
350  const Controller::DatasetFailCallback& onFailure,
351  const CommandOptions& options)
352 {
353  controller.fetch<ndn::nfd::FaceDataset>(
354  [this, onSuccess] (const std::vector<FaceStatus>& result) {
355  m_status = result;
356  onSuccess();
357  },
358  onFailure, options);
359 }
360 
361 void
362 FaceModule::formatStatusXml(std::ostream& os) const
363 {
364  os << "<faces>";
365  for (const FaceStatus& item : m_status) {
366  this->formatItemXml(os, item);
367  }
368  os << "</faces>";
369 }
370 
371 void
372 FaceModule::formatItemXml(std::ostream& os, const FaceStatus& item) const
373 {
374  os << "<face>";
375 
376  os << "<faceId>" << item.getFaceId() << "</faceId>";
377  os << "<remoteUri>" << xml::Text{item.getRemoteUri()} << "</remoteUri>";
378  os << "<localUri>" << xml::Text{item.getLocalUri()} << "</localUri>";
379 
380  if (item.hasExpirationPeriod()) {
381  os << "<expirationPeriod>" << xml::formatDuration(item.getExpirationPeriod())
382  << "</expirationPeriod>";
383  }
384  os << "<faceScope>" << item.getFaceScope() << "</faceScope>";
385  os << "<facePersistency>" << item.getFacePersistency() << "</facePersistency>";
386  os << "<linkType>" << item.getLinkType() << "</linkType>";
387 
388  if (!item.hasBaseCongestionMarkingInterval() && !item.hasDefaultCongestionThreshold()) {
389  os << "<congestion/>";
390  }
391  else {
392  os << "<congestion>";
393  if (item.hasBaseCongestionMarkingInterval()) {
394  os << "<baseMarkingInterval>" << xml::formatDuration(item.getBaseCongestionMarkingInterval())
395  << "</baseMarkingInterval>";
396  }
397  if (item.hasDefaultCongestionThreshold()) {
398  os << "<defaultThreshold>" << item.getDefaultCongestionThreshold() << "</defaultThreshold>";
399  }
400  os << "</congestion>";
401  }
402 
403  if (item.getFlags() == 0) {
404  os << "<flags/>";
405  }
406  else {
407  os << "<flags>";
408  os << xml::Flag{"localFieldsEnabled", item.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED)};
409  os << xml::Flag{"lpReliabilityEnabled", item.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)};
410  os << xml::Flag{"congestionMarkingEnabled", item.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)};
411  os << "</flags>";
412  }
413 
414  os << "<packetCounters>";
415  os << "<incomingPackets>"
416  << "<nInterests>" << item.getNInInterests() << "</nInterests>"
417  << "<nData>" << item.getNInData() << "</nData>"
418  << "<nNacks>" << item.getNInNacks() << "</nNacks>"
419  << "</incomingPackets>";
420  os << "<outgoingPackets>"
421  << "<nInterests>" << item.getNOutInterests() << "</nInterests>"
422  << "<nData>" << item.getNOutData() << "</nData>"
423  << "<nNacks>" << item.getNOutNacks() << "</nNacks>"
424  << "</outgoingPackets>";
425  os << "</packetCounters>";
426 
427  os << "<byteCounters>";
428  os << "<incomingBytes>" << item.getNInBytes() << "</incomingBytes>";
429  os << "<outgoingBytes>" << item.getNOutBytes() << "</outgoingBytes>";
430  os << "</byteCounters>";
431 
432  os << "</face>";
433 }
434 
435 void
436 FaceModule::formatStatusText(std::ostream& os) const
437 {
438  os << "Faces:\n";
439  for (const FaceStatus& item : m_status) {
440  os << " ";
441  formatItemText(os, item, false);
442  os << '\n';
443  }
444 }
445 
446 void
447 FaceModule::formatItemText(std::ostream& os, const FaceStatus& item, bool wantMultiLine)
448 {
449  text::ItemAttributes ia(wantMultiLine, 10);
450 
451  os << ia("faceid") << item.getFaceId();
452  os << ia("remote") << item.getRemoteUri();
453  os << ia("local") << item.getLocalUri();
454 
455  if (item.hasExpirationPeriod()) {
456  os << ia("expires") << text::formatDuration<time::seconds>(item.getExpirationPeriod());
457  }
458 
459  if (item.hasBaseCongestionMarkingInterval() || item.hasDefaultCongestionThreshold()) {
460  os << ia("congestion") << "{";
461  text::Separator congestionSep("", " ");
462  if (item.hasBaseCongestionMarkingInterval()) {
463  os << congestionSep << "base-marking-interval="
464  << text::formatDuration<time::milliseconds>(item.getBaseCongestionMarkingInterval());
465  }
466  if (item.hasDefaultCongestionThreshold()) {
467  os << congestionSep << "default-threshold=" << item.getDefaultCongestionThreshold() << "B";
468  }
469  os << "}";
470  }
471 
472  os << ia("counters")
473  << "{in={"
474  << item.getNInInterests() << "i "
475  << item.getNInData() << "d "
476  << item.getNInNacks() << "n "
477  << item.getNInBytes() << "B} "
478  << "out={"
479  << item.getNOutInterests() << "i "
480  << item.getNOutData() << "d "
481  << item.getNOutNacks() << "n "
482  << item.getNOutBytes() << "B}}";
483 
484  os << ia("flags") << '{';
485  text::Separator flagSep("", " ");
486  os << flagSep << item.getFaceScope();
487  os << flagSep << item.getFacePersistency();
488  os << flagSep << item.getLinkType();
489  if (item.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED)) {
490  os << flagSep << "local-fields";
491  }
492  if (item.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)) {
493  os << flagSep << "lp-reliability";
494  }
495  if (item.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)) {
496  os << flagSep << "congestion-marking";
497  }
498  os << '}';
499 
500  os << ia.end();
501 }
502 
503 void
504 FaceModule::printFaceParams(std::ostream& os, text::ItemAttributes& ia, const ControlParameters& resp)
505 {
506  os << ia("reliability") << text::OnOff{resp.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)}
507  << ia("congestion-marking") << text::OnOff{resp.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)};
508  if (resp.hasBaseCongestionMarkingInterval()) {
509  os << ia("congestion-marking-interval")
510  << text::formatDuration<time::milliseconds>(resp.getBaseCongestionMarkingInterval());
511  }
512  if (resp.hasDefaultCongestionThreshold()) {
513  os << ia("default-congestion-threshold") << resp.getDefaultCongestionThreshold() << "B";
514  }
515  os << '\n';
516 }
517 
518 } // namespace nfdc
519 } // namespace tools
520 } // namespace nfd
const CommandArguments & args
void formatStatusText(std::ostream &os) const override
format collected status as text
std::string formatDuration(time::nanoseconds d)
ndn::nfd::CommandOptions makeCommandOptions() const
Controller::CommandFailCallback makeCommandFailureHandler(const std::string &commandName)
declares semantics of a command
std::ostream & out
output stream
context for command execution
void formatStatusXml(std::ostream &os) const override
format collected status as XML
time::nanoseconds getTimeout() const
static void printFaceParams(std::ostream &os, text::ItemAttributes &ia, const ControlParameters &resp)
print face response parameters to specified ostream
T get(const std::string &key, const T &defaultValue=T()) const
found exactly one face, or found multiple faces when allowMulti is true
error during FaceUri canonization
static bool persistencyLessThan(FacePersistency x, FacePersistency y)
order persistency in NONE < ON_DEMAND < PERSISTENCY < PERMANENT
CommandDefinition & setTitle(const std::string &title)
set one-line description
print true as an empty element and false as nothing
found multiple faces and allowMulti is false
static void create(ExecuteContext &ctx)
the &#39;face create&#39; command
void printDisambiguation(std::ostream &os, DisambiguationStyle style) const
print results for disambiguation
Definition: find-face.cpp:170
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
Definition: algorithm.hpp:32
procedure to find a face
Definition: find-face.hpp:40
face persistency &#39;persistent&#39; or &#39;permanent&#39;
Code execute(const FaceUri &faceUri, bool allowMulti=false)
find face by FaceUri
Definition: find-face.cpp:43
static void registerCommands(CommandParser &parser)
register &#39;face list&#39;, &#39;face show&#39;, &#39;face create&#39;, &#39;face destroy&#39; commands
Definition: face-module.cpp:34
CommandDefinition & addArg(const std::string &name, ArgValueType valueType, Required isRequired=Required::NO, Positional allowPositional=Positional::NO, const std::string &metavar="")
declare an argument
print attributes of an item
argument is required
static void show(ExecuteContext &ctx)
the &#39;face show&#39; command
void formatItemXml(std::ostream &os, const FaceStatus &item) const
format a single status item as XML
optional< T > getOptional(const std::string &key) const
std::ostream & err
error stream
const FaceStatus & getFaceStatus() const
Definition: find-face.cpp:163
CommandParser & addCommand(const CommandDefinition &def, const ExecuteCommand &execute, std::underlying_type< AvailableIn >::type modes=AVAILABLE_IN_ALL)
add an available command
boost::logic::tribool getTribool(const std::string &key) const
get an optional boolean argument as tribool
static void formatItemText(std::ostream &os, const FaceStatus &item, bool wantMultiLine)
format a single status item as text
static void list(ExecuteContext &ctx)
the &#39;face list&#39; command
Definition: face-module.cpp:71
argument is optional
static void destroy(ExecuteContext &ctx)
the &#39;face destroy&#39; command
void fetchStatus(Controller &controller, const std::function< void()> &onSuccess, const Controller::DatasetFailCallback &onFailure, const CommandOptions &options) override
collect status from NFD
const std::string & getErrorReason() const
Definition: find-face.hpp:113
CommandParser & addAlias(const std::string &noun, const std::string &verb, const std::string &verb2)
add an alias "noun verb2" to existing command "noun verb"
const std::vector< FaceStatus > & getResults() const
Definition: find-face.hpp:90
print different string on first and subsequent usage
print boolean as &#39;on&#39; or &#39;off&#39;