blob: 666cca161207daa3b66a68d1b053ba7bbedd3b17 [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"
30#include "guess-from-identity-name.hpp"
31
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -080032#include <ndn-cxx/util/network-monitor.hpp>
33#include <ndn-cxx/util/scheduler.hpp>
34#include <ndn-cxx/util/scheduler-scoped-event-id.hpp>
35
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080036#include <boost/noncopyable.hpp>
Alexander Afanasyev5c475972015-12-20 16:16:56 -080037#include <boost/program_options/options_description.hpp>
38#include <boost/program_options/variables_map.hpp>
39#include <boost/program_options/parsers.hpp>
40
41namespace po = boost::program_options;
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080042
43namespace ndn {
44namespace tools {
45
46class NdnAutoconfig : boost::noncopyable
47{
48public:
49 class Error : public std::runtime_error
50 {
51 public:
52 explicit
53 Error(const std::string& what)
54 : std::runtime_error(what)
55 {
56 }
57 };
58
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -080059 explicit
60 NdnAutoconfig(bool isDaemonMode)
61 : m_face(m_io)
62 , m_scheduler(m_io)
63 , m_startStagesEvent(m_scheduler)
64 , m_isDaemonMode(isDaemonMode)
65 , m_terminationSignalSet(m_io)
66 , m_stage1(m_face, m_keyChain,
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080067 [&] (const std::string& errorMessage) {
68 std::cerr << "Stage 1 failed: " << errorMessage << std::endl;
69 m_stage2.start();
70 })
71 , m_stage2(m_face, m_keyChain,
72 [&] (const std::string& errorMessage) {
73 std::cerr << "Stage 2 failed: " << errorMessage << std::endl;
74 m_stage3.start();
75 })
76 , m_stage3(m_face, m_keyChain,
77 [&] (const std::string& errorMessage) {
78 std::cerr << "Stage 3 failed: " << errorMessage << std::endl;
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -080079 if (!m_isDaemonMode)
Spyridon Mastorakis149e02c2015-07-27 13:22:22 -070080 BOOST_THROW_EXCEPTION(Error("No more stages, automatic discovery failed"));
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -080081 else
82 std::cerr << "No more stages, automatic discovery failed" << std::endl;
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080083 })
84 {
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -080085 if (m_isDaemonMode) {
86 m_networkMonitor.reset(new util::NetworkMonitor(m_io));
87 m_networkMonitor->onNetworkStateChanged.connect([this] {
88 // delay stages, so if multiple events are triggered in short sequence,
89 // only one auto-detection procedure is triggered
90 m_startStagesEvent = m_scheduler.scheduleEvent(time::seconds(5),
91 bind(&NdnAutoconfig::startStages, this));
92 });
93 }
94
95 // Delay a little bit
96 m_startStagesEvent = m_scheduler.scheduleEvent(time::milliseconds(100),
97 bind(&NdnAutoconfig::startStages, this));
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080098 }
99
100 void
101 run()
102 {
Alexander Afanasyevba3f79e2015-02-02 13:56:13 -0800103 if (m_isDaemonMode) {
104 m_terminationSignalSet.add(SIGINT);
105 m_terminationSignalSet.add(SIGTERM);
106 m_terminationSignalSet.async_wait(bind(&NdnAutoconfig::terminate, this, _1, _2));
107 }
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -0800108
109 m_io.run();
110 }
111
112 void
113 terminate(const boost::system::error_code& error, int signalNo)
114 {
115 if (error)
116 return;
117
118 m_io.stop();
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800119 }
120
Alexander Afanasyev5c475972015-12-20 16:16:56 -0800121
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800122 static void
Alexander Afanasyev5c475972015-12-20 16:16:56 -0800123 usage(std::ostream& os,
124 const po::options_description& optionDescription,
125 const char* programName)
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800126 {
Alexander Afanasyev5c475972015-12-20 16:16:56 -0800127 os << "Usage:\n"
128 << " " << programName << " [options]\n"
129 << "\n";
130 os << optionDescription;
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800131 }
132
133private:
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -0800134 void
135 startStages()
136 {
137 m_stage1.start();
138 if (m_isDaemonMode) {
139 m_startStagesEvent = m_scheduler.scheduleEvent(time::hours(1),
140 bind(&NdnAutoconfig::startStages, this));
141 }
142 }
143
144private:
145 boost::asio::io_service m_io;
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800146 Face m_face;
147 KeyChain m_keyChain;
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -0800148 unique_ptr<util::NetworkMonitor> m_networkMonitor;
149 util::Scheduler m_scheduler;
150 util::scheduler::ScopedEventId m_startStagesEvent;
151 bool m_isDaemonMode;
152 boost::asio::signal_set m_terminationSignalSet;
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800153
154 autoconfig::MulticastDiscovery m_stage1;
155 autoconfig::GuessFromSearchDomains m_stage2;
156 autoconfig::GuessFromIdentityName m_stage3;
157};
158
159} // namespace tools
160} // namespace ndn
161
162int
163main(int argc, char** argv)
164{
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -0800165 bool isDaemonMode = false;
Alexander Afanasyev5c475972015-12-20 16:16:56 -0800166 std::string configFile;
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800167
Alexander Afanasyev5c475972015-12-20 16:16:56 -0800168 po::options_description optionDescription("Options");
169 optionDescription.add_options()
170 ("help,h", "produce help message")
171 ("daemon,d", po::bool_switch(&isDaemonMode)->default_value(isDaemonMode),
172 "run in daemon mode, detecting network change events and re-running "
173 "auto-discovery procedure. In addition, the auto-discovery procedure "
174 "is unconditionally re-run every hour.\n"
175 "NOTE: if connection to NFD fails, the daemon will be terminated.")
176 ("config,c", po::value<std::string>(&configFile), "configuration file. If `enabled = true` "
177 "is not specified, no actions will be performed.")
178 ("version,V", "show version and exit")
179 ;
180
181 po::variables_map options;
182 try {
183 po::store(po::parse_command_line(argc, argv, optionDescription), options);
184 po::notify(options);
185 }
186 catch (const std::exception& e) {
187 std::cerr << "ERROR: " << e.what() << "\n" << std::endl;
188 ndn::tools::NdnAutoconfig::usage(std::cerr, optionDescription, argv[0]);
189 return 1;
190 }
191
192 if (options.count("help")) {
193 ndn::tools::NdnAutoconfig::usage(std::cout, optionDescription, argv[0]);
194 return 0;
195 }
196
197 if (options.count("version")) {
198 std::cout << NFD_VERSION_BUILD_STRING << std::endl;
199 return 0;
200 }
201
202 // Enable (one-shot or daemon mode whenever config file is not specified)
203 bool isEnabled = true;
204
205 po::options_description configFileOptions;
206 configFileOptions.add_options()
207 ("enabled", po::value<bool>(&isEnabled))
208 ;
209
210 if (!configFile.empty()) {
211 isEnabled = false; // Disable by default if config file is specified
212 try {
213 po::store(po::parse_config_file<char>(configFile.c_str(), configFileOptions), options);
214 po::notify(options);
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800215 }
Alexander Afanasyev5c475972015-12-20 16:16:56 -0800216 catch (const std::exception& e) {
217 std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
218 return 1;
219 }
220 }
221
222 if (!isEnabled) {
223 return 0;
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800224 }
225
226 try {
Alexander Afanasyeve46279dc2015-01-29 15:39:17 -0800227 ndn::tools::NdnAutoconfig autoConfigInstance(isDaemonMode);
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800228 autoConfigInstance.run();
229 }
230 catch (const std::exception& error) {
231 std::cerr << "ERROR: " << error.what() << std::endl;
232 return 1;
233 }
234 return 0;
235}