fill out tutorial tracing section with semi-real plot
authorCraig Dowell <craigdo@ee.washington.edu>
Mon, 19 Oct 2009 16:44:41 -0700
changeset 5432 2cb21147d154
parent 5431 01a657b8d1ef
child 5433 be5517a35ea0
fill out tutorial tracing section with semi-real plot
doc/tutorial/figures/cwnd.png
doc/tutorial/tracing.texi
examples/tutorial/fifth.cc
examples/tutorial/wscript
Binary file doc/tutorial/figures/cwnd.png has changed
--- a/doc/tutorial/tracing.texi	Sun Oct 18 22:11:29 2009 -0700
+++ b/doc/tutorial/tracing.texi	Mon Oct 19 16:44:41 2009 -0700
@@ -1,4 +1,3 @@
-
 @c ============================================================================
 @c Begin document body here
 @c ============================================================================
@@ -17,6 +16,7 @@
 
 @menu
 * Background::
+* Overview::
 @end menu
 
 @c ============================================================================
@@ -1096,10 +1096,807 @@
 of the most frequently used constructs in the low-level parts of @code{ns-3}.
 It is, in my opinion, a quite elegant thing.
 
+@subsection What About TracedValue?
 
+Earlier in this section, we presented a simple piece of code that used a
+@code{TracedValue<int32_t>} to demonstrate the basics of the tracing code.
+We just glossed over the way to find the return type and formal arguments
+for the @code{TracedValue}.  Rather than go through the whole exercise, we
+will just point you at the correct file, @code{src/core/traced-value.h} and
+to the important piece of code:
 
+@verbatim
+  template <typename T>
+  class TracedValue
+  {
+  public:
+    ...
+    void Set (const T &v) {
+      if (m_v != v)
+        {
+  	m_cb (m_v, v);
+  	m_v = v;
+        }
+    }
+    ...
+  private:
+    T m_v;
+    TracedCallback<T,T> m_cb;
+  };
+@end verbatim
+
+Here you see that the @code{TracedValue} is templated, of course.  In the simple
+example case at the start of the section, the typename is int32_t.  This means 
+that the member variable being traced (@code>m_v} in the private section of the 
+class) will be an @code{int32_t m_v}.  The @code{Set} method will take a 
+@code{const uint32_t &v} as a parameter.  You should now be able to understand 
+that the @code{Set} code will fire the @code{m_cb} callback with two parameters:
+the first being the current value of the @code{TracedValue}; and the second 
+being the new value being set.
+
+The callback, @code{m_cb} is declared as a @code{TracedCallback<T, T>} which
+will correspond to a @code{TracedCallback<int32_t, int32_t>} when the class is 
+instantiated.
+
+Recall that the callback target of a TracedCallback always returns @code{void}.  
+Further recall that there is a one-to-one correspondence between the template 
+parameter list in the declaration and the formal arguments of the callback 
+function.  Therefore the callback will need to have a function signature that 
+looks like:
+
+@verbatim
+  void
+  MyCallback (uint32_t oldValue, uint32_t newValue)
+  {
+    ...
+  }
+@end verbatim
+
+It probably won't surprise you that this is exactly what we provided in that 
+simple example we covered so long ago:
+
+@verbatim
+  void
+  IntTrace (int32_t oldValue, int32_t newValue)
+  {
+    std::cout << "Traced " << oldValue << " to " << newValue << std::endl;
+  }
+@end verbatim
+
+@c ============================================================================
+@c A Real Example
+@c ============================================================================
+@node A Real Example
+@section A Real Example
+
+Let's do an example taken from one of the best-known books on TCP around.  
+``TCP/IP Illustrated, Volume 1: The Protocols,'' by W. Richard Stevens is a 
+classic.  I just flipped the book open and ran across a nice plot of both the 
+congestion window and sequence numbers versus time on page 366.  Stevens calls 
+this, ``Figure 21.10. Value of cwnd and send sequence number while data is being 
+transmitted.''  Let's just recreate the cwnd part of that plot in @command{ns-3}
+using the tracing system and @code{gnuplot}.
+
+@subsection Are There Trace Sources Available?
+
+The first thing to think about is how we want to get the data out.  What is it
+that we need to trace?  The first thing to do is to consult ``The list of all
+trace sources'' to see what we have to work with.  Recall that this is found
+in the @command{ns-3} Doxygen in the ``Core'' Module section.  If you scroll
+through the list, you will eventually find:
+
+@verbatim
+  ns3::TcpSocketImpl
+  CongestionWindow: The TCP connection's congestion window
+@end verbatim
+
+It turns out that the @command{ns-3} TCP implementation lives (mostly) in the 
+file @code{src/internet-stack/tcp-socket-impl.cc}.  If you don't know this a 
+priori, you can use the recursive grep trick:
+
+@vervatim
+  find . -name '*.cc' | xargs grep -i tcp
+@end verbatim
+
+You will find page after page of instances of tcp pointing you to that file. 
+
+If you open @code{src/internet-stack/tcp-socket-impl.cc} in your favorite 
+editor, you will see right up at the top of the file, the following declarations:
+
+@verbatim
+  TypeId
+  TcpSocketImpl::GetTypeId ()
+  {
+    static TypeId tid = TypeId(``ns3::TcpSocketImpl'')
+      .SetParent<TcpSocket> ()
+      .AddTraceSource (``CongestionWindow'',
+                       ``The TCP connection's congestion window'',
+                       MakeTraceSourceAccessor (&TcpSocketImpl::m_cWnd))
+      ;
+    return tid;
+  }
+@end verbatim
+
+This should tell you to look for the declaration of @code{m_cWnd} in the header
+file @code{src/internet-stack/tcp-socket-impl.h}.  If you open this file in your
+favorite editor, you will find:
+
+@verbatim
+  TracedValue<uint32_t> m_cWnd; //Congestion window
+@end verbatim
+
+You should now understand this code completely.  If we have a pointer to the 
+@code{TcpSocketImpl}, we can @code{TraceConnect} to the ``CongestionWindow'' trace 
+source if we provide an appropriate callback target.  This is the same kind of
+trace source that we saw in the simple example at the start of this section,
+except that we are talking about @code{uint32_t} instead of @code{int32_t}.
+
+We now know that we need to provide a callback that returns void and takes 
+two @code{uint32_t} parameters, the first being the old value and the second 
+being the new value:
+
+@verbatim
+  void
+  CwndTrace (uint32_t oldValue, uint32_t newValue)
+  {
+    ...
+  }
+@end verbatim
+
+@subsection What Script to Use?
+
+It's always best to try and find working code laying around that you can 
+modify, rather than starting from scratch.  So the fist order of business now
+is to find some code that already hooks the ``CongestionWindow'' trace source
+and see if we can modify it.  As usual, grep is your friend:
+
+@verbatim
+  find . -name '*.cc' | xargs grep CongestionWindow
+@end verbatim
+
+This will point out a couple of promising candidates: 
+@code{examples/tcp/tcp-large-transfer.cc} and 
+@code{src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc}.
+
+We haven't visited any of the test code yet, so let's take a look there.  You
+will typically find that test code is fairly minimal, so this is probably a
+very good bet.  Open @code{src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc} in your
+favorite editor and search for ``CongestionWindow.''  You will find,
+
+@verbatim
+  ns3TcpSocket->TraceConnectWithoutContext (``CongestionWindow'', 
+    MakeCallback (&Ns3TcpCwndTestCase1::CwndChange, this));
+@end verbatim
+
+This should look very familiar to you.  We mentioned above that if we had a
+pointer to the @code{TcpSocketImpl}, we could @code{TraceConnect} to the 
+``CongestionWindow'' trace source.  That's exactly what we have here; so it
+turns out that this line of code does exactly what we want.  Let's go ahead
+and extract the code we need from this function 
+(@code{Ns3TcpCwndTestCase1::DoRun (void)}).  If you look at this function,
+you will find that it looks just like an @code{ns-3} script.  It turns out that
+is exactly what it is.  It is a script run by the test framework, so we can just
+pull it out and wrap it in @code{main} instead of in @code{DoRun}.  Rather than
+walk through this step, by step, we have provided the file that results from
+porting this test back to a native @code{ns-3} script.
+
+Rather than go through this extraction process, we'll just provide the results 
+in a file named @code{examples/tutorial/fifth.cc}.  
+
+@subsection A Common Problem and Solution
+
+The @code{fifth.cc} example demonstrates an extremely important rule that you 
+must understand before using any kind of @code{Attribute}:  you must ensure 
+that the target of a @code{Config} command exists before trying to use it.
+This is no different than saying an object must be instantiated before trying
+to call it,  Although this may seem obvious when stated this way, it does
+trip up many people trying to use the system for the first time.
+
+Let's return to basics for a moment.  There are three basic time periods that
+exist in any @command{ns-3} script.  The first time period is sometimes called 
+``Configuration Time'' or ``Setup Time,'' and is in force during the period 
+when the @code{main} function of your script is running, but before 
+@code{Simulator::Run} is called.  The second time period  is sometimes called
+``Simulation Time'' and is in force during the time period when 
+@code{Simulator::Run} is actively executing its events.  After it completes
+executing the simulation,  @code{Simulator::Run} will return control back to 
+the @code{main} function.  When this happens, the script enters what can be 
+called ``Teardown Time,'' which is when the structures and objects created 
+during setup and taken apart and released,
+
+Perhaps the most common mistake made in trying to use the tracing system is 
+assuming that entities constructed dynamically during simulation time are
+available during configuration time.  In particular, an @command{ns-3}
+@code{Socket} is a dynamic object often created by @code{Applications} to
+communicate between @code{Nodes}.  An @command{ns-3} @code{Application} 
+always has a ``Start Time'' and a ``Stop Time'' associated with it.  In the
+vast majority of cases, an @code{Application} will not attempt to create 
+a dynamic object until its @code{StartApplication} method is called.  This
+is to ensure that the simulation is completely configured before the app
+tries to do anything (what would happen if it tried to connect to a node
+that didn't exist yet during configuration time).  The answer to this 
+issue is to 1) create a simulator event that is run after the dynamic object
+is created and hook the trace when that event is executedl or 2) create the
+dynamic object at configuration time, hook it then, and give the object to
+the system to use during simulation time.  We took the second approach in
+the @code{fifth.cc} example.  This decision required us to create the 
+@code{SimpleSource} @code{Application}, the entire purpose of which is to 
+take a @code{Socket} as a parameter.  
+
+@subsection A fifth.cc Walkthrough
+
+Now, let's take a look at the example program we constructed by disecting
+the congestion window test.  Open @code{examples/tutorial/fifth.cc} in your
+favorite editor.  You should see some familiar looking code:
+
+@verbatim
+  /* -*- Mode:C++; c-file-style:''gnu''; indent-tabs-mode:nil; -*- */
+  /*
+   * 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, Include., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+   */
+  
+  #include ``ns3/core-module.h''
+  #include ``ns3/common-module.h''
+  #include ``ns3/simulator-module.h''
+  #include ``ns3/node-module.h''
+  #include ``ns3/helper-module.h''
+  
+  using namespace ns3;
+  
+  NS_LOG_COMPONENT_DEFINE (``FifthScriptExample'');
+@end verbatim
+
+This has all been covered, so we won't discuss it.  The next lines of source are
+the network illustration and a comment addressing the problem described above
+with @code{Socket}.
+
+@verbatim
+  // ===========================================================================
+  //
+  //         node 0                 node 1
+  //   +----------------+    +----------------+
+  //   |    ns-3 TCP    |    |    ns-3 TCP    |
+  //   +----------------+    +----------------+
+  //   |    10.1.1.1    |    |    10.1.1.2    |
+  //   +----------------+    +----------------+
+  //   | point-to-point |    | point-to-point |
+  //   +----------------+    +----------------+
+  //           |                     |
+  //           +---------------------+
+  //                5 Mbps, 2 ms
+  //
+  //
+  // We want to look at changes in the ns-3 TCP congestion window.  We need
+  // to crank up a flow and hook the CongestionWindow attribute on the socket
+  // of the sender.  Normally one would use an on-off application to generate a
+  // flow, but this has a couple of problems.  First, the socket of the on-off
+  // application is not created until Application Start time, so we wouldn't be
+  // able to hook the socket (now) at configuration time.  Second, even if we
+  // could arrange a call after start time, the socket is not public so we
+  // couldn't get at it.
+  //
+  // So, we can cook up a simple version of the on-off application that does what
+  // we want.  On the plus side we don't need all of the complexity of the on-off
+  // application.  On the minus side, we don't have a helper, so we have to get
+  // a little more involved in the details, but this is trivial.
+  //
+  // So first, we create a socket and do the trace connect on it; then we pass
+  // this socket into the constructor of our simple application which we then
+  // install in the source node.
+  // ===========================================================================
+  //
+@end verbatim
+
+This should also be self-explanatory.  
+
+The next part is the declaration of the @code{SimpleSource} @code{Application} that
+we put together to allow the @code{Socket} to be created at configuration time.
+
+@verbatim
+  class SimpleSource : public Application
+  {
+  public:
+  
+    SimpleSource ();
+    virtual ~SimpleSource();
+  
+    void Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, 
+      uint32_t nPackets, DataRate dataRate);
+  
+  private:
+    virtual void StartApplication (void);
+    virtual void StopApplication (void);
+  
+    void ScheduleTx (void);
+    void SendPacket (void);
+  
+    Ptr<Socket>     m_socket;
+    Address         m_peer;
+    uint32_t        m_packetSize;
+    uint32_t        m_nPackets;
+    DataRate        m_dataRate;
+    EventId         m_sendEvent;
+    bool            m_running;
+    uint32_t        m_packetsSent;
+  };
+@end verbatim
+
+You can see that this class inherits from the @command{ns-3} @code{Application}
+class.  Take a look at @code{src/node/application.h} if you are interested in 
+what is inherited.  This class is obligated to override the 
+@code{StartApplication} and @code{StopApplication} methods.  These methods are
+called when the corresponding @code{Start} and @code{Stop} methods are called
+during simulation time.  
+
+@subsubsection How Applications are Started and Stopped
+
+It is worthwhile to spend a bit of time explaining how events actually get 
+started in the system.  The most common way to start pumping events is to start
+an @code{Application}.  This is done as the result of the following (hopefully)
+familar lines of an @sommand{ns-3} script:
+
+@verbatim
+  ApplicationContainer apps = ...
+  apps.Start (Seconds (1.0));
+  apps.Stop (Seconds (10.0));
+@end verbatim
+
+The application container code (see @code{src/helper/application-container.h} if
+you are interested) loops through its contained applications and calls,
+
+@verbatim
+  app->Start (startTime);
+  app->Stop (stopTime);
+@end verbatim
+
+on each of them.  The @code{Start} method of an @code{Application} calls 
+@code{Application::ScheduleStart} (see @code{src/helper/application-container.cc})
+which, in turn, schedules an event to start the @code{Application}:
+
+@verbatim
+  Simulator::Schedule (startTime, &Application::StartApplication, this);
+@end verbatim
+
+Since @code{SimpleSource} inherits from @code{Application} and overrides 
+@code{StartApplication}, this bit of code causes the simulator to execute
+something that is effectively like,
+
+@verbatim
+  this->StartApplication (startTime);
+@end verbatim
+
+where the @code{this} pointer, if you have kept it all straight, is the pointer
+to the @code{Application} in the container.  It is then expected that another 
+event will be scheduled in the overridden @code{StartApplication} that will 
+begin doing some application-specific function, like sending packets.  
+
+@code{StopApplication} operates in a similar manner and tells the @code{Application}
+to stop generating events.
+
+@subsubsection The SimpleSource Application
+
+The @code{SimpleSource} @code{Application} needs a constructor and a destructor,
+of course:
+
+@verbatim
+  SimpleSource::SimpleSource ()
+    : m_socket (0),
+      m_peer (),
+      m_packetSize (0),
+      m_nPackets (0),
+      m_dataRate (0),
+      m_sendEvent (),
+      m_running (false),
+      m_packetsSent (0)
+  {
+  }
+  
+  SimpleSource::~SimpleSource()
+  {
+    m_socket = 0;
+  }
+@end verbatim
+
+The existence of the next bit of code is the whole reason why we wrote this
+@code{Application} in the first place.
+
+@verbatim
+void
+SimpleSource::Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, 
+                     uint32_t nPackets, DataRate dataRate)
+{
+  m_socket = socket;
+  m_peer = address;
+  m_packetSize = packetSize;
+  m_nPackets = nPackets;
+  m_dataRate = dataRate;
+}
+@end verbatim
+
+This code should be pretty self-explanatory.  We are just initializing member
+variables.  The important one from the perspective of tracing is the 
+@code{Ptr<Socket> socket} which we needed to provide to the application 
+during configuration time.  Recall that we are going to create the @code{Socket}
+as a @code{TcpSocket} (which is implemented by @code{TcpSocketImpl}) and hook 
+its ``CongestionWindow'' trace source before passing it to the @code{Setup}
+method.
+
+@verbatim
+  void
+  SimpleSource::StartApplication (void)
+  {
+    m_running = true;
+    m_packetsSent = 0;
+    m_socket->Bind ();
+    m_socket->Connect (m_peer);
+    SendPacket ();
+  }
+@end verbatim
+
+The above code is the overridden implementation @code{Application::StartApplication}
+that will be automatically called by the simulator to start our @code{Application}
+running.  You can see that it does a @code{Socket} @code{Bind} operation.  If
+you are familiar with Berkeley Sockets this shouldn't be a surprise.  It performs
+the required work on the local side of the connection just as you might expect.
+The following @code{Connect} will do what is required to establish a connection 
+with the TCP at @code{Address} m_peer.  The @code{Application} then starts creating
+simulation events by calling @code{SendPacket}.
+
+The next bit of code explains to the @code{Application} how to stop creating 
+simulation events.
+
+@verbatim
+  void
+  SimpleSource::StopApplication (void)
+  {
+    m_running = false;
+  
+    if (m_sendEvent.IsRunning ())
+      {
+        Simulator::Cancel (m_sendEvent);
+      }
+  
+    if (m_socket)
+      {
+        m_socket->Close ();
+      }
+  }
+@end verbatim
+
+Every time a simulation event is scheduled, an @code{Event} is created.  If the 
+@code{Event} is pending execution or executing, its method @code{IsRunning} will
+return @code{true}.  In this code, if @code{IsRunning()} returns true, we 
+@code{Cancel} the event which removes it from the simulator event queue.  By 
+doing this, we break the chain of events that the @code{Application} is using to
+keep sending its @code{Packets} and the event goes quiet.  After we quiet the
+@code{Application} we @code{Close} the socket which tears down the TCP connection.
+
+The socket is actually deleted in the destructor when the @code{m_socket = 0} is
+executed.  This removes the last reference to the underlying Ptr<Socket> which 
+causes the destructor of that Object to be called.
+
+Recall that @code{StartApplication} called @code{SendPacket} to start the 
+chain of events that describes the @code{Application} behavior.
+
+@verbatim
+  void
+  SimpleSource::SendPacket (void)
+  {
+    Ptr<Packet> packet = Create<Packet> (m_packetSize);
+    m_socket->Send (packet);
+  
+    if (++m_packetsSent < m_nPackets)
+      {
+        ScheduleTx ();
+      }
+  }
+@end verbatim
+
+Here, you see that @code{SendPacket} does just that.  It creates a @code{Packet}
+and then does a @code{Send} which, if you know Berkeley Sockets, is probably 
+just what you expected to see.
+
+It is the responsibility of the @code{Application} to keep scheduling the 
+chain of events, so the next lines call @code{ScheduleTx} to schedule another
+transmit event (a @code{SendPacket}) until the @code{Application} decides it
+has sent enough.
+
+@verbatim
+  void
+  SimpleSource::ScheduleTx (void)
+  {
+    if (m_running)
+      {
+        Time tNext (Seconds (m_packetSize * 8 / static_cast<double> (m_dataRate.GetBitRate ())));
+        m_sendEvent = Simulator::Schedule (tNext, &SimpleSource::SendPacket, this);
+      }
+  }
+@end verbatim
+
+Here, you see that @code{ScheduleTx} does exactly that.  If the @code{Applciation}
+is running (if @code{StopApplication}) has not been called) it will schedule a 
+new event, which calls @code{SendPacket} again.  The alert reader will spot
+something that also trips up new users.  The data rate of an @code{Application} is
+just that.  It has nothing to do with the data rate of an underlying @code{Channel}.
+This is the rate at which the @code{Application} produces bits.  It does not take
+into account any overhead for the various protocols or channels that it uses to 
+transport the data.  If you set the data rate of an @code{Application} to the same
+data rate as your underlying @code{Channel} you will eventually get a buffer overflow.
+
+@subsubsection The Trace Sinks
+
+The whole point of this exercise is to get trace callbacks.  The next piece of
+code implements that callback:
+
+@verbatim
+  static void
+  CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
+  {
+    NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << ``\t'' << newCwnd);
+  }
+@end verbatim
+
+This should be very familiar to you now, so we won't dwell on the details.  This
+function just logs the current simulation time and the new value of the 
+congestion window every time it is changed.  You can probably imagine that you
+could load the resulting output into a graphics program (gnuplot or Excel) and
+immediately see a nice graph of the congestion window behavior over time.
+
+We added a new trace sink to show where are dropped.  We are going to add an
+error model to this code also, so we wanted to demonstrate this working.
+
+@verbatim
+  static void
+  RxDrop (Ptr<const Packet> p)
+  {
+    NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ());
+  }
+@end verbatim
+
+This trace sink will be connected to the ``PhyRxDrop'' trace source of the 
+point-to-point NetDevice.  If you take a small detour there you will see
+(in @code{src/devices/point-to-point/point-to-point-net-device.cc}) that
+this trace source refers to @code{PointToPointNetDevice::m_phyRxDropTrace}.
+If you then look in @code{src/devices/point-to-point/point-to-point-net-device.h}
+for this member variable, you will find that it is declared as a
+@code{TracedCallback<Ptr<const Packet> >}.  This should tell you that the
+callback target should be a function that returns void and takes a single
+parameter which is a @code{Ptr<const Packet>} -- just what we have above.
+
+@subsubsection The Main Program
+
+The following code should be very familiar to you by now:
+
+@end verbatim
+  int
+  main (int argc, char *argv[])
+  {
+    NodeContainer nodes;
+    nodes.Create (2);
+  
+    PointToPointHelper pointToPoint;
+    pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
+    pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
+  
+    NetDeviceContainer devices;
+    devices = pointToPoint.Install (nodes);
+@end verbatim
+
+This creates two nodes with a point-to-point channel between them, just as
+shown in the illustration at the start of the file.
+
+The next few lines of code show somthing new.  If we trace a connection that
+behaves perfectly, we will end up with a monotonically increasing congestion
+window.  To see any interesting behavior, we really want to introduce link 
+errors which will drop packets, cause duplicate ACKs and trigger the more
+interesting behaviors of the congestion window.
+
+@command{ns-3} provides @code{ErrorModel} objects which can be attached to
+@code{Channels}.  We are using the @code{RateErrorModel} which allows us
+to introduce errors into a @code{Channel} at a given @emph{rate}. 
+
+@verbatim
+  Ptr<RateErrorModel> em = CreateObjectWithAttributes<RateErrorModel> (
+    "RanVar", RandomVariableValue (UniformVariable (0., 1.)),
+    "ErrorRate", DoubleValue (0.01));
+  devices.Get (0)->SetAttribute ("ReceiveErrorModel", PointerValue (em));
+@end verbatim
+
+The above code instantiates a @code{RateErrorModel} Object.  Rather than 
+using the two-step process of instantiating it and then setting Attributes,
+we use the convenience function @code{CreateObjectWithAttributes} which
+allows us to do both at the same time.  We set the ``RanVar'' 
+@code{Attribute} to a random variable that generates a uniform distribution
+from 0 to 1.  We also set the ``ErrorRate'' @code{Attribute} to the rate 0.01.
+We then set the resulting instantiated @code{RateErrorModel} as the error
+model used by the point-to-point @code{NetDevice}.  This will result in
+about one of every one hundred packets being dropped by the net device
+and give us those retransmissions we want to make our plot a little more
+interesting.
+
+@verbatim
+  InternetStackHelper stack;
+  stack.Install (nodes);
+
+  Ipv4AddressHelper address;
+  address.SetBase (``10.1.1.0'', ``255.255.255.252'');
+  Ipv4InterfaceContainer interfaces = address.Assign (devices);
+@end verbatim
+
+The above code should be familiar.  It installs internet stacks on our two
+nodes and creates interfaces and assigns IP addresses for the point-to-point
+devices.
+
+Since we are using TCP, we need something on the destination node to receive
+TCP connections and data.  The @code{PacketSink} @code{Application} is commonly
+used in @command{ns-3} for that purpose.
+
+@verbatim
+  uint16_t sinkPort = 8080;
+  Address sinkAddress (InetSocketAddress(interfaces.GetAddress (1), sinkPort));
+  PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", 
+    InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
+  ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (1));
+  sinkApps.Start (Seconds (0.));
+  sinkApps.Stop (Seconds (20.));
+@end verbatim
+
+This should all be familiar, with the exception of,
+
+@verbatim
+  PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", 
+    InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
+@end verbatim
+
+This code instantiates a @code{PacketSinkHelper} and tells it to create sockets
+using the class @code{ns3::TcpSocketFactory}.  This class implements a design 
+pattern called ``object factory'' which is a commonly used mechanism for 
+specifying a class used to create objects in an abstract way.  Here, instead of 
+having to create the objects themselves, you provide the @code{ PacketSinkHelper}
+a string that specifies a @code{TypeId} string used to create an object which 
+can then be used, in turn, to create instances of the Objects created by the 
+factory.
+
+The remaining parameter tells the @code{Application} which address and port it
+should @cod{Bind} to.
+
+The next two lines of code will create the socket and connect the trace source.
+
+@verbatim
+  Ptr<Socket> ns3TcpSocket = Socket::CreateSocket (nodes.Get (0), 
+    TcpSocketFactory::GetTypeId ());
+  ns3TcpSocket->TraceConnectWithoutContext (``CongestionWindow'', 
+    MakeCallback (&CwndChange));
+@end verbatim
+
+The first statement calls the static member function @code{Socket::CreateSocket)
+and provides a @code{Node} and an explicit @code{TypeId} for the object factory
+used to create the socket.  This is a slightly lower level call than the 
+@code{PacketSinkHelper} call above, and uses an explicit C++ type instead of 
+one referred to by a string.  Otherwise, it is conceptually the same thing.
+
+Once the @code{TcpSocket} is created and attached to the @code{Node}, we can
+use @code{TraceConnectWithoutContext} to connect the CongestionWindow trace 
+source to our trace sink.
+
+Recall that we coded an @code{Application} so we could take that @code{Socket}
+we just made (during configuration time) and use it in simulation time.  We now 
+have to instantiate that @code{Application}.  We didn't go to any trouble to
+create a helper to manage the @code{Application} so we are going to have to 
+create and install it ``manually.''  This is actually quite easy:
+
+@verbatim
+  Ptr<SimpleSource> app = CreateObject<SimpleSource> ();
+  app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps"));
+  nodes.Get (0)->AddApplication (app);
+  app->Start (Seconds (1.));
+  app->Stop (Seconds (20.));
+@end verbatim
+
+The first line creates an @code{Object} of type @code{SimpleSource} -- our
+@code{Application}.  The second line tells the @code{Application} what
+@code{Socket} to use, what address to connect to, how much data to send 
+at each send event, how many send events to generate and the rate at which
+to produce data from those events.
+
+Next, we manually add the @code{SimpleSource Application} to the source node
+and explicitly call the @code{Start} and @code{Stop} methods on the 
+@code{Application} to tell it when to start and stop doing its thing.
+
+We need to actually do the connect from the receiver point-to-point @code{NetDevice}
+to our callback now.
+
+@verbatim
+  devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop));
+@end verbatim
+
+It should now be obvious that we are getting a reference to the receiving 
+@code{Node NetDevice} from its container and connecting the trace source defined
+by the attribute ``PhyRxDrop'' on that device to the trace sink @code{RxDrop}.
+
+Finally, we tell the simulator to override any @code{Applications} and just
+stop processing events at 20 seconds into the simulation.
+
+@verbatim
+    Simulator::Stop (Seconds(20));
+    Simulator::Run ();
+    Simulator::Destroy ();
+
+    return 0;
+  }
+@end verbatim
+
+Recall that as soon as @code{Simulator::Run} is called, configuration time
+ends, and simulation time begins.  All of the work we orchestrated by 
+creating the @code{Application} and teaching it how to connect and send
+data actually happens during this function call.
+
+As soon as @code{Simulator::Run} returns, the simulation is complete and
+we enter the teardown phase.  In this case, @code{Simulator::Destroy} takes
+care of the gory details and we just return a success code after it completes.
+
+@subsection Running fifth.cc
+
+Since we have provided the file @code{fifth.cc} for you, if you have built
+your distribution (in debug mode since it uses NS_LOG -- recall that optimized
+builds optimize out NS_LOGs) it will be waiting for you to run.
+
+@verbatim
+  ./waf --run fifth
+  Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build'
+  Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build'
+  'build' finished successfully (0.525s)
+  1.21397 1072
+  1.22755 1608
+  1.24114 2144
+  ...
+  1.35211 8576
+  1.36136 9112
+  1.37061 9648
+  RxDrop at 1.3729
+  ...
+@end verbatim
+
+You can probably see immediately a downside of using prints of any kind in your
+traces.  We get those extraneous waf messages printed all over our interesting
+information along with those RxDrop messages.  We will remedy that soon, but I'm
+sure you can't wait to see the results of all of this work.  Let's redirect that
+output to a file called @code{cwnd.dat}:
+
+@verbatim
+  ./waf --run fifth > cwnd.dat 2>&1
+@end verbatim
+
+Now edit up ``cwnd.dat'' in your favorite editor and remove the waf build status
+and drop lines, leaving only the traced data (you could also comment out the
+@code{TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop));} in the
+script to get rid of the drop prints just as easily. 
+
+You can now run gnuplot (if you have it installed) and tell it to generate some 
+pretty pictures:
+
+@verbatim
+  gnuplot> set terminal png size 1024,768
+  gnuplot> set output "cwnd.png"
+  gnuplot> plot "cwnd.dat" using 1:2 title 'Congestion Window' with linespoints
+  gnuplot> exit
+@end verbatim
+
+You should now have a graph of the congestion window versus time sitting in the 
+file ``cwnd.png'' in all of its glory, that looks like:
+
+@sp 1
+@center @image{figures/cwnd,,,,png}
 
 
-
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/tutorial/fifth.cc	Mon Oct 19 16:44:41 2009 -0700
@@ -0,0 +1,224 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#include <fstream>
+#include "ns3/core-module.h"
+#include "ns3/common-module.h"
+#include "ns3/simulator-module.h"
+#include "ns3/node-module.h"
+#include "ns3/helper-module.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("FifthScriptExample");
+
+// ===========================================================================
+//
+//         node 0                 node 1
+//   +----------------+    +----------------+
+//   |    ns-3 TCP    |    |    ns-3 TCP    |
+//   +----------------+    +----------------+
+//   |    10.1.1.1    |    |    10.1.1.2    |
+//   +----------------+    +----------------+
+//   | point-to-point |    | point-to-point |
+//   +----------------+    +----------------+
+//           |                     |
+//           +---------------------+
+//                5 Mbps, 2 ms
+//
+//
+// We want to look at changes in the ns-3 TCP congestion window.  We need
+// to crank up a flow and hook the CongestionWindow attribute on the socket
+// of the sender.  Normally one would use an on-off application to generate a
+// flow, but this has a couple of problems.  First, the socket of the on-off 
+// application is not created until Application Start time, so we wouldn't be 
+// able to hook the socket (now) at configuration time.  Second, even if we 
+// could arrange a call after start time, the socket is not public so we 
+// couldn't get at it.
+//
+// So, we can cook up a simple version of the on-off application that does what
+// we want.  On the plus side we don't need all of the complexity of the on-off
+// application.  On the minus side, we don't have a helper, so we have to get
+// a little more involved in the details, but this is trivial.
+//
+// So first, we create a socket and do the trace connect on it; then we pass 
+// this socket into the constructor of our simple application which we then 
+// install in the source node.
+// ===========================================================================
+//
+class SimpleSource : public Application 
+{
+public:
+
+  SimpleSource ();
+  virtual ~SimpleSource();
+
+  void Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate);
+
+private:
+  virtual void StartApplication (void);  
+  virtual void StopApplication (void);
+
+  void ScheduleTx (void);
+  void SendPacket (void);
+
+  Ptr<Socket>     m_socket;
+  Address         m_peer;
+  uint32_t        m_packetSize;
+  uint32_t        m_nPackets;
+  DataRate        m_dataRate;
+  EventId         m_sendEvent;
+  bool            m_running;
+  uint32_t        m_packetsSent;
+};
+
+SimpleSource::SimpleSource ()
+  : m_socket (0), 
+    m_peer (), 
+    m_packetSize (0), 
+    m_nPackets (0), 
+    m_dataRate (0), 
+    m_sendEvent (), 
+    m_running (false), 
+    m_packetsSent (0)
+{
+}
+
+SimpleSource::~SimpleSource()
+{
+  m_socket = 0;
+}
+
+void
+SimpleSource::Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate)
+{
+  m_socket = socket;
+  m_peer = address;
+  m_packetSize = packetSize;
+  m_nPackets = nPackets;
+  m_dataRate = dataRate;
+}
+
+void
+SimpleSource::StartApplication (void)
+{
+  m_running = true;
+  m_packetsSent = 0;
+  m_socket->Bind ();
+  m_socket->Connect (m_peer);
+  SendPacket ();
+}
+
+void 
+SimpleSource::StopApplication (void)
+{
+  m_running = false;
+
+  if (m_sendEvent.IsRunning ())
+    {
+      Simulator::Cancel (m_sendEvent);
+    }
+
+  if (m_socket)
+    {
+      m_socket->Close ();
+    }
+}
+
+void 
+SimpleSource::SendPacket (void)
+{
+  Ptr<Packet> packet = Create<Packet> (m_packetSize);
+  m_socket->Send (packet);
+
+  if (++m_packetsSent < m_nPackets)
+    {
+      ScheduleTx ();
+    }
+}
+
+void 
+SimpleSource::ScheduleTx (void)
+{
+  if (m_running)
+    {
+      Time tNext (Seconds (m_packetSize * 8 / static_cast<double> (m_dataRate.GetBitRate ())));
+      m_sendEvent = Simulator::Schedule (tNext, &SimpleSource::SendPacket, this);
+    }
+}
+
+static void
+CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
+{
+  NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
+}
+
+static void
+RxDrop (Ptr<const Packet> p)
+{
+  NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ());
+}
+
+int 
+main (int argc, char *argv[])
+{
+  NodeContainer nodes;
+  nodes.Create (2);
+
+  PointToPointHelper pointToPoint;
+  pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("1Mbps"));
+  pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
+
+  NetDeviceContainer devices;
+  devices = pointToPoint.Install (nodes);
+
+  Ptr<RateErrorModel> em = CreateObjectWithAttributes<RateErrorModel> (
+    "RanVar", RandomVariableValue (UniformVariable (0., 1.)),
+    "ErrorRate", DoubleValue (0.00001));
+  devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em));
+
+  InternetStackHelper stack;
+  stack.Install (nodes);
+
+  Ipv4AddressHelper address;
+  address.SetBase ("10.1.1.0", "255.255.255.252");
+  Ipv4InterfaceContainer interfaces = address.Assign (devices);
+
+  uint16_t sinkPort = 8080;
+  Address sinkAddress (InetSocketAddress(interfaces.GetAddress (1), sinkPort));
+  PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
+  ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (1));
+  sinkApps.Start (Seconds (0.));
+  sinkApps.Stop (Seconds (20.));
+
+  Ptr<Socket> ns3TcpSocket = Socket::CreateSocket (nodes.Get (0), TcpSocketFactory::GetTypeId ());
+  ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndChange));
+
+  Ptr<SimpleSource> app = CreateObject<SimpleSource> ();
+  app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("5Mbps"));
+  nodes.Get (0)->AddApplication (app);
+  app->Start (Seconds (1.));
+  app->Stop (Seconds (20.));
+
+  devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop));
+
+  Simulator::Stop (Seconds(20));
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  return 0;
+}
+
--- a/examples/tutorial/wscript	Sun Oct 18 22:11:29 2009 -0700
+++ b/examples/tutorial/wscript	Mon Oct 19 16:44:41 2009 -0700
@@ -15,3 +15,6 @@
 
     obj = bld.create_ns3_program('fourth', ['core'])
     obj.source = 'fourth.cc'
+
+    obj = bld.create_ns3_program('fifth', ['core', 'simulator', 'point-to-point', 'internet-stack'])
+    obj.source = 'fifth.cc'