blob: b85556c8288d106aa8b8d298f2db275ba2a577ef [file] [log] [blame]
Davide Pesavento35185332019-01-14 04:00:15 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Eric Newberryc8e18582018-05-31 19:27:01 -07002/*
Davide Pesavento92669062022-03-10 19:09:44 -05003 * Copyright (c) 2014-2022, Arizona Board of Regents.
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -08004 *
Davide Pesaventod0b59982015-02-27 19:15:15 +01005 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080017 *
18 * Author: Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
19 */
20
Davide Pesavento35185332019-01-14 04:00:15 -050021#include "util.hpp"
Eric Newberryc8e18582018-05-31 19:27:01 -070022
Davide Pesavento35185332019-01-14 04:00:15 -050023#include <ndn-cxx/data.hpp>
Eric Newberryc8e18582018-05-31 19:27:01 -070024#include <ndn-cxx/face.hpp>
25#include <ndn-cxx/security/key-chain.hpp>
26#include <ndn-cxx/security/signing-info.hpp>
27#include <ndn-cxx/util/backports.hpp>
Davide Pesavento35185332019-01-14 04:00:15 -050028#include <ndn-cxx/util/random.hpp>
29
Davide Pesavento35185332019-01-14 04:00:15 -050030#include <limits>
31#include <sstream>
32#include <vector>
jeraldabraham420dbf02014-04-25 22:58:31 -070033
Davide Pesaventod0b59982015-02-27 19:15:15 +010034#include <boost/asio/io_service.hpp>
35#include <boost/asio/signal_set.hpp>
jeraldabraham420dbf02014-04-25 22:58:31 -070036#include <boost/noncopyable.hpp>
Davide Pesavento35185332019-01-14 04:00:15 -050037#include <boost/program_options/options_description.hpp>
38#include <boost/program_options/parsers.hpp>
39#include <boost/program_options/variables_map.hpp>
40#include <boost/thread/thread.hpp>
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080041
Davide Pesavento35185332019-01-14 04:00:15 -050042namespace po = boost::program_options;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080043
44namespace ndn {
45
jeraldabraham420dbf02014-04-25 22:58:31 -070046class NdnTrafficServer : boost::noncopyable
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080047{
48public:
jeraldabrahamcc3c6c92014-03-28 02:21:45 -070049 explicit
Davide Pesavento35185332019-01-14 04:00:15 -050050 NdnTrafficServer(const std::string& configFile)
51 : m_signalSet(m_ioService, SIGINT, SIGTERM)
52 , m_logger("NdnTrafficServer")
jeraldabrahamcc3c6c92014-03-28 02:21:45 -070053 , m_face(m_ioService)
Davide Pesavento35185332019-01-14 04:00:15 -050054 , m_configurationFile(configFile)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080055 {
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080056 }
57
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080058 void
Davide Pesavento35185332019-01-14 04:00:15 -050059 setMaximumInterests(uint64_t maxInterests)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080060 {
Davide Pesavento35185332019-01-14 04:00:15 -050061 m_nMaximumInterests = maxInterests;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080062 }
63
64 void
Davide Pesavento35185332019-01-14 04:00:15 -050065 setContentDelay(time::milliseconds delay)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080066 {
Davide Pesavento35185332019-01-14 04:00:15 -050067 BOOST_ASSERT(delay >= 0_ms);
68 m_contentDelay = delay;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080069 }
70
71 void
jeraldabraham420dbf02014-04-25 22:58:31 -070072 setQuietLogging()
73 {
Davide Pesavento35185332019-01-14 04:00:15 -050074 m_wantQuiet = true;
jeraldabraham420dbf02014-04-25 22:58:31 -070075 }
76
Davide Pesavento306e5bc2019-01-26 16:20:34 -050077 int
Davide Pesavento35185332019-01-14 04:00:15 -050078 run()
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080079 {
Davide Pesavento35185332019-01-14 04:00:15 -050080 m_logger.initializeLog(to_string(random::generateWord32()));
Davide Pesavento306e5bc2019-01-26 16:20:34 -050081
82 if (!readConfigurationFile(m_configurationFile, m_trafficPatterns, m_logger)) {
83 return 2;
84 }
85
86 if (!checkTrafficPatternCorrectness()) {
87 m_logger.log("ERROR: Traffic configuration provided is not proper", false, true);
88 return 2;
89 }
90
91 m_logger.log("Traffic configuration file processing completed.\n", true, false);
92 for (std::size_t i = 0; i < m_trafficPatterns.size(); i++) {
93 m_logger.log("Traffic Pattern Type #" + to_string(i + 1), false, false);
94 m_trafficPatterns[i].printTrafficConfiguration(m_logger);
95 m_logger.log("", false, false);
96 }
Davide Pesaventod0b59982015-02-27 19:15:15 +010097
Davide Pesavento35185332019-01-14 04:00:15 -050098 if (m_nMaximumInterests == 0) {
99 logStatistics();
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500100 return 0;
Davide Pesavento35185332019-01-14 04:00:15 -0500101 }
Davide Pesaventod0b59982015-02-27 19:15:15 +0100102
Davide Pesavento35185332019-01-14 04:00:15 -0500103 m_signalSet.async_wait([this] (const boost::system::error_code&, int) {
104 if (m_nMaximumInterests && m_nInterestsReceived < *m_nMaximumInterests) {
105 m_hasError = true;
106 }
107 stop();
108 });
109
110 for (std::size_t id = 0; id < m_trafficPatterns.size(); id++) {
111 m_registeredPrefixes.push_back(
112 m_face.setInterestFilter(m_trafficPatterns[id].m_name,
113 [=] (auto&&, const auto& interest) { this->onInterest(interest, id); },
114 nullptr,
115 [=] (auto&&, const auto& reason) { this->onRegisterFailed(reason, id); }));
116 }
117
118 try {
119 m_face.processEvents();
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500120 return m_hasError ? 1 : 0;
Davide Pesavento35185332019-01-14 04:00:15 -0500121 }
122 catch (const std::exception& e) {
123 m_logger.log("ERROR: "s + e.what(), true, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500124 m_ioService.stop();
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500125 return 1;
Davide Pesavento35185332019-01-14 04:00:15 -0500126 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800127 }
128
Davide Pesavento35185332019-01-14 04:00:15 -0500129private:
130 class DataTrafficConfiguration
131 {
132 public:
133 void
134 printTrafficConfiguration(Logger& logger) const
135 {
136 std::ostringstream os;
137
138 if (!m_name.empty()) {
139 os << "Name=" << m_name << ", ";
140 }
141 if (m_contentDelay >= 0_ms) {
142 os << "ContentDelay=" << m_contentDelay.count() << ", ";
143 }
144 if (m_freshnessPeriod >= 0_ms) {
145 os << "FreshnessPeriod=" << m_freshnessPeriod.count() << ", ";
146 }
147 if (m_contentType) {
148 os << "ContentType=" << *m_contentType << ", ";
149 }
150 if (m_contentLength) {
151 os << "ContentBytes=" << *m_contentLength << ", ";
152 }
153 if (!m_content.empty()) {
154 os << "Content=" << m_content << ", ";
155 }
156 os << "SigningInfo=" << m_signingInfo;
157
158 logger.log(os.str(), false, false);
159 }
160
161 bool
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500162 parseConfigurationLine(const std::string& line, Logger& logger, int lineNumber)
Davide Pesavento35185332019-01-14 04:00:15 -0500163 {
164 std::string parameter, value;
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500165 if (!extractParameterAndValue(line, parameter, value)) {
166 logger.log("Line " + to_string(lineNumber) + " - Invalid syntax: " + line,
167 false, true);
168 return false;
169 }
170
171 if (parameter == "Name") {
172 m_name = value;
173 }
174 else if (parameter == "ContentDelay") {
175 m_contentDelay = time::milliseconds(std::stoul(value));
176 }
177 else if (parameter == "FreshnessPeriod") {
178 m_freshnessPeriod = time::milliseconds(std::stoul(value));
179 }
180 else if (parameter == "ContentType") {
181 m_contentType = std::stoul(value);
182 }
183 else if (parameter == "ContentBytes") {
184 m_contentLength = std::stoul(value);
185 }
186 else if (parameter == "Content") {
187 m_content = value;
188 }
189 else if (parameter == "SigningInfo") {
190 m_signingInfo = security::SigningInfo(value);
Davide Pesavento35185332019-01-14 04:00:15 -0500191 }
192 else {
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500193 logger.log("Line " + to_string(lineNumber) + " - Ignoring unknown parameter: " + parameter,
194 false, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500195 }
196 return true;
197 }
198
199 bool
200 checkTrafficDetailCorrectness() const
201 {
202 return true;
203 }
204
205 public:
206 std::string m_name;
207 time::milliseconds m_contentDelay = -1_ms;
208 time::milliseconds m_freshnessPeriod = -1_ms;
209 optional<uint32_t> m_contentType;
210 optional<std::size_t> m_contentLength;
211 std::string m_content;
212 security::SigningInfo m_signingInfo;
213 uint64_t m_nInterestsReceived = 0;
214 };
215
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800216 void
217 logStatistics()
218 {
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800219 m_logger.log("\n\n== Interest Traffic Report ==\n", false, true);
Alexander Afanasyevfda32a32014-03-20 10:50:00 -0700220 m_logger.log("Total Traffic Pattern Types = " +
Spencer Lee8e990232015-11-27 03:54:39 -0700221 to_string(m_trafficPatterns.size()), false, true);
Alexander Afanasyevfda32a32014-03-20 10:50:00 -0700222 m_logger.log("Total Interests Received = " +
Spencer Lee8e990232015-11-27 03:54:39 -0700223 to_string(m_nInterestsReceived), false, true);
Davide Pesaventod0b59982015-02-27 19:15:15 +0100224
Eric Newberryc8e18582018-05-31 19:27:01 -0700225 for (std::size_t patternId = 0; patternId < m_trafficPatterns.size(); patternId++) {
226 m_logger.log("\nTraffic Pattern Type #" + to_string(patternId + 1), false, true);
227 m_trafficPatterns[patternId].printTrafficConfiguration(m_logger);
Davide Pesavento35185332019-01-14 04:00:15 -0500228 m_logger.log("Total Interests Received = " +
229 to_string(m_trafficPatterns[patternId].m_nInterestsReceived) + "\n", false, true);
Eric Newberryc8e18582018-05-31 19:27:01 -0700230 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800231 }
232
233 bool
Davide Pesavento35185332019-01-14 04:00:15 -0500234 checkTrafficPatternCorrectness() const
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800235 {
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500236 // TODO
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800237 return true;
238 }
239
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800240 static std::string
Davide Pesavento35185332019-01-14 04:00:15 -0500241 getRandomByteString(std::size_t length)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800242 {
Davide Pesavento35185332019-01-14 04:00:15 -0500243 // per ISO C++ std, cannot instantiate uniform_int_distribution with char
244 static std::uniform_int_distribution<short> dist(std::numeric_limits<char>::min(),
245 std::numeric_limits<char>::max());
246
247 std::string s;
248 s.reserve(length);
249 for (std::size_t i = 0; i < length; i++) {
250 s += static_cast<char>(dist(random::getRandomNumberEngine()));
Eric Newberryc8e18582018-05-31 19:27:01 -0700251 }
Davide Pesavento35185332019-01-14 04:00:15 -0500252 return s;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800253 }
254
255 void
Davide Pesavento35185332019-01-14 04:00:15 -0500256 onInterest(const Interest& interest, std::size_t patternId)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800257 {
Spencer Leee7a5b742015-10-29 02:18:11 -0700258 auto& pattern = m_trafficPatterns[patternId];
259
Davide Pesavento35185332019-01-14 04:00:15 -0500260 if (!m_nMaximumInterests || m_nInterestsReceived < *m_nMaximumInterests) {
Eric Newberryc8e18582018-05-31 19:27:01 -0700261 Data data(interest.getName());
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800262
Davide Pesavento35185332019-01-14 04:00:15 -0500263 if (pattern.m_freshnessPeriod >= 0_ms)
Eric Newberryc8e18582018-05-31 19:27:01 -0700264 data.setFreshnessPeriod(pattern.m_freshnessPeriod);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700265
Davide Pesavento35185332019-01-14 04:00:15 -0500266 if (pattern.m_contentType)
267 data.setContentType(*pattern.m_contentType);
268
Eric Newberryc8e18582018-05-31 19:27:01 -0700269 std::string content;
Davide Pesavento35185332019-01-14 04:00:15 -0500270 if (pattern.m_contentLength > 0)
271 content = getRandomByteString(*pattern.m_contentLength);
Eric Newberryc8e18582018-05-31 19:27:01 -0700272 if (!pattern.m_content.empty())
273 content = pattern.m_content;
Davide Pesavento92669062022-03-10 19:09:44 -0500274 data.setContent(makeStringBlock(tlv::Content, content));
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700275
Eric Newberryc8e18582018-05-31 19:27:01 -0700276 m_keyChain.sign(data, pattern.m_signingInfo);
Spencer Leee7a5b742015-10-29 02:18:11 -0700277
Eric Newberryc8e18582018-05-31 19:27:01 -0700278 m_nInterestsReceived++;
279 pattern.m_nInterestsReceived++;
Davide Pesaventod0b59982015-02-27 19:15:15 +0100280
Davide Pesavento35185332019-01-14 04:00:15 -0500281 if (!m_wantQuiet) {
282 auto logLine = "Interest received - PatternType=" + to_string(patternId + 1) +
283 ", GlobalID=" + to_string(m_nInterestsReceived) +
284 ", LocalID=" + to_string(pattern.m_nInterestsReceived) +
285 ", Name=" + pattern.m_name;
Eric Newberryc8e18582018-05-31 19:27:01 -0700286 m_logger.log(logLine, true, false);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700287 }
Eric Newberryc8e18582018-05-31 19:27:01 -0700288
Davide Pesavento35185332019-01-14 04:00:15 -0500289 if (pattern.m_contentDelay > 0_ms)
290 boost::this_thread::sleep_for(pattern.m_contentDelay);
291 if (m_contentDelay > 0_ms)
292 boost::this_thread::sleep_for(m_contentDelay);
293
Eric Newberryc8e18582018-05-31 19:27:01 -0700294 m_face.put(data);
295 }
Davide Pesavento35185332019-01-14 04:00:15 -0500296
297 if (m_nMaximumInterests && m_nInterestsReceived >= *m_nMaximumInterests) {
Eric Newberryc8e18582018-05-31 19:27:01 -0700298 logStatistics();
Davide Pesavento35185332019-01-14 04:00:15 -0500299 m_registeredPrefixes.clear();
Eric Newberry51459402018-06-28 00:06:18 -0700300 m_signalSet.cancel();
Eric Newberryc8e18582018-05-31 19:27:01 -0700301 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800302 }
303
304 void
Davide Pesavento35185332019-01-14 04:00:15 -0500305 onRegisterFailed(const std::string& reason, std::size_t patternId)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800306 {
Davide Pesavento35185332019-01-14 04:00:15 -0500307 auto logLine = "Prefix registration failed - PatternType=" + to_string(patternId + 1) +
308 ", Name=" + m_trafficPatterns[patternId].m_name +
309 ", Reason=" + reason;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800310 m_logger.log(logLine, true, true);
Davide Pesaventod0b59982015-02-27 19:15:15 +0100311
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700312 m_nRegistrationsFailed++;
Eric Newberryc8e18582018-05-31 19:27:01 -0700313 if (m_nRegistrationsFailed == m_trafficPatterns.size()) {
314 m_hasError = true;
Davide Pesavento35185332019-01-14 04:00:15 -0500315 stop();
Eric Newberryc8e18582018-05-31 19:27:01 -0700316 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800317 }
318
319 void
Davide Pesavento35185332019-01-14 04:00:15 -0500320 stop()
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800321 {
Davide Pesavento35185332019-01-14 04:00:15 -0500322 logStatistics();
323 m_face.shutdown();
324 m_ioService.stop();
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800325 }
326
327private:
Alexander Afanasyev976c3972014-05-26 17:03:40 +0300328 boost::asio::io_service m_ioService;
Eric Newberry51459402018-06-28 00:06:18 -0700329 boost::asio::signal_set m_signalSet;
Davide Pesavento35185332019-01-14 04:00:15 -0500330 Logger m_logger;
331 Face m_face;
332 KeyChain m_keyChain;
333
334 std::string m_configurationFile;
335 optional<uint64_t> m_nMaximumInterests;
336 time::milliseconds m_contentDelay = 0_ms;
337 bool m_wantQuiet = false;
338
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700339 std::vector<DataTrafficConfiguration> m_trafficPatterns;
Davide Pesavento35185332019-01-14 04:00:15 -0500340 std::vector<ScopedRegisteredPrefixHandle> m_registeredPrefixes;
341 uint64_t m_nRegistrationsFailed = 0;
342 uint64_t m_nInterestsReceived = 0;
343 bool m_hasError = false;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800344};
345
346} // namespace ndn
347
Davide Pesavento35185332019-01-14 04:00:15 -0500348static void
349usage(std::ostream& os, const std::string& programName, const po::options_description& desc)
350{
351 os << "Usage: " << programName << " [options] <Traffic_Configuration_File>\n"
352 << "\n"
353 << "Respond to Interests as per provided Traffic_Configuration_File.\n"
354 << "Multiple prefixes can be configured for handling.\n"
355 << "Set the environment variable NDN_TRAFFIC_LOGFOLDER to redirect output to a log file.\n"
356 << "\n"
357 << desc;
358}
359
Alexander Afanasyevfda32a32014-03-20 10:50:00 -0700360int
361main(int argc, char* argv[])
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800362{
Davide Pesavento35185332019-01-14 04:00:15 -0500363 std::string configFile;
Davide Pesaventod0b59982015-02-27 19:15:15 +0100364
Davide Pesavento35185332019-01-14 04:00:15 -0500365 po::options_description visibleOptions("Options");
366 visibleOptions.add_options()
367 ("help,h", "print this help message and exit")
368 ("count,c", po::value<int>(), "maximum number of Interests to respond to")
369 ("delay,d", po::value<ndn::time::milliseconds::rep>()->default_value(0),
370 "wait this amount of milliseconds before responding to each Interest")
371 ("quiet,q", po::bool_switch(), "turn off logging of Interest reception/Data generation")
372 ;
373
374 po::options_description hiddenOptions;
375 hiddenOptions.add_options()
376 ("config-file", po::value<std::string>(&configFile))
377 ;
378
379 po::positional_options_description posOptions;
380 posOptions.add("config-file", -1);
381
382 po::options_description allOptions;
383 allOptions.add(visibleOptions).add(hiddenOptions);
384
385 po::variables_map vm;
386 try {
387 po::store(po::command_line_parser(argc, argv).options(allOptions).positional(posOptions).run(), vm);
388 po::notify(vm);
389 }
390 catch (const po::error& e) {
391 std::cerr << "ERROR: " << e.what() << std::endl;
392 return 2;
393 }
394 catch (const boost::bad_any_cast& e) {
395 std::cerr << "ERROR: " << e.what() << std::endl;
396 return 2;
397 }
398
399 if (vm.count("help") > 0) {
400 usage(std::cout, argv[0], visibleOptions);
401 return 0;
402 }
403
404 if (configFile.empty()) {
405 usage(std::cerr, argv[0], visibleOptions);
406 return 2;
407 }
408
409 ndn::NdnTrafficServer server(configFile);
410
411 if (vm.count("count") > 0) {
412 int count = vm["count"].as<int>();
413 if (count < 0) {
414 std::cerr << "ERROR: the argument for option '--count' cannot be negative" << std::endl;
415 return 2;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800416 }
Davide Pesavento35185332019-01-14 04:00:15 -0500417 server.setMaximumInterests(static_cast<uint64_t>(count));
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800418 }
419
Davide Pesavento35185332019-01-14 04:00:15 -0500420 if (vm.count("delay") > 0) {
421 ndn::time::milliseconds delay(vm["delay"].as<ndn::time::milliseconds::rep>());
422 if (delay < ndn::time::milliseconds::zero()) {
423 std::cerr << "ERROR: the argument for option '--delay' cannot be negative" << std::endl;
424 return 2;
425 }
426 server.setContentDelay(delay);
Eric Newberryc8e18582018-05-31 19:27:01 -0700427 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800428
Davide Pesavento35185332019-01-14 04:00:15 -0500429 if (vm["quiet"].as<bool>()) {
430 server.setQuietLogging();
431 }
432
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500433 return server.run();
Eric Newberryc8e18582018-05-31 19:27:01 -0700434}