PortMonitor/G 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) Files: 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 readme.txt 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.