Project

General

Profile

nfd-status.cpp

Yukai Tu, 05/25/2015 08:35 PM

 
1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2
/**
3
 * Copyright (c) 2014-2015,  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
 * @author Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
26
 */
27

    
28
#include "version.hpp"
29

    
30
#include <ndn-cxx/face.hpp>
31
#include <ndn-cxx/name.hpp>
32
#include <ndn-cxx/interest.hpp>
33
#include <ndn-cxx/encoding/buffer-stream.hpp>
34

    
35
#include <ndn-cxx/management/nfd-forwarder-status.hpp>
36
#include <ndn-cxx/management/nfd-channel-status.hpp>
37
#include <ndn-cxx/management/nfd-face-status.hpp>
38
#include <ndn-cxx/management/nfd-fib-entry.hpp>
39
#include <ndn-cxx/management/nfd-rib-entry.hpp>
40
#include <ndn-cxx/management/nfd-strategy-choice.hpp>
41
#include <ndn-cxx/util/segment-fetcher.hpp>
42

    
43
#include <boost/algorithm/string/replace.hpp>
44
#include <list>
45

    
46
namespace ndn {
47

    
48
class NfdStatus
49
{
50
public:
51
  explicit
52
  NfdStatus(char* toolName)
53
    : m_toolName(toolName)
54
    , m_needVersionRetrieval(false)
55
    , m_needChannelStatusRetrieval(false)
56
    , m_needFaceStatusRetrieval(false)
57
    , m_needFibEnumerationRetrieval(false)
58
    , m_needRibStatusRetrieval(false)
59
    , m_needStrategyChoiceRetrieval(false)
60
    , m_isOutputXml(false)
61
  {
62
  }
63

    
64
  void
65
  usage()
66
  {
67
    std::cout << "Usage: \n  " << m_toolName << " [options]\n\n"
68
      "Show NFD version and status information\n\n"
69
      "Options:\n"
70
      "  [-h] - print this help message\n"
71
      "  [-v] - retrieve version information\n"
72
      "  [-c] - retrieve channel status information\n"
73
      "  [-f] - retrieve face status information\n"
74
      "  [-b] - retrieve FIB information\n"
75
      "  [-r] - retrieve RIB information\n"
76
      "  [-s] - retrieve configured strategy choice for NDN namespaces\n"
77
      "  [-x] - output NFD status information in XML format\n"
78
      "\n"
79
      "  [-V] - show version information of nfd-status and exit\n"
80
      "\n"
81
      "If no options are provided, all information is retrieved.\n"
82
      "If -x is provided, other options(-v, -c, etc.) are ignored, and all information is printed in XML format.\n"
83
      ;
84
  }
85

    
86
  void
87
  enableVersionRetrieval()
88
  {
89
    m_needVersionRetrieval = true;
90
  }
91

    
92
  void
93
  enableChannelStatusRetrieval()
94
  {
95
    m_needChannelStatusRetrieval = true;
96
  }
97

    
98
  void
99
  enableFaceStatusRetrieval()
100
  {
101
    m_needFaceStatusRetrieval = true;
102
  }
103

    
104
  void
105
  enableFibEnumerationRetrieval()
106
  {
107
    m_needFibEnumerationRetrieval = true;
108
  }
109

    
110
  void
111
  enableStrategyChoiceRetrieval()
112
  {
113
    m_needStrategyChoiceRetrieval = true;
114
  }
115

    
116
  void
117
  enableRibStatusRetrieval()
118
  {
119
    m_needRibStatusRetrieval = true;
120
  }
121

    
122
  void
123
  enableXmlOutput()
124
  {
125
    m_isOutputXml = true;
126
  }
127
  void
128
  onTimeout()
129
  {
130
    std::cerr << "Request timed out" << std::endl;
131

    
132
    runNextStep();
133
  }
134

    
135

    
136
  void
137
    onErrorFetch(uint32_t errorCode, const std::string& errorMsg)
138
    {
139
      std::cerr << "Error code:"<<errorCode<<", message:"<<errorMsg << std::endl;
140

    
141
      runNextStep();
142
    }
143

    
144
  void
145
  escapeSpecialCharacters(std::string *data)
146
  {
147
    using boost::algorithm::replace_all;
148
    replace_all(*data, "&",  "&amp;");
149
    replace_all(*data, "\"", "&quot;");
150
    replace_all(*data, "\'", "&apos;");
151
    replace_all(*data, "<",  "&lt;");
152
    replace_all(*data, ">",  "&gt;");
153
  }
154

    
155
  //////////////////////////////////////////////////////////////////////////////////
156
  //////////////////////////////////////////////////////////////////////////////////
157

    
158
  void
159
  fetchVersionInformation()
160
  {
161
    Interest interest("/localhost/nfd/status");
162
    interest.setChildSelector(1);
163
    interest.setMustBeFresh(true);
164
    m_face.expressInterest(
165
                           interest,
166
                           bind(&NfdStatus::afterFetchedVersionInformation, this, _2),
167
                           bind(&NfdStatus::onTimeout, this));
168
  }
169

    
170
  void
171
  afterFetchedVersionInformation(const Data& data)
172
  {
173
    nfd::ForwarderStatus status(data.getContent());
174
    std::string nfdId;
175
    if (data.getSignature().hasKeyLocator())
176
      {
177
        const ndn::KeyLocator& locator = data.getSignature().getKeyLocator();
178
        if (locator.getType() == KeyLocator::KeyLocator_Name)
179
          nfdId = locator.getName().toUri();
180
        //todo: KeyDigest supporting
181
      }
182

    
183
    if (m_isOutputXml)
184
      {
185
        std::cout << "<generalStatus>";
186
        std::cout << "<nfdId>"
187
                  << nfdId << "</nfdId>";
188
        std::cout << "<version>"
189
                  << status.getNfdVersion() << "</version>";
190
        std::cout << "<startTime>"
191
                  << time::toString(status.getStartTimestamp(), "%Y-%m-%dT%H:%M:%S%F")
192
                  << "</startTime>";
193
        std::cout << "<currentTime>"
194
                  << time::toString(status.getCurrentTimestamp(), "%Y-%m-%dT%H:%M:%S%F")
195
                  << "</currentTime>";
196
        std::cout << "<uptime>PT"
197
                  << time::duration_cast<time::seconds>(status.getCurrentTimestamp()
198
                                                        - status.getStartTimestamp()).count()
199
                  << "S</uptime>";
200
        std::cout << "<nNameTreeEntries>"     << status.getNNameTreeEntries()
201
                  << "</nNameTreeEntries>";
202
        std::cout << "<nFibEntries>"          << status.getNFibEntries()
203
                  << "</nFibEntries>";
204
        std::cout << "<nPitEntries>"          << status.getNPitEntries()
205
                  << "</nPitEntries>";
206
        std::cout << "<nMeasurementsEntries>" << status.getNMeasurementsEntries()
207
                  << "</nMeasurementsEntries>";
208
        std::cout << "<nCsEntries>"           << status.getNCsEntries()
209
                  << "</nCsEntries>";
210
        std::cout << "<packetCounters>";
211
        std::cout << "<incomingPackets>";
212
        std::cout << "<nInterests>"           << status.getNInInterests()
213
                  << "</nInterests>";
214
        std::cout << "<nDatas>"               << status.getNInDatas()
215
                  << "</nDatas>";
216
        std::cout << "</incomingPackets>";
217
        std::cout << "<outgoingPackets>";
218
        std::cout << "<nInterests>"           << status.getNOutInterests()
219
                  << "</nInterests>";
220
        std::cout << "<nDatas>"               << status.getNOutDatas()
221
                  << "</nDatas>";
222
        std::cout << "</outgoingPackets>";
223
        std::cout << "</packetCounters>";
224
        std::cout << "</generalStatus>";
225
      }
226
    else
227
      {
228
        std::cout << "General NFD status:" << std::endl;
229
        std::cout << "                 nfdId="
230
                  << nfdId << std::endl;
231
        std::cout << "               version="
232
                  << status.getNfdVersion() << std::endl;
233
        std::cout << "             startTime="
234
                  << time::toIsoString(status.getStartTimestamp()) << std::endl;
235
        std::cout << "           currentTime="
236
                  << time::toIsoString(status.getCurrentTimestamp()) << std::endl;
237
        std::cout << "                uptime="
238
                  << time::duration_cast<time::seconds>(status.getCurrentTimestamp()
239
                                                        - status.getStartTimestamp()) << std::endl;
240

    
241
        std::cout << "      nNameTreeEntries=" << status.getNNameTreeEntries()     << std::endl;
242
        std::cout << "           nFibEntries=" << status.getNFibEntries()          << std::endl;
243
        std::cout << "           nPitEntries=" << status.getNPitEntries()          << std::endl;
244
        std::cout << "  nMeasurementsEntries=" << status.getNMeasurementsEntries() << std::endl;
245
        std::cout << "            nCsEntries=" << status.getNCsEntries()           << std::endl;
246
        std::cout << "          nInInterests=" << status.getNInInterests()         << std::endl;
247
        std::cout << "         nOutInterests=" << status.getNOutInterests()        << std::endl;
248
        std::cout << "              nInDatas=" << status.getNInDatas()             << std::endl;
249
        std::cout << "             nOutDatas=" << status.getNOutDatas()            << std::endl;
250
      }
251

    
252
    runNextStep();
253
  }
254

    
255
  //////////////////////////////////////////////////////////////////////////////////
256
  //////////////////////////////////////////////////////////////////////////////////
257

    
258
  void
259
  fetchChannelStatusInformation()
260
  {
261
    m_buffer = make_shared<OBufferStream>();
262

    
263
    Interest interest("/localhost/nfd/faces/channels");
264
    interest.setChildSelector(1);
265
    interest.setMustBeFresh(true);
266

    
267
    ndn::util::SegmentFetcher::fetch(m_face, interest,
268
                                    ndn::util::DontVerifySegment(),
269
                                    bind(&NfdStatus::afterFetchedChannelStatusInformation, this, _1),
270
                                    bind(&NfdStatus::onErrorFetch, this, _1, _2));
271
  }
272

    
273
  void
274
  afterFetchedChannelStatusInformation(const ConstBufferPtr& data)
275
  {
276
    //ConstBufferPtr buf = m_buffer->buf();
277
    if (m_isOutputXml) {
278
      std::cout << "<channels>";
279

    
280
      size_t offset = 0;
281
      while (offset < data->size()) {
282
        bool isOk = false;
283
        Block block;
284
        std::tie(isOk, block) = Block::fromBuffer(data, offset);
285
        if (!isOk) {
286
          std::cerr << "ERROR: cannot decode ChannelStatus TLV" << std::endl;
287
          break;
288
        }
289

    
290
        offset += block.size();
291

    
292
        nfd::ChannelStatus channelStatus(block);
293

    
294
        std::cout << "<channel>";
295
        std::string localUri(channelStatus.getLocalUri());
296
        escapeSpecialCharacters(&localUri);
297
        std::cout << "<localUri>" << localUri << "</localUri>";
298
        std::cout << "</channel>";
299
      }
300

    
301
      std::cout << "</channels>";
302
    }
303
    else {
304
      std::cout << "Channels:" << std::endl;
305

    
306
      size_t offset = 0;
307
      while (offset < data->size()) {
308
        bool isOk = false;
309
        Block block;
310
        std::tie(isOk, block) = Block::fromBuffer(data, offset);
311
        if (!isOk) {
312
          std::cerr << "ERROR: cannot decode ChannelStatus TLV" << std::endl;
313
          break;
314
        }
315

    
316
        offset += block.size();
317

    
318
        nfd::ChannelStatus channelStatus(block);
319
        std::cout << "  " << channelStatus.getLocalUri() << std::endl;
320
      }
321
    }
322

    
323
    runNextStep();
324
  }
325

    
326
  //////////////////////////////////////////////////////////////////////////////////
327
  //////////////////////////////////////////////////////////////////////////////////
328

    
329
  void
330
  fetchFaceStatusInformation()
331
  {
332
    m_buffer = make_shared<OBufferStream>();
333

    
334
    Interest interest("/localhost/nfd/faces/list");
335
    interest.setChildSelector(1);
336
    interest.setMustBeFresh(true);
337

    
338
    ndn::util::SegmentFetcher::fetch(m_face, interest,
339
                                        ndn::util::DontVerifySegment(),
340
                                        bind(&NfdStatus::afterFetchedFaceStatusInformation, this, _1),
341
                                        bind(&NfdStatus::onErrorFetch, this, _1, _2));
342
  }
343

    
344
  void
345
  afterFetchedFaceStatusInformation(const ConstBufferPtr& data)
346
  {
347
    //ConstBufferPtr buf = m_buffer->buf();
348
    if (m_isOutputXml) {
349
      std::cout << "<faces>";
350

    
351
      size_t offset = 0;
352
      while (offset < data->size()) {
353
        bool isOk = false;
354
        Block block;
355
        std::tie(isOk, block) = Block::fromBuffer(data, offset);
356
        if (!isOk) {
357
          std::cerr << "ERROR: cannot decode FaceStatus TLV" << std::endl;
358
          break;
359
        }
360

    
361
        offset += block.size();
362

    
363
        nfd::FaceStatus faceStatus(block);
364

    
365
        std::cout << "<face>";
366
        std::cout << "<faceId>" << faceStatus.getFaceId() << "</faceId>";
367

    
368
        std::string remoteUri(faceStatus.getRemoteUri());
369
        escapeSpecialCharacters(&remoteUri);
370
        std::cout << "<remoteUri>" << remoteUri << "</remoteUri>";
371

    
372
        std::string localUri(faceStatus.getLocalUri());
373
        escapeSpecialCharacters(&localUri);
374
        std::cout << "<localUri>" << localUri << "</localUri>";
375

    
376
        if (faceStatus.hasExpirationPeriod()) {
377
          std::cout << "<expirationPeriod>PT"
378
                    << time::duration_cast<time::seconds>(faceStatus.getExpirationPeriod())
379
                       .count() << "S"
380
                    << "</expirationPeriod>";
381
        }
382

    
383
        std::cout << "<faceScope>" << faceStatus.getFaceScope()
384
                  << "</faceScope>";
385
        std::cout << "<facePersistency>" << faceStatus.getFacePersistency()
386
                  << "</facePersistency>";
387
        std::cout << "<linkType>" << faceStatus.getLinkType()
388
                  << "</linkType>";
389

    
390
        std::cout << "<packetCounters>";
391
        std::cout << "<incomingPackets>";
392
        std::cout << "<nInterests>"       << faceStatus.getNInInterests()
393
                  << "</nInterests>";
394
        std::cout << "<nDatas>"           << faceStatus.getNInDatas()
395
                  << "</nDatas>";
396
        std::cout << "</incomingPackets>";
397
        std::cout << "<outgoingPackets>";
398
        std::cout << "<nInterests>"       << faceStatus.getNOutInterests()
399
                  << "</nInterests>";
400
        std::cout << "<nDatas>"           << faceStatus.getNOutDatas()
401
                  << "</nDatas>";
402
        std::cout << "</outgoingPackets>";
403
        std::cout << "</packetCounters>";
404

    
405
        std::cout << "<byteCounters>";
406
        std::cout << "<incomingBytes>"    << faceStatus.getNInBytes()
407
                  << "</incomingBytes>";
408
        std::cout << "<outgoingBytes>"    << faceStatus.getNOutBytes()
409
                  << "</outgoingBytes>";
410
        std::cout << "</byteCounters>";
411

    
412
        std::cout << "</face>";
413
      }
414
      std::cout << "</faces>";
415
    }
416
    else {
417
      std::cout << "Faces:" << std::endl;
418

    
419
      size_t offset = 0;
420
      while (offset < data->size()) {
421
        bool isOk = false;
422
        Block block;
423
        std::tie(isOk, block) = Block::fromBuffer(data, offset);
424
        if (!isOk) {
425
          std::cerr << "ERROR: cannot decode FaceStatus TLV" << std::endl;
426
          break;
427
        }
428

    
429
        offset += block.size();
430

    
431
        nfd::FaceStatus faceStatus(block);
432

    
433
        std::cout << "  faceid=" << faceStatus.getFaceId()
434
                  << " remote=" << faceStatus.getRemoteUri()
435
                  << " local=" << faceStatus.getLocalUri();
436
        if (faceStatus.hasExpirationPeriod()) {
437
          std::cout  << " expires="
438
                     << time::duration_cast<time::seconds>(faceStatus.getExpirationPeriod())
439
                        .count() << "s";
440
        }
441
        std::cout << " counters={"
442
                  << "in={" << faceStatus.getNInInterests() << "i "
443
                  << faceStatus.getNInDatas() << "d "
444
                  << faceStatus.getNInBytes() << "B}"
445
                  << " out={" << faceStatus.getNOutInterests() << "i "
446
                  << faceStatus.getNOutDatas() << "d "
447
                  << faceStatus.getNOutBytes() << "B}"
448
                  << "}";
449
        std::cout << " " << faceStatus.getFaceScope()
450
                  << " " << faceStatus.getFacePersistency()
451
                  << " " << faceStatus.getLinkType();
452
        std::cout << std::endl;
453
      }
454
    }
455

    
456
    runNextStep();
457
  }
458

    
459
  //////////////////////////////////////////////////////////////////////////////////
460
  //////////////////////////////////////////////////////////////////////////////////
461

    
462
  void
463
  fetchFibEnumerationInformation()
464
  {
465
    m_buffer = make_shared<OBufferStream>();
466

    
467
    Interest interest("/localhost/nfd/fib/list");
468
    interest.setChildSelector(1);
469
    interest.setMustBeFresh(true);
470
    ndn::util::SegmentFetcher::fetch(m_face, interest,
471
                                            ndn::util::DontVerifySegment(),
472
                                            bind(&NfdStatus::afterFetchedFibEnumerationInformation, this, _1),
473
                                            bind(&NfdStatus::onErrorFetch, this, _1, _2));
474
  }
475

    
476
  void
477
  afterFetchedFibEnumerationInformation(const ConstBufferPtr& data)
478
  {
479
    //ConstBufferPtr buf = m_buffer->buf();
480
    if (m_isOutputXml) {
481
      std::cout << "<fib>";
482

    
483
      size_t offset = 0;
484
      while (offset < data->size()) {
485
        bool isOk = false;
486
        Block block;
487
        std::tie(isOk, block) = Block::fromBuffer(data, offset);
488
        if (!isOk) {
489
          std::cerr << "ERROR: cannot decode FibEntry TLV";
490
          break;
491
        }
492
        offset += block.size();
493

    
494
        nfd::FibEntry fibEntry(block);
495

    
496
        std::cout << "<fibEntry>";
497
        std::string prefix(fibEntry.getPrefix().toUri());
498
        escapeSpecialCharacters(&prefix);
499
        std::cout << "<prefix>" << prefix << "</prefix>";
500
        std::cout << "<nextHops>";
501
        for (const nfd::NextHopRecord& nextHop : fibEntry.getNextHopRecords()) {
502
          std::cout << "<nextHop>" ;
503
          std::cout << "<faceId>"  << nextHop.getFaceId() << "</faceId>";
504
          std::cout << "<cost>"    << nextHop.getCost()   << "</cost>";
505
          std::cout << "</nextHop>";
506
        }
507
        std::cout << "</nextHops>";
508
        std::cout << "</fibEntry>";
509
      }
510

    
511
      std::cout << "</fib>";
512
    }
513
    else {
514
      std::cout << "FIB:" << std::endl;
515

    
516
      size_t offset = 0;
517
      while (offset < data->size()) {
518
        bool isOk = false;
519
        Block block;
520
        std::tie(isOk, block) = Block::fromBuffer(data, offset);
521
        if (!isOk) {
522
          std::cerr << "ERROR: cannot decode FibEntry TLV" << std::endl;
523
          break;
524
        }
525
        offset += block.size();
526

    
527
        nfd::FibEntry fibEntry(block);
528

    
529
        std::cout << "  " << fibEntry.getPrefix() << " nexthops={";
530
        bool isFirst = true;
531
        for (const nfd::NextHopRecord& nextHop : fibEntry.getNextHopRecords()) {
532
          if (isFirst)
533
            isFirst = false;
534
          else
535
            std::cout << ", ";
536

    
537
          std::cout << "faceid=" << nextHop.getFaceId()
538
                    << " (cost=" << nextHop.getCost() << ")";
539
        }
540
        std::cout << "}" << std::endl;
541
      }
542
    }
543

    
544
    runNextStep();
545
  }
546

    
547
  //////////////////////////////////////////////////////////////////////////////////
548
  //////////////////////////////////////////////////////////////////////////////////
549

    
550
  void
551
  fetchStrategyChoiceInformation()
552
  {
553
    m_buffer = make_shared<OBufferStream>();
554

    
555
    Interest interest("/localhost/nfd/strategy-choice/list");
556
    interest.setChildSelector(1);
557
    interest.setMustBeFresh(true);
558
    ndn::util::SegmentFetcher::fetch(m_face, interest,
559
                                                ndn::util::DontVerifySegment(),
560
                                                bind(&NfdStatus::afterFetchedStrategyChoiceInformationInformation, this, _1),
561
                                                bind(&NfdStatus::onErrorFetch, this, _1, _2));
562
  }
563

    
564
  void
565
  afterFetchedStrategyChoiceInformationInformation(const ConstBufferPtr& data)
566
  {
567
   // ConstBufferPtr buf = m_buffer->buf();
568
    if (m_isOutputXml) {
569
      std::cout << "<strategyChoices>";
570

    
571
      size_t offset = 0;
572
      while (offset < data->size()) {
573
        bool isOk = false;
574
        Block block;
575
        std::tie(isOk, block) = Block::fromBuffer(data, offset);
576
        if (!isOk) {
577
          std::cerr << "ERROR: cannot decode StrategyChoice TLV";
578
          break;
579
        }
580
        offset += block.size();
581

    
582
        nfd::StrategyChoice strategyChoice(block);
583

    
584
        std::cout << "<strategyChoice>";
585

    
586
        std::string name(strategyChoice.getName().toUri());
587
        escapeSpecialCharacters(&name);
588
        std::cout << "<namespace>" << name << "</namespace>";
589
        std::cout << "<strategy>";
590

    
591
        std::string strategy(strategyChoice.getStrategy().toUri());
592
        escapeSpecialCharacters(&strategy);
593

    
594
        std::cout << "<name>" << strategy << "</name>";
595
        std::cout << "</strategy>";
596
        std::cout << "</strategyChoice>";
597
      }
598

    
599
      std::cout << "</strategyChoices>";
600
    }
601
    else {
602
      std::cout << "Strategy choices:" << std::endl;
603

    
604
      size_t offset = 0;
605
      while (offset < data->size()) {
606
        bool isOk = false;
607
        Block block;
608
        std::tie(isOk, block) = Block::fromBuffer(data, offset);
609
        if (!isOk) {
610
          std::cerr << "ERROR: cannot decode StrategyChoice TLV" << std::endl;
611
          break;
612
        }
613
        offset += block.size();
614

    
615
        nfd::StrategyChoice strategyChoice(block);
616

    
617
        std::cout << "  " << strategyChoice.getName()
618
                  << " strategy=" << strategyChoice.getStrategy() << std::endl;
619
      }
620
    }
621

    
622
    runNextStep();
623
  }
624

    
625
  void
626
  fetchRibStatusInformation()
627
  {
628
    m_buffer = make_shared<OBufferStream>();
629

    
630
    Interest interest("/localhost/nfd/rib/list");
631
    interest.setChildSelector(1);
632
    interest.setMustBeFresh(true);
633

    
634
    ndn::util::SegmentFetcher::fetch(m_face, interest,
635
                                                   ndn::util::DontVerifySegment(),
636
                                                   bind(&NfdStatus::afterFetchedRibStatusInformation, this, _1),
637
                                                   bind(&NfdStatus::onErrorFetch, this, _1, _2));
638
  }
639

    
640
  void
641
  afterFetchedRibStatusInformation(const ConstBufferPtr& data)
642
  {
643
    //ConstBufferPtr buf = m_buffer->buf();
644
    if (m_isOutputXml) {
645
      std::cout << "<rib>";
646

    
647
      size_t offset = 0;
648
      while (offset < data->size()) {
649
        bool isOk = false;
650
        Block block;
651
        std::tie(isOk, block) = Block::fromBuffer(data, offset);
652
        if (!isOk) {
653
          std::cerr << "ERROR: cannot decode RibEntry TLV";
654
          break;
655
        }
656
        offset += block.size();
657

    
658
        nfd::RibEntry ribEntry(block);
659

    
660
        std::cout << "<ribEntry>";
661
        std::string prefix(ribEntry.getName().toUri());
662
        escapeSpecialCharacters(&prefix);
663
        std::cout << "<prefix>" << prefix << "</prefix>";
664
        std::cout << "<routes>";
665
        for (const nfd::Route& nextRoute : ribEntry) {
666
          std::cout << "<route>" ;
667
          std::cout << "<faceId>"  << nextRoute.getFaceId() << "</faceId>";
668
          std::cout << "<origin>"  << nextRoute.getOrigin() << "</origin>";
669
          std::cout << "<cost>"    << nextRoute.getCost()   << "</cost>";
670

    
671
          std::cout << "<flags>";
672
          if (nextRoute.isChildInherit())
673
            std::cout << "<childInherit/>";
674
          if (nextRoute.isRibCapture())
675
            std::cout << "<ribCapture/>";
676
          std::cout << "</flags>";
677

    
678
          if (!nextRoute.hasInfiniteExpirationPeriod()) {
679
            std::cout << "<expirationPeriod>PT"
680
                      << time::duration_cast<time::seconds>(nextRoute.getExpirationPeriod())
681
                         .count() << "S"
682
                      << "</expirationPeriod>";
683
          }
684
          std::cout << "</route>";
685
        }
686
        std::cout << "</routes>";
687
        std::cout << "</ribEntry>";
688
      }
689

    
690
      std::cout << "</rib>";
691
    }
692
    else {
693
      std::cout << "RIB:" << std::endl;
694

    
695
      size_t offset = 0;
696
      while (offset < data->size()) {
697
        bool isOk = false;
698
        Block block;
699
        std::tie(isOk, block) = Block::fromBuffer(data, offset);
700
        if (!isOk) {
701
          std::cerr << "ERROR: cannot decode RibEntry TLV" << std::endl;
702
          break;
703
        }
704

    
705
        offset += block.size();
706

    
707
        nfd::RibEntry ribEntry(block);
708

    
709
        std::cout << "  " << ribEntry.getName().toUri() << " route={";
710
        bool isFirst = true;
711
        for (const nfd::Route& nextRoute : ribEntry) {
712
          if (isFirst)
713
            isFirst = false;
714
          else
715
            std::cout << ", ";
716

    
717
          std::cout << "faceid="   << nextRoute.getFaceId()
718
                    << " (origin="  << nextRoute.getOrigin()
719
                    << " cost="    << nextRoute.getCost();
720
          if (!nextRoute.hasInfiniteExpirationPeriod()) {
721
            std::cout << " expires="
722
                      << time::duration_cast<time::seconds>(nextRoute.getExpirationPeriod())
723
                         .count() << "s";
724
          }
725

    
726
          if (nextRoute.isChildInherit())
727
            std::cout << " ChildInherit";
728
          if (nextRoute.isRibCapture())
729
            std::cout << " RibCapture";
730

    
731
          std::cout << ")";
732
        }
733
        std::cout << "}" << std::endl;
734
      }
735
    }
736

    
737
    runNextStep();
738
  }
739

    
740

    
741
  void
742
  fetchInformation()
743
  {
744
        
745
    if (m_isOutputXml ||
746
        (!m_needVersionRetrieval &&
747
         !m_needChannelStatusRetrieval &&
748
         !m_needFaceStatusRetrieval &&
749
         !m_needFibEnumerationRetrieval &&
750
         !m_needRibStatusRetrieval &&
751
         !m_needStrategyChoiceRetrieval))
752
      {
753
        enableVersionRetrieval();
754
        enableChannelStatusRetrieval();
755
        enableFaceStatusRetrieval();
756
        enableFibEnumerationRetrieval();
757
        enableRibStatusRetrieval();
758
        enableStrategyChoiceRetrieval();
759
      }
760

    
761
    if (m_isOutputXml)
762
      m_fetchSteps.push_back(bind(&NfdStatus::printXmlHeader, this));
763

    
764
    if (m_needVersionRetrieval)
765
      m_fetchSteps.push_back(bind(&NfdStatus::fetchVersionInformation, this));
766

    
767
    if (m_needChannelStatusRetrieval)
768
      m_fetchSteps.push_back(bind(&NfdStatus::fetchChannelStatusInformation, this));
769

    
770
    if (m_needFaceStatusRetrieval)
771
      m_fetchSteps.push_back(bind(&NfdStatus::fetchFaceStatusInformation, this));
772

    
773
    if (m_needFibEnumerationRetrieval)
774
      m_fetchSteps.push_back(bind(&NfdStatus::fetchFibEnumerationInformation, this));
775

    
776
    if (m_needRibStatusRetrieval)
777
      m_fetchSteps.push_back(bind(&NfdStatus::fetchRibStatusInformation, this));
778

    
779
    if (m_needStrategyChoiceRetrieval)
780
      m_fetchSteps.push_back(bind(&NfdStatus::fetchStrategyChoiceInformation, this));
781

    
782
    if (m_isOutputXml)
783
      m_fetchSteps.push_back(bind(&NfdStatus::printXmlFooter, this));
784

    
785
    runNextStep();
786
    m_face.processEvents();
787
  }
788

    
789
private:
790
  void
791
  printXmlHeader()
792
  {
793
    std::cout << "<?xml version=\"1.0\"?>";
794
    std::cout << "<nfdStatus xmlns=\"ndn:/localhost/nfd/status/1\">";
795

    
796
    runNextStep();
797
  }
798

    
799
  void
800
  printXmlFooter()
801
  {
802
    std::cout << "</nfdStatus>";
803

    
804
    runNextStep();
805
  }
806

    
807
  void
808
  runNextStep()
809
  {
810
    if (m_fetchSteps.empty())
811
      return;
812

    
813
    function<void()> nextStep = m_fetchSteps.front();
814
    m_fetchSteps.pop_front();
815
    nextStep();
816
  }
817

    
818
private:
819
  std::string m_toolName;
820
  bool m_needVersionRetrieval;
821
  bool m_needChannelStatusRetrieval;
822
  bool m_needFaceStatusRetrieval;
823
  bool m_needFibEnumerationRetrieval;
824
  bool m_needRibStatusRetrieval;
825
  bool m_needStrategyChoiceRetrieval;
826
  bool m_isOutputXml;
827
  Face m_face;
828

    
829
  shared_ptr<OBufferStream> m_buffer;
830

    
831
  std::deque<function<void()> > m_fetchSteps;
832
};
833

    
834
}
835

    
836
int main(int argc, char* argv[])
837
{
838
  int option;
839
  ndn::NfdStatus nfdStatus(argv[0]);
840

    
841
  while ((option = getopt(argc, argv, "hvcfbrsxV")) != -1) {
842
    switch (option) {
843
    case 'h':
844
      nfdStatus.usage();
845
      return 0;
846
    case 'v':
847
      nfdStatus.enableVersionRetrieval();
848
      break;
849
    case 'c':
850
      nfdStatus.enableChannelStatusRetrieval();
851
      break;
852
    case 'f':
853
      nfdStatus.enableFaceStatusRetrieval();
854
      break;
855
    case 'b':
856
      nfdStatus.enableFibEnumerationRetrieval();
857
      break;
858
    case 'r':
859
      nfdStatus.enableRibStatusRetrieval();
860
      break;
861
    case 's':
862
      nfdStatus.enableStrategyChoiceRetrieval();
863
      break;
864
    case 'x':
865
      nfdStatus.enableXmlOutput();
866
      break;
867
    case 'V':
868
      std::cout << NFD_VERSION_BUILD_STRING << std::endl;
869
      return 0;
870
    default:
871
      nfdStatus.usage();
872
      return 1;
873
    }
874
  }
875

    
876
  try {
877
    nfdStatus.fetchInformation();
878
  }
879
  catch (std::exception& e) {
880
    std::cerr << "ERROR: " << e.what() << std::endl;
881
    return 2;
882
  }
883

    
884
  return 0;
885
}
886