Skip to content
Snippets Groups Projects
Commit c5d0f0d1 authored by g0dil's avatar g0dil
Browse files

Documented coding guidelines (file naming, class naming etc)

Extended the Sniffer example to optionally use the Scheduler
Some additional small documentation fixes
parent df91a1a7
No related branches found
No related tags found
No related merge requests found
......@@ -2,97 +2,156 @@
\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.
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.
We will be looking at \c Sniffer.cc in the \c Sniffer
directory. We start by including the necessary headers
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 Ethernet
\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 }
(The additional includes 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 and go directly to the \c main function
This routine simply interprets the first command line argument and dispatches to the required
implementation.
\skip main
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 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. By uncommenting the last line, you may switch the
interface into promiscuous mode.
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
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
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.
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
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 \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.
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
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++.
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.
That's it. This is all, that's necessary to read and parse raw
network packets using the SENF library. To try out the example
application, check out the library, go to the \c Sniffer directory
and execute
\section example_scheduler Using the Scheduler
<pre>
# scons -u
# ./Sniffer
</pre>
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
......
This diff is collapsed.
......@@ -36,7 +36,9 @@ SConscript(glob.glob("*/SConscript"))
SENFSCons.StandardTargets(env)
SENFSCons.GlobalTargets(env)
SENFSCons.Doxygen(env)
SENFSCons.Doxygen(env, extra_sources = [
'Sniffer/Sniffer.cc',
])
SENFSCons.DoxyXRef(env,
HTML_HEADER = '#/doclib/doxy-header-overview.html',
HTML_FOOTER = '#/doclib/doxy-footer.html')
......
......@@ -4,4 +4,4 @@ import SENFSCons
###########################################################################
SENFSCons.Binary(env, 'sniffer', SENFSCons.GlobSources(),
LIBS = [ 'Packets', 'Socket', 'Utils' ]);
LIBS = [ 'Scheduler', 'Packets', 'Socket', 'Utils' ]);
......@@ -30,6 +30,9 @@
#include <iostream>
#include <iomanip>
#include "Socket/PacketSocketHandle.hh"
#include "Scheduler/Scheduler.hh"
#include "Utils/membind.hh"
#include "Packets/EthernetPacket.hh"
#include "Packets/IpV4Packet.hh"
#include "Packets/UDPPacket.hh"
......@@ -86,7 +89,7 @@ namespace {
}
}
int main (int argc, char const * argv[])
int loop_main (int argc, char const * argv[])
{
try {
senf::PacketSocketHandle sock;
......@@ -107,6 +110,59 @@ int main (int argc, char const * argv[])
catch (std::exception const & ex) {
std::cerr << senf::prettyName(typeid(ex)) << ": " << ex.what() << "\n";
}
return 0;
}
class Sniffer
{
senf::PacketSocketHandle sock;
public:
Sniffer(std::string const & interface)
{ sock.bind(senf::LLSocketAddress(interface)); }
void run()
{
senf::Scheduler::instance().add(sock, senf::membind(&Sniffer::dumpPacket, this));
senf::Scheduler::instance().process();
}
private:
void dumpPacket(senf::FileHandle /* ignored */, senf::Scheduler::EventId event)
{
std::string data (sock.read());
senf::EthernetPacket::ptr packet (
senf::Packet::create<senf::EthernetPacket>(
data.begin(), data.end()));
packet->dump(std::cout);
hexdump(packet->last()->begin(),
packet->last()->end());
std::cout << "\n\n";
}
};
int scheduler_main(int argc, char const * argv[])
{
try {
Sniffer sniffer ("eth0");
sniffer.run();
}
catch (std::exception const & ex) {
std::cerr << senf::prettyName(typeid(ex)) << ": " << ex.what() << "\n";
}
return 0;
}
int main(int argc, char const * argv[])
{
if (argc >= 2)
if (std::string(argv[1]) == "loop")
return loop_main(argc,argv);
else if (std::string(argv[1]) == "scheduler")
return scheduler_main(argc,argv);
std::cerr << "Usage: sniffer { loop | scheduler }" << std::endl;
return 1;
}
///////////////////////////////cc.e////////////////////////////////////////
......
......@@ -147,9 +147,12 @@ namespace senf {
interface). You will not have \c write or \c readfrom members. \c write will be disabled since
the WritePolicy is unknown, \c readfrom will be disabled since a socket with the
ConnectedCommunicationPolicy does not have a \c readfrom member.
*/
\see
\ref policy_group \n
\ref handle_group \n
\ref protocol_group
*/
/** \page extend Extending the Library
......
......@@ -61,7 +61,7 @@ namespace senf {
\par Socket Handle typedefs:
\ref PacketSocketHandle (ProtocolClientSocketHandle)
\par Protocol Interface:
\par Policy Interface:
ClientSocketHandle::read(), ClientSocketHandle::readfrom(), ClientSocketHandle::writeto(),
ClientSocketHandle::bind(), ClientSocketHandle::local(), ClientSocketHandle::rcvbuf(),
ClientSocketHandle::sndbuf()
......
......@@ -103,7 +103,7 @@ namespace senf {
class SocketPolicyBase;
/** \brief Socket protocol base class
/** \brief Socket Protocol base class
This is the base class of all socket protocol classes. Every protocol class must directly or
indirectly inherit from SocketProtocol
......@@ -211,7 +211,7 @@ namespace senf {
};
/** \brief Concrete socket protocol implementation base class
/** \brief Concrete Socket Protocol implementation base class
ConcreteSocketProtocol is the base class of a concrete socket protocol implementation. The
final protocol class must inherit from ConcreteSocketProtocol. The template argument \a
......
......@@ -64,7 +64,7 @@ namespace senf {
\ref TCPv4ClientSocketHandle (ProtocolClientSocketHandle), \ref TCPv4ServerSocketHandle
(ProtocolServerSocketHandle)
\par Protocol Interface:
\par Policy Interface:
ClientSocketHandle::read(), ClientSocketHandle::write(), ClientSocketHandle::bind(),
ClientSocketHandle::local(), ClientSocketHandle::connect(), ClientSocketHandle::peer(),
ClientSocketHandle::rcvbuf(), ClientSocketHandle::sndbuf()
......@@ -145,7 +145,7 @@ namespace senf {
\ref TCPv6ClientSocketHandle (ProtocolClientSocketHandle), \ref TCPv6ServerSocketHandle
(ProtocolServerSocketHandle)
\par Protocol Interface:
\par Policy Interface:
ClientSocketHandle::read(), ClientSocketHandle::write(), ClientSocketHandle::bind(),
ClientSocketHandle::local(), ClientSocketHandle::connect(), ClientSocketHandle::peer(),
ClientSocketHandle::rcvbuf(), ClientSocketHandle::sndbuf()
......
......@@ -268,6 +268,7 @@ dl.parameters dd table {
table.glossary {
border: none;
border-spacing: 0;
margin: 10px 0;
}
table.glossary tr td {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment