git-svn-id: https://svn.microneil.com/svn/SNFMilter/trunk@1 2c985dca-31e6-41a4-b4a2-d8f5b7f8e074master
@@ -0,0 +1,103 @@ | |||
// MailHeaders.cpp | |||
// Copyright (C) 2008 ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// This file contains the functions to extract the mail header and | |||
// body from the string returned by SNFMilterEngine::XHeaders(). | |||
#include <stdexcept> | |||
#include <sstream> | |||
#include "MailHeaders.hpp" | |||
using namespace std; | |||
const string DefaultSMTPENDL = "\r\n"; ///< Default SMTP endline. | |||
const string DefaultLibmilterENDL = "\n "; ///< Default libmilter endline. | |||
const string DefaultPrefix = "X-"; ///< Default start of header line. | |||
MailHeaders::MailHeaders() : | |||
SMTPENDL(DefaultSMTPENDL), | |||
LibMilterENDL(DefaultLibmilterENDL) { | |||
} | |||
MailHeaders::~MailHeaders() { | |||
} | |||
void | |||
MailHeaders::loadHeaders(const string &HeaderBuffer) { | |||
Buffer = HeaderBuffer; | |||
} | |||
bool | |||
MailHeaders::getHeaderName(string *HeaderName) { | |||
if (Buffer.empty()) { // No header if the buffer is empty. | |||
return false; | |||
} | |||
string::size_type endIndex = Buffer.find(SMTPENDL); | |||
if (string::npos == endIndex) { // No SMPENDL. | |||
ostringstream Temp; | |||
Temp << "Invalid header line (no SMTP end-of-line): '" | |||
<< Buffer << "'."; | |||
throw std::invalid_argument(Temp.str()); | |||
} | |||
string Line(Buffer, 0, endIndex); // First line of the header. | |||
string::size_type colonIndex = Line.find(":"); | |||
if (string::npos == colonIndex) { // No ":". | |||
ostringstream Temp; | |||
Temp << "Invalid header line (no ':'): '" | |||
<< Buffer << "'."; | |||
throw std::invalid_argument(Temp.str()); | |||
} | |||
HeaderName->assign(Line, 0, colonIndex); | |||
if (0 == HeaderName->size()) { // Null header name. | |||
ostringstream Temp; | |||
Temp << "Invalid header line (no name): '" | |||
<< Buffer << "'."; | |||
throw std::invalid_argument(Temp.str()); | |||
} | |||
Buffer.erase(0, colonIndex + 1); // Erase the header name and ":". | |||
return true; | |||
} | |||
bool | |||
MailHeaders::getHeaderLine(string *HeaderLine) { | |||
if (Buffer.empty()) { // No line if the buffer is empty. | |||
return false; | |||
} | |||
string::size_type EndIndex = Buffer.find(SMTPENDL); | |||
if (string::npos == EndIndex) { // No SMPENDL. | |||
ostringstream Temp; | |||
Temp << "Invalid header line (no SMTP end-of-line): '" | |||
<< Buffer << "'."; | |||
throw std::invalid_argument(Temp.str()); | |||
} | |||
HeaderLine->assign(Buffer, 0, EndIndex); // Tentative line of the body. | |||
string::size_type XIndex = HeaderLine->find("X-"); | |||
if (XIndex == 0) { // Does it begin with "X-"? | |||
return false; // Yes; it's not the body line. | |||
} | |||
Buffer.erase(0, EndIndex + SMTPENDL.size()); // Erase line and SMTPENDL. | |||
return true; | |||
} | |||
bool | |||
MailHeaders::getNameBody(string *HeaderName, string *FormattedHeaderBody) { | |||
if (!getHeaderName(HeaderName)) { // Get the header. | |||
return false; // No more headers. | |||
} | |||
FormattedHeaderBody->clear(); | |||
string HeaderLine; // One line of the body. | |||
bool FirstTime = true; | |||
while (getHeaderLine(&HeaderLine)) { // While this header has lines... | |||
if (FirstTime) { | |||
*FormattedHeaderBody = HeaderLine; | |||
FirstTime = false; | |||
} else { | |||
*FormattedHeaderBody += LibMilterENDL; | |||
*FormattedHeaderBody += HeaderLine; | |||
} | |||
} | |||
return true; | |||
} |
@@ -0,0 +1,102 @@ | |||
// MailHeaders.hpp | |||
// Copyright (C) 2008 ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// Header file for MailHeaders.cpp. | |||
#ifndef MailHeadershpp_included | |||
#define Mailheadershpp_included | |||
#include <string> | |||
using namespace std; | |||
/// Class to extract mail header name/body pairs. | |||
// | |||
// This class extracts mail header name/body pairs from a string | |||
// containing a series of mail headers. | |||
// | |||
class MailHeaders { | |||
private: | |||
string Buffer; ///< Contains the mail headers. | |||
const string SMTPENDL; ///< STMP end-of-line string (e.g. "\r\n). | |||
const string LibMilterENDL; ///< libmilter end-of-line string. | |||
const string Prefix; ///< Start of header name (e.g. "X-"). | |||
/// Get the next header name and body. | |||
// | |||
// This method inputs a string containing zero or more RFC | |||
// 2822-compliant headers, and returns the header name and body in | |||
// a format suitable for adding the header using the libmilter | |||
// library. The header name, ":", body, and the trailing SMTPENDL | |||
// are removed from the input string. | |||
// | |||
// \param[out] HeaderName contains the name of the header. | |||
// | |||
// \param[in,out] Buffer on input contains the headers. On output, | |||
// the name of the first header, the ":", header body, and trailing | |||
// SMTPENDL are removed from the beginning. | |||
// | |||
// \returns true if a header is found, false if Buffer is "". | |||
// | |||
// \throws std::invalid_argument if Buffer does not have the correct | |||
// format. | |||
// | |||
// \see getHeaderLine. | |||
// | |||
// \see getHeaderBody. | |||
// | |||
bool getHeaderName(std::string *HeaderName); | |||
/// Get the next line of a mail header. | |||
// | |||
// This method inputs a string containing zero or more lines of | |||
// the body of a RFC 2822-compliant header, and returns the next | |||
// line of the body of the header. The line and the SMTPENDL are | |||
// removed from the input string Buffer. | |||
// | |||
// \param[out] HeaderLine contains the line of the header. | |||
// | |||
// \returns true if a line is found, false if Buffer is "". | |||
// | |||
// \throws std::invalid_argument if the first line of Buffer is not | |||
// "", and does not end with SMTPENDL. | |||
// | |||
bool getHeaderLine(std::string *HeaderLine); | |||
public: | |||
MailHeaders(); ///< Constructer for MailHeaders. | |||
~MailHeaders(); ///< Destructor for MailHeaders. | |||
/// Load mail headers. | |||
// | |||
// This method loads the object with the headers. | |||
// | |||
// \param[in] HeaderBuffer contains the headers. | |||
// | |||
void loadHeaders(const string &HeaderBuffer); | |||
/// Get the next header name and body. | |||
// | |||
// This method returns the next header name and body. The body is | |||
// formatted so that it can be used as input for the libmilter | |||
// smfi_addheader() function. | |||
// | |||
// \param[out] HeaderName contains the header name. | |||
// | |||
// \param[out] FormattedHeaderBody contains the formatted header | |||
// body. | |||
// | |||
// \returns true if a header/body is found, false if the buffer is | |||
// "". | |||
// | |||
// \throws exceptions thrown by getHeaderName and getHeaderLine. | |||
// | |||
// \see getHeaderName. | |||
// | |||
// \see getHeaderLine. | |||
// | |||
bool getNameBody(string *HeaderName, string *FormattedHeaderBody); | |||
}; | |||
#endif |
@@ -0,0 +1,34 @@ | |||
## Process this file with automake to produce Makefile.in | |||
## | |||
## $Id$ | |||
## | |||
## automake input for the MicroNeil SNFMilter application (SNFMilter directory). | |||
## | |||
## Author: Alban Deniz | |||
## | |||
## Copyright (C) 2009 ARM Research Labs, LLC. | |||
## See www.armresearch.com for the copyright terms. | |||
## | |||
## | |||
LIBS = @SNF_LIBS@ -L../SNFMulti -L../CodeDweller -lSNFMulti -lCodeDweller @LIBS@ | |||
CXXFLAGS = $(SNF_CXXFLAGS) -I@top_srcdir@/SNFMulti -I@top_srcdir@/CodeDweller | |||
sbin_PROGRAMS = \ | |||
SNFMilter | |||
SNFMilter_SOURCES = \ | |||
@top_srcdir@/SNFMilter/main.cpp \ | |||
@top_srcdir@/SNFMilter/SNFMilter.cpp \ | |||
@top_srcdir@/SNFMilter/MailHeaders.cpp | |||
noinst_HEADERS = \ | |||
@top_srcdir@/SNFMilter/MailHeaders.hpp \ | |||
@top_srcdir@/SNFMilter/ProductionQueue.hpp \ | |||
@top_srcdir@/SNFMilter/SNFMilter.hpp | |||
EXTRA_DIST = \ | |||
Makefile.am | |||
clean-local: | |||
rm -f *.gcno *.gcov *.gcda *~ $(CONFDATA) |
@@ -0,0 +1,48 @@ | |||
// ProductionQueue.hpp | |||
// Copyright (C) 2007 MicroNeil Research Corporation | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// A ProductionQueue is a templated, thread safe mechanism for implementing | |||
// a producer/consumer relationship. The objects in the queue should be simple | |||
// data so that they can be created, destroyed, and copied without trouble. Put | |||
// another way - the objects in the ProductionQueue should be lightweight | |||
// handles for other things. Those things should be created and destroyed | |||
// elsewhere. | |||
#include <queue> | |||
#include "threading.hpp" | |||
using namespace std; | |||
template<typename T> // Templatized | |||
class ProductionQueue { // Production Queue Class | |||
private: | |||
Mutex myMutex; // Contains a mutex and | |||
volatile int LatestSize; // a volatile (blinking light) size | |||
ProductionGateway myGateway; // integrated with a production | |||
queue<T> myQueue; // gateway and a queue. | |||
public: | |||
ProductionQueue() : LatestSize(0) {} // The size always starts at zero. | |||
T take() { // To consume a queued object | |||
myGateway.consume(); // we wait on the production gateway | |||
ScopeMutex OneAtATimePlease(myMutex); // and when we get through we lock | |||
T O = myQueue.front(); // the mutext, take the object on the | |||
myQueue.pop(); // front of the queue, pop it out, | |||
LatestSize = myQueue.size(); // and rest our size (blinking light). | |||
return O; // Then return the object we got. | |||
} | |||
void give(T O) { // To produce a queued object | |||
ScopeMutex OneAtATimePlease(myMutex); // we wait on the mutex. When we | |||
myQueue.push(O); // get through we push our object | |||
LatestSize = myQueue.size(); // into the queue, reset our size | |||
myGateway.produce(); // indicator and tell the gateway. | |||
} // When we're done it can be grabbed. | |||
int size() { // To check the size we look at | |||
return LatestSize; // the blinking light. | |||
} | |||
}; | |||
@@ -0,0 +1,258 @@ | |||
// SNFMilter.hpp | |||
// Copyright (C) 2007 ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// This file defines the SNFMilter configuration data structures and interface. | |||
#ifndef SNFMilterhpp_included | |||
#define SNFMilterhpp_included | |||
#include <signal.h> | |||
#include <libmilter/mfapi.h> | |||
#include <vector> | |||
#include <string> | |||
#include "ProductionQueue.hpp" | |||
#include "MailHeaders.hpp" | |||
#include "timing.hpp" | |||
#include "threading.hpp" | |||
using namespace std; | |||
class snf_EngineHandler; // We must know that these exist. | |||
class snf_RulebaseHandler; | |||
// Connection types. | |||
enum SNFMilterSocketType { | |||
TCPMilterSocket = 1, | |||
UNIXMilterSocket = 2, | |||
NOMilterSocket = 3 | |||
}; | |||
// SNFMilterAction - What we can do. | |||
enum SNFMilterAction { // SNFMilter Actions | |||
Error = -1, // Error result. | |||
Allow = 0, // Process the message. | |||
Accept = 1, // White-List the message. | |||
Retry = 2, // Return Try Again (tmp fail) | |||
Reject = 3, // Reject the message. | |||
Discard = 4, // Silently discard. | |||
Quarantine = 5, // Store in quarantine. | |||
NoAction = 6, // Take no action. | |||
NMilterActions | |||
}; | |||
// | |||
// Configuration. | |||
// | |||
const string AllowActionMnemonic = "0"; | |||
const string AcceptActionMnemonic = "1"; | |||
const string RetryActionMnemonic = "2"; | |||
const string RejectActionMnemonic = "3"; | |||
const string DiscardActionMnemonic = "4"; | |||
const string QuarantineActionMnemonic = "5"; | |||
const string NoActionMnemonic = "6"; | |||
const string TCPMilterSocketMnemonic = "1"; | |||
const string UNIXMilterSocketMnemonic = "2"; | |||
const int ResultCodesCount = 64; // Number of valid result codes. | |||
const int ConfigurationLifetime = 1000; // Config life time in ms. | |||
const bool PrependLocalReceivedHeader = true; // True to prepend local received headers | |||
// to the buffer to scan. | |||
const sfsistat FailSafeMilterResponse = SMFIS_CONTINUE; // Return value to libmilter | |||
// in case of error. | |||
const string::size_type MailBufferReserveSize = 65536; // Maximum amount of email message to scan. | |||
const string SMTPENDL = "\r\n"; // SMTP endline. | |||
const int ShutdownPeriods = 5; // Number of time periods to wait while | |||
// shutting down. | |||
const int ShutdownWaitPeriod_ms = 1000; // Time period duration for shutting down. | |||
const string UnknownExceptionMessage = "Unknown exception occurred."; // Logged when an unknown exception occurs. | |||
const int ShutdownSignal = SIGTERM; // Signal for shutdown. | |||
// | |||
// End of configuration. | |||
// | |||
// The SNFMilterEngine class provides up to date configuration data and | |||
// a scanning engine for the milter. It is presumed that at one of these objects | |||
// will be used in each message scan. They can be created, used, and destroyed, | |||
// or for a more optimized approach they can be created, used, stored in a pool, | |||
// and refreshed, and used again for a new scan. They should all be properly | |||
// destroyed before runLibMilter() returns. | |||
class SNFMilterEngine { // Milter config objec. One per scan. | |||
private: | |||
Mutex ConfigMutex; // Configuration lock mutex. | |||
snf_RulebaseHandler* myRulebase; // Where is my rulebase? | |||
snf_EngineHandler* myEngine; // Where is my engine? | |||
// Configuration data. | |||
// IP scan actions | |||
SNFMilterAction WhiteAction; // Action for White IP. | |||
SNFMilterAction CautionAction; // Action for Caution IP. | |||
SNFMilterAction BlackAction; // Action for Black IP. | |||
SNFMilterAction TruncateAction; // Action for Truncate IP. | |||
SNFMilterAction NonZeroAction; // Action for nonzero scans. | |||
// Message scan actions | |||
SNFMilterAction ResultActions[ResultCodesCount]; // Array of possible scan actions. | |||
Timeout ConfigurationCheckTime; // Timer for checking the configuration. | |||
string RunningConfiguration; // The current running config string. | |||
void readConfiguration(); // Parses the configuration. | |||
void checkConfiguration(); // Reload the config if it is old. | |||
public: | |||
SNFMilterEngine(snf_RulebaseHandler* R); // Construct the configuration. | |||
~SNFMilterEngine(); // Destroy the configuration. | |||
void setResultAction(int Result, SNFMilterAction Action); // Set a result / action pair. | |||
SNFMilterAction scanIP(unsigned long int IP); // Scans an IP. | |||
SNFMilterAction scanMessage(const unsigned char* bfr, int length); // Scans a message. | |||
string XHeaders(); // Return X headers from last scan. | |||
}; | |||
// The SNFMilterContext class maintains the context for a connection | |||
// from the MTA. There is one SNFMilterContext object for each | |||
// connection from the MTA. They can be created, used, and destroyed, | |||
// or for a more optimized approach they can be created, used, stored | |||
// in a pool, and refreshed, and used again for a new scan. They | |||
// should all be properly destroyed before runLibMilter() returns. | |||
class SNFMilterContext { // Milter connection context object. | |||
public: | |||
// Object states. The object transitions to the corresponding state | |||
// when a libmilter callback is invoked. The object is in the | |||
// Pooled state when the object is not being used. | |||
enum SNFMilterState { | |||
Pooled, | |||
Connect, | |||
Helo, | |||
EnvFrom, | |||
EnvRcpt, | |||
Data, | |||
Header, | |||
EOH, | |||
Body, | |||
EOM, | |||
Close, | |||
NMilterStates | |||
} State; | |||
SNFMilterContext(snf_RulebaseHandler *); | |||
~SNFMilterContext(); | |||
sfsistat SkipReturn; // libmilter return value when further | |||
// callbacks of the same type are to be skipped. | |||
// Map the scan result to the libmilter return value. | |||
sfsistat | |||
smfisReturn(SNFMilterAction); | |||
// Scanning engine. | |||
SNFMilterEngine milterEngine; | |||
string getLocalReceivedHeader(); | |||
// Connection data. | |||
struct SNFMilterConnectionData { | |||
string HostName; | |||
IP4Address HostIP; | |||
string HostHelo; | |||
// Clear the object. | |||
void clear() { | |||
HostName.clear(); | |||
HostIP = (long unsigned )0; | |||
HostHelo.clear(); | |||
} | |||
} ConnectionData; | |||
// Message buffer. | |||
struct SNFMilterMessageData { | |||
// Buffer to hold the message. | |||
string MessageBuffer; | |||
// Sender address. | |||
string SenderAddress; | |||
// Constructor reserves memory to hold the message. | |||
SNFMilterMessageData(string::size_type reserveSize) { | |||
MessageBuffer.reserve(reserveSize); | |||
} | |||
// Clear the object. | |||
void clear() { | |||
MessageBuffer.clear(); | |||
SenderAddress.clear(); | |||
} | |||
} MessageData; | |||
}; | |||
class SNFMilterContextPool { // SNFMilter Pool Manager | |||
private: | |||
Mutex ContextAllocationControl; // Protects context allocation. | |||
vector<SNFMilterContext*> ContextPool; // Contains all created contexts. | |||
ProductionQueue<SNFMilterContext*> AvailableContexts; // Contains all available contexts. | |||
snf_RulebaseHandler* myRulebase; // Rulebase handler. | |||
// Connection info. | |||
SNFMilterSocketType MilterSocketType; | |||
string MilterSocketPath; | |||
string MilterSocketGroup; | |||
string MilterSocketIP; | |||
int MilterSocketPort; | |||
public: | |||
SNFMilterContextPool(snf_RulebaseHandler* Rulebase); // Ctor needs a live rulebase handler. | |||
~SNFMilterContextPool(); // Dtor gracefully discards contexts. | |||
SNFMilterSocketType getSocketType(); // Named pipe or TCP socket specified | |||
// in the configuration. | |||
string getSocketPath(); // Path of named pipe specified in | |||
// the configuration | |||
string getSocketGroup(); // Group specified for named pipe | |||
// in the conofiguration. | |||
string getSocketIP(); // IP (host) specified in the | |||
// configuration. | |||
int getSocketPort(); // TCP port specified in the | |||
// configuration | |||
SNFMilterContext* grab(); // Get an context to use. | |||
void drop(SNFMilterContext* E); // Drop an context after use. | |||
bool allUnused(); // Return true if no contexts are in use. | |||
void logThisError(string ContextName, int Code, string Text); // Log an error message. | |||
void logThisInfo(string ContextName, int Code, string Text); // Log an informational message. | |||
}; | |||
// The runLibMilter function establishes the appropriate libmilter call backs and | |||
// accepts calls from the MTA via libmilter until it is told to quit. When it | |||
// is told to quit it gracefully closes down, reclaims any memory it allocated, | |||
// and returns. | |||
// The actual code for the runLibMilter() function call is found in SNFMilter.cpp. | |||
void runLibMilter(SNFMilterContextPool* Contexts, bool DebugMode); // Run the milter 'til it's done. | |||
#endif |
@@ -0,0 +1,171 @@ | |||
// main.cpp | |||
// | |||
// Copyright (C) 2007, ARM Research Labs, LLC. | |||
// See www.armresearch.com for the copyright terms. | |||
// | |||
// This is the entry point for the SNF Milter. | |||
// The main() function acquires the configuration file path, sets up the | |||
// SNF engine, and passes control to the SNFMilter module via runSNFMilter(). | |||
// | |||
// SNFMilter() makes use of the SNF engine until it is dismissed by the MTA via | |||
// the appropriate libmilter call. | |||
// | |||
// While SNFMilter() is running, it will get new configuration data for each | |||
// scan it is asked to perform. A configuration packet will be produced on | |||
// demand by the main module. The main module will check the configuration once | |||
// every second or so to make sure it has the correct current data. The | |||
// configuration data structure is defined in SNFMilter.hpp. | |||
// | |||
// When the SNFMilter() function returns, the main() function closes down the | |||
// SNF Engine and exits the program. | |||
#include <errno.h> | |||
#include <string.h> | |||
#include <exception> | |||
#include <iostream> | |||
#include "SNFMulti.hpp" | |||
#include "SNFMilter.hpp" | |||
#include "config.h" | |||
using namespace std; | |||
const char* SNF_MILTER_VERSION = "SNFMilter " PACKAGE_VERSION " Build: " __DATE__ " " __TIME__; | |||
static const string XCIShutdownResponse = | |||
"<snf><xci><server><response message=\'shutdown in progress\' code=\'1\'/></server></xci></snf>\n"; | |||
class XCIShutdownWatcher : public snfXCIServerCommandHandler { // Shutdown watcher. | |||
public: | |||
XCIShutdownWatcher(){} | |||
string processXCIRequest(snf_xci& X) { // Here is how we process requests. | |||
if(0 == X.xci_server_command.find("shutdown")) { // If we find shutdown then | |||
smfi_stop(); // Stop processing messages. | |||
return XCIShutdownResponse; // respond with a message. | |||
} // If we get some other request | |||
return XCIErrorResponse; // return the error response. | |||
} | |||
}; | |||
class SignalCatcher : public Thread { // Class to catch a signal. | |||
private: | |||
sigset_t *MySignalSet; | |||
snf_RulebaseHandler *MyRulebase; | |||
public: | |||
SignalCatcher(sigset_t *Signal_Set, snf_RulebaseHandler* Rulebase) : // Construct. | |||
MySignalSet(Signal_Set), // Set of signals to catch. | |||
MyRulebase(Rulebase) { // Used for error logging. | |||
run(); // Start the thread. | |||
} | |||
void myTask() { | |||
int ReceivedSignal; | |||
int Status = sigwait(MySignalSet, &ReceivedSignal); | |||
if (0 != Status) { | |||
// Log error. | |||
ostringstream Temp; | |||
Temp << "Error waiting for signal: " << strerror(Status) << "."; | |||
MyRulebase->logThisError("Signal Catcher", 1, Temp.str()); | |||
return; | |||
} | |||
smfi_stop(); // Stop processing. | |||
} | |||
}; | |||
const int CorrectARGc = 2; // How many arguments we expect. | |||
void displayHelp() { // Display some help. | |||
cout | |||
<< SNF_MILTER_VERSION << endl | |||
<< "Copyright (C) 2007, ARM Research Labs, LLC (www.armresearch.com)" << endl | |||
<< endl | |||
<< "Use snfmilter <full path to configuration file>" << endl | |||
<< "Example: /home/snfmilter/snfmilter /home/snfmilter/snf_milter.xml" << endl; | |||
}; | |||
int main(int argc, char* argv[]) { | |||
// Get and check the command line arguments. | |||
if(CorrectARGc != argc) { // If our command line arguments | |||
displayHelp(); // don't look right then display | |||
return 0; // our help screen. | |||
} | |||
bool DebugMode = false; // This will be our debug mode. | |||
string argv0(argv[0]); // Capture how we were called. | |||
if( | |||
string::npos != argv0.find("Debug") || // If we find "Debug" or | |||
string::npos != argv0.find("debug") // "debug" in our command path | |||
) { // then we are in DebugMode. | |||
DebugMode = true; // Set the flag and tell the | |||
cout << "Debug Mode" << endl; // watchers. | |||
} | |||
sigset_t SignalSet; // Set of signals to mask. | |||
SignalCatcher *SigCatcher; // Object to catch signal. | |||
try { // Catch anything that breaks loose. | |||
int PthreadStatus; | |||
if ( (0 != sigemptyset(&SignalSet)) || // Mask signal for this thread and | |||
// all threads to be created. | |||
(0 != sigaddset(&SignalSet, ShutdownSignal)) ) { | |||
ostringstream Temp; | |||
Temp << "Error masking signal on startup: " << strerror(errno) << "."; | |||
throw runtime_error(Temp.str()); | |||
} | |||
PthreadStatus = pthread_sigmask(SIG_BLOCK, &SignalSet, 0); | |||
if (0 != PthreadStatus) { | |||
ostringstream Temp; | |||
Temp << "Error masking signal on startup (pthread_sigmask): " << strerror(PthreadStatus) << "."; | |||
throw runtime_error(Temp.str()); | |||
} | |||
snf_RulebaseHandler* MilterRulebase = new snf_RulebaseHandler(); // Allocate a rulebase handler. | |||
MilterRulebase->PlatformVersion(SNF_MILTER_VERSION); // Record our version identification. | |||
XCIShutdownWatcher ShutdownWatcher; // Make a server shutdown processor | |||
MilterRulebase->XCIServerCommandHandler(ShutdownWatcher); // and register it with the engine. | |||
MilterRulebase->open(argv[1], "", ""); // Open the rulebase. | |||
SNFMilterContextPool* MilterContexts = | |||
new SNFMilterContextPool(MilterRulebase); // Create the Milter Context Pool. | |||
SigCatcher = new SignalCatcher(&SignalSet, MilterRulebase); // Create thread object to catch the signal. | |||
runLibMilter(MilterContexts, DebugMode); // Run the milter. | |||
ThreadState const &SigCatcherState = SigCatcher->MyState(); | |||
if (Thread::ThreadStarted.Name == SigCatcherState.Name) { // Is the signal catcher thread running? | |||
PthreadStatus = pthread_kill(SigCatcher->getMyThread(), ShutdownSignal); // Yes. Send it a signal. | |||
if (0 == PthreadStatus) { | |||
SigCatcher->join(); // Wait for signal catcher to complete. | |||
} else { | |||
ostringstream Temp; | |||
Temp << "Error terminating signal catcher: " << strerror(PthreadStatus) << "."; | |||
throw runtime_error(Temp.str()); | |||
} | |||
} | |||
delete MilterContexts; // Destroy the context pool. | |||
MilterContexts = 0; // Forget it. | |||
MilterRulebase->close(); // Close down the rulebase handler. | |||
delete MilterRulebase; // Destroy the rulebase. | |||
MilterRulebase = 0; // Forget it. | |||
delete SigCatcher; // Destroy the signal catcher. | |||
SigCatcher = 0; // Forget it. | |||
} // That's all folks. | |||
catch(exception& e) { // Report any normal exceptions. | |||
cerr << "SNFMilter Exception: " << e.what() << endl; | |||
} | |||
catch(...) { // Report any unexpected exceptions. | |||
cerr << "SNFMilter Panic! Unknown Exception!" << endl; | |||
} | |||
return 0; // Normally we return zero. | |||
} | |||