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  FindFace findFace(ctx);
314  FindFace::Code res = findFace.execute(ctx.args.at("face"));
315 
316  ctx.exitCode = static_cast<int>(res);
317  switch (res) {
318  case FindFace::Code::OK:
319  break;
323  ctx.err << findFace.getErrorReason() << '\n';
324  return;
326  ctx.err << "Multiple faces match specified remote FaceUri. Re-run the command with a FaceId:";
328  ctx.err << '\n';
329  return;
330  default:
331  BOOST_ASSERT_MSG(false, "unexpected FindFace result");
332  return;
333  }
334 
335  const FaceStatus& face = findFace.getFaceStatus();
336 
337  ctx.controller.start<ndn::nfd::FaceDestroyCommand>(
338  ControlParameters().setFaceId(face.getFaceId()),
339  [&] (const ControlParameters& resp) {
340  ctx.out << "face-destroyed ";
342  ctx.out << ia("id") << face.getFaceId()
343  << ia("local") << face.getLocalUri()
344  << ia("remote") << face.getRemoteUri()
345  << ia("persistency") << face.getFacePersistency();
346  printFaceParams(ctx.out, ia, resp);
347  },
348  ctx.makeCommandFailureHandler("destroying face"),
349  ctx.makeCommandOptions());
350 
351  ctx.face.processEvents();
352 }
353 
354 void
355 FaceModule::fetchStatus(Controller& controller,
356  const std::function<void()>& onSuccess,
357  const Controller::DatasetFailCallback& onFailure,
358  const CommandOptions& options)
359 {
360  controller.fetch<ndn::nfd::FaceDataset>(
361  [this, onSuccess] (const std::vector<FaceStatus>& result) {
362  m_status = result;
363  onSuccess();
364  },
365  onFailure, options);
366 }
367 
368 void
369 FaceModule::formatStatusXml(std::ostream& os) const
370 {
371  os << "<faces>";
372  for (const FaceStatus& item : m_status) {
373  this->formatItemXml(os, item);
374  }
375  os << "</faces>";
376 }
377 
378 void
379 FaceModule::formatItemXml(std::ostream& os, const FaceStatus& item) const
380 {
381  os << "<face>";
382 
383  os << "<faceId>" << item.getFaceId() << "</faceId>";
384  os << "<remoteUri>" << xml::Text{item.getRemoteUri()} << "</remoteUri>";
385  os << "<localUri>" << xml::Text{item.getLocalUri()} << "</localUri>";
386 
387  if (item.hasExpirationPeriod()) {
388  os << "<expirationPeriod>" << xml::formatDuration(item.getExpirationPeriod())
389  << "</expirationPeriod>";
390  }
391  os << "<faceScope>" << item.getFaceScope() << "</faceScope>";
392  os << "<facePersistency>" << item.getFacePersistency() << "</facePersistency>";
393  os << "<linkType>" << item.getLinkType() << "</linkType>";
394 
395  if (!item.hasBaseCongestionMarkingInterval() && !item.hasDefaultCongestionThreshold()) {
396  os << "<congestion/>";
397  }
398  else {
399  os << "<congestion>";
400  if (item.hasBaseCongestionMarkingInterval()) {
401  os << "<baseMarkingInterval>" << xml::formatDuration(item.getBaseCongestionMarkingInterval())
402  << "</baseMarkingInterval>";
403  }
404  if (item.hasDefaultCongestionThreshold()) {
405  os << "<defaultThreshold>" << item.getDefaultCongestionThreshold() << "</defaultThreshold>";
406  }
407  os << "</congestion>";
408  }
409 
410  if (item.hasMtu()) {
411  os << "<mtu>" << item.getMtu() << "</mtu>";
412  }
413 
414  if (item.getFlags() == 0) {
415  os << "<flags/>";
416  }
417  else {
418  os << "<flags>";
419  os << xml::Flag{"localFieldsEnabled", item.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED)};
420  os << xml::Flag{"lpReliabilityEnabled", item.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)};
421  os << xml::Flag{"congestionMarkingEnabled", item.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)};
422  os << "</flags>";
423  }
424 
425  os << "<packetCounters>";
426  os << "<incomingPackets>"
427  << "<nInterests>" << item.getNInInterests() << "</nInterests>"
428  << "<nData>" << item.getNInData() << "</nData>"
429  << "<nNacks>" << item.getNInNacks() << "</nNacks>"
430  << "</incomingPackets>";
431  os << "<outgoingPackets>"
432  << "<nInterests>" << item.getNOutInterests() << "</nInterests>"
433  << "<nData>" << item.getNOutData() << "</nData>"
434  << "<nNacks>" << item.getNOutNacks() << "</nNacks>"
435  << "</outgoingPackets>";
436  os << "</packetCounters>";
437 
438  os << "<byteCounters>";
439  os << "<incomingBytes>" << item.getNInBytes() << "</incomingBytes>";
440  os << "<outgoingBytes>" << item.getNOutBytes() << "</outgoingBytes>";
441  os << "</byteCounters>";
442 
443  os << "</face>";
444 }
445 
446 void
447 FaceModule::formatStatusText(std::ostream& os) const
448 {
449  os << "Faces:\n";
450  for (const FaceStatus& item : m_status) {
451  os << " ";
452  formatItemText(os, item, false);
453  os << '\n';
454  }
455 }
456 
457 void
458 FaceModule::formatItemText(std::ostream& os, const FaceStatus& item, bool wantMultiLine)
459 {
460  text::ItemAttributes ia(wantMultiLine, 10);
461 
462  os << ia("faceid") << item.getFaceId();
463  os << ia("remote") << item.getRemoteUri();
464  os << ia("local") << item.getLocalUri();
465 
466  if (item.hasExpirationPeriod()) {
467  os << ia("expires") << text::formatDuration<time::seconds>(item.getExpirationPeriod());
468  }
469 
470  if (item.hasBaseCongestionMarkingInterval() || item.hasDefaultCongestionThreshold()) {
471  os << ia("congestion") << "{";
472  text::Separator congestionSep("", " ");
473  if (item.hasBaseCongestionMarkingInterval()) {
474  os << congestionSep << "base-marking-interval="
475  << text::formatDuration<time::milliseconds>(item.getBaseCongestionMarkingInterval());
476  }
477  if (item.hasDefaultCongestionThreshold()) {
478  os << congestionSep << "default-threshold=" << item.getDefaultCongestionThreshold() << "B";
479  }
480  os << "}";
481  }
482 
483  if (item.hasMtu()) {
484  os << ia("mtu") << item.getMtu();
485  }
486 
487  os << ia("counters")
488  << "{in={"
489  << item.getNInInterests() << "i "
490  << item.getNInData() << "d "
491  << item.getNInNacks() << "n "
492  << item.getNInBytes() << "B} "
493  << "out={"
494  << item.getNOutInterests() << "i "
495  << item.getNOutData() << "d "
496  << item.getNOutNacks() << "n "
497  << item.getNOutBytes() << "B}}";
498 
499  os << ia("flags") << '{';
500  text::Separator flagSep("", " ");
501  os << flagSep << item.getFaceScope();
502  os << flagSep << item.getFacePersistency();
503  os << flagSep << item.getLinkType();
504  if (item.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED)) {
505  os << flagSep << "local-fields";
506  }
507  if (item.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)) {
508  os << flagSep << "lp-reliability";
509  }
510  if (item.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)) {
511  os << flagSep << "congestion-marking";
512  }
513  os << '}';
514 
515  os << ia.end();
516 }
517 
518 void
519 FaceModule::printFaceParams(std::ostream& os, text::ItemAttributes& ia, const ControlParameters& resp)
520 {
521  os << ia("reliability") << text::OnOff{resp.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)}
522  << ia("congestion-marking") << text::OnOff{resp.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)};
523  if (resp.hasBaseCongestionMarkingInterval()) {
524  os << ia("congestion-marking-interval")
525  << text::formatDuration<time::milliseconds>(resp.getBaseCongestionMarkingInterval());
526  }
527  if (resp.hasDefaultCongestionThreshold()) {
528  os << ia("default-congestion-threshold") << resp.getDefaultCongestionThreshold() << "B";
529  }
530  if (resp.hasMtu()) {
531  os << ia("mtu") << resp.getMtu();
532  }
533  os << '\n';
534 }
535 
536 } // namespace nfdc
537 } // namespace tools
538 } // 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;