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)
62  parser.addCommand(defFaceCreate, &FaceModule::create);
63 
64  CommandDefinition defFaceDestroy("face", "destroy");
65  defFaceDestroy
66  .setTitle("destroy a face")
68  parser.addCommand(defFaceDestroy, &FaceModule::destroy);
69 }
70 
71 void
73 {
74  auto remoteUri = ctx.args.getOptional<FaceUri>("remote");
75  auto localUri = ctx.args.getOptional<FaceUri>("local");
76  auto uriScheme = ctx.args.getOptional<std::string>("scheme");
77 
78  FaceQueryFilter filter;
79  if (remoteUri) {
80  filter.setRemoteUri(remoteUri->toString());
81  }
82  if (localUri) {
83  filter.setLocalUri(localUri->toString());
84  }
85  if (uriScheme) {
86  filter.setUriScheme(*uriScheme);
87  }
88 
89  FindFace findFace(ctx);
90  FindFace::Code res = findFace.execute(filter, true);
91 
92  ctx.exitCode = static_cast<int>(res);
93  switch (res) {
94  case FindFace::Code::OK:
95  for (const FaceStatus& item : findFace.getResults()) {
96  formatItemText(ctx.out, item, false);
97  ctx.out << '\n';
98  }
99  break;
103  ctx.err << findFace.getErrorReason() << '\n';
104  break;
105  default:
106  BOOST_ASSERT_MSG(false, "unexpected FindFace result");
107  break;
108  }
109 }
110 
111 void
113 {
114  uint64_t faceId = ctx.args.get<uint64_t>("id");
115 
116  FindFace findFace(ctx);
117  FindFace::Code res = findFace.execute(faceId);
118 
119  ctx.exitCode = static_cast<int>(res);
120  switch (res) {
121  case FindFace::Code::OK:
122  formatItemText(ctx.out, findFace.getFaceStatus(), true);
123  break;
126  ctx.err << findFace.getErrorReason() << '\n';
127  break;
128  default:
129  BOOST_ASSERT_MSG(false, "unexpected FindFace result");
130  break;
131  }
132 }
133 
136 static bool
137 persistencyLessThan(FacePersistency x, FacePersistency y)
138 {
139  switch (x) {
140  case FacePersistency::FACE_PERSISTENCY_NONE:
141  return y != FacePersistency::FACE_PERSISTENCY_NONE;
142  case FacePersistency::FACE_PERSISTENCY_ON_DEMAND:
143  return y == FacePersistency::FACE_PERSISTENCY_PERSISTENT ||
144  y == FacePersistency::FACE_PERSISTENCY_PERMANENT;
145  case FacePersistency::FACE_PERSISTENCY_PERSISTENT:
146  return y == FacePersistency::FACE_PERSISTENCY_PERMANENT;
147  case FacePersistency::FACE_PERSISTENCY_PERMANENT:
148  return false;
149  }
150  return static_cast<int>(x) < static_cast<int>(y);
151 }
152 
153 void
155 {
156  auto remoteUri = ctx.args.get<FaceUri>("remote");
157  auto localUri = ctx.args.getOptional<FaceUri>("local");
158  auto persistency = ctx.args.get<FacePersistency>("persistency", FacePersistency::FACE_PERSISTENCY_PERSISTENT);
159  auto lpReliability = ctx.args.getTribool("reliability");
160  auto congestionMarking = ctx.args.getTribool("congestion-marking");
161  auto baseCongestionMarkingIntervalMs = ctx.args.getOptional<uint64_t>("congestion-marking-interval");
162  auto defaultCongestionThreshold = ctx.args.getOptional<uint64_t>("default-congestion-threshold");
163  auto mtu = ctx.args.getOptional<uint64_t>("mtu");
164 
165  FaceUri canonicalRemote;
166  optional<FaceUri> canonicalLocal;
167 
168  auto handleCanonizeError = [&] (const FaceUri& faceUri, const std::string& error) {
169  ctx.exitCode = 4;
170  ctx.err << "Error when canonizing '" << faceUri << "': " << error << '\n';
171  };
172 
173  auto printPositiveResult = [&] (const std::string& actionSummary, const ControlParameters& resp) {
175  ctx.out << actionSummary << ' '
176  << ia("id") << resp.getFaceId()
177  << ia("local") << resp.getLocalUri()
178  << ia("remote") << resp.getUri()
179  << ia("persistency") << resp.getFacePersistency();
180  printFaceParams(ctx.out, ia, resp);
181  };
182 
183  auto updateFace = [&printPositiveResult] (ControlParameters respParams, ControlParameters resp) {
184  // faces/update response does not have FaceUris, copy from faces/create response
185  resp.setLocalUri(respParams.getLocalUri())
186  .setUri(respParams.getUri());
187  printPositiveResult("face-updated", resp);
188  };
189 
190  auto handle409 = [&] (const ControlResponse& resp) {
191  ControlParameters respParams(resp.getBody());
192  if (respParams.getUri() != canonicalRemote.toString()) {
193  // we are conflicting with a different face, which is a general error
194  return false;
195  }
196 
197  if (mtu && (!respParams.hasMtu() || respParams.getMtu() != *mtu)) {
198  // Mtu cannot be changed with faces/update
199  return false;
200  }
201  else if (persistencyLessThan(respParams.getFacePersistency(), persistency)) {
202  // need to upgrade persistency
203  ControlParameters params;
204  params.setFaceId(respParams.getFaceId()).setFacePersistency(persistency);
205  if (!boost::logic::indeterminate(lpReliability)) {
206  params.setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED, lpReliability);
207  }
208  ctx.controller.start<ndn::nfd::FaceUpdateCommand>(
209  params,
210  bind(updateFace, respParams, _1),
211  ctx.makeCommandFailureHandler("upgrading face persistency"),
212  ctx.makeCommandOptions());
213  }
214  else if ((!boost::logic::indeterminate(lpReliability) &&
215  lpReliability != respParams.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)) ||
216  (!boost::logic::indeterminate(congestionMarking) &&
217  congestionMarking != respParams.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)) ||
218  baseCongestionMarkingIntervalMs ||
219  defaultCongestionThreshold) {
220  ControlParameters params;
221  params.setFaceId(respParams.getFaceId());
222 
223  if (!boost::logic::indeterminate(lpReliability) &&
224  lpReliability != respParams.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)) {
225  params.setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED, lpReliability);
226  }
227  if (!boost::logic::indeterminate(congestionMarking) &&
228  congestionMarking != respParams.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)) {
229  params.setFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED, congestionMarking);
230  }
231 
232  if (baseCongestionMarkingIntervalMs) {
233  params.setBaseCongestionMarkingInterval(time::milliseconds(*baseCongestionMarkingIntervalMs));
234  }
235 
236  if (defaultCongestionThreshold) {
237  params.setDefaultCongestionThreshold(*defaultCongestionThreshold);
238  }
239 
240  ctx.controller.start<ndn::nfd::FaceUpdateCommand>(
241  params,
242  bind(updateFace, respParams, _1),
243  ctx.makeCommandFailureHandler("updating face"),
244  ctx.makeCommandOptions());
245  }
246  else {
247  // don't do anything
248  printPositiveResult("face-exists", respParams);
249  }
250  return true;
251  };
252 
253  auto doCreateFace = [&] {
254  ControlParameters params;
255  params.setUri(canonicalRemote.toString());
256  if (canonicalLocal) {
257  params.setLocalUri(canonicalLocal->toString());
258  }
259  params.setFacePersistency(persistency);
260  if (!boost::logic::indeterminate(lpReliability)) {
261  params.setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED, lpReliability);
262  }
263  if (!boost::logic::indeterminate(congestionMarking)) {
264  params.setFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED, congestionMarking);
265  }
266  if (baseCongestionMarkingIntervalMs) {
267  params.setBaseCongestionMarkingInterval(time::milliseconds(*baseCongestionMarkingIntervalMs));
268  }
269  if (defaultCongestionThreshold) {
270  params.setDefaultCongestionThreshold(*defaultCongestionThreshold);
271  }
272  if (mtu) {
273  params.setMtu(*mtu);
274  }
275 
276  ctx.controller.start<ndn::nfd::FaceCreateCommand>(
277  params,
278  bind(printPositiveResult, "face-created", _1),
279  [&] (const ControlResponse& resp) {
280  if (resp.getCode() == 409 && handle409(resp)) {
281  return;
282  }
283  ctx.makeCommandFailureHandler("creating face")(resp); // invoke general error handler
284  },
285  ctx.makeCommandOptions());
286  };
287 
288  remoteUri.canonize(
289  [&] (const FaceUri& canonicalUri) {
290  canonicalRemote = canonicalUri;
291  if (localUri) {
292  localUri->canonize(
293  [&] (const FaceUri& canonicalUri) {
294  canonicalLocal = canonicalUri;
295  doCreateFace();
296  },
297  bind(handleCanonizeError, *localUri, _1),
298  ctx.face.getIoService(), ctx.getTimeout());
299  }
300  else {
301  doCreateFace();
302  }
303  },
304  bind(handleCanonizeError, remoteUri, _1),
305  ctx.face.getIoService(), ctx.getTimeout());
306 
307  ctx.face.processEvents();
308 }
309 
310 void
312 {
313  const boost::any& faceIdOrUri = ctx.args.at("face");
314 
315  FindFace findFace(ctx);
316  FindFace::Code res = findFace.execute(faceIdOrUri);
317 
318  ctx.exitCode = static_cast<int>(res);
319  switch (res) {
320  case FindFace::Code::OK:
321  break;
325  ctx.err << findFace.getErrorReason() << '\n';
326  return;
328  ctx.err << "Multiple faces match specified remote FaceUri. Re-run the command with a FaceId:";
330  ctx.err << '\n';
331  return;
332  default:
333  BOOST_ASSERT_MSG(false, "unexpected FindFace result");
334  return;
335  }
336 
337  const FaceStatus& face = findFace.getFaceStatus();
338 
339  ctx.controller.start<ndn::nfd::FaceDestroyCommand>(
340  ControlParameters().setFaceId(face.getFaceId()),
341  [&] (const ControlParameters& resp) {
342  ctx.out << "face-destroyed ";
344  ctx.out << ia("id") << face.getFaceId()
345  << ia("local") << face.getLocalUri()
346  << ia("remote") << face.getRemoteUri()
347  << ia("persistency") << face.getFacePersistency();
348  printFaceParams(ctx.out, ia, resp);
349  },
350  ctx.makeCommandFailureHandler("destroying face"),
351  ctx.makeCommandOptions());
352 
353  ctx.face.processEvents();
354 }
355 
356 void
357 FaceModule::fetchStatus(Controller& controller,
358  const std::function<void()>& onSuccess,
359  const Controller::DatasetFailCallback& onFailure,
360  const CommandOptions& options)
361 {
362  controller.fetch<ndn::nfd::FaceDataset>(
363  [this, onSuccess] (const std::vector<FaceStatus>& result) {
364  m_status = result;
365  onSuccess();
366  },
367  onFailure, options);
368 }
369 
370 void
371 FaceModule::formatStatusXml(std::ostream& os) const
372 {
373  os << "<faces>";
374  for (const FaceStatus& item : m_status) {
375  this->formatItemXml(os, item);
376  }
377  os << "</faces>";
378 }
379 
380 void
381 FaceModule::formatItemXml(std::ostream& os, const FaceStatus& item) const
382 {
383  os << "<face>";
384 
385  os << "<faceId>" << item.getFaceId() << "</faceId>";
386  os << "<remoteUri>" << xml::Text{item.getRemoteUri()} << "</remoteUri>";
387  os << "<localUri>" << xml::Text{item.getLocalUri()} << "</localUri>";
388 
389  if (item.hasExpirationPeriod()) {
390  os << "<expirationPeriod>" << xml::formatDuration(item.getExpirationPeriod())
391  << "</expirationPeriod>";
392  }
393  os << "<faceScope>" << item.getFaceScope() << "</faceScope>";
394  os << "<facePersistency>" << item.getFacePersistency() << "</facePersistency>";
395  os << "<linkType>" << item.getLinkType() << "</linkType>";
396 
397  if (!item.hasBaseCongestionMarkingInterval() && !item.hasDefaultCongestionThreshold()) {
398  os << "<congestion/>";
399  }
400  else {
401  os << "<congestion>";
402  if (item.hasBaseCongestionMarkingInterval()) {
403  os << "<baseMarkingInterval>" << xml::formatDuration(item.getBaseCongestionMarkingInterval())
404  << "</baseMarkingInterval>";
405  }
406  if (item.hasDefaultCongestionThreshold()) {
407  os << "<defaultThreshold>" << item.getDefaultCongestionThreshold() << "</defaultThreshold>";
408  }
409  os << "</congestion>";
410  }
411 
412  if (item.hasMtu()) {
413  os << "<mtu>" << item.getMtu() << "</mtu>";
414  }
415 
416  if (item.getFlags() == 0) {
417  os << "<flags/>";
418  }
419  else {
420  os << "<flags>";
421  os << xml::Flag{"localFieldsEnabled", item.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED)};
422  os << xml::Flag{"lpReliabilityEnabled", item.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)};
423  os << xml::Flag{"congestionMarkingEnabled", item.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)};
424  os << "</flags>";
425  }
426 
427  os << "<packetCounters>";
428  os << "<incomingPackets>"
429  << "<nInterests>" << item.getNInInterests() << "</nInterests>"
430  << "<nData>" << item.getNInData() << "</nData>"
431  << "<nNacks>" << item.getNInNacks() << "</nNacks>"
432  << "</incomingPackets>";
433  os << "<outgoingPackets>"
434  << "<nInterests>" << item.getNOutInterests() << "</nInterests>"
435  << "<nData>" << item.getNOutData() << "</nData>"
436  << "<nNacks>" << item.getNOutNacks() << "</nNacks>"
437  << "</outgoingPackets>";
438  os << "</packetCounters>";
439 
440  os << "<byteCounters>";
441  os << "<incomingBytes>" << item.getNInBytes() << "</incomingBytes>";
442  os << "<outgoingBytes>" << item.getNOutBytes() << "</outgoingBytes>";
443  os << "</byteCounters>";
444 
445  os << "</face>";
446 }
447 
448 void
449 FaceModule::formatStatusText(std::ostream& os) const
450 {
451  os << "Faces:\n";
452  for (const FaceStatus& item : m_status) {
453  os << " ";
454  formatItemText(os, item, false);
455  os << '\n';
456  }
457 }
458 
459 void
460 FaceModule::formatItemText(std::ostream& os, const FaceStatus& item, bool wantMultiLine)
461 {
462  text::ItemAttributes ia(wantMultiLine, 10);
463 
464  os << ia("faceid") << item.getFaceId();
465  os << ia("remote") << item.getRemoteUri();
466  os << ia("local") << item.getLocalUri();
467 
468  if (item.hasExpirationPeriod()) {
469  os << ia("expires") << text::formatDuration<time::seconds>(item.getExpirationPeriod());
470  }
471 
472  if (item.hasBaseCongestionMarkingInterval() || item.hasDefaultCongestionThreshold()) {
473  os << ia("congestion") << "{";
474  text::Separator congestionSep("", " ");
475  if (item.hasBaseCongestionMarkingInterval()) {
476  os << congestionSep << "base-marking-interval="
477  << text::formatDuration<time::milliseconds>(item.getBaseCongestionMarkingInterval());
478  }
479  if (item.hasDefaultCongestionThreshold()) {
480  os << congestionSep << "default-threshold=" << item.getDefaultCongestionThreshold() << "B";
481  }
482  os << "}";
483  }
484 
485  if (item.hasMtu()) {
486  os << ia("mtu") << item.getMtu();
487  }
488 
489  os << ia("counters")
490  << "{in={"
491  << item.getNInInterests() << "i "
492  << item.getNInData() << "d "
493  << item.getNInNacks() << "n "
494  << item.getNInBytes() << "B} "
495  << "out={"
496  << item.getNOutInterests() << "i "
497  << item.getNOutData() << "d "
498  << item.getNOutNacks() << "n "
499  << item.getNOutBytes() << "B}}";
500 
501  os << ia("flags") << '{';
502  text::Separator flagSep("", " ");
503  os << flagSep << item.getFaceScope();
504  os << flagSep << item.getFacePersistency();
505  os << flagSep << item.getLinkType();
506  if (item.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED)) {
507  os << flagSep << "local-fields";
508  }
509  if (item.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)) {
510  os << flagSep << "lp-reliability";
511  }
512  if (item.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)) {
513  os << flagSep << "congestion-marking";
514  }
515  os << '}';
516 
517  os << ia.end();
518 }
519 
520 void
521 FaceModule::printFaceParams(std::ostream& os, text::ItemAttributes& ia, const ControlParameters& resp)
522 {
523  os << ia("reliability") << text::OnOff{resp.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)}
524  << ia("congestion-marking") << text::OnOff{resp.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)};
525  if (resp.hasBaseCongestionMarkingInterval()) {
526  os << ia("congestion-marking-interval")
527  << text::formatDuration<time::milliseconds>(resp.getBaseCongestionMarkingInterval());
528  }
529  if (resp.hasDefaultCongestionThreshold()) {
530  os << ia("default-congestion-threshold") << resp.getDefaultCongestionThreshold() << "B";
531  }
532  if (resp.hasMtu()) {
533  os << ia("mtu") << resp.getMtu();
534  }
535  os << '\n';
536 }
537 
538 } // namespace nfdc
539 } // namespace tools
540 } // 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:72
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;