blob: fc3a6fc351c9993497951ace1fdb7c562bb9f5b2 [file] [log] [blame]
Alexander Afanasyev2a655f72015-01-26 18:38:33 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shi9f5b01d2016-08-05 03:54:28 +00003 * Copyright (c) 2014-2016, Regents of the University of California,
Alexander Afanasyev2a655f72015-01-26 18:38:33 -08004 * 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
Junxiao Shi9f5b01d2016-08-05 03:54:28 +000026#include "core/version.hpp"
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080027
28#include "multicast-discovery.hpp"
29#include "guess-from-search-domains.hpp"
Alexander Afanasyev2a001942016-12-14 18:18:41 -080030#include "ndn-fch-discovery.hpp"
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080031#include "guess-from-identity-name.hpp"
32
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -080033#include <ndn-cxx/util/network-monitor.hpp>
34#include <ndn-cxx/util/scheduler.hpp>
35#include <ndn-cxx/util/scheduler-scoped-event-id.hpp>
36
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080037#include <boost/noncopyable.hpp>
Alexander Afanasyev5c475972015-12-20 16:16:56 -080038#include <boost/program_options/options_description.hpp>
Alexander Afanasyev5c475972015-12-20 16:16:56 -080039#include <boost/program_options/parsers.hpp>
Junxiao Shi52fa45c2016-11-29 21:18:13 +000040#include <boost/program_options/variables_map.hpp>
Alexander Afanasyev5c475972015-12-20 16:16:56 -080041
42namespace po = boost::program_options;
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080043
44namespace ndn {
45namespace tools {
Junxiao Shi52fa45c2016-11-29 21:18:13 +000046namespace autoconfig {
47// ndn-autoconfig is an NDN tool not an NFD tool, so it uses ndn::tools::autoconfig namespace.
48// It lives in NFD repository because nfd-start can automatically start ndn-autoconfig in daemon mode.
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080049
50class NdnAutoconfig : boost::noncopyable
51{
52public:
53 class Error : public std::runtime_error
54 {
55 public:
56 explicit
57 Error(const std::string& what)
58 : std::runtime_error(what)
59 {
60 }
61 };
62
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -080063 explicit
Alexander Afanasyev2a001942016-12-14 18:18:41 -080064 NdnAutoconfig(const std::string& ndnFchUrl, bool isDaemonMode)
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -080065 : m_face(m_io)
66 , m_scheduler(m_io)
67 , m_startStagesEvent(m_scheduler)
68 , m_isDaemonMode(isDaemonMode)
69 , m_terminationSignalSet(m_io)
70 , m_stage1(m_face, m_keyChain,
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080071 [&] (const std::string& errorMessage) {
72 std::cerr << "Stage 1 failed: " << errorMessage << std::endl;
73 m_stage2.start();
74 })
75 , m_stage2(m_face, m_keyChain,
76 [&] (const std::string& errorMessage) {
77 std::cerr << "Stage 2 failed: " << errorMessage << std::endl;
78 m_stage3.start();
79 })
80 , m_stage3(m_face, m_keyChain,
Alexander Afanasyev2a001942016-12-14 18:18:41 -080081 ndnFchUrl,
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080082 [&] (const std::string& errorMessage) {
83 std::cerr << "Stage 3 failed: " << errorMessage << std::endl;
Alexander Afanasyev2a001942016-12-14 18:18:41 -080084 m_stage4.start();
85 })
86 , m_stage4(m_face, m_keyChain,
87 [&] (const std::string& errorMessage) {
88 std::cerr << "Stage 4 failed: " << errorMessage << std::endl;
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -080089 if (!m_isDaemonMode)
Spyridon Mastorakis149e02c2015-07-27 13:22:22 -070090 BOOST_THROW_EXCEPTION(Error("No more stages, automatic discovery failed"));
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -080091 else
92 std::cerr << "No more stages, automatic discovery failed" << std::endl;
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080093 })
94 {
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -080095 if (m_isDaemonMode) {
Junxiao Shi52fa45c2016-11-29 21:18:13 +000096 m_networkMonitor.reset(new ndn::util::NetworkMonitor(m_io));
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -080097 m_networkMonitor->onNetworkStateChanged.connect([this] {
98 // delay stages, so if multiple events are triggered in short sequence,
99 // only one auto-detection procedure is triggered
100 m_startStagesEvent = m_scheduler.scheduleEvent(time::seconds(5),
101 bind(&NdnAutoconfig::startStages, this));
102 });
103 }
104
105 // Delay a little bit
106 m_startStagesEvent = m_scheduler.scheduleEvent(time::milliseconds(100),
107 bind(&NdnAutoconfig::startStages, this));
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800108 }
109
110 void
111 run()
112 {
Alexander Afanasyevba3f79e2015-02-02 13:56:13 -0800113 if (m_isDaemonMode) {
114 m_terminationSignalSet.add(SIGINT);
115 m_terminationSignalSet.add(SIGTERM);
116 m_terminationSignalSet.async_wait(bind(&NdnAutoconfig::terminate, this, _1, _2));
117 }
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -0800118
119 m_io.run();
120 }
121
122 void
123 terminate(const boost::system::error_code& error, int signalNo)
124 {
125 if (error)
126 return;
127
128 m_io.stop();
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800129 }
130
131 static void
Alexander Afanasyev5c475972015-12-20 16:16:56 -0800132 usage(std::ostream& os,
133 const po::options_description& optionDescription,
134 const char* programName)
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800135 {
Alexander Afanasyev5c475972015-12-20 16:16:56 -0800136 os << "Usage:\n"
137 << " " << programName << " [options]\n"
138 << "\n";
139 os << optionDescription;
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800140 }
141
142private:
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -0800143 void
144 startStages()
145 {
146 m_stage1.start();
147 if (m_isDaemonMode) {
148 m_startStagesEvent = m_scheduler.scheduleEvent(time::hours(1),
149 bind(&NdnAutoconfig::startStages, this));
150 }
151 }
152
153private:
154 boost::asio::io_service m_io;
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800155 Face m_face;
156 KeyChain m_keyChain;
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -0800157 unique_ptr<util::NetworkMonitor> m_networkMonitor;
158 util::Scheduler m_scheduler;
159 util::scheduler::ScopedEventId m_startStagesEvent;
160 bool m_isDaemonMode;
161 boost::asio::signal_set m_terminationSignalSet;
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800162
Junxiao Shi52fa45c2016-11-29 21:18:13 +0000163 MulticastDiscovery m_stage1;
164 GuessFromSearchDomains m_stage2;
Alexander Afanasyev2a001942016-12-14 18:18:41 -0800165 NdnFchDiscovery m_stage3;
166 GuessFromIdentityName m_stage4;
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800167};
168
Junxiao Shi52fa45c2016-11-29 21:18:13 +0000169static int
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800170main(int argc, char** argv)
171{
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -0800172 bool isDaemonMode = false;
Alexander Afanasyev5c475972015-12-20 16:16:56 -0800173 std::string configFile;
Alexander Afanasyev2a001942016-12-14 18:18:41 -0800174 std::string ndnFchUrl;
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800175
Alexander Afanasyev5c475972015-12-20 16:16:56 -0800176 po::options_description optionDescription("Options");
177 optionDescription.add_options()
178 ("help,h", "produce help message")
179 ("daemon,d", po::bool_switch(&isDaemonMode)->default_value(isDaemonMode),
180 "run in daemon mode, detecting network change events and re-running "
181 "auto-discovery procedure. In addition, the auto-discovery procedure "
182 "is unconditionally re-run every hour.\n"
183 "NOTE: if connection to NFD fails, the daemon will be terminated.")
Alexander Afanasyev2a001942016-12-14 18:18:41 -0800184 ("ndn-fch-url", po::value<std::string>(&ndnFchUrl)->default_value("http://ndn-fch.named-data.net"),
185 "URL for NDN-FCH (Find Closest Hub) service")
Alexander Afanasyev5c475972015-12-20 16:16:56 -0800186 ("config,c", po::value<std::string>(&configFile), "configuration file. If `enabled = true` "
187 "is not specified, no actions will be performed.")
188 ("version,V", "show version and exit")
189 ;
190
191 po::variables_map options;
192 try {
193 po::store(po::parse_command_line(argc, argv, optionDescription), options);
194 po::notify(options);
195 }
196 catch (const std::exception& e) {
197 std::cerr << "ERROR: " << e.what() << "\n" << std::endl;
Junxiao Shi52fa45c2016-11-29 21:18:13 +0000198 NdnAutoconfig::usage(std::cerr, optionDescription, argv[0]);
Alexander Afanasyev5c475972015-12-20 16:16:56 -0800199 return 1;
200 }
201
202 if (options.count("help")) {
Junxiao Shi52fa45c2016-11-29 21:18:13 +0000203 NdnAutoconfig::usage(std::cout, optionDescription, argv[0]);
Alexander Afanasyev5c475972015-12-20 16:16:56 -0800204 return 0;
205 }
206
207 if (options.count("version")) {
208 std::cout << NFD_VERSION_BUILD_STRING << std::endl;
209 return 0;
210 }
211
212 // Enable (one-shot or daemon mode whenever config file is not specified)
213 bool isEnabled = true;
214
215 po::options_description configFileOptions;
216 configFileOptions.add_options()
217 ("enabled", po::value<bool>(&isEnabled))
218 ;
219
220 if (!configFile.empty()) {
221 isEnabled = false; // Disable by default if config file is specified
222 try {
223 po::store(po::parse_config_file<char>(configFile.c_str(), configFileOptions), options);
224 po::notify(options);
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800225 }
Alexander Afanasyev5c475972015-12-20 16:16:56 -0800226 catch (const std::exception& e) {
227 std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
228 return 1;
229 }
230 }
231
232 if (!isEnabled) {
233 return 0;
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800234 }
235
236 try {
Alexander Afanasyev2a001942016-12-14 18:18:41 -0800237 NdnAutoconfig autoConfigInstance(ndnFchUrl, isDaemonMode);
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800238 autoConfigInstance.run();
239 }
240 catch (const std::exception& error) {
241 std::cerr << "ERROR: " << error.what() << std::endl;
242 return 1;
243 }
244 return 0;
245}
Junxiao Shi52fa45c2016-11-29 21:18:13 +0000246
247} // namespace autoconfig
248} // namespace tools
249} // namespace ndn
250
251int
252main(int argc, char** argv)
253{
254 return ndn::tools::autoconfig::main(argc, argv);
255}