blob: fd5d1edd8446cbc82bc85b22261543e3bfd81280 [file] [log] [blame]
Davide Pesavento912d2e82019-01-10 17:04:31 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
Davide Pesavento84e77302023-04-17 01:10:06 -04003 * Copyright (c) 2014-2023, 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"
22
Davide Pesaventoef064892022-04-05 02:26:03 -040023#include <ndn-cxx/data.hpp>
Davide Pesavento35185332019-01-14 04:00:15 -050024#include <ndn-cxx/face.hpp>
Davide Pesaventoef064892022-04-05 02:26:03 -040025#include <ndn-cxx/interest.hpp>
Davide Pesavento35185332019-01-14 04:00:15 -050026#include <ndn-cxx/lp/tags.hpp>
Davide Pesavento35185332019-01-14 04:00:15 -050027#include <ndn-cxx/util/random.hpp>
Davide Pesaventoef064892022-04-05 02:26:03 -040028#include <ndn-cxx/util/time.hpp>
Davide Pesavento912d2e82019-01-10 17:04:31 -050029
Davide Pesavento35185332019-01-14 04:00:15 -050030#include <limits>
Davide Pesaventoef064892022-04-05 02:26:03 -040031#include <optional>
Davide Pesavento56f79d62019-01-26 17:30:32 -050032#include <sstream>
Davide Pesaventoef064892022-04-05 02:26:03 -040033#include <string_view>
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080034#include <vector>
35
Davide Pesavento912d2e82019-01-10 17:04:31 -050036#include <boost/asio/deadline_timer.hpp>
37#include <boost/asio/io_service.hpp>
38#include <boost/asio/signal_set.hpp>
jeraldabraham420dbf02014-04-25 22:58:31 -070039#include <boost/date_time/posix_time/posix_time.hpp>
Davide Pesavento912d2e82019-01-10 17:04:31 -050040#include <boost/lexical_cast.hpp>
jeraldabraham420dbf02014-04-25 22:58:31 -070041#include <boost/noncopyable.hpp>
Davide Pesavento35185332019-01-14 04:00:15 -050042#include <boost/program_options/options_description.hpp>
43#include <boost/program_options/parsers.hpp>
44#include <boost/program_options/variables_map.hpp>
jeraldabraham420dbf02014-04-25 22:58:31 -070045
Davide Pesaventoef064892022-04-05 02:26:03 -040046using namespace ndn::time_literals;
47using namespace std::string_literals;
jeraldabraham420dbf02014-04-25 22:58:31 -070048
Davide Pesaventoef064892022-04-05 02:26:03 -040049namespace ndntg {
50
51namespace time = ndn::time;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080052
jeraldabraham420dbf02014-04-25 22:58:31 -070053class NdnTrafficClient : boost::noncopyable
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080054{
55public:
jeraldabrahamcc3c6c92014-03-28 02:21:45 -070056 explicit
Davide Pesavento35185332019-01-14 04:00:15 -050057 NdnTrafficClient(const std::string& configFile)
58 : m_signalSet(m_ioService, SIGINT, SIGTERM)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -070059 , m_logger("NdnTrafficClient")
Alexander Afanasyev740812e2014-10-30 15:37:45 -070060 , m_face(m_ioService)
Davide Pesavento35185332019-01-14 04:00:15 -050061 , m_configurationFile(configFile)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080062 {
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080063 }
64
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080065 void
Davide Pesavento35185332019-01-14 04:00:15 -050066 setMaximumInterests(uint64_t maxInterests)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080067 {
Davide Pesavento35185332019-01-14 04:00:15 -050068 m_nMaximumInterests = maxInterests;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080069 }
70
71 void
Davide Pesavento35185332019-01-14 04:00:15 -050072 setInterestInterval(time::milliseconds interval)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080073 {
Davide Pesavento35185332019-01-14 04:00:15 -050074 BOOST_ASSERT(interval > 0_ms);
75 m_interestInterval = interval;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080076 }
77
78 void
jeraldabraham420dbf02014-04-25 22:58:31 -070079 setQuietLogging()
80 {
Davide Pesavento35185332019-01-14 04:00:15 -050081 m_wantQuiet = true;
jeraldabraham420dbf02014-04-25 22:58:31 -070082 }
83
Davide Pesavento306e5bc2019-01-26 16:20:34 -050084 int
Davide Pesavento35185332019-01-14 04:00:15 -050085 run()
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080086 {
Davide Pesaventoef064892022-04-05 02:26:03 -040087 m_logger.initializeLog(std::to_string(ndn::random::generateWord32()));
Davide Pesavento306e5bc2019-01-26 16:20:34 -050088
89 if (!readConfigurationFile(m_configurationFile, m_trafficPatterns, m_logger)) {
90 return 2;
91 }
92
93 if (!checkTrafficPatternCorrectness()) {
94 m_logger.log("ERROR: Traffic configuration provided is not proper", false, true);
95 return 2;
96 }
97
98 m_logger.log("Traffic configuration file processing completed.\n", true, false);
99 for (std::size_t i = 0; i < m_trafficPatterns.size(); i++) {
Davide Pesaventoef064892022-04-05 02:26:03 -0400100 m_logger.log("Traffic Pattern Type #" + std::to_string(i + 1), false, false);
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500101 m_trafficPatterns[i].printTrafficConfiguration(m_logger);
102 m_logger.log("", false, false);
103 }
Davide Pesaventod0b59982015-02-27 19:15:15 +0100104
Davide Pesavento35185332019-01-14 04:00:15 -0500105 if (m_nMaximumInterests == 0) {
106 logStatistics();
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500107 return 0;
Davide Pesavento35185332019-01-14 04:00:15 -0500108 }
Davide Pesaventod0b59982015-02-27 19:15:15 +0100109
Davide Pesaventoef064892022-04-05 02:26:03 -0400110 m_signalSet.async_wait([this] (auto&&...) { stop(); });
Davide Pesavento35185332019-01-14 04:00:15 -0500111
112 boost::asio::deadline_timer timer(m_ioService,
113 boost::posix_time::millisec(m_interestInterval.count()));
Davide Pesaventoef064892022-04-05 02:26:03 -0400114 timer.async_wait([this, &timer] (auto&&...) { generateTraffic(timer); });
Davide Pesavento35185332019-01-14 04:00:15 -0500115
116 try {
117 m_face.processEvents();
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500118 return m_hasError ? 1 : 0;
Davide Pesavento35185332019-01-14 04:00:15 -0500119 }
120 catch (const std::exception& e) {
121 m_logger.log("ERROR: "s + e.what(), true, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500122 m_ioService.stop();
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500123 return 1;
Davide Pesavento35185332019-01-14 04:00:15 -0500124 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800125 }
126
Davide Pesavento35185332019-01-14 04:00:15 -0500127private:
128 class InterestTrafficConfiguration
129 {
130 public:
131 void
132 printTrafficConfiguration(Logger& logger) const
133 {
Davide Pesavento56f79d62019-01-26 17:30:32 -0500134 std::ostringstream os;
Davide Pesavento35185332019-01-14 04:00:15 -0500135
Davide Pesavento56f79d62019-01-26 17:30:32 -0500136 os << "TrafficPercentage=" << m_trafficPercentage << ", ";
137 os << "Name=" << m_name << ", ";
138 if (m_nameAppendBytes) {
139 os << "NameAppendBytes=" << *m_nameAppendBytes << ", ";
140 }
141 if (m_nameAppendSeqNum) {
142 os << "NameAppendSequenceNumber=" << *m_nameAppendSeqNum << ", ";
143 }
144 if (m_canBePrefix) {
145 os << "CanBePrefix=" << m_canBePrefix << ", ";
146 }
147 if (m_mustBeFresh) {
148 os << "MustBeFresh=" << m_mustBeFresh << ", ";
149 }
150 if (m_nonceDuplicationPercentage > 0) {
151 os << "NonceDuplicationPercentage=" << m_nonceDuplicationPercentage << ", ";
152 }
153 if (m_interestLifetime >= 0_ms) {
154 os << "InterestLifetime=" << m_interestLifetime.count() << ", ";
155 }
156 if (m_nextHopFaceId > 0) {
157 os << "NextHopFaceId=" << m_nextHopFaceId << ", ";
158 }
159 if (m_expectedContent) {
160 os << "ExpectedContent=" << *m_expectedContent << ", ";
161 }
Davide Pesavento35185332019-01-14 04:00:15 -0500162
Davide Pesavento56f79d62019-01-26 17:30:32 -0500163 auto str = os.str();
164 str = str.substr(0, str.length() - 2); // remove suffix ", "
165 logger.log(str, false, false);
Davide Pesavento35185332019-01-14 04:00:15 -0500166 }
167
168 bool
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500169 parseConfigurationLine(const std::string& line, Logger& logger, int lineNumber)
Davide Pesavento35185332019-01-14 04:00:15 -0500170 {
171 std::string parameter, value;
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500172 if (!extractParameterAndValue(line, parameter, value)) {
Davide Pesaventoef064892022-04-05 02:26:03 -0400173 logger.log("Line " + std::to_string(lineNumber) + " - Invalid syntax: " + line,
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500174 false, true);
175 return false;
176 }
177
178 if (parameter == "TrafficPercentage") {
179 m_trafficPercentage = std::stoul(value);
180 }
181 else if (parameter == "Name") {
182 m_name = value;
183 }
184 else if (parameter == "NameAppendBytes") {
185 m_nameAppendBytes = std::stoul(value);
186 }
187 else if (parameter == "NameAppendSequenceNumber") {
188 m_nameAppendSeqNum = std::stoull(value);
189 }
Davide Pesavento56f79d62019-01-26 17:30:32 -0500190 else if (parameter == "CanBePrefix") {
191 m_canBePrefix = parseBoolean(value);
192 }
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500193 else if (parameter == "MustBeFresh") {
194 m_mustBeFresh = parseBoolean(value);
195 }
196 else if (parameter == "NonceDuplicationPercentage") {
197 m_nonceDuplicationPercentage = std::stoul(value);
198 }
199 else if (parameter == "InterestLifetime") {
200 m_interestLifetime = time::milliseconds(std::stoul(value));
201 }
202 else if (parameter == "NextHopFaceId") {
203 m_nextHopFaceId = std::stoull(value);
204 }
205 else if (parameter == "ExpectedContent") {
206 m_expectedContent = value;
Davide Pesavento35185332019-01-14 04:00:15 -0500207 }
208 else {
Davide Pesaventoef064892022-04-05 02:26:03 -0400209 logger.log("Line " + std::to_string(lineNumber) + " - Ignoring unknown parameter: " + parameter,
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500210 false, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500211 }
212 return true;
213 }
214
215 bool
216 checkTrafficDetailCorrectness() const
217 {
218 return true;
219 }
220
221 public:
222 uint8_t m_trafficPercentage = 0;
223 std::string m_name;
Davide Pesaventoef064892022-04-05 02:26:03 -0400224 std::optional<std::size_t> m_nameAppendBytes;
225 std::optional<uint64_t> m_nameAppendSeqNum;
Davide Pesavento56f79d62019-01-26 17:30:32 -0500226 bool m_canBePrefix = false;
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500227 bool m_mustBeFresh = false;
Davide Pesavento35185332019-01-14 04:00:15 -0500228 uint8_t m_nonceDuplicationPercentage = 0;
229 time::milliseconds m_interestLifetime = -1_ms;
230 uint64_t m_nextHopFaceId = 0;
Davide Pesaventoef064892022-04-05 02:26:03 -0400231 std::optional<std::string> m_expectedContent;
Davide Pesavento35185332019-01-14 04:00:15 -0500232
233 uint64_t m_nInterestsSent = 0;
234 uint64_t m_nInterestsReceived = 0;
235 uint64_t m_nNacks = 0;
236 uint64_t m_nContentInconsistencies = 0;
237
238 // RTT is stored as milliseconds with fractional sub-milliseconds precision
239 double m_minimumInterestRoundTripTime = std::numeric_limits<double>::max();
240 double m_maximumInterestRoundTripTime = 0;
241 double m_totalInterestRoundTripTime = 0;
242 };
243
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800244 void
245 logStatistics()
246 {
Davide Pesavento84e77302023-04-17 01:10:06 -0400247 using std::to_string;
248
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800249 m_logger.log("\n\n== Interest Traffic Report ==\n", false, true);
Davide Pesavento84e77302023-04-17 01:10:06 -0400250 m_logger.log("Total Traffic Pattern Types = " + to_string(m_trafficPatterns.size()), false, true);
251 m_logger.log("Total Interests Sent = " + to_string(m_nInterestsSent), false, true);
252 m_logger.log("Total Responses Received = " + to_string(m_nInterestsReceived), false, true);
253 m_logger.log("Total Nacks Received = " + to_string(m_nNacks), false, true);
Davide Pesaventod0b59982015-02-27 19:15:15 +0100254
Davide Pesavento35185332019-01-14 04:00:15 -0500255 double loss = 0.0;
256 if (m_nInterestsSent > 0) {
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700257 loss = (m_nInterestsSent - m_nInterestsReceived) * 100.0 / m_nInterestsSent;
Davide Pesavento35185332019-01-14 04:00:15 -0500258 }
Davide Pesavento84e77302023-04-17 01:10:06 -0400259 m_logger.log("Total Interest Loss = " + to_string(loss) + "%", false, true);
Davide Pesaventod0b59982015-02-27 19:15:15 +0100260
Davide Pesavento35185332019-01-14 04:00:15 -0500261 double average = 0.0;
262 double inconsistency = 0.0;
263 if (m_nInterestsReceived > 0) {
264 average = m_totalInterestRoundTripTime / m_nInterestsReceived;
265 inconsistency = m_nContentInconsistencies * 100.0 / m_nInterestsReceived;
266 }
Davide Pesavento84e77302023-04-17 01:10:06 -0400267 m_logger.log("Total Data Inconsistency = " + to_string(inconsistency) + "%", false, true);
268 m_logger.log("Total Round Trip Time = " + to_string(m_totalInterestRoundTripTime) + "ms", false, true);
269 m_logger.log("Average Round Trip Time = " + to_string(average) + "ms\n", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700270
Davide Pesavento35185332019-01-14 04:00:15 -0500271 for (std::size_t patternId = 0; patternId < m_trafficPatterns.size(); patternId++) {
Davide Pesavento84e77302023-04-17 01:10:06 -0400272 const auto& pattern = m_trafficPatterns[patternId];
273
274 m_logger.log("Traffic Pattern Type #" + to_string(patternId + 1), false, true);
275 pattern.printTrafficConfiguration(m_logger);
276 m_logger.log("Total Interests Sent = " + to_string(pattern.m_nInterestsSent), false, true);
277 m_logger.log("Total Responses Received = " + to_string(pattern.m_nInterestsReceived), false, true);
278 m_logger.log("Total Nacks Received = " + to_string(pattern.m_nNacks), false, true);
279
280 loss = 0.0;
281 if (pattern.m_nInterestsSent > 0) {
282 loss = (pattern.m_nInterestsSent - pattern.m_nInterestsReceived) * 100.0 / pattern.m_nInterestsSent;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800283 }
Davide Pesavento84e77302023-04-17 01:10:06 -0400284 m_logger.log("Total Interest Loss = " + to_string(loss) + "%", false, true);
285
286 average = 0.0;
287 inconsistency = 0.0;
288 if (pattern.m_nInterestsReceived > 0) {
289 average = pattern.m_totalInterestRoundTripTime / pattern.m_nInterestsReceived;
290 inconsistency = pattern.m_nContentInconsistencies * 100.0 / pattern.m_nInterestsReceived;
Davide Pesavento35185332019-01-14 04:00:15 -0500291 }
Davide Pesavento84e77302023-04-17 01:10:06 -0400292 m_logger.log("Total Data Inconsistency = " + to_string(inconsistency) + "%", false, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500293 m_logger.log("Total Round Trip Time = " +
Davide Pesavento84e77302023-04-17 01:10:06 -0400294 to_string(pattern.m_totalInterestRoundTripTime) + "ms", false, true);
295 m_logger.log("Average Round Trip Time = " + to_string(average) + "ms\n", false, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500296 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800297 }
298
299 bool
Davide Pesavento35185332019-01-14 04:00:15 -0500300 checkTrafficPatternCorrectness() const
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800301 {
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500302 // TODO
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800303 return true;
304 }
305
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700306 uint32_t
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800307 getNewNonce()
308 {
Davide Pesavento35185332019-01-14 04:00:15 -0500309 if (m_nonces.size() >= 1000)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700310 m_nonces.clear();
jeraldabraham473ef3d2014-03-06 12:40:35 -0700311
Davide Pesaventoef064892022-04-05 02:26:03 -0400312 auto randomNonce = ndn::random::generateWord32();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700313 while (std::find(m_nonces.begin(), m_nonces.end(), randomNonce) != m_nonces.end())
Davide Pesaventoef064892022-04-05 02:26:03 -0400314 randomNonce = ndn::random::generateWord32();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700315
316 m_nonces.push_back(randomNonce);
317 return randomNonce;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800318 }
319
Davide Pesavento35185332019-01-14 04:00:15 -0500320 uint32_t
321 getOldNonce()
322 {
323 if (m_nonces.empty())
324 return getNewNonce();
325
326 std::uniform_int_distribution<std::size_t> dist(0, m_nonces.size() - 1);
Davide Pesaventoef064892022-04-05 02:26:03 -0400327 return m_nonces[dist(ndn::random::getRandomNumberEngine())];
Davide Pesavento35185332019-01-14 04:00:15 -0500328 }
329
Davide Pesaventoef064892022-04-05 02:26:03 -0400330 static auto
Davide Pesavento912d2e82019-01-10 17:04:31 -0500331 generateRandomNameComponent(std::size_t length)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800332 {
Davide Pesavento35185332019-01-14 04:00:15 -0500333 // per ISO C++ std, cannot instantiate uniform_int_distribution with uint8_t
334 static std::uniform_int_distribution<unsigned short> dist(std::numeric_limits<uint8_t>::min(),
335 std::numeric_limits<uint8_t>::max());
336
Davide Pesaventoef064892022-04-05 02:26:03 -0400337 ndn::Buffer buf(length);
Davide Pesavento912d2e82019-01-10 17:04:31 -0500338 for (std::size_t i = 0; i < length; i++) {
Davide Pesaventoef064892022-04-05 02:26:03 -0400339 buf[i] = static_cast<uint8_t>(dist(ndn::random::getRandomNumberEngine()));
Eric Newberry3b284192015-07-06 21:44:46 -0700340 }
Davide Pesaventoef064892022-04-05 02:26:03 -0400341 return ndn::name::Component(buf);
Davide Pesavento35185332019-01-14 04:00:15 -0500342 }
343
Davide Pesaventoef064892022-04-05 02:26:03 -0400344 auto
Davide Pesavento35185332019-01-14 04:00:15 -0500345 prepareInterest(std::size_t patternId)
346 {
Davide Pesaventoef064892022-04-05 02:26:03 -0400347 ndn::Interest interest;
Davide Pesavento35185332019-01-14 04:00:15 -0500348 auto& pattern = m_trafficPatterns[patternId];
349
Davide Pesaventoef064892022-04-05 02:26:03 -0400350 ndn::Name name(pattern.m_name);
Davide Pesavento35185332019-01-14 04:00:15 -0500351 if (pattern.m_nameAppendBytes > 0) {
352 name.append(generateRandomNameComponent(*pattern.m_nameAppendBytes));
353 }
354 if (pattern.m_nameAppendSeqNum) {
355 auto seqNum = *pattern.m_nameAppendSeqNum;
356 name.appendSequenceNumber(seqNum);
357 pattern.m_nameAppendSeqNum = seqNum + 1;
358 }
359 interest.setName(name);
360
Davide Pesavento56f79d62019-01-26 17:30:32 -0500361 interest.setCanBePrefix(pattern.m_canBePrefix);
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500362 interest.setMustBeFresh(pattern.m_mustBeFresh);
Davide Pesavento35185332019-01-14 04:00:15 -0500363
364 static std::uniform_int_distribution<> duplicateNonceDist(1, 100);
Davide Pesaventoef064892022-04-05 02:26:03 -0400365 if (duplicateNonceDist(ndn::random::getRandomNumberEngine()) <= pattern.m_nonceDuplicationPercentage)
Davide Pesavento35185332019-01-14 04:00:15 -0500366 interest.setNonce(getOldNonce());
367 else
368 interest.setNonce(getNewNonce());
369
370 if (pattern.m_interestLifetime >= 0_ms)
371 interest.setInterestLifetime(pattern.m_interestLifetime);
372
373 if (pattern.m_nextHopFaceId > 0)
Davide Pesaventoef064892022-04-05 02:26:03 -0400374 interest.setTag(std::make_shared<ndn::lp::NextHopFaceIdTag>(pattern.m_nextHopFaceId));
Davide Pesavento35185332019-01-14 04:00:15 -0500375
376 return interest;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800377 }
378
379 void
Davide Pesavento84e77302023-04-17 01:10:06 -0400380 onData(const ndn::Interest&, const ndn::Data& data, int globalRef, int localRef,
381 std::size_t patternId, const time::steady_clock::time_point& sentTime)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800382 {
Davide Pesaventoef064892022-04-05 02:26:03 -0400383 auto logLine = "Data Received - PatternType=" + std::to_string(patternId + 1) +
384 ", GlobalID=" + std::to_string(globalRef) +
385 ", LocalID=" + std::to_string(localRef) +
Davide Pesavento35185332019-01-14 04:00:15 -0500386 ", Name=" + data.getName().toUri();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700387
388 m_nInterestsReceived++;
389 m_trafficPatterns[patternId].m_nInterestsReceived++;
Davide Pesavento35185332019-01-14 04:00:15 -0500390
391 if (m_trafficPatterns[patternId].m_expectedContent) {
Davide Pesavento92669062022-03-10 19:09:44 -0500392 std::string receivedContent = readString(data.getContent());
Davide Pesavento35185332019-01-14 04:00:15 -0500393 if (receivedContent != *m_trafficPatterns[patternId].m_expectedContent) {
Davide Pesavento912d2e82019-01-10 17:04:31 -0500394 m_nContentInconsistencies++;
395 m_trafficPatterns[patternId].m_nContentInconsistencies++;
396 logLine += ", IsConsistent=No";
jeraldabraham473ef3d2014-03-06 12:40:35 -0700397 }
Davide Pesavento35185332019-01-14 04:00:15 -0500398 else {
Davide Pesavento912d2e82019-01-10 17:04:31 -0500399 logLine += ", IsConsistent=Yes";
Davide Pesavento35185332019-01-14 04:00:15 -0500400 }
Davide Pesavento912d2e82019-01-10 17:04:31 -0500401 }
Davide Pesavento35185332019-01-14 04:00:15 -0500402 else {
jeraldabraham473ef3d2014-03-06 12:40:35 -0700403 logLine += ", IsConsistent=NotChecked";
Davide Pesavento35185332019-01-14 04:00:15 -0500404 }
405 if (!m_wantQuiet) {
jeraldabraham420dbf02014-04-25 22:58:31 -0700406 m_logger.log(logLine, true, false);
Davide Pesavento35185332019-01-14 04:00:15 -0500407 }
408
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700409 double roundTripTime = (time::steady_clock::now() - sentTime).count() / 1000000.0;
410 if (m_minimumInterestRoundTripTime > roundTripTime)
411 m_minimumInterestRoundTripTime = roundTripTime;
412 if (m_maximumInterestRoundTripTime < roundTripTime)
413 m_maximumInterestRoundTripTime = roundTripTime;
414 if (m_trafficPatterns[patternId].m_minimumInterestRoundTripTime > roundTripTime)
415 m_trafficPatterns[patternId].m_minimumInterestRoundTripTime = roundTripTime;
416 if (m_trafficPatterns[patternId].m_maximumInterestRoundTripTime < roundTripTime)
417 m_trafficPatterns[patternId].m_maximumInterestRoundTripTime = roundTripTime;
418 m_totalInterestRoundTripTime += roundTripTime;
419 m_trafficPatterns[patternId].m_totalInterestRoundTripTime += roundTripTime;
Davide Pesavento35185332019-01-14 04:00:15 -0500420
421 if (m_nMaximumInterests == globalRef) {
422 stop();
Davide Pesavento912d2e82019-01-10 17:04:31 -0500423 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700424 }
425
426 void
Davide Pesaventoef064892022-04-05 02:26:03 -0400427 onNack(const ndn::Interest& interest, const ndn::lp::Nack& nack,
Davide Pesavento35185332019-01-14 04:00:15 -0500428 int globalRef, int localRef, std::size_t patternId)
Eric Newberry976c2042016-06-19 23:37:35 -0700429 {
Davide Pesaventoef064892022-04-05 02:26:03 -0400430 auto logLine = "Interest Nack'd - PatternType=" + std::to_string(patternId + 1) +
431 ", GlobalID=" + std::to_string(globalRef) +
432 ", LocalID=" + std::to_string(localRef) +
Davide Pesavento35185332019-01-14 04:00:15 -0500433 ", Name=" + interest.getName().toUri() +
434 ", NackReason=" + boost::lexical_cast<std::string>(nack.getReason());
Eric Newberry976c2042016-06-19 23:37:35 -0700435 m_logger.log(logLine, true, false);
436
437 m_nNacks++;
438 m_trafficPatterns[patternId].m_nNacks++;
439
Davide Pesavento35185332019-01-14 04:00:15 -0500440 if (m_nMaximumInterests == globalRef) {
441 stop();
Eric Newberry976c2042016-06-19 23:37:35 -0700442 }
443 }
444
445 void
Davide Pesavento84e77302023-04-17 01:10:06 -0400446 onTimeout(const ndn::Interest& interest, int globalRef, int localRef, std::size_t patternId)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700447 {
Davide Pesaventoef064892022-04-05 02:26:03 -0400448 auto logLine = "Interest Timed Out - PatternType=" + std::to_string(patternId + 1) +
449 ", GlobalID=" + std::to_string(globalRef) +
450 ", LocalID=" + std::to_string(localRef) +
Davide Pesavento35185332019-01-14 04:00:15 -0500451 ", Name=" + interest.getName().toUri();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700452 m_logger.log(logLine, true, false);
Davide Pesavento35185332019-01-14 04:00:15 -0500453
454 if (m_nMaximumInterests == globalRef) {
455 stop();
456 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700457 }
458
459 void
Davide Pesavento35185332019-01-14 04:00:15 -0500460 generateTraffic(boost::asio::deadline_timer& timer)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700461 {
Davide Pesavento35185332019-01-14 04:00:15 -0500462 if (m_nMaximumInterests && m_nInterestsSent >= *m_nMaximumInterests) {
Davide Pesavento912d2e82019-01-10 17:04:31 -0500463 return;
464 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700465
Davide Pesavento35185332019-01-14 04:00:15 -0500466 static std::uniform_int_distribution<> trafficDist(1, 100);
Davide Pesaventoef064892022-04-05 02:26:03 -0400467 int trafficKey = trafficDist(ndn::random::getRandomNumberEngine());
Davide Pesaventod0b59982015-02-27 19:15:15 +0100468
Davide Pesavento35185332019-01-14 04:00:15 -0500469 int cumulativePercentage = 0;
470 std::size_t patternId = 0;
471 for (; patternId < m_trafficPatterns.size(); patternId++) {
Davide Pesavento84e77302023-04-17 01:10:06 -0400472 auto& pattern = m_trafficPatterns[patternId];
473 cumulativePercentage += pattern.m_trafficPercentage;
Davide Pesavento35185332019-01-14 04:00:15 -0500474 if (trafficKey <= cumulativePercentage) {
Davide Pesavento84e77302023-04-17 01:10:06 -0400475 m_nInterestsSent++;
476 pattern.m_nInterestsSent++;
Davide Pesavento35185332019-01-14 04:00:15 -0500477 auto interest = prepareInterest(patternId);
478 try {
Davide Pesavento84e77302023-04-17 01:10:06 -0400479 int globalRef = m_nInterestsSent;
480 int localRef = pattern.m_nInterestsSent;
Davide Pesavento35185332019-01-14 04:00:15 -0500481 m_face.expressInterest(interest,
Davide Pesavento84e77302023-04-17 01:10:06 -0400482 [=, now = time::steady_clock::now()] (auto&&... args) {
483 onData(std::forward<decltype(args)>(args)..., globalRef, localRef, patternId, now);
484 },
485 [=] (auto&&... args) {
486 onNack(std::forward<decltype(args)>(args)..., globalRef, localRef, patternId);
487 },
488 [=] (auto&&... args) {
489 onTimeout(std::forward<decltype(args)>(args)..., globalRef, localRef, patternId);
490 });
Davide Pesavento35185332019-01-14 04:00:15 -0500491
492 if (!m_wantQuiet) {
Davide Pesaventoef064892022-04-05 02:26:03 -0400493 auto logLine = "Sending Interest - PatternType=" + std::to_string(patternId + 1) +
494 ", GlobalID=" + std::to_string(m_nInterestsSent) +
Davide Pesavento84e77302023-04-17 01:10:06 -0400495 ", LocalID=" + std::to_string(pattern.m_nInterestsSent) +
Davide Pesavento35185332019-01-14 04:00:15 -0500496 ", Name=" + interest.getName().toUri();
497 m_logger.log(logLine, true, false);
498 }
499
Davide Pesaventoef064892022-04-05 02:26:03 -0400500 timer.expires_at(timer.expires_at() + boost::posix_time::millisec(m_interestInterval.count()));
501 timer.async_wait([this, &timer] (auto&&...) { generateTraffic(timer); });
Davide Pesavento35185332019-01-14 04:00:15 -0500502 }
503 catch (const std::exception& e) {
504 m_logger.log("ERROR: "s + e.what(), true, true);
505 }
506 break;
507 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800508 }
Davide Pesavento35185332019-01-14 04:00:15 -0500509 if (patternId == m_trafficPatterns.size()) {
Davide Pesaventoef064892022-04-05 02:26:03 -0400510 timer.expires_at(timer.expires_at() + boost::posix_time::millisec(m_interestInterval.count()));
511 timer.async_wait([this, &timer] (auto&&...) { generateTraffic(timer); });
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800512 }
513 }
514
Davide Pesavento35185332019-01-14 04:00:15 -0500515 void
516 stop()
517 {
518 if (m_nContentInconsistencies > 0 || m_nInterestsSent != m_nInterestsReceived) {
519 m_hasError = true;
520 }
521
522 logStatistics();
523 m_face.shutdown();
524 m_ioService.stop();
525 }
526
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800527private:
Alexander Afanasyev976c3972014-05-26 17:03:40 +0300528 boost::asio::io_service m_ioService;
Davide Pesavento35185332019-01-14 04:00:15 -0500529 boost::asio::signal_set m_signalSet;
530 Logger m_logger;
Davide Pesaventoef064892022-04-05 02:26:03 -0400531 ndn::Face m_face;
Davide Pesavento35185332019-01-14 04:00:15 -0500532
533 std::string m_configurationFile;
Davide Pesaventoef064892022-04-05 02:26:03 -0400534 std::optional<uint64_t> m_nMaximumInterests;
Davide Pesavento35185332019-01-14 04:00:15 -0500535 time::milliseconds m_interestInterval = 1_s;
Davide Pesavento35185332019-01-14 04:00:15 -0500536
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700537 std::vector<InterestTrafficConfiguration> m_trafficPatterns;
538 std::vector<uint32_t> m_nonces;
Davide Pesavento35185332019-01-14 04:00:15 -0500539 uint64_t m_nInterestsSent = 0;
540 uint64_t m_nInterestsReceived = 0;
541 uint64_t m_nNacks = 0;
542 uint64_t m_nContentInconsistencies = 0;
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700543
Davide Pesavento912d2e82019-01-10 17:04:31 -0500544 // RTT is stored as milliseconds with fractional sub-milliseconds precision
Davide Pesavento35185332019-01-14 04:00:15 -0500545 double m_minimumInterestRoundTripTime = std::numeric_limits<double>::max();
546 double m_maximumInterestRoundTripTime = 0;
547 double m_totalInterestRoundTripTime = 0;
548
Davide Pesaventoef064892022-04-05 02:26:03 -0400549 bool m_wantQuiet = false;
Davide Pesavento35185332019-01-14 04:00:15 -0500550 bool m_hasError = false;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800551};
552
Davide Pesaventoef064892022-04-05 02:26:03 -0400553} // namespace ndntg
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800554
Davide Pesavento84e77302023-04-17 01:10:06 -0400555namespace po = boost::program_options;
556
Davide Pesavento35185332019-01-14 04:00:15 -0500557static void
Davide Pesaventoef064892022-04-05 02:26:03 -0400558usage(std::ostream& os, std::string_view programName, const po::options_description& desc)
Davide Pesavento35185332019-01-14 04:00:15 -0500559{
560 os << "Usage: " << programName << " [options] <Traffic_Configuration_File>\n"
561 << "\n"
562 << "Generate Interest traffic as per provided Traffic_Configuration_File.\n"
563 << "Interests are continuously generated unless a total number is specified.\n"
564 << "Set the environment variable NDN_TRAFFIC_LOGFOLDER to redirect output to a log file.\n"
565 << "\n"
566 << desc;
567}
568
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700569int
570main(int argc, char* argv[])
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800571{
Davide Pesavento35185332019-01-14 04:00:15 -0500572 std::string configFile;
Davide Pesaventod0b59982015-02-27 19:15:15 +0100573
Davide Pesavento35185332019-01-14 04:00:15 -0500574 po::options_description visibleOptions("Options");
575 visibleOptions.add_options()
576 ("help,h", "print this help message and exit")
577 ("count,c", po::value<int>(), "total number of Interests to be generated")
578 ("interval,i", po::value<ndn::time::milliseconds::rep>()->default_value(1000),
579 "Interest generation interval in milliseconds")
580 ("quiet,q", po::bool_switch(), "turn off logging of Interest generation/Data reception")
581 ;
582
583 po::options_description hiddenOptions;
584 hiddenOptions.add_options()
585 ("config-file", po::value<std::string>(&configFile))
586 ;
587
588 po::positional_options_description posOptions;
589 posOptions.add("config-file", -1);
590
591 po::options_description allOptions;
592 allOptions.add(visibleOptions).add(hiddenOptions);
593
594 po::variables_map vm;
595 try {
596 po::store(po::command_line_parser(argc, argv).options(allOptions).positional(posOptions).run(), vm);
597 po::notify(vm);
598 }
599 catch (const po::error& e) {
600 std::cerr << "ERROR: " << e.what() << std::endl;
601 return 2;
602 }
603 catch (const boost::bad_any_cast& e) {
604 std::cerr << "ERROR: " << e.what() << std::endl;
605 return 2;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800606 }
607
Davide Pesavento35185332019-01-14 04:00:15 -0500608 if (vm.count("help") > 0) {
609 usage(std::cout, argv[0], visibleOptions);
610 return 0;
611 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800612
Davide Pesavento35185332019-01-14 04:00:15 -0500613 if (configFile.empty()) {
614 usage(std::cerr, argv[0], visibleOptions);
615 return 2;
616 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800617
Davide Pesaventoef064892022-04-05 02:26:03 -0400618 ndntg::NdnTrafficClient client(configFile);
Davide Pesavento35185332019-01-14 04:00:15 -0500619
620 if (vm.count("count") > 0) {
621 int count = vm["count"].as<int>();
622 if (count < 0) {
623 std::cerr << "ERROR: the argument for option '--count' cannot be negative" << std::endl;
624 return 2;
625 }
626 client.setMaximumInterests(static_cast<uint64_t>(count));
627 }
628
629 if (vm.count("interval") > 0) {
630 ndn::time::milliseconds interval(vm["interval"].as<ndn::time::milliseconds::rep>());
Davide Pesaventoef064892022-04-05 02:26:03 -0400631 if (interval <= 0_ms) {
Davide Pesavento35185332019-01-14 04:00:15 -0500632 std::cerr << "ERROR: the argument for option '--interval' must be positive" << std::endl;
633 return 2;
634 }
635 client.setInterestInterval(interval);
636 }
637
638 if (vm["quiet"].as<bool>()) {
639 client.setQuietLogging();
640 }
641
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500642 return client.run();
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800643}