Merge with ns-3-dev.
--- a/AUTHORS Wed Nov 11 16:25:10 2009 +0100
+++ b/AUTHORS Thu Nov 12 09:52:54 2009 +0100
@@ -12,23 +12,33 @@
Craig Dowell (craigdo@ee.washington.edu)
David Gross (gdavid.devel@gmail.com)
Tom Henderson (tomhend@u.washington.edu)
-Andrey Mazo (mazo@iitp.ru)
Sam Jansen (sam.jansen@gmail.com)
Liu Jian (liujatp@gmail.com)
Joe Kopena (tjkopena@cs.drexel.edu)
Aleksey Kovalenko (kovalenko@iitp.ru)
Mathieu Lacage (mathieu.lacage@sophia.inria.fr)
Emmanuelle Laprise (emmmanuelle.laprise@bluekazoo.ca)
+Keith Ma (keith.nwsuaf@gmail.com)
Federico Maguolo (maguolof@dei.unipd.it)
+Antti Makela (zarhan@cc.hut.fi)
Francesco Malandrino (francesco.malandrino@gmail.com)
+Fabian Mauchle (f1mauchl@hsr.ch)
+Andrey Mazo (mazo@iitp.ru)
Faker Moatamri (faker.moatamri@sophia.inria.fr)
Duy Nguyen (duy@soe.ucsc.edu)
+Tommaso Pecorella (tommaso.pecorella@unifi.it)
+Yana Podkosova (yanapdk@rambler.ru)
Guangyu Pei (guangyu.pei@boeing.com)
George F. Riley (riley@ece.gatech.edu)
Providence Salumu Munga (Providence.Salumu@gmail.com, Providence.Salumu_Munga@it-sudparis.eu)
+Guillaume Seguin (guillaume.seguin@sophia.inria.fr)
Kulin Shah (m.kulin@gmail.com)
+Ewgenij Starostin (estar@cs.tu-berlin.de)
+Adrian S. W. Tam (adrian.sw.tam@gmail.com)
+Wilson Thong (wilsonwk@ee.cityu.edu.hk)
Mauro Tortonesi (mauro.tortonesi@unife.it)
Sebastien Vincent (vincent@clarinet.u-strasbg.fr)
Guillaume Vu-Brugier (gvubrugier@gmail.com)
+Tom Wambold (tom5760@gmail.com)
Florian Westphal (fw@strlen.de)
Josh Pelkey (jpelkey@gatech.edu)
--- a/CHANGES.html Wed Nov 11 16:25:10 2009 +0100
+++ b/CHANGES.html Thu Nov 12 09:52:54 2009 +0100
@@ -44,6 +44,24 @@
us a note on ns-developers mailing list. </p>
<hr>
+<h1>Changes from ns-3.6 to ns-3.7</h1>
+
+<h2>Changes to build system:</h2>
+
+<h2>New API:</h2>
+
+<h2>Changes to existing API:</h2>
+
+<h2>Changed behavior:</h2>
+<ul>
+<li> Changed default value of YansWifiPhy::EnergyDetectionThreshold from
+-140.0 dBm to -96.0 dBm. Changed default value of
+YansWifiPhy::CcaModelThreshold from -140.0 dBm to -99.0 dBm. Rationale
+can be found <a href="http://www.nsnam.org/bugzilla/show_bug.cgi?id=689">
+here</a>.
+</ul>
+
+<hr>
<h1>Changes from ns-3.5 to ns-3.6</h1>
<h2>Changes to build system:</h2>
--- a/RELEASE_NOTES Wed Nov 11 16:25:10 2009 +0100
+++ b/RELEASE_NOTES Thu Nov 12 09:52:54 2009 +0100
@@ -1,11 +1,14 @@
ns-3 RELEASE NOTES
-This file contains ns-3 release notes (most recent releases first).
+This file contains ns-3 release notes (most recent releases first).
All of the ns-3 documentation is accessible from the ns-3 website:
http://www.nsnam.org including tutorials: http://www.nsnam.org/tutorials.html
+Consult the file CHANGES.html for more detailed information about changed
+API and behavior across ns-3 releases.
+
Release 3.6
===========
@@ -21,7 +24,6 @@
- linux x86_64 gcc 4.4.0, 4.3.2, 4.2.3, 4.2.1, 4.1.3, 3.4.6
- MacOS X ppc and x86 (gcc 4.0.x and 4.2.x)
- cygwin gcc 3.4.4 (debug only), gcc 4.3.2 (debug and optimized)
- - mingw gcc 3.4.5 (debug only)
Not all ns-3 options are available on all platforms; consult the
wiki for more information:
@@ -78,7 +80,7 @@
Known issues
------------
-ns-3 build is known to fail on the following platforms:
+ns-3.6 build is known to fail on the following platforms:
- gcc 3.3 and earlier
- optimized builds on gcc 3.4.4 and 3.4.5
- optimized builds on linux x86 gcc 4.0.x
--- a/examples/stats/README Wed Nov 11 16:25:10 2009 +0100
+++ b/examples/stats/README Thu Nov 12 09:52:54 2009 +0100
@@ -14,3 +14,23 @@
available online on the ns-3 wiki at:
http://www.nsnam.org/wiki/index.php/Statistical_Framework_for_Network_Simulation
+
+*** Using ns-3 with the OMNeT++ analysis tool ***
+
+The stat framework can write out the result in a format that is compatible with the
+output format of OMNeT++ 4 Discrete Event Simulator Framework.
+Use the wifi-example-omnet.sh script to generate the results in OMNeT++ format.
+
+If you want to analyse the results with OMNeT++'s result analyser tool:
+a) Download OMNeT++ 4 and install it. Start the IDE. (www.omnetpp.org)
+b) If you do not want to install the whole simulator framework, there is a seperate
+ package which contains only the analysis tool from the OMNeT++ package.
+ You can download it from http://omnetpp.org/download/release/omnetpp-scave.tgz
+
+Once you are running the OMNeT++ IDE or the separate analysis tool (SCAVE)
+- Choose File|Import...|Existing Projects into Workspace, then click [Next]
+- Select root directory. (choose the examples/stats directory) and click [Finish]
+
+Double click the wifi-example-omnet.anf in the opened project and select
+the Chart page to see the created chart. Experiment with the analysis tool and read its
+documentation: http://omnetpp.org/doc/omnetpp40/userguide/ch09.html
--- a/examples/stats/wifi-example-sim.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/examples/stats/wifi-example-sim.cc Thu Nov 12 09:52:54 2009 +0100
@@ -200,6 +200,7 @@
Ptr<CounterCalculator<uint32_t> > totalTx =
CreateObject<CounterCalculator<uint32_t> >();
totalTx->SetKey("wifi-tx-frames");
+ totalTx->SetContext("node[0]");
Config::Connect("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Mac/MacTx",
MakeBoundCallback(&TxCallback, totalTx));
data.AddDataCalculator(totalTx);
@@ -211,6 +212,7 @@
Ptr<PacketCounterCalculator> totalRx =
CreateObject<PacketCounterCalculator>();
totalRx->SetKey("wifi-rx-frames");
+ totalRx->SetContext("node[1]");
Config::Connect("/NodeList/1/DeviceList/*/$ns3::WifiNetDevice/Mac/MacRx",
MakeCallback(&PacketCounterCalculator::PacketUpdate,
totalRx));
@@ -225,6 +227,7 @@
Ptr<PacketCounterCalculator> appTx =
CreateObject<PacketCounterCalculator>();
appTx->SetKey("sender-tx-packets");
+ appTx->SetContext("node[0]");
Config::Connect("/NodeList/0/ApplicationList/*/$Sender/Tx",
MakeCallback(&PacketCounterCalculator::PacketUpdate,
appTx));
@@ -237,6 +240,7 @@
Ptr<CounterCalculator<> > appRx =
CreateObject<CounterCalculator<> >();
appRx->SetKey("receiver-rx-packets");
+ appRx->SetContext("node[1]");
receiver->SetCounter(appRx);
data.AddDataCalculator(appRx);
@@ -263,6 +267,7 @@
Ptr<PacketSizeMinMaxAvgTotalCalculator> appTxPkts =
CreateObject<PacketSizeMinMaxAvgTotalCalculator>();
appTxPkts->SetKey("tx-pkt-size");
+ appTxPkts->SetContext("node[0]");
Config::Connect("/NodeList/0/ApplicationList/*/$Sender/Tx",
MakeCallback
(&PacketSizeMinMaxAvgTotalCalculator::PacketUpdate,
@@ -277,6 +282,7 @@
Ptr<TimeMinMaxAvgTotalCalculator> delayStat =
CreateObject<TimeMinMaxAvgTotalCalculator>();
delayStat->SetKey("delay");
+ delayStat->SetContext(".");
receiver->SetDelayTracker(delayStat);
data.AddDataCalculator(delayStat);
--- a/src/common/packet.h Wed Nov 11 16:25:10 2009 +0100
+++ b/src/common/packet.h Thu Nov 12 09:52:54 2009 +0100
@@ -32,7 +32,6 @@
#include "ns3/callback.h"
#include "ns3/assert.h"
#include "ns3/ptr.h"
-#include "ns3/deprecated.h"
namespace ns3 {
--- a/src/common/pcap-file-test-suite.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/common/pcap-file-test-suite.cc Thu Nov 12 09:52:54 2009 +0100
@@ -107,7 +107,7 @@
std::stringstream filename;
uint32_t n = rand ();
filename << n;
- m_testFilename = "/tmp/" + filename.str () + ".pcap";
+ m_testFilename = GetTempDir () + filename.str () + ".pcap";
}
void
@@ -218,7 +218,7 @@
std::stringstream filename;
uint32_t n = rand ();
filename << n;
- m_testFilename = "/tmp/" + filename.str () + ".pcap";
+ m_testFilename = GetTempDir () + filename.str () + ".pcap";
}
void
@@ -317,7 +317,7 @@
std::stringstream filename;
uint32_t n = rand ();
filename << n;
- m_testFilename = "/tmp/" + filename.str () + ".pcap";
+ m_testFilename = GetTempDir () + filename.str () + ".pcap";
}
void
@@ -416,7 +416,7 @@
std::stringstream filename;
uint32_t n = rand ();
filename << n;
- m_testFilename = "/tmp/" + filename.str () + ".pcap";
+ m_testFilename = GetTempDir () + filename.str () + ".pcap";
}
void
@@ -607,7 +607,7 @@
std::stringstream filename;
uint32_t n = rand ();
filename << n;
- m_testFilename = "/tmp/" + filename.str () + ".pcap";
+ m_testFilename = GetTempDir () + filename.str () + ".pcap";
}
void
--- a/src/contrib/net-anim/animation-interface.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/net-anim/animation-interface.cc Thu Nov 12 09:52:54 2009 +0100
@@ -21,9 +21,15 @@
#include <stdio.h>
#include <sstream>
+#include "ns3/net-anim-config.h"
+
// Socket related includes
-#include <sys/socket.h>
-#include <netinet/in.h>
+#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_NETINET_IN_H)
+# include <sys/socket.h>
+# include <netinet/in.h>
+#else
+#include <fcntl.h>
+#endif
// ns3 includes
#include "ns3/animation-interface.h"
@@ -58,6 +64,7 @@
bool AnimationInterface::SetServerPort (uint16_t port)
{
+#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_NETINET_IN_H)
int s = socket (AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
@@ -77,6 +84,8 @@
int t = 1;
setsockopt (s, SOL_SOCKET, SO_LINGER, &t, sizeof(t));
return true;
+#endif
+ return false;//never reached unless the above is disabled
}
bool AnimationInterface::SetInternalAnimation ()
--- a/src/contrib/net-anim/point-to-point-dumbbell-helper.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/net-anim/point-to-point-dumbbell-helper.cc Thu Nov 12 09:52:54 2009 +0100
@@ -21,10 +21,6 @@
#include <iostream>
#include <sstream>
-// Socket related includes
-#include <sys/socket.h>
-#include <netinet/in.h>
-
// ns3 includes
#include "ns3/animation-interface.h"
#include "ns3/point-to-point-dumbbell-helper.h"
--- a/src/contrib/net-anim/wscript Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/net-anim/wscript Thu Nov 12 09:52:54 2009 +0100
@@ -1,5 +1,11 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+def configure(conf):
+ conf.check(header_name='sys/socket.h', define_name='HAVE_SYS_SOCKET_H')
+ conf.check(header_name='netinet/in.h', define_name='HAVE_NETINET_IN_H')
+ conf.write_config_header('ns3/net-anim-config.h', top=True)
+
+
def build(bld):
obj = bld.create_ns3_module('net-anim')
obj.source = [
--- a/src/contrib/stats/basic-data-calculators.h Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/basic-data-calculators.h Thu Nov 12 09:52:54 2009 +0100
@@ -29,7 +29,8 @@
//------------------------------------------------------------
//--------------------------------------------
template <typename T = uint32_t>
- class MinMaxAvgTotalCalculator : public DataCalculator {
+ class MinMaxAvgTotalCalculator : public DataCalculator,
+ public StatisticalSummary {
public:
MinMaxAvgTotalCalculator();
virtual ~MinMaxAvgTotalCalculator();
@@ -38,6 +39,15 @@
virtual void Output(DataOutputCallback &callback) const;
+ long getCount() const { return m_count; }
+ double getSum() const { return m_total; }
+ double getMin() const { return m_min; }
+ double getMax() const { return m_max; }
+ double getMean() const { return m_total / (double)m_count; }
+ double getStddev() const { return NaN; } // unsupported
+ double getVariance() const { return NaN; } // unsupported
+ double getSqrSum() const { return NaN; } // unsupported
+
protected:
virtual void DoDispose(void);
@@ -86,23 +96,15 @@
}
// end MinMaxAvgTotalCalculator::Update
}
+
template <typename T>
void
MinMaxAvgTotalCalculator<T>::Output(DataOutputCallback &callback) const
{
- callback.OutputSingleton(m_key, "count", m_count);
- if (m_count > 0) {
- callback.OutputSingleton(m_key, "total", m_total);
- callback.OutputSingleton(m_key, "average", m_total/m_count);
- callback.OutputSingleton(m_key, "max", m_max);
- callback.OutputSingleton(m_key, "min", m_min);
- }
- // end MinMaxAvgTotalCalculator::Output
+ callback.OutputStatistic(m_context, m_key, this);
}
-
-
//------------------------------------------------------------
//--------------------------------------------
template <typename T = uint32_t>
@@ -178,7 +180,7 @@
void
CounterCalculator<T>::Output(DataOutputCallback &callback) const
{
- callback.OutputSingleton(m_key, "count", m_count);
+ callback.OutputSingleton(m_context, m_key, m_count);
// end CounterCalculator::Output
}
--- a/src/contrib/stats/data-calculator.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/data-calculator.cc Thu Nov 12 09:52:54 2009 +0100
@@ -27,6 +27,8 @@
NS_LOG_COMPONENT_DEFINE("DataCalculator");
+static double zero = 0;
+const double ns3::NaN = zero / zero;
//--------------------------------------------------------------
//----------------------------------------------
@@ -70,6 +72,20 @@
//----------------------------------------------
void
+DataCalculator::SetContext(const std::string context)
+{
+ m_context = context;
+ // end DataCalculator::SetContext
+}
+
+std::string
+DataCalculator::GetContext() const
+{
+ return m_context;
+ // end DataCalculator::GetContext
+}
+//----------------------------------------------
+void
DataCalculator::Enable()
{
m_enabled = true;
--- a/src/contrib/stats/data-calculator.h Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/data-calculator.h Thu Nov 12 09:52:54 2009 +0100
@@ -26,9 +26,56 @@
#include "ns3/simulator.h"
namespace ns3 {
+ extern const double NaN;
+ inline bool isNaN(double x) { return x != x; }
class DataOutputCallback;
+ class StatisticalSummary {
+ public:
+ /**
+ * Returns the number of the observations.
+ */
+ virtual long getCount() const = 0;
+
+ /**
+ * Returns the sum of the values.
+ * @see getWeightedSum()
+ */
+ virtual double getSum() const = 0;
+
+ /**
+ * Returns the sum of the squared values.
+ * @see getWeightedSqrSum()
+ */
+ virtual double getSqrSum() const = 0;
+
+ /**
+ * Returns the minimum of the values.
+ */
+ virtual double getMin() const = 0;
+
+ /**
+ * Returns the maximum of the values.
+ */
+ virtual double getMax() const = 0;
+
+ /**
+ * Returns the mean of the (weighted) observations.
+ */
+ virtual double getMean() const = 0;
+
+ /**
+ * Returns the standard deviation of the (weighted) observations.
+ */
+ virtual double getStddev() const = 0;
+
+ /**
+ * Returns the variance of the (weighted) observations.
+ */
+ virtual double getVariance() const = 0;
+ };
+
//------------------------------------------------------------
//--------------------------------------------
class DataCalculator : public Object {
@@ -43,6 +90,9 @@
void SetKey(const std::string key);
std::string GetKey() const;
+ void SetContext(const std::string context);
+ std::string GetContext() const;
+
virtual void Start(const Time& startTime);
virtual void Stop(const Time& stopTime);
@@ -52,6 +102,7 @@
bool m_enabled; // Descendant classes *must* check & respect m_enabled!
std::string m_key;
+ std::string m_context;
virtual void DoDispose(void);
--- a/src/contrib/stats/data-output-interface.h Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/data-output-interface.h Thu Nov 12 09:52:54 2009 +0100
@@ -23,6 +23,7 @@
#include "ns3/object.h"
#include "ns3/nstime.h"
+#include "ns3/data-calculator.h"
namespace ns3 {
@@ -52,6 +53,10 @@
public:
virtual ~DataOutputCallback() {}
+ virtual void OutputStatistic(std::string key,
+ std::string variable,
+ const StatisticalSummary *statSum) = 0;
+
virtual void OutputSingleton(std::string key,
std::string variable,
int val) = 0;
--- a/src/contrib/stats/omnet-data-output.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/omnet-data-output.cc Thu Nov 12 09:52:54 2009 +0100
@@ -19,6 +19,7 @@
*/
#include <fstream>
+#include <cstdlib>
#include "ns3/log.h"
#include "ns3/nstime.h"
@@ -54,26 +55,31 @@
}
//----------------------------------------------
+
+inline bool isNumeric(const std::string& s) {
+ char *endp;
+ strtod(s.c_str(), &endp);
+ return endp == s.c_str() + s.size();
+}
+
void
OmnetDataOutput::Output(DataCollector &dc)
{
std::ofstream scalarFile;
- std::string fn = m_filePrefix + ".sca";
- scalarFile.open(fn.c_str(), std::ios_base::app);
+ std::string fn = m_filePrefix +"-"+dc.GetRunLabel()+ ".sca";
+ scalarFile.open(fn.c_str(), std::ios_base::out);
- scalarFile << std::endl;
+ // TODO add timestamp to the runlevel
scalarFile << "run " << dc.GetRunLabel() << std::endl;
- scalarFile << std::endl;
scalarFile << "attr experiment \"" << dc.GetExperimentLabel()
<< "\"" << std::endl;
scalarFile << "attr strategy \"" << dc.GetStrategyLabel()
<< "\"" << std::endl;
- scalarFile << "attr input \"" << dc.GetInputLabel()
+ scalarFile << "attr measurement \"" << dc.GetInputLabel()
<< "\"" << std::endl;
scalarFile << "attr description \"" << dc.GetDescription()
<< "\"" << std::endl;
- scalarFile << std::endl;
for (MetadataList::iterator i = dc.MetadataBegin();
i != dc.MetadataEnd(); i++) {
@@ -83,7 +89,18 @@
}
scalarFile << std::endl;
-
+ if (isNumeric(dc.GetInputLabel())) {
+ scalarFile << "scalar . measurement \"" << dc.GetInputLabel()
+ << "\"" << std::endl;
+ }
+ for (MetadataList::iterator i = dc.MetadataBegin();
+ i != dc.MetadataEnd(); i++) {
+ std::pair<std::string, std::string> blob = (*i);
+ if (isNumeric(blob.second)) {
+ scalarFile << "scalar . \"" << blob.first << "\" \"" << blob.second << "\""
+ << std::endl;
+ }
+ }
OmnetOutputCallback callback(&scalarFile);
for (DataCalculatorList::iterator i = dc.DataCalculatorBegin();
@@ -97,6 +114,7 @@
// end OmnetDataOutput::Output
}
+
OmnetDataOutput::OmnetOutputCallback::OmnetOutputCallback
(std::ostream *scalar) :
m_scalar(scalar)
@@ -104,42 +122,92 @@
}
void
-OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key,
- std::string variable,
+OmnetDataOutput::OmnetOutputCallback::OutputStatistic(std::string context,
+ std::string name,
+ const StatisticalSummary *statSum)
+{
+ if (context == "")
+ context = ".";
+ if (name == "")
+ name = "\"\"";
+ (*m_scalar) << "statistic " << context << " " << name << std::endl;
+ if (!isNaN(statSum->getCount()))
+ (*m_scalar) << "field count " << statSum->getCount() << std::endl;
+ if (!isNaN(statSum->getSum()))
+ (*m_scalar) << "field sum " << statSum->getSum() << std::endl;
+ if (!isNaN(statSum->getMean()))
+ (*m_scalar) << "field mean " << statSum->getMean() << std::endl;
+ if (!isNaN(statSum->getMin()))
+ (*m_scalar) << "field min " << statSum->getMin() << std::endl;
+ if (!isNaN(statSum->getMax()))
+ (*m_scalar) << "field max " << statSum->getMax() << std::endl;
+ if (!isNaN(statSum->getSqrSum()))
+ (*m_scalar) << "field sqrsum " << statSum->getSqrSum() << std::endl;
+ if (!isNaN(statSum->getStddev()))
+ (*m_scalar) << "field stddev " << statSum->getStddev() << std::endl;
+}
+
+void
+OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string context,
+ std::string name,
int val)
{
- (*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl;
+ if (context == "")
+ context = ".";
+ if (name == "")
+ name = "\"\"";
+ (*m_scalar) << "scalar " << context << " " << name << " " << val << std::endl;
// end OmnetDataOutput::OmnetOutputCallback::OutputSingleton
}
+
void
-OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key,
- std::string variable,
+OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string context,
+ std::string name,
uint32_t val)
{
- (*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl;
+ if (context == "")
+ context = ".";
+ if (name == "")
+ name = "\"\"";
+ (*m_scalar) << "scalar " << context << " " << name << " " << val << std::endl;
// end OmnetDataOutput::OmnetOutputCallback::OutputSingleton
}
+
void
-OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key,
- std::string variable,
+OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string context,
+ std::string name,
double val)
{
- (*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl;
+ if (context == "")
+ context = ".";
+ if (name == "")
+ name = "\"\"";
+ (*m_scalar) << "scalar " << context << " " << name << " " << val << std::endl;
// end OmnetDataOutput::OmnetOutputCallback::OutputSingleton
}
+
void
-OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key,
- std::string variable,
+OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string context,
+ std::string name,
std::string val)
{
- (*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl;
+ if (context == "")
+ context = ".";
+ if (name == "")
+ name = "\"\"";
+ (*m_scalar) << "scalar " << context << " " << name << " " << val << std::endl;
// end OmnetDataOutput::OmnetOutputCallback::OutputSingleton
}
+
void
-OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key,
- std::string variable,
+OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string context,
+ std::string name,
Time val)
{
- (*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl;
+ if (context == "")
+ context = ".";
+ if (name == "")
+ name = "\"\"";
+ (*m_scalar) << "scalar " << context << " " << name << " " << val.GetTimeStep() << std::endl;
// end OmnetDataOutput::OmnetOutputCallback::OutputSingleton
}
--- a/src/contrib/stats/omnet-data-output.h Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/omnet-data-output.h Thu Nov 12 09:52:54 2009 +0100
@@ -45,24 +45,28 @@
public:
OmnetOutputCallback(std::ostream *scalar);
- void OutputSingleton(std::string key,
- std::string variable,
+ void OutputStatistic(std::string context,
+ std::string name,
+ const StatisticalSummary *statSum);
+
+ void OutputSingleton(std::string context,
+ std::string name,
int val);
- void OutputSingleton(std::string key,
- std::string variable,
+ void OutputSingleton(std::string context,
+ std::string name,
uint32_t val);
- void OutputSingleton(std::string key,
- std::string variable,
+ void OutputSingleton(std::string context,
+ std::string name,
double val);
- void OutputSingleton(std::string key,
- std::string variable,
+ void OutputSingleton(std::string context,
+ std::string name,
std::string val);
- void OutputSingleton(std::string key,
- std::string variable,
+ void OutputSingleton(std::string context,
+ std::string name,
Time val);
private:
--- a/src/contrib/stats/sqlite-data-output.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/sqlite-data-output.cc Thu Nov 12 09:52:54 2009 +0100
@@ -154,6 +154,25 @@
}
void
+SqliteDataOutput::SqliteOutputCallback::OutputStatistic(std::string key,
+ std::string variable,
+ const StatisticalSummary *statSum)
+{
+ OutputSingleton(key,variable+"-count", (double)statSum->getCount());
+ if (!isNaN(statSum->getSum()))
+ OutputSingleton(key,variable+"-total", statSum->getSum());
+ if (!isNaN(statSum->getMax()))
+ OutputSingleton(key,variable+"-max", statSum->getMax());
+ if (!isNaN(statSum->getMin()))
+ OutputSingleton(key,variable+"-min", statSum->getMin());
+ if (!isNaN(statSum->getSqrSum()))
+ OutputSingleton(key,variable+"-sqrsum", statSum->getSqrSum());
+ if (!isNaN(statSum->getStddev()))
+ OutputSingleton(key,variable+"-stddev", statSum->getStddev());
+}
+
+
+void
SqliteDataOutput::SqliteOutputCallback::OutputSingleton(std::string key,
std::string variable,
int val)
--- a/src/contrib/stats/sqlite-data-output.h Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/sqlite-data-output.h Thu Nov 12 09:52:54 2009 +0100
@@ -48,6 +48,10 @@
public:
SqliteOutputCallback(Ptr<SqliteDataOutput> owner, std::string run);
+ void OutputStatistic(std::string key,
+ std::string variable,
+ const StatisticalSummary *statSum);
+
void OutputSingleton(std::string key,
std::string variable,
int val);
--- a/src/contrib/stats/time-data-calculators.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/time-data-calculators.cc Thu Nov 12 09:52:54 2009 +0100
@@ -70,12 +70,12 @@
void
TimeMinMaxAvgTotalCalculator::Output(DataOutputCallback &callback) const
{
- callback.OutputSingleton(m_key, "count", m_count);
+ callback.OutputSingleton(m_context, m_key + "-count", m_count);
if (m_count > 0) {
- callback.OutputSingleton(m_key, "total", m_total);
- callback.OutputSingleton(m_key, "average", m_total/Scalar(m_count));
- callback.OutputSingleton(m_key, "max", m_max);
- callback.OutputSingleton(m_key, "min", m_min);
+ callback.OutputSingleton(m_context, m_key + "-total", m_total);
+ callback.OutputSingleton(m_context, m_key + "-average", m_total/Scalar(m_count));
+ callback.OutputSingleton(m_context, m_key + "-max", m_max);
+ callback.OutputSingleton(m_context, m_key + "-min", m_min);
}
// end TimeMinMaxAvgTotalCalculator::Output
}
--- a/src/contrib/wscript Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/wscript Thu Nov 12 09:52:54 2009 +0100
@@ -14,9 +14,11 @@
conf.report_optional_feature("XmlIo", "XmlIo",
conf.env['ENABLE_LIBXML2'],
"library 'libxml-2.0 >= 2.7' not found")
- conf.sub_config('stats')
+ conf.write_config_header('ns3/contrib-config.h', top=True)
- conf.write_config_header('ns3/contrib-config.h', top=True)
+ conf.sub_config('stats')
+ conf.sub_config('net-anim')
+
def build(bld):
module = bld.create_ns3_module('contrib', ['simulator', 'common'])
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/object-ref-count.h Thu Nov 12 09:52:54 2009 +0100
@@ -0,0 +1,120 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 Mathieu Lacage
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@gmail.com>
+ */
+#ifndef OBJECT_REF_COUNT_H
+#define OBJECT_REF_COUNT_H
+
+#include "empty.h"
+
+namespace ns3 {
+
+/**
+ * This templated class provides the refcounting implementation
+ * for the ns3::Object class.
+ *
+ * The tricky aspect of the implementation of this class is that
+ * instead of storing a count directly, it keeps track of a pointer
+ * to a count to allow multiple instances of the class to share the
+ * same pointer/count. This is mainly used by the aggregation support
+ * of the ns3::Object class
+ */
+template <typename T, typename PARENT = empty>
+class ObjectRefCount : public PARENT
+{
+public:
+ ObjectRefCount ()
+ : m_count (new int (1))
+ {}
+ ObjectRefCount (const ObjectRefCount &o)
+ : m_count (new int (1))
+ {}
+ ObjectRefCount & operator = (const ObjectRefCount &o)
+ {
+ return *this;
+ }
+ ~ObjectRefCount ()
+ {
+ m_count = 0;
+ }
+
+ /**
+ * Get the reference count of the object. Normally not needed; for language bindings.
+ */
+ int GetReferenceCount (void) const {
+ return *m_count;
+ }
+ /**
+ * Increment the reference count. This method should not be called
+ * by user code. Object instances are expected to be used in conjunction
+ * of the Ptr template which would make calling Ref unecessary and
+ * dangerous.
+ */
+ inline void Ref (void) const
+ {
+ (*m_count)++;
+ }
+ /**
+ * Decrement the reference count. This method should not be called
+ * by user code. Object instances are expected to be used in conjunction
+ * of the Ptr template which would make calling Ref unecessary and
+ * dangerous.
+ */
+ inline void Unref (void) const
+ {
+ (*m_count)--;
+ if ((*m_count) == 0)
+ {
+ const_cast<ObjectRefCount<T,PARENT>*>(this)->DoDelete ();
+ }
+ }
+protected:
+ /**
+ * \param other another object
+ *
+ * This method makes this object and the input other object
+ * share the same reference count.
+ */
+ void ShareCount (ObjectRefCount *other)
+ {
+ (*m_count) += (*other->m_count);
+ delete other->m_count;
+ other->m_count = m_count;
+ }
+ /**
+ * Called just before deleting this object: when two
+ * objects share the same reference count, the user
+ * who is deleting them must be careful to delete the
+ * associated count only once and this is done by calling
+ * this method to get a reference to the count and, then,
+ * calling delete on the count.
+ *
+ * \sa ns3::Object::DoDelete
+ */
+ int *PeekCountPtr (void) const
+ {
+ return m_count;
+ }
+private:
+ virtual void DoDelete (void) = 0;
+ mutable int *m_count;
+};
+
+} // namespace ns3
+
+#endif /* OBJECT_REF_COUNT_H */
--- a/src/core/object.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/core/object.cc Thu Nov 12 09:52:54 2009 +0100
@@ -28,6 +28,8 @@
#include "string.h"
#include <vector>
#include <sstream>
+#include <stdlib.h>
+#include <string.h>
NS_LOG_COMPONENT_DEFINE ("Object");
@@ -40,28 +42,23 @@
NS_OBJECT_ENSURE_REGISTERED (Object);
Object::AggregateIterator::AggregateIterator ()
- : m_first (0),
+ : m_object (0),
m_current (0)
{}
bool
Object::AggregateIterator::HasNext (void) const
{
- if (m_current != 0 && m_current->m_next != PeekPointer (m_first))
- {
- return true;
- }
- return false;
+ return m_current < m_object->m_aggregates->n;
}
Ptr<const Object>
Object::AggregateIterator::Next (void)
{
- m_current = m_current->m_next;
- return m_current;
+ return m_object->m_aggregates->buffer[m_current];
}
-Object::AggregateIterator::AggregateIterator (Ptr<const Object> first)
- : m_first (first),
- m_current (first)
+Object::AggregateIterator::AggregateIterator (Ptr<const Object> object)
+ : m_object (object),
+ m_current (0)
{}
@@ -82,25 +79,45 @@
Object::Object ()
- : m_count (1),
- m_tid (Object::GetTypeId ()),
+ : m_tid (Object::GetTypeId ()),
m_disposed (false),
- m_next (this)
-{}
+ m_aggregates ((struct Aggregates *)malloc (sizeof (struct Aggregates))),
+ m_getObjectCount (0)
+{
+ m_aggregates->n = 1;
+ m_aggregates->buffer[0] = this;
+}
Object::~Object ()
{
- m_next = 0;
+ // remove this object from the aggregate list
+ uint32_t n = m_aggregates->n;
+ for (uint32_t i = 0; i < n; i++)
+ {
+ Object *current = m_aggregates->buffer[i];
+ if (current == this)
+ {
+ memmove (&m_aggregates->buffer[i],
+ &m_aggregates->buffer[i+1],
+ sizeof (Object *)*(m_aggregates->n - (i+1)));
+ m_aggregates->n--;
+ }
+ }
+ // finally, if all objects have been removed from the list,
+ // delete the aggregate list
+ if (m_aggregates->n == 0)
+ {
+ free (m_aggregates);
+ }
+ m_aggregates = 0;
}
Object::Object (const Object &o)
- : m_count (1),
- m_tid (o.m_tid),
+ : m_tid (o.m_tid),
m_disposed (false),
- m_next (this)
-{}
-uint32_t
-Object::GetReferenceCount (void) const
+ m_aggregates ((struct Aggregates *)malloc (sizeof (struct Aggregates))),
+ m_getObjectCount (0)
{
- return m_count;
+ m_aggregates->n = 1;
+ m_aggregates->buffer[0] = this;
}
void
Object::Construct (const AttributeList &attributes)
@@ -112,34 +129,58 @@
Object::DoGetObject (TypeId tid) const
{
NS_ASSERT (CheckLoose ());
- const Object *currentObject = this;
+
+ uint32_t n = m_aggregates->n;
TypeId objectTid = Object::GetTypeId ();
- do {
- NS_ASSERT (currentObject != 0);
- TypeId cur = currentObject->GetInstanceTypeId ();
- while (cur != tid && cur != objectTid)
- {
- cur = cur.GetParent ();
- }
- if (cur == tid)
- {
- return const_cast<Object *> (currentObject);
- }
- currentObject = currentObject->m_next;
- } while (currentObject != this);
+ for (uint32_t i = 0; i < n; i++)
+ {
+ Object *current = m_aggregates->buffer[i];
+ TypeId cur = current->GetInstanceTypeId ();
+ while (cur != tid && cur != objectTid)
+ {
+ cur = cur.GetParent ();
+ }
+ if (cur == tid)
+ {
+ // This is an attempt to 'cache' the result of this lookup.
+ // the idea is that if we perform a lookup for a TypeId on this object,
+ // we are likely to perform the same lookup later so, we make sure
+ // that the aggregate array is sorted by the number of accesses
+ // to each object.
+
+ // first, increment the access count
+ current->m_getObjectCount++;
+ // then, update the sort
+ UpdateSortedArray (m_aggregates, i);
+ // finally, return the match
+ return const_cast<Object *> (current);
+ }
+ }
return 0;
}
void
Object::Dispose (void)
{
- Object *current = this;
- do {
- NS_ASSERT (current != 0);
- NS_ASSERT (!current->m_disposed);
- current->DoDispose ();
- current->m_disposed = true;
- current = current->m_next;
- } while (current != this);
+ uint32_t n = m_aggregates->n;
+ for (uint32_t i = 0; i < n; i++)
+ {
+ Object *current = m_aggregates->buffer[i];
+ NS_ASSERT (!current->m_disposed);
+ current->DoDispose ();
+ current->m_disposed = true;
+ }
+}
+void
+Object::UpdateSortedArray (struct Aggregates *aggregates, uint32_t j) const
+{
+ while (j > 0 &&
+ aggregates->buffer[j]->m_getObjectCount > aggregates->buffer[j-1]->m_getObjectCount)
+ {
+ Object *tmp = aggregates->buffer[j-1];
+ aggregates->buffer[j-1] = aggregates->buffer[j];
+ aggregates->buffer[j] = tmp;
+ j--;
+ }
}
void
Object::AggregateObject (Ptr<Object> o)
@@ -157,20 +198,42 @@
}
Object *other = PeekPointer (o);
- Object *next = m_next;
- m_next = other->m_next;
- other->m_next = next;
- NS_ASSERT (CheckLoose ());
- NS_ASSERT (o->CheckLoose ());
- // call NotifyNewAggregate in the listed chain
- Object *currentObject = this;
- do
+ // first create the new aggregate buffer.
+ uint32_t total = m_aggregates->n + other->m_aggregates->n;
+ struct Aggregates *aggregates =
+ (struct Aggregates *)malloc (sizeof(struct Aggregates)+(total-1)*sizeof(Object*));
+ aggregates->n = total;
+ memcpy (&aggregates->buffer[0],
+ &m_aggregates->buffer[0],
+ m_aggregates->n*sizeof(Object*));
+ // append the other aggregates in the new buffer
+ for (uint32_t i = 0; i < other->m_aggregates->n; i++)
{
- // the NotifyNewAggregate of the current object implementation
- // should be called on the next object in the linked chain
- currentObject->NotifyNewAggregate ();
- currentObject = currentObject->m_next;
- } while (currentObject != this);
+ aggregates->buffer[m_aggregates->n+i] = other->m_aggregates->buffer[i];
+ UpdateSortedArray (aggregates, m_aggregates->n + i);
+ }
+
+ // free both aggregate buffers
+ free (m_aggregates);
+ free (other->m_aggregates);
+
+ // Then, assign that buffer to every object
+ uint32_t n = aggregates->n;
+ for (uint32_t i = 0; i < n; i++)
+ {
+ Object *current = aggregates->buffer[i];
+ current->m_aggregates = aggregates;
+ }
+
+ // share the counts
+ ShareCount (other);
+
+ // Finally, call NotifyNewAggregate in the listed chain
+ for (uint32_t i = 0; i < n; i++)
+ {
+ Object *current = m_aggregates->buffer[i];
+ current->NotifyNewAggregate ();
+ }
}
/**
* This function must be implemented in the stack that needs to notify
@@ -205,7 +268,7 @@
bool
Object::Check (void) const
{
- return (m_count > 0);
+ return (GetReferenceCount () > 0);
}
/* In some cases, when an event is scheduled against a subclass of
@@ -219,54 +282,43 @@
Object::CheckLoose (void) const
{
uint32_t refcount = 0;
- const Object *current = this;
- do
+ uint32_t n = m_aggregates->n;
+ for (uint32_t i = 0; i < n; i++)
{
- refcount += current->m_count;
- current = current->m_next;
+ Object *current = m_aggregates->buffer[i];
+ refcount += current->GetReferenceCount ();
}
- while (current != this);
-
return (refcount > 0);
}
-
void
-Object::MaybeDelete (void) const
+Object::DoDelete (void)
{
- // First, check if any of the attached
- // Object has a non-zero count.
- const Object *current = this;
- do {
- NS_ASSERT (current != 0);
- if (current->m_count != 0)
- {
- return;
- }
- current = current->m_next;
- } while (current != this);
-
+ uint32_t n = m_aggregates->n;
// Ensure we are disposed.
- Object *tmp = const_cast<Object *> (this);
- const Object *end = this;
- do {
- NS_ASSERT (current != 0);
- Object *next = tmp->m_next;
- if (!tmp->m_disposed)
- {
- tmp->DoDispose ();
- }
- tmp = next;
- } while (tmp != end);
+ for (uint32_t i = 0; i < n; i++)
+ {
+ Object *current = m_aggregates->buffer[i];
+ if (!current->m_disposed)
+ {
+ current->DoDispose ();
+ }
+ }
+
+ int *count = PeekCountPtr ();
- // all attached objects have a zero count so,
- // we can delete all attached objects.
- current = this;
- do {
- NS_ASSERT (current != 0);
- Object *next = current->m_next;
- delete current;
- current = next;
- } while (current != end);
+ // Now, actually delete all objects
+ struct Aggregates *aggregates = m_aggregates;
+ for (uint32_t i = 0; i < n; i++)
+ {
+ // There is a trick here: each time we call delete below,
+ // the deleted object is removed from the aggregate buffer
+ // in the destructor so, the index of the next element to
+ // lookup is always zero
+ Object *current = aggregates->buffer[0];
+ delete current;
+ }
+
+ delete count;
}
} // namespace ns3
--- a/src/core/object.h Wed Nov 11 16:25:10 2009 +0100
+++ b/src/core/object.h Thu Nov 12 09:52:54 2009 +0100
@@ -28,6 +28,7 @@
#include "attribute.h"
#include "object-base.h"
#include "attribute-list.h"
+#include "object-ref-count.h"
namespace ns3 {
@@ -55,7 +56,7 @@
* invoked from the Object::Unref method before destroying the object, even if the user
* did not call Object::Dispose directly.
*/
-class Object : public ObjectBase
+class Object : public ObjectRefCount<Object,ObjectBase>
{
public:
static TypeId GetTypeId (void);
@@ -85,9 +86,9 @@
Ptr<const Object> Next (void);
private:
friend class Object;
- AggregateIterator (Ptr<const Object> first);
- Ptr<const Object> m_first;
- Ptr<const Object> m_current;
+ AggregateIterator (Ptr<const Object> object);
+ Ptr<const Object> m_object;
+ uint32_t m_current;
};
Object ();
@@ -99,30 +100,10 @@
virtual TypeId GetInstanceTypeId (void) const;
/**
- * Increment the reference count. This method should not be called
- * by user code. Object instances are expected to be used in conjunction
- * of the Ptr template which would make calling Ref unecessary and
- * dangerous.
- */
- inline void Ref (void) const;
- /**
- * Decrement the reference count. This method should not be called
- * by user code. Object instances are expected to be used in conjunction
- * of the Ptr template which would make calling Ref unecessary and
- * dangerous.
- */
- inline void Unref (void) const;
-
- /**
- * Get the reference count of the object. Normally not needed; for language bindings.
- */
- uint32_t GetReferenceCount (void) const;
-
- /**
* \returns a pointer to the requested interface or zero if it could not be found.
*/
template <typename T>
- Ptr<T> GetObject (void) const;
+ inline Ptr<T> GetObject (void) const;
/**
* \param tid the interface id of the requested interface
* \returns a pointer to the requested interface or zero if it could not be found.
@@ -215,17 +196,25 @@
friend class ObjectFactory;
friend class AggregateIterator;
+ /**
+ * This data structure uses a classic C-style trick to
+ * hold an array of variable size without performing
+ * two memory allocations: the declaration of the structure
+ * declares a one-element array but when we allocate
+ * memory for this struct, we effectively allocate a larger
+ * chunk of memory than the struct to allow space for a larger
+ * variable sized buffer whose size is indicated by the element
+ * 'n'
+ */
+ struct Aggregates {
+ uint32_t n;
+ Object *buffer[1];
+ };
+
Ptr<Object> DoGetObject (TypeId tid) const;
bool Check (void) const;
bool CheckLoose (void) const;
/**
- * Attempt to delete this object. This method iterates
- * over all aggregated objects to check if they all
- * have a zero refcount. If yes, the object and all
- * its aggregates are deleted. If not, nothing is done.
- */
- void MaybeDelete (void) const;
- /**
* \param tid an TypeId
*
* Invoked from ns3::CreateObject only.
@@ -243,14 +232,15 @@
*/
void Construct (const AttributeList &attributes);
+ void UpdateSortedArray (struct Aggregates *aggregates, uint32_t i) const;
/**
- * The reference count for this object. Each aggregate
- * has an individual reference count. When the global
- * reference count (the sum of all reference counts)
- * reaches zero, the object and all its aggregates is
- * deleted.
+ * Attempt to delete this object. This method iterates
+ * over all aggregated objects to check if they all
+ * have a zero refcount. If yes, the object and all
+ * its aggregates are deleted. If not, nothing is done.
*/
- mutable uint32_t m_count;
+ virtual void DoDelete (void);
+
/**
* Identifies the type of this object instance.
*/
@@ -261,13 +251,19 @@
*/
bool m_disposed;
/**
- * A pointer to the next aggregate object. This is a circular
- * linked list of aggregated objects: the last one points
- * back to the first one. If an object is not aggregated to
- * any other object, the value of this field is equal to the
- * value of the 'this' pointer.
+ * a pointer to an array of 'aggregates'. i.e., a pointer to
+ * each object aggregated to this object is stored in this
+ * array. The array is shared by all aggregated objects
+ * so the size of the array is indirectly a reference count.
*/
- Object *m_next;
+ struct Aggregates * m_aggregates;
+ /**
+ * Indicates the number of times the object was accessed with a
+ * call to GetObject. This integer is used to implement a
+ * heuristic to sort the array of aggregates to put at the start
+ * of the array the most-frequently accessed elements.
+ */
+ uint32_t m_getObjectCount;
};
/**
@@ -340,26 +336,15 @@
* The Object implementation which depends on templates
*************************************************************************/
-void
-Object::Ref (void) const
-{
- m_count++;
-}
-void
-Object::Unref (void) const
-{
- NS_ASSERT (Check ());
- m_count--;
- if (m_count == 0)
- {
- MaybeDelete ();
- }
-}
-
template <typename T>
Ptr<T>
Object::GetObject () const
{
+ T *result = dynamic_cast<T *> (m_aggregates->buffer[0]);
+ if (result != 0)
+ {
+ return Ptr<T> (result);
+ }
Ptr<Object> found = DoGetObject (T::GetTypeId ());
if (found != 0)
{
--- a/src/core/system-thread.h Wed Nov 11 16:25:10 2009 +0100
+++ b/src/core/system-thread.h Thu Nov 12 09:52:54 2009 +0100
@@ -72,12 +72,20 @@
* is asking the SystemThread to call object->MyMethod () in a new thread
* of execution.
*
- * Remember that if you are invoking a callback on an object that is
- * managed by a smart pointer, you need to call PeekPointer.
+ * If starting a thread in your currently executing object, you can use the
+ * "this" pointer:
+ *
+ * Ptr<SystemThread> st = Create<SystemThread> (
+ * MakeCallback (&MyClass::MyMethod, this));
+ * st->Start ();
+ *
+ * Object lifetime is always an issue with threads, so it is common to use
+ * smart pointers. If you are spinning up a thread in an object that is
+ * managed by a smart pointer, you can use that pointer directly:
*
* Ptr<MyClass> myPtr = Create<MyClass> ();
* Ptr<SystemThread> st = Create<SystemThread> (
- * MakeCallback (&MyClass::MyMethod, PeekPointer (myPtr)));
+ * MakeCallback (&MyClass::MyMethod, myPtr));
* st->Start ();
*
* Just like any thread, you can synchronize with its termination. The
--- a/src/core/test.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/core/test.cc Thu Nov 12 09:52:54 2009 +0100
@@ -87,6 +87,7 @@
m_continueOnFailure (false),
m_detailsReported (false),
m_basedir ("invalid"),
+ m_tempdir ("invalid"),
m_ofs (0),
m_error (false)
{
@@ -203,7 +204,18 @@
void
TestCase::SetBaseDir (std::string basedir)
{
- m_basedir = basedir;
+ //
+ // C and C++ allow one to use forward slashes even on systems where the
+ // separator is actually a backslash.
+ //
+ if (basedir[basedir.length () - 1] != '/')
+ {
+ m_basedir = basedir + "/";
+ }
+ else
+ {
+ m_basedir = basedir;
+ }
}
std::string
@@ -212,13 +224,52 @@
return m_basedir;
}
+void
+TestCase::SetTempDir (std::string tempdir)
+{
+ //
+ // C and C++ allow one to use forward slashes even on systems where the
+ // separator is actually a backslash.
+ //
+ if (tempdir[tempdir.length () - 1] != '/')
+ {
+ m_tempdir = tempdir + "/";
+ }
+ else
+ {
+ m_tempdir = tempdir;
+ }
+}
+
+std::string
+TestCase::GetTempDir (void)
+{
+ return m_tempdir;
+}
+
std::string
TestCase::GetSourceDir (std::string file)
{
+ //
+ // The <file> parameter is actually going to be __FILE__ which may have
+ // backslashes in it on win32 systems. For example,
+ //
+ // ..\src\common\pcap-file-test-suite.cc (win32)
+ //
+ // or
+ //
+ // ../src/common/pcap-file-test-suite.cc (grown-up systems)
+ //
+#ifdef WIN32
+ std::string::size_type relPathBegin = file.find_first_of ("\\");
+ std::string::size_type relPathEnd = file.find_last_of ("\\");
+#else
std::string::size_type relPathBegin = file.find_first_of ("/");
- NS_ABORT_MSG_IF (relPathBegin == std::string::npos, "TestCase::GetSrouceDir(): Internal Error");
std::string::size_type relPathEnd = file.find_last_of ("/");
- NS_ABORT_MSG_IF (relPathEnd == std::string::npos, "TestCase::GetSrouceDir(): Internal Error");
+#endif
+
+ NS_ABORT_MSG_IF (relPathBegin == std::string::npos, "TestCase::GetSourceDir(): Internal Error");
+ NS_ABORT_MSG_IF (relPathEnd == std::string::npos, "TestCase::GetSourceDir(): Internal Error");
return GetBaseDir () + file.substr (relPathBegin, relPathEnd + 1 - relPathBegin);
}
@@ -353,6 +404,7 @@
: m_name (name),
m_verbose (false),
m_basedir ("invalid"),
+ m_tempdir ("invalid"),
m_ofs (0),
m_error (false),
m_type (type)
@@ -476,7 +528,18 @@
void
TestSuite::SetBaseDir (std::string basedir)
{
- m_basedir = basedir;
+ //
+ // C and C++ allow one to use forward slashes even on systems where the
+ // separator is actually a backslash.
+ //
+ if (basedir[basedir.length () - 1] != '/')
+ {
+ m_basedir = basedir + "/";
+ }
+ else
+ {
+ m_basedir = basedir;
+ }
}
std::string
@@ -486,6 +549,29 @@
}
void
+TestSuite::SetTempDir (std::string tempdir)
+{
+ //
+ // C and C++ allow one to use forward slashes even on systems where the
+ // separator is actually a backslash.
+ //
+ if (tempdir[tempdir.length () - 1] != '/')
+ {
+ m_tempdir = tempdir + "/";
+ }
+ else
+ {
+ m_tempdir = tempdir;
+ }
+}
+
+std::string
+TestSuite::GetTempDir (void)
+{
+ return m_tempdir;
+}
+
+void
TestSuite::SetStream (std::ofstream *ofs)
{
m_ofs = ofs;
@@ -589,6 +675,7 @@
(*i)->SetVerbose (m_verbose);
(*i)->SetContinueOnFailure (m_continueOnFailure);
(*i)->SetBaseDir (m_basedir);
+ (*i)->SetTempDir (m_tempdir);
(*i)->SetStream (m_ofs);
//
--- a/src/core/test.h Wed Nov 11 16:25:10 2009 +0100
+++ b/src/core/test.h Thu Nov 12 09:52:54 2009 +0100
@@ -662,6 +662,16 @@
*/
std::string GetBaseDir (void);
+ /**
+ * \brief Set the temporary file directory (where to write temporary files).
+ */
+ void SetTempDir (std::string dir);
+
+ /**
+ * \brief Get the temporary file directory .
+ */
+ std::string GetTempDir (void);
+
/**
* \brief Get the source directory of the current source file.
*
@@ -830,6 +840,7 @@
bool m_continueOnFailure;
bool m_detailsReported;
std::string m_basedir;
+ std::string m_tempdir;
std::ofstream *m_ofs;
bool m_error;
};
@@ -945,6 +956,16 @@
std::string GetBaseDir (void);
/**
+ * \brief Set the temporary file directory (where to write temporary files).
+ */
+ void SetTempDir (std::string dir);
+
+ /**
+ * \brief Get the temporary file directory.
+ */
+ std::string GetTempDir (void);
+
+ /**
* \brief Set the stream to which status and result messages will be written.
*
* We really don't want to have to pass an ofstream around to every function
@@ -1064,6 +1085,7 @@
bool m_verbose;
bool m_continueOnFailure;
std::string m_basedir;
+ std::string m_tempdir;
std::ofstream *m_ofs;
bool m_error;
TestType m_type;
--- a/src/core/wscript Wed Nov 11 16:25:10 2009 +0100
+++ b/src/core/wscript Thu Nov 12 09:52:54 2009 +0100
@@ -126,6 +126,7 @@
'abort.h',
'names.h',
'vector.h',
+ 'object-ref-count.h',
]
if sys.platform == 'win32':
--- a/src/devices/mesh/dot11s/dot11s-test-suite.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/dot11s-test-suite.cc Thu Nov 12 09:52:54 2009 +0100
@@ -174,9 +174,9 @@
{
for (std::vector<Mac48Address>::const_iterator i = precursors.begin (); i != precursors.end (); i++)
{
- table->AddPrecursor (dst, iface, *i);
+ table->AddPrecursor (dst, iface, *i, Seconds (100));
// Check that duplicates are filtered
- table->AddPrecursor (dst, iface, *i);
+ table->AddPrecursor (dst, iface, *i, Seconds (100));
}
}
--- a/src/devices/mesh/dot11s/hwmp-protocol.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/hwmp-protocol.cc Thu Nov 12 09:52:54 2009 +0100
@@ -401,6 +401,7 @@
//acceptance cretirea:
std::map<Mac48Address, std::pair<uint32_t, uint32_t> >::const_iterator i = m_hwmpSeqnoMetricDatabase.find (
preq.GetOriginatorAddress ());
+ bool freshInfo (true);
if (i != m_hwmpSeqnoMetricDatabase.end ())
{
if ((int32_t)(i->second.first - preq.GetOriginatorSeqNumber ()) > 0)
@@ -409,21 +410,25 @@
}
if (i->second.first == preq.GetOriginatorSeqNumber ())
{
+ freshInfo = false;
if (i->second.second <= preq.GetMetric ())
{
return;
}
}
}
- m_hwmpSeqnoMetricDatabase[preq.GetOriginatorAddress ()] = std::make_pair (preq.GetOriginatorSeqNumber (), preq.GetMetric ());
-
+ m_hwmpSeqnoMetricDatabase[preq.GetOriginatorAddress ()] =
+ std::make_pair (preq.GetOriginatorSeqNumber (), preq.GetMetric ());
NS_LOG_DEBUG("I am " << GetAddress () << "Accepted preq from address" << from << ", preq:" << preq);
std::vector<Ptr<DestinationAddressUnit> > destinations = preq.GetDestinationList ();
//Add reactive path to originator:
if (
- ((m_rtable->LookupReactive (preq.GetOriginatorAddress ())).retransmitter == Mac48Address::GetBroadcast ()) ||
- ((m_rtable->LookupReactive (preq.GetOriginatorAddress ())).metric > preq.GetMetric ())
+ (freshInfo) ||
+ (
+ (m_rtable->LookupReactive (preq.GetOriginatorAddress ()).retransmitter == Mac48Address::GetBroadcast ()) ||
+ (m_rtable->LookupReactive (preq.GetOriginatorAddress ()).metric > preq.GetMetric ())
)
+ )
{
m_rtable->AddReactivePath (
preq.GetOriginatorAddress (),
@@ -432,13 +437,12 @@
preq.GetMetric (),
MicroSeconds (preq.GetLifetime () * 1024),
preq.GetOriginatorSeqNumber ()
- );
+ );
ReactivePathResolved (preq.GetOriginatorAddress ());
}
- //Add reactive path for precursor:
if (
- ((m_rtable->LookupReactive (fromMp)).retransmitter == Mac48Address::GetBroadcast ()) ||
- ((m_rtable->LookupReactive (fromMp)).metric > preq.GetMetric ())
+ (m_rtable->LookupReactive (fromMp).retransmitter == Mac48Address::GetBroadcast ()) ||
+ (m_rtable->LookupReactive (fromMp).metric > metric)
)
{
m_rtable->AddReactivePath (
@@ -477,15 +481,6 @@
preq.GetOriginatorSeqNumber ()
);
ProactivePathResolved ();
- m_rtable->AddReactivePath (
- preq.GetOriginatorAddress (),
- from,
- interface,
- preq.GetMetric (),
- MicroSeconds (preq.GetLifetime () * 1024),
- preq.GetOriginatorSeqNumber ()
- );
- ReactivePathResolved (preq.GetOriginatorAddress ());
}
if (!preq.IsNeedNotPrep ())
{
@@ -493,7 +488,7 @@
GetAddress (),
preq.GetOriginatorAddress (),
from,
- preq.GetMetric (),
+ (uint32_t)0,
preq.GetOriginatorSeqNumber (),
GetNextHwmpSeqno (),
preq.GetLifetime (),
@@ -523,9 +518,6 @@
if ((! ((*i)->IsDo ())) && (result.retransmitter != Mac48Address::GetBroadcast ()))
{
//have a valid information and can answer
- //!NB: If there is information from peer - set lifetime as
- //we have got from PREQ, and set the rest lifetime of the
- //route if the information is correct
uint32_t lifetime = result.lifetime.GetMicroSeconds () / 1024;
if ((lifetime > 0) && ((int32_t)(result.seqnum - (*i)->GetDestSeqNumber ()) >= 0))
{
@@ -539,6 +531,8 @@
lifetime,
interface
);
+ m_rtable->AddPrecursor ((*i)->GetDestinationAddress (), interface, from,
+ MicroSeconds (preq.GetLifetime () * 1024));
if ((*i)->IsRf ())
{
(*i)->SetFlags (true, false, (*i)->IsUsn ()); //DO = 1, RF = 0
@@ -570,38 +564,52 @@
//acceptance cretirea:
std::map<Mac48Address, std::pair<uint32_t, uint32_t> >::const_iterator i = m_hwmpSeqnoMetricDatabase.find (
prep.GetOriginatorAddress ());
- if ((i != m_hwmpSeqnoMetricDatabase.end ()) && ((int32_t)(i->second.first - prep.GetOriginatorSeqNumber ()) > 0))
+ bool freshInfo (true);
+ if (i != m_hwmpSeqnoMetricDatabase.end ())
{
- return;
+ if ((int32_t)(i->second.first - prep.GetOriginatorSeqNumber ()) > 0)
+ {
+ return;
+ }
+ if (i->second.first == prep.GetOriginatorSeqNumber ())
+ {
+ freshInfo = false;
+ }
}
m_hwmpSeqnoMetricDatabase[prep.GetOriginatorAddress ()] = std::make_pair (prep.GetOriginatorSeqNumber (), prep.GetMetric ());
//update routing info
//Now add a path to destination and add precursor to source
NS_LOG_DEBUG ("I am " << GetAddress () << ", received prep from " << prep.GetOriginatorAddress () << ", receiver was:" << from);
HwmpRtable::LookupResult result = m_rtable->LookupReactive (prep.GetDestinationAddress ());
- //Add a reactive path only if it is better than existing:
+ //Add a reactive path only if seqno is fresher or it improves the
+ //metric
if (
- ((m_rtable->LookupReactive (prep.GetOriginatorAddress ())).retransmitter == Mac48Address::GetBroadcast ()) ||
- ((m_rtable->LookupReactive (prep.GetOriginatorAddress ())).metric > prep.GetMetric ())
+ (freshInfo) ||
+ (
+ ((m_rtable->LookupReactive (prep.GetOriginatorAddress ())).retransmitter == Mac48Address::GetBroadcast ()) ||
+ ((m_rtable->LookupReactive (prep.GetOriginatorAddress ())).metric > prep.GetMetric ())
)
+ )
{
m_rtable->AddReactivePath (
prep.GetOriginatorAddress (),
from,
interface,
prep.GetMetric (),
- MicroSeconds(prep.GetLifetime () * 1024),
+ MicroSeconds (prep.GetLifetime () * 1024),
prep.GetOriginatorSeqNumber ());
- m_rtable->AddPrecursor (prep.GetDestinationAddress (), interface, from);
+ m_rtable->AddPrecursor (prep.GetDestinationAddress (), interface, from,
+ MicroSeconds (prep.GetLifetime () * 1024));
if (result.retransmitter != Mac48Address::GetBroadcast ())
{
- m_rtable->AddPrecursor (prep.GetOriginatorAddress (), interface, result.retransmitter);
+ m_rtable->AddPrecursor (prep.GetOriginatorAddress (), interface, result.retransmitter,
+ result.lifetime);
}
ReactivePathResolved (prep.GetOriginatorAddress ());
}
if (
((m_rtable->LookupReactive (fromMp)).retransmitter == Mac48Address::GetBroadcast ()) ||
- ((m_rtable->LookupReactive (fromMp)).metric > prep.GetMetric ())
+ ((m_rtable->LookupReactive (fromMp)).metric > metric)
)
{
m_rtable->AddReactivePath (
@@ -669,7 +677,7 @@
prep.SetDestinationAddress (dst);
prep.SetDestinationSeqNumber (destinationSN);
prep.SetLifetime (lifetime);
- prep.SetMetric (0);
+ prep.SetMetric (initMetric);
prep.SetOriginatorAddress (src);
prep.SetOriginatorSeqNumber (originatorDsn);
HwmpProtocolMacMap::const_iterator prep_sender = m_interfaces.find (interface);
--- a/src/devices/mesh/dot11s/hwmp-rtable.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/hwmp-rtable.cc Thu Nov 12 09:52:54 2009 +0100
@@ -84,11 +84,12 @@
}
void
HwmpRtable::AddPrecursor (Mac48Address destination, uint32_t precursorInterface,
- Mac48Address precursorAddress)
+ Mac48Address precursorAddress, Time lifetime)
{
- std::pair<uint32_t, Mac48Address> precursor;
- precursor.first = precursorInterface;
- precursor.second = precursorAddress;
+ Precursor precursor;
+ precursor.interface = precursorInterface;
+ precursor.address = precursorAddress;
+ precursor.whenExpire = Simulator::Now () + lifetime;
std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find (destination);
if (i != m_routes.end ())
{
@@ -97,9 +98,10 @@
{
//NB: Only one active route may exist, so do not check
//interface ID, just address
- if (i->second.precursors[j].second == precursorAddress)
+ if (i->second.precursors[j].address == precursorAddress)
{
should_add = false;
+ i->second.precursors[j].whenExpire = precursor.whenExpire;
break;
}
}
@@ -108,17 +110,6 @@
i->second.precursors.push_back (precursor);
}
}
- if (m_root.root == destination)
- {
- for (unsigned int j = 0; j < m_root.precursors.size (); j++)
- {
- if (m_root.precursors[j].second == precursorAddress)
- {
- return;
- }
- }
- }
- m_root.precursors.push_back (precursor);
}
void
HwmpRtable::DeleteProactivePath ()
@@ -221,27 +212,12 @@
std::map<Mac48Address, ReactiveRoute>::iterator route = m_routes.find (destination);
if (route != m_routes.end ())
{
- for (unsigned int i = 0; i < route->second.precursors.size (); i++)
- {
- retval.push_back (route->second.precursors[i]);
- }
- }
- if (m_root.root == destination)
- {
- for (unsigned int i = 0; i < m_root.precursors.size (); i++)
+ for (std::vector<Precursor>::const_iterator i = route->second.precursors.begin ();
+ i != route->second.precursors.end (); i++)
{
- bool should_add = true;
- for (unsigned int j = 0; j < retval.size (); j++)
+ if (i->whenExpire > Simulator::Now ())
{
- if (retval[j].second == m_root.precursors[i].second)
- {
- should_add = false;
- break;
- }
- }
- if (should_add)
- {
- retval.push_back (m_root.precursors[i]);
+ retval.push_back (std::make_pair(i->interface, i->address));
}
}
}
--- a/src/devices/mesh/dot11s/hwmp-rtable.h Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/hwmp-rtable.h Thu Nov 12 09:52:54 2009 +0100
@@ -85,7 +85,7 @@
Time lifetime,
uint32_t seqnum
);
- void AddPrecursor (Mac48Address destination, uint32_t precursorInterface, Mac48Address precursorAddress);
+ void AddPrecursor (Mac48Address destination, uint32_t precursorInterface, Mac48Address precursorAddress, Time lifetime);
PrecursorList GetPrecursors (Mac48Address destination);
void DeleteProactivePath ();
void DeleteProactivePath (Mac48Address root);
@@ -109,6 +109,12 @@
private:
/// Route found in reactive mode
+ struct Precursor
+ {
+ Mac48Address address;
+ uint32_t interface;
+ Time whenExpire;
+ };
struct ReactiveRoute
{
Mac48Address retransmitter;
@@ -116,7 +122,7 @@
uint32_t metric;
Time whenExpire;
uint32_t seqnum;
- std::vector<std::pair<uint32_t, Mac48Address> > precursors;
+ std::vector<Precursor> precursors;
};
/// Route fond in proactive mode
struct ProactiveRoute
@@ -127,7 +133,7 @@
uint32_t metric;
Time whenExpire;
uint32_t seqnum;
- std::vector<std::pair<uint32_t, Mac48Address> > precursors;
+ std::vector<Precursor> precursors;
};
/// List of routes
--- a/src/devices/mesh/dot11s/ie-dot11s-prep.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/ie-dot11s-prep.cc Thu Nov 12 09:52:54 2009 +0100
@@ -135,6 +135,7 @@
IePrep::DecrementTtl ()
{
m_ttl--;
+ m_hopcount ++;
}
void
--- a/src/devices/mesh/dot11s/ie-dot11s-preq.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/ie-dot11s-preq.cc Thu Nov 12 09:52:54 2009 +0100
@@ -317,17 +317,17 @@
IePreq::Print (std::ostream &os) const
{
os << std::endl << "<information_element id=" << ElementId () << ">" << std::endl;
- os << " originator address = " << m_originatorAddress << "std::endl";
- os << " TTL = " << (uint16_t) m_ttl << "std::endl";
- os << " hop count = " << (uint16_t) m_hopCount << "std::endl";
- os << " metric = " << m_metric << "std::endl";
- os << " seqno = " << m_originatorSeqNumber << "std::endl";
- os << " lifetime = " << m_lifetime << "std::endl";
- os << " preq ID = " << m_preqId << "std::endl";
- os << " Destinations are:std::endl";
+ os << " originator address = " << m_originatorAddress << std::endl;
+ os << " TTL = " << (uint16_t) m_ttl << std::endl;
+ os << " hop count = " << (uint16_t) m_hopCount << std::endl;
+ os << " metric = " << m_metric << std::endl;
+ os << " seqno = " << m_originatorSeqNumber << std::endl;
+ os << " lifetime = " << m_lifetime << std::endl;
+ os << " preq ID = " << m_preqId << std::endl;
+ os << " Destinations are:" << std::endl;
for (int j = 0; j < m_destCount; j++)
{
- os << " " << m_destinations[j]->GetDestinationAddress () << "std::endl";
+ os << " " << m_destinations[j]->GetDestinationAddress () << std::endl;
}
os << "</information_element>" << std::endl;
}
--- a/src/devices/mesh/dot11s/ie-dot11s-rann.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/ie-dot11s-rann.cc Thu Nov 12 09:52:54 2009 +0100
@@ -152,12 +152,12 @@
IeRann::Print (std::ostream &os) const
{
os << std::endl << "<information_element id=" << ElementId () << ">" << std::endl;
- os << " flags = " << (int) m_flags << "std::endl";
- os << " hop count = " << (int) m_hopcount << "std::endl";
- os << " TTL = " << (int) m_ttl << "std::endl";
- os << " originator address = " << m_originatorAddress << "std::endl";
- os << " dst seq. number = " << m_destSeqNumber << "std::endl";
- os << " metric = " << m_metric << "std::endl";
+ os << " flags = " << (int) m_flags << std::endl;
+ os << " hop count = " << (int) m_hopcount << std::endl;
+ os << " TTL = " << (int) m_ttl << std::endl;
+ os << " originator address = " << m_originatorAddress << std::endl;
+ os << " dst seq. number = " << m_destSeqNumber << std::endl;
+ os << " metric = " << m_metric << std::endl;
os << "</information_element>" << std::endl;
}
--- a/src/devices/mesh/dot11s/peer-link-frame.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/peer-link-frame.cc Thu Nov 12 09:52:54 2009 +0100
@@ -69,7 +69,7 @@
}
}
PeerLinkFrameStart::PlinkFrameStartFields
-PeerLinkFrameStart::GetFields ()
+PeerLinkFrameStart::GetFields () const
{
PlinkFrameStartFields retval;
//TODO: protocol version:
--- a/src/devices/mesh/dot11s/peer-link-frame.h Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/peer-link-frame.h Thu Nov 12 09:52:54 2009 +0100
@@ -62,7 +62,7 @@
//action header knows about subtype
void SetPlinkFrameSubtype (uint8_t subtype);
void SetPlinkFrameStart (PlinkFrameStartFields);
- PlinkFrameStartFields GetFields ();
+ PlinkFrameStartFields GetFields () const;
/** \name Inherited from header:
* \{
*/
--- a/src/devices/mesh/wifi-information-element-vector.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/wifi-information-element-vector.cc Thu Nov 12 09:52:54 2009 +0100
@@ -58,7 +58,8 @@
WifiInformationElementVector::GetTypeId ()
{
static TypeId tid = TypeId ("ns3::WifiInformationElementVector")
- .SetParent<Header> ();
+ .SetParent<Header> ()
+ .AddConstructor<WifiInformationElementVector> ();
return tid;
}
TypeId
--- a/src/devices/point-to-point/point-to-point-net-device.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/point-to-point/point-to-point-net-device.cc Thu Nov 12 09:52:54 2009 +0100
@@ -173,8 +173,8 @@
PointToPointNetDevice::AddHeader(Ptr<Packet> p, uint16_t protocolNumber)
{
NS_LOG_FUNCTION_NOARGS ();
- NS_ASSERT_MSG (protocolNumber == 0x800, "PointToPointNetDevice::AddHeader(): protocolNumber must be 0x800");
PppHeader ppp;
+ ppp.SetProtocol(EtherToPpp(protocolNumber));
p->AddHeader (ppp);
}
@@ -184,7 +184,7 @@
NS_LOG_FUNCTION_NOARGS ();
PppHeader ppp;
p->RemoveHeader (ppp);
- param = 0x800;
+ param = PppToEther(ppp.GetProtocol());
return true;
}
@@ -655,5 +655,29 @@
return m_mtu;
}
+ uint16_t
+PointToPointNetDevice::PppToEther(uint16_t proto)
+{
+ switch(proto)
+ {
+ case 0x0021: return 0x0800; //IPv4
+ case 0x0057: return 0x86DD; //IPv6
+ default: NS_ASSERT_MSG(false, "PPP Protocol number not defined!");
+ }
+ return 0;
+}
+
+ uint16_t
+PointToPointNetDevice::EtherToPpp(uint16_t proto)
+{
+ switch(proto)
+ {
+ case 0x0800: return 0x0021; //IPv4
+ case 0x86DD: return 0x0057; //IPv6
+ default: NS_ASSERT_MSG(false, "PPP Protocol number not defined!");
+ }
+ return 0;
+}
+
} // namespace ns3
--- a/src/devices/point-to-point/point-to-point-net-device.h Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/point-to-point/point-to-point-net-device.h Thu Nov 12 09:52:54 2009 +0100
@@ -548,6 +548,20 @@
uint32_t m_mtu;
Ptr<Packet> m_currentPkt;
+
+ /**
+ * \brief PPP to Ethernet protocol number mapping
+ * \param protocol A PPP protocol number
+ * \return The corresponding Ethernet protocol number
+ */
+ static uint16_t PppToEther(uint16_t protocol);
+
+ /**
+ * \brief Ethernet to PPP protocol number mapping
+ * \param protocol An Ethernet protocol number
+ * \return The corresponding PPP protocol number
+ */
+ static uint16_t EtherToPpp(uint16_t protocol);
};
} // namespace ns3
--- a/src/devices/point-to-point/ppp-header.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/point-to-point/ppp-header.cc Thu Nov 12 09:52:54 2009 +0100
@@ -56,7 +56,7 @@
void
PppHeader::Print (std::ostream &os) const
{
- os << "Point-to-Point Protocol: IP (0x0021)";
+ os << "Point-to-Point Protocol: " << m_protocol;
}
uint32_t
@@ -68,15 +68,27 @@
void
PppHeader::Serialize (Buffer::Iterator start) const
{
- start.WriteHtonU16 (0x0021);
+ start.WriteHtonU16 (m_protocol);
}
uint32_t
PppHeader::Deserialize (Buffer::Iterator start)
{
- uint16_t data = start.ReadNtohU16 ();
- NS_ABORT_MSG_UNLESS (data == 0x0021, "MyHeader::Deserialize(): expected protocol 0x0021");
- return 2;
+ m_protocol = start.ReadNtohU16 ();
+ return GetSerializedSize();
}
+ void
+PppHeader::SetProtocol (uint16_t protocol)
+{
+ m_protocol=protocol;
+}
+
+ uint16_t
+PppHeader::GetProtocol (void)
+{
+ return m_protocol;
+}
+
+
} // namespace ns3
--- a/src/devices/point-to-point/ppp-header.h Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/point-to-point/ppp-header.h Thu Nov 12 09:52:54 2009 +0100
@@ -28,9 +28,9 @@
*
* This class can be used to add a header to PPP packet. Currently we do not
* implement any of the state machine in RFC 1661, we just encapsulate the
- * inbound packet as an IP version 4 type and send it on. The goal here is
- * not really to implement the point-to-point protocol, but to encapsulate our
- * packets in a known protocol so packet sniffers can parse them.
+ * inbound packet send it on. The goal here is not really to implement the
+ * point-to-point protocol, but to encapsulate our packets in a known protocol
+ * so packet sniffers can parse them.
*
* if PPP is transmitted over a serial link, it will typically be framed in
* some way derivative of IBM SDLC (HDLC) with all that that entails.
@@ -41,20 +41,20 @@
* teach the PcapWriter about the appropriate data link type (DLT_PPP = 9),
* and we need to add a PPP header to each packet. Since we are not using
* framed PPP, this just means prepending the sixteen bit PPP protocol number
- * (0x0021) to the packet. The ns-3 way to do this is via a class that
- * inherits from class Header.
+ * to the packet. The ns-3 way to do this is via a class that inherits from
+ * class Header.
*/
class PppHeader : public Header
{
public:
/**
- * \brief Construct an IP version 4 PPP header.
+ * \brief Construct a PPP header.
*/
PppHeader ();
/**
- * \brief Destroy an IP version 4 PPP header.
+ * \brief Destroy a PPP header.
*/
virtual ~PppHeader ();
@@ -64,6 +64,31 @@
virtual void Serialize (Buffer::Iterator start) const;
virtual uint32_t Deserialize (Buffer::Iterator start);
virtual uint32_t GetSerializedSize (void) const;
+
+ /**
+ * \brief Set the protocol type carried by this PPP packet
+ *
+ * The type numbers to be used are defined in RFC3818
+ *
+ * \param protocol the protocol type being carried
+ */
+ void SetProtocol(uint16_t protocol);
+
+ /**
+ * \brief Get the protocol type carried by this PPP packet
+ *
+ * The type numbers to be used are defined in RFC3818
+ *
+ * \return the protocol type being carried
+ */
+ uint16_t GetProtocol(void);
+
+private:
+
+ /**
+ * \brief The PPP protocol type of the payload packet
+ */
+ uint16_t m_protocol;
};
}; // namespace ns3
--- a/src/devices/wifi/yans-wifi-phy.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/wifi/yans-wifi-phy.cc Thu Nov 12 09:52:54 2009 +0100
@@ -52,14 +52,14 @@
.AddAttribute ("EnergyDetectionThreshold",
"The energy of a received signal should be higher than "
"this threshold (dbm) to allow the PHY layer to detect the signal.",
- DoubleValue (-140.0),
+ DoubleValue (-96.0),
MakeDoubleAccessor (&YansWifiPhy::SetEdThreshold,
&YansWifiPhy::GetEdThreshold),
MakeDoubleChecker<double> ())
.AddAttribute ("CcaMode1Threshold",
"The energy of a received signal should be higher than "
"this threshold (dbm) to allow the PHY layer to declare CCA BUSY state",
- DoubleValue (-140.0),
+ DoubleValue (-99.0),
MakeDoubleAccessor (&YansWifiPhy::SetCcaMode1Threshold,
&YansWifiPhy::GetCcaMode1Threshold),
MakeDoubleChecker<double> ())
--- a/src/internet-stack/ipv4-l3-protocol.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/internet-stack/ipv4-l3-protocol.cc Thu Nov 12 09:52:54 2009 +0100
@@ -82,8 +82,7 @@
}
Ipv4L3Protocol::Ipv4L3Protocol()
- : m_nInterfaces (0),
- m_identification (0)
+ : m_identification (0)
{
NS_LOG_FUNCTION_NOARGS ();
}
@@ -266,9 +265,8 @@
Ipv4L3Protocol::AddIpv4Interface (Ptr<Ipv4Interface>interface)
{
NS_LOG_FUNCTION (this << interface);
- uint32_t index = m_nInterfaces;
+ uint32_t index = m_interfaces.size ();
m_interfaces.push_back (interface);
- m_nInterfaces++;
return index;
}
@@ -276,14 +274,9 @@
Ipv4L3Protocol::GetInterface (uint32_t index) const
{
NS_LOG_FUNCTION (this << index);
- uint32_t tmp = 0;
- for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
+ if (index < m_interfaces.size ())
{
- if (index == tmp)
- {
- return *i;
- }
- tmp++;
+ return m_interfaces[index];
}
return 0;
}
@@ -292,7 +285,7 @@
Ipv4L3Protocol::GetNInterfaces (void) const
{
NS_LOG_FUNCTION_NOARGS ();
- return m_nInterfaces;
+ return m_interfaces.size ();
}
int32_t
--- a/src/internet-stack/ipv4-l3-protocol.h Wed Nov 11 16:25:10 2009 +0100
+++ b/src/internet-stack/ipv4-l3-protocol.h Thu Nov 12 09:52:54 2009 +0100
@@ -22,6 +22,7 @@
#define IPV4_L3_PROTOCOL_H
#include <list>
+#include <vector>
#include <stdint.h>
#include "ns3/ipv4-address.h"
#include "ns3/ptr.h"
@@ -233,7 +234,7 @@
Ptr<Icmpv4L4Protocol> GetIcmp (void) const;
bool IsUnicast (Ipv4Address ad, Ipv4Mask interfaceMask) const;
- typedef std::list<Ptr<Ipv4Interface> > Ipv4InterfaceList;
+ typedef std::vector<Ptr<Ipv4Interface> > Ipv4InterfaceList;
typedef std::list<Ptr<Ipv4RawSocketImpl> > SocketList;
typedef std::list<Ptr<Ipv4L4Protocol> > L4List_t;
--- a/src/mobility/mobility.h Wed Nov 11 16:25:10 2009 +0100
+++ b/src/mobility/mobility.h Thu Nov 12 09:52:54 2009 +0100
@@ -28,4 +28,9 @@
* - ns3::RandomDirection2dMobilityModel: a 2d random direction mobility
* model where the bounds of the mobility are are a rectangle.
*
+ * - ns3::WaypointMobilityModel: A model which determines paths from sets
+ * of ns3::Waypoint objects, similar to using events to update velocity
+ * and direction with a ns3::ConstantVelocityMobilityModel. This model
+ * is slightly faster for this task and uses less memory.
+ *
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/waypoint-mobility-model.cc Thu Nov 12 09:52:54 2009 +0100
@@ -0,0 +1,180 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 Phillip Sitbon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Phillip Sitbon <phillip@sitbon.net>
+ */
+#include <limits>
+#include "ns3/abort.h"
+#include "ns3/simulator.h"
+#include "ns3/uinteger.h"
+#include "ns3/log.h"
+#include "waypoint-mobility-model.h"
+
+NS_LOG_COMPONENT_DEFINE ("WaypointMobilityModel");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (WaypointMobilityModel);
+
+
+TypeId
+WaypointMobilityModel::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::WaypointMobilityModel")
+ .SetParent<MobilityModel> ()
+ .SetGroupName ("Mobility")
+ .AddConstructor<WaypointMobilityModel> ()
+ .AddAttribute ("NextWaypoint", "The next waypoint used to determine position.",
+ TypeId::ATTR_GET,
+ WaypointValue (),
+ MakeWaypointAccessor (&WaypointMobilityModel::GetNextWaypoint),
+ MakeWaypointChecker ())
+ .AddAttribute ("WaypointsLeft", "The number of waypoints remaining.",
+ TypeId::ATTR_GET,
+ UintegerValue (0),
+ MakeUintegerAccessor (&WaypointMobilityModel::WaypointsLeft),
+ MakeUintegerChecker<uint32_t> ())
+ ;
+ return tid;
+}
+
+
+WaypointMobilityModel::WaypointMobilityModel ()
+ : m_first (true)
+{
+}
+WaypointMobilityModel::~WaypointMobilityModel ()
+{
+}
+void
+WaypointMobilityModel::DoDispose (void)
+{
+ MobilityModel::DoDispose ();
+}
+void
+WaypointMobilityModel::AddWaypoint (const Waypoint &waypoint)
+{
+ if ( m_first )
+ {
+ m_first = false;
+ m_current = m_next = waypoint;
+ }
+ else
+ {
+ NS_ABORT_MSG_IF ( !m_waypoints.empty () && (m_waypoints.back ().time >= waypoint.time),
+ "Waypoints must be added in ascending time order");
+ m_waypoints.push_back (waypoint);
+ }
+}
+Waypoint
+WaypointMobilityModel::GetNextWaypoint (void) const
+{
+ Update ();
+ return m_next;
+}
+uint32_t
+WaypointMobilityModel::WaypointsLeft (void) const
+{
+ Update ();
+ return m_waypoints.size();
+}
+void
+WaypointMobilityModel::Update (void) const
+{
+ const Time now = Simulator::Now ();
+ bool newWaypoint = false;
+
+ if ( now <= m_current.time )
+ {
+ return;
+ }
+
+ while ( now >= m_next.time )
+ {
+ if ( m_waypoints.empty () )
+ {
+ if ( m_current.time <= m_next.time )
+ {
+ m_current.position = m_next.position;
+ m_current.time = now;
+ m_velocity = Vector (0,0,0);
+ NotifyCourseChange ();
+ }
+ else
+ {
+ m_current.time = now;
+ }
+
+ return;
+ }
+
+ m_current = m_next;
+ m_next = m_waypoints.front ();
+ m_waypoints.pop_front ();
+ newWaypoint = true;
+
+ const double t_span = (m_next.time - m_current.time).GetSeconds ();
+ NS_ASSERT (t_span > 0);
+ m_velocity.x = (m_next.position.x - m_current.position.x) / t_span;
+ m_velocity.y = (m_next.position.y - m_current.position.y) / t_span;
+ m_velocity.z = (m_next.position.z - m_current.position.z) / t_span;
+ }
+
+
+ const double t_diff = (now - m_current.time).GetSeconds();
+ m_current.position.x += m_velocity.x * t_diff;
+ m_current.position.y += m_velocity.y * t_diff;
+ m_current.position.z += m_velocity.z * t_diff;
+ m_current.time = now;
+
+ if ( newWaypoint )
+ {
+ NotifyCourseChange ();
+ }
+}
+Vector
+WaypointMobilityModel::DoGetPosition (void) const
+{
+ Update ();
+ return m_current.position;
+}
+void
+WaypointMobilityModel::DoSetPosition (const Vector &position)
+{
+ const Time now = Simulator::Now ();
+ Update ();
+ m_current.time = std::max (now, m_next.time);
+ m_current.position = position;
+ m_velocity = Vector (0,0,0);
+ NotifyCourseChange ();
+}
+void
+WaypointMobilityModel::EndMobility (void)
+{
+ m_waypoints.clear ();
+ m_current.time = Seconds (std::numeric_limits<double>::infinity ());
+ m_next.time = m_current.time;
+ m_first = true;
+}
+Vector
+WaypointMobilityModel::DoGetVelocity (void) const
+{
+ return m_velocity;
+}
+
+} // namespace ns3
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/waypoint-mobility-model.h Thu Nov 12 09:52:54 2009 +0100
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 Phillip Sitbon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Phillip Sitbon <phillip@sitbon.net>
+ */
+#ifndef WAYPOINT_MOBILITY_MODEL_H
+#define WAYPOINT_MOBILITY_MODEL_H
+
+#include <stdint.h>
+#include <deque>
+#include "mobility-model.h"
+#include "ns3/vector.h"
+#include "waypoint.h"
+
+namespace ns3 {
+
+/**
+ * \brief a waypoint-based mobility model
+ *
+ * Each object determines its velocity and position at a given time
+ * from a set of ns3::Waypoint objects. The position of each object
+ * is not updated unless queried, and past waypoints are discarded
+ * after the current simulation time greater than their time value.
+ *
+ * The initial position of each object corresponds to the position of
+ * the first waypoint, and the initial velocity of each object is zero.
+ * Upon reaching the last waypoint, object positions becomes static and
+ * velocity is zero.
+ *
+ * When a node is in between waypoints (in time), it moves with a constant
+ * velocity between the position at the previous waypoint and the position
+ * at the current waypoint. To make a node hold a certain position for a
+ * time interval, two waypoints with the same position (but different times)
+ * should be inserted sequentially.
+ *
+ * Waypoints can be added at any time, and setting the current position
+ * of an object will set its velocity to zero until the next waypoint time
+ * (at which time the object jumps to the next waypoint), unless there are
+ * no more waypoints in which case it will not change without user
+ * intervention.
+ *
+ */
+class WaypointMobilityModel : public MobilityModel
+{
+ public:
+ static TypeId GetTypeId (void);
+
+ /**
+ * Create a path with no waypoints at location (0,0,0).
+ */
+ WaypointMobilityModel ();
+ virtual ~WaypointMobilityModel ();
+
+ /**
+ * \param waypoint waypoint to append to the object path.
+ *
+ * Add a waypoint to the path of the object. The time must
+ * be greater than the previous waypoint added, otherwise
+ * a fatal error occurs. The first waypoint is set as the
+ * current position with a velocity of zero.
+ *
+ */
+ void AddWaypoint (const Waypoint &waypoint);
+
+ /**
+ * Get the waypoint that this object is traveling towards.
+ */
+ Waypoint GetNextWaypoint (void) const;
+
+ /**
+ * Get the number of waypoints left for this object, excluding
+ * the next one.
+ */
+ uint32_t WaypointsLeft (void) const;
+
+ /**
+ * Clear any existing waypoints and set the current waypoint
+ * time to infinity. Calling this is only an optimization and
+ * not required. After calling this function, adding waypoints
+ * behaves as it would for a new object.
+ */
+ void EndMobility (void);
+
+ private:
+ void Update (void) const;
+ virtual void DoDispose (void);
+ virtual Vector DoGetPosition (void) const;
+ virtual void DoSetPosition (const Vector &position);
+ virtual Vector DoGetVelocity (void) const;
+
+ bool m_first;
+ mutable std::deque<Waypoint> m_waypoints;
+ mutable Waypoint m_current;
+ mutable Waypoint m_next;
+ mutable Vector m_velocity;
+};
+
+} // namespace ns3
+
+#endif /* WAYPOINT_MOBILITY_MODEL_H */
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/waypoint.cc Thu Nov 12 09:52:54 2009 +0100
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 Phillip Sitbon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Phillip Sitbon <phillip@sitbon.net>
+ */
+#include "waypoint.h"
+
+namespace ns3 {
+
+ATTRIBUTE_HELPER_CPP (Waypoint);
+
+Waypoint::Waypoint (const Time &waypointTime, const Vector &waypointPosition)
+ : time (waypointTime),
+ position (waypointPosition)
+{}
+Waypoint::Waypoint ()
+ : time (0.0),
+ position (0,0,0)
+{}
+
+std::ostream &operator << (std::ostream &os, const Waypoint &waypoint)
+{
+ os << waypoint.time.GetSeconds () << "$" << waypoint.position;
+ return os;
+}
+std::istream &operator >> (std::istream &is, Waypoint &waypoint)
+{
+ char separator;
+ is >> waypoint.time >> separator >> waypoint.position;
+ if (separator != '$')
+ {
+ is.setstate (std::ios_base::failbit);
+ }
+ return is;
+}
+
+} // namespace ns3
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/waypoint.h Thu Nov 12 09:52:54 2009 +0100
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 Phillip Sitbon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Phillip Sitbon <phillip@sitbon.net>
+ */
+#ifndef WAYPOINT_H
+#define WAYPOINT_H
+
+#include "ns3/attribute.h"
+#include "ns3/attribute-helper.h"
+#include "ns3/nstime.h"
+#include "ns3/vector.h"
+
+namespace ns3 {
+
+/**
+ * \brief a (time, location) pair.
+ *
+ */
+class Waypoint
+{
+public:
+ /**
+ * \param _time time of waypoint.
+ * \param _position position of waypoint corresponding to the given time.
+ *
+ * Create a waypoint.
+ */
+ Waypoint (const Time &waypointTime, const Vector &waypointPosition);
+
+ /**
+ * Create a waypoint at time 0 and position (0,0,0).
+ */
+ Waypoint ();
+ /* The waypoint time */
+ Time time;
+ /* The position of the waypoint */
+ Vector position;
+};
+
+/**
+ * \class ns3::WaypointValue
+ * \brief hold objects of type ns3::Waypoint
+ */
+ATTRIBUTE_HELPER_HEADER ( Waypoint);
+
+std::ostream &
+operator << (std::ostream &os, const Waypoint &waypoint);
+std::istream &
+operator >> (std::istream &is, Waypoint &waypoint);
+
+} // namespace ns3
+
+#endif /* WAYPOINT_H */
+
--- a/src/mobility/wscript Wed Nov 11 16:25:10 2009 +0100
+++ b/src/mobility/wscript Thu Nov 12 09:52:54 2009 +0100
@@ -14,6 +14,8 @@
'random-walk-2d-mobility-model.cc',
'random-direction-2d-mobility-model.cc',
'constant-acceleration-mobility-model.cc',
+ 'waypoint.cc',
+ 'waypoint-mobility-model.cc',
]
headers = bld.new_task_gen('ns3header')
@@ -30,4 +32,6 @@
'random-walk-2d-mobility-model.h',
'random-direction-2d-mobility-model.h',
'constant-acceleration-mobility-model.h',
+ 'waypoint.h',
+ 'waypoint-mobility-model.h',
]
--- a/src/simulator/simulator.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/src/simulator/simulator.cc Thu Nov 12 09:52:54 2009 +0100
@@ -297,6 +297,12 @@
NS_FATAL_ERROR ("It is not possible to set the implementation after calling any Simulator:: function. Call Simulator::SetImplementation earlier or after Simulator::Destroy.");
}
*PeekImpl () = impl;
+ // Set the default scheduler
+ ObjectFactory factory;
+ StringValue s;
+ g_schedTypeImpl.GetValue (s);
+ factory.SetTypeId (s.Get ());
+ impl->SetScheduler (factory.Create<Scheduler> ());
//
// Note: we call LogSetTimePrinter _after_ creating the implementation
// object because the act of creation can trigger calls to the logging
--- a/test.py Wed Nov 11 16:25:10 2009 +0100
+++ b/test.py Thu Nov 12 09:52:54 2009 +0100
@@ -132,6 +132,7 @@
("tutorial/second", "True", "True"),
("tutorial/third", "True", "True"),
("tutorial/fourth", "True", "True"),
+ ("tutorial/fifth", "True", "True"),
("udp/udp-echo", "True", "True"),
@@ -616,6 +617,7 @@
self.shell_command = ""
self.display_name = ""
self.basedir = ""
+ self.tempdir = ""
self.cwd = ""
self.tmp_file_name = ""
self.returncode = False
@@ -674,6 +676,13 @@
self.basedir = basedir
#
+ # This is the directory to which a running test suite should write any
+ # temporary files.
+ #
+ def set_tempdir(self, tempdir):
+ self.tempdir = tempdir
+
+ #
# This is the current working directory that will be given to an executing
# test as it is being run. It will be used for examples to tell them where
# to write all of the pcap files that we will be carefully ignoring. For
@@ -766,7 +775,8 @@
# file name
#
(job.returncode, standard_out, standard_err, et) = run_job_synchronously(job.shell_command +
- " --basedir=%s --out=%s" % (job.basedir, job.tmp_file_name), job.cwd, options.valgrind)
+ " --basedir=%s --tempdir=%s --out=%s" % (job.basedir, job.tempdir, job.tmp_file_name),
+ job.cwd, options.valgrind)
job.set_elapsed_time(et)
@@ -1004,6 +1014,7 @@
job.set_tmp_file_name(os.path.join(testpy_output_dir, "%s.xml" % test))
job.set_cwd(os.getcwd())
job.set_basedir(os.getcwd())
+ job.set_tempdir(testpy_output_dir)
if (options.multiple):
multiple = " --multiple"
else:
@@ -1074,6 +1085,7 @@
job.set_tmp_file_name("")
job.set_cwd(testpy_output_dir)
job.set_basedir(os.getcwd())
+ job.set_tempdir(testpy_output_dir)
job.set_shell_command("examples/%s" % test)
if options.valgrind and not eval(do_valgrind_run):
@@ -1097,6 +1109,7 @@
job.set_tmp_file_name("")
job.set_cwd(testpy_output_dir)
job.set_basedir(os.getcwd())
+ job.set_tempdir(testpy_output_dir)
job.set_shell_command("examples/%s" % options.example)
if options.verbose:
--- a/utils/test-runner.cc Wed Nov 11 16:25:10 2009 +0100
+++ b/utils/test-runner.cc Thu Nov 12 09:52:54 2009 +0100
@@ -40,11 +40,13 @@
bool doKinds = false;
bool haveBasedir = false;
+ bool haveTempdir = false;
bool haveOutfile = false;
bool haveType = false;
std::string suiteName;
std::string basedir;
+ std::string tempdir;
std::string outfileName;
std::string typeName;
@@ -96,6 +98,12 @@
doSuite = true;
}
+ if (arg.find ("--tempdir=") != std::string::npos)
+ {
+ tempdir = arg.substr (arg.find_first_of ("=") + 1, 9999);
+ haveTempdir = true;
+ }
+
if (arg.compare ("--verbose") == 0)
{
doVerbose = true;
@@ -247,6 +255,7 @@
if (doSuite == false || (doSuite == true && suiteName == testSuite->GetName ()))
{
testSuite->SetBaseDir (basedir);
+ testSuite->SetTempDir (tempdir);
testSuite->SetStream (pofs);
testSuite->SetVerbose (doVerbose);
testSuite->SetContinueOnFailure (doMultiple);