diff --git a/doc/howtos/howtos-application.h b/doc/howtos/howtos-application.h
new file mode 100644
index 000000000..33ba848c3
--- /dev/null
+++ b/doc/howtos/howtos-application.h
@@ -0,0 +1,203 @@
+/*!
+ \page application How to create a traffic generator ?
+ \anchor howtos-application
+
+ Question: How do I create a new traffic generator ?
+
+ Answer: It is possible to instanciate \ref ns3::Packet "Packet"
+ objects, schedule events, and call functions from any piece of code
+ in ns-3 so, technically, there is no single answer to the question of
+ how we can write a new traffic generator. However, the
+ \ref ns3::Socket "Socket" API was really designed to be the single
+ point of entry for traffic generators or traffic analysers and the
+ \ref ns3::Application "Application" class was designed to hold
+ together any number of sockets.
+
+ Implementing a new traffic generator thus boils down to:
+- implementing a new subclass of the \ref ns3::Application "Application"
+ base class
+- instanciate one or many sockets within that application
+- start scheduling events when \ref ns3::Application::StartApplication "StartApplication"
+ is called
+- stop scheduling events when \ref ns3::Application::StopApplication "StopApplication"
+ is called
+- create packets and send them over one or many sockets in each event
+
+The following "random" generator generates packets separated by a random
+delay and with a random size.
+
+\code
+class RandomGenerator : public Application
+{
+public:
+ RandomGenerator ();
+ void SetDelay (RandomVariable delay);
+ void SetSize (RandomVariable size);
+ void SetRemote (std::string socketType,
+ Address remote);
+private:
+ virtual void StartApplication (void);
+ virtual void StopApplication (void);
+ void DoGenerate (void);
+
+ RandomVariable m_delay;
+ RandomVariable m_size;
+ Ptr m_socket;
+};
+\endcode
+
+The socket is created in the SetRemote method:
+\code
+void
+RandomGenerator::SetRemote (std::string socketType,
+ Address remote)
+{
+ TypeId tid = TypeId::LookupByName (socketType);
+ m_socket = Socket::CreateSocket (GetNode (), tid);
+ m_socket->Bind ();
+ m_socket->ShutdownRecv ();
+ m_socket->Connect (remote);
+}
+\endcode
+While the the crux of the logic is located in the DoGenerate method
+which is called from within StartApplication:
+\code
+void
+RandomGenerator::DoGenerate (void)
+{
+ m_next = Simulator::Schedule (Seconds (m_delay.GetValue ()),
+ &RandomGenerator::DoGenerate, this);
+ Ptr p = Create (m_size.GetIntValue ());
+ m_socket->Send (p);
+}
+\endcode
+
+To make that application more integrated in ns-3, it needs an associated
+helper class:
+\code
+class RandomAppHelper
+{
+public:
+ RandomAppHelper (std::string protocol, Address remote);
+ void SetPacketSize (RandomVariable packetSize);
+ void SetDelay (RandomVariable delay);
+ ApplicationContainer Install (NodeContainer nodes);
+private:
+ std::string m_protocol;
+ Address m_remote;
+ RandomVariable m_packetSize;
+ RandomVariable m_delay;
+};
+\endcode
+
+which could be trivially implemented as:
+\code
+ApplicationContainer
+RandomAppHelper::Install (NodeContainer nodes)
+{
+ ApplicationContainer applications;
+ for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i)
+ {
+ Ptr app = CreateObject ();
+ app->SetSize (m_packetSize);
+ app->SetDelay (m_delay);
+ app->SetRemote (m_protocol, m_remote);
+ (*i)->AddApplication (app);
+ applications.Add (app);
+ }
+ return applications;
+}
+\endcode
+
+Despite being functional, this API is not very consistant with the style of
+the other helper classes, all of which allow you to control the parameters
+of the underlying class through attributes and not explicit setters. The
+following API thus replaces the pair SetPacketSize/SetDelay with a single
+method SetAttribute:
+\code
+class RandomAppHelper
+{
+public:
+ RandomAppHelper (std::string protocol, Address remote);
+ void SetAttribute (std::string name, const AttributeValue &value);
+ ApplicationContainer Install (NodeContainer c);
+private:
+ std::string m_protocol;
+ Address m_remote;
+ ObjectFactory m_factory;
+};
+\endcode
+
+And which can be used as follows:
+\code
+RandomAppHelper app = RandomAppHelper ("ns3::TcpSocketFactory",
+ InetSocketAddress (Ipv4Address ("192.168.1.10"), 10));
+app.SetAttribute ("Delay", StringValue ("Constant:2.5"));
+app.SetAttribute ("Size", StringValue ("Constant:2100"));
+app.Install (nodes);
+\endcode
+
+The implementation, in this case, is not necessarily longer but its
+simplicity hides a lot of behind-the-scenes complexity:
+
+\code
+void
+RandomAppHelper::SetAttribute (std::string name, const AttributeValue &value)
+{
+ m_factory.Set (name, value);
+}
+ApplicationContainer
+RandomAppHelper::Install (NodeContainer nodes)
+{
+ ApplicationContainer applications;
+ for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i)
+ {
+ Ptr app = m_factory.Create ();
+ app->SetRemote (m_socketType, m_remote);
+ (*i)->AddApplication (app);
+ applications.Add (app);
+ }
+ return applications;
+}
+\endcode
+
+The key difference between this implementation and the previous one
+is that this helper does not handle explicitely the attributes
+delay and packet size. Instead, it stores them in an
+\ref ns3::ObjectFactory "ObjectFactory" object. This, of course,
+does not work magically, and requires extra support from the
+underlying RandomGenerator class. Specifically, it requires
+that the underlying RandomGenerator defines its attributes
+in its \ref ns3::TypeId "TypeId" in a new public static method:
+
+\code
+class RandomGenerator
+{
+public:
+ static TypeId GetTypeId (void);
+};
+\endcode
+
+The corresponding implementation is shown below:
+
+\code
+TypeId
+RandomGenerator::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("RandomGenerator")
+ .SetParent ()
+ .AddConstructor ()
+ .AddAttribute ("Delay", "The delay between two packets (s)",
+ RandomVariableValue (ConstantVariable (1.0)),
+ MakeRandomVariableAccessor (&RandomGenerator::m_delay),
+ MakeRandomVariableChecker ())
+ .AddAttribute ("PacketSize", "The size of each packet (bytes)",
+ RandomVariableValue (ConstantVariable (2000)),
+ MakeRandomVariableAccessor (&RandomGenerator::m_size),
+ MakeRandomVariableChecker ())
+ ;
+ return tid;
+}
+\endcode
+
+*/
diff --git a/doc/howtos/howtos.h b/doc/howtos/howtos.h
index 2e84cd8e6..199b0d1b9 100644
--- a/doc/howtos/howtos.h
+++ b/doc/howtos/howtos.h
@@ -11,9 +11,10 @@ for ns-3. This complements the following wiki pages:
Please consider contributing tips to either the wiki (yourself) or
by submitting a patch to this maintained documentation.
-- \subpage net-device
- \subpage callbacks
- \subpage packet-header-trailer
+- \subpage net-device
+- \subpage application
*/