Testing
authorEmmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
Mon, 16 Jul 2007 18:42:40 -0500
changeset 939 9c8c1a11b77f
parent 938 0ad45bb86c11 (current diff)
parent 928 218063b19458 (diff)
child 940 24813ddb6d15
Testing
--- a/doc/build-waf.txt	Tue Jul 03 22:28:45 2007 -0500
+++ b/doc/build-waf.txt	Mon Jul 16 18:42:40 2007 -0500
@@ -12,39 +12,55 @@
 === 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 in your path, see the section 
+"Note for developers" below ]
 
-[ Note: if ./waf does not exist, see the section "Note for developers" below ]
+To see valid configure options, type waf --help.  The most important
+option is -d <debug level>.  Valid debug levels (which are listed in
+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.
 
-To see valid configure options, type ./waf --help.  The most important
-option is -d <debug level>.  Valid debug levels (which are listed in
-./waf --help) are: ultradebug, debug, release, and optimized.
+[ 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/<debuglevel>/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 @@
 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 ~).
-
--- a/src/applications/wscript	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/applications/wscript	Mon Jul 16 18:42:40 2007 -0500
@@ -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'
--- a/src/common/wscript	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/common/wscript	Mon Jul 16 18:42:40 2007 -0500
@@ -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'
--- a/src/core/test.h	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/core/test.h	Mon Jul 16 18:42:40 2007 -0500
@@ -130,8 +130,8 @@
     if (!(assertion))                                   \
       {                                                 \
         Failure () << __FILE__ << ":" <<__LINE__        \
-                   << ": assertion `" << (assertion)    \
-                   << "'failed." << std::endl;          \
+                   << ": assertion `" << #assertion     \
+                   << "' failed." << std::endl;         \
         result = false;                                 \
       }
 
--- a/src/core/wscript	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/core/wscript	Mon Jul 16 18:42:40 2007 -0500
@@ -3,8 +3,6 @@
 
 
 def configure(conf):
-    conf.env.append_value('NS3_MODULES', 'ns3-core')
-
     e = conf.create_header_configurator()
     e.mandatory = False
     e.name = 'stdlib.h'
--- a/src/devices/p2p/p2p-channel.cc	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/devices/p2p/p2p-channel.cc	Mon Jul 16 18:42:40 2007 -0500
@@ -76,8 +76,7 @@
   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 @@
     }
 }
 
-bool
-PointToPointChannel::TransmitStart(Packet& p, Ptr<PointToPointNetDevice> src)
+bool PointToPointChannel::TransmitStart(Packet& p,
+                                        Ptr<PointToPointNetDevice> src,
+                                        const Time& txTime)
 {
   NS_DEBUG ("PointToPointChannel::TransmitStart (" << &p << ", " << src << 
             ")");
@@ -104,65 +104,15 @@
 
   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<PointToPointNetDevice> 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<PointToPointNetDevice> 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 @@
   return m_link[i].m_src;
 }
 
-  DataRate
+const DataRate&
 PointToPointChannel::GetDataRate (void)
 {
   return m_bps;
 }
 
-  Time
+const Time&
 PointToPointChannel::GetDelay (void)
 {
   return m_delay;
--- a/src/devices/p2p/p2p-channel.h	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/devices/p2p/p2p-channel.h	Mon Jul 16 18:42:40 2007 -0500
@@ -51,11 +51,7 @@
  */
 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 @@
   /**
    * \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 @@
    * \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 @@
    * \param device pointer to the netdevice to attach to the channel
    */
   void Attach (Ptr<PointToPointNetDevice> device);
-  bool TransmitStart (Packet& p, Ptr<PointToPointNetDevice> src);
-  bool TransmitEnd (Packet &p, Ptr<PointToPointNetDevice> src);
-  void PropagationCompleteEvent(Packet p, Ptr<PointToPointNetDevice> src);
+  bool TransmitStart (Packet& p, Ptr<PointToPointNetDevice> src,
+                      const Time& txTime);
+  // Below two not needed
+  //bool TransmitEnd (Packet &p, Ptr<PointToPointNetDevice> src);
+  //void PropagationCompleteEvent(Packet p, Ptr<PointToPointNetDevice> src);
 
 
   virtual uint32_t GetNDevices (void) const;
   virtual Ptr<NetDevice> 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
--- a/src/devices/p2p/p2p-net-device.cc	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/devices/p2p/p2p-net-device.cc	Mon Jul 16 18:42:40 2007 -0500
@@ -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 <mathieu.lacage@sophia.inria.fr>
+ * Author:  Craig Dowell <craigdo@ee.washington.edu>
+ * Revised: George Riley <riley@ece.gatech.edu>
  */
 
 #include <iostream>
@@ -32,11 +33,17 @@
 
 namespace ns3 {
 
-PointToPointNetDevice::PointToPointNetDevice (Ptr<Node> node) 
+DataRateDefaultValue PointToPointNetDevice::g_defaultRate(
+           "PointToPointLinkDataRate", 
+           "The default data rate for point to point links",
+           DataRate ("10Mb/s"));
+
+  PointToPointNetDevice::PointToPointNetDevice (Ptr<Node> 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 @@
 // 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 @@
     
 }
 
+  // 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 @@
 //
 // 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.  
-//
-// 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.
+// link, this means that we're simulating something like a UART.
 //
-// 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 @@
 //
 // 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;
+  m_txMachineState = READY;
   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);
+  if (!m_queue->Dequeue(p)) return; // Nothing to do at this point
+  TransmitStart(p);
 }
 
-  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);
-    }
-}
-
-TraceResolver *
-PointToPointNetDevice::DoCreateTraceResolver (TraceContext const &context)
+TraceResolver* PointToPointNetDevice::DoCreateTraceResolver (
+                                      TraceContext const &context)
 {
   CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
   resolver->Add ("queue", 
@@ -292,8 +218,7 @@
   return resolver;
 }
 
-bool
-PointToPointNetDevice::Attach (Ptr<PointToPointChannel> ch)
+bool PointToPointNetDevice::Attach (Ptr<PointToPointChannel> ch)
 {
   NS_DEBUG ("PointToPointNetDevice::Attach (" << &ch << ")");
 
@@ -301,7 +226,9 @@
 
   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 @@
   return true;
 }
 
-void
-PointToPointNetDevice::AddQueue (Ptr<Queue> q)
+void PointToPointNetDevice::AddQueue (Ptr<Queue> 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<Queue>
-PointToPointNetDevice::GetQueue(void) const 
+Ptr<Queue> PointToPointNetDevice::GetQueue(void) const 
 { 
     return m_queue;
 }
 
-Ptr<Channel>
-PointToPointNetDevice::DoGetChannel(void) const 
+Ptr<Channel> PointToPointNetDevice::DoGetChannel(void) const 
 { 
     return m_channel;
 }
 
-bool 
-PointToPointNetDevice::DoNeedsArp (void) const
+bool PointToPointNetDevice::DoNeedsArp (void) const
 {
   return false;
 }
--- a/src/devices/p2p/p2p-net-device.h	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/devices/p2p/p2p-net-device.h	Mon Jul 16 18:42:40 2007 -0500
@@ -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 @@
    * @see PointToPointTopology::AddPointToPointLink ()
    * @param node the Node to which this device is connected.
    */
-  PointToPointNetDevice (Ptr<Node> node);
+  PointToPointNetDevice (Ptr<Node> node,
+                         const DataRate& = g_defaultRate.GetValue());
   /**
    * Copy Construct a PointToPointNetDevice
    *
@@ -105,7 +107,7 @@
    *
    * @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 @@
    * @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 @@
    * @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 @@
    * @returns a pointer to the channel
    */
   virtual Ptr<Channel> 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 @@
   /**
    * 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 @@
   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 @@
    * @see class TraceResolver
    */
   CallbackTraceSource<Packet &> m_rxTrace;
+  /** 
+   * Default data rate.  Used for all newly created p2p net devices
+   */
+   static DataRateDefaultValue g_defaultRate;
+
 };
 
 }; // namespace ns3
--- a/src/devices/p2p/wscript	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/devices/p2p/wscript	Mon Jul 16 18:42:40 2007 -0500
@@ -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'
--- a/src/internet-node/wscript	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/internet-node/wscript	Mon Jul 16 18:42:40 2007 -0500
@@ -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'
--- a/src/node/mac-address.cc	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/node/mac-address.cc	Mon Jul 16 18:42:40 2007 -0500
@@ -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(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 @@
         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);
--- a/src/node/mac-address.h	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/node/mac-address.h	Mon Jul 16 18:42:40 2007 -0500
@@ -47,6 +47,13 @@
    */
   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
    *
    * low byte should be first.
@@ -97,6 +104,14 @@
    */
   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;
--- a/src/node/wscript	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/node/wscript	Mon Jul 16 18:42:40 2007 -0500
@@ -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'
--- a/src/simulator/event-id.cc	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/simulator/event-id.cc	Mon Jul 16 18:42:40 2007 -0500
@@ -45,12 +45,12 @@
     }
 }
 bool 
-EventId::IsExpired (void)
+EventId::IsExpired (void) const
 {
   return Simulator::IsExpired (*this);
 }
 bool 
-EventId::IsRunning (void)
+EventId::IsRunning (void) const
 {
   return !IsExpired ();
 }
--- a/src/simulator/event-id.h	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/simulator/event-id.h	Mon Jul 16 18:42:40 2007 -0500
@@ -44,8 +44,8 @@
    * 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
--- a/src/simulator/simulator.cc	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/simulator/simulator.cc	Mon Jul 16 18:42:40 2007 -0500
@@ -266,7 +266,7 @@
 }
 
 bool
-SimulatorPrivate::IsExpired (EventId ev)
+SimulatorPrivate::IsExpired (const EventId ev)
 {
   if (ev.GetEventImpl () == 0 ||
       ev.GetTs () < m_currentTs ||
--- a/src/simulator/simulator.h	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/simulator/simulator.h	Mon Jul 16 18:42:40 2007 -0500
@@ -173,6 +173,10 @@
    */
   template <typename T, typename OBJ, typename T1>
   static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1), OBJ obj, T1 a1);
+  template <typename T, typename OBJ, typename T1>
+  static EventId Schedule (Time const &time, void (T::*mem_ptr) (const T1&), OBJ obj, T1 a1); // GFR
+  template <typename T, typename OBJ, typename T1>
+  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 @@
    */
   template <typename T1>
   static EventId Schedule (Time const &time, void (*f) (T1), T1 a1);
+  template <typename T1>
+  static EventId Schedule (Time const &time, void (*f) (const T1&), T1 a1); // GFR
+  template <typename T1>
+  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 @@
    * @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 @@
   static EventImpl *MakeEvent (void (T::*mem_ptr) (void), OBJ obj);
   template <typename T, typename OBJ, typename T1>
   static EventImpl *MakeEvent (void (T::*mem_ptr) (T1), OBJ obj, T1 a1);
+  template <typename T, typename OBJ, typename T1>
+  static EventImpl *MakeEvent (void (T::*mem_ptr) (const T1&), OBJ obj, T1 a1); // GFR
+  template <typename T, typename OBJ, typename T1>
+  static EventImpl *MakeEvent (void (T::*mem_ptr) (T1&), OBJ obj, T1 a1); // GFR
   template <typename T, typename OBJ, typename T1, typename T2>
   static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2);
   template <typename T, typename OBJ, typename T1, typename T2, typename T3>
@@ -642,6 +654,56 @@
   return ev;
 }
 
+template <typename T, typename OBJ, typename T1>
+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<OBJ>::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 <typename T, typename OBJ, typename T1>
+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<OBJ>::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 <typename T, typename OBJ, typename T1, typename T2>
 EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2) 
 {
@@ -920,6 +982,18 @@
   return Schedule (time, MakeEvent (mem_ptr, obj, a1));
 }
 
+template <typename T, typename OBJ, typename T1>
+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 <typename T, typename OBJ, typename T1>
+EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1&), OBJ obj, T1 a1) 
+{
+  return Schedule (time, MakeEvent (mem_ptr, obj, a1));
+}
+
 template <typename T, typename OBJ, typename T1, typename T2>
 EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2) 
 {
--- a/src/simulator/wscript	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/simulator/wscript	Mon Jul 16 18:42:40 2007 -0500
@@ -15,8 +15,6 @@
 
 
 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
--- a/src/wscript	Tue Jul 03 22:28:45 2007 -0500
+++ b/src/wscript	Mon Jul 16 18:42:40 2007 -0500
@@ -29,9 +29,11 @@
 
     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)
--- a/wscript	Tue Jul 03 22:28:45 2007 -0500
+++ b/wscript	Mon Jul 16 18:42:40 2007 -0500
@@ -8,6 +8,7 @@
 import Object
 import pproc as subprocess
 import optparse
+import os.path
 
 Params.g_autoconfig = 1
 
@@ -20,8 +21,8 @@
 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 @@
 
     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 @@
     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 @@
     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 @@
     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 @@
         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():