07/25/04 00:30:22
A work in progress.

PortMonitor/G is a program I wrote to graphically visualize the network ports under use
in real time, by tapping into the libpcap/winpcap packet capture library. Think of it
as a kind of graphical netstat. I'm writing it as a way to practice some multi-threaded
design and programming.

Here's a writeup on some of the things I've learned: sdl-tips-and-tricks.html.

What you need to run it:
* winpcap (Windows) or libpcap (Linux)
* Simple DirectMedia Layer library (Win32 DLL included)

0.8.7 (RAR) includes source and executable. 08/16/04 15:14:50
0.8.6 (RAR)(ZIP)(SRC) 07/25/04 14:59:38
0.8.5 (RAR)(ZIP)(SRC) 07/19/04 19:51:00

Features to add include (ranked by importance)  --
* Rework while() loops to be less aggressive. Use semaphore sleeping / signaling. [0.8.6]
* 8x8 fixed width font class. (based on linux/drivers/video/font_8x8.c) [0.8.7]
* Command console / Options within program.
* Zooming
* Run from tcpdump-compatible packet capture file.
* NSIS Installer w/automatic wpcap.dll installation and registry keys.
* Convert to use as plugin for IDS system. (Firestorm?)
* Always on top [0.8.7] / Always on top with GDI+ transparency. (Could be tricky w/SDL.)

The UI itself is simply a 512 x 512 grid where each 2x2 block represents one network
port out of 65536. The ports ascend from left -> right, and top -> bottom. I plan to
add an option (either command line or within the program) to set the scaling factor
at some point, it's currently set as a compile-time #define.

The program uses the SDL library to handle screen setup and threads. I haven't gotten
around to compiling a copy on Linux yet, but am fairly certain it will work.

One forewarning: It will chew up 100% of your CPU at runtime, running three threads
that run infinite while() loops. I've got a fix for this using a sleep/wait on signal
type system, but need more time to code it out.

As of version 0.8.6, the program runs with much better efficiency. It chews up ~15%
at low traffic on my 366MHz Celeron.

Things to keep in mind while doing multi-threaded programming:

* Lock access to global variables during critical sections of code.

  Think. Before you lock down a section of code or access to a variable, try to
  think about which threads are going to be reading or writing it, and whether
  they may be colliding for access to a given variable.
  Keep critical sections as small as possible. Only protect those read and write
  operations that are absolutely necessary and only for as short of periods as possible.

  This helps prevent stalls in your program, which inevitably happens as one thread
  waits for another to unlock a mutex.
* Use the C++ Standard Template Library: #include <set>

  Who doesn't love excellently designed data objects?
  In PortMonitor/G, I use an instance of the set object to store the port numbers that
  are being accessed at a given moment. The nice thing is that if a port has been
  stored previously in the set, it is not stored again. In other words, all values
  in the set object are unique. Ultimately, this cuts down on the number of pixels
  that need to be updated by the UI thread.
* Try swinging buffers, they're gr-e-e-a-t.

  Swinging buffers are pretty cool. They do take up twice as much memory, but they
  are very fast because you don't suffer from read and write access contention,
  the read thread and the write thread use mutable pointers to what they see as
  their own dedicated data structure.

  As the program runs, those pointers are occasionally flipped in a very quick
  and thread-safe operation, ensuring that subscribing threads don't get flubbed up.
  This is essentially double-buffering (as applied to computer graphics), applied
  to data structures.
* The more threads you can manageably suspend, the better.

  Between version 0.8.5 and 0.8.6, I learned a lot about thread waiting, which
  dramatically lowers CPU utilization if done properly. Basically, some parts of
  the program need to run all the time, while others need to run only when some
  condition is met. (e.g. a subscribed-to variable contains data)
  In PortMonitor/G, the packet grabbing function is forced to poll the network
  interface. (For some reason there isn't a reliable callback-based mechanism for
  alerting an application when packets are available.) I think of the packet grabber
  thread as a 'publisher', and the swinging buffer thread as the 'subscriber'. The
  subscriber doesn't need to run at all if there are no packets being received, so
  you can suspend the thread, and have it woken up using a signal sent by the
  publisher. No muss, no fuss. And, most importantly, no wasted CPU cycles.
©2004, research, mv