20091009.1549 _M

Copyright (C) 2009 ARM Research Labs, LLC

SNF4CGP provides a high-performance, multi-threaded spam filter plugin for
Communigate Pro using the Message Sniffer (SNFMulti) engine.

http://www.communigate.com/CommuniGatePro/VirusScan.html
http://www.communigate.com/CommuniGatePro/Helpers.html
http://www.communigate.com/CommuniGatePro/Data.html#String

The general design goals are (in no particular order):

1. Provide a customizable match between each possible SNF result code and
   each possible communigate response.

2. Provide comprehensive debugging and performance logging capabilities
   consistent with the way Communigate operates.

3. Provide a flexible message-hold capability to allow for additional processing
   by other software for quarantine operations or further message handing.

4. Provide the highest possible message handling performance.

5. Create an architecture that is easy to extend and support on multiple
   platforms.

See Architecture.jpg for a drawing of the architecture. Note that the snap-shot
is slightly out of spec. When the Architecture.jpg was snapped the thinking was
that each Job in the pool would contain it's own dedicated scanner. Later during
development it was decided that scanners should also be pooled and conserved and
only bound to a job for as short a time as possible. The latest drawing shows
this by connecting a Scanner Pool to the scan operation with a short loop and
indicating that the scanner pool resides inside the Job pool with a small symbol
in each. When we redraw this architectural diagram we will include these changes.

The application uses threads in this way:

* One thread sets up the application, reads requests, and ultimately closes
down the application.

* Another thread processes all finished jobs by pumping their output through
cout and then recycling job objects.

* Worker threads from a pool process each request.

Resource contention is minimized wherever possible:

- Ram allocation is conserved by pre-allocating and reusing buffers.

- Scanners, Worker threads, and Jobs are allocated as needed and pooled.

- Scanners are borrowed from a pool only long enough to scan a message and
  capture the results.

- Configuration data is parsed and cached only when it has changed.

- Worker threads are released back to the pool without waiting for IO to cout.

- As much as possible thread interactions are reduced to reference passing
  in very short mutex protected functions.
