blob: 21b1750c0fb328b9c82a23d275cb605b669cadf7 [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>
Davide Pesavento56f79d62019-01-26 17:30:32 -050030#include <sstream>
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080031#include <vector>
32
Davide Pesavento912d2e82019-01-10 17:04:31 -050033#include <boost/asio/deadline_timer.hpp>
34#include <boost/asio/io_service.hpp>
35#include <boost/asio/signal_set.hpp>
jeraldabraham420dbf02014-04-25 22:58:31 -070036#include <boost/date_time/posix_time/posix_time.hpp>
Davide Pesavento912d2e82019-01-10 17:04:31 -050037#include <boost/lexical_cast.hpp>
jeraldabraham420dbf02014-04-25 22:58:31 -070038#include <boost/noncopyable.hpp>
Davide Pesavento35185332019-01-14 04:00:15 -050039#include <boost/program_options/options_description.hpp>
40#include <boost/program_options/parsers.hpp>
41#include <boost/program_options/variables_map.hpp>
jeraldabraham420dbf02014-04-25 22:58:31 -070042
Davide Pesavento35185332019-01-14 04:00:15 -050043namespace po = boost::program_options;
jeraldabraham420dbf02014-04-25 22:58:31 -070044
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080045namespace ndn {
46
jeraldabraham420dbf02014-04-25 22:58:31 -070047class NdnTrafficClient : boost::noncopyable
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080048{
49public:
jeraldabrahamcc3c6c92014-03-28 02:21:45 -070050 explicit
Davide Pesavento35185332019-01-14 04:00:15 -050051 NdnTrafficClient(const std::string& configFile)
52 : m_signalSet(m_ioService, SIGINT, SIGTERM)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -070053 , m_logger("NdnTrafficClient")
Alexander Afanasyev740812e2014-10-30 15:37:45 -070054 , m_face(m_ioService)
Davide Pesavento35185332019-01-14 04:00:15 -050055 , m_configurationFile(configFile)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080056 {
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080057 }
58
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080059 void
Davide Pesavento35185332019-01-14 04:00:15 -050060 setMaximumInterests(uint64_t maxInterests)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080061 {
Davide Pesavento35185332019-01-14 04:00:15 -050062 m_nMaximumInterests = maxInterests;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080063 }
64
65 void
Davide Pesavento35185332019-01-14 04:00:15 -050066 setInterestInterval(time::milliseconds interval)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080067 {
Davide Pesavento35185332019-01-14 04:00:15 -050068 BOOST_ASSERT(interval > 0_ms);
69 m_interestInterval = interval;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080070 }
71
72 void
jeraldabraham420dbf02014-04-25 22:58:31 -070073 setQuietLogging()
74 {
Davide Pesavento35185332019-01-14 04:00:15 -050075 m_wantQuiet = true;
jeraldabraham420dbf02014-04-25 22:58:31 -070076 }
77
Davide Pesavento306e5bc2019-01-26 16:20:34 -050078 int
Davide Pesavento35185332019-01-14 04:00:15 -050079 run()
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080080 {
Davide Pesavento35185332019-01-14 04:00:15 -050081 m_logger.initializeLog(to_string(random::generateWord32()));
Davide Pesavento306e5bc2019-01-26 16:20:34 -050082
83 if (!readConfigurationFile(m_configurationFile, m_trafficPatterns, m_logger)) {
84 return 2;
85 }
86
87 if (!checkTrafficPatternCorrectness()) {
88 m_logger.log("ERROR: Traffic configuration provided is not proper", false, true);
89 return 2;
90 }
91
92 m_logger.log("Traffic configuration file processing completed.\n", true, false);
93 for (std::size_t i = 0; i < m_trafficPatterns.size(); i++) {
94 m_logger.log("Traffic Pattern Type #" + to_string(i + 1), false, false);
95 m_trafficPatterns[i].printTrafficConfiguration(m_logger);
96 m_logger.log("", false, false);
97 }
Davide Pesaventod0b59982015-02-27 19:15:15 +010098
Davide Pesavento35185332019-01-14 04:00:15 -050099 if (m_nMaximumInterests == 0) {
100 logStatistics();
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500101 return 0;
Davide Pesavento35185332019-01-14 04:00:15 -0500102 }
Davide Pesaventod0b59982015-02-27 19:15:15 +0100103
Davide Pesavento35185332019-01-14 04:00:15 -0500104 m_signalSet.async_wait([this] (auto&&...) { this->stop(); });
105
106 boost::asio::deadline_timer timer(m_ioService,
107 boost::posix_time::millisec(m_interestInterval.count()));
108 timer.async_wait([this, &timer] (auto&&...) { this->generateTraffic(timer); });
109
110 try {
111 m_face.processEvents();
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500112 return m_hasError ? 1 : 0;
Davide Pesavento35185332019-01-14 04:00:15 -0500113 }
114 catch (const std::exception& e) {
115 m_logger.log("ERROR: "s + e.what(), true, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500116 m_ioService.stop();
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500117 return 1;
Davide Pesavento35185332019-01-14 04:00:15 -0500118 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800119 }
120
Davide Pesavento35185332019-01-14 04:00:15 -0500121private:
122 class InterestTrafficConfiguration
123 {
124 public:
125 void
126 printTrafficConfiguration(Logger& logger) const
127 {
Davide Pesavento56f79d62019-01-26 17:30:32 -0500128 std::ostringstream os;
Davide Pesavento35185332019-01-14 04:00:15 -0500129
Davide Pesavento56f79d62019-01-26 17:30:32 -0500130 os << "TrafficPercentage=" << m_trafficPercentage << ", ";
131 os << "Name=" << m_name << ", ";
132 if (m_nameAppendBytes) {
133 os << "NameAppendBytes=" << *m_nameAppendBytes << ", ";
134 }
135 if (m_nameAppendSeqNum) {
136 os << "NameAppendSequenceNumber=" << *m_nameAppendSeqNum << ", ";
137 }
138 if (m_canBePrefix) {
139 os << "CanBePrefix=" << m_canBePrefix << ", ";
140 }
141 if (m_mustBeFresh) {
142 os << "MustBeFresh=" << m_mustBeFresh << ", ";
143 }
144 if (m_nonceDuplicationPercentage > 0) {
145 os << "NonceDuplicationPercentage=" << m_nonceDuplicationPercentage << ", ";
146 }
147 if (m_interestLifetime >= 0_ms) {
148 os << "InterestLifetime=" << m_interestLifetime.count() << ", ";
149 }
150 if (m_nextHopFaceId > 0) {
151 os << "NextHopFaceId=" << m_nextHopFaceId << ", ";
152 }
153 if (m_expectedContent) {
154 os << "ExpectedContent=" << *m_expectedContent << ", ";
155 }
Davide Pesavento35185332019-01-14 04:00:15 -0500156
Davide Pesavento56f79d62019-01-26 17:30:32 -0500157 auto str = os.str();
158 str = str.substr(0, str.length() - 2); // remove suffix ", "
159 logger.log(str, false, false);
Davide Pesavento35185332019-01-14 04:00:15 -0500160 }
161
162 bool
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500163 parseConfigurationLine(const std::string& line, Logger& logger, int lineNumber)
Davide Pesavento35185332019-01-14 04:00:15 -0500164 {
165 std::string parameter, value;
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500166 if (!extractParameterAndValue(line, parameter, value)) {
167 logger.log("Line " + to_string(lineNumber) + " - Invalid syntax: " + line,
168 false, true);
169 return false;
170 }
171
172 if (parameter == "TrafficPercentage") {
173 m_trafficPercentage = std::stoul(value);
174 }
175 else if (parameter == "Name") {
176 m_name = value;
177 }
178 else if (parameter == "NameAppendBytes") {
179 m_nameAppendBytes = std::stoul(value);
180 }
181 else if (parameter == "NameAppendSequenceNumber") {
182 m_nameAppendSeqNum = std::stoull(value);
183 }
Davide Pesavento56f79d62019-01-26 17:30:32 -0500184 else if (parameter == "CanBePrefix") {
185 m_canBePrefix = parseBoolean(value);
186 }
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500187 else if (parameter == "MustBeFresh") {
188 m_mustBeFresh = parseBoolean(value);
189 }
190 else if (parameter == "NonceDuplicationPercentage") {
191 m_nonceDuplicationPercentage = std::stoul(value);
192 }
193 else if (parameter == "InterestLifetime") {
194 m_interestLifetime = time::milliseconds(std::stoul(value));
195 }
196 else if (parameter == "NextHopFaceId") {
197 m_nextHopFaceId = std::stoull(value);
198 }
199 else if (parameter == "ExpectedContent") {
200 m_expectedContent = value;
Davide Pesavento35185332019-01-14 04:00:15 -0500201 }
202 else {
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500203 logger.log("Line " + to_string(lineNumber) + " - Ignoring unknown parameter: " + parameter,
204 false, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500205 }
206 return true;
207 }
208
209 bool
210 checkTrafficDetailCorrectness() const
211 {
212 return true;
213 }
214
215 public:
216 uint8_t m_trafficPercentage = 0;
217 std::string m_name;
218 optional<std::size_t> m_nameAppendBytes;
219 optional<uint64_t> m_nameAppendSeqNum;
Davide Pesavento56f79d62019-01-26 17:30:32 -0500220 bool m_canBePrefix = false;
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500221 bool m_mustBeFresh = false;
Davide Pesavento35185332019-01-14 04:00:15 -0500222 uint8_t m_nonceDuplicationPercentage = 0;
223 time::milliseconds m_interestLifetime = -1_ms;
224 uint64_t m_nextHopFaceId = 0;
225 optional<std::string> m_expectedContent;
226
227 uint64_t m_nInterestsSent = 0;
228 uint64_t m_nInterestsReceived = 0;
229 uint64_t m_nNacks = 0;
230 uint64_t m_nContentInconsistencies = 0;
231
232 // RTT is stored as milliseconds with fractional sub-milliseconds precision
233 double m_minimumInterestRoundTripTime = std::numeric_limits<double>::max();
234 double m_maximumInterestRoundTripTime = 0;
235 double m_totalInterestRoundTripTime = 0;
236 };
237
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800238 void
239 logStatistics()
240 {
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800241 m_logger.log("\n\n== Interest Traffic Report ==\n", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700242 m_logger.log("Total Traffic Pattern Types = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500243 to_string(m_trafficPatterns.size()), false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700244 m_logger.log("Total Interests Sent = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500245 to_string(m_nInterestsSent), false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700246 m_logger.log("Total Responses Received = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500247 to_string(m_nInterestsReceived), false, true);
Eric Newberry976c2042016-06-19 23:37:35 -0700248 m_logger.log("Total Nacks Received = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500249 to_string(m_nNacks), false, true);
Davide Pesaventod0b59982015-02-27 19:15:15 +0100250
Davide Pesavento35185332019-01-14 04:00:15 -0500251 double loss = 0.0;
252 if (m_nInterestsSent > 0) {
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700253 loss = (m_nInterestsSent - m_nInterestsReceived) * 100.0 / m_nInterestsSent;
Davide Pesavento35185332019-01-14 04:00:15 -0500254 }
Spencer Lee8e990232015-11-27 03:54:39 -0700255 m_logger.log("Total Interest Loss = " + to_string(loss) + "%", false, true);
Davide Pesaventod0b59982015-02-27 19:15:15 +0100256
Davide Pesavento35185332019-01-14 04:00:15 -0500257 double average = 0.0;
258 double inconsistency = 0.0;
259 if (m_nInterestsReceived > 0) {
260 average = m_totalInterestRoundTripTime / m_nInterestsReceived;
261 inconsistency = m_nContentInconsistencies * 100.0 / m_nInterestsReceived;
262 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700263 m_logger.log("Total Data Inconsistency = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500264 to_string(inconsistency) + "%", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700265 m_logger.log("Total Round Trip Time = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500266 to_string(m_totalInterestRoundTripTime) + "ms", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700267 m_logger.log("Average Round Trip Time = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500268 to_string(average) + "ms\n", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700269
Davide Pesavento35185332019-01-14 04:00:15 -0500270 for (std::size_t patternId = 0; patternId < m_trafficPatterns.size(); patternId++) {
271 m_logger.log("Traffic Pattern Type #" + to_string(patternId + 1), false, true);
272 m_trafficPatterns[patternId].printTrafficConfiguration(m_logger);
273 m_logger.log("Total Interests Sent = " +
274 to_string(m_trafficPatterns[patternId].m_nInterestsSent), false, true);
275 m_logger.log("Total Responses Received = " +
276 to_string(m_trafficPatterns[patternId].m_nInterestsReceived), false, true);
277 m_logger.log("Total Nacks Received = " +
278 to_string(m_trafficPatterns[patternId].m_nNacks), false, true);
279 loss = 0;
280 if (m_trafficPatterns[patternId].m_nInterestsSent > 0) {
281 loss = (m_trafficPatterns[patternId].m_nInterestsSent -
282 m_trafficPatterns[patternId].m_nInterestsReceived);
283 loss *= 100.0;
284 loss /= m_trafficPatterns[patternId].m_nInterestsSent;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800285 }
Davide Pesavento35185332019-01-14 04:00:15 -0500286 m_logger.log("Total Interest Loss = " + to_string(loss) + "%", false, true);
287 average = 0;
288 inconsistency = 0;
289 if (m_trafficPatterns[patternId].m_nInterestsReceived > 0) {
290 average = (m_trafficPatterns[patternId].m_totalInterestRoundTripTime /
291 m_trafficPatterns[patternId].m_nInterestsReceived);
292 inconsistency = m_trafficPatterns[patternId].m_nContentInconsistencies;
293 inconsistency *= 100.0 / m_trafficPatterns[patternId].m_nInterestsReceived;
294 }
295 m_logger.log("Total Data Inconsistency = " + to_string(inconsistency) + "%", false, true);
296 m_logger.log("Total Round Trip Time = " +
297 to_string(m_trafficPatterns[patternId].m_totalInterestRoundTripTime) + "ms", false, true);
298 m_logger.log("Average Round Trip Time = " + to_string(average) + "ms\n", false, true);
299 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800300 }
301
302 bool
Davide Pesavento35185332019-01-14 04:00:15 -0500303 checkTrafficPatternCorrectness() const
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800304 {
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500305 // TODO
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800306 return true;
307 }
308
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700309 uint32_t
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800310 getNewNonce()
311 {
Davide Pesavento35185332019-01-14 04:00:15 -0500312 if (m_nonces.size() >= 1000)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700313 m_nonces.clear();
jeraldabraham473ef3d2014-03-06 12:40:35 -0700314
Davide Pesavento35185332019-01-14 04:00:15 -0500315 auto randomNonce = random::generateWord32();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700316 while (std::find(m_nonces.begin(), m_nonces.end(), randomNonce) != m_nonces.end())
Davide Pesavento35185332019-01-14 04:00:15 -0500317 randomNonce = random::generateWord32();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700318
319 m_nonces.push_back(randomNonce);
320 return randomNonce;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800321 }
322
Davide Pesavento35185332019-01-14 04:00:15 -0500323 uint32_t
324 getOldNonce()
325 {
326 if (m_nonces.empty())
327 return getNewNonce();
328
329 std::uniform_int_distribution<std::size_t> dist(0, m_nonces.size() - 1);
330 return m_nonces[dist(random::getRandomNumberEngine())];
331 }
332
Eric Newberry3b284192015-07-06 21:44:46 -0700333 static name::Component
Davide Pesavento912d2e82019-01-10 17:04:31 -0500334 generateRandomNameComponent(std::size_t length)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800335 {
Davide Pesavento35185332019-01-14 04:00:15 -0500336 // per ISO C++ std, cannot instantiate uniform_int_distribution with uint8_t
337 static std::uniform_int_distribution<unsigned short> dist(std::numeric_limits<uint8_t>::min(),
338 std::numeric_limits<uint8_t>::max());
339
340 Buffer buf(length);
Davide Pesavento912d2e82019-01-10 17:04:31 -0500341 for (std::size_t i = 0; i < length; i++) {
Davide Pesavento35185332019-01-14 04:00:15 -0500342 buf[i] = static_cast<uint8_t>(dist(random::getRandomNumberEngine()));
Eric Newberry3b284192015-07-06 21:44:46 -0700343 }
Davide Pesavento35185332019-01-14 04:00:15 -0500344 return name::Component(buf);
345 }
346
347 Interest
348 prepareInterest(std::size_t patternId)
349 {
350 Interest interest;
351 auto& pattern = m_trafficPatterns[patternId];
352
353 Name name(pattern.m_name);
354 if (pattern.m_nameAppendBytes > 0) {
355 name.append(generateRandomNameComponent(*pattern.m_nameAppendBytes));
356 }
357 if (pattern.m_nameAppendSeqNum) {
358 auto seqNum = *pattern.m_nameAppendSeqNum;
359 name.appendSequenceNumber(seqNum);
360 pattern.m_nameAppendSeqNum = seqNum + 1;
361 }
362 interest.setName(name);
363
Davide Pesavento56f79d62019-01-26 17:30:32 -0500364 interest.setCanBePrefix(pattern.m_canBePrefix);
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500365 interest.setMustBeFresh(pattern.m_mustBeFresh);
Davide Pesavento35185332019-01-14 04:00:15 -0500366
367 static std::uniform_int_distribution<> duplicateNonceDist(1, 100);
368 if (duplicateNonceDist(random::getRandomNumberEngine()) <= pattern.m_nonceDuplicationPercentage)
369 interest.setNonce(getOldNonce());
370 else
371 interest.setNonce(getNewNonce());
372
373 if (pattern.m_interestLifetime >= 0_ms)
374 interest.setInterestLifetime(pattern.m_interestLifetime);
375
376 if (pattern.m_nextHopFaceId > 0)
377 interest.setTag(make_shared<lp::NextHopFaceIdTag>(pattern.m_nextHopFaceId));
378
379 return interest;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800380 }
381
382 void
Davide Pesavento35185332019-01-14 04:00:15 -0500383 onData(const Data& data, int globalRef, int localRef, std::size_t patternId,
384 const time::steady_clock::TimePoint& sentTime)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800385 {
Davide Pesavento35185332019-01-14 04:00:15 -0500386 auto logLine = "Data Received - PatternType=" + to_string(patternId + 1) +
387 ", GlobalID=" + to_string(globalRef) +
388 ", LocalID=" + to_string(localRef) +
389 ", Name=" + data.getName().toUri();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700390
391 m_nInterestsReceived++;
392 m_trafficPatterns[patternId].m_nInterestsReceived++;
Davide Pesavento35185332019-01-14 04:00:15 -0500393
394 if (m_trafficPatterns[patternId].m_expectedContent) {
395 std::string receivedContent(reinterpret_cast<const char*>(data.getContent().value()),
396 data.getContent().value_size());
397 if (receivedContent != *m_trafficPatterns[patternId].m_expectedContent) {
Davide Pesavento912d2e82019-01-10 17:04:31 -0500398 m_nContentInconsistencies++;
399 m_trafficPatterns[patternId].m_nContentInconsistencies++;
400 logLine += ", IsConsistent=No";
jeraldabraham473ef3d2014-03-06 12:40:35 -0700401 }
Davide Pesavento35185332019-01-14 04:00:15 -0500402 else {
Davide Pesavento912d2e82019-01-10 17:04:31 -0500403 logLine += ", IsConsistent=Yes";
Davide Pesavento35185332019-01-14 04:00:15 -0500404 }
Davide Pesavento912d2e82019-01-10 17:04:31 -0500405 }
Davide Pesavento35185332019-01-14 04:00:15 -0500406 else {
jeraldabraham473ef3d2014-03-06 12:40:35 -0700407 logLine += ", IsConsistent=NotChecked";
Davide Pesavento35185332019-01-14 04:00:15 -0500408 }
409 if (!m_wantQuiet) {
jeraldabraham420dbf02014-04-25 22:58:31 -0700410 m_logger.log(logLine, true, false);
Davide Pesavento35185332019-01-14 04:00:15 -0500411 }
412
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700413 double roundTripTime = (time::steady_clock::now() - sentTime).count() / 1000000.0;
414 if (m_minimumInterestRoundTripTime > roundTripTime)
415 m_minimumInterestRoundTripTime = roundTripTime;
416 if (m_maximumInterestRoundTripTime < roundTripTime)
417 m_maximumInterestRoundTripTime = roundTripTime;
418 if (m_trafficPatterns[patternId].m_minimumInterestRoundTripTime > roundTripTime)
419 m_trafficPatterns[patternId].m_minimumInterestRoundTripTime = roundTripTime;
420 if (m_trafficPatterns[patternId].m_maximumInterestRoundTripTime < roundTripTime)
421 m_trafficPatterns[patternId].m_maximumInterestRoundTripTime = roundTripTime;
422 m_totalInterestRoundTripTime += roundTripTime;
423 m_trafficPatterns[patternId].m_totalInterestRoundTripTime += roundTripTime;
Davide Pesavento35185332019-01-14 04:00:15 -0500424
425 if (m_nMaximumInterests == globalRef) {
426 stop();
Davide Pesavento912d2e82019-01-10 17:04:31 -0500427 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700428 }
429
430 void
Davide Pesavento35185332019-01-14 04:00:15 -0500431 onNack(const Interest& interest, const lp::Nack& nack,
432 int globalRef, int localRef, std::size_t patternId)
Eric Newberry976c2042016-06-19 23:37:35 -0700433 {
Davide Pesavento35185332019-01-14 04:00:15 -0500434 auto logLine = "Interest Nack'd - PatternType=" + to_string(patternId + 1) +
435 ", GlobalID=" + to_string(globalRef) +
436 ", LocalID=" + to_string(localRef) +
437 ", Name=" + interest.getName().toUri() +
438 ", NackReason=" + boost::lexical_cast<std::string>(nack.getReason());
Eric Newberry976c2042016-06-19 23:37:35 -0700439 m_logger.log(logLine, true, false);
440
441 m_nNacks++;
442 m_trafficPatterns[patternId].m_nNacks++;
443
Davide Pesavento35185332019-01-14 04:00:15 -0500444 if (m_nMaximumInterests == globalRef) {
445 stop();
Eric Newberry976c2042016-06-19 23:37:35 -0700446 }
447 }
448
449 void
Davide Pesavento35185332019-01-14 04:00:15 -0500450 onTimeout(const Interest& interest, int globalRef, int localRef, int patternId)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700451 {
Davide Pesavento35185332019-01-14 04:00:15 -0500452 auto logLine = "Interest Timed Out - PatternType=" + to_string(patternId + 1) +
453 ", GlobalID=" + to_string(globalRef) +
454 ", LocalID=" + to_string(localRef) +
455 ", Name=" + interest.getName().toUri();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700456 m_logger.log(logLine, true, false);
Davide Pesavento35185332019-01-14 04:00:15 -0500457
458 if (m_nMaximumInterests == globalRef) {
459 stop();
460 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700461 }
462
463 void
Davide Pesavento35185332019-01-14 04:00:15 -0500464 generateTraffic(boost::asio::deadline_timer& timer)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700465 {
Davide Pesavento35185332019-01-14 04:00:15 -0500466 if (m_nMaximumInterests && m_nInterestsSent >= *m_nMaximumInterests) {
Davide Pesavento912d2e82019-01-10 17:04:31 -0500467 return;
468 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700469
Davide Pesavento35185332019-01-14 04:00:15 -0500470 static std::uniform_int_distribution<> trafficDist(1, 100);
471 int trafficKey = trafficDist(random::getRandomNumberEngine());
Davide Pesaventod0b59982015-02-27 19:15:15 +0100472
Davide Pesavento35185332019-01-14 04:00:15 -0500473 int cumulativePercentage = 0;
474 std::size_t patternId = 0;
475 for (; patternId < m_trafficPatterns.size(); patternId++) {
476 cumulativePercentage += m_trafficPatterns[patternId].m_trafficPercentage;
477 if (trafficKey <= cumulativePercentage) {
478 auto interest = prepareInterest(patternId);
479 try {
480 m_nInterestsSent++;
481 m_trafficPatterns[patternId].m_nInterestsSent++;
482 auto sentTime = time::steady_clock::now();
483 m_face.expressInterest(interest,
484 bind(&NdnTrafficClient::onData, this, _2, m_nInterestsSent,
485 m_trafficPatterns[patternId].m_nInterestsSent, patternId, sentTime),
486 bind(&NdnTrafficClient::onNack, this, _1, _2, m_nInterestsSent,
487 m_trafficPatterns[patternId].m_nInterestsSent, patternId),
488 bind(&NdnTrafficClient::onTimeout, this, _1, m_nInterestsSent,
489 m_trafficPatterns[patternId].m_nInterestsSent, patternId));
490
491 if (!m_wantQuiet) {
492 auto logLine = "Sending Interest - PatternType=" + to_string(patternId + 1) +
493 ", GlobalID=" + to_string(m_nInterestsSent) +
494 ", LocalID=" + to_string(m_trafficPatterns[patternId].m_nInterestsSent) +
495 ", Name=" + interest.getName().toUri();
496 m_logger.log(logLine, true, false);
497 }
498
499 timer.expires_at(timer.expires_at() +
500 boost::posix_time::millisec(m_interestInterval.count()));
501 timer.async_wait([this, &timer] (auto&&...) { this->generateTraffic(timer); });
502 }
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()) {
510 timer.expires_at(timer.expires_at() +
511 boost::posix_time::millisec(m_interestInterval.count()));
512 timer.async_wait([this, &timer] (auto&&...) { this->generateTraffic(timer); });
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800513 }
514 }
515
Davide Pesavento35185332019-01-14 04:00:15 -0500516 void
517 stop()
518 {
519 if (m_nContentInconsistencies > 0 || m_nInterestsSent != m_nInterestsReceived) {
520 m_hasError = true;
521 }
522
523 logStatistics();
524 m_face.shutdown();
525 m_ioService.stop();
526 }
527
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800528private:
Alexander Afanasyev976c3972014-05-26 17:03:40 +0300529 boost::asio::io_service m_ioService;
Davide Pesavento35185332019-01-14 04:00:15 -0500530 boost::asio::signal_set m_signalSet;
531 Logger m_logger;
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700532 Face m_face;
Davide Pesavento35185332019-01-14 04:00:15 -0500533
534 std::string m_configurationFile;
535 optional<uint64_t> m_nMaximumInterests;
536 time::milliseconds m_interestInterval = 1_s;
537 bool m_wantQuiet = false;
538
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700539 std::vector<InterestTrafficConfiguration> m_trafficPatterns;
540 std::vector<uint32_t> m_nonces;
Davide Pesavento35185332019-01-14 04:00:15 -0500541 uint64_t m_nInterestsSent = 0;
542 uint64_t m_nInterestsReceived = 0;
543 uint64_t m_nNacks = 0;
544 uint64_t m_nContentInconsistencies = 0;
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700545
Davide Pesavento912d2e82019-01-10 17:04:31 -0500546 // RTT is stored as milliseconds with fractional sub-milliseconds precision
Davide Pesavento35185332019-01-14 04:00:15 -0500547 double m_minimumInterestRoundTripTime = std::numeric_limits<double>::max();
548 double m_maximumInterestRoundTripTime = 0;
549 double m_totalInterestRoundTripTime = 0;
550
551 bool m_hasError = false;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800552};
553
554} // namespace ndn
555
Davide Pesavento35185332019-01-14 04:00:15 -0500556static void
557usage(std::ostream& os, const std::string& programName, const po::options_description& desc)
558{
559 os << "Usage: " << programName << " [options] <Traffic_Configuration_File>\n"
560 << "\n"
561 << "Generate Interest traffic as per provided Traffic_Configuration_File.\n"
562 << "Interests are continuously generated unless a total number is specified.\n"
563 << "Set the environment variable NDN_TRAFFIC_LOGFOLDER to redirect output to a log file.\n"
564 << "\n"
565 << desc;
566}
567
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700568int
569main(int argc, char* argv[])
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800570{
Davide Pesavento35185332019-01-14 04:00:15 -0500571 std::string configFile;
Davide Pesaventod0b59982015-02-27 19:15:15 +0100572
Davide Pesavento35185332019-01-14 04:00:15 -0500573 po::options_description visibleOptions("Options");
574 visibleOptions.add_options()
575 ("help,h", "print this help message and exit")
576 ("count,c", po::value<int>(), "total number of Interests to be generated")
577 ("interval,i", po::value<ndn::time::milliseconds::rep>()->default_value(1000),
578 "Interest generation interval in milliseconds")
579 ("quiet,q", po::bool_switch(), "turn off logging of Interest generation/Data reception")
580 ;
581
582 po::options_description hiddenOptions;
583 hiddenOptions.add_options()
584 ("config-file", po::value<std::string>(&configFile))
585 ;
586
587 po::positional_options_description posOptions;
588 posOptions.add("config-file", -1);
589
590 po::options_description allOptions;
591 allOptions.add(visibleOptions).add(hiddenOptions);
592
593 po::variables_map vm;
594 try {
595 po::store(po::command_line_parser(argc, argv).options(allOptions).positional(posOptions).run(), vm);
596 po::notify(vm);
597 }
598 catch (const po::error& e) {
599 std::cerr << "ERROR: " << e.what() << std::endl;
600 return 2;
601 }
602 catch (const boost::bad_any_cast& e) {
603 std::cerr << "ERROR: " << e.what() << std::endl;
604 return 2;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800605 }
606
Davide Pesavento35185332019-01-14 04:00:15 -0500607 if (vm.count("help") > 0) {
608 usage(std::cout, argv[0], visibleOptions);
609 return 0;
610 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800611
Davide Pesavento35185332019-01-14 04:00:15 -0500612 if (configFile.empty()) {
613 usage(std::cerr, argv[0], visibleOptions);
614 return 2;
615 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800616
Davide Pesavento35185332019-01-14 04:00:15 -0500617 ndn::NdnTrafficClient client(configFile);
618
619 if (vm.count("count") > 0) {
620 int count = vm["count"].as<int>();
621 if (count < 0) {
622 std::cerr << "ERROR: the argument for option '--count' cannot be negative" << std::endl;
623 return 2;
624 }
625 client.setMaximumInterests(static_cast<uint64_t>(count));
626 }
627
628 if (vm.count("interval") > 0) {
629 ndn::time::milliseconds interval(vm["interval"].as<ndn::time::milliseconds::rep>());
630 if (interval <= ndn::time::milliseconds::zero()) {
631 std::cerr << "ERROR: the argument for option '--interval' must be positive" << std::endl;
632 return 2;
633 }
634 client.setInterestInterval(interval);
635 }
636
637 if (vm["quiet"].as<bool>()) {
638 client.setQuietLogging();
639 }
640
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500641 return client.run();
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800642}