blob: 005b8d47dafcd87aec8dbd76be92a8d493a4dd06 [file] [log] [blame]
Davide Pesavento912d2e82019-01-10 17:04:31 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2014-2019, 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
23#include <ndn-cxx/face.hpp>
24#include <ndn-cxx/name.hpp>
25#include <ndn-cxx/lp/tags.hpp>
26#include <ndn-cxx/util/backports.hpp>
27#include <ndn-cxx/util/random.hpp>
Davide Pesavento912d2e82019-01-10 17:04:31 -050028
Davide Pesavento35185332019-01-14 04:00:15 -050029#include <limits>
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080030#include <vector>
31
Davide Pesavento912d2e82019-01-10 17:04:31 -050032#include <boost/asio/deadline_timer.hpp>
33#include <boost/asio/io_service.hpp>
34#include <boost/asio/signal_set.hpp>
jeraldabraham420dbf02014-04-25 22:58:31 -070035#include <boost/date_time/posix_time/posix_time.hpp>
Davide Pesavento912d2e82019-01-10 17:04:31 -050036#include <boost/lexical_cast.hpp>
jeraldabraham420dbf02014-04-25 22:58:31 -070037#include <boost/noncopyable.hpp>
Davide Pesavento35185332019-01-14 04:00:15 -050038#include <boost/program_options/options_description.hpp>
39#include <boost/program_options/parsers.hpp>
40#include <boost/program_options/variables_map.hpp>
jeraldabraham420dbf02014-04-25 22:58:31 -070041
Davide Pesavento35185332019-01-14 04:00:15 -050042namespace po = boost::program_options;
jeraldabraham420dbf02014-04-25 22:58:31 -070043
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080044namespace ndn {
45
jeraldabraham420dbf02014-04-25 22:58:31 -070046class NdnTrafficClient : 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 NdnTrafficClient(const std::string& configFile)
51 : m_signalSet(m_ioService, SIGINT, SIGTERM)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -070052 , m_logger("NdnTrafficClient")
Alexander Afanasyev740812e2014-10-30 15:37: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 setInterestInterval(time::milliseconds interval)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080066 {
Davide Pesavento35185332019-01-14 04:00:15 -050067 BOOST_ASSERT(interval > 0_ms);
68 m_interestInterval = interval;
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] (auto&&...) { this->stop(); });
104
105 boost::asio::deadline_timer timer(m_ioService,
106 boost::posix_time::millisec(m_interestInterval.count()));
107 timer.async_wait([this, &timer] (auto&&...) { this->generateTraffic(timer); });
108
109 try {
110 m_face.processEvents();
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500111 return m_hasError ? 1 : 0;
Davide Pesavento35185332019-01-14 04:00:15 -0500112 }
113 catch (const std::exception& e) {
114 m_logger.log("ERROR: "s + e.what(), true, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500115 m_ioService.stop();
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500116 return 1;
Davide Pesavento35185332019-01-14 04:00:15 -0500117 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800118 }
119
Davide Pesavento35185332019-01-14 04:00:15 -0500120private:
121 class InterestTrafficConfiguration
122 {
123 public:
124 void
125 printTrafficConfiguration(Logger& logger) const
126 {
127 std::string detail;
128
129 detail += "TrafficPercentage=" + to_string(m_trafficPercentage) + ", ";
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500130 detail += "Name=" + m_name + ", ";
Davide Pesavento35185332019-01-14 04:00:15 -0500131 if (m_nameAppendBytes)
132 detail += "NameAppendBytes=" + to_string(*m_nameAppendBytes) + ", ";
133 if (m_nameAppendSeqNum)
134 detail += "NameAppendSequenceNumber=" + to_string(*m_nameAppendSeqNum) + ", ";
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500135 detail += "MustBeFresh=" + to_string(m_mustBeFresh) + ", ";
Davide Pesavento35185332019-01-14 04:00:15 -0500136 if (m_nonceDuplicationPercentage > 0)
137 detail += "NonceDuplicationPercentage=" + to_string(m_nonceDuplicationPercentage) + ", ";
138 if (m_interestLifetime >= 0_ms)
139 detail += "InterestLifetime=" + to_string(m_interestLifetime.count()) + ", ";
140 if (m_nextHopFaceId > 0)
141 detail += "NextHopFaceId=" + to_string(m_nextHopFaceId) + ", ";
142 if (m_expectedContent)
143 detail += "ExpectedContent=" + *m_expectedContent + ", ";
144 if (detail.length() >= 2)
145 detail = detail.substr(0, detail.length() - 2); // Removing suffix ", "
146
147 logger.log(detail, false, false);
148 }
149
150 bool
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500151 parseConfigurationLine(const std::string& line, Logger& logger, int lineNumber)
Davide Pesavento35185332019-01-14 04:00:15 -0500152 {
153 std::string parameter, value;
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500154 if (!extractParameterAndValue(line, parameter, value)) {
155 logger.log("Line " + to_string(lineNumber) + " - Invalid syntax: " + line,
156 false, true);
157 return false;
158 }
159
160 if (parameter == "TrafficPercentage") {
161 m_trafficPercentage = std::stoul(value);
162 }
163 else if (parameter == "Name") {
164 m_name = value;
165 }
166 else if (parameter == "NameAppendBytes") {
167 m_nameAppendBytes = std::stoul(value);
168 }
169 else if (parameter == "NameAppendSequenceNumber") {
170 m_nameAppendSeqNum = std::stoull(value);
171 }
172 else if (parameter == "MustBeFresh") {
173 m_mustBeFresh = parseBoolean(value);
174 }
175 else if (parameter == "NonceDuplicationPercentage") {
176 m_nonceDuplicationPercentage = std::stoul(value);
177 }
178 else if (parameter == "InterestLifetime") {
179 m_interestLifetime = time::milliseconds(std::stoul(value));
180 }
181 else if (parameter == "NextHopFaceId") {
182 m_nextHopFaceId = std::stoull(value);
183 }
184 else if (parameter == "ExpectedContent") {
185 m_expectedContent = value;
Davide Pesavento35185332019-01-14 04:00:15 -0500186 }
187 else {
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500188 logger.log("Line " + to_string(lineNumber) + " - Ignoring unknown parameter: " + parameter,
189 false, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500190 }
191 return true;
192 }
193
194 bool
195 checkTrafficDetailCorrectness() const
196 {
197 return true;
198 }
199
200 public:
201 uint8_t m_trafficPercentage = 0;
202 std::string m_name;
203 optional<std::size_t> m_nameAppendBytes;
204 optional<uint64_t> m_nameAppendSeqNum;
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500205 bool m_mustBeFresh = false;
Davide Pesavento35185332019-01-14 04:00:15 -0500206 uint8_t m_nonceDuplicationPercentage = 0;
207 time::milliseconds m_interestLifetime = -1_ms;
208 uint64_t m_nextHopFaceId = 0;
209 optional<std::string> m_expectedContent;
210
211 uint64_t m_nInterestsSent = 0;
212 uint64_t m_nInterestsReceived = 0;
213 uint64_t m_nNacks = 0;
214 uint64_t m_nContentInconsistencies = 0;
215
216 // RTT is stored as milliseconds with fractional sub-milliseconds precision
217 double m_minimumInterestRoundTripTime = std::numeric_limits<double>::max();
218 double m_maximumInterestRoundTripTime = 0;
219 double m_totalInterestRoundTripTime = 0;
220 };
221
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800222 void
223 logStatistics()
224 {
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800225 m_logger.log("\n\n== Interest Traffic Report ==\n", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700226 m_logger.log("Total Traffic Pattern Types = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500227 to_string(m_trafficPatterns.size()), false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700228 m_logger.log("Total Interests Sent = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500229 to_string(m_nInterestsSent), false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700230 m_logger.log("Total Responses Received = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500231 to_string(m_nInterestsReceived), false, true);
Eric Newberry976c2042016-06-19 23:37:35 -0700232 m_logger.log("Total Nacks Received = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500233 to_string(m_nNacks), false, true);
Davide Pesaventod0b59982015-02-27 19:15:15 +0100234
Davide Pesavento35185332019-01-14 04:00:15 -0500235 double loss = 0.0;
236 if (m_nInterestsSent > 0) {
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700237 loss = (m_nInterestsSent - m_nInterestsReceived) * 100.0 / m_nInterestsSent;
Davide Pesavento35185332019-01-14 04:00:15 -0500238 }
Spencer Lee8e990232015-11-27 03:54:39 -0700239 m_logger.log("Total Interest Loss = " + to_string(loss) + "%", false, true);
Davide Pesaventod0b59982015-02-27 19:15:15 +0100240
Davide Pesavento35185332019-01-14 04:00:15 -0500241 double average = 0.0;
242 double inconsistency = 0.0;
243 if (m_nInterestsReceived > 0) {
244 average = m_totalInterestRoundTripTime / m_nInterestsReceived;
245 inconsistency = m_nContentInconsistencies * 100.0 / m_nInterestsReceived;
246 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700247 m_logger.log("Total Data Inconsistency = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500248 to_string(inconsistency) + "%", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700249 m_logger.log("Total Round Trip Time = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500250 to_string(m_totalInterestRoundTripTime) + "ms", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700251 m_logger.log("Average Round Trip Time = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500252 to_string(average) + "ms\n", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700253
Davide Pesavento35185332019-01-14 04:00:15 -0500254 for (std::size_t patternId = 0; patternId < m_trafficPatterns.size(); patternId++) {
255 m_logger.log("Traffic Pattern Type #" + to_string(patternId + 1), false, true);
256 m_trafficPatterns[patternId].printTrafficConfiguration(m_logger);
257 m_logger.log("Total Interests Sent = " +
258 to_string(m_trafficPatterns[patternId].m_nInterestsSent), false, true);
259 m_logger.log("Total Responses Received = " +
260 to_string(m_trafficPatterns[patternId].m_nInterestsReceived), false, true);
261 m_logger.log("Total Nacks Received = " +
262 to_string(m_trafficPatterns[patternId].m_nNacks), false, true);
263 loss = 0;
264 if (m_trafficPatterns[patternId].m_nInterestsSent > 0) {
265 loss = (m_trafficPatterns[patternId].m_nInterestsSent -
266 m_trafficPatterns[patternId].m_nInterestsReceived);
267 loss *= 100.0;
268 loss /= m_trafficPatterns[patternId].m_nInterestsSent;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800269 }
Davide Pesavento35185332019-01-14 04:00:15 -0500270 m_logger.log("Total Interest Loss = " + to_string(loss) + "%", false, true);
271 average = 0;
272 inconsistency = 0;
273 if (m_trafficPatterns[patternId].m_nInterestsReceived > 0) {
274 average = (m_trafficPatterns[patternId].m_totalInterestRoundTripTime /
275 m_trafficPatterns[patternId].m_nInterestsReceived);
276 inconsistency = m_trafficPatterns[patternId].m_nContentInconsistencies;
277 inconsistency *= 100.0 / m_trafficPatterns[patternId].m_nInterestsReceived;
278 }
279 m_logger.log("Total Data Inconsistency = " + to_string(inconsistency) + "%", false, true);
280 m_logger.log("Total Round Trip Time = " +
281 to_string(m_trafficPatterns[patternId].m_totalInterestRoundTripTime) + "ms", false, true);
282 m_logger.log("Average Round Trip Time = " + to_string(average) + "ms\n", false, true);
283 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800284 }
285
286 bool
Davide Pesavento35185332019-01-14 04:00:15 -0500287 checkTrafficPatternCorrectness() const
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800288 {
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500289 // TODO
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800290 return true;
291 }
292
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700293 uint32_t
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800294 getNewNonce()
295 {
Davide Pesavento35185332019-01-14 04:00:15 -0500296 if (m_nonces.size() >= 1000)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700297 m_nonces.clear();
jeraldabraham473ef3d2014-03-06 12:40:35 -0700298
Davide Pesavento35185332019-01-14 04:00:15 -0500299 auto randomNonce = random::generateWord32();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700300 while (std::find(m_nonces.begin(), m_nonces.end(), randomNonce) != m_nonces.end())
Davide Pesavento35185332019-01-14 04:00:15 -0500301 randomNonce = random::generateWord32();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700302
303 m_nonces.push_back(randomNonce);
304 return randomNonce;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800305 }
306
Davide Pesavento35185332019-01-14 04:00:15 -0500307 uint32_t
308 getOldNonce()
309 {
310 if (m_nonces.empty())
311 return getNewNonce();
312
313 std::uniform_int_distribution<std::size_t> dist(0, m_nonces.size() - 1);
314 return m_nonces[dist(random::getRandomNumberEngine())];
315 }
316
Eric Newberry3b284192015-07-06 21:44:46 -0700317 static name::Component
Davide Pesavento912d2e82019-01-10 17:04:31 -0500318 generateRandomNameComponent(std::size_t length)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800319 {
Davide Pesavento35185332019-01-14 04:00:15 -0500320 // per ISO C++ std, cannot instantiate uniform_int_distribution with uint8_t
321 static std::uniform_int_distribution<unsigned short> dist(std::numeric_limits<uint8_t>::min(),
322 std::numeric_limits<uint8_t>::max());
323
324 Buffer buf(length);
Davide Pesavento912d2e82019-01-10 17:04:31 -0500325 for (std::size_t i = 0; i < length; i++) {
Davide Pesavento35185332019-01-14 04:00:15 -0500326 buf[i] = static_cast<uint8_t>(dist(random::getRandomNumberEngine()));
Eric Newberry3b284192015-07-06 21:44:46 -0700327 }
Davide Pesavento35185332019-01-14 04:00:15 -0500328 return name::Component(buf);
329 }
330
331 Interest
332 prepareInterest(std::size_t patternId)
333 {
334 Interest interest;
335 auto& pattern = m_trafficPatterns[patternId];
336
337 Name name(pattern.m_name);
338 if (pattern.m_nameAppendBytes > 0) {
339 name.append(generateRandomNameComponent(*pattern.m_nameAppendBytes));
340 }
341 if (pattern.m_nameAppendSeqNum) {
342 auto seqNum = *pattern.m_nameAppendSeqNum;
343 name.appendSequenceNumber(seqNum);
344 pattern.m_nameAppendSeqNum = seqNum + 1;
345 }
346 interest.setName(name);
347
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500348 interest.setMustBeFresh(pattern.m_mustBeFresh);
Davide Pesavento35185332019-01-14 04:00:15 -0500349
350 static std::uniform_int_distribution<> duplicateNonceDist(1, 100);
351 if (duplicateNonceDist(random::getRandomNumberEngine()) <= pattern.m_nonceDuplicationPercentage)
352 interest.setNonce(getOldNonce());
353 else
354 interest.setNonce(getNewNonce());
355
356 if (pattern.m_interestLifetime >= 0_ms)
357 interest.setInterestLifetime(pattern.m_interestLifetime);
358
359 if (pattern.m_nextHopFaceId > 0)
360 interest.setTag(make_shared<lp::NextHopFaceIdTag>(pattern.m_nextHopFaceId));
361
362 return interest;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800363 }
364
365 void
Davide Pesavento35185332019-01-14 04:00:15 -0500366 onData(const Data& data, int globalRef, int localRef, std::size_t patternId,
367 const time::steady_clock::TimePoint& sentTime)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800368 {
Davide Pesavento35185332019-01-14 04:00:15 -0500369 auto logLine = "Data Received - PatternType=" + to_string(patternId + 1) +
370 ", GlobalID=" + to_string(globalRef) +
371 ", LocalID=" + to_string(localRef) +
372 ", Name=" + data.getName().toUri();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700373
374 m_nInterestsReceived++;
375 m_trafficPatterns[patternId].m_nInterestsReceived++;
Davide Pesavento35185332019-01-14 04:00:15 -0500376
377 if (m_trafficPatterns[patternId].m_expectedContent) {
378 std::string receivedContent(reinterpret_cast<const char*>(data.getContent().value()),
379 data.getContent().value_size());
380 if (receivedContent != *m_trafficPatterns[patternId].m_expectedContent) {
Davide Pesavento912d2e82019-01-10 17:04:31 -0500381 m_nContentInconsistencies++;
382 m_trafficPatterns[patternId].m_nContentInconsistencies++;
383 logLine += ", IsConsistent=No";
jeraldabraham473ef3d2014-03-06 12:40:35 -0700384 }
Davide Pesavento35185332019-01-14 04:00:15 -0500385 else {
Davide Pesavento912d2e82019-01-10 17:04:31 -0500386 logLine += ", IsConsistent=Yes";
Davide Pesavento35185332019-01-14 04:00:15 -0500387 }
Davide Pesavento912d2e82019-01-10 17:04:31 -0500388 }
Davide Pesavento35185332019-01-14 04:00:15 -0500389 else {
jeraldabraham473ef3d2014-03-06 12:40:35 -0700390 logLine += ", IsConsistent=NotChecked";
Davide Pesavento35185332019-01-14 04:00:15 -0500391 }
392 if (!m_wantQuiet) {
jeraldabraham420dbf02014-04-25 22:58:31 -0700393 m_logger.log(logLine, true, false);
Davide Pesavento35185332019-01-14 04:00:15 -0500394 }
395
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700396 double roundTripTime = (time::steady_clock::now() - sentTime).count() / 1000000.0;
397 if (m_minimumInterestRoundTripTime > roundTripTime)
398 m_minimumInterestRoundTripTime = roundTripTime;
399 if (m_maximumInterestRoundTripTime < roundTripTime)
400 m_maximumInterestRoundTripTime = roundTripTime;
401 if (m_trafficPatterns[patternId].m_minimumInterestRoundTripTime > roundTripTime)
402 m_trafficPatterns[patternId].m_minimumInterestRoundTripTime = roundTripTime;
403 if (m_trafficPatterns[patternId].m_maximumInterestRoundTripTime < roundTripTime)
404 m_trafficPatterns[patternId].m_maximumInterestRoundTripTime = roundTripTime;
405 m_totalInterestRoundTripTime += roundTripTime;
406 m_trafficPatterns[patternId].m_totalInterestRoundTripTime += roundTripTime;
Davide Pesavento35185332019-01-14 04:00:15 -0500407
408 if (m_nMaximumInterests == globalRef) {
409 stop();
Davide Pesavento912d2e82019-01-10 17:04:31 -0500410 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700411 }
412
413 void
Davide Pesavento35185332019-01-14 04:00:15 -0500414 onNack(const Interest& interest, const lp::Nack& nack,
415 int globalRef, int localRef, std::size_t patternId)
Eric Newberry976c2042016-06-19 23:37:35 -0700416 {
Davide Pesavento35185332019-01-14 04:00:15 -0500417 auto logLine = "Interest Nack'd - PatternType=" + to_string(patternId + 1) +
418 ", GlobalID=" + to_string(globalRef) +
419 ", LocalID=" + to_string(localRef) +
420 ", Name=" + interest.getName().toUri() +
421 ", NackReason=" + boost::lexical_cast<std::string>(nack.getReason());
Eric Newberry976c2042016-06-19 23:37:35 -0700422 m_logger.log(logLine, true, false);
423
424 m_nNacks++;
425 m_trafficPatterns[patternId].m_nNacks++;
426
Davide Pesavento35185332019-01-14 04:00:15 -0500427 if (m_nMaximumInterests == globalRef) {
428 stop();
Eric Newberry976c2042016-06-19 23:37:35 -0700429 }
430 }
431
432 void
Davide Pesavento35185332019-01-14 04:00:15 -0500433 onTimeout(const Interest& interest, int globalRef, int localRef, int patternId)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700434 {
Davide Pesavento35185332019-01-14 04:00:15 -0500435 auto logLine = "Interest Timed Out - PatternType=" + to_string(patternId + 1) +
436 ", GlobalID=" + to_string(globalRef) +
437 ", LocalID=" + to_string(localRef) +
438 ", Name=" + interest.getName().toUri();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700439 m_logger.log(logLine, true, false);
Davide Pesavento35185332019-01-14 04:00:15 -0500440
441 if (m_nMaximumInterests == globalRef) {
442 stop();
443 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700444 }
445
446 void
Davide Pesavento35185332019-01-14 04:00:15 -0500447 generateTraffic(boost::asio::deadline_timer& timer)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700448 {
Davide Pesavento35185332019-01-14 04:00:15 -0500449 if (m_nMaximumInterests && m_nInterestsSent >= *m_nMaximumInterests) {
Davide Pesavento912d2e82019-01-10 17:04:31 -0500450 return;
451 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700452
Davide Pesavento35185332019-01-14 04:00:15 -0500453 static std::uniform_int_distribution<> trafficDist(1, 100);
454 int trafficKey = trafficDist(random::getRandomNumberEngine());
Davide Pesaventod0b59982015-02-27 19:15:15 +0100455
Davide Pesavento35185332019-01-14 04:00:15 -0500456 int cumulativePercentage = 0;
457 std::size_t patternId = 0;
458 for (; patternId < m_trafficPatterns.size(); patternId++) {
459 cumulativePercentage += m_trafficPatterns[patternId].m_trafficPercentage;
460 if (trafficKey <= cumulativePercentage) {
461 auto interest = prepareInterest(patternId);
462 try {
463 m_nInterestsSent++;
464 m_trafficPatterns[patternId].m_nInterestsSent++;
465 auto sentTime = time::steady_clock::now();
466 m_face.expressInterest(interest,
467 bind(&NdnTrafficClient::onData, this, _2, m_nInterestsSent,
468 m_trafficPatterns[patternId].m_nInterestsSent, patternId, sentTime),
469 bind(&NdnTrafficClient::onNack, this, _1, _2, m_nInterestsSent,
470 m_trafficPatterns[patternId].m_nInterestsSent, patternId),
471 bind(&NdnTrafficClient::onTimeout, this, _1, m_nInterestsSent,
472 m_trafficPatterns[patternId].m_nInterestsSent, patternId));
473
474 if (!m_wantQuiet) {
475 auto logLine = "Sending Interest - PatternType=" + to_string(patternId + 1) +
476 ", GlobalID=" + to_string(m_nInterestsSent) +
477 ", LocalID=" + to_string(m_trafficPatterns[patternId].m_nInterestsSent) +
478 ", Name=" + interest.getName().toUri();
479 m_logger.log(logLine, true, false);
480 }
481
482 timer.expires_at(timer.expires_at() +
483 boost::posix_time::millisec(m_interestInterval.count()));
484 timer.async_wait([this, &timer] (auto&&...) { this->generateTraffic(timer); });
485 }
486 catch (const std::exception& e) {
487 m_logger.log("ERROR: "s + e.what(), true, true);
488 }
489 break;
490 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800491 }
Davide Pesavento35185332019-01-14 04:00:15 -0500492 if (patternId == m_trafficPatterns.size()) {
493 timer.expires_at(timer.expires_at() +
494 boost::posix_time::millisec(m_interestInterval.count()));
495 timer.async_wait([this, &timer] (auto&&...) { this->generateTraffic(timer); });
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800496 }
497 }
498
Davide Pesavento35185332019-01-14 04:00:15 -0500499 void
500 stop()
501 {
502 if (m_nContentInconsistencies > 0 || m_nInterestsSent != m_nInterestsReceived) {
503 m_hasError = true;
504 }
505
506 logStatistics();
507 m_face.shutdown();
508 m_ioService.stop();
509 }
510
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800511private:
Alexander Afanasyev976c3972014-05-26 17:03:40 +0300512 boost::asio::io_service m_ioService;
Davide Pesavento35185332019-01-14 04:00:15 -0500513 boost::asio::signal_set m_signalSet;
514 Logger m_logger;
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700515 Face m_face;
Davide Pesavento35185332019-01-14 04:00:15 -0500516
517 std::string m_configurationFile;
518 optional<uint64_t> m_nMaximumInterests;
519 time::milliseconds m_interestInterval = 1_s;
520 bool m_wantQuiet = false;
521
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700522 std::vector<InterestTrafficConfiguration> m_trafficPatterns;
523 std::vector<uint32_t> m_nonces;
Davide Pesavento35185332019-01-14 04:00:15 -0500524 uint64_t m_nInterestsSent = 0;
525 uint64_t m_nInterestsReceived = 0;
526 uint64_t m_nNacks = 0;
527 uint64_t m_nContentInconsistencies = 0;
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700528
Davide Pesavento912d2e82019-01-10 17:04:31 -0500529 // RTT is stored as milliseconds with fractional sub-milliseconds precision
Davide Pesavento35185332019-01-14 04:00:15 -0500530 double m_minimumInterestRoundTripTime = std::numeric_limits<double>::max();
531 double m_maximumInterestRoundTripTime = 0;
532 double m_totalInterestRoundTripTime = 0;
533
534 bool m_hasError = false;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800535};
536
537} // namespace ndn
538
Davide Pesavento35185332019-01-14 04:00:15 -0500539static void
540usage(std::ostream& os, const std::string& programName, const po::options_description& desc)
541{
542 os << "Usage: " << programName << " [options] <Traffic_Configuration_File>\n"
543 << "\n"
544 << "Generate Interest traffic as per provided Traffic_Configuration_File.\n"
545 << "Interests are continuously generated unless a total number is specified.\n"
546 << "Set the environment variable NDN_TRAFFIC_LOGFOLDER to redirect output to a log file.\n"
547 << "\n"
548 << desc;
549}
550
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700551int
552main(int argc, char* argv[])
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800553{
Davide Pesavento35185332019-01-14 04:00:15 -0500554 std::string configFile;
Davide Pesaventod0b59982015-02-27 19:15:15 +0100555
Davide Pesavento35185332019-01-14 04:00:15 -0500556 po::options_description visibleOptions("Options");
557 visibleOptions.add_options()
558 ("help,h", "print this help message and exit")
559 ("count,c", po::value<int>(), "total number of Interests to be generated")
560 ("interval,i", po::value<ndn::time::milliseconds::rep>()->default_value(1000),
561 "Interest generation interval in milliseconds")
562 ("quiet,q", po::bool_switch(), "turn off logging of Interest generation/Data reception")
563 ;
564
565 po::options_description hiddenOptions;
566 hiddenOptions.add_options()
567 ("config-file", po::value<std::string>(&configFile))
568 ;
569
570 po::positional_options_description posOptions;
571 posOptions.add("config-file", -1);
572
573 po::options_description allOptions;
574 allOptions.add(visibleOptions).add(hiddenOptions);
575
576 po::variables_map vm;
577 try {
578 po::store(po::command_line_parser(argc, argv).options(allOptions).positional(posOptions).run(), vm);
579 po::notify(vm);
580 }
581 catch (const po::error& e) {
582 std::cerr << "ERROR: " << e.what() << std::endl;
583 return 2;
584 }
585 catch (const boost::bad_any_cast& e) {
586 std::cerr << "ERROR: " << e.what() << std::endl;
587 return 2;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800588 }
589
Davide Pesavento35185332019-01-14 04:00:15 -0500590 if (vm.count("help") > 0) {
591 usage(std::cout, argv[0], visibleOptions);
592 return 0;
593 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800594
Davide Pesavento35185332019-01-14 04:00:15 -0500595 if (configFile.empty()) {
596 usage(std::cerr, argv[0], visibleOptions);
597 return 2;
598 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800599
Davide Pesavento35185332019-01-14 04:00:15 -0500600 ndn::NdnTrafficClient client(configFile);
601
602 if (vm.count("count") > 0) {
603 int count = vm["count"].as<int>();
604 if (count < 0) {
605 std::cerr << "ERROR: the argument for option '--count' cannot be negative" << std::endl;
606 return 2;
607 }
608 client.setMaximumInterests(static_cast<uint64_t>(count));
609 }
610
611 if (vm.count("interval") > 0) {
612 ndn::time::milliseconds interval(vm["interval"].as<ndn::time::milliseconds::rep>());
613 if (interval <= ndn::time::milliseconds::zero()) {
614 std::cerr << "ERROR: the argument for option '--interval' must be positive" << std::endl;
615 return 2;
616 }
617 client.setInterestInterval(interval);
618 }
619
620 if (vm["quiet"].as<bool>()) {
621 client.setQuietLogging();
622 }
623
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500624 return client.run();
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800625}