blob: 47f73333a7e998dac6a323d1e1853ded9e7d9741 [file] [log] [blame]
Alexander Afanasyev2aa39622014-01-22 11:51:11 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoa997d292017-08-24 20:16:59 -04002/*
Davide Pesavento97e33022019-02-14 16:00:50 -05003 * Copyright (c) 2014-2019, Regents of the University of California,
Alexander Afanasyev31c781e2015-02-09 17:39:59 -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.
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070010 *
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/>.
Steve DiBenedetto3a4f83d2014-06-02 14:58:54 -060024 */
Alexander Afanasyev2aa39622014-01-22 11:51:11 -080025
Alexander Afanasyev31c781e2015-02-09 17:39:59 -080026#include "nfd.hpp"
Junxiao Shib2600172016-07-11 08:53:53 +000027#include "rib/service.hpp"
Junxiao Shi98e29f42014-03-31 10:27:26 -070028
Davide Pesavento2cae8ca2019-04-18 20:48:05 -040029#include "common/global.hpp"
30#include "common/logger.hpp"
31#include "common/privilege-helper.hpp"
Davide Pesavento59769b12017-11-12 23:52:06 -050032#include "core/version.hpp"
Alexander Afanasyev31c781e2015-02-09 17:39:59 -080033
Davide Pesaventoa3148082018-04-12 18:21:54 -040034#include <string.h> // for strsignal()
Alexander Afanasyev31c781e2015-02-09 17:39:59 -080035
Davide Pesavento47456e72018-02-25 16:21:53 -050036#include <boost/config.hpp>
Davide Pesavento97e33022019-02-14 16:00:50 -050037#include <boost/exception/diagnostic_information.hpp>
Alexander Afanasyev31c781e2015-02-09 17:39:59 -080038#include <boost/filesystem.hpp>
39#include <boost/program_options/options_description.hpp>
Alexander Afanasyev31c781e2015-02-09 17:39:59 -080040#include <boost/program_options/parsers.hpp>
Davide Pesavento59769b12017-11-12 23:52:06 -050041#include <boost/program_options/variables_map.hpp>
Davide Pesavento47456e72018-02-25 16:21:53 -050042#include <boost/version.hpp>
Alexander Afanasyevf08a7372015-02-09 21:28:19 -080043
44#include <atomic>
45#include <condition_variable>
Davide Pesaventoa997d292017-08-24 20:16:59 -040046#include <iostream>
Davide Pesavento2bdf60c2019-02-19 18:23:45 -050047#include <thread>
Alexander Afanasyevf08a7372015-02-09 21:28:19 -080048
Davide Pesaventoa3148082018-04-12 18:21:54 -040049#include <ndn-cxx/util/logging.hpp>
Davide Pesavento759db612019-08-31 22:56:28 -040050#include <ndn-cxx/util/ostream-joiner.hpp>
Davide Pesavento47456e72018-02-25 16:21:53 -050051#include <ndn-cxx/version.hpp>
Davide Pesaventoa3148082018-04-12 18:21:54 -040052
Davide Pesavento47456e72018-02-25 16:21:53 -050053#ifdef HAVE_LIBPCAP
54#include <pcap/pcap.h>
55#endif
Davide Pesavento774071c2018-11-15 21:33:23 -050056#ifdef HAVE_SYSTEMD
57#include <systemd/sd-daemon.h>
58#endif
Davide Pesavento47456e72018-02-25 16:21:53 -050059#ifdef HAVE_WEBSOCKET
60#include <websocketpp/version.hpp>
61#endif
62
Davide Pesavento59769b12017-11-12 23:52:06 -050063namespace po = boost::program_options;
Junxiao Shi09bf7c42014-01-31 11:10:25 -070064
Davide Pesaventoa3148082018-04-12 18:21:54 -040065NFD_LOG_INIT(Main);
Junxiao Shi09bf7c42014-01-31 11:10:25 -070066
Davide Pesavento59769b12017-11-12 23:52:06 -050067namespace nfd {
68
Alexander Afanasyevf08a7372015-02-09 21:28:19 -080069/** \brief Executes NFD with RIB manager
70 *
71 * NFD (main forwarding procedure) and RIB manager execute in two different threads.
Junxiao Shi71d12142016-07-23 20:10:18 +000072 * Each thread has its own instances of global io_service and global scheduler.
Alexander Afanasyevf08a7372015-02-09 21:28:19 -080073 *
74 * When either of the daemons fails, execution of non-failed daemon will be terminated as
75 * well. In other words, when NFD fails, RIB manager will be terminated; when RIB manager
76 * fails, NFD will be terminated.
77 */
Alexander Afanasyev31367922015-02-09 20:51:10 -080078class NfdRunner : noncopyable
Junxiao Shi09bf7c42014-01-31 11:10:25 -070079{
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -070080public:
Alexander Afanasyev5959b012014-06-02 19:18:12 +030081 explicit
Alexander Afanasyev31c781e2015-02-09 17:39:59 -080082 NfdRunner(const std::string& configFile)
Alexander Afanasyevf08a7372015-02-09 21:28:19 -080083 : m_nfd(configFile, m_nfdKeyChain)
84 , m_configFile(configFile)
Alexander Afanasyev31c781e2015-02-09 17:39:59 -080085 , m_terminationSignalSet(getGlobalIoService())
86 , m_reloadSignalSet(getGlobalIoService())
Alexander Afanasyev5959b012014-06-02 19:18:12 +030087 {
Alexander Afanasyev31c781e2015-02-09 17:39:59 -080088 m_terminationSignalSet.add(SIGINT);
89 m_terminationSignalSet.add(SIGTERM);
90 m_terminationSignalSet.async_wait(bind(&NfdRunner::terminate, this, _1, _2));
Alexander Afanasyev5959b012014-06-02 19:18:12 +030091
Alexander Afanasyev31c781e2015-02-09 17:39:59 -080092 m_reloadSignalSet.add(SIGHUP);
93 m_reloadSignalSet.async_wait(bind(&NfdRunner::reload, this, _1, _2));
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -070094 }
95
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -070096 void
Alexander Afanasyevf08a7372015-02-09 21:28:19 -080097 initialize()
98 {
99 m_nfd.initialize();
100 }
101
102 int
103 run()
104 {
Davide Pesavento59769b12017-11-12 23:52:06 -0500105 // Return value: a non-zero value is assigned when either NFD or RIB manager (running in
106 // a separate thread) fails.
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800107 std::atomic_int retval(0);
108
109 boost::asio::io_service* const mainIo = &getGlobalIoService();
Teng Liangf59e58f2018-09-07 16:41:54 -0700110 setMainIoService(mainIo);
Junxiao Shib2600172016-07-11 08:53:53 +0000111 boost::asio::io_service* ribIo = nullptr;
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800112
113 // Mutex and conditional variable to implement synchronization between main and RIB manager
114 // threads:
Junxiao Shib2600172016-07-11 08:53:53 +0000115 // - to block main thread until RIB manager thread starts and initializes ribIo (to allow
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800116 // stopping it later)
117 std::mutex m;
118 std::condition_variable cv;
119
Davide Pesavento2bdf60c2019-02-19 18:23:45 -0500120 std::thread ribThread([configFile = m_configFile, &retval, &ribIo, mainIo, &cv, &m] {
121 {
122 std::lock_guard<std::mutex> lock(m);
123 ribIo = &getGlobalIoService();
124 BOOST_ASSERT(ribIo != mainIo);
125 setRibIoService(ribIo);
126 }
127 cv.notify_all(); // notify that ribIo has been assigned
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800128
Davide Pesavento2bdf60c2019-02-19 18:23:45 -0500129 try {
130 ndn::KeyChain ribKeyChain;
131 // must be created inside a separate thread
132 rib::Service ribService(configFile, ribKeyChain);
133 getGlobalIoService().run(); // ribIo is not thread-safe to use here
134 }
135 catch (const std::exception& e) {
136 NFD_LOG_FATAL(boost::diagnostic_information(e));
137 retval = 1;
138 mainIo->stop();
139 }
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800140
Davide Pesavento2bdf60c2019-02-19 18:23:45 -0500141 {
142 std::lock_guard<std::mutex> lock(m);
143 ribIo = nullptr;
144 }
145 });
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800146
147 {
Junxiao Shib2600172016-07-11 08:53:53 +0000148 // Wait to guarantee that ribIo is properly initialized, so it can be used to terminate
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800149 // RIB manager thread.
150 std::unique_lock<std::mutex> lock(m);
Junxiao Shib2600172016-07-11 08:53:53 +0000151 cv.wait(lock, [&ribIo] { return ribIo != nullptr; });
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800152 }
153
154 try {
Davide Pesavento774071c2018-11-15 21:33:23 -0500155 systemdNotify("READY=1");
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800156 mainIo->run();
157 }
158 catch (const std::exception& e) {
Davide Pesavento97e33022019-02-14 16:00:50 -0500159 NFD_LOG_FATAL(boost::diagnostic_information(e));
Davide Pesavento59769b12017-11-12 23:52:06 -0500160 retval = 1;
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800161 }
162 catch (const PrivilegeHelper::Error& e) {
163 NFD_LOG_FATAL(e.what());
Davide Pesavento59769b12017-11-12 23:52:06 -0500164 retval = 4;
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800165 }
166
167 {
Junxiao Shib2600172016-07-11 08:53:53 +0000168 // ribIo is guaranteed to be alive at this point
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800169 std::lock_guard<std::mutex> lock(m);
Junxiao Shib2600172016-07-11 08:53:53 +0000170 if (ribIo != nullptr) {
171 ribIo->stop();
172 ribIo = nullptr;
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800173 }
174 }
Junxiao Shib2600172016-07-11 08:53:53 +0000175 ribThread.join();
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800176
177 return retval;
178 }
179
Davide Pesavento774071c2018-11-15 21:33:23 -0500180 static void
181 systemdNotify(const char* state)
182 {
183#ifdef HAVE_SYSTEMD
184 sd_notify(0, state);
185#endif
186 }
187
188private:
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800189 void
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800190 terminate(const boost::system::error_code& error, int signalNo)
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700191 {
192 if (error)
193 return;
Junxiao Shi09bf7c42014-01-31 11:10:25 -0700194
Davide Pesavento97e33022019-02-14 16:00:50 -0500195 NFD_LOG_INFO("Caught signal " << signalNo << " (" << ::strsignal(signalNo) << "), exiting...");
Davide Pesavento774071c2018-11-15 21:33:23 -0500196
197 systemdNotify("STOPPING=1");
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800198 getGlobalIoService().stop();
Junxiao Shiea48d8b2014-03-16 13:53:47 -0700199 }
Steve DiBenedetto84da5bf2014-03-11 14:51:29 -0600200
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300201 void
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800202 reload(const boost::system::error_code& error, int signalNo)
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300203 {
204 if (error)
205 return;
206
Davide Pesavento97e33022019-02-14 16:00:50 -0500207 NFD_LOG_INFO("Caught signal " << signalNo << " (" << ::strsignal(signalNo) << "), reloading...");
Davide Pesavento774071c2018-11-15 21:33:23 -0500208
209 systemdNotify("RELOADING=1");
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800210 m_nfd.reloadConfigFile();
Davide Pesavento774071c2018-11-15 21:33:23 -0500211 systemdNotify("READY=1");
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300212
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800213 m_reloadSignalSet.async_wait(bind(&NfdRunner::reload, this, _1, _2));
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300214 }
215
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700216private:
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800217 ndn::KeyChain m_nfdKeyChain;
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800218 Nfd m_nfd;
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800219 std::string m_configFile;
220
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800221 boost::asio::signal_set m_terminationSignalSet;
222 boost::asio::signal_set m_reloadSignalSet;
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700223};
Junxiao Shi09bf7c42014-01-31 11:10:25 -0700224
Davide Pesavento59769b12017-11-12 23:52:06 -0500225static void
Davide Pesaventoa3148082018-04-12 18:21:54 -0400226printUsage(std::ostream& os, const char* programName, const po::options_description& opts)
Davide Pesavento59769b12017-11-12 23:52:06 -0500227{
228 os << "Usage: " << programName << " [options]\n"
Davide Pesaventoa3148082018-04-12 18:21:54 -0400229 << "\n"
Davide Pesavento59769b12017-11-12 23:52:06 -0500230 << "Run the NDN Forwarding Daemon (NFD)\n"
231 << "\n"
232 << opts;
233}
234
235static void
236printLogModules(std::ostream& os)
237{
Davide Pesaventoa3148082018-04-12 18:21:54 -0400238 const auto& modules = ndn::util::Logging::getLoggerNames();
239 std::copy(modules.begin(), modules.end(), ndn::make_ostream_joiner(os, "\n"));
240 os << std::endl;
Davide Pesavento59769b12017-11-12 23:52:06 -0500241}
242
Junxiao Shi09bf7c42014-01-31 11:10:25 -0700243} // namespace nfd
244
245int
246main(int argc, char** argv)
247{
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700248 using namespace nfd;
Junxiao Shiea48d8b2014-03-16 13:53:47 -0700249
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800250 std::string configFile = DEFAULT_CONFIG_FILE;
Davide Pesavento59769b12017-11-12 23:52:06 -0500251
252 po::options_description description("Options");
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800253 description.add_options()
Davide Pesavento59769b12017-11-12 23:52:06 -0500254 ("help,h", "print this message and exit")
255 ("version,V", "show version information and exit")
256 ("config,c", po::value<std::string>(&configFile),
257 "path to configuration file (default: " DEFAULT_CONFIG_FILE ")")
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800258 ("modules,m", "list available logging modules")
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800259 ;
260
261 po::variables_map vm;
262 try {
Davide Pesavento59769b12017-11-12 23:52:06 -0500263 po::store(po::parse_command_line(argc, argv, description), vm);
Spyridon Mastorakis149e02c2015-07-27 13:22:22 -0700264 po::notify(vm);
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800265 }
266 catch (const std::exception& e) {
Davide Pesaventoa3148082018-04-12 18:21:54 -0400267 // Cannot use NFD_LOG_* macros here, because the logging subsystem is not initialized yet
268 // at this point. Moreover, we don't want to clutter error messages related to command-line
269 // parsing with timestamps and other useless text added by the macros.
Davide Pesavento59769b12017-11-12 23:52:06 -0500270 std::cerr << "ERROR: " << e.what() << "\n\n";
271 printUsage(std::cerr, argv[0], description);
272 return 2;
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700273 }
Alexander Afanasyevb47d5382014-05-05 14:35:03 -0700274
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800275 if (vm.count("help") > 0) {
Davide Pesavento59769b12017-11-12 23:52:06 -0500276 printUsage(std::cout, argv[0], description);
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700277 return 0;
278 }
279
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800280 if (vm.count("version") > 0) {
Alexander Afanasyevb47d5382014-05-05 14:35:03 -0700281 std::cout << NFD_VERSION_BUILD_STRING << std::endl;
282 return 0;
283 }
284
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800285 if (vm.count("modules") > 0) {
Davide Pesavento59769b12017-11-12 23:52:06 -0500286 printLogModules(std::cout);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600287 return 0;
288 }
289
Davide Pesavento47456e72018-02-25 16:21:53 -0500290 const std::string boostBuildInfo =
291 "with Boost version " + to_string(BOOST_VERSION / 100000) +
292 "." + to_string(BOOST_VERSION / 100 % 1000) +
293 "." + to_string(BOOST_VERSION % 100);
294 const std::string pcapBuildInfo =
295#ifdef HAVE_LIBPCAP
296 "with " + std::string(pcap_lib_version());
297#else
298 "without libpcap";
299#endif
300 const std::string wsBuildInfo =
301#ifdef HAVE_WEBSOCKET
302 "with WebSocket++ version " + to_string(websocketpp::major_version) +
303 "." + to_string(websocketpp::minor_version) +
304 "." + to_string(websocketpp::patch_version);
305#else
306 "without WebSocket++";
307#endif
308
Davide Pesavento03f45d22019-04-04 12:34:26 -0400309 std::clog << "NFD version " << NFD_VERSION_BUILD_STRING << " starting\n"
Davide Pesaventoa3148082018-04-12 18:21:54 -0400310 << "Built with " BOOST_COMPILER ", with " BOOST_STDLIB
Davide Pesavento47456e72018-02-25 16:21:53 -0500311 ", " << boostBuildInfo <<
312 ", " << pcapBuildInfo <<
313 ", " << wsBuildInfo <<
Davide Pesaventoa3148082018-04-12 18:21:54 -0400314 ", with ndn-cxx version " NDN_CXX_VERSION_BUILD_STRING
315 << std::endl;
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600316
Davide Pesavento59769b12017-11-12 23:52:06 -0500317 NfdRunner runner(configFile);
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700318 try {
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800319 runner.initialize();
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700320 }
Alexander Afanasyev31c781e2015-02-09 17:39:59 -0800321 catch (const boost::filesystem::filesystem_error& e) {
Davide Pesavento97e33022019-02-14 16:00:50 -0500322 NFD_LOG_FATAL(boost::diagnostic_information(e));
323 return e.code() == boost::system::errc::permission_denied ? 4 : 1;
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600324 }
325 catch (const std::exception& e) {
Davide Pesavento97e33022019-02-14 16:00:50 -0500326 NFD_LOG_FATAL(boost::diagnostic_information(e));
Davide Pesavento59769b12017-11-12 23:52:06 -0500327 return 1;
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700328 }
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600329 catch (const PrivilegeHelper::Error& e) {
330 // PrivilegeHelper::Errors do not inherit from std::exception
331 // and represent seteuid/gid failures
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600332 NFD_LOG_FATAL(e.what());
Davide Pesavento59769b12017-11-12 23:52:06 -0500333 return 4;
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600334 }
335
Alexander Afanasyevf08a7372015-02-09 21:28:19 -0800336 return runner.run();
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700337}