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