diff --git a/doc/build-waf.txt b/doc/build-waf.txt index 056a45274..42bc70eb1 100644 --- a/doc/build-waf.txt +++ b/doc/build-waf.txt @@ -12,39 +12,55 @@ Gustavo Carneiro (gjcarneiro@gmail.com) is the maintainer. === Building with Waf === To build ns-3 with waf type the commands: - 1. ./waf configure [options] - 2. ./waf + 1. waf configure [options] + 2. waf -[ Note: if ./waf does not exist, see the section "Note for developers" below ] +[ Note: if waf does not exist in your path, see the section +"Note for developers" below ] -To see valid configure options, type ./waf --help. The most important +To see valid configure options, type waf --help. The most important option is -d . Valid debug levels (which are listed in -./waf --help) are: ultradebug, debug, release, and optimized. +waf --help) are: ultradebug, debug, release, and optimized. It is +also possible to change the flags used for compilation with (e.g.): +CXXFLAGS="-O3" waf configure. + +[ Note: Unlike some other build tools, to change the build target, +the option must be supplied during the configure stage rather than +the build stage (i.e., "waf -d optimized" will not work; instead, do +"waf -d optimized configure; waf" ] The resulting binaries are placed in build//srcpath. Other waf usages include: - 1. ./waf check + 1. waf check Runs the unit tests - 2. ./waf --doxygen + 2. waf --doxygen Run doxygen to generate documentation - 3. ./waf --lcov-report + 3. waf --lcov-report Run code coverage analysis (assuming the project was configured with --enable-gcov) - 4. ./waf --run "program [args]" + 4. waf --run "program [args]" Run a ns3 program, given its target name, with the given arguments. This takes care of automatically modifying the the path for finding the ns3 dynamic libraries in the environment before running the program. Note: the "program [args]" string is parsed using POSIX shell rules. - 5. ./waf --shell + 5. waf --shell Starts a nested system shell with modified environment to run ns3 programs. + 6. waf distclean + Cleans out the entire build/ directory + + 7. waf dist + The command 'waf dist' can be used to create a distribution tarball. + It includes all files in the source directory, except some particular + extensions that are blacklisted, such as back files (ending in ~). + === Extending ns-3 === @@ -90,13 +106,9 @@ developers should check it out from a subversion repository: tested to work correctly with ns3, although 'trunk' will likely work as well ] -Then it can be installed system-wide with 'sudo ./waf-light install'. +Then it can be installed system-wide with 'sudo waf-light install'. When preparing a distribution, the resulting 'waf' script, which is self contained (no external files needed), can be easily included in the tarball so that users downloading ns-3 can easily build it without having Waf installed (although Python >= 2.3 is still needed). -The command 'waf dist' can be used to create a distribution tarball. -It includes all files in the source directory, except some particular -extensions that are blacklisted, such as back files (ending in ~). - diff --git a/src/applications/wscript b/src/applications/wscript index 85fa0513b..0874d58ab 100644 --- a/src/applications/wscript +++ b/src/applications/wscript @@ -1,10 +1,5 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- - -def configure(conf): - conf.env.append_value('NS3_MODULES', 'ns3-applications') - - def build(bld): obj = bld.create_obj('cpp', 'shlib') obj.name = 'ns3-applications' diff --git a/src/common/wscript b/src/common/wscript index c6f3be7f0..6efd5bfc9 100644 --- a/src/common/wscript +++ b/src/common/wscript @@ -1,8 +1,5 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -def configure(conf): - conf.env.append_value('NS3_MODULES', 'ns3-common') - def build(bld): common = bld.create_obj('cpp', 'shlib') common.name = 'ns3-common' diff --git a/src/core/test.h b/src/core/test.h index 982cb989c..356c08ee2 100644 --- a/src/core/test.h +++ b/src/core/test.h @@ -130,8 +130,8 @@ private: if (!(assertion)) \ { \ Failure () << __FILE__ << ":" <<__LINE__ \ - << ": assertion `" << (assertion) \ - << "'failed." << std::endl; \ + << ": assertion `" << #assertion \ + << "' failed." << std::endl; \ result = false; \ } diff --git a/src/core/wscript b/src/core/wscript index ce9795c8e..222539171 100644 --- a/src/core/wscript +++ b/src/core/wscript @@ -3,8 +3,6 @@ import sys def configure(conf): - conf.env.append_value('NS3_MODULES', 'ns3-core') - e = conf.create_header_configurator() e.mandatory = False e.name = 'stdlib.h' diff --git a/src/devices/p2p/p2p-channel.cc b/src/devices/p2p/p2p-channel.cc index 2833c8bb1..adceda3f4 100644 --- a/src/devices/p2p/p2p-channel.cc +++ b/src/devices/p2p/p2p-channel.cc @@ -76,8 +76,7 @@ PointToPointChannel::Attach(Ptr device) NS_ASSERT(m_nDevices < N_DEVICES && "Only two devices permitted"); NS_ASSERT(device != 0); - m_link[m_nDevices].m_src = device; - ++m_nDevices; + m_link[m_nDevices++].m_src = device; // // If we have both devices connected to the channel, then finish introducing // the two halves and set the links to IDLE. @@ -91,8 +90,9 @@ PointToPointChannel::Attach(Ptr device) } } -bool -PointToPointChannel::TransmitStart(Packet& p, Ptr src) +bool PointToPointChannel::TransmitStart(Packet& p, + Ptr src, + const Time& txTime) { NS_DEBUG ("PointToPointChannel::TransmitStart (" << &p << ", " << src << ")"); @@ -104,65 +104,15 @@ PointToPointChannel::TransmitStart(Packet& p, Ptr src) uint32_t wire = src == m_link[0].m_src ? 0 : 1; - if (m_link[wire].m_state == TRANSMITTING) - { - NS_DEBUG("PointToPointChannel::TransmitStart (): **** ERROR ****"); - NS_DEBUG("PointToPointChannel::TransmitStart (): state TRANSMITTING"); - return false; - } - - NS_DEBUG("PointToPointChannel::TransmitStart (): switch to TRANSMITTING"); - m_link[wire].m_state = TRANSMITTING; + // Here we schedule the packet receive event at the receiver, + // which simplifies this model quite a bit. The channel just + // adds the propagation delay time + Simulator::Schedule (txTime + m_delay, + &PointToPointNetDevice::Receive, + m_link[wire].m_dst, p); return true; } -bool -PointToPointChannel::TransmitEnd(Packet& p, Ptr src) -{ - NS_DEBUG("PointToPointChannel::TransmitEnd (" << &p << ", " << src << ")"); - NS_DEBUG ("PointToPointChannel::TransmitEnd (): UID is " << - p.GetUid () << ")"); - - NS_ASSERT(m_link[0].m_state != INITIALIZING); - NS_ASSERT(m_link[1].m_state != INITIALIZING); - - uint32_t wire = src == m_link[0].m_src ? 0 : 1; - - NS_ASSERT(m_link[wire].m_state == TRANSMITTING); - - m_link[wire].m_state = PROPAGATING; -// -// The sender is going to free the packet as soon as it has been transmitted. -// We need to copy it to get a reference so it won't e deleted. -// - Packet packet = p; - NS_DEBUG ("PointToPointChannel::TransmitEnd (): Schedule event in " << - m_delay.GetSeconds () << "sec"); - Simulator::Schedule (m_delay, - &PointToPointChannel::PropagationCompleteEvent, - this, packet, src); - return true; -} - -void -PointToPointChannel::PropagationCompleteEvent( - Packet p, - Ptr src) -{ - NS_DEBUG("PointToPointChannel::PropagationCompleteEvent (" << &p << ", " << - src << ")"); - NS_DEBUG ("PointToPointChannel::PropagationCompleteEvent (): UID is " << - p.GetUid () << ")"); - - uint32_t wire = src == m_link[0].m_src ? 0 : 1; - NS_ASSERT(m_link[wire].m_state == PROPAGATING); - m_link[wire].m_state = IDLE; - - NS_DEBUG ("PointToPointChannel::PropagationCompleteEvent (): Receive"); - m_link[wire].m_dst->Receive (p); -} - - uint32_t PointToPointChannel::GetNDevices (void) const { @@ -176,13 +126,13 @@ PointToPointChannel::GetDevice (uint32_t i) const return m_link[i].m_src; } - DataRate +const DataRate& PointToPointChannel::GetDataRate (void) { return m_bps; } - Time +const Time& PointToPointChannel::GetDelay (void) { return m_delay; diff --git a/src/devices/p2p/p2p-channel.h b/src/devices/p2p/p2p-channel.h index 97a251177..71bc50ca3 100644 --- a/src/devices/p2p/p2p-channel.h +++ b/src/devices/p2p/p2p-channel.h @@ -51,11 +51,7 @@ class PointToPointNetDevice; */ class PointToPointChannel : public Channel { public: -// -// This is really kidding myself, since just setting N_DEVICES to 3 isn't -// going to come close to magically creating a multi-drop link, but I can't -// bring myself to just type 2 in the code (even though I type 0 and 1 :-). -// +// Each point to point link has exactly two net devices static const int N_DEVICES = 2; /** * \brief Create a PointToPointChannel @@ -68,7 +64,7 @@ public: /** * \brief Create a PointToPointChannel * - * \param bps The bitrate of the channel + * \param bps The maximum bitrate of the channel * \param delay Transmission delay through the channel */ PointToPointChannel (const DataRate& bps, const Time& delay); @@ -77,7 +73,7 @@ public: * \brief Create a PointToPointChannel * * \param name the name of the channel for identification purposes - * \param bps The bitrate of the channel + * \param bps The maximum bitrate of the channel * \param delay Transmission delay through the channel */ PointToPointChannel (const std::string& name, @@ -88,21 +84,22 @@ public: * \param device pointer to the netdevice to attach to the channel */ void Attach (Ptr device); - bool TransmitStart (Packet& p, Ptr src); - bool TransmitEnd (Packet &p, Ptr src); - void PropagationCompleteEvent(Packet p, Ptr src); + bool TransmitStart (Packet& p, Ptr src, + const Time& txTime); + // Below two not needed + //bool TransmitEnd (Packet &p, Ptr src); + //void PropagationCompleteEvent(Packet p, Ptr src); virtual uint32_t GetNDevices (void) const; virtual Ptr GetDevice (uint32_t i) const; - virtual DataRate GetDataRate (void); - virtual Time GetDelay (void); + virtual const DataRate& GetDataRate (void); + virtual const Time& GetDelay (void); private: DataRate m_bps; Time m_delay; - int32_t m_nDevices; enum WireState diff --git a/src/devices/p2p/p2p-net-device.cc b/src/devices/p2p/p2p-net-device.cc index 9542d951b..102cc247f 100644 --- a/src/devices/p2p/p2p-net-device.cc +++ b/src/devices/p2p/p2p-net-device.cc @@ -16,7 +16,8 @@ * 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 + * Author: Craig Dowell + * Revised: George Riley */ #include @@ -32,11 +33,17 @@ NS_DEBUG_COMPONENT_DEFINE ("PointToPointNetDevice"); namespace ns3 { -PointToPointNetDevice::PointToPointNetDevice (Ptr node) +DataRateDefaultValue PointToPointNetDevice::g_defaultRate( + "PointToPointLinkDataRate", + "The default data rate for point to point links", + DataRate ("10Mb/s")); + + PointToPointNetDevice::PointToPointNetDevice (Ptr node, + const DataRate& rate) : - NetDevice(node, MacAddress ("00:00:00:00:00:00")), + NetDevice(node, MacAddress (6)), m_txMachineState (READY), - m_bps (DataRate (0xffffffff)), + m_bps (rate), m_tInterframeGap (Seconds(0)), m_channel (0), m_queue (0), @@ -73,6 +80,9 @@ PointToPointNetDevice::~PointToPointNetDevice() // We're assuming that the tracing will be set up after the topology creation // phase and this won't actually matter. // +// GFR Comments. Don't see where the "copy the pointer and add reference" +// stated above is done. Can original author please comment and/or fix. +// Shouldn't the queue pointer also bump the refcount? PointToPointNetDevice::PointToPointNetDevice (const PointToPointNetDevice& nd) : NetDevice(nd), @@ -92,6 +102,8 @@ PointToPointNetDevice::PointToPointNetDevice (const PointToPointNetDevice& nd) } + // GFR COmments...shouldn't this decrement the refcount instead + // of just nil-ing out the pointer? Don't understand this. void PointToPointNetDevice::DoDispose() { m_channel = 0; @@ -101,100 +113,54 @@ void PointToPointNetDevice::DoDispose() // // Assignment operator for PointToPointNetDevice. // -// This uses the non-obvious trick of taking the source net device passed by -// value instead of by reference. This causes the copy constructor to be -// invoked (where the real work is done -- see above). All we have to do -// here is to return the newly constructed net device. // - PointToPointNetDevice& -PointToPointNetDevice::operator= (const PointToPointNetDevice nd) +PointToPointNetDevice& +PointToPointNetDevice::operator= (const PointToPointNetDevice& nd) { NS_DEBUG ("PointToPointNetDevice::operator= (" << &nd << ")"); + // FIXME. Not sure what to do here + // GFR Note. I would suggest dis-allowing netdevice assignment, + // as well as pass-by-value (ie. copy constructor). + // This resolves some of the questions above about copy constructors. + // Why should we ever copy or assign a net device? return *this; } - void -PointToPointNetDevice::SetDataRate(DataRate bps) +void PointToPointNetDevice::SetDataRate(const DataRate& bps) { m_bps = bps; } - void -PointToPointNetDevice::SetInterframeGap(Time t) +void PointToPointNetDevice::SetInterframeGap(const Time& t) { m_tInterframeGap = t; } - bool -PointToPointNetDevice::SendTo (Packet& p, const MacAddress& dest) +bool PointToPointNetDevice::SendTo (Packet& p, const MacAddress& dest) { NS_DEBUG ("PointToPointNetDevice::SendTo (" << &p << ", " << &dest << ")"); NS_DEBUG ("PointToPointNetDevice::SendTo (): UID is " << p.GetUid () << ")"); + // GFR Comment. Why is this an assertion? Can't a link legitimately + // "go down" during the simulation? Shouldn't we just wait for it + // to come back up? NS_ASSERT (IsLinkUp ()); -#ifdef NOTYET - struct NetDevicePacketDestAddress tag; - tag.address = address; - p.AddTag (tag); -#endif - // // This class simulates a point to point device. In the case of a serial -// link, this means that we're simulating something like a UART. This is -// not a requirement for a point-to-point link, but it's a typical model for -// the device. +// link, this means that we're simulating something like a UART. // -// Generally, a real device will have a list of pending packets to transmit. -// An on-device CPU frees the main CPU(s) of the details of what is happening -// in the device and feeds the USART. The main CPU basically just sees the -// list of packets -- it puts packets into the list, and the device frees the -// packets when they are transmitted. -// -// In the case of our virtual device here, the queue pointed to by m_queue -// corresponds to this list. The main CPU adds packets to the list by -// calling this method and when the device completes a send, the packets are -// freed in an "interrupt" service routine. -// -// We're going to do the same thing here. So first of all, the incoming packet -// goes onto our queue if possible. If the queue can't handle it, there's -// nothing to be done. -// - if (m_queue->Enqueue(p) == false ) - { - return false; - } -// -// If there's a transmission in progress, the "interrupt" will keep the -// transmission process going. If the device is idle, we need to start a -// transmission. -// -// In the real world, the USART runs until it finishes sending bits, and then -// pulls on the device's transmit complete interrupt wire. At the same time, -// the electrons from the last wiggle of the wire are busy propagating down -// the wire. In the case of a long speed-of-light delay in the wire, we could -// conceivably start transmitting the next packet before the end of the -// previously sent data has even reached the end of the wire. This situation -// is usually avoided (like the plague) and an "interframe gap" is introduced. -// This is usually the round-trip delay on the channel plus some hard-to- -// quantify receiver turn-around time (the time required for the receiver -// to process the last frame and prepare for reception of the next). -// -// So, if the transmit machine is ready, we need to schedule a transmit -// complete event (at which time we tell the channel we're no longer sending -// bits). A separate transmit ready event (at which time the transmitter -// becomes ready to start sending bits again is scheduled there). Finally, -// we tell the channel (via TransmitStart ()) that we've started wiggling the -// wire and bits are coming out. -// -// If the transmit machine is not ready, we just leave and the transmit ready -// event we know is coming will kick-start the transmit process. // +// If there's a transmission in progress, we enque the packet for later +// trnsmission; otherwise we send it now. if (m_txMachineState == READY) { return TransmitStart (p); } - return true; + else + { + return m_queue->Enqueue(p); + } } bool @@ -206,81 +172,41 @@ PointToPointNetDevice::TransmitStart (Packet &p) // // This function is called to start the process of transmitting a packet. // We need to tell the channel that we've started wiggling the wire and -// schedule an event that will be executed when it's time to tell the -// channel that we're done wiggling the wire. +// schedule an event that will be executed when the transmission is complete. // NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit"); m_txMachineState = BUSY; - Time tEvent = Seconds (m_bps.CalculateTxTime(p.GetSize())); + Time txTime = Seconds (m_bps.CalculateTxTime(p.GetSize())); + Time txCompleteTime = txTime + m_tInterframeGap; NS_DEBUG ("PointToPointNetDevice::TransmitStart (): " << "Schedule TransmitCompleteEvent in " << - tEvent.GetSeconds () << "sec"); - - Simulator::Schedule (tEvent, - &PointToPointNetDevice::TransmitCompleteEvent, + txCompleteTime.GetSeconds () << "sec"); + // Schedule the tx complete event + Simulator::Schedule (txCompleteTime, + &PointToPointNetDevice::TransmitComplete, this); - return m_channel->TransmitStart (p, this); + return m_channel->TransmitStart(p, this, txTime); } - void -PointToPointNetDevice::TransmitCompleteEvent (void) +void PointToPointNetDevice::TransmitComplete (void) { NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent ()"); // // This function is called to finish the process of transmitting a packet. // We need to tell the channel that we've stopped wiggling the wire and -// schedule an event that will be executed when it's time to re-enable -// the transmitter after the interframe gap. +// get the next packet from the queue. If the queue is empty, we are +// done, otherwise transmit the next packet. // NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting"); - m_txMachineState = GAP; - Packet p; - bool found; - found = m_queue->Dequeue (p); - NS_ASSERT_MSG(found, "Packet must be on queue if transmitted"); - NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent (): Pkt UID is " << - p.GetUid () << ")"); - m_channel->TransmitEnd (p, this); - - NS_DEBUG ( - "PointToPointNetDevice::TransmitCompleteEvent (): " << - "Schedule TransmitReadyEvent in " - << m_tInterframeGap.GetSeconds () << "sec"); - - Simulator::Schedule (m_tInterframeGap, - &PointToPointNetDevice::TransmitReadyEvent, - this); -} - - void -PointToPointNetDevice::TransmitReadyEvent (void) -{ - NS_DEBUG ("PointToPointNetDevice::TransmitReadyEvent ()"); -// -// This function is called to enable the transmitter after the interframe -// gap has passed. If there are pending transmissions, we use this opportunity -// to start the next transmit. -// - NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap"); m_txMachineState = READY; - - if (m_queue->IsEmpty()) - { - return; - } - else - { - Packet p; - bool found; - found = m_queue->Peek (p); - NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?"); - TransmitStart (p); - } + Packet p; + if (!m_queue->Dequeue(p)) return; // Nothing to do at this point + TransmitStart(p); } -TraceResolver * -PointToPointNetDevice::DoCreateTraceResolver (TraceContext const &context) +TraceResolver* PointToPointNetDevice::DoCreateTraceResolver ( + TraceContext const &context) { CompositeTraceResolver *resolver = new CompositeTraceResolver (context); resolver->Add ("queue", @@ -292,8 +218,7 @@ PointToPointNetDevice::DoCreateTraceResolver (TraceContext const &context) return resolver; } -bool -PointToPointNetDevice::Attach (Ptr ch) +bool PointToPointNetDevice::Attach (Ptr ch) { NS_DEBUG ("PointToPointNetDevice::Attach (" << &ch << ")"); @@ -301,7 +226,9 @@ PointToPointNetDevice::Attach (Ptr ch) m_channel->Attach(this); m_bps = m_channel->GetDataRate (); - m_tInterframeGap = m_channel->GetDelay (); + // GFR Comment. Below is definitely wrong. Interframe gap + // is unrelated to channel delay. + //m_tInterframeGap = m_channel->GetDelay (); /* * For now, this device is up whenever a channel is attached to it. @@ -315,38 +242,32 @@ PointToPointNetDevice::Attach (Ptr ch) return true; } -void -PointToPointNetDevice::AddQueue (Ptr q) +void PointToPointNetDevice::AddQueue (Ptr q) { NS_DEBUG ("PointToPointNetDevice::AddQueue (" << q << ")"); m_queue = q; } -void -PointToPointNetDevice::Receive (Packet& p) +void PointToPointNetDevice::Receive (Packet& p) { - // ignore return value for now. NS_DEBUG ("PointToPointNetDevice::Receive (" << &p << ")"); m_rxTrace (p); ForwardUp (p); } -Ptr -PointToPointNetDevice::GetQueue(void) const +Ptr PointToPointNetDevice::GetQueue(void) const { return m_queue; } -Ptr -PointToPointNetDevice::DoGetChannel(void) const +Ptr PointToPointNetDevice::DoGetChannel(void) const { return m_channel; } -bool -PointToPointNetDevice::DoNeedsArp (void) const +bool PointToPointNetDevice::DoNeedsArp (void) const { return false; } diff --git a/src/devices/p2p/p2p-net-device.h b/src/devices/p2p/p2p-net-device.h index e1eb8a666..526d84523 100644 --- a/src/devices/p2p/p2p-net-device.h +++ b/src/devices/p2p/p2p-net-device.h @@ -30,6 +30,7 @@ #include "ns3/callback-trace-source.h" #include "ns3/nstime.h" #include "ns3/data-rate.h" +#include "ns3/default-value.h" #include "ns3/ptr.h" namespace ns3 { @@ -80,7 +81,8 @@ public: * @see PointToPointTopology::AddPointToPointLink () * @param node the Node to which this device is connected. */ - PointToPointNetDevice (Ptr node); + PointToPointNetDevice (Ptr node, + const DataRate& = g_defaultRate.GetValue()); /** * Copy Construct a PointToPointNetDevice * @@ -105,7 +107,7 @@ public: * * @param nd the object to be copied */ - PointToPointNetDevice& operator= (PointToPointNetDevice nd); + PointToPointNetDevice& operator= (const PointToPointNetDevice& nd); /** * Set the Data Rate used for transmission of packets. The data rate is * set in the Attach () method from the corresponding field in the channel @@ -114,7 +116,7 @@ public: * @see Attach () * @param bps the data rate at which this object operates */ - void SetDataRate(DataRate bps); + void SetDataRate(const DataRate& bps); /** * Set the inteframe gap used to separate packets. The interframe gap * defines the minimum space required between packets sent by this device. @@ -125,7 +127,7 @@ public: * @see Attach () * @param t the interframe gap time */ - void SetInterframeGap(Time t); + void SetInterframeGap(const Time& t); /** * Attach the device to a channel. * @@ -190,6 +192,19 @@ protected: * @returns a pointer to the channel */ virtual Ptr DoGetChannel(void) const; + /** + * Set a new default data rate + * @param Data rate to set for new default + */ + static void SetDefaultRate(const DataRate&); + + /** + * Get the current default rate. + * @returns a const reference to current default + */ + + static const DataRate& GetDefaultRate(); + private: /** * Send a Packet Down the Wire. @@ -223,39 +238,17 @@ private: /** * Stop Sending a Packet Down the Wire and Begin the Interframe Gap. * - * The TransmitCompleteEvent method is used internally to finish the process - * of sending a packet out on the channel. During execution of this method - * the TransmitEnd method is called on the channel to let it know that the - * physical device this class represents has virually finished sending - * signals. The channel uses this event to begin its speed of light delay - * timer after which it notifies the Net Device at the other end of the - * link that the bits have arrived. During this method, the net device - * also schedules the TransmitReadyEvent at which time the transmitter - * becomes ready to send the next packet. + * The TransmitComplete method is used internally to finish the process + * of sending a packet out on the channel. * - * @see PointToPointChannel::TransmitEnd () - * @see TransmitReadyEvent () - * @returns true if success, false on failure */ - void TransmitCompleteEvent (void); - /** - * Cause the Transmitter to Become Ready to Send Another Packet. - * - * The TransmitReadyEvent method is used internally to re-enable the - * transmit machine of the net device. It is scheduled after a suitable - * interframe gap after the completion of the previous transmission. - * The queue is checked at this time, and if there is a packet waiting on - * the queue, the transmission process is begun. - * - * @see TransmitStart () - */ - void TransmitReadyEvent (void); + void TransmitComplete(void); /** * Create a Trace Resolver for events in the net device. * * @see class TraceResolver */ - virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context); + virtual TraceResolver* DoCreateTraceResolver (TraceContext const &context); virtual bool DoNeedsArp (void) const; /** * Enumeration of the states of the transmit machine of the net device. @@ -263,8 +256,7 @@ private: enum TxMachineState { READY, /**< The transmitter is ready to begin transmission of a packet */ - BUSY, /**< The transmitter is busy transmitting a packet */ - GAP /**< The transmitter is in the interframe gap time */ + BUSY /**< The transmitter is busy transmitting a packet */ }; /** * The state of the Net Device transmit state machine. @@ -305,6 +297,11 @@ private: * @see class TraceResolver */ CallbackTraceSource m_rxTrace; + /** + * Default data rate. Used for all newly created p2p net devices + */ + static DataRateDefaultValue g_defaultRate; + }; }; // namespace ns3 diff --git a/src/devices/p2p/wscript b/src/devices/p2p/wscript index c4c0f7952..73b27d061 100644 --- a/src/devices/p2p/wscript +++ b/src/devices/p2p/wscript @@ -1,10 +1,6 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -def configure(conf): - conf.env.append_value('NS3_MODULES', 'ns3-p2p') - - def build(bld): p2p = bld.create_obj('cpp', 'shlib') p2p.name = 'ns3-p2p' diff --git a/src/internet-node/wscript b/src/internet-node/wscript index 806861fd3..bf3236159 100644 --- a/src/internet-node/wscript +++ b/src/internet-node/wscript @@ -1,10 +1,6 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -def configure(conf): - conf.env.append_value('NS3_MODULES', 'ns3-internet-node') - - def build(bld): obj = bld.create_obj('cpp', 'shlib') obj.name = 'ns3-internet-node' diff --git a/src/node/mac-address.cc b/src/node/mac-address.cc index be455a8a3..9dcf9bdd6 100644 --- a/src/node/mac-address.cc +++ b/src/node/mac-address.cc @@ -33,6 +33,9 @@ namespace ns3 { +// Static variables +uint8_t MacAddress::g_nextAddress[MacAddress::MAX_LEN]; + static char AsciiToLowCase (char c) { @@ -54,6 +57,13 @@ MacAddress::MacAddress () : m_len(0) } } +MacAddress::MacAddress(uint8_t len) : m_len(len) +{ + NS_ASSERT (len <= MacAddress::MAX_LEN); + AdvanceAddress(); + memcpy(m_address, g_nextAddress, len); +} + MacAddress::MacAddress (uint8_t const *address, uint8_t len) { NS_ASSERT (len <= MacAddress::MAX_LEN); @@ -148,6 +158,17 @@ MacAddress::Set (uint8_t const ad[MacAddress::MAX_LEN], uint8_t len) m_len = len; } +// Static methods +void MacAddress::AdvanceAddress() + { + // Advance to next address, little end first + for(size_t i = 0; i < MAX_LEN; ++i) + { + if (++g_nextAddress[i] != 0) break; + } + } + +// Non-member operators bool operator == (MacAddress const&a, MacAddress const&b) { return a.IsEqual (b); diff --git a/src/node/mac-address.h b/src/node/mac-address.h index 75a80b700..76c5a6ae0 100644 --- a/src/node/mac-address.h +++ b/src/node/mac-address.h @@ -46,6 +46,13 @@ public: * This MacAddress has length of zero, and is internally all zeros */ MacAddress (void); + /** + * \brief Construct a MacAddress using the next available + * address. + * \see MacAddres::Next + * \param len length, in bytes, of the desired address + */ + MacAddress(uint8_t len); /** * \brief Construct a MacAddress from a byte-array * @@ -97,6 +104,14 @@ public: */ void Set (uint8_t const ad[MAX_LEN], uint8_t len); + // Static methods/members + /** + * + * Advance the global to the next available mac address. + */ + static void AdvanceAddress(); + static uint8_t g_nextAddress[MAX_LEN]; + private: uint8_t m_address[MAX_LEN]; uint8_t m_len; diff --git a/src/node/wscript b/src/node/wscript index c608945c7..18419e1df 100644 --- a/src/node/wscript +++ b/src/node/wscript @@ -1,9 +1,5 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -def configure(conf): - conf.env.append_value('NS3_MODULES', 'ns3-node') - - def build(bld): node = bld.create_obj('cpp', 'shlib') node.name = 'ns3-node' diff --git a/src/simulator/event-id.cc b/src/simulator/event-id.cc index 7357070b0..356be7f60 100644 --- a/src/simulator/event-id.cc +++ b/src/simulator/event-id.cc @@ -45,12 +45,12 @@ EventId::Cancel (void) } } bool -EventId::IsExpired (void) +EventId::IsExpired (void) const { return Simulator::IsExpired (*this); } bool -EventId::IsRunning (void) +EventId::IsRunning (void) const { return !IsExpired (); } diff --git a/src/simulator/event-id.h b/src/simulator/event-id.h index a7514289d..499065373 100644 --- a/src/simulator/event-id.h +++ b/src/simulator/event-id.h @@ -44,8 +44,8 @@ public: * method. * \returns true if the event has expired, false otherwise. */ - bool IsExpired (void); - bool IsRunning (void); + bool IsExpired (void) const; + bool IsRunning (void) const; public: /* The following methods are semi-private * they are supposed to be invoked only by diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index 226f7357a..9e21fa2ba 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -266,7 +266,7 @@ SimulatorPrivate::Cancel (EventId &id) } bool -SimulatorPrivate::IsExpired (EventId ev) +SimulatorPrivate::IsExpired (const EventId ev) { if (ev.GetEventImpl () == 0 || ev.GetTs () < m_currentTs || diff --git a/src/simulator/simulator.h b/src/simulator/simulator.h index 02cf6741c..f307be980 100644 --- a/src/simulator/simulator.h +++ b/src/simulator/simulator.h @@ -173,6 +173,10 @@ public: */ template static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1), OBJ obj, T1 a1); + template + static EventId Schedule (Time const &time, void (T::*mem_ptr) (const T1&), OBJ obj, T1 a1); // GFR + template + static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1&), OBJ obj, T1 a1); // GFR /** * @param time the relative expiration time of the event. * @param mem_ptr member method pointer to invoke @@ -234,6 +238,10 @@ public: */ template static EventId Schedule (Time const &time, void (*f) (T1), T1 a1); + template + static EventId Schedule (Time const &time, void (*f) (const T1&), T1 a1); // GFR + template + static EventId Schedule (Time const &time, void (*f) (T1&), T1 a1); // GFR /** * @param time the relative expiration time of the event. * @param f the function to invoke @@ -521,7 +529,7 @@ public: * @param id the event to test for expiration * @returns true if the event has expired, false otherwise. */ - static bool IsExpired (EventId id); + static bool IsExpired (const EventId id); /** * Return the "current simulation time". */ @@ -533,6 +541,10 @@ private: static EventImpl *MakeEvent (void (T::*mem_ptr) (void), OBJ obj); template static EventImpl *MakeEvent (void (T::*mem_ptr) (T1), OBJ obj, T1 a1); + template + static EventImpl *MakeEvent (void (T::*mem_ptr) (const T1&), OBJ obj, T1 a1); // GFR + template + static EventImpl *MakeEvent (void (T::*mem_ptr) (T1&), OBJ obj, T1 a1); // GFR template static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2); template @@ -642,6 +654,56 @@ EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1), OBJ obj, T1 a1) return ev; } +template +EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (const T1&), OBJ obj, T1 a1) +{ + // one argument version, with const reference + class EventMemberImpl1 : public EventImpl { + public: + typedef void (T::*F)(const T1&); + EventMemberImpl1 (OBJ obj, F function, T1 a1) + : m_obj (obj), + m_function (function), + m_a1 (a1) + {} + protected: + virtual ~EventMemberImpl1 () {} + private: + virtual void Notify (void) { + (EventMemberImplTraits::GetReference (m_obj).*m_function) (m_a1); + } + OBJ m_obj; + F m_function; + T1 m_a1; + } *ev = new EventMemberImpl1 (obj, mem_ptr, a1); + return ev; +} + +template +EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1&), OBJ obj, T1 a1) +{ + // one argument version with non-const reference + class EventMemberImpl1 : public EventImpl { + public: + typedef void (T::*F)(T1&); + EventMemberImpl1 (OBJ obj, F function, T1 a1) + : m_obj (obj), + m_function (function), + m_a1 (a1) + {} + protected: + virtual ~EventMemberImpl1 () {} + private: + virtual void Notify (void) { + (EventMemberImplTraits::GetReference (m_obj).*m_function) (m_a1); + } + OBJ m_obj; + F m_function; + T1 m_a1; + } *ev = new EventMemberImpl1 (obj, mem_ptr, a1); + return ev; +} + template EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2) { @@ -920,6 +982,18 @@ EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1), OBJ obj, return Schedule (time, MakeEvent (mem_ptr, obj, a1)); } +template +EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (const T1&), OBJ obj, T1 a1) +{ + return Schedule (time, MakeEvent (mem_ptr, obj, a1)); +} + +template +EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1&), OBJ obj, T1 a1) +{ + return Schedule (time, MakeEvent (mem_ptr, obj, a1)); +} + template EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2) { diff --git a/src/simulator/wscript b/src/simulator/wscript index fec0412c0..a940cd25a 100644 --- a/src/simulator/wscript +++ b/src/simulator/wscript @@ -15,8 +15,6 @@ def set_options(opt): def configure(conf): - conf.env.append_value('NS3_MODULES', 'ns3-simulator') - if Params.g_options.high_precision_as_double: conf.add_define('USE_HIGH_PRECISION_DOUBLE', 1) conf.env['USE_HIGH_PRECISION_DOUBLE'] = 1 diff --git a/src/wscript b/src/wscript index 2e2349f10..bc0fb4ff8 100644 --- a/src/wscript +++ b/src/wscript @@ -29,9 +29,11 @@ def configure(conf): blddir = os.path.abspath(os.path.join(conf.m_blddir, conf.env.variant())) for module in all_modules: - conf.sub_config(module) conf.env.append_value('NS3_MODULE_PATH', os.path.join(blddir, 'src', module)) + ## Used to link the 'run-tests' program with all of ns-3 code + conf.env['NS3_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules] + def build(bld): Object.register('ns3header', Ns3Header) diff --git a/wscript b/wscript index b5be10dda..bfa1d96de 100644 --- a/wscript +++ b/wscript @@ -8,6 +8,7 @@ import Params import Object import pproc as subprocess import optparse +import os.path Params.g_autoconfig = 1 @@ -20,8 +21,8 @@ srcdir = '.' blddir = 'build' def dist_hook(srcdir, blddir): - shutil.rmtree("doc/html") - shutil.rmtree("doc/latex") + shutil.rmtree("doc/html", True) + shutil.rmtree("doc/latex", True) def set_options(opt): @@ -105,13 +106,23 @@ def configure(conf): variant_env.append_value('CXXDEFINES', 'RUN_SELF_TESTS') - if os.path.basename(conf.env['CXX']).startswith("g++"): + if (os.path.basename(conf.env['CXX']).startswith("g++") + and 'CXXFLAGS' not in os.environ): variant_env.append_value('CXXFLAGS', ['-Wall', '-Werror']) if 'debug' in Params.g_options.debug_level.lower(): variant_env.append_value('CXXDEFINES', 'NS3_DEBUG_ENABLE') variant_env.append_value('CXXDEFINES', 'NS3_ASSERT_ENABLE') + ## In optimized builds we still want debugging symbols, e.g. for + ## profiling, and at least partially usable stack traces. + if ('optimized' in Params.g_options.debug_level.lower() + and 'CXXFLAGS' not in os.environ): + for flag in variant_env['CXXFLAGS_DEBUG']: + ## this probably doesn't work for MSVC + if flag.startswith('-g'): + variant_env.append_value('CXXFLAGS', flag) + if sys.platform == 'win32': if os.path.basename(conf.env['CXX']).startswith("g++"): variant_env.append_value("LINKFLAGS", "-Wl,--enable-runtime-pseudo-reloc") @@ -124,10 +135,7 @@ def build(bld): variant_env = bld.env_of_name(variant_name) bld.m_allenvs['default'] = variant_env # switch to the active variant - if Params.g_options.run: - run_program(Params.g_options.run) - return - elif Params.g_options.shell: + if Params.g_options.shell: run_shell() return @@ -154,11 +162,26 @@ def shutdown(): if Params.g_options.doxygen: doxygen() -def _find_program(program_name): + if Params.g_options.run: + run_program(Params.g_options.run) + +def _find_program(program_name, env): + launch_dir = os.path.abspath(Params.g_cwd_launch) + found_programs = [] for obj in Object.g_allobjs: + if obj.m_type != 'program' or not obj.target: + continue + + ## filter out programs not in the subtree starting at the launch dir + if not (obj.path.abspath().startswith(launch_dir) + or obj.path.abspath(env).startswith(launch_dir)): + continue + + found_programs.append(obj.target) if obj.target == program_name: return obj - raise ValueError("progam '%s' not found" % (program_name,)) + raise ValueError("program '%s' not found; available programs are: %r" + % (program_name, found_programs)) def _run_argv(argv): env = Params.g_build.env_of_name('default') @@ -198,9 +221,9 @@ def run_program(program_string): program_name = argv[0] try: - program_obj = _find_program(program_name) - except ValueError: - Params.fatal("progam '%s' not found" % (program_name,)) + program_obj = _find_program(program_name, env) + except ValueError, ex: + Params.fatal(str(ex)) try: program_node, = program_obj.m_linktask.m_outputs @@ -208,7 +231,13 @@ def run_program(program_string): Params.fatal("%s does not appear to be a program" % (program_name,)) execvec = [program_node.abspath(env)] + argv[1:] - return _run_argv(execvec) + + former_cwd = os.getcwd() + os.chdir(Params.g_cwd_launch) + try: + return _run_argv(execvec) + finally: + os.chdir(former_cwd) def run_shell():