multicast-discovery.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
26 #include "multicast-discovery.hpp"
27 
28 #include <ndn-cxx/util/segment-fetcher.hpp>
29 
30 namespace ndn {
31 namespace tools {
32 namespace autoconfig {
33 
34 static const Name LOCALHOP_HUB_DISCOVERY_PREFIX = "/localhop/ndn-autoconf/hub";
35 
36 MulticastDiscovery::MulticastDiscovery(Face& face, KeyChain& keyChain,
37  const NextStageCallback& nextStageOnFailure)
38  : Base(face, keyChain, nextStageOnFailure)
39  , nRequestedRegs(0)
40  , nFinishedRegs(0)
41 {
42 }
43 
44 void
46 {
47  std::cerr << "Trying multicast discovery..." << std::endl;
48 
49  util::SegmentFetcher::fetch(m_face, Interest("/localhost/nfd/faces/list"),
50  m_validator,
51  [this] (const ConstBufferPtr& data) {
52  registerHubDiscoveryPrefix(data);
53  },
54  [this] (uint32_t code, const std::string& msg) {
56  });
57 }
58 
59 void
60 MulticastDiscovery::registerHubDiscoveryPrefix(const ConstBufferPtr& buffer)
61 {
62  std::vector<uint64_t> multicastFaces;
63 
64  size_t offset = 0;
65  while (offset < buffer->size()) {
66  bool isOk = false;
67  Block block;
68  std::tie(isOk, block) = Block::fromBuffer(buffer, offset);
69  if (!isOk) {
70  std::cerr << "ERROR: cannot decode FaceStatus TLV" << std::endl;
71  break;
72  }
73 
74  offset += block.size();
75 
76  nfd::FaceStatus faceStatus(block);
77 
78  ndn::util::FaceUri uri(faceStatus.getRemoteUri());
79  if (uri.getScheme() == "udp4") {
80  namespace ip = boost::asio::ip;
81  boost::system::error_code ec;
82  ip::address address = ip::address::from_string(uri.getHost(), ec);
83 
84  if (!ec && address.is_multicast()) {
85  multicastFaces.push_back(faceStatus.getFaceId());
86  }
87  else
88  continue;
89  }
90  }
91 
92  if (multicastFaces.empty()) {
93  m_nextStageOnFailure("No multicast faces available, skipping multicast discovery stage");
94  }
95  else {
96  nfd::ControlParameters parameters;
97  parameters
98  .setName(LOCALHOP_HUB_DISCOVERY_PREFIX)
99  .setCost(1)
100  .setExpirationPeriod(time::seconds(30));
101 
102  nRequestedRegs = multicastFaces.size();
103  nFinishedRegs = 0;
104 
105  for (const auto& face : multicastFaces) {
106  parameters.setFaceId(face);
107  m_controller.start<nfd::RibRegisterCommand>(parameters,
108  bind(&MulticastDiscovery::onRegisterSuccess,
109  this),
110  bind(&MulticastDiscovery::onRegisterFailure,
111  this, _1));
112  }
113  }
114 }
115 
116 void
117 MulticastDiscovery::onRegisterSuccess()
118 {
119  ++nFinishedRegs;
120 
121  if (nRequestedRegs == nFinishedRegs) {
122  MulticastDiscovery::setStrategy();
123  }
124 }
125 
126 void
127 MulticastDiscovery::onRegisterFailure(const nfd::ControlResponse& response)
128 {
129  std::cerr << "ERROR: " << response.getText() << " (code: " << response.getCode() << ")" << std::endl;
130  --nRequestedRegs;
131 
132  if (nRequestedRegs == nFinishedRegs) {
133  if (nRequestedRegs > 0) {
134  MulticastDiscovery::setStrategy();
135  } else {
136  m_nextStageOnFailure("Failed to register " + LOCALHOP_HUB_DISCOVERY_PREFIX.toUri() +
137  " for all multicast faces, skipping multicast discovery stage");
138  }
139  }
140 }
141 
142 void
143 MulticastDiscovery::setStrategy()
144 {
145  nfd::ControlParameters parameters;
146  parameters
147  .setName(LOCALHOP_HUB_DISCOVERY_PREFIX)
148  .setStrategy("/localhost/nfd/strategy/multicast");
149 
150  m_controller.start<nfd::StrategyChoiceSetCommand>(parameters,
151  bind(&MulticastDiscovery::requestHubData, this),
152  bind(&MulticastDiscovery::onSetStrategyFailure,
153  this, _1));
154 }
155 
156 void
157 MulticastDiscovery::onSetStrategyFailure(const nfd::ControlResponse& response)
158 {
159  m_nextStageOnFailure("Failed to set multicast strategy for " +
160  LOCALHOP_HUB_DISCOVERY_PREFIX.toUri() + " namespace (" + response.getText() + "). "
161  "Skipping multicast discovery stage");
162 }
163 
164 void
165 MulticastDiscovery::requestHubData()
166 {
167  Interest interest(LOCALHOP_HUB_DISCOVERY_PREFIX);
168  interest.setInterestLifetime(time::milliseconds(4000)); // 4 seconds
169  interest.setMustBeFresh(true);
170 
171  m_face.expressInterest(interest,
172  bind(&MulticastDiscovery::onSuccess, this, _2),
173  bind(m_nextStageOnFailure, "Timeout"));
174 }
175 
176 void
177 MulticastDiscovery::onSuccess(Data& data)
178 {
179  const Block& content = data.getContent();
180  content.parse();
181 
182  // Get Uri
183  Block::element_const_iterator blockValue = content.find(tlv::nfd::Uri);
184  if (blockValue == content.elements_end()) {
185  m_nextStageOnFailure("Incorrect reply to multicast discovery stage");
186  return;
187  }
188  std::string hubUri(reinterpret_cast<const char*>(blockValue->value()), blockValue->value_size());
189  this->connectToHub(hubUri);
190 }
191 
192 } // namespace autoconfig
193 } // namespace tools
194 } // namespace ndn
Copyright (c) 2014-2016, Regents of the University of California, Arizona Board of Regents...
Definition: nfd.hpp:35
virtual void start() override
Start the stage.
static const Name LOCALHOP_HUB_DISCOVERY_PREFIX
NextStageCallback m_nextStageOnFailure
Definition: base.hpp:111
nfd::Controller m_controller
Definition: base.hpp:110
void connectToHub(const std::string &uri)
Attempt to connect to local hub using the uri FaceUri.
Definition: base.cpp:41
std::function< void(const std::string &)> NextStageCallback
Callback to be called when the stage fails.
Definition: base.hpp:61
Base class for discovery stages.
Definition: base.hpp:45
MulticastDiscovery(Face &face, KeyChain &keyChain, const NextStageCallback &nextStageOnFailure)
Create multicast discovery stage.