blob: 59db21f26624bb552ce7285b0e0dad7327e8d620 [file] [log] [blame]
Alexander Afanasyev2a655f72015-01-26 18:38:33 -08001/* -*- 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
26#include "multicast-discovery.hpp"
27
28#include <ndn-cxx/util/segment-fetcher.hpp>
29
30namespace ndn {
31namespace tools {
32namespace autoconfig {
33
34static const Name LOCALHOP_HUB_DISCOVERY_PREFIX = "/localhop/ndn-autoconf/hub";
35
36MulticastDiscovery::MulticastDiscovery(Face& face, KeyChain& keyChain,
37 const NextStageCallback& nextStageOnFailure)
38 : Base(face, keyChain, nextStageOnFailure)
39 , nRequestedRegs(0)
40 , nFinishedRegs(0)
41{
42}
43
44void
45MulticastDiscovery::start()
46{
47 std::cerr << "Trying multicast discovery..." << std::endl;
48
49 util::SegmentFetcher::fetch(m_face, Interest("/localhost/nfd/faces/list"),
50 ndn::util::DontVerifySegment(),
51 [this] (const ConstBufferPtr& data) {
52 registerHubDiscoveryPrefix(data);
53 },
54 [this] (uint32_t code, const std::string& msg) {
55 m_nextStageOnFailure(msg);
56 });
57}
58
59void
60MulticastDiscovery::registerHubDiscoveryPrefix(const ConstBufferPtr& buffer)
61{
62 std::vector<uint64_t> multicastFaces;
63
64 size_t offset = 0;
65 while (offset < buffer->size()) {
66 Block block;
67 bool ok = Block::fromBuffer(buffer, offset, block);
68 if (!ok)
69 {
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, _2));
112 }
113 }
114}
115
116void
117MulticastDiscovery::onRegisterSuccess()
118{
119 ++nFinishedRegs;
120
121 if (nRequestedRegs == nFinishedRegs) {
122 MulticastDiscovery::setStrategy();
123 }
124}
125
126void
127MulticastDiscovery::onRegisterFailure(uint32_t code, const std::string& error)
128{
129 std::cerr << "ERROR: " << error << " (code: " << code << ")" << 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
142void
143MulticastDiscovery::setStrategy()
144{
145 nfd::ControlParameters parameters;
146 parameters
147 .setName(LOCALHOP_HUB_DISCOVERY_PREFIX)
148 .setStrategy("/localhost/nfd/strategy/broadcast");
149
150 m_controller.start<nfd::StrategyChoiceSetCommand>(parameters,
151 bind(&MulticastDiscovery::requestHubData, this),
152 bind(&MulticastDiscovery::onSetStrategyFailure,
153 this, _2));
154}
155
156void
157MulticastDiscovery::onSetStrategyFailure(const std::string& error)
158{
159 m_nextStageOnFailure("Failed to set broadcast strategy for " +
160 LOCALHOP_HUB_DISCOVERY_PREFIX.toUri() + " namespace (" + error + "). "
161 "Skipping multicast discovery stage");
162}
163
164void
165MulticastDiscovery::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
176void
177MulticastDiscovery::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