tools/ndn-autoconfig/main.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
26 #include "core/version.hpp"
27 
28 #include "multicast-discovery.hpp"
30 #include "ndn-fch-discovery.hpp"
32 
33 #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 
37 #include <boost/noncopyable.hpp>
38 #include <boost/program_options/options_description.hpp>
39 #include <boost/program_options/parsers.hpp>
40 #include <boost/program_options/variables_map.hpp>
41 
42 namespace po = boost::program_options;
43 
44 namespace ndn {
45 namespace tools {
46 namespace 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.
49 
50 class NdnAutoconfig : boost::noncopyable
51 {
52 public:
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 
63  explicit
64  NdnAutoconfig(const std::string& ndnFchUrl, bool isDaemonMode)
65  : 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,
71  [&] (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,
81  ndnFchUrl,
82  [&] (const std::string& errorMessage) {
83  std::cerr << "Stage 3 failed: " << errorMessage << std::endl;
84  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;
89  if (!m_isDaemonMode)
90  BOOST_THROW_EXCEPTION(Error("No more stages, automatic discovery failed"));
91  else
92  std::cerr << "No more stages, automatic discovery failed" << std::endl;
93  })
94  {
95  if (m_isDaemonMode) {
96  m_networkMonitor.reset(new ndn::util::NetworkMonitor(m_io));
97  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));
108  }
109 
110  void
111  run()
112  {
113  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  }
118 
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();
129  }
130 
131  static void
132  usage(std::ostream& os,
133  const po::options_description& optionDescription,
134  const char* programName)
135  {
136  os << "Usage:\n"
137  << " " << programName << " [options]\n"
138  << "\n";
139  os << optionDescription;
140  }
141 
142 private:
143  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 
153 private:
154  boost::asio::io_service m_io;
155  Face m_face;
156  KeyChain m_keyChain;
157  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;
162 
163  MulticastDiscovery m_stage1;
164  GuessFromSearchDomains m_stage2;
165  NdnFchDiscovery m_stage3;
166  GuessFromIdentityName m_stage4;
167 };
168 
169 static int
170 main(int argc, char** argv)
171 {
172  bool isDaemonMode = false;
173  std::string configFile;
174  std::string ndnFchUrl;
175 
176  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.")
184  ("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")
186  ("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;
198  NdnAutoconfig::usage(std::cerr, optionDescription, argv[0]);
199  return 1;
200  }
201 
202  if (options.count("help")) {
203  NdnAutoconfig::usage(std::cout, optionDescription, argv[0]);
204  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);
225  }
226  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;
234  }
235 
236  try {
237  NdnAutoconfig autoConfigInstance(ndnFchUrl, isDaemonMode);
238  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 }
246 
247 } // namespace autoconfig
248 } // namespace tools
249 } // namespace ndn
250 
251 int
252 main(int argc, char** argv)
253 {
254  return ndn::tools::autoconfig::main(argc, argv);
255 }
Copyright (c) 2014-2016, Regents of the University of California, Arizona Board of Regents...
Definition: nfd.hpp:35
static int main(int argc, char **argv)
static void usage(const char *programName)
STL namespace.
int main(int argc, char **argv)