Reorganize examples
g0dil [Mon, 20 Aug 2007 23:06:51 +0000 (23:06 +0000)]
Examples/RateStuffer: documentation

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@402 270642c3-0616-0410-b53a-bc976706d245

16 files changed:
Examples/Doxyfile
Examples/Mainpage.dox
Examples/RateStuffer/Doxyfile [new file with mode: 0644]
Examples/RateStuffer/Mainpage.dox [new file with mode: 0644]
Examples/RateStuffer/SConscript
Examples/RateStuffer/ratestuffer.cc
Examples/RateStuffer/ratestuffer.dia [new file with mode: 0644]
Examples/RateStuffer/screenshot.png [new file with mode: 0644]
Examples/Sniffer/Doxyfile [new file with mode: 0644]
Examples/Sniffer/Mainpage.dox [new file with mode: 0644]
Examples/Sniffer/SConscript
PPI/Doxyfile
PPI/Module.hh
PPI/Setup.hh
doclib/Doxyfile.global
doclib/SConscript

index 1cfe419..48505f2 100644 (file)
@@ -1,7 +1,3 @@
-@INCLUDE                 = "$(TOPDIR)/doclib/Doxyfile.global"
+@INCLUDE           = "$(TOPDIR)/doclib/Doxyfile.global"
 
-PROJECT_NAME     = Examples
-TAGFILES          = "$(TOPDIR)/Utils/doc/Utils.tag" "$(TOPDIR)/Socket/doc/Socket.tag" "$(TOPDIR)/Packets/doc/Packets.tag" "$(TOPDIR)/Scheduler/doc/Scheduler.tag" "$(TOPDIR)/doc/overview.tag"
-GENERATE_TAGFILE  = doc/Examples.tag
-
-EXAMPLE_PATH      = "Sniffer"
\ No newline at end of file
+PROJECT_NAME      = Examples
index f8ef7eb..9557a71 100644 (file)
 /** \mainpage Examples
     
-    \ref sniffer
-*/
-
-/** \page sniffer Sniffer: A simple example application
-
-    \dontinclude Sniffer.cc
-
-    The Sniffer application is a simple command line network sniffer like \c tcpdump or \c
-    tethereal. The application uses a packet socket to read Ethernet packets from the \c eth0
-    interface and dumps the parsed packets out to the standard output.
-
-    To try out the example application, check out the library, go to the \c Sniffer
-    directory and execute
-
-    <pre>
-    # scons -u
-    # ./sniffer loop
-    < Hit Ctrl-C when you've seen enough >
-    # ./sniffer scheduler
-    < Hit Ctrl-C when you've seen enough >
-    </pre>
-
-    We will now look at the code which is found in \c Sniffer.cc in the \c Sniffer directory. The
-    code starts out by including the necessary headers
-
-    \skip // Custom includes
-    \until membind
-
-    (The additional includes found in the source but not shown here are part of a short-time fix
-    which will be removed as soon as possible). The example application now contains a helper
-    routine to produce a packet hexdump. We will skip this routine here. The example includes two
-    implementations, one using blocking calls and a while loop, the other using the senf::Scheduler
-    for asynchronous event notification. They are implemented in \c loop_main() and \c
-    scheduler_main(). They will be documented below. For now, we skip these implementations and go
-    straight to the \c main() function
-
-    \skip int main(
-    \until return 1;
-    \until }
-
-    This routine simply interprets the first command line argument and dispatches to the required
-    implementation.
-
-    Now lets go back and study each implementation in detail.
-
-    \dontinclude Sniffer.cc
-
-    \section example_loop A Blocking Implementation
-
-    This implementation is found in the \c loop_main function.
-
-    \skip loop_main
-    \until try
-
-    We catch all exceptions in a \c try block. This is good for a deliverable binary. When debugging
-    the application, it might be better to let the exception \c abort the execution so you can get a
-    backtrace of the exception origin in the debugger.
-
-    We now create a packet socket and bind it to the \c eth0 interface. A packet socket is a linux
-    specific type of socket which returns ethernet packets directly from the network wire. By
-    uncommenting the last line, you may switch the interface into promiscuous mode.
-
-    \until //
-
-    We will now read packets from the socket forever, that is until the user hits Ctrl-C
-
-    \skip while
-    \until read
-
-    The next step is, to parse the data read from the socket as an Ethernet packet
-
-    \until ;
-
-    Lets digest this line step by step: We declare a variable named \c packet as a smart pointer to
-    an \c EthernetPacket instance. \c ptr is a typedef member of all Packet classes for the
-    corresponding smart pointer type. We then initialize this pointer with a call to the static \c
-    create member of the \c Packet class. This member takes the type of Packet to parse as a
-    template argument. We pass \c EthernetPacket here. The function takes an iterator range as an
-    argument, and we pass it the complete packet just read by giving the range \c begin() to \c
-    end() of our just read \c data string.
-
-    The next step is to write out the packet to the standard output
+    \htmlonly
+    <dl>
+   
+    <dt><a href="../../Sniffer/doc/html/index.html">Sniffer</a></dt><dd>Simple packet sniffer
+    reading packets from a packet socket and dumping packet parse to stdout</dd>
 
-    \until \n\n
-
-    The \c dump call will write out a complete representation of the parsed packet data. The Packet
-    library will \e not try to interpret payload data as long as no exact indication of the payload
-    type is available (example: A UDP Payload is not parsed further unless you explicitly tell the
-    library, how to parse it).  Tools like \c tethereal guess the payload type by checking port
-    numbers and the payload data, however this is not advisable for a general purpose packet
-    library.
-
-    The next line, \c hexdump, will write out the \e last packet component. Packets are managed as a
-    chain of headers. The last header is normally a \c DataPacket holding the payload data.
-
-    That's it. We finish of by catching the exception and giving as much detail as possible if an
-    exception is caught
-
-    \until ;
-    \until }
-    \until }
-
-    The \c prettyName function from the \c Utils library is used, to get a nice, printable
-    representation of the \e dynamic type of the exception instance. It is an interface to the g++
-    demangler. This is necessary since the \c name member of the C++ \c type_info instance is a
-    mangled name in \c g++.
-    
-    That's it for the simple blocking implementation. 
-
-    \section example_scheduler Using the Scheduler
-
-    However, we have another one which uses the Scheduler. We do this as it will be most of the
-    time: We define a class which manages reading the packets and dumping them out.
-
-    \until }
-
-    The class constructor binds the socket defined as a data member to the correct interface.
-
-    \until add
-
-    The public \c run() member is called to run the sniffer.  It first adds the socket to the
-    Scheduler. The \c add() call takes two Arguments, the socket to bind to (which can be a lot of
-    things and must not necessarily be a socket instance) and callback to call, whenever there is an
-    event on that socket. A third argument may be specified to restrict the events, on which the
-    function is called, here we have left out this argument which defaults to
-    senf::Scheduler::EV_ALL.
-
-    The callback is specified as a <a
-    href="http://www.boost.org/doc/html/function.html">Boost.Function</a> object. We use the \c
-    senf::membind helper from the Utils library to build such a function object. This helper takes
-    an arbitrary class member and binds it to a specific instance.
-
-    \until }
-
-    Calling the Schedulers \c process() method will start the event loop. This call does not return
-    (ok, it does return in special cases if \c senf::Scheduler::terminate() is called which does not
-    apply here).
-    
-    \until {
-
-    The \c dumpPacket() member is called by the scheduler whenever an event on the socket is
-    encountered. The scheduler always passes two arguments: The socket and an event id which
-    identifies the type of event which triggered the call.
-
-    \until };
-
-    The body is absolutely identical to the body of the \c while loop of the blocking
-    implementation. However, the scheduler guarantees, that a read on the socket will not block if
-    the socket is triggered to be readable (even if the socket is not set to non-blocking mode).
-
-    We now only need to provide the \c scheduler_main() function to run this code
-
-    \until 0;
-    \until }
-
-    This function is straight forward. The exception handling is the same as in \c loop_main(). The
-    code then just creates a \c Sniffer instance and calls it's \c run() member.
-
-    \see \ref components \n
-         \ref build \n
-         <a href="../../../Socket/doc/html/index.html"><b>libSocket API reference</b></a> \n
-         <a href="../../../Packets/doc/html/index.html"><b>libPackets API reference</b></a> \n
-         <a href="../../../Utils/doc/html/index.html"><b>libUtils API reference</b></a>
- */
+    <dt><a href="../../RateStuffer/doc/html/index.html">RateStuffer</a></dt><dd>Example application
+    showing of the PPI infrastructure</dd>
 
+    </dl>
+    \endhtmlonly
+*/
 
 \f
 // Local Variables:
diff --git a/Examples/RateStuffer/Doxyfile b/Examples/RateStuffer/Doxyfile
new file mode 100644 (file)
index 0000000..ed23663
--- /dev/null
@@ -0,0 +1,7 @@
+@INCLUDE          = "$(TOPDIR)/doclib/Doxyfile.global"
+
+PROJECT_NAME      = RateStuffer
+TAGFILES          = "$(TOPDIR)/Utils/doc/Utils.tag" "$(TOPDIR)/Socket/doc/Socket.tag" "$(TOPDIR)/Packets/doc/Packets.tag" "$(TOPDIR)/Scheduler/doc/Scheduler.tag" "$(TOPDIR)/PPI/doc/PPI.tag"
+ALPHABETICAL_INDEX = NO
+
+EXAMPLE_PATH      = "."
\ No newline at end of file
diff --git a/Examples/RateStuffer/Mainpage.dox b/Examples/RateStuffer/Mainpage.dox
new file mode 100644 (file)
index 0000000..9f51da2
--- /dev/null
@@ -0,0 +1,187 @@
+// $Id$
+//
+// Copyright (C) 2007 
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// 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.
+
+/** \mainpage RateStuffer: A simple example featuring the Packet Processing Infrastructure
+
+    This example application implements a simple PPI application: It will read UDP packets from an
+    input port and will forward them to another port at a fixed packet rate. If the input stream
+    does not provide enough packets, empty UDP packets will be sent instead.
+    
+    \section run Running the example
+
+    Running the example is a little bit more complicated since we need to provide example UDP
+    packets so we can see the application at work. We do this using \c netcat. We open several shell
+    windows and run the folling commands, each in it's own window
+
+    The first command listens for incoming UDP packets on port 44345:
+    <pre>
+    # nc -u -l -p 44345
+    </pre>
+    
+    The next command starts the \c ratestuffer
+    <pre>
+    # cd .../Examples/RateStuffer
+    # scons -u
+    # ./ratestuffer
+    </pre>
+
+    We should now see '<idle>' messages arriving in the first window once per second. We now can
+    start another \c netcat to send packets to the input port.
+
+    <pre>
+    # nc -u localhost 44344
+    < type any text here >
+    </pre>
+
+    Whenever we send out a packet with CR in the last window we should see it appear in the first
+    one. If we send out packets faster than 1 packet per seccond, they will still only be forwarded
+    with a speed of 1 packet / seccond. If the kernel UDP buffer overflows, packets would be dropped
+    (however, this buffer is prohibitively large) 
+
+    \image html screenshot.png
+
+    \section setup Module setup
+
+    \image html ratestuffer.png
+
+    Above image depicts the module setup implementing the rate stuffer. A
+    senf::ppi::module::ActiveSocketReader reads the incoming UDP packets and sends them into a
+    senf::ppi::module::PassiveQueue.
+
+    The \a queue feeds the packets into a senf::ppi::module::PriorityJoin. The CopyPacketGenerator
+    \a generator is fed as second input into the \a join to provide the stuffing packets.
+
+    The RateFilter \a rateFilter reads packets from it's input at a fixed rate and writes them into
+    the senf::ppi::module::PassiveSocketWriter \a udpWriter. The senf::ppi::module::PriorityJoin
+    ensures that read requests of the RateStuffer's input are always serviced, either from the \a
+    queue or, if the \a queue output is throttled, from the \a generator.
+
+    \section code Example code
+
+    \dontinclude ratestuffer.cc
+
+    The code starts out including the necessary header files
+
+    \skip Custom
+    \skip #include
+    \until Setup
+
+    We also define some namepsace aliases
+
+    \skip namespace
+    \until senf::ppi;
+
+    The RateStuffer application is based on two additional modules.
+
+    \subsection ratefilter The RateFilter module
+
+    The RateFilter module simply forwards packets at a fixed rate.
+
+    \skip class
+    \until };
+
+    Both connectors of the RateFilter module are active. The module is driven by a
+    senf::ppi::IntervalTimer.
+
+    \until }
+
+    The event is initialized to fire eery \a interval nanoseconds.  The traffic is routed 'accross'
+    the timer which controls the traffic. The timer is then registered to call
+    RateFilter::timeout().
+
+    \until }
+
+    The event handler is quite simple: Every \a interval nanoseconds a packet is read from \a input
+    and forwarded to \a output.
+
+    This is all there is to the RateFilter module. Due to the routing setup, the timer will
+    automatically be disabled if either \a input or \a output become throttled (which is not even
+    needed here).
+
+    \subsection generator The CopyPacketGenerator
+
+    We need an additional module to provide the stuffing packets. The CopyPacketGenerator provides
+    an unlimited stream of clone's of a template packet.
+
+    \skip class
+    \until };
+
+    This module is very simple. 
+
+    \until }
+
+    We save the template packet and initialize the \a output connector to call
+    CopyPacketGenerator::request() whenever a packet is requested.
+
+    \until }
+
+    The handler just provides \a packet on each request. This is ok as long as the packets are not
+    changed, in which case we would return <tt>packet->clone()</tt> instead.
+
+    \subsection main Connecting the modules
+
+    The applications main() method starts out by initializing the socket handles
+
+    \skip main
+    \until 44345
+
+    The \a inputSocket is listening on port 44344 while the \a outputSocket will send packets to
+    port 44345 on localhost. The \a outputSocket uses a ConnectedUDPv4SocketHandle which is
+    compatible with the senf::ppi::module::PassiveSocketWriter module.
+
+    \until udpWriter
+
+    Next all the modules are allocated:
+
+    \li \a udpReader to read the packets from \a inputSocket
+    \li \a queue to convert the active output of senf::ppi::module::ActiveSocketReader into a
+        passive output
+    \li \a generator to provide the stuffing in the form of packets containing <tt>"<idle>\n"</tt>
+    \li \a join to combine the two packet streams (from \a udpReader and from \a generator) into a
+        single stream
+    \li \a rateFilter to generate the fixed rate packet stream of 1 packet every 1000000000
+        nanoseconds and
+    \li \a udpWriter to send the packets to \a outputSocket
+
+    \until udpWriter
+
+    The \ref senf::ppi::connect() calls now setup the necessary connections.
+    
+    \until run
+
+    The module setup is complete, \ref senf::ppi::run() is called to enter the event loop.
+
+    \until }
+ */
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u doc"
+// mode: flyspell
+// mode: auto-fill
+// End:
index 6d9f231..dec0b30 100644 (file)
@@ -5,3 +5,7 @@ import SENFSCons
 
 SENFSCons.Binary( env, 'ratestuffer', SENFSCons.GlobSources(),
                   LIBS = [ 'PPI', 'Scheduler', 'Packets', 'Socket', 'Utils' ] );
+
+SENFSCons.Doxygen(env, extra_sources=[
+    env.Dia2Png('ratestuffer.dia')
+])
index ea29427..7c1d1c7 100644 (file)
@@ -46,53 +46,73 @@ namespace module = senf::ppi::module;
 namespace connector = senf::ppi::connector;
 namespace ppi = senf::ppi;
 
-namespace {
-
-    class RateFilter
-        : public module::Module
-    {
-        SENF_PPI_MODULE(RateFilter);
-    public:
-
-        connector::ActiveInput input;
-        connector::ActiveOutput output;
-
-        RateFilter(senf::ClockService::clock_type interval) : timer(interval) {
-            route(input,output);
-            route(input,timer);
-            registerEvent(&RateFilter::timeout, timer);
-        }
-
-    private:
-        void timeout() {
-            output(input());
-        }
-
-        ppi::IntervalTimer timer;
-    };
-
-    class CopyPacketGenerator
-        : public module::Module
-    {
-        SENF_PPI_MODULE(CopyPacketGenerator);
-    public:
-
-        connector::PassiveOutput output;
-
-        CopyPacketGenerator(senf::Packet p) : packet(p) {
-            noroute(output);
-            output.onRequest(&CopyPacketGenerator::request);
-        }
-
-    private:
-        void request() {
-            output(packet);
-        }
-
-        senf::Packet packet;
-    };
+// ////////////////////////////////////////////////////////////////////////
+// RateFilter
+
+class RateFilter
+    : public module::Module
+{
+    SENF_PPI_MODULE(RateFilter);
+public:
+
+    connector::ActiveInput input;
+    connector::ActiveOutput output;
+
+    RateFilter(senf::ClockService::clock_type interval);
+
+private:
+    void timeout();
+
+    ppi::IntervalTimer timer;
+};
+
+RateFilter::RateFilter(senf::ClockService::clock_type interval)
+    : timer(interval) 
+{
+    route(input,timer);
+    route(timer,output);
+    registerEvent(&RateFilter::timeout, timer);
+}
+
+void RateFilter::timeout()
+{
+    output(input());
 }
 
+// ////////////////////////////////////////////////////////////////////////
+// CopyPacketGenerator
+
+class CopyPacketGenerator
+    : public module::Module
+{
+    SENF_PPI_MODULE(CopyPacketGenerator);
+public:
+
+    connector::PassiveOutput output;
+
+    CopyPacketGenerator(senf::Packet p);
+
+private:
+    void request();
+
+    senf::Packet packet;
+};
+
+CopyPacketGenerator::CopyPacketGenerator(senf::Packet p)
+    : packet(p) 
+{
+    noroute(output);
+    output.onRequest(&CopyPacketGenerator::request);
+}
+
+void CopyPacketGenerator::request()
+{
+    output(packet);
+}
+
+// ////////////////////////////////////////////////////////////////////////
+// ////////////////////////////////////////////////////////////////////////
+
 // Module setup:
 //
 // 'O'        = active connector
diff --git a/Examples/RateStuffer/ratestuffer.dia b/Examples/RateStuffer/ratestuffer.dia
new file mode 100644 (file)
index 0000000..3056cd9
Binary files /dev/null and b/Examples/RateStuffer/ratestuffer.dia differ
diff --git a/Examples/RateStuffer/screenshot.png b/Examples/RateStuffer/screenshot.png
new file mode 100644 (file)
index 0000000..28d8495
Binary files /dev/null and b/Examples/RateStuffer/screenshot.png differ
diff --git a/Examples/Sniffer/Doxyfile b/Examples/Sniffer/Doxyfile
new file mode 100644 (file)
index 0000000..7818719
--- /dev/null
@@ -0,0 +1,6 @@
+@INCLUDE         = "$(TOPDIR)/doclib/Doxyfile.global"
+
+PROJECT_NAME     = Sniffer
+TAGFILES          = "$(TOPDIR)/Utils/doc/Utils.tag" "$(TOPDIR)/Socket/doc/Socket.tag" "$(TOPDIR)/Packets/doc/Packets.tag" "$(TOPDIR)/Scheduler/doc/Scheduler.tag"
+
+EXAMPLE_PATH      = "."
\ No newline at end of file
diff --git a/Examples/Sniffer/Mainpage.dox b/Examples/Sniffer/Mainpage.dox
new file mode 100644 (file)
index 0000000..4c41d5f
--- /dev/null
@@ -0,0 +1,196 @@
+// $Id$
+//
+// Copyright (C) 2007 
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// 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.
+
+/** \mainpage Sniffer: A simple example application
+
+    \dontinclude Sniffer.cc
+
+    The Sniffer application is a simple command line network sniffer like \c tcpdump or \c
+    tethereal. The application uses a packet socket to read Ethernet packets from the \c eth0
+    interface and dumps the parsed packets out to the standard output.
+
+    To try out the example application, check out the library, go to the \c Sniffer
+    directory and execute
+
+    <pre>
+    # scons -u
+    # ./sniffer loop
+    < Hit Ctrl-C when you've seen enough >
+    # ./sniffer scheduler
+    < Hit Ctrl-C when you've seen enough >
+    </pre>
+
+    We will now look at the code which is found in \c Sniffer.cc in the \c Sniffer directory. The
+    code starts out by including the necessary headers
+
+    \skip // Custom includes
+    \until membind
+
+    (The additional includes found in the source but not shown here are part of a short-time fix
+    which will be removed as soon as possible). The example application now contains a helper
+    routine to produce a packet hexdump. We will skip this routine here. The example includes two
+    implementations, one using blocking calls and a while loop, the other using the senf::Scheduler
+    for asynchronous event notification. They are implemented in \c loop_main() and \c
+    scheduler_main(). They will be documented below. For now, we skip these implementations and go
+    straight to the \c main() function
+
+    \skip int main(
+    \until return 1;
+    \until }
+
+    This routine simply interprets the first command line argument and dispatches to the required
+    implementation.
+
+    Now lets go back and study each implementation in detail.
+
+    \dontinclude Sniffer.cc
+
+    \section example_loop A Blocking Implementation
+
+    This implementation is found in the \c loop_main function.
+
+    \skip loop_main
+    \until try
+
+    We catch all exceptions in a \c try block. This is good for a deliverable binary. When debugging
+    the application, it might be better to let the exception \c abort the execution so you can get a
+    backtrace of the exception origin in the debugger.
+
+    We now create a packet socket and bind it to the \c eth0 interface. A packet socket is a linux
+    specific type of socket which returns ethernet packets directly from the network wire. By
+    uncommenting the last line, you may switch the interface into promiscuous mode.
+
+    \until //
+
+    We will now read packets from the socket forever, that is until the user hits Ctrl-C
+
+    \skip while
+    \until read
+
+    The next step is, to parse the data read from the socket as an Ethernet packet
+
+    \until ;
+
+    Lets digest this line step by step: We declare a variable named \c packet as a smart pointer to
+    an \c EthernetPacket instance. \c ptr is a typedef member of all Packet classes for the
+    corresponding smart pointer type. We then initialize this pointer with a call to the static \c
+    create member of the \c Packet class. This member takes the type of Packet to parse as a
+    template argument. We pass \c EthernetPacket here. The function takes an iterator range as an
+    argument, and we pass it the complete packet just read by giving the range \c begin() to \c
+    end() of our just read \c data string.
+
+    The next step is to write out the packet to the standard output
+
+    \until \n\n
+
+    The \c dump call will write out a complete representation of the parsed packet data. The Packet
+    library will \e not try to interpret payload data as long as no exact indication of the payload
+    type is available (example: A UDP Payload is not parsed further unless you explicitly tell the
+    library, how to parse it).  Tools like \c tethereal guess the payload type by checking port
+    numbers and the payload data, however this is not advisable for a general purpose packet
+    library.
+
+    The next line, \c hexdump, will write out the \e last packet component. Packets are managed as a
+    chain of headers. The last header is normally a \c DataPacket holding the payload data.
+
+    That's it. We finish of by catching the exception and giving as much detail as possible if an
+    exception is caught
+
+    \until ;
+    \until }
+    \until }
+
+    The \c prettyName function from the \c Utils library is used, to get a nice, printable
+    representation of the \e dynamic type of the exception instance. It is an interface to the g++
+    demangler. This is necessary since the \c name member of the C++ \c type_info instance is a
+    mangled name in \c g++.
+    
+    That's it for the simple blocking implementation. 
+
+    \section example_scheduler Using the Scheduler
+
+    However, we have another one which uses the Scheduler. We do this as it will be most of the
+    time: We define a class which manages reading the packets and dumping them out.
+
+    \until }
+
+    The class constructor binds the socket defined as a data member to the correct interface.
+
+    \until add
+
+    The public \c run() member is called to run the sniffer.  It first adds the socket to the
+    Scheduler. The \c add() call takes two Arguments, the socket to bind to (which can be a lot of
+    things and must not necessarily be a socket instance) and callback to call, whenever there is an
+    event on that socket. A third argument may be specified to restrict the events, on which the
+    function is called, here we have left out this argument which defaults to
+    senf::Scheduler::EV_ALL.
+
+    The callback is specified as a <a
+    href="http://www.boost.org/doc/html/function.html">Boost.Function</a> object. We use the \c
+    senf::membind helper from the Utils library to build such a function object. This helper takes
+    an arbitrary class member and binds it to a specific instance.
+
+    \until }
+
+    Calling the Schedulers \c process() method will start the event loop. This call does not return
+    (ok, it does return in special cases if \c senf::Scheduler::terminate() is called which does not
+    apply here).
+    
+    \until {
+
+    The \c dumpPacket() member is called by the scheduler whenever an event on the socket is
+    encountered. The scheduler always passes two arguments: The socket and an event id which
+    identifies the type of event which triggered the call.
+
+    \until };
+
+    The body is absolutely identical to the body of the \c while loop of the blocking
+    implementation. However, the scheduler guarantees, that a read on the socket will not block if
+    the socket is triggered to be readable (even if the socket is not set to non-blocking mode).
+
+    We now only need to provide the \c scheduler_main() function to run this code
+
+    \until 0;
+    \until }
+
+    This function is straight forward. The exception handling is the same as in \c loop_main(). The
+    code then just creates a \c Sniffer instance and calls it's \c run() member.
+
+    \see \ref components \n
+         \ref build \n
+         <a href="../../../Socket/doc/html/index.html"><b>libSocket API reference</b></a> \n
+         <a href="../../../Packets/doc/html/index.html"><b>libPackets API reference</b></a> \n
+         <a href="../../../Utils/doc/html/index.html"><b>libUtils API reference</b></a>
+ */
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// mode: flyspell
+// mode: auto-fill
+// End:
index 6c1c57a..e30f7c9 100644 (file)
@@ -6,3 +6,5 @@ import SENFSCons
 SENFSCons.Binary(env, 'sniffer', SENFSCons.GlobSources(),
                  LIBS = [ 'Scheduler', 'Packets', 'Socket', 'Utils' ],
                  OBJECTS = [ '#/Packets/DefaultBundle/DefaultBundle.o' ]);
+
+SENFSCons.Doxygen(env)
index 73ee2a5..6b2f429 100644 (file)
@@ -5,4 +5,5 @@ GENERATE_TAGFILE = doc/ppi.tag
 RECURSIVE = Yes
 SHOW_DIRECTORIES = Yes
 
-TAGFILES = "$(TOPDIR)/Packets/doc/Packets.tag" "$(TOPDIR)/Socket/doc/Socket.tag"
+TAGFILES = "$(TOPDIR)/Packets/doc/Packets.tag" "$(TOPDIR)/Socket/doc/Socket.tag" "$(TOPDIR)/Utils/doc/Utils.tag" "$(TOPDIR)/Scheduler/doc/Scheduler.tag"
+GENERATE_TAGFILE = "doc/PPI.tag"
index e5551ed..5ae07e9 100644 (file)
@@ -126,7 +126,9 @@ namespace module {
 
         void destroy();
 
+#ifndef DOXYGEN
         virtual void macro_SENF_PPI_MODULE_missing() = 0;
+#endif
 
     private:
         virtual void init();
index 12e7d90..57215b1 100644 (file)
@@ -34,7 +34,9 @@
 
 namespace senf {
 namespace ppi {
-    
+
+#ifndef DOXYGEN    
+
     void connect(connector::ActiveOutput & source, connector::PassiveInput & target);
     void connect(connector::PassiveOutput & source, connector::ActiveInput & target);
     
@@ -52,7 +54,14 @@ namespace ppi {
     void connect(M1 & source, M2 & target,
                  typename boost::enable_if< boost::is_base_of<module::Module, M1> >::type * = 0,
                  typename boost::enable_if< boost::is_base_of<module::Module, M2> >::type * = 0);
-    
+
+#else
+
+    template <class Source, class Target>
+    void connect(Source & source, Target & target);
+
+#endif
+
     void run();
     void init();
 
index b2d6303..bdae4f0 100644 (file)
@@ -25,7 +25,7 @@ SEARCHENGINE           = YES
 
 MACRO_EXPANSION        = YES
 EXPAND_ONLY_PREDEF     = YES
-PREDEFINED             = DOXYGEN
+PREDEFINED             = DOXYGEN SENF_PPI_MODULE(x)=
 EXPAND_AS_DEFINED      = prefix_
 
 HTML_HEADER            = "$(TOPDIR)/doclib/doxy-header.html"
index e72656b..3712380 100644 (file)
@@ -11,19 +11,20 @@ def modules():
     # Naja ... etwas rumgehackt aber was solls ...
     global EXTRA_MODULES
     mods = {}
-    ix = len(env.Dir('#').abspath)+1
-    ex = dict((env.Dir(p).abspath,True) for n,p in EXTRA_MODULES)
+    pathbase = len(env.Dir('#').abspath)+1
     for module in env.Alias('all_docs')[0].sources:
         if module.name != 'html.stamp' : continue 
-        if not ex.get(module.dir.abspath):
-            mods[module.dir.dir.dir.abspath] = [ module.dir.dir.dir.name, module.dir.abspath[ix:], 0 ]
+        mods[module.dir.dir.dir.abspath] = [ module.dir.dir.dir.name,
+                                             module.dir.abspath[pathbase:],
+                                             0 ]
+        
     rv = []
     keys = mods.keys()
     keys.sort()
     for mod in keys:
         i = 0
         while i < len(rv):
-            if mod.startswith(rv[i] + '/'):
+            if len(rv[i]) > pathbase and mod.startswith(rv[i] + '/'):
                 level = mods[rv[i]][2] + 1
                 i += 1
                 while i < len(rv) and mods[rv[i]][2] >= level:
@@ -34,11 +35,29 @@ def modules():
             i += 1
         if i == len(rv):
             rv.append(mod)
-    return [ (name, env.Dir(path).abspath[ix:], 0) for name,path in EXTRA_MODULES
-             ] + [ ( (((not mods[mod][2]) and 'lib') or '') + mods[mod][0],
-                     mods[mod][1],
-                     mods[mod][2])
-                   for mod in rv ]
+
+    for mod in keys:
+        if mods[mod][2] == 0:
+            mods[mod][0] = 'lib' + mods[mod][0]
+
+    n = 0
+    for name,path in EXTRA_MODULES:
+        path = env.Dir(path).dir.dir.abspath
+        i = 0
+        while i < len(rv):
+            if rv[i] == path:
+                mods[rv[i]][0] = name
+                m = 1
+                while i+m < len(rv) and mods[rv[i+m]][2] > mods[rv[i]][2]:
+                    m += 1
+                rv[n:n] = rv[i:i+m]
+                rv[i+m:i+2*m] = []
+                i += m
+                n += m
+            else:
+                i += 1
+
+    return ( tuple(mods[mod]) for mod in rv )
 
 def indices():
     ix = len(env.Dir('#').abspath)+1